virtus 0.3.0 → 0.4.0

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.
Files changed (62) hide show
  1. data/Changelog.md +10 -2
  2. data/Guardfile +9 -0
  3. data/README.md +12 -8
  4. data/TODO +0 -35
  5. data/config/flay.yml +1 -1
  6. data/config/site.reek +3 -1
  7. data/lib/virtus.rb +1 -0
  8. data/lib/virtus/attribute.rb +1 -1
  9. data/lib/virtus/attribute/collection.rb +2 -2
  10. data/lib/virtus/attribute/default_value/from_symbol.rb +2 -2
  11. data/lib/virtus/attribute_set.rb +4 -17
  12. data/lib/virtus/attributes_accessor.rb +22 -20
  13. data/lib/virtus/class_methods.rb +1 -1
  14. data/lib/virtus/coercion/hash.rb +1 -1
  15. data/lib/virtus/coercion/object.rb +1 -1
  16. data/lib/virtus/coercion/string.rb +20 -7
  17. data/lib/virtus/coercion/time_coercions.rb +5 -1
  18. data/lib/virtus/instance_methods.rb +8 -8
  19. data/lib/virtus/support/type_lookup.rb +24 -8
  20. data/lib/virtus/value_object/equalizer.rb +3 -2
  21. data/lib/virtus/version.rb +1 -1
  22. data/spec/shared/options_class_method.rb +1 -1
  23. data/spec/spec_helper.rb +1 -1
  24. data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +1 -7
  25. data/spec/unit/virtus/attribute/coerce_spec.rb +2 -2
  26. data/spec/unit/virtus/attribute/collection/coerce_and_append_member_spec.rb +16 -0
  27. data/spec/unit/virtus/attribute/collection/coerce_spec.rb +20 -7
  28. data/spec/unit/virtus/attribute/collection/member_coercion/coerce_and_append_member_spec.rb +18 -0
  29. data/spec/unit/virtus/attribute/collection/member_type_spec.rb +17 -0
  30. data/spec/unit/virtus/attribute/collection/new_collection_spec.rb +9 -0
  31. data/spec/unit/virtus/attribute/default_value/class_methods/build_spec.rb +25 -0
  32. data/spec/unit/virtus/attribute/default_value/evaluate_spec.rb +0 -43
  33. data/spec/unit/virtus/attribute/default_value/from_callable/class_methods/handle_spec.rb +20 -0
  34. data/spec/unit/virtus/attribute/default_value/from_callable/evaluate_spec.rb +21 -0
  35. data/spec/unit/virtus/attribute/default_value/from_clonable/class_methods/handle_spec.rb +20 -0
  36. data/spec/unit/virtus/attribute/default_value/from_clonable/evaluate_spec.rb +22 -0
  37. data/spec/unit/virtus/attribute/default_value/from_symbol/class_methods/handle_spec.rb +20 -0
  38. data/spec/unit/virtus/attribute/default_value/from_symbol/evaluate_spec.rb +18 -0
  39. data/spec/unit/virtus/attribute_set/element_set_spec.rb +5 -4
  40. data/spec/unit/virtus/attributes_accessor/define_reader_method_spec.rb +36 -0
  41. data/spec/unit/virtus/attributes_accessor/define_writer_method_spec.rb +36 -0
  42. data/spec/unit/virtus/coercion/array/{to_set_spec.rb → class_methods/to_set_spec.rb} +0 -0
  43. data/spec/unit/virtus/coercion/{class_name_reference_spec.rb → class_methods/element_reference_spec.rb} +0 -0
  44. data/spec/unit/virtus/coercion/class_methods/primitive_spec.rb +13 -0
  45. data/spec/unit/virtus/coercion/decimal/class_methods/to_decimal_spec.rb +10 -0
  46. data/spec/unit/virtus/coercion/float/class_methods/to_float_spec.rb +10 -0
  47. data/spec/unit/virtus/coercion/integer/class_methods/to_integer_spec.rb +10 -0
  48. data/spec/unit/virtus/coercion/numeric/class_methods/to_decimal_spec.rb +0 -0
  49. data/spec/unit/virtus/coercion/numeric/class_methods/to_float_spec.rb +0 -0
  50. data/spec/unit/virtus/coercion/numeric/class_methods/to_integer_spec.rb +0 -0
  51. data/spec/unit/virtus/coercion/numeric/class_methods/to_string_spec.rb +0 -0
  52. data/spec/unit/virtus/coercion/object/class_methods/to_string_spec.rb +1 -1
  53. data/spec/unit/virtus/coercion/string/class_methods/to_symbol_spec.rb +10 -0
  54. data/spec/unit/virtus/coercion/time/class_methods/to_integer_spec.rb +11 -0
  55. data/spec/unit/virtus/instance_methods/attributes_spec.rb +25 -0
  56. data/spec/unit/virtus/instance_methods/initialize_spec.rb +42 -0
  57. data/spec/unit/virtus/type_lookup/class_methods/extended_spec.rb +10 -0
  58. data/spec/unit/virtus/value_object/class_methods/attribute_spec.rb +16 -0
  59. data/spec/unit/virtus/value_object/equalizer/append_spec.rb +61 -0
  60. data/virtus.gemspec +4 -3
  61. metadata +80 -75
  62. data/spec/unit/virtus/attribute_set/parent_spec.rb +0 -11
@@ -1,4 +1,12 @@
1
- # v0.3.0 to-be-released
1
+ # v0.4.0 2012-03-22
2
+
3
+ * [improvement] Add a caching mechanism for type lookups (solnic)
4
+ * [fixed] Fix attributes mass-assignment when nil is passed (fgrehm)
5
+ * [changed] Replace usage of #to_hash with Hash.try_convert (dkubb)
6
+
7
+ [Compare v0.3.0..v0.4.0](https://github.com/solnic/virtus/compare/v0.3.0...master)
8
+
9
+ # v0.3.0 2012-02-25
2
10
 
3
11
  * [feature] Support for default values from a symbol (which can be a method name) (solnic)
4
12
  * [feature] Support for mass-assignment via custom setters not generated with attribute (fgrehm)
@@ -13,7 +21,7 @@
13
21
  * [BREAKING CHANGE] Removed Attribute#instance_variable_name - this is a private ivar (solnic)
14
22
  * [BREAKING CHANGE] Removed Equalizer#host_name and Equalizer#keys (solnic)
15
23
 
16
- [Compare v0.2.0..master](https://github.com/solnic/virtus/compare/v0.2.0...master)
24
+ [Compare v0.2.0..v0.3.0](https://github.com/solnic/virtus/compare/v0.2.0...v0.3.0)
17
25
 
18
26
  # v0.2.0 2012-02-08
19
27
 
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 1 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
data/README.md CHANGED
@@ -61,13 +61,16 @@ class Page
61
61
  include Virtus
62
62
 
63
63
  attribute :title, String
64
-
64
+
65
65
  # default from a singleton value (integer in this case)
66
66
  attribute :views, Integer, :default => 0
67
-
67
+
68
+ # default from a singleton value (boolean in this case)
69
+ attribute :published, Boolean, :default => false
70
+
68
71
  # default from a callable object (proc in this case)
69
72
  attribute :slug, String, :default => lambda { |page, attribute| page.title.downcase.gsub(' ', '-') }
70
-
73
+
71
74
  # default from a method name as symbol
72
75
  attribute :editor_title, String, :default => :default_editor_title
73
76
 
@@ -76,10 +79,11 @@ class Page
76
79
  end
77
80
  end
78
81
 
79
- page = Page.new(:title => 'Virtus Is Awesome', :editor_title => 'Virtus README')
80
- page.slug # => 'virtus-is-awesome'
81
- page.views # => 0
82
- page.editor_title # => "UNPUBSLISHED: Virtus README"
82
+ page = Page.new(:title => 'Virtus README')
83
+ page.slug # => 'virtus-readme'
84
+ page.views # => 0
85
+ page.published # => false
86
+ page.editor_title # => "UNPUBLISHED: Virtus README"
83
87
  ```
84
88
 
85
89
  **Embedded Value**
@@ -238,7 +242,7 @@ user.password # => '3858f62230ac3c915f300c664312c63f'
238
242
  ``` ruby
239
243
  require 'json'
240
244
 
241
- module MyAppClass
245
+ module MyApp
242
246
 
243
247
  # Defining the custom attribute(s)
244
248
  module Attributes
data/TODO CHANGED
@@ -1,36 +1 @@
1
- * Add missing specs:
2
- * Add spec file spec/unit/virtus/attribute/collection/member_coercion/coerce_and_append_member_spec.rb for Virtus::Attribute::Collection::MemberCoercion#coerce_and_append_member
3
- * Add spec file spec/unit/virtus/attribute/collection/member_type_spec.rb for Virtus::Attribute::Collection#member_type
4
- * Add spec file spec/unit/virtus/attribute/collection/new_collection_spec.rb for Virtus::Attribute::Collection#new_collection
5
- * Add spec file spec/unit/virtus/attribute/collection/coerce_and_append_member_spec.rb for Virtus::Attribute::Collection#coerce_and_append_member
6
- * Add spec file spec/unit/virtus/attribute/default_value/from_symbol/class_methods/handle_spec.rb for Virtus::Attribute::DefaultValue::FromSymbol.handle?
7
- * Add spec file spec/unit/virtus/attribute/default_value/from_symbol/evaluate_spec.rb for Virtus::Attribute::DefaultValue::FromSymbol#evaluate
8
- * Add spec file spec/unit/virtus/attribute/default_value/from_callable/class_methods/handle_spec.rb for Virtus::Attribute::DefaultValue::FromCallable.handle?
9
- * Add spec file spec/unit/virtus/attribute/default_value/from_callable/evaluate_spec.rb for Virtus::Attribute::DefaultValue::FromCallable#evaluate
10
- * Add spec file spec/unit/virtus/attribute/default_value/from_clonable/class_methods/handle_spec.rb for Virtus::Attribute::DefaultValue::FromClonable.handle?
11
- * Add spec file spec/unit/virtus/attribute/default_value/from_clonable/evaluate_spec.rb for Virtus::Attribute::DefaultValue::FromClonable#evaluate
12
- * Add spec file spec/unit/virtus/attribute/default_value/class_methods/build_spec.rb for Virtus::Attribute::DefaultValue.build
13
- * Add spec file spec/unit/virtus/coercion/string/class_methods/to_symbol_spec.rb for Virtus::Coercion::String.to_symbol
14
- * Add spec file spec/unit/virtus/coercion/time/class_methods/to_integer_spec.rb for Virtus::Coercion::Time.to_integer
15
- * Add spec file spec/unit/virtus/coercion/time_coercions/to_datetime_spec.rb for Virtus::Coercion::TimeCoercions#to_datetime
16
- * Add spec file spec/unit/virtus/coercion/time_coercions/to_time_spec.rb for Virtus::Coercion::TimeCoercions#to_time
17
- * Add spec file spec/unit/virtus/coercion/time_coercions/to_date_spec.rb for Virtus::Coercion::TimeCoercions#to_date
18
- * Add spec file spec/unit/virtus/coercion/time_coercions/to_string_spec.rb for Virtus::Coercion::TimeCoercions#to_string
19
- * Add spec file spec/unit/virtus/coercion/array/class_methods/to_set_spec.rb for Virtus::Coercion::Array.to_set
20
- * Add spec file spec/unit/virtus/coercion/decimal/class_methods/to_decimal_spec.rb for Virtus::Coercion::Decimal.to_decimal
21
- * Add spec file spec/unit/virtus/coercion/float/class_methods/to_float_spec.rb for Virtus::Coercion::Float.to_float
22
- * Add spec file spec/unit/virtus/coercion/integer/class_methods/to_integer_spec.rb for Virtus::Coercion::Integer.to_integer
23
- * Add spec file spec/unit/virtus/coercion/numeric/class_methods/to_decimal_spec.rb for Virtus::Coercion::Numeric.to_decimal
24
- * Add spec file spec/unit/virtus/coercion/numeric/class_methods/to_float_spec.rb for Virtus::Coercion::Numeric.to_float
25
- * Add spec file spec/unit/virtus/coercion/numeric/class_methods/to_integer_spec.rb for Virtus::Coercion::Numeric.to_integer
26
- * Add spec file spec/unit/virtus/coercion/numeric/class_methods/to_string_spec.rb for Virtus::Coercion::Numeric.to_string
27
- * Add spec file spec/unit/virtus/coercion/class_methods/element_reference_spec.rb for Virtus::Coercion.[]
28
- * Add spec file spec/unit/virtus/coercion/class_methods/primitive_spec.rb for Virtus::Coercion.primitive
29
- * Add spec file spec/unit/virtus/value_object/class_methods/attribute_spec.rb for Virtus::ValueObject::ClassMethods#attribute
30
- * Add spec file spec/unit/virtus/value_object/instance_methods/with_spec.rb for Virtus::ValueObject::InstanceMethods#with
31
- * Add spec file spec/unit/virtus/value_object/equalizer/append_spec.rb for Virtus::ValueObject::Equalizer#<<
32
- * Add spec file spec/unit/virtus/value_object/equalizer/compile_spec.rb for Virtus::ValueObject::Equalizer#compile
33
- * Add spec file spec/unit/virtus/attributes_accessor/define_reader_method_spec.rb for Virtus::AttributesAccessor#define_reader_method
34
- * Add spec file spec/unit/virtus/attributes_accessor/define_writer_method_spec.rb for Virtus::AttributesAccessor#define_writer_method
35
-
36
1
  * Make #to_time #to_date and #to_datetime work on Ruby 1.8.7 instead of typecasting to string and parsing the value
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 19
3
- total_score: 326
3
+ total_score: 344
@@ -94,7 +94,9 @@ DataClump:
94
94
  max_copies: 2
95
95
  min_clump_size: 2
96
96
  ControlCouple:
97
- exclude: []
97
+ exclude: [
98
+ 'Virtus::InstanceMethods#initialize'
99
+ ]
98
100
  enabled: true
99
101
  LongYieldList:
100
102
  max_params: 1
@@ -83,3 +83,4 @@ require 'virtus/attribute/symbol'
83
83
  require 'virtus/attribute/string'
84
84
  require 'virtus/attribute/time'
85
85
  require 'virtus/attribute/embedded_value'
86
+
@@ -217,7 +217,7 @@ module Virtus
217
217
  #
218
218
  # @api public
219
219
  def coerce(value)
220
- Coercion[value.class].send(coercion_method, value)
220
+ Coercion[value.class].public_send(coercion_method, value)
221
221
  end
222
222
 
223
223
  # Is the given value coerced into the target type for this attribute?
@@ -63,8 +63,8 @@ module Virtus
63
63
  def coerce(value)
64
64
  coerced = super
65
65
  return coerced unless coerced.respond_to?(:inject)
66
- coerced.inject(new_collection) do |collection, entry|
67
- coerce_and_append_member(collection, entry)
66
+ coerced.inject(new_collection) do |*args|
67
+ coerce_and_append_member(*args)
68
68
  end
69
69
  end
70
70
 
@@ -16,7 +16,7 @@ module Virtus
16
16
  value.is_a?(::Symbol)
17
17
  end
18
18
 
19
- # Evaluates the value via instance#__send__(value)
19
+ # Evaluates the value via instance#public_send(value)
20
20
  #
21
21
  # Symbol value is returned if the instance doesn't respond to value
22
22
  #
@@ -26,7 +26,7 @@ module Virtus
26
26
  #
27
27
  # @api private
28
28
  def evaluate(instance)
29
- instance.respond_to?(@value) ? instance.__send__(@value) : @value
29
+ instance.respond_to?(@value) ? instance.public_send(@value) : @value
30
30
  end
31
31
 
32
32
  end # class FromSymbol
@@ -4,17 +4,6 @@ module Virtus
4
4
  class AttributeSet
5
5
  include Enumerable
6
6
 
7
- # Return the parent attributes
8
- #
9
- # @return [AttributeSet]
10
- # the parent attributes
11
- #
12
- # @return [nil]
13
- # nil if there are no parent attributes
14
- #
15
- # @api private
16
- attr_reader :parent
17
-
18
7
  # Initialize an AttributeSet
19
8
  #
20
9
  # @param [AttributeSet] parent
@@ -27,7 +16,6 @@ module Virtus
27
16
  @parent = parent
28
17
  @attributes = attributes.dup
29
18
  @index = {}
30
- @string_index = {}
31
19
  reset
32
20
  end
33
21
 
@@ -47,7 +35,7 @@ module Virtus
47
35
  # @api public
48
36
  def each
49
37
  return to_enum unless block_given?
50
- @index.each_value { |attribute| yield attribute }
38
+ @index.values.uniq.each { |attribute| yield attribute }
51
39
  self
52
40
  end
53
41
 
@@ -92,7 +80,7 @@ module Virtus
92
80
  #
93
81
  # @api public
94
82
  def [](name)
95
- @index.fetch(name) { @string_index[name] }
83
+ @index[name]
96
84
  end
97
85
 
98
86
  # Set an attribute by name
@@ -117,8 +105,7 @@ module Virtus
117
105
  #
118
106
  # @api private
119
107
  def reset
120
- parent = self.parent
121
- merge_attributes(parent) if parent
108
+ merge_attributes(@parent) if @parent
122
109
  merge_attributes(@attributes)
123
110
  self
124
111
  end
@@ -146,7 +133,7 @@ module Virtus
146
133
  #
147
134
  # @api private
148
135
  def update_index(name, attribute)
149
- @index[name] = @string_index[name.to_s.freeze] = attribute
136
+ @index[name] = @index[name.to_s.freeze] = attribute
150
137
  end
151
138
 
152
139
  end # class AttributeSet
@@ -3,25 +3,6 @@ module Virtus
3
3
  # Host attribute accessor methods
4
4
  class AttributesAccessor < Module
5
5
 
6
- # The inspect value of this Module
7
- #
8
- # This provides meaningful output when inspecting the ancestors
9
- # of a class/module that includes this module
10
- #
11
- # @example
12
- #
13
- # class ClassWithAttributes
14
- # include Virtus
15
- # end
16
- #
17
- # mod = ClassWithAttributes.send(:virtus_setup_attributes_accessor_module)
18
- # mod.inspect
19
- #
20
- # @return [String]
21
- #
22
- # @api public
23
- attr_reader :inspect
24
-
25
6
  # Initialize a module for hosting Attribute access methods
26
7
  #
27
8
  # @param [Symbol, String] name
@@ -29,7 +10,7 @@ module Virtus
29
10
  # @api private
30
11
  def initialize(name)
31
12
  super()
32
- @inspect = "#{name}::AttributesAccessor"
13
+ @name = name
33
14
  end
34
15
 
35
16
  # Defines an attribute reader method
@@ -62,5 +43,26 @@ module Virtus
62
43
  self
63
44
  end
64
45
 
46
+ # The inspect value of this Module
47
+ #
48
+ # This provides meaningful output when inspecting the ancestors
49
+ # of a class/module that includes this module
50
+ #
51
+ # @example
52
+ #
53
+ # class ClassWithAttributes
54
+ # include Virtus
55
+ # end
56
+ #
57
+ # mod = ClassWithAttributes.send(:virtus_setup_attributes_accessor_module)
58
+ # mod.inspect
59
+ #
60
+ # @return [String]
61
+ #
62
+ # @api public
63
+ def inspect
64
+ "#{@name}::AttributesAccessor"
65
+ end
66
+
65
67
  end
66
68
  end
@@ -76,7 +76,7 @@ module Virtus
76
76
  return @attributes if defined?(@attributes)
77
77
  superclass = self.superclass
78
78
  method = __method__
79
- parent = superclass.send(method) if superclass.respond_to?(method)
79
+ parent = superclass.public_send(method) if superclass.respond_to?(method)
80
80
  @attributes = AttributeSet.new(parent)
81
81
  end
82
82
 
@@ -59,7 +59,7 @@ module Virtus
59
59
  now = ::Time.now
60
60
 
61
61
  TIME_SEGMENTS.map do |segment|
62
- val = value.fetch(segment, now.send(segment))
62
+ val = value.fetch(segment, now.public_send(segment))
63
63
  Coercion[val.class.name].to_integer(val)
64
64
  end
65
65
  end
@@ -115,7 +115,7 @@ module Virtus
115
115
  #
116
116
  # @api private
117
117
  def self.coerce_with_method(value, method)
118
- value.respond_to?(method) ? value.send(method) : value
118
+ value.respond_to?(method) ? value.public_send(method) : value
119
119
  end
120
120
 
121
121
  private_class_method :coerce_with_method
@@ -27,15 +27,28 @@ module Virtus
27
27
  def self.to_constant(value)
28
28
  names = value.split('::')
29
29
  names.shift if names.first.empty?
30
- names.inject(::Object) do |mod, name|
31
- if mod.const_defined?(name, *EXTRA_CONST_ARGS)
32
- mod.const_get(name, *EXTRA_CONST_ARGS)
33
- else
34
- mod.const_missing(name)
35
- end
30
+ names.inject(::Object) { |*args| constant_lookup(*args) }
31
+ end
32
+
33
+ # Lookup a constant within a module
34
+ #
35
+ # @param [Module] mod
36
+ #
37
+ # @param [String] name
38
+ #
39
+ # @return [Object]
40
+ #
41
+ # @api private
42
+ def self.constant_lookup(mod, name)
43
+ if mod.const_defined?(name, *EXTRA_CONST_ARGS)
44
+ mod.const_get(name, *EXTRA_CONST_ARGS)
45
+ else
46
+ mod.const_missing(name)
36
47
  end
37
48
  end
38
49
 
50
+ private_class_method :constant_lookup
51
+
39
52
  # Coerce give value to a symbol
40
53
  #
41
54
  # @example
@@ -167,7 +180,7 @@ module Virtus
167
180
  # @api private
168
181
  def self.to_numeric(value, method)
169
182
  if value =~ NUMERIC_REGEXP
170
- $1.send(method)
183
+ $1.public_send(method)
171
184
  else
172
185
  value
173
186
  end
@@ -74,7 +74,11 @@ module Virtus
74
74
  # @api private
75
75
  def coerce_with_method(value, method)
76
76
  coerced = super
77
- coerced.equal?(value) ? String.send(method, to_string(value)) : coerced
77
+ if coerced.equal?(value)
78
+ String.public_send(method, to_string(value))
79
+ else
80
+ coerced
81
+ end
78
82
  end
79
83
 
80
84
  end # module TimeCoercions
@@ -11,8 +11,8 @@ module Virtus
11
11
  # @return [undefined]
12
12
  #
13
13
  # @api private
14
- def initialize(attribute_values = {})
15
- self.attributes = attribute_values
14
+ def initialize(attributes = nil)
15
+ self.attributes = attributes if attributes
16
16
  end
17
17
 
18
18
  # Returns a value of the attribute with the given name
@@ -87,7 +87,7 @@ module Virtus
87
87
 
88
88
  # Mass-assign attribute values
89
89
  #
90
- # Keys in the +attribute_values+ param can be symbols or strings.
90
+ # Keys in the +attributes+ param can be symbols or strings.
91
91
  # All referenced Attribute writer methods *will* be called.
92
92
  # Non-attribute setter methods on the receiver *will* be called.
93
93
  #
@@ -102,14 +102,14 @@ module Virtus
102
102
  # user = User.new
103
103
  # user.attributes = { :name => 'John', 'age' => 28 }
104
104
  #
105
- # @param [#to_hash] attribute_values
105
+ # @param [#to_hash] attributes
106
106
  # a hash of attribute names and values to set on the receiver
107
107
  #
108
108
  # @return [Hash]
109
109
  #
110
110
  # @api public
111
- def attributes=(attribute_values)
112
- set_attributes(attribute_values)
111
+ def attributes=(attributes)
112
+ set_attributes(attributes)
113
113
  end
114
114
 
115
115
  # Returns a hash of all publicly accessible attributes
@@ -153,8 +153,8 @@ module Virtus
153
153
  # @return [Hash]
154
154
  #
155
155
  # @api private
156
- def set_attributes(attribute_values)
157
- attribute_values.each do |name, value|
156
+ def set_attributes(attributes)
157
+ ::Hash.try_convert(attributes).each do |name, value|
158
158
  set_attribute(name, value) if self.class.allowed_writer_methods.include?("#{name}=")
159
159
  end
160
160
  end
@@ -5,6 +5,17 @@ module Virtus
5
5
 
6
6
  TYPE_FORMAT = /\A[A-Z]\w*\z/.freeze
7
7
 
8
+ # Set cache ivar on the model
9
+ #
10
+ # @param [Class] model
11
+ #
12
+ # @return [undefined]
13
+ #
14
+ # @api private
15
+ def self.extended(model)
16
+ model.instance_variable_set('@type_lookup_cache', {})
17
+ end
18
+
8
19
  # Returns a descendant based on a name or class
9
20
  #
10
21
  # @example
@@ -21,14 +32,7 @@ module Virtus
21
32
  #
22
33
  # @api public
23
34
  def determine_type(class_or_name)
24
- case class_or_name
25
- when singleton_class
26
- determine_type_from_descendant(class_or_name)
27
- when Class
28
- determine_type_from_primitive(class_or_name)
29
- else
30
- determine_type_from_string(class_or_name.to_s)
31
- end
35
+ @type_lookup_cache[class_or_name] ||= determine_type_and_cache(class_or_name)
32
36
  end
33
37
 
34
38
  # Return the default primitive supported
@@ -42,6 +46,18 @@ module Virtus
42
46
 
43
47
  private
44
48
 
49
+ # @api private
50
+ def determine_type_and_cache(class_or_name)
51
+ type = case class_or_name
52
+ when singleton_class
53
+ determine_type_from_descendant(class_or_name)
54
+ when Class
55
+ determine_type_from_primitive(class_or_name)
56
+ else
57
+ determine_type_from_string(class_or_name.to_s)
58
+ end
59
+ end
60
+
45
61
  # Return the class given a descendant
46
62
  #
47
63
  # @param [Class] descendant