motion_virtus 1.0.0.beta0
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.
- 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
|