virtus 0.4.2 → 0.5.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 +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
|