virtus 0.2.0 → 0.3.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/.pelusa.yml +7 -0
- data/.travis.yml +5 -3
- data/Changelog.md +17 -0
- data/Gemfile +4 -0
- data/README.md +35 -39
- data/TODO +12 -7
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/lib/virtus.rb +8 -0
- data/lib/virtus/attribute.rb +8 -29
- data/lib/virtus/attribute/boolean.rb +1 -1
- data/lib/virtus/attribute/default_value.rb +15 -45
- data/lib/virtus/attribute/default_value/from_callable.rb +33 -0
- data/lib/virtus/attribute/default_value/from_clonable.rb +40 -0
- data/lib/virtus/attribute/default_value/from_symbol.rb +35 -0
- data/lib/virtus/attribute/embedded_value.rb +3 -14
- data/lib/virtus/class_methods.rb +17 -0
- data/lib/virtus/coercion/hash.rb +0 -11
- data/lib/virtus/coercion/object.rb +98 -0
- data/lib/virtus/coercion/string.rb +9 -2
- data/lib/virtus/coercion/time_coercions.rb +2 -5
- data/lib/virtus/instance_methods.rb +16 -37
- data/lib/virtus/support/type_lookup.rb +1 -2
- data/lib/virtus/value_object.rb +31 -8
- data/lib/virtus/value_object/equalizer.rb +21 -26
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/custom_attributes_spec.rb +1 -1
- data/spec/integration/default_values_spec.rb +15 -3
- data/spec/integration/defining_attributes_spec.rb +1 -1
- data/spec/integration/mass_assignment_with_accessors_spec.rb +44 -0
- data/spec/integration/virtus/value_object_spec.rb +2 -2
- data/spec/spec_helper.rb +8 -1
- data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +1 -1
- data/spec/unit/virtus/attribute/default_spec.rb +1 -1
- data/spec/unit/virtus/attribute/default_value/evaluate_spec.rb +25 -11
- data/spec/unit/virtus/attribute/embedded_value/class_methods/merge_options_spec.rb +1 -1
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +1 -1
- data/spec/unit/virtus/class_methods/allowed_writer_methods_spec.rb +25 -0
- data/spec/unit/virtus/coercion/object/class_methods/to_array_spec.rb +51 -0
- data/spec/unit/virtus/coercion/object/class_methods/to_hash_spec.rb +22 -0
- data/spec/unit/virtus/coercion/object/class_methods/to_integer_spec.rb +22 -0
- data/spec/unit/virtus/coercion/object/class_methods/to_string_spec.rb +22 -0
- data/spec/unit/virtus/coercion/string/class_methods/to_constant_spec.rb +37 -1
- data/spec/unit/virtus/instance_methods/attributes_spec.rb +14 -2
- data/spec/unit/virtus/value_object/class_methods/allowed_writer_methods_spec.rb +15 -0
- data/spec/unit/virtus/value_object/class_methods/equalizer_spec.rb +1 -1
- data/spec/unit/virtus/value_object/initialize_spec.rb +1 -1
- data/spec/unit/virtus/value_object/with_spec.rb +1 -1
- metadata +17 -10
- data/spec/unit/virtus/attribute/default_value/instance_methods/evaluate_spec.rb +0 -30
- data/spec/unit/virtus/attribute/instance_variable_name_spec.rb +0 -12
- data/spec/unit/virtus/attribute/reader_visibility_spec.rb +0 -24
- data/spec/unit/virtus/attribute/writer_visibility_spec.rb +0 -24
- data/spec/unit/virtus/coercion/hash/class_methods/to_array_spec.rb +0 -12
@@ -0,0 +1,33 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
class DefaultValue
|
4
|
+
|
5
|
+
# Represents default value evaluated via a callable object
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class FromCallable < DefaultValue
|
9
|
+
|
10
|
+
# Return if the class can handle the value
|
11
|
+
#
|
12
|
+
# @return [Boolean]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def self.handle?(attribute, value)
|
16
|
+
value.respond_to?(:call)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Evaluates the value via value#call
|
20
|
+
#
|
21
|
+
# @param [Object]
|
22
|
+
#
|
23
|
+
# @return [Object] evaluated value
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
def evaluate(instance)
|
27
|
+
@value.call(instance, @attribute)
|
28
|
+
end
|
29
|
+
|
30
|
+
end # class FromCallable
|
31
|
+
end # class DefaultValue
|
32
|
+
end # class Attribute
|
33
|
+
end # module Virtus
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
class DefaultValue
|
4
|
+
|
5
|
+
# Represents default value evaluated via a clonable object
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class FromClonable < DefaultValue
|
9
|
+
SINGLETON_CLASSES = [
|
10
|
+
::NilClass, ::TrueClass, ::FalseClass, ::Numeric, ::Symbol ].freeze
|
11
|
+
|
12
|
+
# Return if the class can handle the value
|
13
|
+
#
|
14
|
+
# @return [Boolean]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def self.handle?(attribute, value)
|
18
|
+
case value
|
19
|
+
when *SINGLETON_CLASSES
|
20
|
+
false
|
21
|
+
else
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Evaluates the value via value#clone
|
27
|
+
#
|
28
|
+
# @param [Object]
|
29
|
+
#
|
30
|
+
# @return [Object] evaluated value
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def evaluate(instance)
|
34
|
+
@value.clone
|
35
|
+
end
|
36
|
+
|
37
|
+
end # class FromClonable
|
38
|
+
end # class DefaultValue
|
39
|
+
end # class Attribute
|
40
|
+
end # module Virtus
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
class DefaultValue
|
4
|
+
|
5
|
+
# Represents default value evaluated via a symbol
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class FromSymbol < DefaultValue
|
9
|
+
|
10
|
+
# Return if the class can handle the value
|
11
|
+
#
|
12
|
+
# @return [Boolean]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def self.handle?(attribute, value)
|
16
|
+
value.is_a?(::Symbol)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Evaluates the value via instance#__send__(value)
|
20
|
+
#
|
21
|
+
# Symbol value is returned if the instance doesn't respond to value
|
22
|
+
#
|
23
|
+
# @param [Object]
|
24
|
+
#
|
25
|
+
# @return [Object] evaluated value
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
def evaluate(instance)
|
29
|
+
instance.respond_to?(@value) ? instance.__send__(@value) : @value
|
30
|
+
end
|
31
|
+
|
32
|
+
end # class FromSymbol
|
33
|
+
end # class DefaultValue
|
34
|
+
end # class Attribute
|
35
|
+
end # module Virtus
|
@@ -25,6 +25,7 @@ module Virtus
|
|
25
25
|
# :street => 'Street 1/2', :zipcode => '12345', :city => 'NYC' })
|
26
26
|
#
|
27
27
|
class EmbeddedValue < Object
|
28
|
+
primitive ::OpenStruct
|
28
29
|
|
29
30
|
# @see Attribute.merge_options
|
30
31
|
#
|
@@ -33,19 +34,7 @@ module Virtus
|
|
33
34
|
#
|
34
35
|
# @api private
|
35
36
|
def self.merge_options(type, options)
|
36
|
-
options.merge(:
|
37
|
-
end
|
38
|
-
|
39
|
-
# Sets @model ivar
|
40
|
-
#
|
41
|
-
# @see Virtus::Attribute#initialize
|
42
|
-
#
|
43
|
-
# @return [undefined]
|
44
|
-
#
|
45
|
-
# @api private
|
46
|
-
def initialize(name, options = {})
|
47
|
-
super
|
48
|
-
@model = options.fetch(:model, OpenStruct)
|
37
|
+
options.merge(:primitive => type)
|
49
38
|
end
|
50
39
|
|
51
40
|
# Coerce attributes into a virtus object
|
@@ -57,7 +46,7 @@ module Virtus
|
|
57
46
|
# @api private
|
58
47
|
def coerce(attributes_or_object)
|
59
48
|
value = if attributes_or_object.kind_of?(::Hash)
|
60
|
-
@
|
49
|
+
@primitive.new(attributes_or_object)
|
61
50
|
else
|
62
51
|
attributes_or_object
|
63
52
|
end
|
data/lib/virtus/class_methods.rb
CHANGED
@@ -2,6 +2,8 @@ module Virtus
|
|
2
2
|
|
3
3
|
# Class methods that are added when you include Virtus
|
4
4
|
module ClassMethods
|
5
|
+
WRITER_METHOD_REGEXP = /=\z/.freeze
|
6
|
+
INVALID_WRITER_METHODS = %w[ == != === []= attributes= ].to_set.freeze
|
5
7
|
|
6
8
|
# Hook called when module is extended
|
7
9
|
#
|
@@ -78,6 +80,21 @@ module Virtus
|
|
78
80
|
@attributes = AttributeSet.new(parent)
|
79
81
|
end
|
80
82
|
|
83
|
+
# The list of writer methods that can be mass-assigned to in #attributes=
|
84
|
+
#
|
85
|
+
# @return [Set]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
def allowed_writer_methods
|
89
|
+
@allowed_writer_methods ||=
|
90
|
+
begin
|
91
|
+
allowed_writer_methods = public_instance_methods.map(&:to_s)
|
92
|
+
allowed_writer_methods = allowed_writer_methods.grep(WRITER_METHOD_REGEXP).to_set
|
93
|
+
allowed_writer_methods -= INVALID_WRITER_METHODS
|
94
|
+
allowed_writer_methods.freeze
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
81
98
|
protected
|
82
99
|
|
83
100
|
# Set up the anonymous module which will host Attribute accessor methods
|
data/lib/virtus/coercion/hash.rb
CHANGED
@@ -7,17 +7,6 @@ module Virtus
|
|
7
7
|
|
8
8
|
TIME_SEGMENTS = [ :year, :month, :day, :hour, :min, :sec ].freeze
|
9
9
|
|
10
|
-
# Creates an Array instance from a Hash
|
11
|
-
#
|
12
|
-
# @param [Hash] value
|
13
|
-
#
|
14
|
-
# @return [Array]
|
15
|
-
#
|
16
|
-
# @api private
|
17
|
-
def self.to_array(value)
|
18
|
-
value.to_a
|
19
|
-
end
|
20
|
-
|
21
10
|
# Creates a Time instance from a Hash
|
22
11
|
#
|
23
12
|
# Valid keys are: :year, :month, :day, :hour, :min, :sec
|
@@ -7,6 +7,87 @@ module Virtus
|
|
7
7
|
|
8
8
|
COERCION_METHOD_REGEXP = /\Ato_/.freeze
|
9
9
|
|
10
|
+
# Create an Array from any Object
|
11
|
+
#
|
12
|
+
# @example with an object that does not respond to #to_a or #to_ary
|
13
|
+
# Virtus::Coercion::Object.to_array(value) # => [ value ]
|
14
|
+
#
|
15
|
+
# @example with an object that responds to #to_a
|
16
|
+
# Virtus::Coercion::Object.to_array(Set[ value ]) # => [ value ]
|
17
|
+
#
|
18
|
+
# @example with n object that responds to #to_ary
|
19
|
+
# Virtus::Coercion::Object.to_array([ value ]) # => [ value ]
|
20
|
+
#
|
21
|
+
# @param [#to_a,#to_ary,Object] value
|
22
|
+
# @param [#to_a,#to_ary,Object] value
|
23
|
+
#
|
24
|
+
# @return [Array]
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
def self.to_array(value)
|
28
|
+
Array(value)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create a Hash from the Object if possible
|
32
|
+
#
|
33
|
+
# @example with a coercible object
|
34
|
+
# Virtus::Coercion::Object.to_hash(key => value) # => { key => value }
|
35
|
+
#
|
36
|
+
# @example with an object that is not coercible
|
37
|
+
# Virtus::Coercion::Object.to_hash(value) # => value
|
38
|
+
#
|
39
|
+
# @param [#to_hash, Object] value
|
40
|
+
#
|
41
|
+
# @return [Hash]
|
42
|
+
# returns a Hash when the object can be coerced
|
43
|
+
# @return [Object]
|
44
|
+
# returns the value when the object cannot be coerced
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def self.to_hash(value)
|
48
|
+
coerce_with_method(value, :to_hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create a String from the Object if possible
|
52
|
+
#
|
53
|
+
# @example with a coercible object
|
54
|
+
# Virtus::Coercion::Object.to_string("string") # => "string"
|
55
|
+
#
|
56
|
+
# @example with an object that is not coercible
|
57
|
+
# Virtus::Coercion::Object.to_string(value) # => value
|
58
|
+
#
|
59
|
+
# @param [#to_str, Object] value
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
# returns a String when the object can be coerced
|
63
|
+
# @return [Object]
|
64
|
+
# returns the value when the object cannot be coerced
|
65
|
+
#
|
66
|
+
# @api public
|
67
|
+
def self.to_string(value)
|
68
|
+
coerce_with_method(value, :to_str)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create an Integer from the Object if possible
|
72
|
+
#
|
73
|
+
# @example with a coercible object
|
74
|
+
# Virtus::Coercion::Object.to_integer(1) # => 1
|
75
|
+
#
|
76
|
+
# @example with an object that is not coercible
|
77
|
+
# Virtus::Coercion::Object.to_integer(value) # => value
|
78
|
+
#
|
79
|
+
# @param [#to_int, Object] value
|
80
|
+
#
|
81
|
+
# @return [Integer]
|
82
|
+
# returns an Integer when the object can be coerced
|
83
|
+
# @return [Object]
|
84
|
+
# returns the value when the object cannot be coerced
|
85
|
+
#
|
86
|
+
# @api public
|
87
|
+
def self.to_integer(value)
|
88
|
+
coerce_with_method(value, :to_int)
|
89
|
+
end
|
90
|
+
|
10
91
|
# Passthrough given value
|
11
92
|
#
|
12
93
|
# @param [Object] value
|
@@ -22,6 +103,23 @@ module Virtus
|
|
22
103
|
end
|
23
104
|
end
|
24
105
|
|
106
|
+
private_class_method :method_missing
|
107
|
+
|
108
|
+
# Try to use native coercion method on the given value
|
109
|
+
#
|
110
|
+
# @param [Object] value
|
111
|
+
#
|
112
|
+
# @param [Symbol] method
|
113
|
+
#
|
114
|
+
# @return [Object]
|
115
|
+
#
|
116
|
+
# @api private
|
117
|
+
def self.coerce_with_method(value, method)
|
118
|
+
value.respond_to?(method) ? value.send(method) : value
|
119
|
+
end
|
120
|
+
|
121
|
+
private_class_method :coerce_with_method
|
122
|
+
|
25
123
|
end # class Object
|
26
124
|
end # class Coercion
|
27
125
|
end # module Virtus
|
@@ -25,8 +25,15 @@ module Virtus
|
|
25
25
|
#
|
26
26
|
# @api public
|
27
27
|
def self.to_constant(value)
|
28
|
-
|
29
|
-
|
28
|
+
names = value.split('::')
|
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
|
36
|
+
end
|
30
37
|
end
|
31
38
|
|
32
39
|
# Coerce give value to a symbol
|
@@ -73,11 +73,8 @@ module Virtus
|
|
73
73
|
#
|
74
74
|
# @api private
|
75
75
|
def coerce_with_method(value, method)
|
76
|
-
|
77
|
-
|
78
|
-
else
|
79
|
-
String.send(method, to_string(value))
|
80
|
-
end
|
76
|
+
coerced = super
|
77
|
+
coerced.equal?(value) ? String.send(method, to_string(value)) : coerced
|
81
78
|
end
|
82
79
|
|
83
80
|
end # module TimeCoercions
|
@@ -82,17 +82,14 @@ module Virtus
|
|
82
82
|
#
|
83
83
|
# @api public
|
84
84
|
def attributes
|
85
|
-
|
86
|
-
name = attribute.name
|
87
|
-
attributes[name] = self[name] if attribute.public_reader?
|
88
|
-
end
|
85
|
+
get_attributes(&:public_reader?)
|
89
86
|
end
|
90
87
|
|
91
88
|
# Mass-assign attribute values
|
92
89
|
#
|
93
90
|
# Keys in the +attribute_values+ param can be symbols or strings.
|
94
|
-
#
|
95
|
-
# Non-attribute setter methods on the receiver will
|
91
|
+
# All referenced Attribute writer methods *will* be called.
|
92
|
+
# Non-attribute setter methods on the receiver *will* be called.
|
96
93
|
#
|
97
94
|
# @example
|
98
95
|
# class User
|
@@ -112,11 +109,7 @@ module Virtus
|
|
112
109
|
#
|
113
110
|
# @api public
|
114
111
|
def attributes=(attribute_values)
|
115
|
-
|
116
|
-
set_attributes(attribute_values.select { |name,|
|
117
|
-
attribute = attributes[name]
|
118
|
-
attribute && attribute.public_writer?
|
119
|
-
})
|
112
|
+
set_attributes(attribute_values)
|
120
113
|
end
|
121
114
|
|
122
115
|
# Returns a hash of all publicly accessible attributes
|
@@ -141,42 +134,28 @@ module Virtus
|
|
141
134
|
|
142
135
|
private
|
143
136
|
|
144
|
-
#
|
145
|
-
#
|
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.
|
149
|
-
#
|
150
|
-
# @example
|
151
|
-
# class User
|
152
|
-
# include Virtus
|
153
|
-
#
|
154
|
-
# attribute :name, String
|
155
|
-
# attribute :age, Integer
|
156
|
-
# end
|
157
|
-
#
|
158
|
-
# user = User.new
|
159
|
-
# user.attributes = { :name => 'John', 'age' => 28 }
|
160
|
-
#
|
161
|
-
# @param [#to_hash] attribute_values
|
162
|
-
# a hash of attribute names and values to set on the receiver
|
137
|
+
# Get values of all attributes defined for this class, ignoring privacy
|
163
138
|
#
|
164
139
|
# @return [Hash]
|
165
140
|
#
|
166
141
|
# @api private
|
167
|
-
def
|
168
|
-
|
142
|
+
def get_attributes
|
143
|
+
self.class.attributes.each_with_object({}) do |attribute, attributes|
|
144
|
+
name = attribute.name
|
145
|
+
attributes[name] = get_attribute(name) if yield(attribute)
|
146
|
+
end
|
169
147
|
end
|
170
148
|
|
171
|
-
#
|
149
|
+
# Mass-assign attribute values
|
150
|
+
#
|
151
|
+
# @see Virtus::InstanceMethods#attributes=
|
172
152
|
#
|
173
153
|
# @return [Hash]
|
174
154
|
#
|
175
155
|
# @api private
|
176
|
-
def
|
177
|
-
|
178
|
-
|
179
|
-
attributes[attribute_name] = get_attribute(attribute_name)
|
156
|
+
def set_attributes(attribute_values)
|
157
|
+
attribute_values.each do |name, value|
|
158
|
+
set_attribute(name, value) if self.class.allowed_writer_methods.include?("#{name}=")
|
180
159
|
end
|
181
160
|
end
|
182
161
|
|
@@ -3,8 +3,7 @@ module Virtus
|
|
3
3
|
# A module that adds type lookup to a class
|
4
4
|
module TypeLookup
|
5
5
|
|
6
|
-
TYPE_FORMAT
|
7
|
-
EXTRA_CONST_ARGS = RUBY_VERSION < '1.9' || RUBY_ENGINE == 'rbx' ? [] : [ false ]
|
6
|
+
TYPE_FORMAT = /\A[A-Z]\w*\z/.freeze
|
8
7
|
|
9
8
|
# Returns a descendant based on a name or class
|
10
9
|
#
|
data/lib/virtus/value_object.rb
CHANGED
@@ -4,6 +4,7 @@ require 'virtus'
|
|
4
4
|
require 'virtus/value_object/equalizer'
|
5
5
|
|
6
6
|
module Virtus
|
7
|
+
|
7
8
|
# Include this Module for Value Object semantics
|
8
9
|
#
|
9
10
|
# The idea is that instances should be immutable and compared based on state
|
@@ -22,6 +23,7 @@ module Virtus
|
|
22
23
|
# hash = { location => :foo }
|
23
24
|
# hash[same_location] #=> :foo
|
24
25
|
module ValueObject
|
26
|
+
|
25
27
|
# Callback to configure including Class as a Value Object
|
26
28
|
#
|
27
29
|
# Including Class will include Virtus and have additional
|
@@ -41,17 +43,25 @@ module Virtus
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
46
|
+
private_class_method :included
|
47
|
+
|
44
48
|
module InstanceMethods
|
49
|
+
# the #get_attributes method accept a Proc object that will filter
|
50
|
+
# out an attribute when the block returns false. the ValueObject
|
51
|
+
# needs all the attributes, so we allow every attribute.
|
52
|
+
FILTER_NONE = proc { true }
|
53
|
+
|
45
54
|
def initialize(attributes = {})
|
46
55
|
set_attributes(attributes)
|
47
56
|
end
|
48
57
|
|
49
58
|
def with(attribute_updates)
|
50
|
-
self.class.new(get_attributes.merge(attribute_updates))
|
59
|
+
self.class.new(get_attributes(&FILTER_NONE).merge(attribute_updates))
|
51
60
|
end
|
52
61
|
end
|
53
62
|
|
54
63
|
module ClassMethods
|
64
|
+
|
55
65
|
# Define an attribute on the receiver
|
56
66
|
#
|
57
67
|
# The Attribute will have private writer methods (eg., immutable instances)
|
@@ -73,7 +83,6 @@ module Virtus
|
|
73
83
|
def attribute(name, type, options = {})
|
74
84
|
equalizer << name
|
75
85
|
options[:writer] = :private
|
76
|
-
|
77
86
|
super
|
78
87
|
end
|
79
88
|
|
@@ -91,14 +100,28 @@ module Virtus
|
|
91
100
|
#
|
92
101
|
# @api public
|
93
102
|
def equalizer
|
94
|
-
|
103
|
+
@equalizer ||=
|
104
|
+
begin
|
105
|
+
equalizer = Equalizer.new(name || inspect)
|
106
|
+
include equalizer
|
107
|
+
equalizer
|
108
|
+
end
|
109
|
+
end
|
95
110
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
111
|
+
# The list of writer methods that can be mass-assigned to in #attributes=
|
112
|
+
#
|
113
|
+
# @return [Set]
|
114
|
+
#
|
115
|
+
# @api private
|
116
|
+
def allowed_writer_methods
|
117
|
+
@allowed_writer_methods ||=
|
118
|
+
begin
|
119
|
+
allowed_writer_methods = super
|
120
|
+
allowed_writer_methods += attributes.map{|attr| "#{attr.name}="}
|
121
|
+
allowed_writer_methods.to_set.freeze
|
122
|
+
end
|
101
123
|
end
|
124
|
+
|
102
125
|
end # module ClassMethods
|
103
126
|
end # module ValueObject
|
104
127
|
end # module Virtus
|