virtus 0.0.10 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +33 -7
- data/.travis.yml +4 -74
- data/Changelog.md +11 -2
- data/Gemfile +10 -9
- data/README.md +85 -1
- data/TODO +18 -0
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/roodi.yml +3 -3
- data/config/site.reek +8 -3
- data/lib/virtus.rb +5 -0
- data/lib/virtus/attribute.rb +137 -30
- data/lib/virtus/attribute/array.rb +17 -1
- data/lib/virtus/attribute/boolean.rb +8 -13
- data/lib/virtus/attribute/collection.rb +96 -0
- data/lib/virtus/attribute/default_value.rb +11 -7
- data/lib/virtus/attribute/embedded_value.rb +70 -0
- data/lib/virtus/attribute/set.rb +25 -0
- data/lib/virtus/attribute_set.rb +18 -16
- data/lib/virtus/attributes_accessor.rb +66 -0
- data/lib/virtus/class_methods.rb +50 -28
- data/lib/virtus/coercion/array.rb +23 -0
- data/lib/virtus/coercion/string.rb +10 -4
- data/lib/virtus/instance_methods.rb +38 -31
- data/lib/virtus/support/options.rb +6 -8
- data/lib/virtus/support/type_lookup.rb +4 -11
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/collection_member_coercion_spec.rb +75 -0
- data/spec/integration/custom_attributes_spec.rb +49 -0
- data/spec/integration/default_values_spec.rb +32 -0
- data/spec/integration/defining_attributes_spec.rb +79 -0
- data/spec/integration/embedded_value_spec.rb +50 -0
- data/spec/integration/overriding_virtus_spec.rb +46 -0
- data/spec/integration/virtus/instance_level_attributes_spec.rb +23 -0
- data/spec/rcov.opts +1 -0
- data/spec/shared/constants_helpers.rb +9 -0
- data/spec/shared/options_class_method.rb +19 -0
- data/spec/spec_helper.rb +20 -7
- data/spec/unit/virtus/attribute/array/coerce_spec.rb +13 -0
- data/spec/unit/virtus/attribute/boolean/coerce_spec.rb +85 -0
- data/spec/unit/virtus/attribute/boolean/define_reader_method_spec.rb +15 -0
- data/spec/unit/virtus/attribute/boolean/value_coerced_spec.rb +97 -0
- data/spec/unit/virtus/attribute/boolean_spec.rb +2 -81
- data/spec/unit/virtus/attribute/class/coerce_spec.rb +13 -0
- data/spec/unit/virtus/attribute/class_methods/accessor_spec.rb +12 -0
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +37 -0
- data/spec/unit/virtus/attribute/class_methods/coercion_method_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/default_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +31 -1
- data/spec/unit/virtus/attribute/class_methods/merge_options_spec.rb +11 -0
- data/spec/unit/virtus/attribute/class_methods/primitive_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/reader_spec.rb +9 -0
- data/spec/unit/virtus/attribute/class_methods/writer_spec.rb +9 -0
- data/spec/unit/virtus/attribute/coerce_spec.rb +30 -0
- data/spec/unit/virtus/attribute/coercion_method_spec.rb +12 -0
- data/spec/unit/virtus/attribute/collection/class_methods/merge_options_spec.rb +40 -0
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +26 -0
- data/spec/unit/virtus/attribute/date/coerce_spec.rb +47 -0
- data/spec/unit/virtus/attribute/date/value_coerced_spec.rb +46 -0
- data/spec/unit/virtus/attribute/date_time/coerce_spec.rb +68 -0
- data/spec/unit/virtus/attribute/decimal/coerce_spec.rb +117 -0
- data/spec/unit/virtus/attribute/default_spec.rb +32 -0
- data/spec/unit/virtus/attribute/default_value/attribute_spec.rb +11 -0
- data/spec/unit/virtus/attribute/default_value/class_methods/new_spec.rb +4 -2
- data/spec/unit/virtus/attribute/default_value/evaluate_spec.rb +51 -0
- data/spec/unit/virtus/attribute/default_value/instance_methods/evaluate_spec.rb +9 -6
- data/spec/unit/virtus/attribute/default_value/value_spec.rb +11 -0
- data/spec/unit/virtus/attribute/define_accessor_methods_spec.rb +26 -0
- data/spec/unit/virtus/attribute/define_reader_method_spec.rb +24 -0
- data/spec/unit/virtus/attribute/define_writer_method_spec.rb +24 -0
- data/spec/unit/virtus/attribute/embedded_value/class_methods/merge_options_spec.rb +17 -0
- data/spec/unit/virtus/attribute/embedded_value/coerce_spec.rb +50 -0
- data/spec/unit/virtus/attribute/float/coerce_spec.rb +117 -0
- data/spec/unit/virtus/attribute/get_spec.rb +80 -0
- data/spec/unit/virtus/attribute/inspect_spec.rb +27 -0
- data/spec/unit/virtus/attribute/instance_variable_name_spec.rb +12 -0
- data/spec/unit/virtus/attribute/integer/coerce_spec.rb +105 -0
- data/spec/unit/virtus/attribute/name_spec.rb +12 -0
- data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +1 -1
- data/spec/unit/virtus/attribute/numeric/class_methods/max_spec.rb +9 -0
- data/spec/unit/virtus/attribute/numeric/class_methods/min_spec.rb +9 -0
- data/spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb +9 -7
- data/spec/unit/virtus/attribute/options_spec.rb +14 -0
- data/spec/unit/virtus/attribute/public_reader_spec.rb +24 -0
- data/spec/unit/virtus/attribute/public_writer_spec.rb +24 -0
- data/spec/unit/virtus/attribute/reader_visibility_spec.rb +24 -0
- data/spec/unit/virtus/attribute/set/coerce_spec.rb +13 -0
- data/spec/unit/virtus/attribute/set_spec.rb +49 -0
- data/spec/unit/virtus/attribute/string/coerce_spec.rb +11 -0
- data/spec/unit/virtus/attribute/time/coerce_spec.rb +67 -0
- data/spec/unit/virtus/attribute/value_coerced_spec.rb +19 -0
- data/spec/unit/virtus/attribute/writer_visibility_spec.rb +24 -0
- data/spec/unit/virtus/attribute_set/append_spec.rb +12 -0
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +4 -0
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +29 -9
- data/spec/unit/virtus/attributes_accessor/inspect_spec.rb +9 -0
- data/spec/unit/virtus/class_methods/attribute_spec.rb +23 -5
- data/spec/unit/virtus/class_methods/attributes_spec.rb +3 -5
- data/spec/unit/virtus/class_methods/const_missing_spec.rb +27 -0
- data/spec/unit/virtus/class_methods/inherited_spec.rb +21 -0
- data/spec/unit/virtus/coercion/array/to_set_spec.rb +12 -0
- data/spec/unit/virtus/coercion/date/class_methods/to_date_spec.rb +10 -0
- data/spec/unit/virtus/coercion/date_time/class_methods/to_datetime_spec.rb +10 -0
- data/spec/unit/virtus/coercion/hash/class_methods/to_date_spec.rb +10 -3
- data/spec/unit/virtus/coercion/hash/class_methods/to_datetime_spec.rb +10 -3
- data/spec/unit/virtus/coercion/hash/class_methods/to_time_spec.rb +10 -3
- data/spec/unit/virtus/coercion/object/class_methods/method_missing_spec.rb +8 -8
- data/spec/unit/virtus/coercion/string/class_methods/to_boolean_spec.rb +2 -2
- data/spec/unit/virtus/coercion/string/class_methods/to_constant_spec.rb +1 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_date_spec.rb +1 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_datetime_spec.rb +13 -13
- data/spec/unit/virtus/coercion/string/class_methods/to_decimal_spec.rb +25 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_float_spec.rb +25 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_integer_spec.rb +30 -1
- data/spec/unit/virtus/coercion/string/class_methods/to_time_spec.rb +13 -13
- data/spec/unit/virtus/coercion/time/class_methods/to_time_spec.rb +10 -0
- data/spec/unit/virtus/coercion/true_class/class_methods/to_string_spec.rb +1 -1
- data/spec/unit/virtus/instance_methods/attributes_spec.rb +77 -20
- data/spec/unit/virtus/instance_methods/element_reference_spec.rb +1 -1
- data/spec/unit/virtus/instance_methods/element_set_spec.rb +2 -2
- data/spec/unit/virtus/instance_methods/to_hash_spec.rb +23 -0
- data/spec/unit/virtus/options/accept_options_spec.rb +10 -11
- data/spec/unit/virtus/options/accepted_options_spec.rb +1 -1
- data/spec/unit/virtus/options/options_spec.rb +27 -4
- data/tasks/metrics/ci.rake +2 -1
- data/tasks/metrics/heckle.rake +207 -0
- data/tasks/spec.rake +14 -7
- data/virtus.gemspec +1 -1
- metadata +111 -97
- data/VERSION +0 -1
- data/examples/custom_coercion_spec.rb +0 -50
- data/examples/default_values_spec.rb +0 -21
- data/examples/override_attribute_methods_spec.rb +0 -40
- data/spec/integration/virtus/attributes/attribute/set_spec.rb +0 -36
- data/spec/integration/virtus/class_methods/attribute_spec.rb +0 -82
- data/spec/integration/virtus/class_methods/attributes_spec.rb +0 -22
- data/spec/integration/virtus/class_methods/const_missing_spec.rb +0 -44
- data/spec/unit/shared/attribute.rb +0 -7
- data/spec/unit/shared/attribute/accept_options.rb +0 -37
- data/spec/unit/shared/attribute/accepted_options.rb +0 -5
- data/spec/unit/shared/attribute/get.rb +0 -44
- data/spec/unit/shared/attribute/inspect.rb +0 -7
- data/spec/unit/shared/attribute/set.rb +0 -37
- data/spec/unit/virtus/attribute/array_spec.rb +0 -24
- data/spec/unit/virtus/attribute/class_spec.rb +0 -24
- data/spec/unit/virtus/attribute/date_spec.rb +0 -59
- data/spec/unit/virtus/attribute/date_time_spec.rb +0 -87
- data/spec/unit/virtus/attribute/decimal_spec.rb +0 -109
- data/spec/unit/virtus/attribute/float_spec.rb +0 -109
- data/spec/unit/virtus/attribute/hash_spec.rb +0 -11
- data/spec/unit/virtus/attribute/integer_spec.rb +0 -99
- data/spec/unit/virtus/attribute/string_spec.rb +0 -21
- data/spec/unit/virtus/attribute/time_spec.rb +0 -82
- data/spec/unit/virtus/class_methods/new_spec.rb +0 -41
@@ -12,10 +12,26 @@ module Virtus
|
|
12
12
|
#
|
13
13
|
# post = Post.new(:tags => %w(red green blue))
|
14
14
|
#
|
15
|
-
class Array <
|
15
|
+
class Array < Collection
|
16
16
|
primitive ::Array
|
17
17
|
coercion_method :to_array
|
18
18
|
|
19
|
+
# Coerce a member of a source collection and append it to the target collection
|
20
|
+
#
|
21
|
+
# @param [Array, Set] collection
|
22
|
+
# target collection to which the coerced member should be appended
|
23
|
+
#
|
24
|
+
# @param [Object] entry
|
25
|
+
# the member that should be coerced and appended
|
26
|
+
#
|
27
|
+
# @return [Array, Set]
|
28
|
+
# collection with the coerced member appended to it
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def coerce_and_append_member(collection, entry)
|
32
|
+
collection << @member_type_instance.coerce(entry)
|
33
|
+
end
|
34
|
+
|
19
35
|
end # class Array
|
20
36
|
end # class Attribute
|
21
37
|
end # module Virtus
|
@@ -21,19 +21,20 @@ module Virtus
|
|
21
21
|
# Returns if the given value is either true or false
|
22
22
|
#
|
23
23
|
# @example
|
24
|
-
# Virtus::Attribute::Boolean.
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
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
|
28
29
|
#
|
29
30
|
# @return [Boolean]
|
30
31
|
#
|
31
32
|
# @api public
|
32
|
-
def
|
33
|
+
def value_coerced?(value)
|
33
34
|
value.equal?(true) || value.equal?(false)
|
34
35
|
end
|
35
36
|
|
36
|
-
# Creates
|
37
|
+
# Creates an attribute reader method as a query
|
37
38
|
#
|
38
39
|
# @param [Module] mod
|
39
40
|
#
|
@@ -42,13 +43,7 @@ module Virtus
|
|
42
43
|
# @api private
|
43
44
|
def define_reader_method(mod)
|
44
45
|
super
|
45
|
-
|
46
|
-
reader_method_name = "#{name}?"
|
47
|
-
attribute = self
|
48
|
-
|
49
|
-
mod.send(:define_method, reader_method_name) { attribute.get(self) }
|
50
|
-
mod.send(reader_visibility, reader_method_name)
|
51
|
-
|
46
|
+
mod.define_reader_method(self, "#{name}?", reader_visibility)
|
52
47
|
self
|
53
48
|
end
|
54
49
|
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
|
4
|
+
# Abstract superclass for collection Attributes.
|
5
|
+
#
|
6
|
+
# Handles coercing members to the designated member type.
|
7
|
+
#
|
8
|
+
# @abstract
|
9
|
+
class Collection < Object
|
10
|
+
|
11
|
+
# The type to which members of this collection will be coerced
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# class Post
|
16
|
+
# include Virtus
|
17
|
+
#
|
18
|
+
# attribute :tags, Array[String]
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Post.attributes[:tags].member_type # => Virtus::Attribute::String
|
22
|
+
#
|
23
|
+
# @return [Virtus::Attribute]
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
attr_reader :member_type
|
27
|
+
|
28
|
+
# Handles collection with member_type syntax
|
29
|
+
#
|
30
|
+
# @param [Class]
|
31
|
+
#
|
32
|
+
# @param [Hash]
|
33
|
+
#
|
34
|
+
# @return [Hash]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
def self.merge_options(type, options)
|
38
|
+
if !type.respond_to?(:size)
|
39
|
+
options
|
40
|
+
elsif type.size > 1
|
41
|
+
raise NotImplementedError, "build SumType from list of types (#{type.inspect})"
|
42
|
+
else
|
43
|
+
options.merge(:member_type => type.first)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Init an instance of Virtus::Attribute::Collection
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
def initialize(*)
|
51
|
+
super
|
52
|
+
@member_type = @options.fetch(:member_type, Virtus::Attribute::Object)
|
53
|
+
@member_type_instance = Attribute.build(@name, @member_type)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Coerce a collection with members
|
57
|
+
#
|
58
|
+
# @param [Object]
|
59
|
+
#
|
60
|
+
# @return [Object]
|
61
|
+
#
|
62
|
+
# @api private
|
63
|
+
def coerce(value)
|
64
|
+
coerced = super
|
65
|
+
return coerced unless coerced.respond_to?(:inject)
|
66
|
+
coerced.inject(new_collection) do |collection, entry|
|
67
|
+
coerce_and_append_member(collection, entry)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return an instance of the collection
|
72
|
+
#
|
73
|
+
# @return [Enumerable]
|
74
|
+
#
|
75
|
+
# @api private
|
76
|
+
def new_collection
|
77
|
+
self.class.primitive.new
|
78
|
+
end
|
79
|
+
|
80
|
+
# Coerce entry and add it to the collection
|
81
|
+
#
|
82
|
+
# @abstract
|
83
|
+
#
|
84
|
+
# @raise NotImplementedError
|
85
|
+
#
|
86
|
+
# @return [undefined]
|
87
|
+
#
|
88
|
+
# @api private
|
89
|
+
def coerce_and_append_member(collection, entry)
|
90
|
+
raise NotImplementedError,
|
91
|
+
"#{self.class}#coerce_and_append_member has not been implemented"
|
92
|
+
end
|
93
|
+
|
94
|
+
end # class Array
|
95
|
+
end # class Attribute
|
96
|
+
end # module Virtus
|
@@ -3,8 +3,8 @@ module Virtus
|
|
3
3
|
|
4
4
|
# Class representing the default value option
|
5
5
|
class DefaultValue
|
6
|
-
|
7
|
-
|
6
|
+
SINGLETON_CLASSES = [ ::NilClass, ::TrueClass, ::FalseClass,
|
7
|
+
::Numeric, ::Symbol ].freeze
|
8
8
|
|
9
9
|
# Returns the attribute associated with this default value instance
|
10
10
|
#
|
@@ -42,8 +42,8 @@ module Virtus
|
|
42
42
|
def evaluate(instance)
|
43
43
|
if callable?
|
44
44
|
call(instance)
|
45
|
-
elsif
|
46
|
-
value.
|
45
|
+
elsif cloneable?
|
46
|
+
value.clone
|
47
47
|
else
|
48
48
|
value
|
49
49
|
end
|
@@ -71,13 +71,17 @@ module Virtus
|
|
71
71
|
value.respond_to?(:call)
|
72
72
|
end
|
73
73
|
|
74
|
-
# Returns whether or not the value is
|
74
|
+
# Returns whether or not the value is cloneable
|
75
75
|
#
|
76
76
|
# # return [TrueClass, FalseClass]
|
77
77
|
#
|
78
78
|
# @api private
|
79
|
-
def
|
80
|
-
|
79
|
+
def cloneable?
|
80
|
+
case value
|
81
|
+
when *SINGLETON_CLASSES then false
|
82
|
+
else
|
83
|
+
true
|
84
|
+
end
|
81
85
|
end
|
82
86
|
|
83
87
|
end # class DefaultValue
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Virtus
|
4
|
+
class Attribute
|
5
|
+
|
6
|
+
# EmbeddedValue
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# class Address
|
11
|
+
# include Virtus
|
12
|
+
#
|
13
|
+
# attribute :street, String
|
14
|
+
# attribute :zipcode, String
|
15
|
+
# attribute :city, String
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# class User
|
19
|
+
# include Virtus
|
20
|
+
#
|
21
|
+
# attribute :address, Address
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# user = User.new(:address => {
|
25
|
+
# :street => 'Street 1/2', :zipcode => '12345', :city => 'NYC' })
|
26
|
+
#
|
27
|
+
class EmbeddedValue < Object
|
28
|
+
|
29
|
+
# @see Attribute.merge_options
|
30
|
+
#
|
31
|
+
# @return [Hash]
|
32
|
+
# an updated options hash for configuring an EmbeddedValue instance
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
def self.merge_options(type, options)
|
36
|
+
options.merge(:model => type)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Sets @model ivar
|
40
|
+
#
|
41
|
+
# @see Virtus::Attribute#initialize
|
42
|
+
#
|
43
|
+
# @return [undefined]
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
def initialize(name, options = {})
|
47
|
+
super
|
48
|
+
@model = options.fetch(:model, OpenStruct)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Coerce attributes into a virtus object
|
52
|
+
#
|
53
|
+
# @param [Hash,Virtus]
|
54
|
+
#
|
55
|
+
# @return [Virtus]
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
def coerce(attributes_or_object)
|
59
|
+
value = if attributes_or_object.kind_of?(::Hash)
|
60
|
+
@model.new(attributes_or_object)
|
61
|
+
else
|
62
|
+
attributes_or_object
|
63
|
+
end
|
64
|
+
|
65
|
+
super(value)
|
66
|
+
end
|
67
|
+
|
68
|
+
end # class EmbeddedValue
|
69
|
+
end # class Attribute
|
70
|
+
end # module Virtus
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Virtus
|
2
|
+
class Attribute
|
3
|
+
|
4
|
+
# Set
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class Post
|
8
|
+
# include Virtus
|
9
|
+
#
|
10
|
+
# attribute :tags, Set
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# post = Post.new(:tags => %w(red green blue))
|
14
|
+
#
|
15
|
+
class Set < Collection
|
16
|
+
primitive ::Set
|
17
|
+
coercion_method :to_set
|
18
|
+
|
19
|
+
def coerce_and_append_member(collection, entry)
|
20
|
+
collection << @member_type_instance.coerce(entry)
|
21
|
+
end
|
22
|
+
|
23
|
+
end # class Set
|
24
|
+
end # class Attribute
|
25
|
+
end # module Virtus
|
data/lib/virtus/attribute_set.rb
CHANGED
@@ -24,9 +24,10 @@ module Virtus
|
|
24
24
|
#
|
25
25
|
# @api private
|
26
26
|
def initialize(parent = nil, attributes = [])
|
27
|
-
@parent
|
28
|
-
@attributes
|
29
|
-
@index
|
27
|
+
@parent = parent
|
28
|
+
@attributes = attributes.dup
|
29
|
+
@index = {}
|
30
|
+
@string_index = {}
|
30
31
|
reset
|
31
32
|
end
|
32
33
|
|
@@ -91,7 +92,7 @@ module Virtus
|
|
91
92
|
#
|
92
93
|
# @api public
|
93
94
|
def [](name)
|
94
|
-
@index[name]
|
95
|
+
@index.fetch(name) { @string_index[name] }
|
95
96
|
end
|
96
97
|
|
97
98
|
# Set an attribute by name
|
@@ -106,9 +107,8 @@ module Virtus
|
|
106
107
|
#
|
107
108
|
# @api public
|
108
109
|
def []=(name, attribute)
|
109
|
-
delete(name)
|
110
110
|
@attributes << attribute
|
111
|
-
|
111
|
+
update_index(name, attribute)
|
112
112
|
end
|
113
113
|
|
114
114
|
# Reset the index when the parent is updated
|
@@ -118,33 +118,35 @@ module Virtus
|
|
118
118
|
# @api private
|
119
119
|
def reset
|
120
120
|
parent = self.parent
|
121
|
-
|
122
|
-
|
121
|
+
merge_attributes(parent) if parent
|
122
|
+
merge_attributes(@attributes)
|
123
123
|
self
|
124
124
|
end
|
125
125
|
|
126
126
|
private
|
127
127
|
|
128
|
-
#
|
128
|
+
# Merge the attributes into the index
|
129
129
|
#
|
130
|
-
# @param [
|
130
|
+
# @param [Array<Attribute>] attributes
|
131
131
|
#
|
132
132
|
# @return [undefined]
|
133
133
|
#
|
134
134
|
# @api private
|
135
|
-
def
|
136
|
-
|
135
|
+
def merge_attributes(attributes)
|
136
|
+
attributes.each { |attribute| update_index(attribute.name, attribute) }
|
137
137
|
end
|
138
138
|
|
139
|
-
#
|
139
|
+
# Update the symbol and string indexes with the attribute
|
140
140
|
#
|
141
|
-
# @param [
|
141
|
+
# @param [Symbol] name
|
142
|
+
#
|
143
|
+
# @param [Attribute] attribute
|
142
144
|
#
|
143
145
|
# @return [undefined]
|
144
146
|
#
|
145
147
|
# @api private
|
146
|
-
def
|
147
|
-
|
148
|
+
def update_index(name, attribute)
|
149
|
+
@index[name] = @string_index[name.to_s.freeze] = attribute
|
148
150
|
end
|
149
151
|
|
150
152
|
end # class AttributeSet
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# Host attribute accessor methods
|
4
|
+
class AttributesAccessor < Module
|
5
|
+
|
6
|
+
# The inspect value of this Module
|
7
|
+
#
|
8
|
+
# This provides meaningful output when inspecting the ancestors
|
9
|
+
# of a class/module that includes this module
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# class ClassWithAttributes
|
14
|
+
# include Virtus
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# mod = ClassWithAttributes.send(:virtus_setup_attributes_accessor_module)
|
18
|
+
# mod.inspect
|
19
|
+
#
|
20
|
+
# @return [String]
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
attr_reader :inspect
|
24
|
+
|
25
|
+
# Initialize a module for hosting Attribute access methods
|
26
|
+
#
|
27
|
+
# @param [Symbol, String] name
|
28
|
+
#
|
29
|
+
# @api private
|
30
|
+
def initialize(name)
|
31
|
+
super()
|
32
|
+
@inspect = "#{name}::AttributesAccessor"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Defines an attribute reader method
|
36
|
+
#
|
37
|
+
# @param [Attribute] attribute
|
38
|
+
# @param [Symbol] method_name
|
39
|
+
# @param [Symbol] visibility
|
40
|
+
#
|
41
|
+
# @return [self]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
def define_reader_method(attribute, method_name, visibility)
|
45
|
+
define_method(method_name) { attribute.get(self) }
|
46
|
+
send(visibility, method_name)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Defines an attribute writer method
|
51
|
+
#
|
52
|
+
# @param [Attribute] attribute
|
53
|
+
# @param [Symbol] method_name
|
54
|
+
# @param [Symbol] visibility
|
55
|
+
#
|
56
|
+
# @return [self]
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
def define_writer_method(attribute, method_name, visibility)
|
60
|
+
define_method(method_name) { |value| attribute.set(self, value) }
|
61
|
+
send(visibility, method_name)
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|