attribute-filters 1.4.0 → 2.0.0
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.tar.gz.sig +0 -0
- data/.yardopts +1 -0
- data/ChangeLog +501 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +7 -7
- data/Manifest.txt +7 -0
- data/README.md +59 -30
- data/Rakefile +1 -0
- data/attribute-filters.gemspec +4 -4
- data/docs/COMMON-FILTERS.md +1067 -0
- data/docs/HISTORY +42 -0
- data/docs/TODO +29 -12
- data/docs/USAGE.md +718 -818
- data/lib/attribute-filters.rb +4 -2
- data/lib/attribute-filters/attribute_set.rb +144 -73
- data/lib/attribute-filters/attribute_set_annotations.rb +110 -77
- data/lib/attribute-filters/attribute_set_attrquery.rb +51 -8
- data/lib/attribute-filters/attribute_set_enum.rb +44 -38
- data/lib/attribute-filters/attribute_set_query.rb +62 -12
- data/lib/attribute-filters/backports.rb +36 -4
- data/lib/attribute-filters/common_filters.rb +83 -37
- data/lib/attribute-filters/common_filters/bare.rb +29 -0
- data/lib/attribute-filters/common_filters/case.rb +34 -19
- data/lib/attribute-filters/common_filters/convert.rb +259 -0
- data/lib/attribute-filters/common_filters/join.rb +37 -30
- data/lib/attribute-filters/common_filters/order.rb +105 -0
- data/lib/attribute-filters/common_filters/pick.rb +90 -0
- data/lib/attribute-filters/common_filters/presence.rb +70 -0
- data/lib/attribute-filters/common_filters/split.rb +37 -21
- data/lib/attribute-filters/common_filters/squeeze.rb +28 -9
- data/lib/attribute-filters/common_filters/strip.rb +7 -3
- data/lib/attribute-filters/dsl_attr_virtual.rb +2 -1
- data/lib/attribute-filters/dsl_filters.rb +14 -61
- data/lib/attribute-filters/dsl_sets.rb +238 -88
- data/lib/attribute-filters/helpers.rb +7 -1
- data/lib/attribute-filters/meta_set.rb +38 -0
- data/lib/attribute-filters/version.rb +1 -1
- data/spec/attribute-filters_spec.rb +178 -16
- data/spec/spec_helper.rb +9 -4
- metadata +129 -69
- metadata.gz.sig +0 -0
|
@@ -21,21 +21,25 @@ module ActiveModel
|
|
|
21
21
|
# +should_be_stripped+. It operates directly on attribute's contents.
|
|
22
22
|
#
|
|
23
23
|
# @note If a value of currently processed attribute is an array
|
|
24
|
-
# then any element of the array is changed.
|
|
24
|
+
# then any element of the array is changed. The same with hash (its values are changed).
|
|
25
25
|
#
|
|
26
26
|
# @return [void]
|
|
27
27
|
def strip_attributes
|
|
28
28
|
filter_attrs_from_set(:should_be_stripped) do |atr|
|
|
29
|
-
|
|
29
|
+
AFHelpers.each_element(atr, String) { |v| v.strip }
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
+
filtering_method :strip_attributes, :should_be_stripped
|
|
33
|
+
|
|
32
34
|
# This submodule contains class methods used to easily define filter.
|
|
33
35
|
module ClassMethods
|
|
34
36
|
# Registers attributes that should be stripped.
|
|
35
37
|
def strip_attributes(*args)
|
|
36
38
|
attributes_that(:should_be_stripped, args)
|
|
37
39
|
end
|
|
38
|
-
alias_method :strip_attribute,
|
|
40
|
+
alias_method :strip_attribute, :strip_attributes
|
|
41
|
+
alias_method :strips_attribute, :strip_attributes
|
|
42
|
+
alias_method :strips_attributes, :strip_attributes
|
|
39
43
|
end # module ClassMethods
|
|
40
44
|
end # module Strip
|
|
41
45
|
|
|
@@ -25,7 +25,7 @@ module ActiveModel
|
|
|
25
25
|
writer_name = "#{atr_name}="
|
|
26
26
|
atr_name = atr_name.to_sym
|
|
27
27
|
attr_reader(atr_name) unless method_defined?(atr_name)
|
|
28
|
-
|
|
28
|
+
treat_as_virtual(atr_name)
|
|
29
29
|
if method_defined?(writer_name)
|
|
30
30
|
self.class_eval <<-EVAL
|
|
31
31
|
alias_method :#{atr_name}_without_change_tracking=, :#{writer_name}
|
|
@@ -43,6 +43,7 @@ module ActiveModel
|
|
|
43
43
|
EVAL
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
|
+
nil
|
|
46
47
|
end # def attr_virtual
|
|
47
48
|
end # unless method_defined?(:attr_virtual)
|
|
48
49
|
end # module ClassMethods
|
|
@@ -17,6 +17,9 @@ module ActiveModel
|
|
|
17
17
|
:include_missing => false
|
|
18
18
|
}.freeze
|
|
19
19
|
|
|
20
|
+
# Helpers module shortcut.
|
|
21
|
+
AFHelpers = AttributeFiltersHelpers
|
|
22
|
+
|
|
20
23
|
# Gets names of attributes for which filters should be applied by
|
|
21
24
|
# selecting attributes that are meeting certain criteria and belong
|
|
22
25
|
# to the given attribute set.
|
|
@@ -24,28 +27,26 @@ module ActiveModel
|
|
|
24
27
|
# @overload attributes_to_filter(set_name, process_all, no_presence_check)
|
|
25
28
|
# @param set_name [String,Symbol] name of a set of attributes used to get attributes
|
|
26
29
|
# @param process_all [Boolean] if set then all the attributes from the attribute set are selected,
|
|
27
|
-
# not just attributes that have changed (defaults to +false+)
|
|
28
|
-
# @param no_presence_check [Boolean] if set then the checking whether attribute exists will be
|
|
30
|
+
# not just the attributes that have changed (defaults to +false+)
|
|
31
|
+
# @param no_presence_check [Boolean] if set then the checking whether each attribute exists will be
|
|
29
32
|
# disabled (matters only when +process_all+ is also set) (defaults to +false+)
|
|
30
33
|
# @return [AttributeSet] set of attributes (attribute name => previous_value)
|
|
31
34
|
#
|
|
32
35
|
# @overload attributes_to_filter(attribute_set, process_all, no_presence_check)
|
|
33
36
|
# @param attribute_set [AttributeSet] set of attributes used to get attributes
|
|
34
37
|
# @param process_all [Boolean] if set then all the attributes from the attribute set are selected,
|
|
35
|
-
# not just attributes that has changed (defaults to +false+)
|
|
36
|
-
# @param no_presence_check [Boolean] if set then the checking whether attribute exists will be
|
|
38
|
+
# not just the attributes that has changed (defaults to +false+)
|
|
39
|
+
# @param no_presence_check [Boolean] if set then the checking whether each attribute exists will be
|
|
37
40
|
# disabled (matters only when +process_all+ is also set) (defaults to +false+)
|
|
38
41
|
# @return [AttributeSet] set of attributes (attribute name => previous_value)
|
|
39
42
|
def attributes_to_filter(set_name, process_all = false, no_presence_check = false)
|
|
40
|
-
|
|
43
|
+
set_name.blank? and return ::ActiveModel::AttributeSet.new
|
|
44
|
+
atf = set_name.is_a?(::ActiveModel::AttributeSet) ? set_name : self.class.send(:__attribute_sets)[set_name.to_sym]
|
|
41
45
|
if process_all
|
|
42
|
-
no_presence_check ? atf : atf &
|
|
46
|
+
no_presence_check ? atf.deep_dup : atf & __all_attributes(false)
|
|
43
47
|
else
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
else
|
|
47
|
-
atf & (__vatrf(no_presence_check) + changes.keys)
|
|
48
|
-
end
|
|
48
|
+
sr = self.class.send(:__attribute_filters_semi_real)
|
|
49
|
+
atf & ((no_presence_check ? sr : sr.select_accessible(self)) + changes.keys)
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
52
|
|
|
@@ -141,7 +142,7 @@ module ActiveModel
|
|
|
141
142
|
# * +:no_presence_check+ – tells not to check for existence of each processed attribute when processing
|
|
142
143
|
# all attributes; increases performance but you must care about putting into set only the existing attributes
|
|
143
144
|
# * +:include_missing+ – includes attributes that does not exist in a resulting iteration (their values are
|
|
144
|
-
# always +nil+); has effect only when +process_blank+ and +no_presence_check+ are set
|
|
145
|
+
# always +nil+); has the effect only when +process_blank+ and +no_presence_check+ are set
|
|
145
146
|
# @yield [attribute_value, set_name, attribute_name, *args] block that will be called for each attribute
|
|
146
147
|
# @yieldparam attribute_value [Object] current attribute value that should be altered
|
|
147
148
|
# @yieldparam attribute_name [String] a name of currently processed attribute
|
|
@@ -174,60 +175,12 @@ module ActiveModel
|
|
|
174
175
|
alias_method :for_attributes_that_are, :for_each_attr_from_set
|
|
175
176
|
alias_method :for_attributes_which_are, :for_each_attr_from_set
|
|
176
177
|
|
|
177
|
-
module ClassMethods
|
|
178
|
-
# @overload treat_as_real(*attributes)
|
|
179
|
-
# Informs Attribute Filters that the given attributes
|
|
180
|
-
# should be treated as present, even they are not in
|
|
181
|
-
# attributes hash provided by ORM or ActiveModel.
|
|
182
|
-
# Useful when operating on virtual attributes.
|
|
183
|
-
#
|
|
184
|
-
# @param attributes [Array] list of attribute names
|
|
185
|
-
# @return [void]
|
|
186
|
-
#
|
|
187
|
-
# @overload treat_as_real()
|
|
188
|
-
# Gets the memorized attribute names that should be
|
|
189
|
-
# treated as existing.
|
|
190
|
-
#
|
|
191
|
-
# @return [AttributeSet] set of attribute name
|
|
192
|
-
def treat_as_real(*args)
|
|
193
|
-
return __treat_as_real.dup if args.blank?
|
|
194
|
-
__treat_as_real << args.flatten.compact.map { |atr| atr.to_s }
|
|
195
|
-
nil
|
|
196
|
-
end
|
|
197
|
-
alias_method :treat_attribute_as_real, :treat_as_real
|
|
198
|
-
alias_method :treat_attributes_as_real, :treat_as_real
|
|
199
|
-
|
|
200
|
-
# Sets the internal flag that causes to check virtual attributes
|
|
201
|
-
# for changes when selecting attributes for filtering.
|
|
202
|
-
# @return [void]
|
|
203
|
-
def filter_virtual_attributes_that_have_changed
|
|
204
|
-
@filter_virtual_attributes_that_changed = true
|
|
205
|
-
end
|
|
206
|
-
alias_method :filter_virtual_attributes_that_changed, :filter_virtual_attributes_that_have_changed
|
|
207
|
-
alias_method :filter_changed_virtual_attributes, :filter_virtual_attributes_that_have_changed
|
|
208
|
-
alias_method :virtual_attributes_are_tracked, :filter_virtual_attributes_that_have_changed
|
|
209
|
-
|
|
210
|
-
# Gets the internal flag that causes to check virtual attributes
|
|
211
|
-
# for changes when selecting attributes for filtering.
|
|
212
|
-
# @return [Boolean] +true+ if the virtual attributes should be checked for a change, +false+ otherwise
|
|
213
|
-
def filter_virtual_attributes_that_changed?
|
|
214
|
-
!!@filter_virtual_attributes_that_changed
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
private
|
|
218
|
-
|
|
219
|
-
def __treat_as_real
|
|
220
|
-
@__treat_as_real ||= ActiveModel::AttributeSet.new
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
end # module ClassMethods
|
|
224
|
-
|
|
225
178
|
private
|
|
226
179
|
|
|
227
180
|
# Applies operations to elements from set.
|
|
228
181
|
def operate_on_attrs_from_set(set_name, alter_mode, *args, &block)
|
|
229
182
|
block_given? or return enum_for(__method__, set_name, alter_mode, *args)
|
|
230
|
-
flags =
|
|
183
|
+
flags = AFHelpers.process_flags(args)
|
|
231
184
|
process_all = flags[:process_all]
|
|
232
185
|
process_blank = flags[:process_blank]
|
|
233
186
|
no_presence_check = flags[:no_presence_check]
|
|
@@ -29,6 +29,9 @@ module ActiveModel
|
|
|
29
29
|
# If the argument is a kind of {AttributeSet} then the local set
|
|
30
30
|
# is taken and wrapped in a {AttributeSet::AttrQuery} instance.
|
|
31
31
|
#
|
|
32
|
+
# If the argument is +nil+ then the local set is guessed by assuming
|
|
33
|
+
# that the next method in a call chain is really the name of a set.
|
|
34
|
+
#
|
|
32
35
|
# If the argument is other kind than the specified above then
|
|
33
36
|
# the method tries to initialize new, local set object and wraps
|
|
34
37
|
# it in a `AttributeSet::AttrQuery` instance.
|
|
@@ -40,23 +43,20 @@ module ActiveModel
|
|
|
40
43
|
#
|
|
41
44
|
# @param set_name [Symbol] name of attribute set, attribute object or any object that can initialize a set
|
|
42
45
|
# @return [AttributeSet] attribute set
|
|
43
|
-
def attribute_set(set_name=nil)
|
|
44
|
-
|
|
45
|
-
all_attributes
|
|
46
|
-
else
|
|
47
|
-
ActiveModel::AttributeSet::Query.new(set_name, self)
|
|
48
|
-
end
|
|
46
|
+
def attribute_set(set_name = nil)
|
|
47
|
+
ActiveModel::AttributeSet::Query.new(set_name, self)
|
|
49
48
|
end
|
|
50
49
|
alias_method :attributes_that_are, :attribute_set
|
|
51
50
|
alias_method :from_attributes_that, :attribute_set
|
|
51
|
+
alias_method :are_attributes_that, :attribute_set
|
|
52
52
|
alias_method :are_attributes_that_are, :attribute_set
|
|
53
|
+
alias_method :are_attributes, :attribute_set
|
|
54
|
+
alias_method :are_attributes_for, :attribute_set
|
|
53
55
|
alias_method :from_attributes_that_are, :attribute_set
|
|
54
|
-
alias_method :
|
|
56
|
+
alias_method :in_attributes_that_are, :attribute_set
|
|
55
57
|
alias_method :attributes_that, :attribute_set
|
|
56
58
|
alias_method :attributes_are, :attribute_set
|
|
57
59
|
alias_method :attributes_for, :attribute_set
|
|
58
|
-
alias_method :are_attributes, :attribute_set
|
|
59
|
-
alias_method :are_attributes_for, :attribute_set
|
|
60
60
|
alias_method :attributes_set, :attribute_set
|
|
61
61
|
alias_method :properties_that, :attribute_set
|
|
62
62
|
|
|
@@ -71,25 +71,21 @@ module ActiveModel
|
|
|
71
71
|
# @param set_name [Symbol] name of attribute set
|
|
72
72
|
# @return [AttributeSet] attribute set
|
|
73
73
|
def attribute_set_simple(set_name)
|
|
74
|
-
self.class.attribute_set(set_name)
|
|
74
|
+
self.class.attribute_set(set_name)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
# Returns a set containing all known attributes
|
|
78
|
-
# without wrapping
|
|
79
|
-
#
|
|
80
|
-
# @return [AttributeSet] attribute set
|
|
81
|
-
def all_attributes_simple(no_presence_check = true)
|
|
82
|
-
(ActiveModel::AttributeSet.new(attributes.keys) +
|
|
83
|
-
all_accessible_attributes(true) +
|
|
84
|
-
all_protected_attributes(true) +
|
|
85
|
-
__vatrf(no_presence_check)).delete("")
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Returns a set containing all known attributes.
|
|
78
|
+
# without wrapping the result in a proxy.
|
|
89
79
|
#
|
|
80
|
+
# @param simple [Boolean] optional parameter that disables
|
|
81
|
+
# wrapping a resulting set in a proxy (defaults to +false+)
|
|
82
|
+
# @param no_presence_check [Boolean] optional parameter that
|
|
83
|
+
# disables checking for presence of setters and getters for each
|
|
84
|
+
# virtual and semi-real attribute (defaults to +true+)
|
|
90
85
|
# @return [AttributeSet] attribute set
|
|
91
|
-
def all_attributes
|
|
92
|
-
|
|
86
|
+
def all_attributes(simple = false, no_presence_check = true)
|
|
87
|
+
r = __all_attributes(no_presence_check).deep_dup
|
|
88
|
+
simple ? r : ActiveModel::AttributeSet::Query.new(r, self)
|
|
93
89
|
end
|
|
94
90
|
alias_method :all_attributes_set, :all_attributes
|
|
95
91
|
|
|
@@ -99,8 +95,9 @@ module ActiveModel
|
|
|
99
95
|
# wrapping a resulting set in a proxy (defaults to +false+)
|
|
100
96
|
# @return [AttributeSet] attribute set
|
|
101
97
|
def all_accessible_attributes(simple = false)
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
my_class = self.class
|
|
99
|
+
c = my_class.respond_to?(:accessible_attributes) ? my_class.accessible_attributes : []
|
|
100
|
+
simple ? AttributeSet.new(c) : AttributeSet::Query.new(c, self)
|
|
104
101
|
end
|
|
105
102
|
alias_method :accessible_attributes_set, :all_accessible_attributes
|
|
106
103
|
|
|
@@ -110,15 +107,50 @@ module ActiveModel
|
|
|
110
107
|
# wrapping a resulting set in a proxy (defaults to +false+)
|
|
111
108
|
# @return [AttributeSet] attribute set
|
|
112
109
|
def all_protected_attributes(simple = false)
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
my_class = self.class
|
|
111
|
+
c = my_class.respond_to?(:protected_attributes) ? my_class.protected_attributes : []
|
|
112
|
+
simple ? AttributeSet.new(c) : AttributeSet::Query.new(c, self)
|
|
115
113
|
end
|
|
116
114
|
alias_method :protected_attributes_set, :all_protected_attributes
|
|
117
115
|
|
|
116
|
+
# Returns a set containing attributes declared as virtual with +attr_virtual+.
|
|
117
|
+
#
|
|
118
|
+
# @param simple [Boolean] optional parameter that disables
|
|
119
|
+
# wrapping a resulting set in a proxy (defaults to +false+)
|
|
120
|
+
# @return [AttributeSet] attribute set
|
|
121
|
+
def all_virtual_attributes(simple = false)
|
|
122
|
+
c = self.class.attribute_filters_virtual
|
|
123
|
+
simple ? c : AttributeSet::Query.new(c, self)
|
|
124
|
+
end
|
|
125
|
+
alias_method :virtual_attributes_set, :all_virtual_attributes
|
|
126
|
+
alias_method :attribute_filters_virtual, :all_virtual_attributes
|
|
127
|
+
|
|
128
|
+
# Returns a set containing attributes declared as semi-real.
|
|
129
|
+
#
|
|
130
|
+
# @param simple [Boolean] optional parameter that disables
|
|
131
|
+
# wrapping a resulting set in a proxy (defaults to +false+)
|
|
132
|
+
# @param no_presence_check [Boolean] optional parameter that
|
|
133
|
+
# disables checking for presence of setters and getters for each
|
|
134
|
+
# attribute (defaults to +true+)
|
|
135
|
+
# @return [AttributeSet] attribute set
|
|
136
|
+
def all_semi_real_attributes(simple = false, no_presence_check = true)
|
|
137
|
+
c = self.class.treat_as_real
|
|
138
|
+
c = c.select_accessible(self) unless no_presence_check || c.empty?
|
|
139
|
+
simple ? c : AttributeSet::Query.new(c, self)
|
|
140
|
+
end
|
|
141
|
+
alias_method :semi_real_attributes_set, :all_semi_real_attributes
|
|
142
|
+
alias_method :treat_as_real, :all_semi_real_attributes
|
|
143
|
+
|
|
118
144
|
# Returns a set containing all attributes that are not accessible attributes.
|
|
145
|
+
#
|
|
146
|
+
# @param simple [Boolean] optional parameter that disables
|
|
147
|
+
# wrapping a resulting set in a proxy (defaults to +false+)
|
|
148
|
+
# @param no_presence_check [Boolean] optional parameter that
|
|
149
|
+
# disables checking for presence of setters and getters for each
|
|
150
|
+
# virtual and semi-real attribute (defaults to +true+)
|
|
119
151
|
# @return [AttributeSet] attribute set
|
|
120
|
-
def all_inaccessible_attributes
|
|
121
|
-
all_attributes - all_accessible_attributes(
|
|
152
|
+
def all_inaccessible_attributes(simple = false, no_presence_check = true)
|
|
153
|
+
all_attributes(simple, no_presence_check) - all_accessible_attributes(simple)
|
|
122
154
|
end
|
|
123
155
|
alias_method :all_non_accessible_attributes, :all_inaccessible_attributes
|
|
124
156
|
alias_method :inaccessible_attributes_set, :all_inaccessible_attributes
|
|
@@ -129,21 +161,31 @@ module ActiveModel
|
|
|
129
161
|
# will always return {AttributeSet} object. If there is no such set defined then the returned,
|
|
130
162
|
# matching set will be empty.
|
|
131
163
|
#
|
|
132
|
-
# @return [
|
|
164
|
+
# @return [MetaSet{Symbol => AttributeSet<String>}] the collection of attribute sets indexed by their names
|
|
133
165
|
def attribute_sets
|
|
134
166
|
s = self.class.attribute_sets
|
|
135
|
-
s.
|
|
136
|
-
ActiveModel::AttributeSet::Query.new(set_object, self)
|
|
167
|
+
s.each_pair do |set_name, set_object|
|
|
168
|
+
s[set_name] = ActiveModel::AttributeSet::Query.new(set_object, self)
|
|
137
169
|
end
|
|
138
|
-
s.default = ActiveModel::AttributeSet::Query.new(ActiveModel::AttributeSet.new.freeze, self)
|
|
139
170
|
s
|
|
140
171
|
end
|
|
141
172
|
alias_method :attributes_sets, :attribute_sets
|
|
142
173
|
alias_method :properties_sets, :attribute_sets
|
|
143
174
|
|
|
175
|
+
# Checks if the given set exists.
|
|
176
|
+
#
|
|
177
|
+
# @param [String, Symbol] set_name name of a set
|
|
178
|
+
# @return [Boolean] +true+ if a set of the given name exists, +false+ otherwise
|
|
179
|
+
def attribute_set_exists?(set_name)
|
|
180
|
+
set_name.present? && self.class.send(:__attribute_sets).key?(set_name.to_sym)
|
|
181
|
+
end
|
|
182
|
+
|
|
144
183
|
# Returns the set of set names that the attribute of the given
|
|
145
184
|
# name belongs to.
|
|
146
185
|
#
|
|
186
|
+
# If the given attribute name is +nil+ then it is taken from
|
|
187
|
+
# the name of a next method in a method call chain.
|
|
188
|
+
#
|
|
147
189
|
# @note The returned value is a duplicate. Adding or removing
|
|
148
190
|
# elements to it will have no effect. Altering attribute sets
|
|
149
191
|
# is possible on a class-level only, since attribute sets
|
|
@@ -151,26 +193,64 @@ module ActiveModel
|
|
|
151
193
|
#
|
|
152
194
|
# @param attribute_name [Symbol] name of attribute set
|
|
153
195
|
# @return [AttributeSet] attribute set
|
|
154
|
-
def filtered_attribute(attribute_name)
|
|
155
|
-
ActiveModel::AttributeSet::AttrQuery.new(
|
|
196
|
+
def filtered_attribute(attribute_name = nil)
|
|
197
|
+
ActiveModel::AttributeSet::AttrQuery.new(attribute_name, self)
|
|
156
198
|
end
|
|
157
199
|
alias_method :the_attribute, :filtered_attribute
|
|
158
200
|
alias_method :is_the_attribute, :filtered_attribute
|
|
201
|
+
alias_method :has_the_attribute, :filtered_attribute
|
|
159
202
|
alias_method :are_attributes, :filtered_attribute
|
|
160
203
|
alias_method :are_the_attributes, :filtered_attribute
|
|
161
204
|
|
|
205
|
+
# Returns the set of set names that the attribute of the given
|
|
206
|
+
# name belongs to.
|
|
207
|
+
#
|
|
208
|
+
# @note The returned value is a duplicate. Adding or removing
|
|
209
|
+
# elements to it will have no effect. Altering attribute sets
|
|
210
|
+
# is possible on a class-level only, since attribute sets
|
|
211
|
+
# are part of models' interfaces.
|
|
212
|
+
#
|
|
213
|
+
# @param attribute_name [Symbol] name of attribute set
|
|
214
|
+
# @return [AttributeSet] attribute set
|
|
215
|
+
def filtered_attribute_simple(attribute_name)
|
|
216
|
+
self.class.filter_attribute(attribute_name)
|
|
217
|
+
end
|
|
218
|
+
alias_method :the_attribute_simple, :filtered_attribute_simple
|
|
219
|
+
|
|
162
220
|
# Gets all the defined attribute set names hashed by attribute names.
|
|
163
221
|
#
|
|
164
222
|
# @note Use +key+ method explicitly to check if the given attribute is assigned to any set. The hash
|
|
165
223
|
# returned by this method will always return {AttributeSet} object. If the attribute is not assigned
|
|
166
224
|
# to any set then the returned, matching set will be empty.
|
|
167
225
|
#
|
|
168
|
-
# @return [
|
|
226
|
+
# @return [MetaSet{String => AttributeSet<Symbol>}] the collection of attribute set names indexed by attribute names
|
|
169
227
|
def attributes_to_sets
|
|
170
228
|
self.class.attributes_to_sets
|
|
171
229
|
end
|
|
172
230
|
alias_method :attribute_sets_map, :attributes_to_sets
|
|
173
231
|
|
|
232
|
+
# Returns a set containing all known attributes
|
|
233
|
+
# without wrapping the result in a proxy.
|
|
234
|
+
#
|
|
235
|
+
# @param no_presence_check [Boolean] optional parameter that
|
|
236
|
+
# disables checking for presence of setters and getters for each
|
|
237
|
+
# virtual and semi-real attribute (defaults to +true+)
|
|
238
|
+
# @return [AttributeSet] attribute set
|
|
239
|
+
def __all_attributes(no_presence_check = true)
|
|
240
|
+
my_class = self.class
|
|
241
|
+
c = my_class.send(:__attribute_filters_semi_real)
|
|
242
|
+
c = c.select_accessible(self) unless no_presence_check || c.empty?
|
|
243
|
+
r = ActiveModel::AttributeSet.new(c)
|
|
244
|
+
r.merge!(my_class.send(:__attribute_filters_virtual))
|
|
245
|
+
r << attributes.keys
|
|
246
|
+
if respond_to?(:accessible_attributes)
|
|
247
|
+
r << accessible_attributes
|
|
248
|
+
r << protected_attributes
|
|
249
|
+
end
|
|
250
|
+
r
|
|
251
|
+
end
|
|
252
|
+
private :__all_attributes
|
|
253
|
+
|
|
174
254
|
# This module contains class methods
|
|
175
255
|
# that create DSL for managing attribute sets.
|
|
176
256
|
module ClassMethods
|
|
@@ -207,31 +287,38 @@ module ActiveModel
|
|
|
207
287
|
attribute_sets
|
|
208
288
|
when 1
|
|
209
289
|
first_arg = args.first
|
|
210
|
-
if first_arg.is_a?(Hash)
|
|
290
|
+
if first_arg.is_a?(Hash) # [write] multiple sets defined
|
|
211
291
|
first_arg.each_pair { |k, v| attribute_set(k, v) }
|
|
212
292
|
nil
|
|
213
|
-
else
|
|
214
|
-
|
|
293
|
+
else # [read] single set to read
|
|
294
|
+
r = __attribute_sets[first_arg.to_sym]
|
|
295
|
+
r.frozen? ? r : r.deep_dup
|
|
215
296
|
end
|
|
216
297
|
else
|
|
217
298
|
first_arg = args.shift
|
|
218
|
-
if first_arg.is_a?(Hash)
|
|
299
|
+
if first_arg.is_a?(Hash) # [write] multiple sets defined
|
|
219
300
|
first_arg.each_pair do |k, v|
|
|
220
301
|
attribute_set(k, v, args)
|
|
221
302
|
end
|
|
222
|
-
else
|
|
223
|
-
|
|
303
|
+
else # [write core] sinle set and optional attrs given
|
|
304
|
+
AFHelpers.check_wanted_methods(self)
|
|
224
305
|
add_atrs_to_set(first_arg.to_sym, *args)
|
|
225
306
|
end
|
|
226
307
|
nil
|
|
227
308
|
end
|
|
228
309
|
end
|
|
229
|
-
alias_method :
|
|
230
|
-
alias_method :
|
|
231
|
-
alias_method :
|
|
232
|
-
alias_method :
|
|
233
|
-
alias_method :
|
|
234
|
-
alias_method :
|
|
310
|
+
alias_method :attributes_set, :attribute_set
|
|
311
|
+
alias_method :attributes_that_are, :attribute_set
|
|
312
|
+
alias_method :attributes_that, :attribute_set
|
|
313
|
+
alias_method :properties_that, :attribute_set
|
|
314
|
+
alias_method :has_attribute_set, :attribute_set
|
|
315
|
+
alias_method :has_attribute_that, :attribute_set
|
|
316
|
+
alias_method :has_attribute_that_is, :attribute_set
|
|
317
|
+
alias_method :has_attributes, :attribute_set
|
|
318
|
+
alias_method :has_attributes_set, :attribute_set
|
|
319
|
+
alias_method :has_attributes_that_are, :attribute_set
|
|
320
|
+
alias_method :has_attributes_that, :attribute_set
|
|
321
|
+
alias_method :has_properties_that, :attribute_set
|
|
235
322
|
|
|
236
323
|
# @overload filter_attribute()
|
|
237
324
|
# Gets all the defined attribute sets.
|
|
@@ -262,7 +349,7 @@ module ActiveModel
|
|
|
262
349
|
# @param set_names [Array<Symbol,String>] names of additional sets to assign attributes to
|
|
263
350
|
# @return [nil]
|
|
264
351
|
def filter_attribute(*args)
|
|
265
|
-
|
|
352
|
+
AFHelpers.check_wanted_methods(self)
|
|
266
353
|
case args.size
|
|
267
354
|
when 0
|
|
268
355
|
attributes_to_sets
|
|
@@ -272,7 +359,8 @@ module ActiveModel
|
|
|
272
359
|
first_arg.each_pair { |k, v| filter_attribute(k, v) }
|
|
273
360
|
nil
|
|
274
361
|
else
|
|
275
|
-
|
|
362
|
+
r = __attributes_to_sets_map[first_arg.to_s]
|
|
363
|
+
r.frozen? ? r : r.deep_dup
|
|
276
364
|
end
|
|
277
365
|
else
|
|
278
366
|
first_arg = args.shift
|
|
@@ -295,12 +383,17 @@ module ActiveModel
|
|
|
295
383
|
nil
|
|
296
384
|
end
|
|
297
385
|
end
|
|
298
|
-
alias_method :the_attribute,
|
|
299
|
-
alias_method :
|
|
300
|
-
alias_method :
|
|
301
|
-
alias_method :
|
|
302
|
-
alias_method :
|
|
303
|
-
alias_method :
|
|
386
|
+
alias_method :the_attribute, :filter_attribute
|
|
387
|
+
alias_method :attribute_to_set, :filter_attribute
|
|
388
|
+
alias_method :filtered_attribute, :filter_attribute
|
|
389
|
+
alias_method :filtered_attributes, :filter_attribute
|
|
390
|
+
alias_method :filters_attribute, :filter_attribute
|
|
391
|
+
alias_method :filters_attributes, :filter_attribute
|
|
392
|
+
alias_method :its_attribute, :filter_attribute
|
|
393
|
+
alias_method :has_attribute, :filter_attribute
|
|
394
|
+
alias_method :has_the_attribute, :filter_attribute
|
|
395
|
+
alias_method :has_filtered_attribute, :filter_attribute
|
|
396
|
+
alias_method :has_filtered_attributes, :filter_attribute
|
|
304
397
|
|
|
305
398
|
# Gets all the defined attribute sets.
|
|
306
399
|
#
|
|
@@ -308,13 +401,9 @@ module ActiveModel
|
|
|
308
401
|
# will always return {AttributeSet} object. If there is no such set defined then the returned,
|
|
309
402
|
# matching set will be empty. All set objects are duplicates of the defined sets.
|
|
310
403
|
#
|
|
311
|
-
# @return [
|
|
404
|
+
# @return [MetaSet{Symbol => AttributeSet<String>}] the collection of attribute sets indexed by their names
|
|
312
405
|
def attribute_sets
|
|
313
|
-
|
|
314
|
-
__attribute_sets.each_pair do |set_name, set_object|
|
|
315
|
-
d[set_name] = set_object.dup
|
|
316
|
-
end
|
|
317
|
-
d
|
|
406
|
+
__attribute_sets.deep_dup
|
|
318
407
|
end
|
|
319
408
|
alias_method :attributes_sets, :attribute_sets
|
|
320
409
|
alias_method :properties_sets, :attribute_sets
|
|
@@ -323,26 +412,87 @@ module ActiveModel
|
|
|
323
412
|
#
|
|
324
413
|
# @note Use +key+ method explicitly to check if the given attribute is assigned to any set. The hash
|
|
325
414
|
# returned by this method will always return {AttributeSet} object. If the attribute is not assigned
|
|
326
|
-
# to any set then the returned, matching set will be empty.
|
|
415
|
+
# to any set then the returned, matching set will be empty. This method returns a duplicate of each
|
|
416
|
+
# reverse mapped set.
|
|
327
417
|
#
|
|
328
|
-
# @return [
|
|
418
|
+
# @return [MetaSet{String => AttributeSet<Symbol>}] the collection of attribute set names indexed by attribute names
|
|
329
419
|
def attributes_to_sets
|
|
330
|
-
|
|
331
|
-
__attributes_to_sets_map.each_pair do |set_name, set_object|
|
|
332
|
-
d[set_name] = set_object.dup
|
|
333
|
-
end
|
|
334
|
-
d
|
|
420
|
+
__attributes_to_sets_map.deep_dup
|
|
335
421
|
end
|
|
336
422
|
alias_method :attribute_sets_map, :attributes_to_sets
|
|
337
423
|
|
|
424
|
+
# @overload treat_as_real(*attributes)
|
|
425
|
+
# Informs Attribute Filters that the given attributes
|
|
426
|
+
# should be treated as present, even they are not in
|
|
427
|
+
# attributes hash provided by ORM or ActiveModel.
|
|
428
|
+
# Useful when operating on semi-virtual attributes.
|
|
429
|
+
#
|
|
430
|
+
# @note To operate on virtual attributes use +attr_virtual+ instead.
|
|
431
|
+
#
|
|
432
|
+
# @param attributes [Array] list of attribute names
|
|
433
|
+
# @return [void]
|
|
434
|
+
#
|
|
435
|
+
# @overload treat_as_real()
|
|
436
|
+
# Gets the memorized attribute names that should be
|
|
437
|
+
# treated as existing.
|
|
438
|
+
#
|
|
439
|
+
# @return [AttributeSet] set of attribute names
|
|
440
|
+
def treat_as_real(*args)
|
|
441
|
+
return __attribute_filters_semi_real.deep_dup if args.blank?
|
|
442
|
+
__attribute_filters_semi_real << args.flatten.compact.map { |atr| atr.to_s }
|
|
443
|
+
nil
|
|
444
|
+
end
|
|
445
|
+
alias_method :attribute_filters_semi_real, :treat_as_real
|
|
446
|
+
alias_method :treat_attribute_as_real, :treat_as_real
|
|
447
|
+
alias_method :treat_attributes_as_real, :treat_as_real
|
|
448
|
+
alias_method :treats_attribute_as_real, :treat_as_real
|
|
449
|
+
alias_method :treats_attributes_as_real, :treat_as_real
|
|
450
|
+
alias_method :treats_as_real, :treat_as_real
|
|
451
|
+
|
|
452
|
+
# @overload attribute_filters_virtual(*attributes)
|
|
453
|
+
# Informs Attribute Filters that the given attributes
|
|
454
|
+
# should be treated as virtual (even not present in the
|
|
455
|
+
# attributes hash provided by ORM or ActiveModel).
|
|
456
|
+
#
|
|
457
|
+
# @note This method may be used directly if your setter
|
|
458
|
+
# notifies Rails about changes. Otherwise it's recommended
|
|
459
|
+
# to use the DSL keyword +attr_virtual+.
|
|
460
|
+
# @param attributes [Array] list of attribute names
|
|
461
|
+
# @return [void]
|
|
462
|
+
#
|
|
463
|
+
# @overload attribute_filters_virtual()
|
|
464
|
+
# Gets the memorized attribute names that should be
|
|
465
|
+
# treated as virtual.
|
|
466
|
+
#
|
|
467
|
+
# @return [AttributeSet] set of attribute names
|
|
468
|
+
def treat_as_virtual(*args)
|
|
469
|
+
return __attribute_filters_virtual.deep_dup if args.blank?
|
|
470
|
+
__attribute_filters_virtual << args.flatten.compact.map { |atr| atr.to_s }
|
|
471
|
+
nil
|
|
472
|
+
end
|
|
473
|
+
alias_method :attribute_filters_virtual, :treat_as_virtual
|
|
474
|
+
alias_method :treat_attribute_as_virtual, :treat_as_virtual
|
|
475
|
+
alias_method :treat_attributes_as_virtual, :treat_as_virtual
|
|
476
|
+
alias_method :treats_attribute_as_virtual, :treat_as_virtual
|
|
477
|
+
alias_method :treats_attributes_as_virtual, :treat_as_virtual
|
|
478
|
+
alias_method :treats_as_virtual, :treat_as_virtual
|
|
479
|
+
|
|
338
480
|
private
|
|
339
481
|
|
|
482
|
+
def __attribute_filters_semi_real
|
|
483
|
+
@__attribute_filters_semi_real ||= ActiveModel::AttributeSet.new
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
def __attribute_filters_virtual
|
|
487
|
+
@__attribute_filters_virtual ||= ActiveModel::AttributeSet.new
|
|
488
|
+
end
|
|
489
|
+
|
|
340
490
|
def __attributes_to_sets_map
|
|
341
|
-
@__attributes_to_sets_map ||=
|
|
491
|
+
@__attributes_to_sets_map ||= MetaSet.new(ActiveModel::MetaSet.new.freeze)
|
|
342
492
|
end
|
|
343
493
|
|
|
344
494
|
def __attribute_sets
|
|
345
|
-
@__attribute_sets ||=
|
|
495
|
+
@__attribute_sets ||= MetaSet.new(ActiveModel::AttributeSet.new.freeze)
|
|
346
496
|
end
|
|
347
497
|
|
|
348
498
|
def add_atrs_to_set(set_name, *atrs)
|
|
@@ -351,29 +501,29 @@ module ActiveModel
|
|
|
351
501
|
if atr_name.is_a?(Hash) # annotation
|
|
352
502
|
atr_name.each_pair do |atr_name_b, a_defs|
|
|
353
503
|
add_atrs_to_set(set_name, atr_name_b)
|
|
354
|
-
|
|
504
|
+
if __attribute_sets.key?(set_name) && a_defs.is_a?(Hash)
|
|
505
|
+
a_defs.each_pair do |n, v|
|
|
506
|
+
__attribute_sets[set_name].annotate(atr_name_b, n, v)
|
|
507
|
+
end
|
|
508
|
+
end
|
|
355
509
|
end
|
|
356
|
-
return
|
|
510
|
+
return nil
|
|
357
511
|
else
|
|
358
512
|
atr_name = atr_name.to_s
|
|
359
|
-
__attributes_to_sets_map
|
|
360
|
-
|
|
513
|
+
unless __attributes_to_sets_map.key?(atr_name)
|
|
514
|
+
__attributes_to_sets_map[atr_name] = ActiveModel::MetaSet.new
|
|
515
|
+
end
|
|
516
|
+
__attributes_to_sets_map[atr_name] << set_name
|
|
361
517
|
end
|
|
362
518
|
end
|
|
363
|
-
|
|
364
|
-
__attribute_sets
|
|
519
|
+
sanitized_atrs = atrs.map{ |a| a.to_s.dup }
|
|
520
|
+
unless __attribute_sets.key?(set_name)
|
|
521
|
+
__attribute_sets[set_name] = ActiveModel::AttributeSet.new(sanitized_atrs)
|
|
522
|
+
else
|
|
523
|
+
__attribute_sets[set_name] << sanitized_atrs
|
|
524
|
+
end
|
|
525
|
+
nil
|
|
365
526
|
end
|
|
366
527
|
end # module ClassMethods
|
|
367
|
-
|
|
368
|
-
private
|
|
369
|
-
|
|
370
|
-
# Helper that collects untracked virtual attributes that
|
|
371
|
-
# have setters and getters.
|
|
372
|
-
def __vatrf(no_presence_check = false)
|
|
373
|
-
tar = self.class.send(:__treat_as_real)
|
|
374
|
-
return tar if no_presence_check || tar.empty?
|
|
375
|
-
tar.select { |a| respond_to?(a) && respond_to?("#{a}=") }
|
|
376
|
-
end
|
|
377
|
-
|
|
378
528
|
end # module AttributeMethods
|
|
379
529
|
end # module ActiveModel
|