attribute-filters 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/ChangeLog CHANGED
@@ -1,3 +1,33 @@
1
+ commit c523068642e1461a11b96816d1c0b8adf20dcdc1
2
+ Author: Paweł Wilk <siefca@gnu.org>
3
+ Date: Wed Nov 21 18:58:32 2012 +0100
4
+
5
+ Release 2.0.2
6
+
7
+ commit ca7d41f8d7fd964bb04715b8cfe1276e641faa30
8
+ Author: Paweł Wilk <siefca@gnu.org>
9
+ Date: Sat Nov 10 03:40:43 2012 +0100
10
+
11
+ Documentation updated
12
+
13
+ commit defb9c5e80809b9098e781d44e9764b8a685bfd0
14
+ Author: Paweł Wilk <siefca@gnu.org>
15
+ Date: Mon Nov 5 00:07:17 2012 +0100
16
+
17
+ README updated
18
+
19
+ commit 3bbf561be52ecc64998230e63601f8dac87d9d5f
20
+ Author: Paweł Wilk <siefca@gnu.org>
21
+ Date: Sun Nov 4 23:57:44 2012 +0100
22
+
23
+ README updated
24
+
25
+ commit ae25d0fefbe299216b82a4c3df431584cdc1610f
26
+ Author: Paweł Wilk <siefca@gnu.org>
27
+ Date: Sun Nov 4 17:04:14 2012 +0100
28
+
29
+ README updated
30
+
1
31
  commit 364a5df0dfe8bed367351c55b7b64c174b2a3d91
2
32
  Author: Paweł Wilk <siefca@gnu.org>
3
33
  Date: Sun Nov 4 16:44:10 2012 +0100
@@ -48,22 +48,22 @@ GEM
48
48
  rake (>= 0.8.7)
49
49
  rdoc (~> 3.4)
50
50
  thor (~> 0.14.4)
51
- rake (0.9.2.2)
51
+ rake (0.9.5)
52
52
  rdoc (3.12)
53
53
  json (~> 1.4)
54
54
  redcarpet (2.2.2)
55
- rspec (2.11.0)
56
- rspec-core (~> 2.11.0)
57
- rspec-expectations (~> 2.11.0)
58
- rspec-mocks (~> 2.11.0)
59
- rspec-core (2.11.1)
60
- rspec-expectations (2.11.3)
55
+ rspec (2.12.0)
56
+ rspec-core (~> 2.12.0)
57
+ rspec-expectations (~> 2.12.0)
58
+ rspec-mocks (~> 2.12.0)
59
+ rspec-core (2.12.0)
60
+ rspec-expectations (2.12.0)
61
61
  diff-lcs (~> 1.1.3)
62
- rspec-mocks (2.11.3)
62
+ rspec-mocks (2.12.0)
63
63
  supermodel (0.1.6)
64
64
  activemodel (~> 3.0.0)
65
65
  thor (0.14.6)
66
- tzinfo (0.3.34)
66
+ tzinfo (0.3.35)
67
67
  yard (0.8.3)
68
68
 
69
69
  PLATFORMS
data/README.md CHANGED
@@ -140,7 +140,7 @@ Attributes that should be altered may be simply added
140
140
  to the attribute sets that you define and then filtered
141
141
  with generic methods that operate on that sets. You can share
142
142
  these methods across all of your models by putting them into your own
143
- handy module that will be included in models that needs it.
143
+ handy module that will be included in models that need it.
144
144
 
145
145
  Alternatively (as presented at the beginning) you can use predefined filtering methods from `ActiveModel::AttributeFilters::Common` module and its submodules. They contain filters
146
146
  for changing the case, stripping, squishng, squeezing, joining, splitting
@@ -161,13 +161,17 @@ Tracking changes and filtering virtual attributes is also easy:
161
161
 
162
162
  ```ruby
163
163
  class User < ActiveRecord::Base
164
- include ActiveModel::AttributeFilters::Split
164
+ include ActiveModel::AttributeFilters::Common::Split
165
165
 
166
166
  split_attribute :real_name => [ :first_name, :last_name ]
167
167
  before_validation :filter_attributes
168
168
 
169
169
  attr_virtual :real_name
170
- attr_accessor :real_name
170
+ attr_writer :real_name
171
+
172
+ def real_name
173
+ @real_name ||= "#{first_name} #{last_name}"
174
+ end
171
175
  end
172
176
  ```
173
177
 
@@ -185,9 +189,9 @@ use it to express some logic
185
189
  ### Sneak peeks ###
186
190
 
187
191
  ```ruby
188
- @user.is_the_attribute.username.required_to_use_application?
192
+ @user.is_the_attribute.username.required_to_make_deals?
189
193
  # => true
190
-
194
+
191
195
  @user.the_attribute(:username).should_be_stripped?
192
196
  # => true
193
197
 
@@ -196,18 +200,21 @@ use it to express some logic
196
200
 
197
201
  @user.is_the_attribute.username.protected?
198
202
  # => false
199
-
203
+
200
204
  @user.has_the_attribute.username.changed?
201
205
  # => false
202
-
206
+
203
207
  @user.is_the_attribute.username.valid?
204
208
  # => true
205
209
 
206
210
  @user.are_attributes_that.should_be_stripped.all.present?
207
211
  # => false
208
212
 
213
+ @user.from_attributes_that.should_be_stripped.list.blank?
214
+ # => #<ActiveModel::AttributeSet: {"unconfirmed_email"}>
215
+
209
216
  @user.the_attribute(:username).list.sets
210
- # => #<ActiveModel::AttributeSet: {:should_be_downcased, :should_be_stripped}>
217
+ # => {:should_be_downcased=>true, :should_be_stripped=>true}
211
218
 
212
219
  @user.attributes_that.should_be_stripped.list.present?
213
220
  # => #<ActiveModel::AttributeSet: {"username", "email"}>
@@ -227,21 +234,20 @@ How it works?
227
234
 
228
235
  It creates a new Active Model submodule called `AttributeFilters`. That module
229
236
  contains the needed DSL that goes into your models. It also creates `ActiveModel::AttributeSet`
230
- class which is just a new kind of set, a structure for storing attribute names.
237
+ and `ActiveModel::MetaSet` classes which are just new kinds of hash used for storing attribute names
238
+ and attribute set names.
231
239
 
232
240
  Then it forces Rails to include the `ActiveModel::AttributeFilters` in any model that
233
- at any time includes `ActiveModel::AttributeMethods`. The last one is included
234
- quite often; e.g. Active Record and other popular ORM-s use it. (I'm calling that thechnique
241
+ will at any time include `ActiveModel::AttributeMethods`. The last one is included
242
+ quite often; many popular ORM-s use it. (I'm calling that thechnique
235
243
  "the accompanying module".)
236
244
 
237
- That's why you can make use of attribute filters without explicitly including
238
- the module, as long as your application uses some popular ORM.
239
-
240
- However, if something goes wrong or your application is somehow unusual, you can always
241
- include the `AttributeFilters` module manually in any of your models:
245
+ It all should work out of the box with ActiveModel. However, if your application
246
+ is somehow unusua (for example you don't need to include `ActiveModel::AttributeMethods`)
247
+ you can always include the `AttributeFilters` module manually in any model or entity:
242
248
 
243
249
  ```ruby
244
- class ExampleModel
250
+ class User
245
251
  include ActiveModel::AttributeFilters
246
252
  end
247
253
  ```
@@ -306,10 +312,12 @@ You can send me some bitcoins if you would like to support me:
306
312
 
307
313
  * `13wZbBjs6yQQuAb3zjfHubQSyer2cLAYzH`
308
314
 
309
- Or you can endorse my skills on LinkedIn:
315
+ Or you can endorse my skills on LinkedIn or Coderwall:
310
316
 
311
317
  * [pl.linkedin.com/in/pwilk](http://www.linkedin.com/profile/view?id=4251568#profile-skills)
312
318
 
319
+ * [![endorse](http://api.coderwall.com/siefca/endorsecount.png)](http://coderwall.com/siefca)
320
+
313
321
  License
314
322
  -------
315
323
 
@@ -2,12 +2,12 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "attribute-filters"
5
- s.version = "2.0.1.20121104164328"
5
+ s.version = "2.0.2.20121121185803"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Pawe\u{142} Wilk"]
9
9
  s.cert_chain = ["/Users/siefca/.gem/gem-public_cert.pem"]
10
- s.date = "2012-11-04"
10
+ s.date = "2012-11-21"
11
11
  s.description = "Concise way of filtering model attributes in Rails."
12
12
  s.email = ["pw@gnu.org"]
13
13
  s.extra_rdoc_files = ["Manifest.txt"]
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
16
16
  s.rdoc_options = ["--title", "Attribute::Filters Documentation", "--quiet"]
17
17
  s.require_paths = ["lib"]
18
18
  s.rubyforge_project = "attribute-filters"
19
- s.rubygems_version = "1.8.24"
19
+ s.rubygems_version = "1.8.23"
20
20
  s.signing_key = "/Users/siefca/.gem/gem-private_key.pem"
21
21
  s.summary = "Concise way of filtering and grouping model attributes in Rails"
22
22
 
@@ -1,3 +1,9 @@
1
+ === 2.0.2 / 2012-11-18
2
+
3
+ * minor enhancements
4
+
5
+ * `attribute_set` class and instance aliases are created if methods named the same aren't defined yet
6
+
1
7
  === 2.0.1 / 2012-10-04
2
8
 
3
9
  * major enhancements
data/docs/TODO CHANGED
@@ -1,3 +1,8 @@
1
+ * attr_virtual - handle situation when method appears because module was included (wrap include and check for methods that module has)
2
+
3
+ * add some configuration keywords that would allow a quick integration with strange frameworks
4
+ (add proxy methods for attributes, changes and so on and allow configuration of these methods - call AR/AM if @method_slot is nil, send @method_slot otherwise)
5
+
1
6
  * add sanitize to common filters
2
7
  -- sanitize_url
3
8
  -- sanitize_string
@@ -76,10 +76,15 @@ end
76
76
 
77
77
  Instead of `attribute_set` you may also use one of the aliases:
78
78
 
79
- * `attributes_set`, `attributes_that_are`, `attributes_that`, `properties_that`,
79
+ * `af_attribute_set`, `attributes_set`, `attributes_that_are`, `attributes_that`, `properties_that`,
80
80
  `has_attribute_set`, `has_attribute_that`, `has_attribute_that_is`, `has_attributes`,
81
81
  `has_attributes_set`, `has_attributes_that_are`, `has_attributes_that`, `has_properties_that`
82
82
 
83
+ **WARNING**
84
+
85
+ If you are using other module that provides `attribute_set` class method (e.g. Virtus) then make sure you are including `AttributeFilters` (or `ActiveModel::AttributeMethods`) **after** including that module. Then use any other alias
86
+ (e.g. `af_attribute_set`) instead of `attribute_set`.
87
+
83
88
  #### `filter_attribute(attr => set_names)` ####
84
89
 
85
90
  You may prefer the alternative syntax, that **uses attribute names**
@@ -268,6 +273,11 @@ Example:
268
273
 
269
274
  It works the same as the `all_attributes` method.
270
275
 
276
+ **WARNING**
277
+
278
+ If you are using other module that provides `attribute_set` method (e.g. Virtus) then make sure you are including `AttributeFilters` (or `ActiveModel::AttributeMethods`) **after** including that module. Then use any other alias
279
+ (e.g. `af_attribute_set`) instead of `attribute_set`.
280
+
271
281
  #### `attribute_set(set_name)` ####
272
282
 
273
283
  The [`attribute_set`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:attribute_set)
@@ -303,7 +313,7 @@ There are also variants of this method that differ in a kind of taken argument:
303
313
 
304
314
  Instead of `attribute_set` you may also use one of the aliases:
305
315
 
306
- * `attributes_set`, `attributes_that_are`, `attributes_that`, `properties_that`,
316
+ * `af_attribute_set`, `attributes_set`, `attributes_that_are`, `attributes_that`, `properties_that`,
307
317
  `has_attribute_set`, `has_attribute_that`, `has_attribute_that_is`, `has_attributes`,
308
318
  `has_attributes_set`, `has_attributes_that_are`, `has_attributes_that`, `has_properties_that`
309
319
 
@@ -314,6 +324,11 @@ Instead of `attribute_set` you may also use:
314
324
  It works same way as `attribute_set(set_name)` but doesn't wrap the result in a transparent proxy
315
325
  object that brings some syntactic sugar (explained later).
316
326
 
327
+ **WARNING**
328
+
329
+ If you are using other module that provides `attribute_set` method (e.g. Virtus) then make sure you are including `AttributeFilters` (or `ActiveModel::AttributeMethods`) **after** including that module. Then use any other alias
330
+ (e.g. `af_attribute_set`) instead of `attribute_set`.
331
+
317
332
  #### `attribute_sets` ####
318
333
 
319
334
  The [`attribute_sets`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters:attribute_sets)
@@ -1621,7 +1636,7 @@ or
1621
1636
 
1622
1637
  #### After defining sets ####
1623
1638
 
1624
- To create annotations for class-level sets use the [`annotate_attribute_set`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods.html#annotate_attribute_set-instance_method) method (an its aliases):
1639
+ To create annotations for class-level sets use the [`annotate_attribute_set`](http://rubydoc.info/gems/attribute-filters/ActiveModel/AttributeFilters/ClassMethods.html#annotate_attribute_set-instance_method) method or one of its aliases:
1625
1640
 
1626
1641
  * **`annotate_attributes_that_are`**
1627
1642
  * **`annotate_attributes_that`**
@@ -131,9 +131,9 @@ module ActiveModel
131
131
  output_set[atr_name][default_param.to_sym] = atr_annotations
132
132
  end
133
133
  end
134
- attribute_set(set_name, output_set)
134
+ af_attribute_set(set_name, output_set)
135
135
  else
136
- attribute_set(set_name, *attribute_defs)
136
+ af_attribute_set(set_name, *attribute_defs)
137
137
  end
138
138
  nil
139
139
  end
@@ -78,7 +78,7 @@ module ActiveModel
78
78
 
79
79
  # set name as a method name
80
80
  if @set_object.nil?
81
- @set_object = @am_object.class.attribute_set(method_sym)
81
+ @set_object = @am_object.class.af_attribute_set(method_sym)
82
82
  return self
83
83
  end
84
84
 
@@ -124,7 +124,7 @@ module ActiveModel
124
124
  :split_flatten => [ :flatten, :split_flatten ]
125
125
  }, :split_into
126
126
  # write some defaults
127
- limit, into = attribute_set(:should_be_splitted).get_annotations(atr_name, :split_limit, :split_into)
127
+ limit, into = af_attribute_set(:should_be_splitted).get_annotations(atr_name, :split_limit, :split_into)
128
128
  annotate_attribute_set(:should_be_splitted, atr_name, :split_limit, limit.to_i) unless limit.blank?
129
129
  if into.blank?
130
130
  annotate_attribute_set(:should_be_splitted, atr_name,:split_into, nil)
@@ -17,6 +17,11 @@ module ActiveModel
17
17
  # @return [void]
18
18
  def self.included(base)
19
19
  base.extend ClassMethods
20
+ base.module_eval do
21
+ unless method_defined?(:attribute_set)
22
+ alias_method :attribute_set, :af_attribute_set
23
+ end
24
+ end
20
25
  end
21
26
 
22
27
  # Returns the attribute set of the given name or the set containing
@@ -43,22 +48,22 @@ module ActiveModel
43
48
  #
44
49
  # @param set_name [Symbol] name of attribute set, attribute object or any object that can initialize a set
45
50
  # @return [AttributeSet] attribute set
46
- def attribute_set(set_name = nil)
51
+ def af_attribute_set(set_name = nil)
47
52
  ActiveModel::AttributeSet::Query.new(set_name, self)
48
53
  end
49
- alias_method :attributes_that_are, :attribute_set
50
- alias_method :from_attributes_that, :attribute_set
51
- alias_method :are_attributes_that, :attribute_set
52
- alias_method :are_attributes_that_are, :attribute_set
53
- alias_method :are_attributes, :attribute_set
54
- alias_method :are_attributes_for, :attribute_set
55
- alias_method :from_attributes_that_are, :attribute_set
56
- alias_method :in_attributes_that_are, :attribute_set
57
- alias_method :attributes_that, :attribute_set
58
- alias_method :attributes_are, :attribute_set
59
- alias_method :attributes_for, :attribute_set
60
- alias_method :attributes_set, :attribute_set
61
- alias_method :properties_that, :attribute_set
54
+ alias_method :attributes_that_are, :af_attribute_set
55
+ alias_method :from_attributes_that, :af_attribute_set
56
+ alias_method :are_attributes_that, :af_attribute_set
57
+ alias_method :are_attributes_that_are, :af_attribute_set
58
+ alias_method :are_attributes, :af_attribute_set
59
+ alias_method :are_attributes_for, :af_attribute_set
60
+ alias_method :from_attributes_that_are, :af_attribute_set
61
+ alias_method :in_attributes_that_are, :af_attribute_set
62
+ alias_method :attributes_that, :af_attribute_set
63
+ alias_method :attributes_are, :af_attribute_set
64
+ alias_method :attributes_for, :af_attribute_set
65
+ alias_method :attributes_set, :af_attribute_set
66
+ alias_method :properties_that, :af_attribute_set
62
67
 
63
68
  # Returns the attribute set of the given name without wrapping
64
69
  # the result in proxy methods.
@@ -71,7 +76,7 @@ module ActiveModel
71
76
  # @param set_name [Symbol] name of attribute set
72
77
  # @return [AttributeSet] attribute set
73
78
  def attribute_set_simple(set_name)
74
- self.class.attribute_set(set_name)
79
+ self.class.af_attribute_set(set_name)
75
80
  end
76
81
 
77
82
  # Returns a set containing all known attributes
@@ -254,9 +259,18 @@ module ActiveModel
254
259
  # This module contains class methods
255
260
  # that create DSL for managing attribute sets.
256
261
  module ClassMethods
262
+ def self.extended(base)
263
+ base.module_eval do
264
+ unless method_defined?(:attribute_set)
265
+ alias_method :attribute_set, :af_attribute_set
266
+ end
267
+ end
268
+ end
269
+
257
270
  # @overload attribute_set()
258
- # Gets all the defined attribute sets by calling +attribute_sets+.
259
- # @return [Hash{Symbol => AttributeSet<String>}] the collection of attribute sets indexed by their names
271
+ # Gets all the defined attribute sets by calling +attribute_sets+ unless some other module overriden this method –
272
+ # In such cache it calls that method.
273
+ # @return [Object,Hash{Symbol => AttributeSet<String>}] the collection of attribute sets indexed by their names
260
274
  #
261
275
  # @overload attribute_set(set_name)
262
276
  # Gets the attribute set of the given name from internal storage.
@@ -281,14 +295,14 @@ module ActiveModel
281
295
  # and arrays of attributes
282
296
  # @param attribute_names [Array<Symbol,String>] names of additional attributes to be stored in set
283
297
  # @return [nil]
284
- def attribute_set(*args)
298
+ def af_attribute_set(*args)
285
299
  case args.size
286
300
  when 0
287
301
  attribute_sets
288
302
  when 1
289
303
  first_arg = args.first
290
304
  if first_arg.is_a?(Hash) # [write] multiple sets defined
291
- first_arg.each_pair { |k, v| attribute_set(k, v) }
305
+ first_arg.each_pair { |k, v| af_attribute_set(k, v) }
292
306
  nil
293
307
  else # [read] single set to read
294
308
  r = __attribute_sets[first_arg.to_sym]
@@ -298,7 +312,7 @@ module ActiveModel
298
312
  first_arg = args.shift
299
313
  if first_arg.is_a?(Hash) # [write] multiple sets defined
300
314
  first_arg.each_pair do |k, v|
301
- attribute_set(k, v, args)
315
+ af_attribute_set(k, v, args)
302
316
  end
303
317
  else # [write core] sinle set and optional attrs given
304
318
  AFHelpers.check_wanted_methods(self)
@@ -307,18 +321,18 @@ module ActiveModel
307
321
  nil
308
322
  end
309
323
  end
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
324
+ alias_method :attributes_set, :af_attribute_set
325
+ alias_method :attributes_that_are, :af_attribute_set
326
+ alias_method :attributes_that, :af_attribute_set
327
+ alias_method :properties_that, :af_attribute_set
328
+ alias_method :has_attribute_set, :af_attribute_set
329
+ alias_method :has_attribute_that, :af_attribute_set
330
+ alias_method :has_attribute_that_is, :af_attribute_set
331
+ alias_method :has_attributes, :af_attribute_set
332
+ alias_method :has_attributes_set, :af_attribute_set
333
+ alias_method :has_attributes_that_are, :af_attribute_set
334
+ alias_method :has_attributes_that, :af_attribute_set
335
+ alias_method :has_properties_that, :af_attribute_set
322
336
 
323
337
  # @overload filter_attribute()
324
338
  # Gets all the defined attribute sets.
@@ -373,10 +387,10 @@ module ActiveModel
373
387
  args.flatten.compact.each do |set_name|
374
388
  if set_name.is_a?(Hash) # annotation
375
389
  set_name.each_pair do |set_name_b, a_defs|
376
- attribute_set(set_name_b, first_arg => a_defs)
390
+ af_attribute_set(set_name_b, first_arg => a_defs)
377
391
  end
378
392
  else
379
- attribute_set(set_name, first_arg)
393
+ af_attribute_set(set_name, first_arg)
380
394
  end
381
395
  end
382
396
  end
@@ -14,7 +14,7 @@ module ActiveModel
14
14
  # @private
15
15
  EMAIL = 'pw@gnu.org'
16
16
  # @private
17
- VERSION = '2.0.1'
17
+ VERSION = '2.0.2'
18
18
  # @private
19
19
  NAME = 'attribute-filters'
20
20
  # @private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attribute-filters
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -36,7 +36,7 @@ cert_chain:
36
36
  YzBobXpodlZadEJ3ZlpyaXRTVmhmQ0xwNXVGd3FDcVkKTkszVElaYVBDaDFT
37
37
  Mi9FUzZ3WE52alErNUVuRUVMOWovcFNFb3A5RFlFQlBhTTJXRFZSNWkwakpU
38
38
  QWFSV3c9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
39
- date: 2012-11-04 00:00:00.000000000 Z
39
+ date: 2012-11-21 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: railties
@@ -320,7 +320,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
320
320
  version: '0'
321
321
  segments:
322
322
  - 0
323
- hash: -1229665950453395191
323
+ hash: -1525160072610592703
324
324
  required_rubygems_version: !ruby/object:Gem::Requirement
325
325
  none: false
326
326
  requirements:
@@ -329,7 +329,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
329
329
  version: '0'
330
330
  requirements: []
331
331
  rubyforge_project: attribute-filters
332
- rubygems_version: 1.8.24
332
+ rubygems_version: 1.8.23
333
333
  signing_key:
334
334
  specification_version: 3
335
335
  summary: Concise way of filtering and grouping model attributes in Rails
metadata.gz.sig CHANGED
Binary file