virtus 0.5.5 → 1.0.0.beta3
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/.rspec +1 -1
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -8
- data/Gemfile +8 -2
- data/Gemfile.devtools +24 -30
- data/Guardfile +17 -6
- data/README.md +215 -77
- data/TODO.md +6 -0
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/mutant.yml +12 -1
- data/config/reek.yml +57 -66
- data/lib/virtus.rb +126 -42
- data/lib/virtus/attribute.rb +52 -240
- data/lib/virtus/attribute/accessor.rb +91 -0
- data/lib/virtus/attribute/boolean.rb +11 -8
- data/lib/virtus/attribute/builder.rb +120 -0
- data/lib/virtus/attribute/coercer.rb +51 -0
- data/lib/virtus/attribute/coercible.rb +14 -0
- data/lib/virtus/attribute/collection.rb +44 -90
- data/lib/virtus/attribute/default_value/from_callable.rb +1 -1
- data/lib/virtus/attribute/default_value/from_clonable.rb +1 -6
- data/lib/virtus/attribute/default_value/from_symbol.rb +3 -3
- data/lib/virtus/attribute/embedded_value.rb +37 -28
- data/lib/virtus/attribute/hash.rb +69 -71
- data/lib/virtus/attribute/lazy_default.rb +18 -0
- data/lib/virtus/attribute/strict.rb +16 -0
- data/lib/virtus/attribute_set.rb +81 -9
- data/lib/virtus/class_inclusions.rb +24 -17
- data/lib/virtus/class_methods.rb +13 -31
- data/lib/virtus/configuration.rb +77 -0
- data/lib/virtus/const_missing_extensions.rb +16 -0
- data/lib/virtus/extensions.rb +86 -61
- data/lib/virtus/instance_methods.rb +107 -128
- data/lib/virtus/model.rb +68 -0
- data/lib/virtus/module_builder.rb +184 -0
- data/lib/virtus/module_extensions.rb +27 -15
- data/lib/virtus/support/equalizer.rb +2 -3
- data/lib/virtus/support/type_lookup.rb +1 -1
- data/lib/virtus/value_object.rb +24 -31
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/building_module_spec.rb +68 -0
- data/spec/integration/custom_attributes_spec.rb +8 -15
- data/spec/integration/custom_collection_attributes_spec.rb +101 -0
- data/spec/integration/default_values_spec.rb +9 -2
- data/spec/integration/defining_attributes_spec.rb +2 -2
- data/spec/integration/using_modules_spec.rb +5 -3
- data/spec/shared/freeze_method_behavior.rb +2 -2
- data/spec/shared/options_class_method.rb +1 -1
- data/spec/spec_helper.rb +25 -5
- data/spec/unit/virtus/attribute/boolean/value_coerced_predicate_spec.rb +25 -0
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +115 -22
- data/spec/unit/virtus/attribute/class_methods/coerce_spec.rb +32 -0
- data/spec/unit/virtus/attribute/coerce_spec.rb +38 -21
- data/spec/unit/virtus/attribute/coercible_predicate_spec.rb +20 -0
- data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +84 -0
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +37 -24
- data/spec/unit/virtus/attribute/custom_collection_spec.rb +23 -0
- data/spec/unit/virtus/attribute/embedded_value/class_methods/build_spec.rb +37 -0
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +46 -10
- data/spec/unit/virtus/attribute/get_spec.rb +15 -63
- data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +80 -0
- data/spec/unit/virtus/attribute/hash/coerce_spec.rb +75 -13
- data/spec/unit/virtus/attribute/lazy_predicate_spec.rb +20 -0
- data/spec/unit/virtus/attribute/set_default_value_spec.rb +74 -0
- data/spec/unit/virtus/attribute/set_spec.rb +16 -36
- data/spec/unit/virtus/attribute/value_coerced_predicate_spec.rb +19 -0
- data/spec/unit/virtus/attribute_set/append_spec.rb +3 -5
- data/spec/unit/virtus/attribute_set/define_reader_method_spec.rb +1 -1
- data/spec/unit/virtus/attribute_set/define_writer_method_spec.rb +1 -1
- data/spec/unit/virtus/attribute_set/each_spec.rb +3 -3
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +1 -1
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +4 -4
- data/spec/unit/virtus/attribute_set/merge_spec.rb +10 -16
- data/spec/unit/virtus/attribute_set/reset_spec.rb +6 -10
- data/spec/unit/virtus/attribute_spec.rb +222 -0
- data/spec/unit/virtus/attributes_reader_spec.rb +41 -0
- data/spec/unit/virtus/attributes_writer_spec.rb +51 -0
- data/spec/unit/virtus/class_methods/new_spec.rb +39 -0
- data/spec/unit/virtus/config_spec.rb +13 -0
- data/spec/unit/virtus/element_reader_spec.rb +21 -0
- data/spec/unit/virtus/element_writer_spec.rb +19 -0
- data/spec/unit/virtus/freeze_spec.rb +21 -0
- data/spec/unit/virtus/model_spec.rb +134 -0
- data/spec/unit/virtus/module_spec.rb +76 -0
- data/spec/unit/virtus/set_default_attributes_spec.rb +25 -0
- data/spec/unit/virtus/value_object_spec.rb +105 -0
- data/virtus.gemspec +4 -2
- metadata +82 -191
- data/.rvmrc +0 -1
- data/TODO +0 -1
- data/config/roodi.yml +0 -17
- data/lib/virtus/attribute/array.rb +0 -24
- data/lib/virtus/attribute/class.rb +0 -21
- data/lib/virtus/attribute/date.rb +0 -34
- data/lib/virtus/attribute/date_time.rb +0 -36
- data/lib/virtus/attribute/decimal.rb +0 -21
- data/lib/virtus/attribute/embedded_value/from_open_struct.rb +0 -19
- data/lib/virtus/attribute/embedded_value/from_struct.rb +0 -19
- data/lib/virtus/attribute/float.rb +0 -30
- data/lib/virtus/attribute/integer.rb +0 -27
- data/lib/virtus/attribute/numeric.rb +0 -11
- data/lib/virtus/attribute/object.rb +0 -11
- data/lib/virtus/attribute/set.rb +0 -24
- data/lib/virtus/attribute/string.rb +0 -24
- data/lib/virtus/attribute/symbol.rb +0 -21
- data/lib/virtus/attribute/time.rb +0 -36
- data/lib/virtus/coercion.rb +0 -32
- data/lib/virtus/coercion/array.rb +0 -23
- data/lib/virtus/coercion/date.rb +0 -26
- data/lib/virtus/coercion/date_time.rb +0 -26
- data/lib/virtus/coercion/decimal.rb +0 -40
- data/lib/virtus/coercion/false_class.rb +0 -24
- data/lib/virtus/coercion/float.rb +0 -39
- data/lib/virtus/coercion/hash.rb +0 -71
- data/lib/virtus/coercion/integer.rb +0 -83
- data/lib/virtus/coercion/numeric.rb +0 -66
- data/lib/virtus/coercion/object.rb +0 -125
- data/lib/virtus/coercion/string.rb +0 -218
- data/lib/virtus/coercion/symbol.rb +0 -24
- data/lib/virtus/coercion/time.rb +0 -40
- data/lib/virtus/coercion/time_coercions.rb +0 -86
- data/lib/virtus/coercion/true_class.rb +0 -24
- data/spec/unit/virtus/attribute/array/coerce_spec.rb +0 -13
- data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +0 -85
- data/spec/unit/virtus/attribute/boolean/define_reader_method_spec.rb +0 -15
- data/spec/unit/virtus/attribute/boolean/value_coerced_spec.rb +0 -97
- data/spec/unit/virtus/attribute/boolean_spec.rb +0 -19
- data/spec/unit/virtus/attribute/class/coerce_spec.rb +0 -13
- data/spec/unit/virtus/attribute/class_methods/accessor_spec.rb +0 -12
- data/spec/unit/virtus/attribute/class_methods/coercion_method_spec.rb +0 -9
- data/spec/unit/virtus/attribute/class_methods/default_spec.rb +0 -9
- data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +0 -117
- data/spec/unit/virtus/attribute/class_methods/merge_options_spec.rb +0 -11
- data/spec/unit/virtus/attribute/class_methods/primitive_spec.rb +0 -9
- data/spec/unit/virtus/attribute/class_methods/reader_spec.rb +0 -9
- data/spec/unit/virtus/attribute/class_methods/writer_spec.rb +0 -9
- data/spec/unit/virtus/attribute/coercion_method_spec.rb +0 -12
- data/spec/unit/virtus/attribute/collection/class_methods/merge_options_spec.rb +0 -40
- data/spec/unit/virtus/attribute/collection/coerce_and_append_member_spec.rb +0 -16
- data/spec/unit/virtus/attribute/collection/member_coercion/coerce_and_append_member_spec.rb +0 -18
- data/spec/unit/virtus/attribute/collection/member_type_spec.rb +0 -17
- data/spec/unit/virtus/attribute/collection/new_collection_spec.rb +0 -9
- data/spec/unit/virtus/attribute/date/coerce_spec.rb +0 -47
- data/spec/unit/virtus/attribute/date/value_coerced_spec.rb +0 -46
- data/spec/unit/virtus/attribute/date_time/coerce_spec.rb +0 -80
- data/spec/unit/virtus/attribute/decimal/coerce_spec.rb +0 -123
- data/spec/unit/virtus/attribute/default_spec.rb +0 -28
- data/spec/unit/virtus/attribute/default_value/call_spec.rb +0 -21
- data/spec/unit/virtus/attribute/default_value/class_methods/build_spec.rb +0 -23
- data/spec/unit/virtus/attribute/default_value/class_methods/new_spec.rb +0 -21
- data/spec/unit/virtus/attribute/default_value/from_callable/call_spec.rb +0 -19
- data/spec/unit/virtus/attribute/default_value/from_callable/class_methods/handle_spec.rb +0 -17
- data/spec/unit/virtus/attribute/default_value/from_clonable/call_spec.rb +0 -20
- data/spec/unit/virtus/attribute/default_value/from_clonable/class_methods/handle_spec.rb +0 -19
- data/spec/unit/virtus/attribute/default_value/from_symbol/call_spec.rb +0 -17
- data/spec/unit/virtus/attribute/default_value/from_symbol/class_methods/handle_spec.rb +0 -17
- data/spec/unit/virtus/attribute/default_value/value_spec.rb +0 -10
- data/spec/unit/virtus/attribute/define_accessor_methods_spec.rb +0 -26
- data/spec/unit/virtus/attribute/define_reader_method_spec.rb +0 -24
- data/spec/unit/virtus/attribute/define_writer_method_spec.rb +0 -24
- data/spec/unit/virtus/attribute/embedded_value/class_methods/determine_type_spec.rb +0 -23
- data/spec/unit/virtus/attribute/embedded_value/class_methods/merge_options_spec.rb +0 -17
- data/spec/unit/virtus/attribute/embedded_value/from_open_struct/coerce_spec.rb +0 -34
- data/spec/unit/virtus/attribute/embedded_value/from_struct/coerce_spec.rb +0 -34
- data/spec/unit/virtus/attribute/float/coerce_spec.rb +0 -123
- data/spec/unit/virtus/attribute/hash/class_methods/merge_options_spec.rb +0 -33
- data/spec/unit/virtus/attribute/hash/key_type_spec.rb +0 -10
- data/spec/unit/virtus/attribute/hash/value_type_spec.rb +0 -10
- data/spec/unit/virtus/attribute/inspect_spec.rb +0 -27
- data/spec/unit/virtus/attribute/integer/coerce_spec.rb +0 -117
- data/spec/unit/virtus/attribute/name_spec.rb +0 -12
- data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +0 -15
- data/spec/unit/virtus/attribute/numeric/class_methods/max_spec.rb +0 -9
- data/spec/unit/virtus/attribute/numeric/class_methods/min_spec.rb +0 -9
- data/spec/unit/virtus/attribute/options_spec.rb +0 -14
- data/spec/unit/virtus/attribute/public_reader_spec.rb +0 -24
- data/spec/unit/virtus/attribute/public_writer_spec.rb +0 -24
- data/spec/unit/virtus/attribute/set/coerce_spec.rb +0 -13
- data/spec/unit/virtus/attribute/string/coerce_spec.rb +0 -11
- data/spec/unit/virtus/attribute/symbol/coerce_spec.rb +0 -13
- data/spec/unit/virtus/attribute/time/coerce_spec.rb +0 -67
- data/spec/unit/virtus/attribute/value_coerced_spec.rb +0 -19
- data/spec/unit/virtus/class_methods/attribute_set_spec.rb +0 -9
- data/spec/unit/virtus/class_methods/attribute_spec.rb +0 -30
- data/spec/unit/virtus/class_methods/attributes_spec.rb +0 -22
- data/spec/unit/virtus/class_methods/const_missing_spec.rb +0 -27
- data/spec/unit/virtus/class_methods/inherited_spec.rb +0 -21
- data/spec/unit/virtus/coercion/array/class_methods/to_set_spec.rb +0 -12
- data/spec/unit/virtus/coercion/class_methods/element_reference_spec.rb +0 -17
- data/spec/unit/virtus/coercion/class_methods/primitive_spec.rb +0 -13
- data/spec/unit/virtus/coercion/date/class_methods/to_date_spec.rb +0 -10
- data/spec/unit/virtus/coercion/date/class_methods/to_datetime_spec.rb +0 -30
- data/spec/unit/virtus/coercion/date/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/date/class_methods/to_time_spec.rb +0 -12
- data/spec/unit/virtus/coercion/date_time/class_methods/to_date_spec.rb +0 -30
- data/spec/unit/virtus/coercion/date_time/class_methods/to_datetime_spec.rb +0 -10
- data/spec/unit/virtus/coercion/date_time/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/date_time/class_methods/to_time_spec.rb +0 -30
- data/spec/unit/virtus/coercion/decimal/class_methods/to_decimal_spec.rb +0 -9
- data/spec/unit/virtus/coercion/decimal/class_methods/to_float_spec.rb +0 -12
- data/spec/unit/virtus/coercion/decimal/class_methods/to_integer_spec.rb +0 -12
- data/spec/unit/virtus/coercion/decimal/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/false_class/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/float/class_methods/to_decimal_spec.rb +0 -12
- data/spec/unit/virtus/coercion/float/class_methods/to_float_spec.rb +0 -9
- data/spec/unit/virtus/coercion/float/class_methods/to_integer_spec.rb +0 -12
- data/spec/unit/virtus/coercion/float/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/hash/class_methods/to_date_spec.rb +0 -38
- data/spec/unit/virtus/coercion/hash/class_methods/to_datetime_spec.rb +0 -38
- data/spec/unit/virtus/coercion/hash/class_methods/to_time_spec.rb +0 -38
- data/spec/unit/virtus/coercion/integer/class_methods/to_boolean_spec.rb +0 -25
- data/spec/unit/virtus/coercion/integer/class_methods/to_decimal_spec.rb +0 -12
- data/spec/unit/virtus/coercion/integer/class_methods/to_float_spec.rb +0 -12
- data/spec/unit/virtus/coercion/integer/class_methods/to_integer_spec.rb +0 -9
- data/spec/unit/virtus/coercion/integer/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/numeric/class_methods/to_decimal_spec.rb +0 -10
- data/spec/unit/virtus/coercion/numeric/class_methods/to_float_spec.rb +0 -10
- data/spec/unit/virtus/coercion/numeric/class_methods/to_integer_spec.rb +0 -10
- data/spec/unit/virtus/coercion/numeric/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/object/class_methods/method_missing_spec.rb +0 -33
- data/spec/unit/virtus/coercion/object/class_methods/to_array_spec.rb +0 -51
- data/spec/unit/virtus/coercion/object/class_methods/to_hash_spec.rb +0 -22
- data/spec/unit/virtus/coercion/object/class_methods/to_integer_spec.rb +0 -22
- data/spec/unit/virtus/coercion/object/class_methods/to_string_spec.rb +0 -22
- data/spec/unit/virtus/coercion/string/class_methods/to_boolean_spec.rb +0 -29
- data/spec/unit/virtus/coercion/string/class_methods/to_constant_spec.rb +0 -49
- data/spec/unit/virtus/coercion/string/class_methods/to_date_spec.rb +0 -23
- data/spec/unit/virtus/coercion/string/class_methods/to_datetime_spec.rb +0 -50
- data/spec/unit/virtus/coercion/string/class_methods/to_decimal_spec.rb +0 -47
- data/spec/unit/virtus/coercion/string/class_methods/to_float_spec.rb +0 -57
- data/spec/unit/virtus/coercion/string/class_methods/to_integer_spec.rb +0 -68
- data/spec/unit/virtus/coercion/string/class_methods/to_symbol_spec.rb +0 -9
- data/spec/unit/virtus/coercion/string/class_methods/to_time_spec.rb +0 -50
- data/spec/unit/virtus/coercion/symbol/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/coercion/time/class_methods/to_integer_spec.rb +0 -10
- data/spec/unit/virtus/coercion/time/class_methods/to_time_spec.rb +0 -10
- data/spec/unit/virtus/coercion/time_coercions/to_date_spec.rb +0 -33
- data/spec/unit/virtus/coercion/time_coercions/to_datetime_spec.rb +0 -33
- data/spec/unit/virtus/coercion/time_coercions/to_string_spec.rb +0 -18
- data/spec/unit/virtus/coercion/time_coercions/to_time_spec.rb +0 -33
- data/spec/unit/virtus/coercion/true_class/class_methods/to_string_spec.rb +0 -12
- data/spec/unit/virtus/equalizer/append_spec.rb +0 -82
- data/spec/unit/virtus/equalizer/class_method/new_spec.rb +0 -111
- data/spec/unit/virtus/equalizer/methods/eql_spec.rb +0 -47
- data/spec/unit/virtus/equalizer/methods/equal_value_spec.rb +0 -57
- data/spec/unit/virtus/extensions/allowed_writer_methods_spec.rb +0 -25
- data/spec/unit/virtus/extensions/attribute_spec.rb +0 -26
- data/spec/unit/virtus/instance_methods/attributes_spec.rb +0 -140
- data/spec/unit/virtus/instance_methods/element_reference_spec.rb +0 -24
- data/spec/unit/virtus/instance_methods/element_set_spec.rb +0 -28
- data/spec/unit/virtus/instance_methods/freeze_spec.rb +0 -64
- data/spec/unit/virtus/instance_methods/initialize_spec.rb +0 -48
- data/spec/unit/virtus/instance_methods/to_hash_spec.rb +0 -23
- data/spec/unit/virtus/module_extensions/attribute_spec.rb +0 -31
- data/spec/unit/virtus/options/accept_options_spec.rb +0 -37
- data/spec/unit/virtus/options/accepted_options_spec.rb +0 -21
- data/spec/unit/virtus/options/options_spec.rb +0 -34
- data/spec/unit/virtus/type_lookup/class_methods/extended_spec.rb +0 -9
- data/spec/unit/virtus/type_lookup/determine_type_spec.rb +0 -81
- data/spec/unit/virtus/type_lookup/primitive_spec.rb +0 -9
- data/spec/unit/virtus/value_object/class_methods/allowed_writer_methods_spec.rb +0 -15
- data/spec/unit/virtus/value_object/class_methods/attribute_spec.rb +0 -50
- data/spec/unit/virtus/value_object/class_methods/equalizer_spec.rb +0 -24
- data/spec/unit/virtus/value_object/initialize_spec.rb +0 -19
- data/spec/unit/virtus/value_object/instance_methods/clone_spec.rb +0 -21
- data/spec/unit/virtus/value_object/instance_methods/with_spec.rb +0 -31
@@ -13,29 +13,36 @@ module Virtus
|
|
13
13
|
def self.included(descendant)
|
14
14
|
super
|
15
15
|
descendant.extend(ClassMethods)
|
16
|
+
descendant.class_eval { include Methods }
|
16
17
|
descendant.class_eval { include InstanceMethods }
|
18
|
+
descendant.class_eval { include InstanceMethods::Constructor }
|
19
|
+
descendant.class_eval { include InstanceMethods::MassAssignment }
|
17
20
|
end
|
18
21
|
private_class_method :included
|
19
22
|
|
20
|
-
|
23
|
+
module Methods
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
# Return a list of allowed writer method names
|
26
|
+
#
|
27
|
+
# @return [Set]
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def allowed_writer_methods
|
31
|
+
self.class.allowed_writer_methods
|
32
|
+
end
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
private
|
35
|
+
|
36
|
+
# Return class' attribute set
|
37
|
+
#
|
38
|
+
# @return [Virtus::AttributeSet]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
def attribute_set
|
42
|
+
self.class.attribute_set
|
43
|
+
end
|
44
|
+
|
45
|
+
end # Methods
|
39
46
|
|
40
47
|
end # module ClassInclusions
|
41
48
|
end # module Virtus
|
data/lib/virtus/class_methods.rb
CHANGED
@@ -2,7 +2,8 @@ module Virtus
|
|
2
2
|
|
3
3
|
# Class methods that are added when you include Virtus
|
4
4
|
module ClassMethods
|
5
|
-
include Extensions
|
5
|
+
include Extensions::Methods
|
6
|
+
include ConstMissingExtensions
|
6
7
|
|
7
8
|
# Hook called when module is extended
|
8
9
|
#
|
@@ -13,12 +14,12 @@ module Virtus
|
|
13
14
|
# @api private
|
14
15
|
def self.extended(descendant)
|
15
16
|
super
|
17
|
+
AttributeSet.create(descendant)
|
16
18
|
descendant.module_eval do
|
17
19
|
extend DescendantsTracker
|
18
20
|
include attribute_set
|
19
21
|
end
|
20
22
|
end
|
21
|
-
|
22
23
|
private_class_method :extended
|
23
24
|
|
24
25
|
# Returns all the attributes defined on a Class
|
@@ -39,11 +40,7 @@ module Virtus
|
|
39
40
|
#
|
40
41
|
# @api public
|
41
42
|
def attribute_set
|
42
|
-
|
43
|
-
superclass = self.superclass
|
44
|
-
method = __method__
|
45
|
-
parent = superclass.public_send(method) if superclass.respond_to?(method)
|
46
|
-
@attribute_set = AttributeSet.new(parent)
|
43
|
+
@attribute_set
|
47
44
|
end
|
48
45
|
|
49
46
|
# @see Virtus::ClassMethods.attribute_set
|
@@ -56,18 +53,7 @@ module Virtus
|
|
56
53
|
attribute_set
|
57
54
|
end
|
58
55
|
|
59
|
-
|
60
|
-
#
|
61
|
-
# @param [String] name
|
62
|
-
#
|
63
|
-
# @return [Class]
|
64
|
-
#
|
65
|
-
# @api private
|
66
|
-
def const_missing(name)
|
67
|
-
Attribute.determine_type(name) or super
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
56
|
+
private
|
71
57
|
|
72
58
|
# Setup descendants' own Attribute-accessor-method-hosting modules
|
73
59
|
#
|
@@ -84,21 +70,10 @@ module Virtus
|
|
84
70
|
# @api private
|
85
71
|
def inherited(descendant)
|
86
72
|
super
|
73
|
+
AttributeSet.create(descendant)
|
87
74
|
descendant.module_eval { include attribute_set }
|
88
75
|
end
|
89
76
|
|
90
|
-
# Add the attribute to the class' and descendants' attributes
|
91
|
-
#
|
92
|
-
# @param [Attribute]
|
93
|
-
#
|
94
|
-
# @return [undefined]
|
95
|
-
#
|
96
|
-
# @api private
|
97
|
-
def virtus_add_attribute(attribute)
|
98
|
-
super
|
99
|
-
descendants.each { |descendant| descendant.attribute_set.reset }
|
100
|
-
end
|
101
|
-
|
102
77
|
# The list of allowed public methods
|
103
78
|
#
|
104
79
|
# @return [Array<String>]
|
@@ -108,5 +83,12 @@ module Virtus
|
|
108
83
|
public_instance_methods.map(&:to_s)
|
109
84
|
end
|
110
85
|
|
86
|
+
# @api private
|
87
|
+
def assert_valid_name(name)
|
88
|
+
if instance_methods.include?(:attributes) && name.to_sym == :attributes
|
89
|
+
raise ArgumentError, "#{name.inspect} is not allowed as an attribute name"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
111
93
|
end # module ClassMethods
|
112
94
|
end # module Virtus
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# A Configuration instance
|
4
|
+
class Configuration
|
5
|
+
|
6
|
+
# Access the coerce setting for this instance
|
7
|
+
attr_accessor :coerce
|
8
|
+
|
9
|
+
# Access the strict setting for this instance
|
10
|
+
attr_accessor :strict
|
11
|
+
|
12
|
+
# Access the constructor setting for this instance
|
13
|
+
attr_accessor :constructor
|
14
|
+
|
15
|
+
# Access the mass-assignment setting for this instance
|
16
|
+
attr_accessor :mass_assignment
|
17
|
+
|
18
|
+
# Build new configuration instance using the passed block
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# Configuration.build do |config|
|
22
|
+
# config.coerce = false
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @return [Configuration]
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def self.build(&block)
|
29
|
+
new.call(&block)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Initialized a configuration instance
|
33
|
+
#
|
34
|
+
# @return [undefined]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
def initialize
|
38
|
+
@coerce = true
|
39
|
+
@strict = false
|
40
|
+
@constructor = true
|
41
|
+
@mass_assignment = true
|
42
|
+
@coercer = Coercible::Coercer.new
|
43
|
+
end
|
44
|
+
|
45
|
+
# Provide access to the attributes and methods via the passed block
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# configuration.call do |config|
|
49
|
+
# config.coerce = false
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# @return [self]
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
def call(&block)
|
56
|
+
block.call(self) if block_given?
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# Access the coercer for this instance and optional configure a
|
61
|
+
# new coercer with the passed block
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# configuration.coercer do |config|
|
65
|
+
# config.string.boolean_map = { true => '1', false => '0' }
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# @return [Coercer]
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
def coercer(&block)
|
72
|
+
@coercer = Coercible::Coercer.new(&block) if block_given?
|
73
|
+
@coercer
|
74
|
+
end
|
75
|
+
|
76
|
+
end # class Configuration
|
77
|
+
end # module Virtus
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Virtus
|
2
|
+
module ConstMissingExtensions
|
3
|
+
|
4
|
+
# Hooks into const missing process to determine types of attributes
|
5
|
+
#
|
6
|
+
# @param [String] name
|
7
|
+
#
|
8
|
+
# @return [Class]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
def const_missing(name)
|
12
|
+
Attribute::Builder.determine_type(name) or Axiom::Types.const_get(name) or super
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/virtus/extensions.rb
CHANGED
@@ -4,6 +4,7 @@ module Virtus
|
|
4
4
|
module Extensions
|
5
5
|
WRITER_METHOD_REGEXP = /=\z/.freeze
|
6
6
|
INVALID_WRITER_METHODS = %w[ == != === []= attributes= ].to_set.freeze
|
7
|
+
RESERVED_NAMES = [:attributes].to_set.freeze
|
7
8
|
|
8
9
|
# A hook called when an object is extended with Virtus
|
9
10
|
#
|
@@ -15,78 +16,102 @@ module Virtus
|
|
15
16
|
def self.extended(object)
|
16
17
|
super
|
17
18
|
object.instance_eval do
|
19
|
+
extend Methods
|
18
20
|
extend InstanceMethods
|
21
|
+
extend InstanceMethods::Constructor
|
22
|
+
extend InstanceMethods::MassAssignment
|
19
23
|
extend attribute_set
|
20
24
|
end
|
21
25
|
end
|
22
26
|
private_class_method :extended
|
23
27
|
|
24
|
-
|
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
|
-
# attribute :index # defaults to Object
|
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
|
-
virtus_add_attribute(attribute)
|
54
|
-
self
|
55
|
-
end
|
28
|
+
module Methods
|
56
29
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
@allowed_writer_methods ||=
|
64
|
-
begin
|
65
|
-
allowed_writer_methods = allowed_methods.grep(WRITER_METHOD_REGEXP).to_set
|
66
|
-
allowed_writer_methods -= INVALID_WRITER_METHODS
|
67
|
-
allowed_writer_methods.freeze
|
30
|
+
# @api private
|
31
|
+
def self.extended(descendant)
|
32
|
+
AttributeSet.create(descendant)
|
33
|
+
descendant.instance_eval do
|
34
|
+
extend attribute_set
|
35
|
+
end
|
68
36
|
end
|
69
|
-
|
37
|
+
private_class_method :extended
|
70
38
|
|
71
|
-
|
39
|
+
# Defines an attribute on an object's class
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# class Book
|
43
|
+
# include Virtus
|
44
|
+
#
|
45
|
+
# attribute :title, String
|
46
|
+
# attribute :author, String
|
47
|
+
# attribute :published_at, DateTime
|
48
|
+
# attribute :page_count, Integer
|
49
|
+
# attribute :index # defaults to Object
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# @param [Symbol] name
|
53
|
+
# the name of an attribute
|
54
|
+
#
|
55
|
+
# @param [Class] type
|
56
|
+
# the type class of an attribute
|
57
|
+
#
|
58
|
+
# @param [#to_hash] options
|
59
|
+
# the extra options hash
|
60
|
+
#
|
61
|
+
# @return [self]
|
62
|
+
#
|
63
|
+
# @see Attribute.build
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
def attribute(name, type, options = {})
|
67
|
+
assert_valid_name(name)
|
68
|
+
attribute_set << Attribute.build(type, merge_options(name, options))
|
69
|
+
self
|
70
|
+
end
|
72
71
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
72
|
+
# @api public
|
73
|
+
def values(&block)
|
74
|
+
private :attributes=
|
75
|
+
yield
|
76
|
+
include(::Equalizer.new(*attribute_set.map(&:name)))
|
77
|
+
self
|
78
|
+
end
|
81
79
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
80
|
+
# The list of writer methods that can be mass-assigned to in #attributes=
|
81
|
+
#
|
82
|
+
# @return [Set]
|
83
|
+
#
|
84
|
+
# @api private
|
85
|
+
def allowed_writer_methods
|
86
|
+
@allowed_writer_methods ||=
|
87
|
+
begin
|
88
|
+
allowed_writer_methods = allowed_methods.grep(WRITER_METHOD_REGEXP).to_set
|
89
|
+
allowed_writer_methods -= INVALID_WRITER_METHODS
|
90
|
+
allowed_writer_methods.freeze
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Return an attribute set for that instance
|
97
|
+
#
|
98
|
+
# @return [AttributeSet]
|
99
|
+
#
|
100
|
+
# @api private
|
101
|
+
def attribute_set
|
102
|
+
@attribute_set
|
103
|
+
end
|
104
|
+
|
105
|
+
# Merge default options
|
106
|
+
#
|
107
|
+
# @return [Hash]
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
def merge_options(name, options)
|
111
|
+
{ :name => name }.merge(options)
|
112
|
+
end
|
113
|
+
|
114
|
+
end # Methods
|
90
115
|
|
91
116
|
end # module Extensions
|
92
117
|
end # module Virtus
|
@@ -3,17 +3,74 @@ module Virtus
|
|
3
3
|
# Instance methods that are added when you include Virtus
|
4
4
|
module InstanceMethods
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
module Constructor
|
7
|
+
|
8
|
+
# Set attributes during initialization of an object
|
9
|
+
#
|
10
|
+
# @param [#to_hash] attributes
|
11
|
+
# the attributes hash to be set
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
def initialize(attributes = nil)
|
17
|
+
attribute_set.set(self, attributes) if attributes
|
18
|
+
set_default_attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
end # Constructor
|
22
|
+
|
23
|
+
module MassAssignment
|
24
|
+
|
25
|
+
# Returns a hash of all publicly accessible attributes
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# class User
|
29
|
+
# include Virtus
|
30
|
+
#
|
31
|
+
# attribute :name, String
|
32
|
+
# attribute :age, Integer
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# user = User.new(:name => 'John', :age => 28)
|
36
|
+
# user.attributes # => { :name => 'John', :age => 28 }
|
37
|
+
#
|
38
|
+
# @return [Hash]
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
def attributes
|
42
|
+
attribute_set.get(self)
|
43
|
+
end
|
44
|
+
alias_method :to_hash, :attributes
|
45
|
+
|
46
|
+
# Mass-assign attribute values
|
47
|
+
#
|
48
|
+
# Keys in the +attributes+ param can be symbols or strings.
|
49
|
+
# All referenced Attribute writer methods *will* be called.
|
50
|
+
# Non-attribute setter methods on the receiver *will* be called.
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# class User
|
54
|
+
# include Virtus
|
55
|
+
#
|
56
|
+
# attribute :name, String
|
57
|
+
# attribute :age, Integer
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# user = User.new
|
61
|
+
# user.attributes = { :name => 'John', 'age' => 28 }
|
62
|
+
#
|
63
|
+
# @param [#to_hash] attributes
|
64
|
+
# a hash of attribute names and values to set on the receiver
|
65
|
+
#
|
66
|
+
# @return [Hash]
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def attributes=(attributes)
|
70
|
+
attribute_set.set(self, attributes)
|
71
|
+
end
|
72
|
+
|
73
|
+
end # MassAssignment
|
17
74
|
|
18
75
|
# Returns a value of the attribute with the given name
|
19
76
|
#
|
@@ -35,7 +92,7 @@ module Virtus
|
|
35
92
|
#
|
36
93
|
# @api public
|
37
94
|
def [](name)
|
38
|
-
|
95
|
+
public_send(name)
|
39
96
|
end
|
40
97
|
|
41
98
|
# Sets a value of the attribute with the given name
|
@@ -62,59 +119,17 @@ module Virtus
|
|
62
119
|
#
|
63
120
|
# @api public
|
64
121
|
def []=(name, value)
|
65
|
-
|
122
|
+
public_send("#{name}=", value)
|
66
123
|
end
|
67
124
|
|
68
|
-
#
|
69
|
-
#
|
70
|
-
# @example
|
71
|
-
# class User
|
72
|
-
# include Virtus
|
73
|
-
#
|
74
|
-
# attribute :name, String
|
75
|
-
# attribute :age, Integer
|
76
|
-
# end
|
77
|
-
#
|
78
|
-
# user = User.new(:name => 'John', :age => 28)
|
79
|
-
# user.attributes # => { :name => 'John', :age => 28 }
|
125
|
+
# Freeze object
|
80
126
|
#
|
81
|
-
# @return [
|
127
|
+
# @return [self]
|
82
128
|
#
|
83
129
|
# @api public
|
84
|
-
def attributes
|
85
|
-
get_attributes(&:public_reader?)
|
86
|
-
end
|
87
|
-
|
88
|
-
# Mass-assign attribute values
|
89
|
-
#
|
90
|
-
# Keys in the +attributes+ param can be symbols or strings.
|
91
|
-
# All referenced Attribute writer methods *will* be called.
|
92
|
-
# Non-attribute setter methods on the receiver *will* be called.
|
93
130
|
#
|
94
131
|
# @example
|
95
|
-
# class User
|
96
|
-
# include Virtus
|
97
|
-
#
|
98
|
-
# attribute :name, String
|
99
|
-
# attribute :age, Integer
|
100
|
-
# end
|
101
|
-
#
|
102
|
-
# user = User.new
|
103
|
-
# user.attributes = { :name => 'John', 'age' => 28 }
|
104
|
-
#
|
105
|
-
# @param [#to_hash] attributes
|
106
|
-
# a hash of attribute names and values to set on the receiver
|
107
132
|
#
|
108
|
-
# @return [Hash]
|
109
|
-
#
|
110
|
-
# @api public
|
111
|
-
def attributes=(attributes)
|
112
|
-
set_attributes(attributes)
|
113
|
-
end
|
114
|
-
|
115
|
-
# Returns a hash of all publicly accessible attributes
|
116
|
-
#
|
117
|
-
# @example
|
118
133
|
# class User
|
119
134
|
# include Virtus
|
120
135
|
#
|
@@ -123,16 +138,17 @@ module Virtus
|
|
123
138
|
# end
|
124
139
|
#
|
125
140
|
# user = User.new(:name => 'John', :age => 28)
|
126
|
-
# user.
|
127
|
-
#
|
128
|
-
#
|
141
|
+
# user.frozen? # => false
|
142
|
+
# user.freeze
|
143
|
+
# user.frozen? # => true
|
129
144
|
#
|
130
145
|
# @api public
|
131
|
-
def
|
132
|
-
|
146
|
+
def freeze
|
147
|
+
set_default_attributes!
|
148
|
+
super
|
133
149
|
end
|
134
150
|
|
135
|
-
#
|
151
|
+
# Reset an attribute to its default
|
136
152
|
#
|
137
153
|
# @return [self]
|
138
154
|
#
|
@@ -143,87 +159,43 @@ module Virtus
|
|
143
159
|
# class User
|
144
160
|
# include Virtus
|
145
161
|
#
|
146
|
-
# attribute :
|
147
|
-
# attribute :age, Integer
|
162
|
+
# attribute :age, Integer, default: 21
|
148
163
|
# end
|
149
164
|
#
|
150
165
|
# user = User.new(:name => 'John', :age => 28)
|
151
|
-
# user.
|
152
|
-
# user.
|
153
|
-
# user.
|
166
|
+
# user.age = 30
|
167
|
+
# user.age # => 30
|
168
|
+
# user.reset_attribute(:age)
|
169
|
+
# user.age # => 21
|
154
170
|
#
|
155
171
|
# @api public
|
156
|
-
def
|
157
|
-
|
158
|
-
|
172
|
+
def reset_attribute(attribute_name)
|
173
|
+
attribute = attribute_set[attribute_name]
|
174
|
+
attribute_set.set_default(self, attribute) if attribute
|
175
|
+
self
|
159
176
|
end
|
160
177
|
|
161
|
-
|
162
|
-
|
163
|
-
# Get values of all attributes defined for this class, ignoring privacy
|
164
|
-
#
|
165
|
-
# @return [Hash]
|
166
|
-
#
|
167
|
-
# @api private
|
168
|
-
def get_attributes
|
169
|
-
attribute_set.each_with_object({}) do |attribute, attributes|
|
170
|
-
name = attribute.name
|
171
|
-
attributes[name] = get_attribute(name) if yield(attribute)
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
# Ensure all defaults are set
|
176
|
-
#
|
177
|
-
# @return [AttributeSet]
|
178
|
-
#
|
179
|
-
# @api private
|
180
|
-
def set_defaults
|
181
|
-
attribute_set.each do |attribute|
|
182
|
-
get_attribute(attribute.name)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# Mass-assign attribute values
|
187
|
-
#
|
188
|
-
# @see Virtus::InstanceMethods#attributes=
|
178
|
+
# Set default attributes
|
189
179
|
#
|
190
|
-
# @return [
|
180
|
+
# @return [self]
|
191
181
|
#
|
192
182
|
# @api private
|
193
|
-
def
|
194
|
-
|
195
|
-
|
196
|
-
if hash.nil?
|
197
|
-
raise NoMethodError,
|
198
|
-
"Expected #{attributes.inspect} to respond to #to_hash"
|
199
|
-
end
|
200
|
-
|
201
|
-
hash.each do |name, value|
|
202
|
-
set_attribute(name, value) if allowed_writer_methods.include?("#{name}=")
|
203
|
-
end
|
183
|
+
def set_default_attributes
|
184
|
+
attribute_set.set_defaults(self)
|
185
|
+
self
|
204
186
|
end
|
205
187
|
|
206
|
-
#
|
188
|
+
# Set default attributes even lazy ones
|
207
189
|
#
|
208
|
-
# @
|
209
|
-
#
|
210
|
-
# @return [Object]
|
190
|
+
# @return [self]
|
211
191
|
#
|
212
|
-
# @api
|
213
|
-
def
|
214
|
-
|
192
|
+
# @api public
|
193
|
+
def set_default_attributes!
|
194
|
+
attribute_set.set_defaults(self, proc { |_| false })
|
195
|
+
self
|
215
196
|
end
|
216
197
|
|
217
|
-
|
218
|
-
#
|
219
|
-
# @see Virtus::InstanceMethods#[]=
|
220
|
-
#
|
221
|
-
# @return [Object]
|
222
|
-
#
|
223
|
-
# @api private
|
224
|
-
def set_attribute(name, value)
|
225
|
-
__send__("#{name}=", value)
|
226
|
-
end
|
198
|
+
private
|
227
199
|
|
228
200
|
# The list of allowed public methods
|
229
201
|
#
|
@@ -234,5 +206,12 @@ module Virtus
|
|
234
206
|
public_methods.map(&:to_s)
|
235
207
|
end
|
236
208
|
|
209
|
+
# @api private
|
210
|
+
def assert_valid_name(name)
|
211
|
+
if respond_to?(:attributes) && name.to_sym == :attributes || name.to_sym == :attribute_set
|
212
|
+
raise ArgumentError, "#{name.inspect} is not allowed as an attribute name"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
237
216
|
end # module InstanceMethods
|
238
217
|
end # module Virtus
|