lib/acfs/model/attributes.rb in acfs-0.32.1.1.b275 vs lib/acfs/model/attributes.rb in acfs-0.32.1.1.b276
- old
+ new
@@ -25,11 +25,12 @@
#
# @see #write_attributes
# @see ClassMethods#attributes
#
def initialize(*attrs)
- self.write_attributes self.class.attributes, change: false
+ self.write_attributes self.class.attributes
+ reset_changes
super
end
# @api public
#
@@ -44,11 +45,11 @@
# user.attributes # => { "name" => "John" }
#
# @return [ HashWithIndifferentAccess{ Symbol => Object } ] Attributes and their values.
#
def attributes
- HashWithIndifferentAccess.new self.class.attributes.keys.inject({}) { |h, k| h[k.to_sym] = public_send k; h }
+ @attributes ||= HashWithIndifferentAccess.new
end
# @api public
#
# Update all attributes with given hash. Attribute values will be casted
@@ -71,11 +72,11 @@
#
# @param [ Symbol, String ] name Attribute name.
# @return [ Object ] Attribute value.
#
def read_attribute(name)
- instance_variable_get :"@#{name}"
+ self.attributes[name.to_s]
end
# @api public
#
# Write a hash of attributes and values.
@@ -94,54 +95,69 @@
#
# @param [ Hash{ String, Symbol => Object, Proc }, #each{|key, value|} ] attributes to write.
# @see #write_attribute Delegates attribute values to `#write_attribute`.
#
def write_attributes(attributes, opts = {})
- return false unless attributes.respond_to? :each
+ unless attributes.respond_to?(:each) && attributes.respond_to?(:keys)
+ return false
+ end
if opts.fetch(:unknown,:ignore) == :raise
if (attributes.keys.map(&:to_s) - self.class.attributes.keys).any?
raise ArgumentError.new "Unknown attributes: #{(attributes.keys - self.class.attributes.keys).map(&:inspect).join(', ')}"
end
end
- attributes = attributes.select do |k, v|
- self.class.attributes.keys.include? k.to_s
- end
-
procs = {}
attributes.each do |key, _|
if attributes[key].is_a? Proc
procs[key] = attributes[key]
else
- write_attribute key, attributes[key], opts
+ write_local_attribute key, attributes[key], opts
end
end
procs.each do |key, proc|
- write_attribute key, instance_exec(&proc), opts
+ write_local_attribute key, instance_exec(&proc), opts
end
true
end
+ # @api private
+ #
+ # Check if a public getter for attribute exists that should be called to
+ # write it or of {#write_attribute} should be called directly. This is
+ # necessary as {#write_attribute} should go though setters but can also
+ # handle unknown attribute that will not have a generated setter method.
+ #
+ def write_local_attribute(name, value, opts = {})
+ method = "#{name}="
+ if respond_to? method, true
+ public_send method, value
+ else
+ write_attribute name, value, opts
+ end
+ end
+
# @api public
#
# Write single attribute with given value. Value will be casted
# to defined attribute type.
#
# @param [ String, Symbol ] name Attribute name.
# @param [ Object ] value Value to write.
# @raise [ ArgumentError ] If no attribute with given name is defined.
#
def write_attribute(name, value, opts = {})
- if (attr = self.class.defined_attributes[name.to_s]).nil?
- raise ArgumentError.new "Unknown attribute `#{name}`."
+ attr_type = self.class.defined_attributes[name.to_s]
+ if attr_type
+ write_raw_attribute name, attr_type.cast(value), opts
+ else
+ write_raw_attribute name, value, opts
end
-
- write_raw_attribute name, attr.cast(value), opts
end
# @api private
#
# Write an attribute without checking type or existence or casting
@@ -150,10 +166,10 @@
#
# @param [ String, Symbol ] name Attribute name.
# @param [ Object ] value Attribute value.
#
def write_raw_attribute(name, value, _ = {})
- instance_variable_set :"@#{name}", value
+ self.attributes[name.to_s] = value
end
module ClassMethods
# @api public