virtus 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +11 -15
- data/History.txt +10 -0
- data/TODO +4 -0
- data/VERSION +1 -1
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/roodi.yml +6 -6
- data/config/site.reek +5 -5
- data/lib/virtus.rb +21 -11
- data/lib/virtus/attribute.rb +92 -59
- data/lib/virtus/attribute/array.rb +4 -3
- data/lib/virtus/attribute/boolean.rb +21 -9
- data/lib/virtus/attribute/date.rb +5 -3
- data/lib/virtus/attribute/date_time.rb +5 -3
- data/lib/virtus/attribute/decimal.rb +5 -3
- data/lib/virtus/attribute/float.rb +5 -3
- data/lib/virtus/attribute/hash.rb +4 -3
- data/lib/virtus/attribute/integer.rb +5 -3
- data/lib/virtus/attribute/numeric.rb +5 -3
- data/lib/virtus/attribute/object.rb +4 -4
- data/lib/virtus/attribute/string.rb +7 -9
- data/lib/virtus/attribute/time.rb +5 -3
- data/lib/virtus/attribute_set.rb +151 -0
- data/lib/virtus/class_methods.rb +19 -10
- data/lib/virtus/instance_methods.rb +51 -27
- data/lib/virtus/support/descendants_tracker.rb +30 -0
- data/lib/virtus/typecast/boolean.rb +7 -5
- data/lib/virtus/typecast/numeric.rb +13 -8
- data/lib/virtus/typecast/string.rb +24 -0
- data/lib/virtus/typecast/time.rb +7 -5
- data/spec/integration/virtus/class_methods/attribute_spec.rb +17 -5
- data/spec/integration/virtus/class_methods/attributes_spec.rb +2 -5
- data/spec/shared/idempotent_method_behaviour.rb +5 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/unit/shared/attribute.rb +6 -155
- data/spec/unit/shared/attribute/accept_options.rb +55 -0
- data/spec/unit/shared/attribute/accepted_options.rb +11 -0
- data/spec/unit/shared/attribute/complex.rb +15 -0
- data/spec/unit/shared/attribute/get.rb +29 -0
- data/spec/unit/shared/attribute/options.rb +7 -0
- data/spec/unit/shared/attribute/set.rb +42 -0
- data/spec/unit/virtus/attribute/boolean_spec.rb +1 -2
- data/spec/unit/virtus/attribute/date_spec.rb +1 -2
- data/spec/unit/virtus/attribute/date_time_spec.rb +1 -2
- data/spec/unit/virtus/attribute/decimal_spec.rb +1 -2
- data/spec/unit/virtus/attribute/float_spec.rb +1 -2
- data/spec/unit/virtus/attribute/integer_spec.rb +1 -2
- data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +2 -2
- data/spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb +6 -4
- data/spec/unit/virtus/attribute/string_spec.rb +1 -2
- data/spec/unit/virtus/attribute/time_spec.rb +1 -2
- data/spec/unit/virtus/attribute_set/append_spec.rb +35 -0
- data/spec/unit/virtus/attribute_set/each_spec.rb +60 -0
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +13 -0
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +35 -0
- data/spec/unit/virtus/attribute_set/merge_spec.rb +36 -0
- data/spec/unit/virtus/attribute_set/parent_spec.rb +11 -0
- data/spec/unit/virtus/attribute_set/reset_spec.rb +60 -0
- data/spec/unit/virtus/class_methods/attribute_spec.rb +11 -0
- data/spec/unit/virtus/descendants_tracker/descendants_spec.rb +22 -0
- data/spec/unit/virtus/descendants_tracker/inherited_spec.rb +24 -0
- data/spec/unit/virtus/determine_type_spec.rb +21 -9
- data/spec/unit/virtus/instance_methods/{attribute_get_spec.rb → element_reference_spec.rb} +4 -2
- data/spec/unit/virtus/instance_methods/{attribute_set_spec.rb → element_set_spec.rb} +5 -7
- data/virtus.gemspec +35 -13
- metadata +96 -14
- data/lib/virtus/support/chainable.rb +0 -13
    
        data/Gemfile
    CHANGED
    
    | @@ -1,26 +1,22 @@ | |
| 1 | 
            -
            source  | 
| 2 | 
            -
             | 
| 3 | 
            -
            group :virtus do
         | 
| 4 | 
            -
              gem 'virtus',    File.read('VERSION'), :path => File.dirname(__FILE__)
         | 
| 5 | 
            -
            end
         | 
| 1 | 
            +
            source :rubygems
         | 
| 6 2 |  | 
| 7 3 | 
             
            group :development do
         | 
| 8 | 
            -
              gem  | 
| 9 | 
            -
              gem  | 
| 4 | 
            +
              gem 'jeweler', '~> 1.6.4'
         | 
| 5 | 
            +
              gem 'rspec',   '~> 2.6.0'
         | 
| 10 6 | 
             
            end
         | 
| 11 7 |  | 
| 12 | 
            -
             | 
| 13 | 
            -
               | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 8 | 
            +
            group :metrics do
         | 
| 9 | 
            +
              gem 'flay',      '~> 1.4.2'
         | 
| 10 | 
            +
              gem 'flog',      '~> 2.5.1'
         | 
| 11 | 
            +
              gem 'reek',      '~> 1.2.8', :git => 'git://github.com/dkubb/reek.git'
         | 
| 12 | 
            +
              gem 'roodi',     '~> 2.1.0'
         | 
| 13 | 
            +
              gem 'yardstick', '~> 0.4.0'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              platforms :mri_18 do
         | 
| 16 16 | 
             
                gem 'heckle',    '~> 1.4.3'
         | 
| 17 | 
            -
                gem 'json',      '~> 1.5.1'
         | 
| 18 17 | 
             
                gem 'metric_fu', '~> 2.1.1'
         | 
| 19 18 | 
             
                gem 'mspec',     '~> 1.5.17'
         | 
| 20 19 | 
             
                gem 'rcov',      '~> 0.9.9'
         | 
| 21 | 
            -
                gem 'reek',      '~> 1.2.8', :git => 'git://github.com/dkubb/reek.git'
         | 
| 22 | 
            -
                gem 'roodi',     '~> 2.1.0'
         | 
| 23 20 | 
             
                gem 'ruby2ruby', '=  1.2.2'
         | 
| 24 | 
            -
                gem 'yardstick', '~> 0.4.0'
         | 
| 25 21 | 
             
              end
         | 
| 26 22 | 
             
            end
         | 
    
        data/History.txt
    CHANGED
    
    | @@ -1,3 +1,13 @@ | |
| 1 | 
            +
            === v0.0.4 2011-07-08
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * [BREAKING CHANGE] attributes hash has been replaced by a specialized class AttributeSet (dkubb)
         | 
| 4 | 
            +
            * [BREAKING CHANGE] Virtus::ClassMethods.attribute returns self instead of a created attribute
         | 
| 5 | 
            +
            * [changed] descendants tracking has been extracted into DescendantsTracker module (dkubb)
         | 
| 6 | 
            +
            * [changed] Instance #primitive? method has been replaced by class utility method Virtus::Attribute.primitive?
         | 
| 7 | 
            +
            * [changed] Virtus::Attribute::String#typecast_to_primitive delegates to Virtus::Typecast::String.call
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Details: https://github.com/solnic/virtus/compare/v0.0.3...v0.0.4
         | 
| 10 | 
            +
             | 
| 1 11 | 
             
            === v0.0.3 2011-06-09
         | 
| 2 12 |  | 
| 3 13 | 
             
            * [BREAKING CHANGE] Attribute classes were moved to Virtus::Attribute namespace
         | 
    
        data/TODO
    ADDED
    
    
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.0. | 
| 1 | 
            +
            0.0.4
         | 
    
        data/config/flay.yml
    CHANGED
    
    
    
        data/config/flog.yml
    CHANGED
    
    | @@ -1,2 +1,2 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
            threshold:  | 
| 2 | 
            +
            threshold: 17.2
         | 
    
        data/config/roodi.yml
    CHANGED
    
    | @@ -1,18 +1,18 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
            AbcMetricMethodCheck:            { score:  | 
| 2 | 
            +
            AbcMetricMethodCheck:            { score: 9.5 }
         | 
| 3 3 | 
             
            AssignmentInConditionalCheck:    { }
         | 
| 4 4 | 
             
            CaseMissingElseCheck:            { }
         | 
| 5 | 
            -
            ClassLineCountCheck:             { line_count:  | 
| 5 | 
            +
            ClassLineCountCheck:             { line_count: 345 }
         | 
| 6 6 | 
             
            ClassNameCheck:                  { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
         | 
| 7 7 | 
             
            ClassVariableCheck:              { }
         | 
| 8 8 | 
             
            CyclomaticComplexityBlockCheck:  { complexity: 2 }
         | 
| 9 | 
            -
            CyclomaticComplexityMethodCheck: { complexity:  | 
| 9 | 
            +
            CyclomaticComplexityMethodCheck: { complexity: 3 }
         | 
| 10 10 | 
             
            EmptyRescueBodyCheck:            { }
         | 
| 11 11 | 
             
            ForLoopCheck:                    { }
         | 
| 12 12 | 
             
            # TODO: decrease line_count to 5 to 10
         | 
| 13 | 
            -
            MethodLineCountCheck:            { line_count:  | 
| 14 | 
            -
            MethodNameCheck:                 { pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\] | 
| 15 | 
            -
            ModuleLineCountCheck:            { line_count:  | 
| 13 | 
            +
            MethodLineCountCheck:            { line_count: 17 }
         | 
| 14 | 
            +
            MethodNameCheck:                 { pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/ }
         | 
| 15 | 
            +
            ModuleLineCountCheck:            { line_count: 351 }
         | 
| 16 16 | 
             
            ModuleNameCheck:                 { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
         | 
| 17 17 | 
             
            # TODO: decrease parameter_count to 2 or less
         | 
| 18 18 | 
             
            ParameterNumberCheck:            { parameter_count: 3 }
         | 
    
        data/config/site.reek
    CHANGED
    
    | @@ -8,10 +8,10 @@ UncommunicativeParameterName: | |
| 8 8 | 
             
              - !ruby/regexp /[0-9]$/
         | 
| 9 9 | 
             
              - !ruby/regexp /[A-Z]/
         | 
| 10 10 | 
             
            LargeClass:
         | 
| 11 | 
            -
              max_methods:  | 
| 11 | 
            +
              max_methods: 11
         | 
| 12 12 | 
             
              exclude: []
         | 
| 13 13 | 
             
              enabled: true
         | 
| 14 | 
            -
              max_instance_variables:  | 
| 14 | 
            +
              max_instance_variables: 8
         | 
| 15 15 | 
             
            UncommunicativeMethodName:
         | 
| 16 16 | 
             
              accept: []
         | 
| 17 17 | 
             
              exclude: []
         | 
| @@ -50,7 +50,7 @@ NestedIterators: | |
| 50 50 | 
             
              enabled: true
         | 
| 51 51 | 
             
              max_allowed_nesting: 1
         | 
| 52 52 | 
             
            LongMethod:
         | 
| 53 | 
            -
              max_statements:  | 
| 53 | 
            +
              max_statements: 6
         | 
| 54 54 | 
             
              exclude: []
         | 
| 55 55 | 
             
              enabled: true
         | 
| 56 56 | 
             
            Duplication:
         | 
| @@ -80,12 +80,12 @@ SimulatedPolymorphism: | |
| 80 80 | 
             
            DataClump:
         | 
| 81 81 | 
             
              exclude: []
         | 
| 82 82 | 
             
              enabled: true
         | 
| 83 | 
            -
              max_copies:  | 
| 83 | 
            +
              max_copies: 2
         | 
| 84 84 | 
             
              min_clump_size: 2
         | 
| 85 85 | 
             
            ControlCouple:
         | 
| 86 86 | 
             
              exclude: []
         | 
| 87 87 | 
             
              enabled: true
         | 
| 88 88 | 
             
            LongYieldList:
         | 
| 89 | 
            -
              max_params:  | 
| 89 | 
            +
              max_params: 1
         | 
| 90 90 | 
             
              exclude: []
         | 
| 91 91 | 
             
              enabled: true
         | 
    
        data/lib/virtus.rb
    CHANGED
    
    | @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'pathname'
         | 
| 2 | 
            -
            require 'set'
         | 
| 3 1 | 
             
            require 'date'
         | 
| 4 2 | 
             
            require 'time'
         | 
| 5 3 | 
             
            require 'bigdecimal'
         | 
| @@ -7,10 +5,11 @@ require 'bigdecimal/util' | |
| 7 5 |  | 
| 8 6 | 
             
            # Base module which adds Attribute API to your classes
         | 
| 9 7 | 
             
            module Virtus
         | 
| 8 | 
            +
             | 
| 10 9 | 
             
              # Represents an undefined parameter used by auto-generated option methods
         | 
| 11 | 
            -
               | 
| 10 | 
            +
              Undefined = Object.new.freeze
         | 
| 12 11 |  | 
| 13 | 
            -
              # Extends base class with  | 
| 12 | 
            +
              # Extends base class with class and instance methods
         | 
| 14 13 | 
             
              #
         | 
| 15 14 | 
             
              # @param [Class] base
         | 
| 16 15 | 
             
              #
         | 
| @@ -18,12 +17,12 @@ module Virtus | |
| 18 17 | 
             
              #
         | 
| 19 18 | 
             
              # @api private
         | 
| 20 19 | 
             
              def self.included(base)
         | 
| 20 | 
            +
                base.extend(DescendantsTracker)
         | 
| 21 21 | 
             
                base.extend(ClassMethods)
         | 
| 22 22 | 
             
                base.send(:include, InstanceMethods)
         | 
| 23 | 
            -
                base.extend(Support::Chainable)
         | 
| 24 23 | 
             
              end
         | 
| 25 24 |  | 
| 26 | 
            -
              # Returns a Virtus:: | 
| 25 | 
            +
              # Returns a Virtus::Attribute::Object sub-class based on a name or class
         | 
| 27 26 | 
             
              #
         | 
| 28 27 | 
             
              # @example
         | 
| 29 28 | 
             
              #   Virtus.determine_type('String') # => Virtus::Attribute::String
         | 
| @@ -32,24 +31,35 @@ module Virtus | |
| 32 31 | 
             
              #   name of a class or a class itself
         | 
| 33 32 | 
             
              #
         | 
| 34 33 | 
             
              # @return [Class]
         | 
| 35 | 
            -
              #   one of the Virtus:: | 
| 34 | 
            +
              #   one of the Virtus::Attribute::Object sub-class
         | 
| 36 35 | 
             
              #
         | 
| 37 36 | 
             
              # @api semipublic
         | 
| 38 37 | 
             
              def self.determine_type(class_or_name)
         | 
| 39 | 
            -
                if class_or_name. | 
| 40 | 
            -
                  class_or_name
         | 
| 38 | 
            +
                if class_or_name.kind_of?(Class)
         | 
| 39 | 
            +
                  if class_or_name < Attribute::Object
         | 
| 40 | 
            +
                    class_or_name
         | 
| 41 | 
            +
                  else
         | 
| 42 | 
            +
                    Attribute.descendants.detect do |descendant|
         | 
| 43 | 
            +
                      class_or_name <= descendant.primitive
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 41 46 | 
             
                elsif Attribute.const_defined?(name = class_or_name.to_s)
         | 
| 42 47 | 
             
                  Attribute.const_get(name)
         | 
| 43 48 | 
             
                end
         | 
| 44 49 | 
             
              end
         | 
| 45 | 
            -
            end
         | 
| 46 50 |  | 
| 47 | 
            -
             | 
| 51 | 
            +
            end # module Virtus
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            require 'virtus/support/descendants_tracker'
         | 
| 54 | 
            +
             | 
| 48 55 | 
             
            require 'virtus/class_methods'
         | 
| 49 56 | 
             
            require 'virtus/instance_methods'
         | 
| 50 57 |  | 
| 58 | 
            +
            require 'virtus/attribute_set'
         | 
| 59 | 
            +
             | 
| 51 60 | 
             
            require 'virtus/typecast/boolean'
         | 
| 52 61 | 
             
            require 'virtus/typecast/numeric'
         | 
| 62 | 
            +
            require 'virtus/typecast/string'
         | 
| 53 63 | 
             
            require 'virtus/typecast/time'
         | 
| 54 64 |  | 
| 55 65 | 
             
            require 'virtus/attribute'
         | 
    
        data/lib/virtus/attribute.rb
    CHANGED
    
    | @@ -1,8 +1,11 @@ | |
| 1 1 | 
             
            module Virtus
         | 
| 2 | 
            +
             | 
| 2 3 | 
             
              # Abstract class implementing base API for attribute types
         | 
| 3 4 | 
             
              #
         | 
| 4 5 | 
             
              # @abstract
         | 
| 5 6 | 
             
              class Attribute
         | 
| 7 | 
            +
                extend DescendantsTracker
         | 
| 8 | 
            +
             | 
| 6 9 | 
             
                # Returns default options hash for a given attribute class
         | 
| 7 10 | 
             
                #
         | 
| 8 11 | 
             
                # @example
         | 
| @@ -15,9 +18,9 @@ module Virtus | |
| 15 18 | 
             
                # @api public
         | 
| 16 19 | 
             
                def self.options
         | 
| 17 20 | 
             
                  options = {}
         | 
| 18 | 
            -
                  accepted_options.each do | | 
| 19 | 
            -
                     | 
| 20 | 
            -
                    options[ | 
| 21 | 
            +
                  accepted_options.each do |option_name|
         | 
| 22 | 
            +
                    option_value         = send(option_name)
         | 
| 23 | 
            +
                    options[option_name] = option_value unless option_value.nil?
         | 
| 21 24 | 
             
                  end
         | 
| 22 25 | 
             
                  options
         | 
| 23 26 | 
             
                end
         | 
| @@ -47,14 +50,15 @@ module Virtus | |
| 47 50 | 
             
                #   All accepted options
         | 
| 48 51 | 
             
                #
         | 
| 49 52 | 
             
                # @api public
         | 
| 50 | 
            -
                def self.accept_options(* | 
| 51 | 
            -
                   | 
| 53 | 
            +
                def self.accept_options(*new_options)
         | 
| 54 | 
            +
                  # add new options to the array
         | 
| 55 | 
            +
                  concat_options(new_options)
         | 
| 52 56 |  | 
| 53 57 | 
             
                  # create methods for each new option
         | 
| 54 | 
            -
                   | 
| 58 | 
            +
                  new_options.each { |option| add_option_method(option) }
         | 
| 55 59 |  | 
| 56 60 | 
             
                  # add new options to all descendants
         | 
| 57 | 
            -
                  descendants.each { |descendant| descendant. | 
| 61 | 
            +
                  descendants.each { |descendant| descendant.concat_options(new_options) }
         | 
| 58 62 |  | 
| 59 63 | 
             
                  accepted_options
         | 
| 60 64 | 
             
                end
         | 
| @@ -72,34 +76,61 @@ module Virtus | |
| 72 76 | 
             
                    end                                            # end
         | 
| 73 77 | 
             
                  RUBY
         | 
| 74 78 | 
             
                end
         | 
| 79 | 
            +
             | 
| 75 80 | 
             
                private_class_method :add_option_method
         | 
| 76 81 |  | 
| 77 | 
            -
                #  | 
| 82 | 
            +
                # Sets default options
         | 
| 78 83 | 
             
                #
         | 
| 79 | 
            -
                # @ | 
| 80 | 
            -
                #    | 
| 81 | 
            -
                # | 
| 84 | 
            +
                # @param [#to_hash] new_options
         | 
| 85 | 
            +
                #   options to be set
         | 
| 86 | 
            +
                #
         | 
| 87 | 
            +
                # @return [Hash]
         | 
| 88 | 
            +
                #   default options set on the attribute class
         | 
| 89 | 
            +
                #
         | 
| 90 | 
            +
                # @api private
         | 
| 91 | 
            +
                def self.set_options(new_options)
         | 
| 92 | 
            +
                  new_options.to_hash.each do |option_name, option_value|
         | 
| 93 | 
            +
                    send(option_name, option_value)
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                # Adds new options that an attribute class can accept
         | 
| 98 | 
            +
                #
         | 
| 99 | 
            +
                # @param [#to_ary] new_options
         | 
| 100 | 
            +
                #   new options to be added
         | 
| 82 101 | 
             
                #
         | 
| 83 102 | 
             
                # @return [Array]
         | 
| 84 | 
            -
                #    | 
| 103 | 
            +
                #   all accepted options
         | 
| 85 104 | 
             
                #
         | 
| 86 | 
            -
                # @api  | 
| 87 | 
            -
                def self. | 
| 88 | 
            -
                   | 
| 105 | 
            +
                # @api private
         | 
| 106 | 
            +
                def self.concat_options(new_options)
         | 
| 107 | 
            +
                  accepted_options.concat(new_options.to_ary).uniq
         | 
| 89 108 | 
             
                end
         | 
| 90 109 |  | 
| 91 110 | 
             
                # Adds descendant to descendants array and inherits default options
         | 
| 92 111 | 
             
                #
         | 
| 93 | 
            -
                # @param [Class]
         | 
| 112 | 
            +
                # @param [Class] descendant
         | 
| 94 113 | 
             
                #
         | 
| 95 | 
            -
                # @return [ | 
| 114 | 
            +
                # @return [self]
         | 
| 96 115 | 
             
                #
         | 
| 97 116 | 
             
                # @api private
         | 
| 98 117 | 
             
                def self.inherited(descendant)
         | 
| 99 | 
            -
                   | 
| 100 | 
            -
                  descendant. | 
| 101 | 
            -
                   | 
| 102 | 
            -
                   | 
| 118 | 
            +
                  super
         | 
| 119 | 
            +
                  descendant.concat_options(accepted_options)
         | 
| 120 | 
            +
                  descendant.set_options(options)
         | 
| 121 | 
            +
                  self
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                # Returns if the given value's class is an attribute's primitive
         | 
| 125 | 
            +
                #
         | 
| 126 | 
            +
                # @example
         | 
| 127 | 
            +
                #   Virtus::Attribute::String.primitive?('String') # => true
         | 
| 128 | 
            +
                #
         | 
| 129 | 
            +
                # @return [TrueClass, FalseClass]
         | 
| 130 | 
            +
                #
         | 
| 131 | 
            +
                # @api semipublic
         | 
| 132 | 
            +
                def self.primitive?(value)
         | 
| 133 | 
            +
                  value.kind_of?(primitive)
         | 
| 103 134 | 
             
                end
         | 
| 104 135 |  | 
| 105 136 | 
             
                # Returns name of the attribute
         | 
| @@ -112,13 +143,6 @@ module Virtus | |
| 112 143 | 
             
                # @api public
         | 
| 113 144 | 
             
                attr_reader :name
         | 
| 114 145 |  | 
| 115 | 
            -
                # Returns primitive class of the attribute
         | 
| 116 | 
            -
                #
         | 
| 117 | 
            -
                # @return [Class]
         | 
| 118 | 
            -
                #
         | 
| 119 | 
            -
                # @api private
         | 
| 120 | 
            -
                attr_reader :primitive
         | 
| 121 | 
            -
             | 
| 122 146 | 
             
                # Returns options hash for the attribute
         | 
| 123 147 | 
             
                #
         | 
| 124 148 | 
             
                # @return [Hash]
         | 
| @@ -140,7 +164,6 @@ module Virtus | |
| 140 164 | 
             
                # @api private
         | 
| 141 165 | 
             
                attr_reader :reader_visibility
         | 
| 142 166 |  | 
| 143 | 
            -
             | 
| 144 167 | 
             
                # Returns write visibility
         | 
| 145 168 | 
             
                #
         | 
| 146 169 | 
             
                # @return [Symbol]
         | 
| @@ -148,7 +171,7 @@ module Virtus | |
| 148 171 | 
             
                # @api private
         | 
| 149 172 | 
             
                attr_reader :writer_visibility
         | 
| 150 173 |  | 
| 151 | 
            -
                DEFAULT_ACCESSOR = :public | 
| 174 | 
            +
                DEFAULT_ACCESSOR = :public
         | 
| 152 175 |  | 
| 153 176 | 
             
                OPTIONS = [ :primitive, :complex, :accessor, :reader, :writer ].freeze
         | 
| 154 177 |  | 
| @@ -159,21 +182,18 @@ module Virtus | |
| 159 182 | 
             
                # @param [Symbol] name
         | 
| 160 183 | 
             
                #   the name of an attribute
         | 
| 161 184 | 
             
                #
         | 
| 162 | 
            -
                # @param [ | 
| 185 | 
            +
                # @param [#to_hash] options
         | 
| 163 186 | 
             
                #   hash of extra options which overrides defaults set on an attribute class
         | 
| 164 187 | 
             
                #
         | 
| 165 188 | 
             
                # @api private
         | 
| 166 189 | 
             
                def initialize(name, options = {})
         | 
| 167 190 | 
             
                  @name    = name
         | 
| 168 | 
            -
                  @options = self.class.options.merge(options).freeze
         | 
| 169 | 
            -
             | 
| 170 | 
            -
                  @primitive = @options[:primitive]
         | 
| 191 | 
            +
                  @options = self.class.options.merge(options.to_hash).freeze
         | 
| 171 192 |  | 
| 172 193 | 
             
                  @instance_variable_name = "@#{@name}".freeze
         | 
| 194 | 
            +
                  @complex                = @options.fetch(:complex, false)
         | 
| 173 195 |  | 
| 174 | 
            -
                   | 
| 175 | 
            -
                  @reader_visibility = @options.fetch(:reader, default_accessor)
         | 
| 176 | 
            -
                  @writer_visibility = @options.fetch(:writer, default_accessor)
         | 
| 196 | 
            +
                  set_visibility
         | 
| 177 197 | 
             
                end
         | 
| 178 198 |  | 
| 179 199 | 
             
                # Returns if an attribute is a complex one
         | 
| @@ -186,16 +206,7 @@ module Virtus | |
| 186 206 | 
             
                #
         | 
| 187 207 | 
             
                # @api semipublic
         | 
| 188 208 | 
             
                def complex?
         | 
| 189 | 
            -
                   | 
| 190 | 
            -
                end
         | 
| 191 | 
            -
             | 
| 192 | 
            -
                # Returns if the given value's class is an attribute's primitive
         | 
| 193 | 
            -
                #
         | 
| 194 | 
            -
                # @return [TrueClass, FalseClass]
         | 
| 195 | 
            -
                #
         | 
| 196 | 
            -
                # @api private
         | 
| 197 | 
            -
                def primitive?(value)
         | 
| 198 | 
            -
                  value.kind_of?(primitive)
         | 
| 209 | 
            +
                  @complex
         | 
| 199 210 | 
             
                end
         | 
| 200 211 |  | 
| 201 212 | 
             
                # Converts the given value to the primitive type
         | 
| @@ -208,7 +219,7 @@ module Virtus | |
| 208 219 | 
             
                #
         | 
| 209 220 | 
             
                # @api private
         | 
| 210 221 | 
             
                def typecast(value)
         | 
| 211 | 
            -
                  if value.nil? || primitive?(value)
         | 
| 222 | 
            +
                  if value.nil? || self.class.primitive?(value)
         | 
| 212 223 | 
             
                    value
         | 
| 213 224 | 
             
                  else
         | 
| 214 225 | 
             
                    typecast_to_primitive(value)
         | 
| @@ -268,17 +279,21 @@ module Virtus | |
| 268 279 | 
             
                #
         | 
| 269 280 | 
             
                # @api private
         | 
| 270 281 | 
             
                def add_reader_method(model)
         | 
| 271 | 
            -
                   | 
| 272 | 
            -
             | 
| 273 | 
            -
                      #{reader_visibility}
         | 
| 282 | 
            +
                  instance_variable_name = self.instance_variable_name
         | 
| 283 | 
            +
                  method_name            = name
         | 
| 274 284 |  | 
| 275 | 
            -
             | 
| 285 | 
            +
                  model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 286 | 
            +
                    module AttributeMethods
         | 
| 287 | 
            +
                      def #{method_name}
         | 
| 276 288 | 
             
                        return #{instance_variable_name} if defined?(#{instance_variable_name})
         | 
| 277 | 
            -
                        attribute = self.class.attributes[#{ | 
| 289 | 
            +
                        attribute = self.class.attributes[#{method_name.inspect}]
         | 
| 278 290 | 
             
                        #{instance_variable_name} = attribute ? attribute.get(self) : nil
         | 
| 279 291 | 
             
                      end
         | 
| 280 292 | 
             
                    end
         | 
| 293 | 
            +
                    include AttributeMethods
         | 
| 281 294 | 
             
                  RUBY
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                  model.send(reader_visibility, method_name)
         | 
| 282 297 | 
             
                end
         | 
| 283 298 |  | 
| 284 299 | 
             
                # Creates an attribute writer method
         | 
| @@ -287,15 +302,33 @@ module Virtus | |
| 287 302 | 
             
                #
         | 
| 288 303 | 
             
                # @api private
         | 
| 289 304 | 
             
                def add_writer_method(model)
         | 
| 290 | 
            -
                   | 
| 291 | 
            -
             | 
| 292 | 
            -
                      #{writer_visibility}
         | 
| 305 | 
            +
                  name        = self.name
         | 
| 306 | 
            +
                  method_name = "#{name}="
         | 
| 293 307 |  | 
| 294 | 
            -
             | 
| 308 | 
            +
                  model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
         | 
| 309 | 
            +
                    module AttributeMethods
         | 
| 310 | 
            +
                      def #{method_name}(value)
         | 
| 295 311 | 
             
                        self.class.attributes[#{name.inspect}].set(self, value)
         | 
| 296 312 | 
             
                      end
         | 
| 297 313 | 
             
                    end
         | 
| 314 | 
            +
                    include AttributeMethods
         | 
| 298 315 | 
             
                  RUBY
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                  model.send(writer_visibility, method_name)
         | 
| 299 318 | 
             
                end
         | 
| 300 | 
            -
             | 
| 301 | 
            -
             | 
| 319 | 
            +
             | 
| 320 | 
            +
              private
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                # Sets visibility of reader/write methods based on the options hash
         | 
| 323 | 
            +
                #
         | 
| 324 | 
            +
                # @return [undefined]
         | 
| 325 | 
            +
                #
         | 
| 326 | 
            +
                # @api private
         | 
| 327 | 
            +
                def set_visibility
         | 
| 328 | 
            +
                  default_accessor   = @options.fetch(:accessor, self.class::DEFAULT_ACCESSOR)
         | 
| 329 | 
            +
                  @reader_visibility = @options.fetch(:reader, default_accessor)
         | 
| 330 | 
            +
                  @writer_visibility = @options.fetch(:writer, default_accessor)
         | 
| 331 | 
            +
                end
         | 
| 332 | 
            +
             | 
| 333 | 
            +
              end # class Attribute
         | 
| 334 | 
            +
            end # module Virtus
         |