lib/virtus/attribute/builder.rb in virtus-1.0.0.beta8 vs lib/virtus/attribute/builder.rb in virtus-1.0.0.rc1

- old
+ new

@@ -1,45 +1,49 @@ module Virtus + # Attribute placeholder used when type constant is passed as a string or symbol + # # @private class PendingAttribute - attr_reader :name + attr_reader :type, :options, :name # @api private def initialize(type, options) - @type = type - @options = options - @name = options[:name] + @type, @options = type.to_s, options + @name = options[:name] end # @api private def finalize - Attribute::Builder.call(determine_type, @options).finalize + Attribute::Builder.call(determine_type, options).finalize end # @api private def finalized? false end # @api private def determine_type - if @type.include?('::') + if type.include?('::') # TODO: wrap it up in Virtus.constantize and use feature-detection to # pick up either Inflecto or ActiveSupport, whateve is available if defined?(Inflecto) - Inflecto.constantize(@type) + Inflecto.constantize(type) else raise NotImplementedError, 'Virtus needs inflecto gem to constantize namespaced constant names' end else - Object.const_get(@type) + Object.const_get(type) end end end # PendingAttribute + # Extracts the actual type primitive from input type + # + # @private class TypeDefinition attr_reader :type, :primitive # @api private def initialize(type) @@ -74,17 +78,15 @@ end end class Attribute - # TODO: this is a huge class and it might be a good idea to split it into - # smaller chunks. We probably need some option parser with dedicated - # sub-classes per attribute type (different one for Hash, Collection, EV) + # Builder is used to set up an attribute instance based on input type and options # # @private class Builder - attr_reader :attribute + attr_reader :attribute, :options, :type_definition, :klass, :type # @api private def self.call(type, options = {}) type_definition = TypeDefinition.new(type) @@ -127,51 +129,57 @@ private # @api private def initialize_class - @klass = self.class.determine_type(@type_definition.primitive, Attribute) + @klass = self.class.determine_type(type_definition.primitive, Attribute) end # @api private def initialize_type - @type = @klass.build_type(@type_definition) + @type = klass.build_type(type_definition) end # @api private def initialize_options(options) - @options = @klass.options.merge(:coerce => Virtus.coerce).update(options) - @klass.merge_options!(@type, @options) - determine_visibility! + @options = klass.options.merge(:coerce => Virtus.coerce).update(options) + klass.merge_options!(type, @options) + determine_visibility end # @api private - def determine_visibility! - default_accessor = @options.fetch(:accessor) - reader_visibility = @options.fetch(:reader, default_accessor) - writer_visibility = @options.fetch(:writer, default_accessor) - @options.update(:reader => reader_visibility, :writer => writer_visibility) - end - - # @api private def initialize_default_value - @options.update(:default_value => DefaultValue.build(@options[:default])) + options.update(:default_value => DefaultValue.build(options[:default])) end # @api private def initialize_coercer - @options.update(:coercer => @options.fetch(:coercer) { @klass.build_coercer(@type, @options) }) + options.update(:coercer => determine_coercer) end # @api private def initialize_attribute - @attribute = @klass.new(@type, @options) do |attribute| - attribute.extend(Accessor) if @options[:name] - attribute.extend(Coercible) if @options[:coerce] - attribute.extend(Strict) if @options[:strict] - attribute.extend(LazyDefault) if @options[:lazy] - end - @attribute.finalize if @options[:finalize] + @attribute = klass.new(type, options) + + @attribute.extend(Accessor) if options[:name] + @attribute.extend(Coercible) if options[:coerce] + @attribute.extend(Strict) if options[:strict] + @attribute.extend(LazyDefault) if options[:lazy] + + @attribute.finalize if options[:finalize] + end + + # @api private + def determine_coercer + options.fetch(:coercer) { klass.build_coercer(type, options) } + end + + # @api private + def determine_visibility + default_accessor = options.fetch(:accessor) + reader_visibility = options.fetch(:reader, default_accessor) + writer_visibility = options.fetch(:writer, default_accessor) + options.update(:reader => reader_visibility, :writer => writer_visibility) end end # class Builder end # class Attribute