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,147 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# Define equality, equivalence and inspection methods
|
4
|
+
module Equalizer
|
5
|
+
|
6
|
+
def self.new(name, keys = [])
|
7
|
+
Module.new.tap do |m|
|
8
|
+
m.module_eval do
|
9
|
+
extend Implementation
|
10
|
+
@name = name
|
11
|
+
@keys = keys
|
12
|
+
define_methods
|
13
|
+
include_comparison_methods
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Implementation
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
"#<#{Equalizer.name}:0x#{ '%x' % (object_id << 1) }>"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Initialize an Equalizer with the given keys
|
25
|
+
#
|
26
|
+
# Will use the keys with which it is initialized to define #cmp?,
|
27
|
+
# #hash, and #inspect
|
28
|
+
#
|
29
|
+
# @param [String] name
|
30
|
+
#
|
31
|
+
# @param [Array<Symbol>] keys
|
32
|
+
#
|
33
|
+
# @return [undefined]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
def initialize(name, keys = [])
|
37
|
+
@name = name.dup.freeze
|
38
|
+
@keys = keys.dup
|
39
|
+
define_methods
|
40
|
+
include_comparison_methods
|
41
|
+
end
|
42
|
+
|
43
|
+
# Append a key and compile the equality methods
|
44
|
+
#
|
45
|
+
# @return [Equalizer] self
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
def <<(key)
|
49
|
+
@keys << key
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Define the equalizer methods based on #keys
|
56
|
+
#
|
57
|
+
# @return [undefined]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def define_methods
|
61
|
+
define_cmp_method
|
62
|
+
define_hash_method
|
63
|
+
define_inspect_method
|
64
|
+
end
|
65
|
+
|
66
|
+
# Define an #cmp? method based on the instance's values identified by #keys
|
67
|
+
#
|
68
|
+
# @return [undefined]
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
def define_cmp_method
|
72
|
+
keys = @keys
|
73
|
+
define_method(:cmp?) do |comparator, other|
|
74
|
+
keys.all? { |key| send(key).send(comparator, other.send(key)) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Define a #hash method based on the instance's values identified by #keys
|
79
|
+
#
|
80
|
+
# @return [undefined]
|
81
|
+
#
|
82
|
+
# @api private
|
83
|
+
def define_hash_method
|
84
|
+
keys = @keys
|
85
|
+
define_method(:hash) do
|
86
|
+
keys.map { |key| send(key).hash }.reduce(self.class.hash, :^)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Define an inspect method that reports the values of the instance's keys
|
91
|
+
#
|
92
|
+
# @return [undefined]
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
def define_inspect_method
|
96
|
+
name, keys = @name, @keys
|
97
|
+
define_method(:inspect) do
|
98
|
+
"#<#{name}#{keys.map { |key| " #{key}=#{send(key).inspect}" }.join}>"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Include the #eql? and #== methods
|
103
|
+
#
|
104
|
+
# @return [undefined]
|
105
|
+
#
|
106
|
+
# @api private
|
107
|
+
def include_comparison_methods
|
108
|
+
module_eval { include Methods }
|
109
|
+
end
|
110
|
+
|
111
|
+
# The comparison methods
|
112
|
+
module Methods
|
113
|
+
|
114
|
+
# Compare the object with other object for equality
|
115
|
+
#
|
116
|
+
# @example
|
117
|
+
# object.eql?(other) # => true or false
|
118
|
+
#
|
119
|
+
# @param [Object] other
|
120
|
+
# the other object to compare with
|
121
|
+
#
|
122
|
+
# @return [Boolean]
|
123
|
+
#
|
124
|
+
# @api public
|
125
|
+
def eql?(other)
|
126
|
+
instance_of?(other.class) && cmp?(__method__, other)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Compare the object with other object for equivalency
|
130
|
+
#
|
131
|
+
# @example
|
132
|
+
# object == other # => true or false
|
133
|
+
#
|
134
|
+
# @param [Object] other
|
135
|
+
# the other object to compare with
|
136
|
+
#
|
137
|
+
# @return [Boolean]
|
138
|
+
#
|
139
|
+
# @api public
|
140
|
+
def ==(other)
|
141
|
+
other.kind_of?(self.class) && cmp?(__method__, other)
|
142
|
+
end
|
143
|
+
|
144
|
+
end # module Methods
|
145
|
+
end # module Implementation
|
146
|
+
end # module Equalizer
|
147
|
+
end # module Virtus
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# A module that adds class and instance level options
|
4
|
+
module Options
|
5
|
+
|
6
|
+
Undefined = Object.new.freeze
|
7
|
+
|
8
|
+
# Returns default options hash for a given attribute class
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# Virtus::Attribute::String.options
|
12
|
+
# # => {:primitive => String}
|
13
|
+
#
|
14
|
+
# @return [Hash]
|
15
|
+
# a hash of default option values
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def options
|
19
|
+
accepted_options.each_with_object({}) do |option_name, options|
|
20
|
+
option_value = send(option_name)
|
21
|
+
options[option_name] = option_value unless option_value.nil?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns an array of valid options
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# Virtus::Attribute::String.accepted_options
|
29
|
+
# # => [:primitive, :accessor, :reader, :writer]
|
30
|
+
#
|
31
|
+
# @return [Array]
|
32
|
+
# the array of valid option names
|
33
|
+
#
|
34
|
+
# @api public
|
35
|
+
def accepted_options
|
36
|
+
@accepted_options ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
# Defines which options are valid for a given attribute class
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# class MyAttribute < Virtus::Attribute::Object
|
43
|
+
# accept_options :foo, :bar
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# @return [self]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def accept_options(*new_options)
|
50
|
+
add_accepted_options(new_options)
|
51
|
+
new_options.each { |option| define_option_method(option) }
|
52
|
+
descendants.each { |descendant| descendant.add_accepted_options(new_options) }
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
# Adds a reader/writer method for the give option name
|
59
|
+
#
|
60
|
+
# @return [undefined]
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
def define_option_method(option)
|
64
|
+
self.class.instance_eval do
|
65
|
+
define_method("#{option}") do |value=Undefined|
|
66
|
+
return instance_variable_get("@#{option}") if value.equal?(Undefined)
|
67
|
+
instance_variable_set("@#{option}", value)
|
68
|
+
self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Sets default options
|
74
|
+
#
|
75
|
+
# @param [#each] new_options
|
76
|
+
# options to be set
|
77
|
+
#
|
78
|
+
# @return [self]
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
def set_options(new_options)
|
82
|
+
new_options.each { |pair| send(*pair) }
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
# Adds new options that an attribute class can accept
|
87
|
+
#
|
88
|
+
# @param [#to_ary] new_options
|
89
|
+
# new options to be added
|
90
|
+
#
|
91
|
+
# @return [self]
|
92
|
+
#
|
93
|
+
# @api private
|
94
|
+
def add_accepted_options(new_options)
|
95
|
+
accepted_options.concat(new_options)
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# Adds descendant to descendants array and inherits default options
|
102
|
+
#
|
103
|
+
# @param [Class] descendant
|
104
|
+
#
|
105
|
+
# @return [undefined]
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
def inherited(descendant)
|
109
|
+
super
|
110
|
+
descendant.add_accepted_options(accepted_options).set_options(options)
|
111
|
+
end
|
112
|
+
|
113
|
+
end # module Options
|
114
|
+
end # module Virtus
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# A module that adds type lookup to a class
|
4
|
+
module TypeLookup
|
5
|
+
|
6
|
+
TYPE_FORMAT = /\A[A-Z]\w*\z/.freeze
|
7
|
+
|
8
|
+
# Set cache ivar on the model
|
9
|
+
#
|
10
|
+
# @param [Class] model
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
def self.extended(model)
|
16
|
+
model.instance_variable_set('@type_lookup_cache', {})
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a descendant based on a name or class
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# MyClass.determine_type('String') # => MyClass::String
|
23
|
+
#
|
24
|
+
# @param [Class, #to_s] class_or_name
|
25
|
+
# name of a class or a class itself
|
26
|
+
#
|
27
|
+
# @return [Class]
|
28
|
+
# a descendant
|
29
|
+
#
|
30
|
+
# @return [nil]
|
31
|
+
# nil if the type cannot be determined by the class_or_name
|
32
|
+
#
|
33
|
+
# @api public
|
34
|
+
def determine_type(class_or_name)
|
35
|
+
@type_lookup_cache[class_or_name] ||= determine_type_and_cache(class_or_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return the default primitive supported
|
39
|
+
#
|
40
|
+
# @return [Class]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#def primitive
|
44
|
+
# raise NotImplementedError, "#{self}.primitive must be implemented"
|
45
|
+
#end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
def determine_type_and_cache(class_or_name)
|
51
|
+
type = case class_or_name
|
52
|
+
when singleton_class
|
53
|
+
determine_type_from_descendant(class_or_name)
|
54
|
+
when Class
|
55
|
+
determine_type_from_primitive(class_or_name)
|
56
|
+
else
|
57
|
+
determine_type_from_string(class_or_name.to_s)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return the class given a descendant
|
62
|
+
#
|
63
|
+
# @param [Class] descendant
|
64
|
+
#
|
65
|
+
# @return [Class]
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
def determine_type_from_descendant(descendant)
|
69
|
+
descendant if descendant < self
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return the class given a primitive
|
73
|
+
#
|
74
|
+
# @param [Class] primitive
|
75
|
+
#
|
76
|
+
# @return [Class]
|
77
|
+
#
|
78
|
+
# @return [nil]
|
79
|
+
# nil if the type cannot be determined by the primitive
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
def determine_type_from_primitive(primitive)
|
83
|
+
type = nil
|
84
|
+
descendants.reverse_each do |descendant|
|
85
|
+
descendant_primitive = descendant.primitive
|
86
|
+
next unless primitive <= descendant_primitive
|
87
|
+
type = descendant if type.nil? || type.primitive > descendant_primitive
|
88
|
+
end
|
89
|
+
type
|
90
|
+
end
|
91
|
+
|
92
|
+
# Return the class given a string
|
93
|
+
#
|
94
|
+
# @param [String] string
|
95
|
+
#
|
96
|
+
# @return [Class]
|
97
|
+
#
|
98
|
+
# @return [nil]
|
99
|
+
# nil if the type cannot be determined by the string
|
100
|
+
#
|
101
|
+
# @api private
|
102
|
+
def determine_type_from_string(string)
|
103
|
+
if string =~ TYPE_FORMAT && const_defined?(string, *EXTRA_CONST_ARGS)
|
104
|
+
const_get(string, *EXTRA_CONST_ARGS)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end # module TypeLookup
|
109
|
+
end # module Virtus
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# Include this Module for Value Object semantics
|
4
|
+
#
|
5
|
+
# The idea is that instances should be immutable and compared based on state
|
6
|
+
# (rather than identity, as is typically the case)
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class GeoLocation
|
10
|
+
# include Virtus::ValueObject
|
11
|
+
# attribute :latitude, Float
|
12
|
+
# attribute :longitude, Float
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# location = GeoLocation.new(:latitude => 10, :longitude => 100)
|
16
|
+
# same_location = GeoLocation.new(:latitude => 10, :longitude => 100)
|
17
|
+
# location == same_location #=> true
|
18
|
+
# hash = { location => :foo }
|
19
|
+
# hash[same_location] #=> :foo
|
20
|
+
module ValueObject
|
21
|
+
|
22
|
+
# Callback to configure including Class as a Value Object
|
23
|
+
#
|
24
|
+
# Including Class will include Virtus and have additional
|
25
|
+
# value object semantics defined in this module
|
26
|
+
#
|
27
|
+
# @return [Undefined]
|
28
|
+
#
|
29
|
+
# TODO: stacking modules is getting painful
|
30
|
+
# time for Facets' module_inheritance, ActiveSupport::Concern or the like
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def self.included(base)
|
34
|
+
base.instance_eval do
|
35
|
+
include ::Virtus
|
36
|
+
include InstanceMethods
|
37
|
+
extend ClassMethods
|
38
|
+
private :attributes=
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private_class_method :included
|
43
|
+
|
44
|
+
module InstanceMethods
|
45
|
+
|
46
|
+
# the #get_attributes method accept a Proc object that will filter
|
47
|
+
# out an attribute when the block returns false. the ValueObject
|
48
|
+
# needs all the attributes, so we allow every attribute.
|
49
|
+
FILTER_NONE = proc { true }
|
50
|
+
|
51
|
+
# @api private
|
52
|
+
def with(attribute_updates)
|
53
|
+
self.class.new(
|
54
|
+
attribute_set.get(self, &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
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
module ClassMethods
|
77
|
+
|
78
|
+
# Define an attribute on the receiver
|
79
|
+
#
|
80
|
+
# The Attribute will have private writer methods (eg., immutable instances)
|
81
|
+
# and be used in equality/equivalence comparisons
|
82
|
+
#
|
83
|
+
# @example
|
84
|
+
# class GeoLocation
|
85
|
+
# include Virtus::ValueObject
|
86
|
+
#
|
87
|
+
# attribute :latitude, Float
|
88
|
+
# attribute :longitude, Float
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# @see Virtus::ClassMethods.attribute
|
92
|
+
#
|
93
|
+
# @return [self]
|
94
|
+
#
|
95
|
+
# @api public
|
96
|
+
def attribute(name, type, options = {})
|
97
|
+
equalizer << name
|
98
|
+
super name, type, options.merge(:writer => :private)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Define and include a module that provides Value Object semantics
|
102
|
+
#
|
103
|
+
# Included module will have #inspect, #eql?, #== and #hash
|
104
|
+
# methods whose definition is based on the _keys_ argument
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# virtus_class.equalizer
|
108
|
+
#
|
109
|
+
# @return [Equalizer]
|
110
|
+
# An Equalizer module which defines #inspect, #eql?, #== and #hash
|
111
|
+
# for instances of this class
|
112
|
+
#
|
113
|
+
# @api public
|
114
|
+
def equalizer
|
115
|
+
@equalizer ||=
|
116
|
+
begin
|
117
|
+
equalizer = Equalizer.new(name || inspect)
|
118
|
+
include equalizer
|
119
|
+
equalizer
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# The list of writer methods that can be mass-assigned to in #attributes=
|
124
|
+
#
|
125
|
+
# @return [Set]
|
126
|
+
#
|
127
|
+
# @api private
|
128
|
+
def allowed_writer_methods
|
129
|
+
@allowed_writer_methods ||=
|
130
|
+
begin
|
131
|
+
allowed_writer_methods = super
|
132
|
+
allowed_writer_methods += attribute_set.map{|attr| "#{attr.name}="}
|
133
|
+
allowed_writer_methods.to_set.freeze
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
end # module ClassMethods
|
138
|
+
end # module ValueObject
|
139
|
+
end # module Virtus
|
@@ -0,0 +1,128 @@
|
|
1
|
+
motion_require 'stubs.rb'
|
2
|
+
motion_require 'support/equalizer'
|
3
|
+
motion_require 'support/type_lookup'
|
4
|
+
motion_require 'support/options'
|
5
|
+
|
6
|
+
module Virtus
|
7
|
+
|
8
|
+
# Provides args for const_get and const_defined? to make them behave
|
9
|
+
# consistently across different versions of ruby
|
10
|
+
EXTRA_CONST_ARGS = (RUBY_VERSION < '1.9' ? [] : [ false ]).freeze
|
11
|
+
|
12
|
+
#Undefined = Object.new.freeze
|
13
|
+
|
14
|
+
# Extends base class or a module with virtus methods
|
15
|
+
#
|
16
|
+
# @param [Object] object
|
17
|
+
#
|
18
|
+
# @return [undefined]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
def self.included(object)
|
22
|
+
super
|
23
|
+
if object.class.name == "Class"
|
24
|
+
object.send(:include, ClassInclusions)
|
25
|
+
else
|
26
|
+
object.extend(ModuleExtensions)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
private_class_method :included
|
30
|
+
|
31
|
+
# Extends an object with virtus extensions
|
32
|
+
#
|
33
|
+
# @param [Object] object
|
34
|
+
#
|
35
|
+
# @return [undefined]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
def self.extended(object)
|
39
|
+
object.extend(Extensions)
|
40
|
+
end
|
41
|
+
private_class_method :extended
|
42
|
+
|
43
|
+
# Sets the global coercer configuration
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# Virtus.coercer do |config|
|
47
|
+
# config.string.boolean_map = { true => '1', false => '0' }
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# @return [Coercible::Coercer]
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
def self.coercer(&block)
|
54
|
+
configuration.coercer(&block)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Sets the global coercion configuration value
|
58
|
+
#
|
59
|
+
# @param [Boolean] value
|
60
|
+
#
|
61
|
+
# @return [Virtus]
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
def self.coerce=(value)
|
65
|
+
configuration.coerce = value
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the global coercion setting
|
70
|
+
#
|
71
|
+
# @return [Boolean]
|
72
|
+
#
|
73
|
+
# @api public
|
74
|
+
def self.coerce
|
75
|
+
configuration.coerce
|
76
|
+
end
|
77
|
+
|
78
|
+
# Provides access to the global Virtus configuration
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# Virtus.config do |config|
|
82
|
+
# config.coerce = false
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# @return [Configuration]
|
86
|
+
#
|
87
|
+
# @api public
|
88
|
+
def self.config(&block)
|
89
|
+
configuration.call(&block)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Provides access to the Virtus module builder
|
93
|
+
# see Virtus::ModuleBuilder
|
94
|
+
#
|
95
|
+
# @example
|
96
|
+
# MyVirtusModule = Virtus.module { |mod|
|
97
|
+
# mod.coerce = true
|
98
|
+
# mod.string.boolean_map = { 'yup' => true, 'nope' => false }
|
99
|
+
# }
|
100
|
+
#
|
101
|
+
# class Book
|
102
|
+
# include MyVirtusModule
|
103
|
+
#
|
104
|
+
# attribute :published, Boolean
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# # This could be made more succinct as well
|
108
|
+
# class OtherBook
|
109
|
+
# include Virtus.module { |m| m.coerce = false }
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# @return [Module]
|
113
|
+
#
|
114
|
+
# @api public
|
115
|
+
def self.module(&block)
|
116
|
+
ModuleBuilder.call(&block)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Global configuration instance
|
120
|
+
#
|
121
|
+
# @ return [Configuration]
|
122
|
+
#
|
123
|
+
# @api private
|
124
|
+
def self.configuration
|
125
|
+
@configuration ||= Configuration.new
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|