motion_virtus 1.0.0.beta0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/README.md +445 -0
- data/lib/motion_virtus.rb +13 -0
- data/lib/project/attribute/accessor/builder.rb +69 -0
- data/lib/project/attribute/accessor/lazy_accessor.rb +39 -0
- data/lib/project/attribute/accessor.rb +100 -0
- data/lib/project/attribute/accessor_method.rb +73 -0
- data/lib/project/attribute/array.rb +24 -0
- data/lib/project/attribute/boolean.rb +52 -0
- data/lib/project/attribute/class.rb +23 -0
- data/lib/project/attribute/coercer.rb +43 -0
- data/lib/project/attribute/collection/coercible_writer.rb +83 -0
- data/lib/project/attribute/collection.rb +56 -0
- data/lib/project/attribute/date.rb +36 -0
- data/lib/project/attribute/date_time.rb +38 -0
- data/lib/project/attribute/decimal.rb +23 -0
- data/lib/project/attribute/default_value/from_callable.rb +37 -0
- data/lib/project/attribute/default_value/from_clonable.rb +37 -0
- data/lib/project/attribute/default_value/from_symbol.rb +37 -0
- data/lib/project/attribute/default_value.rb +49 -0
- data/lib/project/attribute/embedded_value/open_struct_coercer.rb +43 -0
- data/lib/project/attribute/embedded_value/struct_coercer.rb +42 -0
- data/lib/project/attribute/embedded_value.rb +69 -0
- data/lib/project/attribute/float.rb +30 -0
- data/lib/project/attribute/hash/coercible_writer.rb +78 -0
- data/lib/project/attribute/hash.rb +66 -0
- data/lib/project/attribute/integer.rb +27 -0
- data/lib/project/attribute/numeric.rb +25 -0
- data/lib/project/attribute/object.rb +13 -0
- data/lib/project/attribute/reader.rb +39 -0
- data/lib/project/attribute/set.rb +22 -0
- data/lib/project/attribute/string.rb +24 -0
- data/lib/project/attribute/symbol.rb +23 -0
- data/lib/project/attribute/time.rb +36 -0
- data/lib/project/attribute/writer/coercible.rb +45 -0
- data/lib/project/attribute/writer.rb +73 -0
- data/lib/project/attribute.rb +292 -0
- data/lib/project/attribute_set.rb +260 -0
- data/lib/project/class_inclusions.rb +41 -0
- data/lib/project/class_methods.rb +102 -0
- data/lib/project/configuration.rb +65 -0
- data/lib/project/const_missing_extensions.rb +16 -0
- data/lib/project/extensions.rb +101 -0
- data/lib/project/instance_methods.rb +165 -0
- data/lib/project/module_builder.rb +92 -0
- data/lib/project/module_extensions.rb +72 -0
- data/lib/project/stubs/date.rb +2 -0
- data/lib/project/stubs/date_time.rb +2 -0
- data/lib/project/stubs/decimal.rb +2 -0
- data/lib/project/stubs/ostruct.rb +149 -0
- data/lib/project/stubs/set.rb +767 -0
- data/lib/project/stubs.rb +5 -0
- data/lib/project/support/equalizer.rb +147 -0
- data/lib/project/support/options.rb +114 -0
- data/lib/project/support/type_lookup.rb +109 -0
- data/lib/project/value_object.rb +139 -0
- data/lib/project/version.rb +3 -0
- data/lib/project/virtus.rb +128 -0
- metadata +158 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
|
4
|
+
# Abstract accessor method class
|
5
|
+
#
|
6
|
+
# @api public
|
7
|
+
#
|
8
|
+
# @abstract
|
9
|
+
class AccessorMethod
|
10
|
+
#include Adamantium::Flat
|
11
|
+
|
12
|
+
#include AbstractType
|
13
|
+
|
14
|
+
#abstract_method :call
|
15
|
+
def call(*)
|
16
|
+
raise NotImplementedError, "#{self.class.inspect}##{name} is not implemented"
|
17
|
+
end
|
18
|
+
|
19
|
+
#abstract_method :define_method
|
20
|
+
def call(*)
|
21
|
+
raise NotImplementedError, "#{self.class.inspect}##{name} is not implemented"
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Return name
|
26
|
+
#
|
27
|
+
# @return [Symbol]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
attr_reader :name
|
31
|
+
|
32
|
+
# Return visibility
|
33
|
+
#
|
34
|
+
# @return [Symbol]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
attr_reader :visibility
|
38
|
+
|
39
|
+
# Return instance variable name
|
40
|
+
#
|
41
|
+
# @return [Symbol]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
attr_reader :instance_variable_name
|
45
|
+
|
46
|
+
# Initialize accessor method instance
|
47
|
+
#
|
48
|
+
# @param [#to_sym] name
|
49
|
+
#
|
50
|
+
# @param [Hash] options
|
51
|
+
#
|
52
|
+
# @return [undefined]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
def initialize(name, options = {})
|
56
|
+
@name = name.to_sym
|
57
|
+
@visibility = options.fetch(:visibility, :public)
|
58
|
+
@instance_variable_name = "@#{name}".to_sym
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return if the accessor is public
|
62
|
+
#
|
63
|
+
# @return [TrueClass,FalseClass]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
def public?
|
67
|
+
visibility == :public
|
68
|
+
end
|
69
|
+
|
70
|
+
end # class AccessorMethod
|
71
|
+
|
72
|
+
end # class Attribute
|
73
|
+
end # module Virtus
|
@@ -0,0 +1,24 @@
|
|
1
|
+
motion_require 'collection.rb'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
# Array
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Post
|
10
|
+
# include Virtus
|
11
|
+
#
|
12
|
+
# attribute :tags, Array
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# post = Post.new(:tags => %w(red green blue))
|
16
|
+
#
|
17
|
+
class Array < Collection
|
18
|
+
primitive ::Array
|
19
|
+
coercion_method :to_array
|
20
|
+
default primitive.new
|
21
|
+
|
22
|
+
end # class Array
|
23
|
+
end # class Attribute
|
24
|
+
end # module Virtus
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
|
4
|
+
# Boolean attribute allows true or false values to be set
|
5
|
+
# Additionally it adds boolean reader method, like "admin?"
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class Post
|
9
|
+
# include Virtus
|
10
|
+
#
|
11
|
+
# attribute :published, Boolean
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# post = Post.new(:published => false)
|
15
|
+
# post.published? # => false
|
16
|
+
#
|
17
|
+
class Boolean < Object
|
18
|
+
primitive TrueClass
|
19
|
+
coercion_method :to_boolean
|
20
|
+
|
21
|
+
# Returns if the given value is either true or false
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# boolean = Virtus::Attribute::Boolean.new(:bool)
|
25
|
+
# boolean.value_coerced?(true) # => true
|
26
|
+
# boolean.value_coerced?(false) # => true
|
27
|
+
# boolean.value_coerced?(1) # => false
|
28
|
+
# boolean.value_coerced?('true') # => false
|
29
|
+
#
|
30
|
+
# @return [Boolean]
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def value_coerced?(value)
|
34
|
+
value.equal?(true) || value.equal?(false)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Creates an attribute reader method as a query
|
38
|
+
#
|
39
|
+
# @param [Module] mod
|
40
|
+
#
|
41
|
+
# @return [self]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
def define_accessor_methods(mod)
|
45
|
+
super
|
46
|
+
mod.define_reader_method(accessor, "#{name}?", reader.visibility)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
end # class Boolean
|
51
|
+
end # class Attribute
|
52
|
+
end # module Virtus
|
@@ -0,0 +1,23 @@
|
|
1
|
+
motion_require 'object'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
# Class
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Entity
|
10
|
+
# include Virtus
|
11
|
+
#
|
12
|
+
# attribute :model, Class
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# post = Entity.new(:model => Model)
|
16
|
+
#
|
17
|
+
class Class < Object
|
18
|
+
primitive ::Class
|
19
|
+
coercion_method :to_constant
|
20
|
+
|
21
|
+
end # class Class
|
22
|
+
end # class Attribute
|
23
|
+
end # module Virtus
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
|
4
|
+
# Coercer accessor wrapper
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class Coercer
|
8
|
+
|
9
|
+
# Initialize a new coercer object
|
10
|
+
#
|
11
|
+
# @param [Object] coercers accessor
|
12
|
+
# @param [Symbol] coercion method
|
13
|
+
#
|
14
|
+
# @return [undefined]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def initialize(coercers, method)
|
18
|
+
@coercers = coercers
|
19
|
+
@method = method
|
20
|
+
end
|
21
|
+
|
22
|
+
# Coerce given value
|
23
|
+
#
|
24
|
+
# @return [Object]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def call(value)
|
28
|
+
self[value.class].public_send(@method, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return coercer object for the given type
|
32
|
+
#
|
33
|
+
# @return [Object]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
def [](type)
|
37
|
+
@coercers[type]
|
38
|
+
end
|
39
|
+
|
40
|
+
end # class Coercer
|
41
|
+
|
42
|
+
end # class Attribute
|
43
|
+
end # module Virtus
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
class Collection
|
4
|
+
|
5
|
+
# Coercible writer for collection attributes
|
6
|
+
#
|
7
|
+
class CoercibleWriter < Attribute::Writer::Coercible
|
8
|
+
|
9
|
+
# Return member type
|
10
|
+
#
|
11
|
+
# @return [Class]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
attr_reader :member_type
|
15
|
+
|
16
|
+
# Return writer for collection members
|
17
|
+
#
|
18
|
+
#
|
19
|
+
# @return [Writer::Coercible]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
attr_reader :member_coercer
|
23
|
+
|
24
|
+
# Initialize a new writer instance
|
25
|
+
#
|
26
|
+
# @param [Symbol] name
|
27
|
+
#
|
28
|
+
# @param [::Hash] options
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def initialize(name, options)
|
32
|
+
super
|
33
|
+
@member_type = options.fetch(:member_type, ::Object)
|
34
|
+
@member_coercer = Attribute.determine_type(@member_type).coercer(@member_type)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Coerce a collection with members
|
38
|
+
#
|
39
|
+
# @param [Object] value
|
40
|
+
#
|
41
|
+
# @return [Object]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
def coerce(_value)
|
45
|
+
coerced = super
|
46
|
+
return coerced unless coerced.respond_to?(:each_with_object)
|
47
|
+
coerced.each_with_object(new_collection) do |entry, collection|
|
48
|
+
coerce_and_append_member(collection, entry)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# Return an instance of the collection
|
55
|
+
#
|
56
|
+
# @return [Enumerable]
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
def new_collection
|
60
|
+
primitive.new
|
61
|
+
end
|
62
|
+
|
63
|
+
# Coerce a member of a source collection and append it to the target collection
|
64
|
+
#
|
65
|
+
# @param [Array, Set] collection
|
66
|
+
# target collection to which the coerced member should be appended
|
67
|
+
#
|
68
|
+
# @param [Object] entry
|
69
|
+
# the member that should be coerced and appended
|
70
|
+
#
|
71
|
+
# @return [Array, Set]
|
72
|
+
# collection with the coerced member appended to it
|
73
|
+
#
|
74
|
+
# @api private
|
75
|
+
def coerce_and_append_member(collection, entry)
|
76
|
+
collection << member_coercer.call(entry)
|
77
|
+
end
|
78
|
+
|
79
|
+
end # class CoercibleWriter
|
80
|
+
|
81
|
+
end # class Collection
|
82
|
+
end # class Attribute
|
83
|
+
end # module Virtus
|
@@ -0,0 +1,56 @@
|
|
1
|
+
motion_require 'object'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
# Abstract superclass for collection Attributes.
|
7
|
+
#
|
8
|
+
# Handles coercing members to the designated member type.
|
9
|
+
#
|
10
|
+
# @abstract
|
11
|
+
class Collection < Object
|
12
|
+
|
13
|
+
# Handles collection with member_type syntax
|
14
|
+
#
|
15
|
+
# @param [Class] type
|
16
|
+
#
|
17
|
+
# @param [Hash] options
|
18
|
+
#
|
19
|
+
# @return [Hash]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
def self.merge_options(type, _options)
|
23
|
+
merged_options = super
|
24
|
+
|
25
|
+
if !type.respond_to?(:count)
|
26
|
+
merged_options
|
27
|
+
elsif type.count > 1
|
28
|
+
raise NotImplementedError, "build SumType from list of types (#{type.inspect})"
|
29
|
+
else
|
30
|
+
merged_options.merge!(:member_type => type.first)
|
31
|
+
end
|
32
|
+
|
33
|
+
merged_options
|
34
|
+
end
|
35
|
+
|
36
|
+
# @see Virtus::Attribute.coercible_writer_class
|
37
|
+
#
|
38
|
+
# @return [::Class]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
def self.coercible_writer_class(_type, options)
|
42
|
+
options[:member_type] ? CoercibleWriter : super
|
43
|
+
end
|
44
|
+
|
45
|
+
# @see Virtus::Attribute.writer_option_names
|
46
|
+
#
|
47
|
+
# @return [Array<Symbol>]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
def self.writer_option_names
|
51
|
+
super << :member_type
|
52
|
+
end
|
53
|
+
|
54
|
+
end # class Collection
|
55
|
+
end # class Attribute
|
56
|
+
end # module Virtus
|
@@ -0,0 +1,36 @@
|
|
1
|
+
motion_require 'object'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
# Date
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Post
|
10
|
+
# include Virtus
|
11
|
+
#
|
12
|
+
# attribute :published_on, Date
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# Post.new(:published_on => Date.today)
|
16
|
+
#
|
17
|
+
# # typecasting from a string
|
18
|
+
# Post.new(:published_on => '2011/06/09')
|
19
|
+
#
|
20
|
+
# # typecasting from a hash
|
21
|
+
# Post.new(:published_on => {
|
22
|
+
# :year => 2011,
|
23
|
+
# :month => 6,
|
24
|
+
# :day => 9,
|
25
|
+
# })
|
26
|
+
#
|
27
|
+
# # typecasting from an object which implements #to_date
|
28
|
+
# Post.new(:published_on => DateTime.now)
|
29
|
+
#
|
30
|
+
class Date < Object
|
31
|
+
primitive ::Date
|
32
|
+
coercion_method :to_date
|
33
|
+
|
34
|
+
end # class Date
|
35
|
+
end # class Attribute
|
36
|
+
end # module Virtus
|
@@ -0,0 +1,38 @@
|
|
1
|
+
motion_require 'object'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
# DateTime
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Post
|
10
|
+
# include Virtus
|
11
|
+
#
|
12
|
+
# attribute :published_at, DateTime
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# Post.new(:published_at => DateTime.now)
|
16
|
+
#
|
17
|
+
# # typecasting from a string
|
18
|
+
# Post.new(:published_on => '2011/06/09 10:48')
|
19
|
+
#
|
20
|
+
# # typecasting from a hash
|
21
|
+
# Post.new(:published_on => {
|
22
|
+
# :year => 2011,
|
23
|
+
# :month => 6,
|
24
|
+
# :day => 9,
|
25
|
+
# :hour => 10,
|
26
|
+
# :min => 48,
|
27
|
+
# })
|
28
|
+
#
|
29
|
+
# # typecasting from an object which implements #to_datetime
|
30
|
+
# Post.new(:published_on => Time.now)
|
31
|
+
#
|
32
|
+
class DateTime < Object
|
33
|
+
primitive ::DateTime
|
34
|
+
coercion_method :to_datetime
|
35
|
+
|
36
|
+
end # class DateTim
|
37
|
+
end # class Attribute
|
38
|
+
end # module Virtus
|
@@ -0,0 +1,23 @@
|
|
1
|
+
motion_require 'object'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
# Decimal
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class ExchangeRate
|
10
|
+
# include Virtus
|
11
|
+
#
|
12
|
+
# attribute :dollar, Decimal
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# ExchangeRate.new(:dollar => '2.6948')
|
16
|
+
#
|
17
|
+
class Decimal < Numeric
|
18
|
+
primitive ::BigDecimal
|
19
|
+
coercion_method :to_decimal
|
20
|
+
|
21
|
+
end # class Decimal
|
22
|
+
end # class Attribute
|
23
|
+
end # module Virtus
|
@@ -0,0 +1,37 @@
|
|
1
|
+
motion_require 'from_clonable'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
class DefaultValue
|
6
|
+
|
7
|
+
# Represents default value evaluated via a callable object
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class FromCallable < DefaultValue
|
11
|
+
|
12
|
+
# Return if the class can handle the value
|
13
|
+
#
|
14
|
+
# @param [Object] value
|
15
|
+
#
|
16
|
+
# @return [Boolean]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
def self.handle?(value)
|
20
|
+
value.respond_to?(:call)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Evaluates the value via value#call
|
24
|
+
#
|
25
|
+
# @param [Object] args
|
26
|
+
#
|
27
|
+
# @return [Object] evaluated value
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def call(*args)
|
31
|
+
@value.call(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
end # class FromCallable
|
35
|
+
end # class DefaultValue
|
36
|
+
end # class Attribute
|
37
|
+
end # module Virtus
|
@@ -0,0 +1,37 @@
|
|
1
|
+
motion_require '../default_value.rb'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
class DefaultValue
|
6
|
+
|
7
|
+
# Represents default value evaluated via a clonable object
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class FromClonable < DefaultValue
|
11
|
+
SINGLETON_CLASSES = [
|
12
|
+
::NilClass, ::TrueClass, ::FalseClass, ::Numeric, ::Symbol ].freeze
|
13
|
+
|
14
|
+
# Return if the class can handle the value
|
15
|
+
#
|
16
|
+
# @param [Object] value
|
17
|
+
#
|
18
|
+
# @return [Boolean]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
def self.handle?(value)
|
22
|
+
SINGLETON_CLASSES.none? {|c| value.is_a?(c) }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Evaluates the value via value#clone
|
26
|
+
#
|
27
|
+
# @return [Object] evaluated value
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def call(*)
|
31
|
+
@value.clone
|
32
|
+
end
|
33
|
+
|
34
|
+
end # class FromClonable
|
35
|
+
end # class DefaultValue
|
36
|
+
end # class Attribute
|
37
|
+
end # module Virtus
|
@@ -0,0 +1,37 @@
|
|
1
|
+
motion_require 'from_callable'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
class DefaultValue
|
6
|
+
|
7
|
+
# Represents default value evaluated via a symbol
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
class FromSymbol < DefaultValue
|
11
|
+
|
12
|
+
# Return if the class can handle the value
|
13
|
+
#
|
14
|
+
# @param [Object] value
|
15
|
+
#
|
16
|
+
# @return [Boolean]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
def self.handle?(value)
|
20
|
+
value.is_a?(::Symbol)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Evaluates the value via instance#public_send(value)
|
24
|
+
#
|
25
|
+
# Symbol value is returned if the instance doesn't respond to value
|
26
|
+
#
|
27
|
+
# @return [Object] evaluated value
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def call(instance, *)
|
31
|
+
instance.respond_to?(@value, true) ? instance.send(@value) : @value
|
32
|
+
end
|
33
|
+
|
34
|
+
end # class FromSymbol
|
35
|
+
end # class DefaultValue
|
36
|
+
end # class Attribute
|
37
|
+
end # module Virtus
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
|
4
|
+
# Class representing the default value option
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
class DefaultValue
|
8
|
+
extend DescendantsTracker
|
9
|
+
|
10
|
+
# Builds a default value instance
|
11
|
+
#
|
12
|
+
# @return [Virtus::Attribute::DefaultValue]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def self.build(*args)
|
16
|
+
klass = descendants.detect { |descendant| descendant.handle?(*args) } || self
|
17
|
+
klass.new(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the value instance
|
21
|
+
#
|
22
|
+
# @return [Object]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
attr_reader :value
|
26
|
+
|
27
|
+
# Initializes an default value instance
|
28
|
+
#
|
29
|
+
# @param [Object] value
|
30
|
+
#
|
31
|
+
# @return [undefined]
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
def initialize(value)
|
35
|
+
@value = value
|
36
|
+
end
|
37
|
+
|
38
|
+
# Evaluates the value
|
39
|
+
#
|
40
|
+
# @return [Object] evaluated value
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
def call(*)
|
44
|
+
value
|
45
|
+
end
|
46
|
+
|
47
|
+
end # class DefaultValue
|
48
|
+
end # class Attribute
|
49
|
+
end # module Virtus
|
@@ -0,0 +1,43 @@
|
|
1
|
+
motion_require '../embedded_value.rb'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
class EmbeddedValue < Object
|
6
|
+
|
7
|
+
# EmbeddedValue coercer handling OpenStruct primitive or Virtus object
|
8
|
+
#
|
9
|
+
class OpenStructCoercer
|
10
|
+
|
11
|
+
# Return primitive class
|
12
|
+
#
|
13
|
+
# @return [::Class]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
attr_reader :primitive
|
17
|
+
|
18
|
+
# Initialize coercer object
|
19
|
+
#
|
20
|
+
# @return [undefined]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
def initialize(primitive)
|
24
|
+
@primitive = primitive
|
25
|
+
end
|
26
|
+
|
27
|
+
# Build object from attribute hash
|
28
|
+
#
|
29
|
+
# @return [::Object]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
def call(attributes)
|
33
|
+
if attributes.kind_of?(primitive)
|
34
|
+
attributes
|
35
|
+
elsif not attributes.nil?
|
36
|
+
primitive.new(attributes)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end # class OpenStructCoercer
|
41
|
+
end # class EmbeddedValue
|
42
|
+
end # class Attribute
|
43
|
+
end # module Virtus
|
@@ -0,0 +1,42 @@
|
|
1
|
+
motion_require '../embedded_value.rb'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
class EmbeddedValue < Object
|
6
|
+
|
7
|
+
# EmbeddedValue coercer handling Struct primitive
|
8
|
+
#
|
9
|
+
class StructCoercer
|
10
|
+
# Return primitive class
|
11
|
+
#
|
12
|
+
# @return [::Class]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
attr_reader :primitive
|
16
|
+
|
17
|
+
# Initialize coercer instance
|
18
|
+
#
|
19
|
+
# @return [undefined]
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
def initialize(primitive)
|
23
|
+
@primitive = primitive
|
24
|
+
end
|
25
|
+
|
26
|
+
# Build a struct object from attributes
|
27
|
+
#
|
28
|
+
# @return [Struct]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def call(attributes)
|
32
|
+
if attributes.kind_of?(primitive)
|
33
|
+
attributes
|
34
|
+
elsif not attributes.nil?
|
35
|
+
primitive.new(*attributes)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end # class StructCoercer
|
40
|
+
end # class EmbeddedValue
|
41
|
+
end # class Attribute
|
42
|
+
end # module Virtus
|