virtus 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Changelog.md +11 -1
- data/README.md +47 -8
- data/config/flay.yml +1 -1
- data/lib/virtus.rb +25 -5
- data/lib/virtus/attribute.rb +1 -5
- data/lib/virtus/attribute/embedded_value.rb +20 -8
- data/lib/virtus/attribute/embedded_value/from_open_struct.rb +17 -0
- data/lib/virtus/attribute/embedded_value/from_struct.rb +17 -0
- data/lib/virtus/class_inclusions.rb +41 -0
- data/lib/virtus/class_methods.rb +18 -60
- data/lib/virtus/extensions.rb +93 -0
- data/lib/virtus/instance_methods.rb +7 -2
- data/lib/virtus/module_extensions.rb +62 -0
- data/lib/virtus/value_object.rb +19 -1
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/default_values_spec.rb +16 -0
- data/spec/integration/extending_objects_spec.rb +35 -0
- data/spec/integration/struct_as_embedded_value_spec.rb +28 -0
- data/spec/integration/using_modules_spec.rb +49 -0
- data/spec/integration/value_object_with_custom_constructor_spec.rb +42 -0
- data/spec/integration/virtus/value_object_spec.rb +6 -2
- data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +3 -1
- data/spec/unit/virtus/attribute/embedded_value/class_methods/determine_type_spec.rb +23 -0
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +8 -37
- data/spec/unit/virtus/attribute/embedded_value/from_open_struct/coerce_spec.rb +28 -0
- data/spec/unit/virtus/attribute/embedded_value/from_struct/coerce_spec.rb +28 -0
- data/spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb +2 -0
- data/spec/unit/virtus/class_methods/{attributes_spec.rb → attribute_set_spec.rb} +2 -2
- data/spec/unit/virtus/class_methods/attribute_spec.rb +1 -1
- data/spec/unit/virtus/{class_methods → extensions}/allowed_writer_methods_spec.rb +1 -1
- data/spec/unit/virtus/value_object/class_methods/attribute_spec.rb +1 -1
- data/spec/unit/virtus/value_object/instance_methods/duplicates_spec.rb +22 -0
- data/virtus.gemspec +2 -2
- metadata +26 -13
data/.gitignore
CHANGED
data/Changelog.md
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
# v0.
|
1
|
+
# v0.5.0 2012-06-08
|
2
|
+
|
3
|
+
* [feature] Support for extending objects (solnic)
|
4
|
+
* [feature] Support for defining attributes in modules (solnic)
|
5
|
+
* [feature] Support for Struct as an EmbeddedValue or ValueObject attribute (solnic)
|
6
|
+
* [changed] Allow any input for EmbeddedValue and ValueObject constructors (solnic)
|
7
|
+
* [changed] ValueObject instances cannot be duped or cloned (senny)
|
8
|
+
|
9
|
+
[Compare v0.4.2..master](https://github.com/solnic/virtus/compare/v0.4.2...master)
|
10
|
+
|
11
|
+
# v0.4.2 2012-05-08
|
2
12
|
|
3
13
|
* [updated] Bump backports dep to ~> 2.5.3 (solnic)
|
4
14
|
|
data/README.md
CHANGED
@@ -41,7 +41,7 @@ class User
|
|
41
41
|
end
|
42
42
|
|
43
43
|
user = User.new(:name => 'Piotr', :age => 28)
|
44
|
-
user.
|
44
|
+
user.attribute_set # => { :name => "Piotr", :age => 28 }
|
45
45
|
|
46
46
|
user.name # => "Piotr"
|
47
47
|
|
@@ -51,8 +51,48 @@ user.age.class # => Fixnum
|
|
51
51
|
user.birthday = 'November 18th, 1983' # => #<DateTime: 1983-11-18T00:00:00+00:00 (4891313/2,0/1,2299161)>
|
52
52
|
```
|
53
53
|
|
54
|
+
### Using Virtus With Modules
|
54
55
|
|
55
|
-
|
56
|
+
You can create modules extended with virtus and define attributes for later
|
57
|
+
inclusion in your classes:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
module Name
|
61
|
+
include Virtus
|
62
|
+
|
63
|
+
attribute :name, String
|
64
|
+
end
|
65
|
+
|
66
|
+
module Age
|
67
|
+
include Virtus
|
68
|
+
|
69
|
+
attribute :age, Integer
|
70
|
+
end
|
71
|
+
|
72
|
+
class User
|
73
|
+
include Name, Age
|
74
|
+
end
|
75
|
+
|
76
|
+
user = User.new(:name => 'John', :age => '30')
|
77
|
+
```
|
78
|
+
|
79
|
+
### Dynamically Extending Instances
|
80
|
+
|
81
|
+
It's also possible to dynamically extend an object with Virtus:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
class User
|
85
|
+
# nothing here
|
86
|
+
end
|
87
|
+
|
88
|
+
user = User.new
|
89
|
+
user.extend(Virtus)
|
90
|
+
user.attribute :name, String
|
91
|
+
user.name = 'John'
|
92
|
+
user.name # => 'John'
|
93
|
+
```
|
94
|
+
|
95
|
+
### Default Values
|
56
96
|
|
57
97
|
``` ruby
|
58
98
|
class Page
|
@@ -84,7 +124,7 @@ page.published # => false
|
|
84
124
|
page.editor_title # => "UNPUBLISHED: Virtus README"
|
85
125
|
```
|
86
126
|
|
87
|
-
|
127
|
+
### Embedded Value
|
88
128
|
|
89
129
|
``` ruby
|
90
130
|
class City
|
@@ -115,7 +155,7 @@ user.address.street # => "Street 1/2"
|
|
115
155
|
user.address.city.name # => "NYC"
|
116
156
|
```
|
117
157
|
|
118
|
-
|
158
|
+
### Collection Member Coercions
|
119
159
|
|
120
160
|
``` ruby
|
121
161
|
# Support "primitive" classes
|
@@ -163,7 +203,7 @@ user.phone_numbers # => [#<PhoneNumber:0x007fdb2d3bef88 @number="212-555-1212">,
|
|
163
203
|
user.addresses # => #<Set: {#<Address:0x007fdb2d3be448 @address="1234 Any St.", @locality="Anytown", @region="DC", @postal_code="21234">}>
|
164
204
|
```
|
165
205
|
|
166
|
-
|
206
|
+
### Value Objects
|
167
207
|
|
168
208
|
``` ruby
|
169
209
|
class GeoLocation
|
@@ -196,7 +236,7 @@ venue_other = Venue.new(
|
|
196
236
|
venue.location === venue_other.location # => true
|
197
237
|
```
|
198
238
|
|
199
|
-
|
239
|
+
### Adding Coercions
|
200
240
|
|
201
241
|
Virtus comes with a builtin coercion library.
|
202
242
|
It's super easy to add your own coercion classes.
|
@@ -235,7 +275,7 @@ user.name # => 'Piotr'
|
|
235
275
|
user.password # => '3858f62230ac3c915f300c664312c63f'
|
236
276
|
```
|
237
277
|
|
238
|
-
|
278
|
+
### Custom Attributes
|
239
279
|
|
240
280
|
``` ruby
|
241
281
|
require 'json'
|
@@ -265,7 +305,6 @@ user.info = '{"email":"john@domain.com"}' # => {"email"=>"john@domain.com"}
|
|
265
305
|
user.info.class # => Hash
|
266
306
|
```
|
267
307
|
|
268
|
-
|
269
308
|
Credits
|
270
309
|
-------
|
271
310
|
|
data/config/flay.yml
CHANGED
data/lib/virtus.rb
CHANGED
@@ -16,21 +16,35 @@ module Virtus
|
|
16
16
|
# Represents an undefined parameter used by auto-generated option methods
|
17
17
|
Undefined = Object.new.freeze
|
18
18
|
|
19
|
-
# Extends base class
|
19
|
+
# Extends base class or a module with virtus methods
|
20
20
|
#
|
21
21
|
# @param [Class] descendant
|
22
22
|
#
|
23
23
|
# @return [undefined]
|
24
24
|
#
|
25
25
|
# @api private
|
26
|
-
def self.included(
|
26
|
+
def self.included(object)
|
27
27
|
super
|
28
|
-
|
29
|
-
|
28
|
+
if Class === object
|
29
|
+
object.send(:include, ClassInclusions)
|
30
|
+
else
|
31
|
+
object.extend(ModuleExtensions)
|
32
|
+
end
|
30
33
|
end
|
31
|
-
|
32
34
|
private_class_method :included
|
33
35
|
|
36
|
+
# Extends an object with virtus extensions
|
37
|
+
#
|
38
|
+
# @param [Object] object
|
39
|
+
#
|
40
|
+
# @return [undefined]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
def self.extended(object)
|
44
|
+
object.extend(Extensions)
|
45
|
+
end
|
46
|
+
private_class_method :extended
|
47
|
+
|
34
48
|
end # module Virtus
|
35
49
|
|
36
50
|
require 'virtus/support/descendants_tracker'
|
@@ -38,6 +52,10 @@ require 'virtus/support/type_lookup'
|
|
38
52
|
require 'virtus/support/options'
|
39
53
|
require 'virtus/support/equalizer'
|
40
54
|
|
55
|
+
require 'virtus/extensions'
|
56
|
+
require 'virtus/class_inclusions'
|
57
|
+
require 'virtus/module_extensions'
|
58
|
+
|
41
59
|
require 'virtus/attributes_accessor'
|
42
60
|
require 'virtus/class_methods'
|
43
61
|
require 'virtus/instance_methods'
|
@@ -86,3 +104,5 @@ require 'virtus/attribute/symbol'
|
|
86
104
|
require 'virtus/attribute/string'
|
87
105
|
require 'virtus/attribute/time'
|
88
106
|
require 'virtus/attribute/embedded_value'
|
107
|
+
require 'virtus/attribute/embedded_value/from_struct'
|
108
|
+
require 'virtus/attribute/embedded_value/from_open_struct'
|
data/lib/virtus/attribute.rb
CHANGED
@@ -81,11 +81,7 @@ module Virtus
|
|
81
81
|
def self.determine_type(class_or_name)
|
82
82
|
case class_or_name
|
83
83
|
when ::Class
|
84
|
-
|
85
|
-
Attribute::EmbeddedValue
|
86
|
-
else
|
87
|
-
super
|
88
|
-
end
|
84
|
+
Attribute::EmbeddedValue.determine_type(class_or_name) || super
|
89
85
|
when ::Array, ::Set
|
90
86
|
super(class_or_name.class)
|
91
87
|
else
|
@@ -35,6 +35,24 @@ module Virtus
|
|
35
35
|
options.merge(:primitive => type)
|
36
36
|
end
|
37
37
|
|
38
|
+
# Determine type based on class
|
39
|
+
#
|
40
|
+
# Virtus::EmbeddedValue.determine_type(Struct) # => Virtus::EmbeddedValue::FromStruct
|
41
|
+
# Virtus::EmbeddedValue.determine_type(VirtusClass) # => Virtus::EmbeddedValue::FromOpenStruct
|
42
|
+
#
|
43
|
+
# @param [Class] klass
|
44
|
+
#
|
45
|
+
# @return [Virtus::Attribute::EmbeddedValue]
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def self.determine_type(klass)
|
49
|
+
if klass <= Virtus || klass <= OpenStruct
|
50
|
+
FromOpenStruct
|
51
|
+
elsif klass <= Struct
|
52
|
+
FromStruct
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
38
56
|
# Coerce attributes into a virtus object
|
39
57
|
#
|
40
58
|
# @param [Hash,Virtus]
|
@@ -42,14 +60,8 @@ module Virtus
|
|
42
60
|
# @return [Virtus]
|
43
61
|
#
|
44
62
|
# @api private
|
45
|
-
def coerce(
|
46
|
-
value
|
47
|
-
@primitive.new(attributes_or_object)
|
48
|
-
else
|
49
|
-
attributes_or_object
|
50
|
-
end
|
51
|
-
|
52
|
-
super(value)
|
63
|
+
def coerce(value)
|
64
|
+
value if value.kind_of?(@primitive)
|
53
65
|
end
|
54
66
|
|
55
67
|
end # class EmbeddedValue
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
class EmbeddedValue < Object
|
4
|
+
|
5
|
+
# EmbeddedValue attribute handling OpenStruct primitive or Virtus object
|
6
|
+
#
|
7
|
+
class FromOpenStruct < EmbeddedValue
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
def coerce(attributes)
|
11
|
+
super or @primitive.new(attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
end # class FromOpenStruct
|
15
|
+
end # class EmbeddedValue
|
16
|
+
end # class Attribute
|
17
|
+
end # module Virtus
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
class EmbeddedValue < Object
|
4
|
+
|
5
|
+
# EmbeddedValue attribute handling Struct primitive
|
6
|
+
#
|
7
|
+
class FromStruct < EmbeddedValue
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
def coerce(attributes)
|
11
|
+
super or @primitive.new(*attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
end # class FromStruct
|
15
|
+
end # class EmbeddedValue
|
16
|
+
end # class Attribute
|
17
|
+
end # module Virtus
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# Class-level extensions
|
4
|
+
module ClassInclusions
|
5
|
+
|
6
|
+
# Extends a descendant with class and instance methods
|
7
|
+
#
|
8
|
+
# @param [Class] descendant
|
9
|
+
#
|
10
|
+
# @return [undefined]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def self.included(descendant)
|
14
|
+
super
|
15
|
+
descendant.extend(ClassMethods)
|
16
|
+
descendant.send(:include, InstanceMethods)
|
17
|
+
end
|
18
|
+
private_class_method :included
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Return class' attribute set
|
23
|
+
#
|
24
|
+
# @return [Virtus::AttributeSet]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def attribute_set
|
28
|
+
self.class.attribute_set
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return a list of allowed writer method names
|
32
|
+
#
|
33
|
+
# @return [Set]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
def allowed_writer_methods
|
37
|
+
self.class.allowed_writer_methods
|
38
|
+
end
|
39
|
+
|
40
|
+
end # module ClassInclusions
|
41
|
+
end # module Virtus
|
data/lib/virtus/class_methods.rb
CHANGED
@@ -2,8 +2,7 @@ module Virtus
|
|
2
2
|
|
3
3
|
# Class methods that are added when you include Virtus
|
4
4
|
module ClassMethods
|
5
|
-
|
6
|
-
INVALID_WRITER_METHODS = %w[ == != === []= attributes= ].to_set.freeze
|
5
|
+
include Extensions
|
7
6
|
|
8
7
|
# Hook called when module is extended
|
9
8
|
#
|
@@ -22,39 +21,6 @@ module Virtus
|
|
22
21
|
|
23
22
|
private_class_method :extended
|
24
23
|
|
25
|
-
# Defines an attribute on an object's class
|
26
|
-
#
|
27
|
-
# @example
|
28
|
-
# class Book
|
29
|
-
# include Virtus
|
30
|
-
#
|
31
|
-
# attribute :title, String
|
32
|
-
# attribute :author, String
|
33
|
-
# attribute :published_at, DateTime
|
34
|
-
# attribute :page_count, Integer
|
35
|
-
# end
|
36
|
-
#
|
37
|
-
# @param [Symbol] name
|
38
|
-
# the name of an attribute
|
39
|
-
#
|
40
|
-
# @param [Class] type
|
41
|
-
# the type class of an attribute
|
42
|
-
#
|
43
|
-
# @param [#to_hash] options
|
44
|
-
# the extra options hash
|
45
|
-
#
|
46
|
-
# @return [self]
|
47
|
-
#
|
48
|
-
# @see Attribute.build
|
49
|
-
#
|
50
|
-
# @api public
|
51
|
-
def attribute(*args)
|
52
|
-
attribute = Attribute.build(*args)
|
53
|
-
attribute.define_accessor_methods(virtus_attributes_accessor_module)
|
54
|
-
virtus_add_attribute(attribute)
|
55
|
-
self
|
56
|
-
end
|
57
|
-
|
58
24
|
# Returns all the attributes defined on a Class
|
59
25
|
#
|
60
26
|
# @example
|
@@ -72,27 +38,22 @@ module Virtus
|
|
72
38
|
# @return [AttributeSet]
|
73
39
|
#
|
74
40
|
# @api public
|
75
|
-
def
|
76
|
-
return @
|
41
|
+
def attribute_set
|
42
|
+
return @attribute_set if defined?(@attribute_set)
|
77
43
|
superclass = self.superclass
|
78
44
|
method = __method__
|
79
45
|
parent = superclass.public_send(method) if superclass.respond_to?(method)
|
80
|
-
@
|
46
|
+
@attribute_set = AttributeSet.new(parent)
|
81
47
|
end
|
82
48
|
|
83
|
-
#
|
49
|
+
# @see Virtus::ClassMethods.attribute_set
|
84
50
|
#
|
85
|
-
# @
|
51
|
+
# @deprecated
|
86
52
|
#
|
87
|
-
# @api
|
88
|
-
def
|
89
|
-
|
90
|
-
|
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
|
53
|
+
# @api public
|
54
|
+
def attributes
|
55
|
+
warn "#{self}.attributes is deprecated. Use #{self}.attribute_set instead: #{caller.first}"
|
56
|
+
attribute_set
|
96
57
|
end
|
97
58
|
|
98
59
|
protected
|
@@ -104,8 +65,7 @@ module Virtus
|
|
104
65
|
# @api private
|
105
66
|
def virtus_setup_attributes_accessor_module
|
106
67
|
@virtus_attributes_accessor_module = AttributesAccessor.new(inspect)
|
107
|
-
include virtus_attributes_accessor_module
|
108
|
-
self
|
68
|
+
include @virtus_attributes_accessor_module
|
109
69
|
end
|
110
70
|
|
111
71
|
private
|
@@ -128,13 +88,6 @@ module Virtus
|
|
128
88
|
descendant.virtus_setup_attributes_accessor_module
|
129
89
|
end
|
130
90
|
|
131
|
-
# Holds the anonymous module which hosts this class's Attribute accessors
|
132
|
-
#
|
133
|
-
# @return [Module]
|
134
|
-
#
|
135
|
-
# @api private
|
136
|
-
attr_reader :virtus_attributes_accessor_module
|
137
|
-
|
138
91
|
# Hooks into const missing process to determine types of attributes
|
139
92
|
#
|
140
93
|
# @param [String] name
|
@@ -154,8 +107,13 @@ module Virtus
|
|
154
107
|
#
|
155
108
|
# @api private
|
156
109
|
def virtus_add_attribute(attribute)
|
157
|
-
|
158
|
-
descendants.each { |descendant| descendant.
|
110
|
+
super
|
111
|
+
descendants.each { |descendant| descendant.attribute_set.reset }
|
112
|
+
end
|
113
|
+
|
114
|
+
# @api private
|
115
|
+
def public_method_list
|
116
|
+
public_instance_methods
|
159
117
|
end
|
160
118
|
|
161
119
|
end # module ClassMethods
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# Extensions common for both classes and instances
|
4
|
+
module Extensions
|
5
|
+
WRITER_METHOD_REGEXP = /=\z/.freeze
|
6
|
+
INVALID_WRITER_METHODS = %w[ == != === []= attributes= ].to_set.freeze
|
7
|
+
|
8
|
+
# A hook called when an object is extended with Virtus
|
9
|
+
#
|
10
|
+
# @param [Object] object
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def self.extended(object)
|
16
|
+
object.extend(InstanceMethods)
|
17
|
+
object.instance_eval do
|
18
|
+
@virtus_attributes_accessor_module = AttributesAccessor.new(object.class.inspect)
|
19
|
+
extend @virtus_attributes_accessor_module
|
20
|
+
end
|
21
|
+
end
|
22
|
+
private_class_method :extended
|
23
|
+
|
24
|
+
# Defines an attribute on an object's class
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# class Book
|
28
|
+
# include Virtus
|
29
|
+
#
|
30
|
+
# attribute :title, String
|
31
|
+
# attribute :author, String
|
32
|
+
# attribute :published_at, DateTime
|
33
|
+
# attribute :page_count, Integer
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# @param [Symbol] name
|
37
|
+
# the name of an attribute
|
38
|
+
#
|
39
|
+
# @param [Class] type
|
40
|
+
# the type class of an attribute
|
41
|
+
#
|
42
|
+
# @param [#to_hash] options
|
43
|
+
# the extra options hash
|
44
|
+
#
|
45
|
+
# @return [self]
|
46
|
+
#
|
47
|
+
# @see Attribute.build
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def attribute(*args)
|
51
|
+
attribute = Attribute.build(*args)
|
52
|
+
attribute.define_accessor_methods(@virtus_attributes_accessor_module)
|
53
|
+
virtus_add_attribute(attribute)
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# The list of writer methods that can be mass-assigned to in #attributes=
|
58
|
+
#
|
59
|
+
# @return [Set]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
def allowed_writer_methods
|
63
|
+
@allowed_writer_methods ||=
|
64
|
+
begin
|
65
|
+
allowed_writer_methods = public_method_list.map(&:to_s)
|
66
|
+
allowed_writer_methods = allowed_writer_methods.grep(WRITER_METHOD_REGEXP).to_set
|
67
|
+
allowed_writer_methods -= INVALID_WRITER_METHODS
|
68
|
+
allowed_writer_methods.freeze
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Return an attribute set for that instance
|
75
|
+
#
|
76
|
+
# @return [AttributeSet]
|
77
|
+
#
|
78
|
+
# @api private
|
79
|
+
def attribute_set
|
80
|
+
@attribute_set ||= AttributeSet.new
|
81
|
+
end
|
82
|
+
|
83
|
+
# Add an attribute to the attribute set
|
84
|
+
#
|
85
|
+
# @return [AttributeSet]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
def virtus_add_attribute(attribute)
|
89
|
+
attribute_set << attribute
|
90
|
+
end
|
91
|
+
|
92
|
+
end # module Extensions
|
93
|
+
end # module Virtus
|
@@ -140,7 +140,7 @@ module Virtus
|
|
140
140
|
#
|
141
141
|
# @api private
|
142
142
|
def get_attributes
|
143
|
-
|
143
|
+
attribute_set.each_with_object({}) do |attribute, attributes|
|
144
144
|
name = attribute.name
|
145
145
|
attributes[name] = get_attribute(name) if yield(attribute)
|
146
146
|
end
|
@@ -155,7 +155,7 @@ module Virtus
|
|
155
155
|
# @api private
|
156
156
|
def set_attributes(attributes)
|
157
157
|
::Hash.try_convert(attributes).each do |name, value|
|
158
|
-
set_attribute(name, value) if
|
158
|
+
set_attribute(name, value) if allowed_writer_methods.include?("#{name}=")
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
@@ -181,5 +181,10 @@ module Virtus
|
|
181
181
|
__send__("#{name}=", value)
|
182
182
|
end
|
183
183
|
|
184
|
+
# @api private
|
185
|
+
def public_method_list
|
186
|
+
public_methods
|
187
|
+
end
|
188
|
+
|
184
189
|
end # module InstanceMethods
|
185
190
|
end # module Virtus
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# Virtus module that can define attributes for later inclusion
|
4
|
+
#
|
5
|
+
module ModuleExtensions
|
6
|
+
|
7
|
+
def attribute(*args)
|
8
|
+
attribute_definitions << args
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Extend an object with Virtus methods and define attributes
|
14
|
+
#
|
15
|
+
# @param [Object] object
|
16
|
+
#
|
17
|
+
# @return [undefined]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
def extended(object)
|
21
|
+
super
|
22
|
+
object.extend(Virtus)
|
23
|
+
define_attributes(object)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Extend a class with Virtus methods and define attributes
|
27
|
+
#
|
28
|
+
# @param [Object] object
|
29
|
+
#
|
30
|
+
# @return [undefined]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def included(object)
|
34
|
+
super
|
35
|
+
object.send(:include, ClassInclusions)
|
36
|
+
define_attributes(object)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return attribute definitions
|
40
|
+
#
|
41
|
+
# @return [Array<Hash>]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
def attribute_definitions
|
45
|
+
@_attribute_definitions ||= []
|
46
|
+
end
|
47
|
+
|
48
|
+
# Define attributes on a class or instance
|
49
|
+
#
|
50
|
+
# @param [Object,Class] object
|
51
|
+
#
|
52
|
+
# @return [undefined]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
def define_attributes(object)
|
56
|
+
attribute_definitions.each do |attribute_args|
|
57
|
+
object.attribute(*attribute_args)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end # class ModuleExtensions
|
62
|
+
end # module Virtus
|
data/lib/virtus/value_object.rb
CHANGED
@@ -41,6 +41,7 @@ module Virtus
|
|
41
41
|
private_class_method :included
|
42
42
|
|
43
43
|
module InstanceMethods
|
44
|
+
|
44
45
|
# the #get_attributes method accept a Proc object that will filter
|
45
46
|
# out an attribute when the block returns false. the ValueObject
|
46
47
|
# needs all the attributes, so we allow every attribute.
|
@@ -53,6 +54,23 @@ module Virtus
|
|
53
54
|
def with(attribute_updates)
|
54
55
|
self.class.new(get_attributes(&FILTER_NONE).merge(attribute_updates))
|
55
56
|
end
|
57
|
+
|
58
|
+
# ValueObjects are immutable and can't be cloned
|
59
|
+
#
|
60
|
+
# They always represent the same value
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
#
|
64
|
+
# value_object.clone === value_object # => true
|
65
|
+
#
|
66
|
+
# @return [self]
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def clone
|
70
|
+
self
|
71
|
+
end
|
72
|
+
alias dup clone
|
73
|
+
|
56
74
|
end
|
57
75
|
|
58
76
|
module ClassMethods
|
@@ -112,7 +130,7 @@ module Virtus
|
|
112
130
|
@allowed_writer_methods ||=
|
113
131
|
begin
|
114
132
|
allowed_writer_methods = super
|
115
|
-
allowed_writer_methods +=
|
133
|
+
allowed_writer_methods += attribute_set.map{|attr| "#{attr.name}="}
|
116
134
|
allowed_writer_methods.to_set.freeze
|
117
135
|
end
|
118
136
|
end
|
data/lib/virtus/version.rb
CHANGED
@@ -4,6 +4,13 @@ describe "default values" do
|
|
4
4
|
|
5
5
|
before do
|
6
6
|
module Examples
|
7
|
+
|
8
|
+
class Reference
|
9
|
+
include Virtus::ValueObject
|
10
|
+
|
11
|
+
attribute :ref, String
|
12
|
+
end
|
13
|
+
|
7
14
|
class Page
|
8
15
|
include Virtus
|
9
16
|
|
@@ -12,6 +19,7 @@ describe "default values" do
|
|
12
19
|
attribute :view_count, Integer, :default => 0
|
13
20
|
attribute :published, Boolean, :default => false, :accessor => :private
|
14
21
|
attribute :editor_title, String, :default => :default_editor_title
|
22
|
+
attribute :reference, String, :default => Reference.new
|
15
23
|
|
16
24
|
def default_editor_title
|
17
25
|
published? ? title : "UNPUBLISHED: #{title}"
|
@@ -41,4 +49,12 @@ describe "default values" do
|
|
41
49
|
subject.editor_title.should == 'UNPUBLISHED: Top Secret'
|
42
50
|
end
|
43
51
|
|
52
|
+
context 'with a ValueObject' do
|
53
|
+
it 'should not duplicate the ValueObject' do
|
54
|
+
page1 = Examples::Page.new
|
55
|
+
page2 = Examples::Page.new
|
56
|
+
page1.reference.should equal(page2.reference)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
44
60
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'I can extend objects' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class User; end
|
7
|
+
|
8
|
+
class Admin; end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
specify 'defining attributes on an object' do
|
13
|
+
attributes = { :name => 'John', :age => 29 }
|
14
|
+
|
15
|
+
admin = Examples::Admin.new
|
16
|
+
admin.extend(Virtus)
|
17
|
+
|
18
|
+
admin.attribute :name, String
|
19
|
+
admin.attribute :age, Integer
|
20
|
+
|
21
|
+
admin.name = 'John'
|
22
|
+
admin.age = 29
|
23
|
+
|
24
|
+
admin.name.should eql('John')
|
25
|
+
admin.age.should eql(29)
|
26
|
+
|
27
|
+
admin.attributes.should eql(attributes)
|
28
|
+
|
29
|
+
new_attributes = { :name => 'Jane', :age => 28 }
|
30
|
+
admin.attributes = new_attributes
|
31
|
+
|
32
|
+
admin.name.should eql('Jane')
|
33
|
+
admin.age.should eql(28)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Using Struct as an embedded value attribute' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
Point = Struct.new(:x, :y)
|
7
|
+
|
8
|
+
class Rectangle
|
9
|
+
include Virtus
|
10
|
+
|
11
|
+
attribute :top_left, Point
|
12
|
+
attribute :bottom_right, Point
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
subject do
|
18
|
+
Examples::Rectangle.new(:top_left => [ 3, 5 ], :bottom_right => [ 8, 7 ])
|
19
|
+
end
|
20
|
+
|
21
|
+
specify 'initialize a struct object with correct attributes' do
|
22
|
+
subject.top_left.x.should be(3)
|
23
|
+
subject.top_left.y.should be(5)
|
24
|
+
|
25
|
+
subject.bottom_right.x.should be(8)
|
26
|
+
subject.bottom_right.y.should be(7)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'I can define attributes within a module' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
module Name
|
7
|
+
include Virtus
|
8
|
+
|
9
|
+
attribute :name, String
|
10
|
+
end
|
11
|
+
|
12
|
+
module Age
|
13
|
+
include Virtus
|
14
|
+
|
15
|
+
attribute :age, Integer
|
16
|
+
end
|
17
|
+
|
18
|
+
class User
|
19
|
+
include Name
|
20
|
+
end
|
21
|
+
|
22
|
+
class Admin < User
|
23
|
+
include Age
|
24
|
+
end
|
25
|
+
|
26
|
+
class Moderator; end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
specify 'including a module with attributes into a class' do
|
31
|
+
Examples::User.attribute_set[:name].should be_instance_of(Virtus::Attribute::String)
|
32
|
+
|
33
|
+
Examples::Admin.attribute_set[:name].should be_instance_of(Virtus::Attribute::String)
|
34
|
+
Examples::Admin.attribute_set[:age].should be_instance_of(Virtus::Attribute::Integer)
|
35
|
+
|
36
|
+
user = Examples::Admin.new(:name => 'Piotr', :age => 29)
|
37
|
+
user.name.should eql('Piotr')
|
38
|
+
user.age.should eql(29)
|
39
|
+
end
|
40
|
+
|
41
|
+
specify 'including a module with attributes into an instance' do
|
42
|
+
moderator = Examples::Moderator.new
|
43
|
+
moderator.extend(Examples::Name, Examples::Age)
|
44
|
+
|
45
|
+
moderator.attributes = { :name => 'John', :age => 21 }
|
46
|
+
moderator.name.should eql('John')
|
47
|
+
moderator.age.should eql(21)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Defining a ValueObject with a custom constructor" do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class Point
|
7
|
+
include Virtus::ValueObject
|
8
|
+
|
9
|
+
attribute :x, Integer
|
10
|
+
attribute :y, Integer
|
11
|
+
|
12
|
+
def initialize(attributes)
|
13
|
+
if attributes.kind_of?(Array)
|
14
|
+
self.x = attributes.first
|
15
|
+
self.y = attributes.last
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Rectangle
|
23
|
+
include Virtus
|
24
|
+
|
25
|
+
attribute :top_left, Point
|
26
|
+
attribute :bottom_right, Point
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
subject do
|
32
|
+
Examples::Rectangle.new(:top_left => [ 3, 4 ], :bottom_right => [ 5, 8 ])
|
33
|
+
end
|
34
|
+
|
35
|
+
specify "initialize a value object attribute with correct attributes" do
|
36
|
+
subject.top_left.x.should be(3)
|
37
|
+
subject.top_left.y.should be(4)
|
38
|
+
|
39
|
+
subject.bottom_right.x.should be(5)
|
40
|
+
subject.bottom_right.y.should be(8)
|
41
|
+
end
|
42
|
+
end
|
@@ -13,11 +13,15 @@ describe Virtus::ValueObject do
|
|
13
13
|
attribute :longitude, Float
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
16
17
|
let(:attribute_values) { { :latitude => 10.0, :longitude => 20.0 } }
|
18
|
+
|
17
19
|
let(:instance_with_equal_state) { class_under_test.new(attribute_values) }
|
20
|
+
|
18
21
|
let(:instance_with_different_state) do
|
19
22
|
class_under_test.new(:latitude => attribute_values[:latitude])
|
20
23
|
end
|
24
|
+
|
21
25
|
subject { class_under_test.new(attribute_values) }
|
22
26
|
|
23
27
|
describe 'initialization' do
|
@@ -29,8 +33,8 @@ describe Virtus::ValueObject do
|
|
29
33
|
|
30
34
|
describe 'writer visibility' do
|
31
35
|
it 'attributes are configured for private writers' do
|
32
|
-
class_under_test.
|
33
|
-
class_under_test.
|
36
|
+
class_under_test.attribute_set[:latitude].public_reader?.should be(true)
|
37
|
+
class_under_test.attribute_set[:longitude].public_writer?.should be(false)
|
34
38
|
end
|
35
39
|
|
36
40
|
it 'writer methods are set to private' do
|
@@ -4,6 +4,8 @@ describe Virtus::Attribute, '.determine_type' do
|
|
4
4
|
let(:object) { described_class }
|
5
5
|
|
6
6
|
(described_class.descendants - [ Virtus::Attribute::Collection ]).each do |attribute_class|
|
7
|
+
next if attribute_class <= Virtus::Attribute::EmbeddedValue
|
8
|
+
|
7
9
|
context "with class #{attribute_class.inspect}" do
|
8
10
|
subject { object.determine_type(attribute_class) }
|
9
11
|
|
@@ -36,7 +38,7 @@ describe Virtus::Attribute, '.determine_type' do
|
|
36
38
|
|
37
39
|
let(:primitive) { Class.new { include Virtus } }
|
38
40
|
|
39
|
-
it { should equal(Virtus::Attribute::EmbeddedValue) }
|
41
|
+
it { should equal(Virtus::Attribute::EmbeddedValue::FromOpenStruct) }
|
40
42
|
end
|
41
43
|
|
42
44
|
context 'when the primitive defaults to Object' do
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::EmbeddedValue, '.determine_type' do
|
4
|
+
subject { described_class.determine_type(value) }
|
5
|
+
|
6
|
+
context "with Struct" do
|
7
|
+
let(:value) { Struct.new(:x) }
|
8
|
+
|
9
|
+
it { should be(Virtus::Attribute::EmbeddedValue::FromStruct) }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with OpenStruct" do
|
13
|
+
let(:value) { OpenStruct }
|
14
|
+
|
15
|
+
it { should be(Virtus::Attribute::EmbeddedValue::FromOpenStruct) }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "with a Virtus descendant" do
|
19
|
+
let(:value) { Class.new { include Virtus; self } }
|
20
|
+
|
21
|
+
it { should be(Virtus::Attribute::EmbeddedValue::FromOpenStruct) }
|
22
|
+
end
|
23
|
+
end
|
@@ -3,47 +3,18 @@ require 'spec_helper'
|
|
3
3
|
describe Virtus::Attribute::EmbeddedValue, '#coerce' do
|
4
4
|
subject { object.coerce(value) }
|
5
5
|
|
6
|
-
let(:
|
7
|
-
let(:
|
8
|
-
let(:
|
6
|
+
let(:object) { described_class.new(:name, :primitive => primitive) }
|
7
|
+
let(:instance) { Object.new }
|
8
|
+
let(:value) { primitive.new }
|
9
9
|
|
10
|
-
context 'when the value is a
|
11
|
-
let(:
|
10
|
+
context 'when the value is a virtus object' do
|
11
|
+
let(:primitive) { Class.new { include Virtus } }
|
12
12
|
|
13
|
-
|
14
|
-
let(:object) { described_class.new(attribute_name, :primitive => model) }
|
15
|
-
let(:model) { mock('model') }
|
16
|
-
let(:model_instance) { mock('model_instance') }
|
17
|
-
|
18
|
-
before do
|
19
|
-
model.should_receive(:new).with(value).and_return(model_instance)
|
20
|
-
end
|
21
|
-
|
22
|
-
it { should be(model_instance) }
|
23
|
-
end
|
24
|
-
|
25
|
-
context 'with the default OpenStruct model' do
|
26
|
-
let(:model_instance) { OpenStruct.new(value) }
|
27
|
-
|
28
|
-
context 'when the options are an empty Hash' do
|
29
|
-
let(:object) { described_class.new(attribute_name, {}) }
|
30
|
-
|
31
|
-
it { should == model_instance }
|
32
|
-
end
|
33
|
-
|
34
|
-
context 'when the options are not provided' do
|
35
|
-
let(:object) { described_class.new(attribute_name) }
|
36
|
-
|
37
|
-
it { should == model_instance }
|
38
|
-
end
|
39
|
-
end
|
13
|
+
it { should be(value) }
|
40
14
|
end
|
41
15
|
|
42
|
-
context 'when the value is
|
43
|
-
let(:
|
44
|
-
let(:value) { mock('value') }
|
45
|
-
|
46
|
-
before { model.should_not_receive(:new) }
|
16
|
+
context 'when the value is a virtus value object' do
|
17
|
+
let(:primitive) { Class.new { include Virtus::ValueObject } }
|
47
18
|
|
48
19
|
it { should be(value) }
|
49
20
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::EmbeddedValue::FromOpenStruct, '#coerce' do
|
4
|
+
subject { object.coerce(value) }
|
5
|
+
|
6
|
+
let(:primitive) { OpenStruct }
|
7
|
+
|
8
|
+
let(:object) do
|
9
|
+
described_class.new(:name, :primitive => primitive)
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when the value is a primitive instance' do
|
13
|
+
let(:value) { primitive.new }
|
14
|
+
|
15
|
+
it { should be(value) }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when the value is a hash' do
|
19
|
+
let(:value) { Hash[:foo => 'bar'] }
|
20
|
+
let(:instance) { mock('instance') }
|
21
|
+
|
22
|
+
before do
|
23
|
+
primitive.should_receive(:new).with(value).and_return(instance)
|
24
|
+
end
|
25
|
+
|
26
|
+
it { should be(instance) }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::Attribute::EmbeddedValue::FromStruct, '#coerce' do
|
4
|
+
subject { object.coerce(value) }
|
5
|
+
|
6
|
+
let(:primitive) { Struct.new(:x, :y) }
|
7
|
+
|
8
|
+
let(:object) do
|
9
|
+
described_class.new(:name, :primitive => primitive)
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when the value is a primitive instance' do
|
13
|
+
let(:value) { primitive.new }
|
14
|
+
|
15
|
+
it { should be(value) }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when the value is an array' do
|
19
|
+
let(:value) { [ 1 ,2 ] }
|
20
|
+
let(:instance) { mock('instance') }
|
21
|
+
|
22
|
+
before do
|
23
|
+
primitive.should_receive(:new).with(*value).and_return(instance)
|
24
|
+
end
|
25
|
+
|
26
|
+
it { should be(instance) }
|
27
|
+
end
|
28
|
+
end
|
@@ -3,6 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe Virtus::Attribute::Object, '.descendants' do
|
4
4
|
subject { described_class.descendants.map { |c| c.to_s }.sort }
|
5
5
|
|
6
|
+
before { pending 'Remove this spec in favor of Virtus::DescentantsTracker spec' }
|
7
|
+
|
6
8
|
let(:known_descendants) do
|
7
9
|
[ Virtus::Attribute::EmbeddedValue, Virtus::Attribute::Symbol,
|
8
10
|
Virtus::Attribute::Time, Virtus::Attribute::String,
|
@@ -9,7 +9,7 @@ describe Virtus::ClassMethods, '#attribute' do
|
|
9
9
|
let(:type) { Virtus::Attribute::String }
|
10
10
|
|
11
11
|
def assert_attribute_added(klass, name, attribute_class)
|
12
|
-
attributes = klass.
|
12
|
+
attributes = klass.attribute_set
|
13
13
|
attributes[name].should be_nil
|
14
14
|
subject
|
15
15
|
attribute = attributes[name]
|
@@ -6,7 +6,7 @@ describe Virtus::ValueObject, '.attribute' do
|
|
6
6
|
let(:object) { Class.new { include Virtus::ValueObject } }
|
7
7
|
let(:name) { :latitude }
|
8
8
|
let(:type) { Float }
|
9
|
-
let(:attribute) { object.
|
9
|
+
let(:attribute) { object.attribute_set[name] }
|
10
10
|
|
11
11
|
it { should be(object) }
|
12
12
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus::ValueObject::InstanceMethods, 'duplication' do
|
4
|
+
let(:described_class) do
|
5
|
+
Class.new do
|
6
|
+
include Virtus::ValueObject
|
7
|
+
|
8
|
+
attribute :name, String
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject { described_class.new }
|
13
|
+
|
14
|
+
it '#clone returns the same instance' do
|
15
|
+
subject.should equal(subject.clone)
|
16
|
+
end
|
17
|
+
|
18
|
+
it '#dup returns the same instance' do
|
19
|
+
subject.should equal(subject.dup)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/virtus.gemspec
CHANGED
@@ -16,9 +16,9 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
17
17
|
gem.extra_rdoc_files = %w[LICENSE README.md TODO]
|
18
18
|
|
19
|
-
gem.add_runtime_dependency('backports', '~> 2.
|
19
|
+
gem.add_runtime_dependency('backports', '~> 2.6.1')
|
20
20
|
|
21
21
|
gem.add_development_dependency('rake', '~> 0.9.2')
|
22
22
|
gem.add_development_dependency('rspec', '~> 1.3.2')
|
23
|
-
gem.add_development_dependency('guard-rspec', '~> 0.
|
23
|
+
gem.add_development_dependency('guard-rspec', '~> 1.0.0')
|
24
24
|
end
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 5
|
9
|
+
- 0
|
10
|
+
version: 0.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Piotr Solnica
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-06-08 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: backports
|
@@ -25,12 +25,12 @@ dependencies:
|
|
25
25
|
requirements:
|
26
26
|
- - ~>
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
28
|
+
hash: 21
|
29
29
|
segments:
|
30
30
|
- 2
|
31
|
-
-
|
32
|
-
-
|
33
|
-
version: 2.
|
31
|
+
- 6
|
32
|
+
- 1
|
33
|
+
version: 2.6.1
|
34
34
|
type: :runtime
|
35
35
|
version_requirements: *id001
|
36
36
|
- !ruby/object:Gem::Dependency
|
@@ -73,12 +73,12 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
hash:
|
76
|
+
hash: 23
|
77
77
|
segments:
|
78
|
+
- 1
|
78
79
|
- 0
|
79
|
-
- 6
|
80
80
|
- 0
|
81
|
-
version: 0.
|
81
|
+
version: 1.0.0
|
82
82
|
type: :development
|
83
83
|
version_requirements: *id004
|
84
84
|
description: Attributes on Steroids for Plain Old Ruby Objects
|
@@ -124,6 +124,8 @@ files:
|
|
124
124
|
- lib/virtus/attribute/default_value/from_clonable.rb
|
125
125
|
- lib/virtus/attribute/default_value/from_symbol.rb
|
126
126
|
- lib/virtus/attribute/embedded_value.rb
|
127
|
+
- lib/virtus/attribute/embedded_value/from_open_struct.rb
|
128
|
+
- lib/virtus/attribute/embedded_value/from_struct.rb
|
127
129
|
- lib/virtus/attribute/float.rb
|
128
130
|
- lib/virtus/attribute/hash.rb
|
129
131
|
- lib/virtus/attribute/integer.rb
|
@@ -135,6 +137,7 @@ files:
|
|
135
137
|
- lib/virtus/attribute/time.rb
|
136
138
|
- lib/virtus/attribute_set.rb
|
137
139
|
- lib/virtus/attributes_accessor.rb
|
140
|
+
- lib/virtus/class_inclusions.rb
|
138
141
|
- lib/virtus/class_methods.rb
|
139
142
|
- lib/virtus/coercion.rb
|
140
143
|
- lib/virtus/coercion/array.rb
|
@@ -152,7 +155,9 @@ files:
|
|
152
155
|
- lib/virtus/coercion/time.rb
|
153
156
|
- lib/virtus/coercion/time_coercions.rb
|
154
157
|
- lib/virtus/coercion/true_class.rb
|
158
|
+
- lib/virtus/extensions.rb
|
155
159
|
- lib/virtus/instance_methods.rb
|
160
|
+
- lib/virtus/module_extensions.rb
|
156
161
|
- lib/virtus/support/descendants_tracker.rb
|
157
162
|
- lib/virtus/support/equalizer.rb
|
158
163
|
- lib/virtus/support/options.rb
|
@@ -164,8 +169,12 @@ files:
|
|
164
169
|
- spec/integration/default_values_spec.rb
|
165
170
|
- spec/integration/defining_attributes_spec.rb
|
166
171
|
- spec/integration/embedded_value_spec.rb
|
172
|
+
- spec/integration/extending_objects_spec.rb
|
167
173
|
- spec/integration/mass_assignment_with_accessors_spec.rb
|
168
174
|
- spec/integration/overriding_virtus_spec.rb
|
175
|
+
- spec/integration/struct_as_embedded_value_spec.rb
|
176
|
+
- spec/integration/using_modules_spec.rb
|
177
|
+
- spec/integration/value_object_with_custom_constructor_spec.rb
|
169
178
|
- spec/integration/virtus/instance_level_attributes_spec.rb
|
170
179
|
- spec/integration/virtus/value_object_spec.rb
|
171
180
|
- spec/rcov.opts
|
@@ -214,8 +223,11 @@ files:
|
|
214
223
|
- spec/unit/virtus/attribute/define_accessor_methods_spec.rb
|
215
224
|
- spec/unit/virtus/attribute/define_reader_method_spec.rb
|
216
225
|
- spec/unit/virtus/attribute/define_writer_method_spec.rb
|
226
|
+
- spec/unit/virtus/attribute/embedded_value/class_methods/determine_type_spec.rb
|
217
227
|
- spec/unit/virtus/attribute/embedded_value/class_methods/merge_options_spec.rb
|
218
228
|
- spec/unit/virtus/attribute/embedded_value/coerce_spec.rb
|
229
|
+
- spec/unit/virtus/attribute/embedded_value/from_open_struct/coerce_spec.rb
|
230
|
+
- spec/unit/virtus/attribute/embedded_value/from_struct/coerce_spec.rb
|
219
231
|
- spec/unit/virtus/attribute/float/coerce_spec.rb
|
220
232
|
- spec/unit/virtus/attribute/get_spec.rb
|
221
233
|
- spec/unit/virtus/attribute/inspect_spec.rb
|
@@ -243,9 +255,8 @@ files:
|
|
243
255
|
- spec/unit/virtus/attributes_accessor/define_reader_method_spec.rb
|
244
256
|
- spec/unit/virtus/attributes_accessor/define_writer_method_spec.rb
|
245
257
|
- spec/unit/virtus/attributes_accessor/inspect_spec.rb
|
246
|
-
- spec/unit/virtus/class_methods/
|
258
|
+
- spec/unit/virtus/class_methods/attribute_set_spec.rb
|
247
259
|
- spec/unit/virtus/class_methods/attribute_spec.rb
|
248
|
-
- spec/unit/virtus/class_methods/attributes_spec.rb
|
249
260
|
- spec/unit/virtus/class_methods/const_missing_spec.rb
|
250
261
|
- spec/unit/virtus/class_methods/inherited_spec.rb
|
251
262
|
- spec/unit/virtus/coercion/array/class_methods/to_set_spec.rb
|
@@ -308,6 +319,7 @@ files:
|
|
308
319
|
- spec/unit/virtus/equalizer/class_method/new_spec.rb
|
309
320
|
- spec/unit/virtus/equalizer/methods/eql_spec.rb
|
310
321
|
- spec/unit/virtus/equalizer/methods/equal_value_spec.rb
|
322
|
+
- spec/unit/virtus/extensions/allowed_writer_methods_spec.rb
|
311
323
|
- spec/unit/virtus/instance_methods/attributes_spec.rb
|
312
324
|
- spec/unit/virtus/instance_methods/element_reference_spec.rb
|
313
325
|
- spec/unit/virtus/instance_methods/element_set_spec.rb
|
@@ -323,6 +335,7 @@ files:
|
|
323
335
|
- spec/unit/virtus/value_object/class_methods/attribute_spec.rb
|
324
336
|
- spec/unit/virtus/value_object/class_methods/equalizer_spec.rb
|
325
337
|
- spec/unit/virtus/value_object/initialize_spec.rb
|
338
|
+
- spec/unit/virtus/value_object/instance_methods/duplicates_spec.rb
|
326
339
|
- spec/unit/virtus/value_object/instance_methods/with_spec.rb
|
327
340
|
- tasks/metrics/ci.rake
|
328
341
|
- tasks/metrics/flay.rake
|