virtus 1.0.0.beta7 → 1.0.0.beta8
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/README.md +31 -2
- data/lib/virtus.rb +7 -0
- data/lib/virtus/attribute.rb +11 -4
- data/lib/virtus/attribute/builder.rb +111 -44
- data/lib/virtus/attribute/collection.rb +25 -6
- data/lib/virtus/attribute/embedded_value.rb +3 -2
- data/lib/virtus/attribute/hash.rb +23 -7
- data/lib/virtus/attribute_set.rb +9 -1
- data/lib/virtus/configuration.rb +4 -0
- data/lib/virtus/module_builder.rb +8 -0
- data/lib/virtus/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +1 -0
- data/spec/unit/virtus/attribute/hash/coerce_spec.rb +2 -0
- data/spec/unit/virtus/class_methods/finalize_spec.rb +55 -0
- metadata +3 -2
data/README.md
CHANGED
@@ -476,6 +476,9 @@ class User
|
|
476
476
|
end
|
477
477
|
```
|
478
478
|
|
479
|
+
Please check out [Coercible README](https://github.com/solnic/coercible/blob/master/README.md)
|
480
|
+
for more information.
|
481
|
+
|
479
482
|
## Strict Coercion Mode
|
480
483
|
|
481
484
|
By default Virtus returns the input value even when it couldn't coerce it to the expected type.
|
@@ -519,8 +522,34 @@ class User
|
|
519
522
|
end
|
520
523
|
```
|
521
524
|
|
522
|
-
|
523
|
-
|
525
|
+
## Attribute Finalization and Circular Dependencies
|
526
|
+
|
527
|
+
If a type references another type which happens to not be available yet you need
|
528
|
+
to use lazy-finalization of attributes and finalize virtus manually after all
|
529
|
+
types have been already loaded:
|
530
|
+
|
531
|
+
``` ruby
|
532
|
+
# in blog.rb
|
533
|
+
class Blog
|
534
|
+
include Virtus.model(:finalize => false)
|
535
|
+
|
536
|
+
attribute :posts, Array['Post']
|
537
|
+
end
|
538
|
+
|
539
|
+
# in post.rb
|
540
|
+
class Post
|
541
|
+
include Virtus.model(:finalize => false)
|
542
|
+
|
543
|
+
attribute :blog, 'Blog'
|
544
|
+
end
|
545
|
+
|
546
|
+
# after loading both files just do:
|
547
|
+
Virtus.finalize
|
548
|
+
|
549
|
+
# constants will be resolved:
|
550
|
+
Blog.attribute_set[:posts].member_type.primitive # => Post
|
551
|
+
Post.attribute_set[:blog].type.primitive # => Blog
|
552
|
+
```
|
524
553
|
|
525
554
|
Credits
|
526
555
|
-------
|
data/lib/virtus.rb
CHANGED
@@ -150,6 +150,13 @@ module Virtus
|
|
150
150
|
@configuration ||= Configuration.new
|
151
151
|
end
|
152
152
|
|
153
|
+
# @api public
|
154
|
+
def self.finalize
|
155
|
+
ExtensionBuilder.pending.each do |klass|
|
156
|
+
klass.attribute_set.finalize
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
153
160
|
# @api private
|
154
161
|
def self.warn(msg)
|
155
162
|
Kernel.warn(msg)
|
data/lib/virtus/attribute.rb
CHANGED
@@ -5,11 +5,12 @@ module Virtus
|
|
5
5
|
|
6
6
|
include ::Equalizer.new(:type, :options)
|
7
7
|
|
8
|
-
accept_options :primitive, :accessor, :default, :lazy, :strict, :required
|
8
|
+
accept_options :primitive, :accessor, :default, :lazy, :strict, :required, :finalize
|
9
9
|
|
10
10
|
strict false
|
11
11
|
required true
|
12
12
|
accessor :public
|
13
|
+
finalize true
|
13
14
|
|
14
15
|
# @see Virtus.coerce
|
15
16
|
#
|
@@ -55,12 +56,12 @@ module Virtus
|
|
55
56
|
def self.new(*args)
|
56
57
|
attribute = super
|
57
58
|
yield(attribute)
|
58
|
-
attribute
|
59
|
+
attribute
|
59
60
|
end
|
60
61
|
|
61
62
|
# @api private
|
62
|
-
def self.build_type(
|
63
|
-
Axiom::Types.infer(
|
63
|
+
def self.build_type(definition)
|
64
|
+
Axiom::Types.infer(definition.primitive)
|
64
65
|
end
|
65
66
|
|
66
67
|
# @api private
|
@@ -126,6 +127,11 @@ module Virtus
|
|
126
127
|
options[:required]
|
127
128
|
end
|
128
129
|
|
130
|
+
# @api public
|
131
|
+
def finalized?
|
132
|
+
frozen?
|
133
|
+
end
|
134
|
+
|
129
135
|
# @api private
|
130
136
|
def define_accessor_methods(attribute_set)
|
131
137
|
attribute_set.define_reader_method(self, name, options[:reader])
|
@@ -135,6 +141,7 @@ module Virtus
|
|
135
141
|
# @api private
|
136
142
|
def finalize
|
137
143
|
freeze
|
144
|
+
self
|
138
145
|
end
|
139
146
|
|
140
147
|
end # class Attribute
|
@@ -1,4 +1,79 @@
|
|
1
1
|
module Virtus
|
2
|
+
|
3
|
+
# @private
|
4
|
+
class PendingAttribute
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
# @api private
|
8
|
+
def initialize(type, options)
|
9
|
+
@type = type
|
10
|
+
@options = options
|
11
|
+
@name = options[:name]
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
def finalize
|
16
|
+
Attribute::Builder.call(determine_type, @options).finalize
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def finalized?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
# @api private
|
25
|
+
def determine_type
|
26
|
+
if @type.include?('::')
|
27
|
+
# TODO: wrap it up in Virtus.constantize and use feature-detection to
|
28
|
+
# pick up either Inflecto or ActiveSupport, whateve is available
|
29
|
+
if defined?(Inflecto)
|
30
|
+
Inflecto.constantize(@type)
|
31
|
+
else
|
32
|
+
raise NotImplementedError, 'Virtus needs inflecto gem to constantize namespaced constant names'
|
33
|
+
end
|
34
|
+
else
|
35
|
+
Object.const_get(@type)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end # PendingAttribute
|
40
|
+
|
41
|
+
class TypeDefinition
|
42
|
+
attr_reader :type, :primitive
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def initialize(type)
|
46
|
+
@type = type
|
47
|
+
initialize_primitive
|
48
|
+
end
|
49
|
+
|
50
|
+
# @api private
|
51
|
+
def pending?
|
52
|
+
@pending
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# @api private
|
58
|
+
def initialize_primitive
|
59
|
+
@primitive =
|
60
|
+
if type.instance_of?(String) || type.instance_of?(Symbol)
|
61
|
+
if !type.to_s.include?('::') && Object.const_defined?(type)
|
62
|
+
Object.const_get(type)
|
63
|
+
elsif not Attribute::Builder.determine_type(type)
|
64
|
+
@pending = true
|
65
|
+
type
|
66
|
+
else
|
67
|
+
type
|
68
|
+
end
|
69
|
+
elsif not type.is_a?(Class)
|
70
|
+
type.class
|
71
|
+
else
|
72
|
+
type
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
2
77
|
class Attribute
|
3
78
|
|
4
79
|
# TODO: this is a huge class and it might be a good idea to split it into
|
@@ -10,8 +85,14 @@ module Virtus
|
|
10
85
|
attr_reader :attribute
|
11
86
|
|
12
87
|
# @api private
|
13
|
-
def self.call(
|
14
|
-
new(
|
88
|
+
def self.call(type, options = {})
|
89
|
+
type_definition = TypeDefinition.new(type)
|
90
|
+
|
91
|
+
if type_definition.pending?
|
92
|
+
PendingAttribute.new(type, options)
|
93
|
+
else
|
94
|
+
new(type_definition, options).attribute
|
95
|
+
end
|
15
96
|
end
|
16
97
|
|
17
98
|
# @api private
|
@@ -33,10 +114,11 @@ module Virtus
|
|
33
114
|
end
|
34
115
|
|
35
116
|
# @api private
|
36
|
-
def initialize(
|
37
|
-
|
117
|
+
def initialize(type_definition, options)
|
118
|
+
@type_definition = type_definition
|
119
|
+
|
38
120
|
initialize_class
|
39
|
-
initialize_type
|
121
|
+
initialize_type
|
40
122
|
initialize_options(options)
|
41
123
|
initialize_default_value
|
42
124
|
initialize_coercer
|
@@ -45,50 +127,14 @@ module Virtus
|
|
45
127
|
|
46
128
|
private
|
47
129
|
|
48
|
-
# @api private
|
49
|
-
def initialize_attribute
|
50
|
-
@attribute = @klass.new(@type, @options) do |attribute|
|
51
|
-
attribute.extend(Accessor) if @options[:name]
|
52
|
-
attribute.extend(Coercible) if @options[:coerce]
|
53
|
-
attribute.extend(Strict) if @options[:strict]
|
54
|
-
attribute.extend(LazyDefault) if @options[:lazy]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# @api private
|
59
|
-
def initialize_default_value
|
60
|
-
@options.update(:default_value => DefaultValue.build(@options[:default]))
|
61
|
-
end
|
62
|
-
|
63
|
-
# @api private
|
64
|
-
def initialize_coercer
|
65
|
-
@options.update(:coercer => @options.fetch(:coercer) { @klass.build_coercer(@type, @options) })
|
66
|
-
end
|
67
|
-
|
68
|
-
# @api private
|
69
|
-
def initialize_primitive(type)
|
70
|
-
@primitive =
|
71
|
-
if type.instance_of?(String) || type.instance_of?(Symbol)
|
72
|
-
begin
|
73
|
-
Object.const_get(type)
|
74
|
-
rescue
|
75
|
-
type
|
76
|
-
end
|
77
|
-
elsif not type.is_a?(Class)
|
78
|
-
type.class
|
79
|
-
else
|
80
|
-
type
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
130
|
# @api private
|
85
131
|
def initialize_class
|
86
|
-
@klass = self.class.determine_type(@primitive, Attribute)
|
132
|
+
@klass = self.class.determine_type(@type_definition.primitive, Attribute)
|
87
133
|
end
|
88
134
|
|
89
135
|
# @api private
|
90
|
-
def initialize_type
|
91
|
-
@type = @klass.build_type(
|
136
|
+
def initialize_type
|
137
|
+
@type = @klass.build_type(@type_definition)
|
92
138
|
end
|
93
139
|
|
94
140
|
# @api private
|
@@ -106,6 +152,27 @@ module Virtus
|
|
106
152
|
@options.update(:reader => reader_visibility, :writer => writer_visibility)
|
107
153
|
end
|
108
154
|
|
155
|
+
# @api private
|
156
|
+
def initialize_default_value
|
157
|
+
@options.update(:default_value => DefaultValue.build(@options[:default]))
|
158
|
+
end
|
159
|
+
|
160
|
+
# @api private
|
161
|
+
def initialize_coercer
|
162
|
+
@options.update(:coercer => @options.fetch(:coercer) { @klass.build_coercer(@type, @options) })
|
163
|
+
end
|
164
|
+
|
165
|
+
# @api private
|
166
|
+
def initialize_attribute
|
167
|
+
@attribute = @klass.new(@type, @options) do |attribute|
|
168
|
+
attribute.extend(Accessor) if @options[:name]
|
169
|
+
attribute.extend(Coercible) if @options[:coerce]
|
170
|
+
attribute.extend(Strict) if @options[:strict]
|
171
|
+
attribute.extend(LazyDefault) if @options[:lazy]
|
172
|
+
end
|
173
|
+
@attribute.finalize if @options[:finalize]
|
174
|
+
end
|
175
|
+
|
109
176
|
end # class Builder
|
110
177
|
|
111
178
|
end # class Attribute
|
@@ -9,15 +9,17 @@ module Virtus
|
|
9
9
|
class Collection < Attribute
|
10
10
|
default Proc.new { |_, attribute| attribute.type.primitive.new }
|
11
11
|
|
12
|
+
attr_reader :member_type
|
13
|
+
|
12
14
|
# FIXME: temporary hack, remove when Axiom::Type works with EV as member_type
|
13
15
|
Type = Struct.new(:primitive, :member_type) do
|
14
16
|
def self.infer(type, primitive)
|
15
|
-
return type if
|
17
|
+
return type if axiom_type?(type)
|
16
18
|
|
17
19
|
klass = Axiom::Types.infer(type)
|
18
20
|
member = infer_member_type(type) || Object
|
19
21
|
|
20
|
-
if EmbeddedValue.handles?(member)
|
22
|
+
if EmbeddedValue.handles?(member) || pending?(member)
|
21
23
|
Type.new(primitive, member)
|
22
24
|
else
|
23
25
|
klass.new {
|
@@ -27,6 +29,14 @@ module Virtus
|
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
32
|
+
def self.pending?(primitive)
|
33
|
+
primitive.is_a?(String) || primitive.is_a?(Symbol)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.axiom_type?(type)
|
37
|
+
type.is_a?(Class) && type < Axiom::Types::Type
|
38
|
+
end
|
39
|
+
|
30
40
|
def self.infer_member_type(type)
|
31
41
|
return unless type.respond_to?(:count)
|
32
42
|
|
@@ -43,8 +53,8 @@ module Virtus
|
|
43
53
|
end
|
44
54
|
|
45
55
|
# @api private
|
46
|
-
def self.build_type(
|
47
|
-
Type.infer(
|
56
|
+
def self.build_type(definition)
|
57
|
+
Type.infer(definition.type, definition.primitive)
|
48
58
|
end
|
49
59
|
|
50
60
|
# @api private
|
@@ -61,10 +71,19 @@ module Virtus
|
|
61
71
|
end
|
62
72
|
end
|
63
73
|
|
64
|
-
|
65
|
-
|
74
|
+
# @api private
|
75
|
+
def finalize
|
76
|
+
return self if finalized?
|
77
|
+
@member_type = @options[:member_type].finalize
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
# @api private
|
82
|
+
def finalized?
|
83
|
+
super && member_type.finalized?
|
66
84
|
end
|
67
85
|
|
68
86
|
end # class Collection
|
87
|
+
|
69
88
|
end # class Attribute
|
70
89
|
end # module Virtus
|
@@ -66,8 +66,9 @@ module Virtus
|
|
66
66
|
end
|
67
67
|
|
68
68
|
# @api private
|
69
|
-
def self.build_type(
|
70
|
-
|
69
|
+
def self.build_type(definition)
|
70
|
+
klass = definition.primitive.is_a?(Class) ? definition.primitive : definition.type
|
71
|
+
Axiom::Types::Object.new { primitive klass }
|
71
72
|
end
|
72
73
|
|
73
74
|
# @api private
|
@@ -16,10 +16,13 @@ module Virtus
|
|
16
16
|
primitive ::Hash
|
17
17
|
default primitive.new
|
18
18
|
|
19
|
+
attr_reader :key_type
|
20
|
+
attr_reader :value_type
|
21
|
+
|
19
22
|
# FIXME: remove this once axiom-types supports it
|
20
23
|
Type = Struct.new(:key_type, :value_type) do
|
21
24
|
def self.infer(type)
|
22
|
-
if
|
25
|
+
if axiom_type?(type)
|
23
26
|
new(type.key_type, type.value_type)
|
24
27
|
else
|
25
28
|
type_options = infer_key_and_value_types(type)
|
@@ -30,7 +33,17 @@ module Virtus
|
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
36
|
+
def self.pending?(primitive)
|
37
|
+
primitive.is_a?(String) || primitive.is_a?(Symbol)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.axiom_type?(type)
|
41
|
+
type.is_a?(Class) && type < Axiom::Types::Type
|
42
|
+
end
|
43
|
+
|
33
44
|
def self.determine_type(type)
|
45
|
+
return type if pending?(type)
|
46
|
+
|
34
47
|
if EmbeddedValue.handles?(type)
|
35
48
|
type
|
36
49
|
else
|
@@ -58,8 +71,8 @@ module Virtus
|
|
58
71
|
end
|
59
72
|
|
60
73
|
# @api private
|
61
|
-
def self.build_type(
|
62
|
-
Type.infer(
|
74
|
+
def self.build_type(definition)
|
75
|
+
Type.infer(definition.type)
|
63
76
|
end
|
64
77
|
|
65
78
|
# @api private
|
@@ -85,13 +98,16 @@ module Virtus
|
|
85
98
|
end
|
86
99
|
|
87
100
|
# @api private
|
88
|
-
def
|
89
|
-
|
101
|
+
def finalize
|
102
|
+
return self if finalized?
|
103
|
+
@key_type = options[:key_type].finalize
|
104
|
+
@value_type = options[:value_type].finalize
|
105
|
+
super
|
90
106
|
end
|
91
107
|
|
92
108
|
# @api private
|
93
|
-
def
|
94
|
-
|
109
|
+
def finalized?
|
110
|
+
super && key_type.finalized? && value_type.finalized?
|
95
111
|
end
|
96
112
|
|
97
113
|
end # class Hash
|
data/lib/virtus/attribute_set.rb
CHANGED
@@ -74,7 +74,8 @@ module Virtus
|
|
74
74
|
# @api public
|
75
75
|
def <<(attribute)
|
76
76
|
self[attribute.name] = attribute
|
77
|
-
attribute.define_accessor_methods(self)
|
77
|
+
attribute.define_accessor_methods(self) if attribute.finalized?
|
78
|
+
self
|
78
79
|
end
|
79
80
|
|
80
81
|
# Get an attribute by name
|
@@ -208,6 +209,13 @@ module Virtus
|
|
208
209
|
)
|
209
210
|
end
|
210
211
|
|
212
|
+
# @api private
|
213
|
+
def finalize
|
214
|
+
each do |attribute|
|
215
|
+
self << attribute.finalize unless attribute.finalized?
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
211
219
|
private
|
212
220
|
|
213
221
|
# @api private
|
data/lib/virtus/configuration.rb
CHANGED
@@ -3,6 +3,9 @@ module Virtus
|
|
3
3
|
# A Configuration instance
|
4
4
|
class Configuration
|
5
5
|
|
6
|
+
# Access the finalize setting for this instance
|
7
|
+
attr_accessor :finalize
|
8
|
+
|
6
9
|
# Access the coerce setting for this instance
|
7
10
|
attr_accessor :coerce
|
8
11
|
|
@@ -35,6 +38,7 @@ module Virtus
|
|
35
38
|
#
|
36
39
|
# @api private
|
37
40
|
def initialize
|
41
|
+
@finalize = true
|
38
42
|
@coerce = true
|
39
43
|
@strict = false
|
40
44
|
@constructor = true
|
@@ -44,6 +44,11 @@ module Virtus
|
|
44
44
|
builder.module
|
45
45
|
end
|
46
46
|
|
47
|
+
# @api private
|
48
|
+
def self.pending
|
49
|
+
@pending ||= []
|
50
|
+
end
|
51
|
+
|
47
52
|
# Initializes a new ModuleBuilder
|
48
53
|
#
|
49
54
|
# @param [Configuration] configuration
|
@@ -68,11 +73,13 @@ module Virtus
|
|
68
73
|
attribute_proc = attribute_method(configuration)
|
69
74
|
constructor = configuration.constructor
|
70
75
|
mass_assignment = configuration.mass_assignment
|
76
|
+
finalize = configuration.finalize
|
71
77
|
extensions = core_extensions
|
72
78
|
inclusions = core_inclusions
|
73
79
|
|
74
80
|
self.module.define_singleton_method :included do |object|
|
75
81
|
super(object)
|
82
|
+
ExtensionBuilder.pending << object unless finalize
|
76
83
|
extensions.each { |mod| object.extend(mod) }
|
77
84
|
inclusions.each { |mod| object.send(:include, mod) }
|
78
85
|
object.send(:include, Model::Constructor) if constructor
|
@@ -114,6 +121,7 @@ module Virtus
|
|
114
121
|
# @api private
|
115
122
|
def module_options
|
116
123
|
{ :coerce => configuration.coerce,
|
124
|
+
:finalize => configuration.finalize,
|
117
125
|
:strict => configuration.strict,
|
118
126
|
:configured_coercer => configuration.coercer }
|
119
127
|
end
|
data/lib/virtus/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -17,6 +17,7 @@ describe Virtus::Attribute::Collection, '#coerce' do
|
|
17
17
|
|
18
18
|
it 'uses coercer to coerce members' do
|
19
19
|
stub(coercer).call(input) { input }
|
20
|
+
stub(member_type).finalize { member_type }
|
20
21
|
stub(member_type).coerce('1') { 1 }
|
21
22
|
stub(member_type).coerce('2') { 2 }
|
22
23
|
|
@@ -41,9 +41,11 @@ describe Virtus::Attribute::Hash, '#coerce' do
|
|
41
41
|
it 'uses coercer to coerce key and value' do
|
42
42
|
stub(coercer).call(input) { input }
|
43
43
|
|
44
|
+
stub(key_type).finalize { key_type }
|
44
45
|
stub(key_type).coerce(1) { '1' }
|
45
46
|
stub(key_type).coerce(2) { '2' }
|
46
47
|
|
48
|
+
stub(value_type).finalize { value_type }
|
47
49
|
stub(value_type).coerce('1') { 1 }
|
48
50
|
stub(value_type).coerce('2') { 2 }
|
49
51
|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus, '.finalize' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class Person
|
7
|
+
include Virtus.model(:finalize => false)
|
8
|
+
|
9
|
+
attribute :articles, Array['Examples::Article']
|
10
|
+
attribute :address, 'Examples::Address'
|
11
|
+
end
|
12
|
+
|
13
|
+
class Article
|
14
|
+
include Virtus.model(:finalize => false)
|
15
|
+
|
16
|
+
attribute :posts, Hash['Examples::Person' => 'Examples::Post']
|
17
|
+
attribute :person, 'Examples::Person'
|
18
|
+
end
|
19
|
+
|
20
|
+
class Post
|
21
|
+
include Virtus.model(:finalize => false)
|
22
|
+
|
23
|
+
attribute :title, String
|
24
|
+
end
|
25
|
+
|
26
|
+
class Address
|
27
|
+
include Virtus.model(:finalize => false)
|
28
|
+
|
29
|
+
attribute :street, String
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Virtus.finalize
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'it finalizes member type for a collection attribute' do
|
37
|
+
expect(Examples::Person.attribute_set[:address].primitive).to be(Examples::Address)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'it finalizes key type for a hash attribute' do
|
41
|
+
expect(Examples::Article.attribute_set[:posts].key_type.primitive).to be(Examples::Person)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'it finalizes value type for a hash attribute' do
|
45
|
+
expect(Examples::Article.attribute_set[:posts].value_type.primitive).to be(Examples::Post)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'it finalizes type for an EV attribute' do
|
49
|
+
expect(Examples::Article.attribute_set[:person].type.primitive).to be(Examples::Person)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'automatically resolves constant when it is already available' do
|
53
|
+
expect(Examples::Article.attribute_set[:person].type.primitive).to be(Examples::Person)
|
54
|
+
end
|
55
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: virtus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.beta8
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: descendants_tracker
|
@@ -189,6 +189,7 @@ files:
|
|
189
189
|
- spec/unit/virtus/attribute_spec.rb
|
190
190
|
- spec/unit/virtus/attributes_reader_spec.rb
|
191
191
|
- spec/unit/virtus/attributes_writer_spec.rb
|
192
|
+
- spec/unit/virtus/class_methods/finalize_spec.rb
|
192
193
|
- spec/unit/virtus/class_methods/new_spec.rb
|
193
194
|
- spec/unit/virtus/config_spec.rb
|
194
195
|
- spec/unit/virtus/element_reader_spec.rb
|