lib/huberry/class.rb in shuber-attr_encrypted-1.0.1 vs lib/huberry/class.rb in shuber-attr_encrypted-1.0.2
- old
+ new
@@ -21,12 +21,12 @@
# would generate attributes named 'email_encrypted' and 'password_encrypted' to store the
# encrypted email. Defaults to ''.
#
# :key => The encryption key. This option may not be required if you're using a custom encryptor. If you pass
# a symbol representing an instance method then the :key option will be replaced with the result of the
- # method before being passed to the encryptor. Proc objects are evaluated as well. Any other key types
- # will be passed directly to the encryptor.
+ # method before being passed to the encryptor. Objects that respond to :call are evaluated as well (including procs).
+ # Any other key types will be passed directly to the encryptor.
#
# :encode => If set to true, attributes will be encoded as well as encrypted. This is useful if you're
# planning on storing the encrypted attributes in a database. The default encoding is 'm*' (base64),
# however this can be overwritten by setting the :encode option to some other encoding string instead of
# just 'true'. See http://www.ruby-doc.org/core/classes/Array.html#M002245 for more encoding directives.
@@ -40,11 +40,18 @@
#
# :encrypt_method => The encrypt method name to call on the <tt>:encryptor</tt> object. Defaults to :encrypt.
#
# :decrypt_method => The decrypt method name to call on the <tt>:encryptor</tt> object. Defaults to :decrypt.
#
+ # :if => Attributes are only encrypted if this option evaluates to true. If you pass a symbol representing an instance
+ # method then the result of the method will be evaluated. Any objects that respond to :call are evaluated as well.
+ # Defaults to true.
#
+ # :unless => Attributes are only encrypted if this option evaluates to false. If you pass a symbol representing an instance
+ # method then the result of the method will be evaluated. Any objects that respond to :call are evaluated as well.
+ # Defaults to false.
+ #
# You can specify your own default options
#
# class User
# # now all attributes will be encoded and marshaled by default
# attr_encrypted_options.merge!(:encode => true, :marshal => true, :some_other_option => true)
@@ -74,11 +81,13 @@
:suffix => '',
:encryptor => Huberry::Encryptor,
:encrypt_method => :encrypt,
:decrypt_method => :decrypt,
:encode => false,
- :marshal => false
+ :marshal => false,
+ :if => true,
+ :unless => false
}.merge(attr_encrypted_options).merge(attrs.last.is_a?(Hash) ? attrs.pop : {})
options[:encode] = 'm*' if options[:encode] == true
attrs.each do |attribute|
encrypted_attribute_name = options[:attribute].nil? ? options[:prefix].to_s + attribute.to_s + options[:suffix].to_s : options[:attribute].to_s
@@ -86,60 +95,73 @@
encrypted_attributes[attribute.to_s] = encrypted_attribute_name
attr_accessor encrypted_attribute_name.to_sym unless instance_methods.include?(encrypted_attribute_name)
define_class_method "encrypt_#{attribute}" do |value|
- if value.nil?
- encrypted_value = nil
+ if options[:if] && !options[:unless]
+ if value.nil?
+ encrypted_value = nil
+ else
+ value = Marshal.dump(value) if options[:marshal]
+ encrypted_value = options[:encryptor].send options[:encrypt_method], options.merge(:value => value)
+ encrypted_value = [encrypted_value].pack(options[:encode]) if options[:encode]
+ end
+ encrypted_value
else
- value = Marshal.dump(value) if options[:marshal]
- encrypted_value = options[:encryptor].send options[:encrypt_method], options.merge(:value => value)
- encrypted_value = [encrypted_value].pack(options[:encode]) if options[:encode]
+ value
end
- encrypted_value
end
define_class_method "decrypt_#{attribute}" do |encrypted_value|
- if encrypted_value.nil?
- decrypted_value = nil
+ if options[:if] && !options[:unless]
+ if encrypted_value.nil?
+ decrypted_value = nil
+ else
+ encrypted_value = encrypted_value.unpack(options[:encode]).to_s if options[:encode]
+ decrypted_value = options[:encryptor].send(options[:decrypt_method], options.merge(:value => encrypted_value))
+ decrypted_value = Marshal.load(decrypted_value) if options[:marshal]
+ end
+ decrypted_value
else
- encrypted_value = encrypted_value.unpack(options[:encode]).to_s if options[:encode]
- decrypted_value = options[:encryptor].send(options[:decrypt_method], options.merge(:value => encrypted_value))
- decrypted_value = Marshal.load(decrypted_value) if options[:marshal]
+ encrypted_value
end
- decrypted_value
end
define_method "#{attribute}" do
value = instance_variable_get("@#{attribute}")
encrypted_value = read_attribute(encrypted_attribute_name)
- original_key = options[:key]
- options[:key] = self.class.send :evaluate_attr_encrypted_key, options[:key], self
+ original_options = [:key, :if, :unless].inject({}) do |hash, option|
+ hash[option] = options[option]
+ options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
+ hash
+ end
value = instance_variable_set("@#{attribute}", self.class.send("decrypt_#{attribute}".to_sym, encrypted_value)) if value.nil? && !encrypted_value.nil?
- options[:key] = original_key
+ options.merge!(original_options)
value
end
define_method "#{attribute}=" do |value|
- original_key = options[:key]
- options[:key] = self.class.send :evaluate_attr_encrypted_key, options[:key], self
+ original_options = [:key, :if, :unless].inject({}) do |hash, option|
+ hash[option] = options[option]
+ options[option] = self.class.send :evaluate_attr_encrypted_option, options[option], self
+ hash
+ end
write_attribute(encrypted_attribute_name, self.class.send("encrypt_#{attribute}".to_sym, value))
- options[:key] = original_key
+ options.merge!(original_options)
instance_variable_set("@#{attribute}", value)
end
end
end
- # Evaluates encryption keys specified as symbols (representing instance methods) or procs
- # If the key is not a symbol or proc then the original key is returned
- def evaluate_attr_encrypted_key(key, object)
- case key
- when Symbol
- object.send(key)
- when Proc
- key.call(object)
+ # Evaluates an option specified as a symbol representing an instance method or a proc
+ # If the option is not a symbol or proc then the original option is returned
+ def evaluate_attr_encrypted_option(option, object)
+ if option.is_a?(Symbol) && object.respond_to?(option)
+ object.send(option)
+ elsif option.respond_to?(:call)
+ option.call(object)
else
- key
+ option
end
end
end
end
\ No newline at end of file