attribute-filters 1.4.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|