virtus 0.0.10 → 0.1.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.
- data/.gitignore +33 -7
- data/.travis.yml +4 -74
- data/Changelog.md +11 -2
- data/Gemfile +10 -9
- data/README.md +85 -1
- data/TODO +18 -0
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/roodi.yml +3 -3
- data/config/site.reek +8 -3
- data/lib/virtus.rb +5 -0
- data/lib/virtus/attribute.rb +137 -30
- data/lib/virtus/attribute/array.rb +17 -1
- data/lib/virtus/attribute/boolean.rb +8 -13
- data/lib/virtus/attribute/collection.rb +96 -0
- data/lib/virtus/attribute/default_value.rb +11 -7
- data/lib/virtus/attribute/embedded_value.rb +70 -0
- data/lib/virtus/attribute/set.rb +25 -0
- data/lib/virtus/attribute_set.rb +18 -16
- data/lib/virtus/attributes_accessor.rb +66 -0
- data/lib/virtus/class_methods.rb +50 -28
- data/lib/virtus/coercion/array.rb +23 -0
- data/lib/virtus/coercion/string.rb +10 -4
- data/lib/virtus/instance_methods.rb +38 -31
- data/lib/virtus/support/options.rb +6 -8
- data/lib/virtus/support/type_lookup.rb +4 -11
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/collection_member_coercion_spec.rb +75 -0
- data/spec/integration/custom_attributes_spec.rb +49 -0
- data/spec/integration/default_values_spec.rb +32 -0
- data/spec/integration/defining_attributes_spec.rb +79 -0
- data/spec/integration/embedded_value_spec.rb +50 -0
- data/spec/integration/overriding_virtus_spec.rb +46 -0
- data/spec/integration/virtus/instance_level_attributes_spec.rb +23 -0
- data/spec/rcov.opts +1 -0
- data/spec/shared/constants_helpers.rb +9 -0
- data/spec/shared/options_class_method.rb +19 -0
- data/spec/spec_helper.rb +20 -7
- data/spec/unit/virtus/attribute/array/coerce_spec.rb +13 -0
- data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +85 -0
- data/spec/unit/virtus/attribute/boolean/define_reader_method_spec.rb +15 -0
- data/spec/unit/virtus/attribute/boolean/value_coerced_spec.rb +97 -0
- data/spec/unit/virtus/attribute/boolean_spec.rb +2 -81
- data/spec/unit/virtus/attribute/class/coerce_spec.rb +13 -0
- data/spec/unit/virtus/attribute/class_methods/accessor_spec.rb +12 -0
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +37 -0
- data/spec/unit/virtus/attribute/class_methods/coercion_method_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/default_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +31 -1
- data/spec/unit/virtus/attribute/class_methods/merge_options_spec.rb +11 -0
- data/spec/unit/virtus/attribute/class_methods/primitive_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/reader_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/writer_spec.rb +9 -0
- data/spec/unit/virtus/attribute/coerce_spec.rb +30 -0
- data/spec/unit/virtus/attribute/coercion_method_spec.rb +12 -0
- data/spec/unit/virtus/attribute/collection/class_methods/merge_options_spec.rb +40 -0
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +26 -0
- data/spec/unit/virtus/attribute/date/coerce_spec.rb +47 -0
- data/spec/unit/virtus/attribute/date/value_coerced_spec.rb +46 -0
- data/spec/unit/virtus/attribute/date_time/coerce_spec.rb +68 -0
- data/spec/unit/virtus/attribute/decimal/coerce_spec.rb +117 -0
- data/spec/unit/virtus/attribute/default_spec.rb +32 -0
- data/spec/unit/virtus/attribute/default_value/attribute_spec.rb +11 -0
- data/spec/unit/virtus/attribute/default_value/class_methods/new_spec.rb +4 -2
- data/spec/unit/virtus/attribute/default_value/evaluate_spec.rb +51 -0
- data/spec/unit/virtus/attribute/default_value/instance_methods/evaluate_spec.rb +9 -6
- data/spec/unit/virtus/attribute/default_value/value_spec.rb +11 -0
- data/spec/unit/virtus/attribute/define_accessor_methods_spec.rb +26 -0
- data/spec/unit/virtus/attribute/define_reader_method_spec.rb +24 -0
- data/spec/unit/virtus/attribute/define_writer_method_spec.rb +24 -0
- data/spec/unit/virtus/attribute/embedded_value/class_methods/merge_options_spec.rb +17 -0
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +50 -0
- data/spec/unit/virtus/attribute/float/coerce_spec.rb +117 -0
- data/spec/unit/virtus/attribute/get_spec.rb +80 -0
- data/spec/unit/virtus/attribute/inspect_spec.rb +27 -0
- data/spec/unit/virtus/attribute/instance_variable_name_spec.rb +12 -0
- data/spec/unit/virtus/attribute/integer/coerce_spec.rb +105 -0
- data/spec/unit/virtus/attribute/name_spec.rb +12 -0
- data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +1 -1
- data/spec/unit/virtus/attribute/numeric/class_methods/max_spec.rb +9 -0
- data/spec/unit/virtus/attribute/numeric/class_methods/min_spec.rb +9 -0
- data/spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb +9 -7
- data/spec/unit/virtus/attribute/options_spec.rb +14 -0
- data/spec/unit/virtus/attribute/public_reader_spec.rb +24 -0
- data/spec/unit/virtus/attribute/public_writer_spec.rb +24 -0
- data/spec/unit/virtus/attribute/reader_visibility_spec.rb +24 -0
- data/spec/unit/virtus/attribute/set/coerce_spec.rb +13 -0
- data/spec/unit/virtus/attribute/set_spec.rb +49 -0
- data/spec/unit/virtus/attribute/string/coerce_spec.rb +11 -0
- data/spec/unit/virtus/attribute/time/coerce_spec.rb +67 -0
- data/spec/unit/virtus/attribute/value_coerced_spec.rb +19 -0
- data/spec/unit/virtus/attribute/writer_visibility_spec.rb +24 -0
- data/spec/unit/virtus/attribute_set/append_spec.rb +12 -0
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +4 -0
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +29 -9
- data/spec/unit/virtus/attributes_accessor/inspect_spec.rb +9 -0
- data/spec/unit/virtus/class_methods/attribute_spec.rb +23 -5
- data/spec/unit/virtus/class_methods/attributes_spec.rb +3 -5
- data/spec/unit/virtus/class_methods/const_missing_spec.rb +27 -0
- data/spec/unit/virtus/class_methods/inherited_spec.rb +21 -0
- data/spec/unit/virtus/coercion/array/to_set_spec.rb +12 -0
- data/spec/unit/virtus/coercion/date/class_methods/to_date_spec.rb +10 -0
- data/spec/unit/virtus/coercion/date_time/class_methods/to_datetime_spec.rb +10 -0
- data/spec/unit/virtus/coercion/hash/class_methods/to_date_spec.rb +10 -3
- data/spec/unit/virtus/coercion/hash/class_methods/to_datetime_spec.rb +10 -3
- data/spec/unit/virtus/coercion/hash/class_methods/to_time_spec.rb +10 -3
- data/spec/unit/virtus/coercion/object/class_methods/method_missing_spec.rb +8 -8
- data/spec/unit/virtus/coercion/string/class_methods/to_boolean_spec.rb +2 -2
- data/spec/unit/virtus/coercion/string/class_methods/to_constant_spec.rb +1 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_date_spec.rb +1 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_datetime_spec.rb +13 -13
- data/spec/unit/virtus/coercion/string/class_methods/to_decimal_spec.rb +25 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_float_spec.rb +25 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_integer_spec.rb +30 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_time_spec.rb +13 -13
- data/spec/unit/virtus/coercion/time/class_methods/to_time_spec.rb +10 -0
- data/spec/unit/virtus/coercion/true_class/class_methods/to_string_spec.rb +1 -1
- data/spec/unit/virtus/instance_methods/attributes_spec.rb +77 -20
- data/spec/unit/virtus/instance_methods/element_reference_spec.rb +1 -1
- data/spec/unit/virtus/instance_methods/element_set_spec.rb +2 -2
- data/spec/unit/virtus/instance_methods/to_hash_spec.rb +23 -0
- data/spec/unit/virtus/options/accept_options_spec.rb +10 -11
- data/spec/unit/virtus/options/accepted_options_spec.rb +1 -1
- data/spec/unit/virtus/options/options_spec.rb +27 -4
- data/tasks/metrics/ci.rake +2 -1
- data/tasks/metrics/heckle.rake +207 -0
- data/tasks/spec.rake +14 -7
- data/virtus.gemspec +1 -1
- metadata +111 -97
- data/VERSION +0 -1
- data/examples/custom_coercion_spec.rb +0 -50
- data/examples/default_values_spec.rb +0 -21
- data/examples/override_attribute_methods_spec.rb +0 -40
- data/spec/integration/virtus/attributes/attribute/set_spec.rb +0 -36
- data/spec/integration/virtus/class_methods/attribute_spec.rb +0 -82
- data/spec/integration/virtus/class_methods/attributes_spec.rb +0 -22
- data/spec/integration/virtus/class_methods/const_missing_spec.rb +0 -44
- data/spec/unit/shared/attribute.rb +0 -7
- data/spec/unit/shared/attribute/accept_options.rb +0 -37
- data/spec/unit/shared/attribute/accepted_options.rb +0 -5
- data/spec/unit/shared/attribute/get.rb +0 -44
- data/spec/unit/shared/attribute/inspect.rb +0 -7
- data/spec/unit/shared/attribute/set.rb +0 -37
- data/spec/unit/virtus/attribute/array_spec.rb +0 -24
- data/spec/unit/virtus/attribute/class_spec.rb +0 -24
- data/spec/unit/virtus/attribute/date_spec.rb +0 -59
- data/spec/unit/virtus/attribute/date_time_spec.rb +0 -87
- data/spec/unit/virtus/attribute/decimal_spec.rb +0 -109
- data/spec/unit/virtus/attribute/float_spec.rb +0 -109
- data/spec/unit/virtus/attribute/hash_spec.rb +0 -11
- data/spec/unit/virtus/attribute/integer_spec.rb +0 -99
- data/spec/unit/virtus/attribute/string_spec.rb +0 -21
- data/spec/unit/virtus/attribute/time_spec.rb +0 -82
- data/spec/unit/virtus/class_methods/new_spec.rb +0 -41
data/lib/virtus/class_methods.rb
CHANGED
|
@@ -12,8 +12,10 @@ module Virtus
|
|
|
12
12
|
# @api private
|
|
13
13
|
def self.extended(descendant)
|
|
14
14
|
super
|
|
15
|
-
descendant.
|
|
16
|
-
|
|
15
|
+
descendant.module_eval do
|
|
16
|
+
extend DescendantsTracker
|
|
17
|
+
virtus_setup_attributes_accessor_module
|
|
18
|
+
end
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
private_class_method :extended
|
|
@@ -41,10 +43,12 @@ module Virtus
|
|
|
41
43
|
#
|
|
42
44
|
# @return [self]
|
|
43
45
|
#
|
|
46
|
+
# @see Attribute.build
|
|
47
|
+
#
|
|
44
48
|
# @api public
|
|
45
|
-
def attribute(
|
|
46
|
-
attribute = Attribute.
|
|
47
|
-
|
|
49
|
+
def attribute(*args)
|
|
50
|
+
attribute = Attribute.build(*args)
|
|
51
|
+
attribute.define_accessor_methods(virtus_attributes_accessor_module)
|
|
48
52
|
virtus_add_attribute(attribute)
|
|
49
53
|
self
|
|
50
54
|
end
|
|
@@ -67,44 +71,62 @@ module Virtus
|
|
|
67
71
|
#
|
|
68
72
|
# @api public
|
|
69
73
|
def attributes
|
|
70
|
-
@attributes
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
return @attributes if defined?(@attributes)
|
|
75
|
+
superclass = self.superclass
|
|
76
|
+
method = __method__
|
|
77
|
+
parent = superclass.send(method) if superclass.respond_to?(method)
|
|
78
|
+
@attributes = AttributeSet.new(parent)
|
|
75
79
|
end
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
protected
|
|
78
82
|
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
# It is used when an attribute is defined and a global class like String
|
|
82
|
-
# or Integer is provided as the type which needs to be mapped to
|
|
83
|
-
# Virtus::Attribute::String and Virtus::Attribute::Integer
|
|
84
|
-
#
|
|
85
|
-
# @param [String] name
|
|
83
|
+
# Set up the anonymous module which will host Attribute accessor methods
|
|
86
84
|
#
|
|
87
|
-
# @return [
|
|
85
|
+
# @return [self]
|
|
88
86
|
#
|
|
89
87
|
# @api private
|
|
90
|
-
def
|
|
91
|
-
|
|
88
|
+
def virtus_setup_attributes_accessor_module
|
|
89
|
+
@virtus_attributes_accessor_module = AttributesAccessor.new(inspect)
|
|
90
|
+
include virtus_attributes_accessor_module
|
|
91
|
+
self
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# Setup descendants' own Attribute-accessor-method-hosting modules
|
|
95
97
|
#
|
|
96
|
-
#
|
|
98
|
+
# Descendants inherit Attribute accessor methods via Ruby's inheritance
|
|
99
|
+
# mechanism: Attribute accessor methods are defined in a module included
|
|
100
|
+
# in a superclass. Attributes defined on descendants add methods to the
|
|
101
|
+
# descendant's Attributes accessor module, leaving the superclass's method
|
|
102
|
+
# table unaffected.
|
|
103
|
+
#
|
|
104
|
+
# @param [Class] descendant
|
|
97
105
|
#
|
|
98
106
|
# @return [undefined]
|
|
99
107
|
#
|
|
100
108
|
# @api private
|
|
101
|
-
def
|
|
102
|
-
|
|
109
|
+
def inherited(descendant)
|
|
110
|
+
super
|
|
111
|
+
descendant.virtus_setup_attributes_accessor_module
|
|
112
|
+
end
|
|
103
113
|
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
# Holds the anonymous module which hosts this class's Attribute accessors
|
|
115
|
+
#
|
|
116
|
+
# @return [Module]
|
|
117
|
+
#
|
|
118
|
+
# @api private
|
|
119
|
+
attr_reader :virtus_attributes_accessor_module
|
|
106
120
|
|
|
107
|
-
|
|
121
|
+
# Hooks into const missing process to determine types of attributes
|
|
122
|
+
#
|
|
123
|
+
# @param [String] name
|
|
124
|
+
#
|
|
125
|
+
# @return [Class]
|
|
126
|
+
#
|
|
127
|
+
# @api private
|
|
128
|
+
def const_missing(name)
|
|
129
|
+
Attribute.determine_type(name) || super
|
|
108
130
|
end
|
|
109
131
|
|
|
110
132
|
# Add the attribute to the class' and descendants' attributes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Virtus
|
|
2
|
+
class Coercion
|
|
3
|
+
|
|
4
|
+
# Coerce Array values
|
|
5
|
+
class Array < Object
|
|
6
|
+
primitive ::Array
|
|
7
|
+
|
|
8
|
+
TIME_SEGMENTS = [ :year, :month, :day, :hour, :min, :sec ].freeze
|
|
9
|
+
|
|
10
|
+
# Creates a Set instance from an Array
|
|
11
|
+
#
|
|
12
|
+
# @param [Array] value
|
|
13
|
+
#
|
|
14
|
+
# @return [Array]
|
|
15
|
+
#
|
|
16
|
+
# @api private
|
|
17
|
+
def self.to_set(value)
|
|
18
|
+
value.to_set
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end # class Array
|
|
22
|
+
end # class Coercion
|
|
23
|
+
end # module Virtus
|
|
@@ -5,11 +5,14 @@ module Virtus
|
|
|
5
5
|
class String < Object
|
|
6
6
|
primitive ::String
|
|
7
7
|
|
|
8
|
-
TRUE_VALUES = %w[ 1 t true ].freeze
|
|
9
|
-
FALSE_VALUES = %w[ 0 f false ].freeze
|
|
8
|
+
TRUE_VALUES = %w[ 1 on t true y yes ].freeze
|
|
9
|
+
FALSE_VALUES = %w[ 0 off f false n no ].freeze
|
|
10
10
|
BOOLEAN_MAP = ::Hash[ TRUE_VALUES.product([ true ]) + FALSE_VALUES.product([ false ]) ].freeze
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
INTEGER_REGEXP = /[-+]?(?:0|[1-9]\d*)/.freeze
|
|
13
|
+
EXPONENT_REGEXP = /(?:[eE][-+]?\d+)/.freeze
|
|
14
|
+
FRACTIONAL_REGEXP = /(?:\.\d+#{EXPONENT_REGEXP}?)/.freeze
|
|
15
|
+
NUMERIC_REGEXP = /\A(#{INTEGER_REGEXP}#{FRACTIONAL_REGEXP}?|#{FRACTIONAL_REGEXP})\z/.freeze
|
|
13
16
|
|
|
14
17
|
# Coerce give value to a constant
|
|
15
18
|
#
|
|
@@ -96,7 +99,10 @@ module Virtus
|
|
|
96
99
|
#
|
|
97
100
|
# @api public
|
|
98
101
|
def self.to_integer(value)
|
|
99
|
-
|
|
102
|
+
# coerce to a Float first to evaluate scientific notation (if any)
|
|
103
|
+
# that may change the integer part, then convert to an integer
|
|
104
|
+
coerced = to_float(value)
|
|
105
|
+
::Float === coerced ? coerced.to_i : coerced
|
|
100
106
|
end
|
|
101
107
|
|
|
102
108
|
# Coerce value to float
|
|
@@ -11,8 +11,8 @@ module Virtus
|
|
|
11
11
|
# @return [undefined]
|
|
12
12
|
#
|
|
13
13
|
# @api private
|
|
14
|
-
def initialize(
|
|
15
|
-
self.attributes =
|
|
14
|
+
def initialize(attribute_values = {})
|
|
15
|
+
self.attributes = attribute_values
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# Returns a value of the attribute with the given name
|
|
@@ -35,7 +35,7 @@ module Virtus
|
|
|
35
35
|
#
|
|
36
36
|
# @api public
|
|
37
37
|
def [](name)
|
|
38
|
-
|
|
38
|
+
__send__(name)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
# Sets a value of the attribute with the given name
|
|
@@ -62,7 +62,7 @@ module Virtus
|
|
|
62
62
|
#
|
|
63
63
|
# @api public
|
|
64
64
|
def []=(name, value)
|
|
65
|
-
|
|
65
|
+
__send__("#{name}=", value)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
# Returns a hash of all publicly accessible attributes
|
|
@@ -82,17 +82,17 @@ module Virtus
|
|
|
82
82
|
#
|
|
83
83
|
# @api public
|
|
84
84
|
def attributes
|
|
85
|
-
attributes
|
|
86
|
-
|
|
87
|
-
self.class.attributes.each do |attribute|
|
|
85
|
+
self.class.attributes.each_with_object({}) do |attribute, attributes|
|
|
88
86
|
name = attribute.name
|
|
89
|
-
attributes[name] =
|
|
87
|
+
attributes[name] = self[name] if attribute.public_reader?
|
|
90
88
|
end
|
|
91
|
-
|
|
92
|
-
attributes
|
|
93
89
|
end
|
|
94
90
|
|
|
95
|
-
# Mass-assign
|
|
91
|
+
# Mass-assign attribute values
|
|
92
|
+
#
|
|
93
|
+
# Keys in the +attribute_values+ param can be symbols or strings.
|
|
94
|
+
# Only non-private referenced Attribute writer methods will be called.
|
|
95
|
+
# Non-attribute setter methods on the receiver will not be called.
|
|
96
96
|
#
|
|
97
97
|
# @example
|
|
98
98
|
# class User
|
|
@@ -103,18 +103,20 @@ module Virtus
|
|
|
103
103
|
# end
|
|
104
104
|
#
|
|
105
105
|
# user = User.new
|
|
106
|
-
# user.attributes = { :name => 'John',
|
|
106
|
+
# user.attributes = { :name => 'John', 'age' => 28 }
|
|
107
107
|
#
|
|
108
|
-
# @param [#to_hash]
|
|
109
|
-
# a hash of attribute values to
|
|
108
|
+
# @param [#to_hash] attribute_values
|
|
109
|
+
# a hash of attribute names and values to set on the receiver
|
|
110
110
|
#
|
|
111
111
|
# @return [Hash]
|
|
112
112
|
#
|
|
113
113
|
# @api public
|
|
114
|
-
def attributes=(
|
|
115
|
-
attributes.
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
def attributes=(attribute_values)
|
|
115
|
+
attributes = self.class.attributes
|
|
116
|
+
set_attributes(attribute_values.select { |name,|
|
|
117
|
+
attribute = attributes[name]
|
|
118
|
+
attribute && attribute.public_writer?
|
|
119
|
+
})
|
|
118
120
|
end
|
|
119
121
|
|
|
120
122
|
# Returns a hash of all publicly accessible attributes
|
|
@@ -139,26 +141,31 @@ module Virtus
|
|
|
139
141
|
|
|
140
142
|
private
|
|
141
143
|
|
|
142
|
-
#
|
|
144
|
+
# Mass-assign attribute values
|
|
143
145
|
#
|
|
144
|
-
#
|
|
146
|
+
# Keys in the +attribute_values+ param can be symbols or strings.
|
|
147
|
+
# All referenced Attribute writer methods *will* be called.
|
|
148
|
+
# Non-attribute setter methods on the receiver *will* be called.
|
|
145
149
|
#
|
|
146
|
-
# @
|
|
150
|
+
# @example
|
|
151
|
+
# class User
|
|
152
|
+
# include Virtus
|
|
147
153
|
#
|
|
148
|
-
#
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# Sets a value of the attribute with the given name
|
|
154
|
+
# attribute :name, String
|
|
155
|
+
# attribute :age, Integer
|
|
156
|
+
# end
|
|
154
157
|
#
|
|
155
|
-
#
|
|
158
|
+
# user = User.new
|
|
159
|
+
# user.attributes = { :name => 'John', 'age' => 28 }
|
|
156
160
|
#
|
|
157
|
-
# @
|
|
161
|
+
# @param [#to_hash] attribute_values
|
|
162
|
+
# a hash of attribute names and values to set on the receiver
|
|
163
|
+
#
|
|
164
|
+
# @return [Hash]
|
|
158
165
|
#
|
|
159
166
|
# @api private
|
|
160
|
-
def
|
|
161
|
-
|
|
167
|
+
def set_attributes(attribute_values)
|
|
168
|
+
attribute_values.each { |name, value| self[name] = value }
|
|
162
169
|
end
|
|
163
170
|
|
|
164
171
|
end # module InstanceMethods
|
|
@@ -14,12 +14,10 @@ module Virtus
|
|
|
14
14
|
#
|
|
15
15
|
# @api public
|
|
16
16
|
def options
|
|
17
|
-
|
|
18
|
-
accepted_options.each do |option_name|
|
|
17
|
+
accepted_options.each_with_object({}) do |option_name, options|
|
|
19
18
|
option_value = send(option_name)
|
|
20
19
|
options[option_name] = option_value unless option_value.nil?
|
|
21
20
|
end
|
|
22
|
-
options
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
# Returns an array of valid options
|
|
@@ -43,8 +41,7 @@ module Virtus
|
|
|
43
41
|
# accept_options :foo, :bar
|
|
44
42
|
# end
|
|
45
43
|
#
|
|
46
|
-
# @return [
|
|
47
|
-
# All accepted options
|
|
44
|
+
# @return [self]
|
|
48
45
|
#
|
|
49
46
|
# @api public
|
|
50
47
|
def accept_options(*new_options)
|
|
@@ -66,20 +63,21 @@ module Virtus
|
|
|
66
63
|
def self.#{option}(value = Undefined) # def self.primitive(value = Undefined)
|
|
67
64
|
return @#{option} if value.equal?(Undefined) # return @primitive if value.equal?(Undefined)
|
|
68
65
|
@#{option} = value # @primitive = value
|
|
66
|
+
self # self
|
|
69
67
|
end # end
|
|
70
68
|
RUBY
|
|
71
69
|
end
|
|
72
70
|
|
|
73
71
|
# Sets default options
|
|
74
72
|
#
|
|
75
|
-
# @param [#
|
|
73
|
+
# @param [#each] new_options
|
|
76
74
|
# options to be set
|
|
77
75
|
#
|
|
78
76
|
# @return [self]
|
|
79
77
|
#
|
|
80
78
|
# @api private
|
|
81
79
|
def set_options(new_options)
|
|
82
|
-
new_options.
|
|
80
|
+
new_options.each { |pair| send(*pair) }
|
|
83
81
|
self
|
|
84
82
|
end
|
|
85
83
|
|
|
@@ -92,7 +90,7 @@ module Virtus
|
|
|
92
90
|
#
|
|
93
91
|
# @api private
|
|
94
92
|
def add_accepted_options(new_options)
|
|
95
|
-
accepted_options.concat(new_options
|
|
93
|
+
accepted_options.concat(new_options)
|
|
96
94
|
self
|
|
97
95
|
end
|
|
98
96
|
|
|
@@ -3,7 +3,8 @@ module Virtus
|
|
|
3
3
|
# A module that adds type lookup to a class
|
|
4
4
|
module TypeLookup
|
|
5
5
|
|
|
6
|
-
TYPE_FORMAT
|
|
6
|
+
TYPE_FORMAT = /\A[A-Z]\w*\z/.freeze
|
|
7
|
+
EXTRA_CONST_ARGS = RUBY_VERSION < '1.9' || RUBY_ENGINE == 'rbx' ? [] : [ false ]
|
|
7
8
|
|
|
8
9
|
# Returns a descendant based on a name or class
|
|
9
10
|
#
|
|
@@ -84,16 +85,8 @@ module Virtus
|
|
|
84
85
|
#
|
|
85
86
|
# @api private
|
|
86
87
|
def determine_type_from_string(string)
|
|
87
|
-
if string =~ TYPE_FORMAT && const_defined?(string,
|
|
88
|
-
const_get(string,
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
if RUBY_VERSION < '1.9' || RUBY_ENGINE == 'rbx'
|
|
93
|
-
def determine_type_from_string(string)
|
|
94
|
-
if string =~ TYPE_FORMAT && const_defined?(string)
|
|
95
|
-
const_get(string)
|
|
96
|
-
end
|
|
88
|
+
if string =~ TYPE_FORMAT && const_defined?(string, *EXTRA_CONST_ARGS)
|
|
89
|
+
const_get(string, *EXTRA_CONST_ARGS)
|
|
97
90
|
end
|
|
98
91
|
end
|
|
99
92
|
|
data/lib/virtus/version.rb
CHANGED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# TODO: refactor to make it inline with the new style of integration specs
|
|
4
|
+
|
|
5
|
+
class Address
|
|
6
|
+
include Virtus
|
|
7
|
+
|
|
8
|
+
attribute :address, String
|
|
9
|
+
attribute :locality, String
|
|
10
|
+
attribute :region, String
|
|
11
|
+
attribute :postal_code, String
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class PhoneNumber
|
|
15
|
+
include Virtus
|
|
16
|
+
|
|
17
|
+
attribute :number, String
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class User
|
|
21
|
+
include Virtus
|
|
22
|
+
|
|
23
|
+
attribute :phone_numbers, Array[PhoneNumber]
|
|
24
|
+
attribute :addresses, Set[Address]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe User do
|
|
28
|
+
it { should respond_to(:phone_numbers) }
|
|
29
|
+
it { should respond_to(:phone_numbers=) }
|
|
30
|
+
it { should respond_to(:addresses) }
|
|
31
|
+
it { should respond_to(:addresses=) }
|
|
32
|
+
|
|
33
|
+
let(:instance) do
|
|
34
|
+
described_class.new(:phone_numbers => phone_numbers_attributes,
|
|
35
|
+
:addresses => addresses_attributes)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
let(:phone_numbers_attributes) { [
|
|
39
|
+
{ :number => '212-555-1212' },
|
|
40
|
+
{ :number => '919-444-3265' },
|
|
41
|
+
] }
|
|
42
|
+
|
|
43
|
+
let(:addresses_attributes) { [
|
|
44
|
+
{ :address => '1234 Any St.', :locality => 'Anytown', :region => "DC", :postal_code => "21234" },
|
|
45
|
+
] }
|
|
46
|
+
|
|
47
|
+
describe '#phone_numbers' do
|
|
48
|
+
describe 'first entry' do
|
|
49
|
+
subject { instance.phone_numbers.first }
|
|
50
|
+
|
|
51
|
+
it { should be_instance_of(PhoneNumber) }
|
|
52
|
+
|
|
53
|
+
its(:number) { should eql('212-555-1212') }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe 'last entry' do
|
|
57
|
+
subject { instance.phone_numbers.last }
|
|
58
|
+
|
|
59
|
+
it { should be_instance_of(PhoneNumber) }
|
|
60
|
+
|
|
61
|
+
its(:number) { should eql('919-444-3265') }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#addresses' do
|
|
66
|
+
subject { instance.addresses.first }
|
|
67
|
+
|
|
68
|
+
it { should be_instance_of(Address) }
|
|
69
|
+
|
|
70
|
+
its(:address) { should eql('1234 Any St.') }
|
|
71
|
+
its(:locality) { should eql('Anytown') }
|
|
72
|
+
its(:region) { should eql('DC') }
|
|
73
|
+
its(:postal_code) { should eql('21234') }
|
|
74
|
+
end
|
|
75
|
+
end
|