to_collection 1.0.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE +1 -1
- data/README.md +36 -76
- data/lib/to_collection.rb +11 -38
- metadata +7 -35
- data/lib/ext/object.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b7f4554abcadb801dd15c605c27fd9f2136afe4af6daaeceae11c1acf0f4e81d
|
4
|
+
data.tar.gz: 450a6c4275d9f288a9ad12d0206b4bae758b53ed4bc4fb0235405e6630124f9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ba415baef5dabf5bbf237d5f6bace35f8942db4198125e119c7ad465ef037d371b199537b09a81582129363da2a1934c481ba897302805a8558c062faa608c1
|
7
|
+
data.tar.gz: a1db7fd8b9762c1d595c23041fab690b379711500e814ac8681d6e7d0d610f60c3350add4e1212dc313bb954de91da3c98dc4941395e03e9e51fc002b3cbce62
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
#
|
1
|
+
# ToCollection 2.0.0 Ruby Refinement
|
2
2
|
[![Gem Version](https://badge.fury.io/rb/to_collection.svg)](http://badge.fury.io/rb/to_collection)
|
3
3
|
[![Build Status](https://travis-ci.org/AndyObtiva/to_collection.svg?branch=master)](https://travis-ci.org/AndyObtiva/to_collection)
|
4
4
|
[![Coverage Status](https://coveralls.io/repos/github/AndyObtiva/to_collection/badge.svg?branch=master)](https://coveralls.io/github/AndyObtiva/to_collection?branch=master)
|
5
5
|
|
6
6
|
Treat an array of objects and a singular object uniformly as a collection of objects.
|
7
|
-
|
7
|
+
|
8
|
+
Especially useful in processing REST Web Service API JSON responses in a uniform functional approach.
|
9
|
+
|
10
|
+
`ToCollection` is a Ruby Refinement, so it may be safely enabled via `using ToCollection` where needed only.
|
8
11
|
|
9
12
|
## Introduction
|
10
13
|
|
11
14
|
Canonicalize data to treat uniformly whether it comes in as a single object or an array of objects, dropping `nils` out automatically.
|
12
15
|
|
13
|
-
API: `object
|
16
|
+
API: `object#to_collection(compact=true)` where `compact` is a boolean for whether to compact collection or not. It is true by default.
|
14
17
|
|
15
18
|
Example:
|
16
19
|
|
@@ -39,17 +42,24 @@ end
|
|
39
42
|
|
40
43
|
## Instructions
|
41
44
|
|
42
|
-
### Bundler
|
45
|
+
### Bundler
|
43
46
|
|
44
|
-
`gem 'to_collection', '~>
|
47
|
+
- Add `gem 'to_collection', '~> 2.0.0'` to Gemfile
|
48
|
+
- Run `bundle`
|
49
|
+
- Require `to_collection` ruby gem in code (e.g. via `Bundler.require(:default)` or `require 'bundler/setup'` & `require 'to_collection'`)
|
50
|
+
- Add `using ToCollection` to the top of the Ruby file you would like to refine `Object` in with `#to_collection` method.
|
45
51
|
|
46
|
-
###
|
52
|
+
### Manual Gem Install
|
47
53
|
|
48
|
-
`
|
54
|
+
- Run `gem install to_collection -v2.0.0`
|
55
|
+
- Add `require 'to_collection'` to code
|
56
|
+
- Add `using ToCollection` to the top of the Ruby file you would like to refine `Object` in with `#to_collection` method.
|
49
57
|
|
50
58
|
### Note
|
51
59
|
|
52
|
-
|
60
|
+
If '#to_collection' was already defined on `Object` in a project, requiring the `to_collection` library will print a warning.
|
61
|
+
|
62
|
+
It is still safe to require as it does not overwrite `Object#to_collection` except in Ruby files where `using ToCollection` is added.
|
53
63
|
|
54
64
|
## Background
|
55
65
|
|
@@ -63,7 +73,7 @@ GET /people
|
|
63
73
|
<= 1 person
|
64
74
|
JSON Response:
|
65
75
|
```JSON
|
66
|
-
{"first_name":"
|
76
|
+
{"first_name":"John","last_name":"Barber","city":"Chicago"}
|
67
77
|
```
|
68
78
|
|
69
79
|
HTTP Request: =>
|
@@ -75,7 +85,7 @@ GET /people
|
|
75
85
|
JSON Response:
|
76
86
|
|
77
87
|
```JSON
|
78
|
-
[{"first_name":"
|
88
|
+
[{"first_name":"John","last_name":"Barber","city":"Chicago"}, {"first_name":"Mark","last_name":"Jones","city":"New York"}, {"first_name":"Josh","last_name":"Beeswax","city":"Denver"}]
|
79
89
|
```
|
80
90
|
|
81
91
|
How do you work with the varied JSON responses in Ruby?
|
@@ -198,7 +208,7 @@ Example:
|
|
198
208
|
How about go one step further and bake this into all objects using our previous approach of object-oriented polymorphism and Ruby open-classes? That way, we don't just collapse the difference between dealing with arrays of hashes vs hashes but also arrays of objects vs singular objects by adding. Note the use of flatten(1) below to prevent arrays or arrays from collapsing more than one level.
|
199
209
|
|
200
210
|
```ruby
|
201
|
-
Object
|
211
|
+
class Object
|
202
212
|
def to_collection
|
203
213
|
[self].flatten(1).compact
|
204
214
|
end
|
@@ -218,7 +228,7 @@ end
|
|
218
228
|
A refactored version including optional compacting would be:
|
219
229
|
|
220
230
|
```ruby
|
221
|
-
Object
|
231
|
+
class Object
|
222
232
|
def to_collection(compact=true)
|
223
233
|
collection = [self].flatten(1)
|
224
234
|
compact ? collection.compact : collection
|
@@ -241,77 +251,27 @@ people_http_request.to_collection(false).each do |person|
|
|
241
251
|
end
|
242
252
|
```
|
243
253
|
|
244
|
-
|
245
|
-
|
246
|
-
## How It Works
|
247
|
-
|
248
|
-
A [super_module](https://github.com/AndyObtiva/super_module) called `ToCollection`
|
249
|
-
contains the `#to_collection` method and is included (mixed) into `Object`, providing
|
250
|
-
`#to_collection` method to inheriting classes.
|
251
|
-
|
252
|
-
## Options
|
253
|
-
|
254
|
-
### `Object.to_collection_already_implemented_strategy`
|
255
|
-
Possible Values: `"raise_error"` (default), `"keep"`, `"overwrite"`
|
256
|
-
|
257
|
-
Setting this option allows developer to configure handling of the case when
|
258
|
-
`Object#to_collection` already exists before loading `to_collection` library.
|
259
|
-
|
260
|
-
#### `"raise_error"` (default)
|
261
|
-
|
262
|
-
For safety reasons, the library will raise AlreadyImplementedError by default to
|
263
|
-
alert the developer and provide information about the other options.
|
264
|
-
This prevents later surprises and puts control in the hand of the developer to
|
265
|
-
responsibly decide what option to pick next.
|
266
|
-
|
267
|
-
#### `"keep"`
|
268
|
-
|
269
|
-
This keeps existing `to_collection` untouched, disabling this library.
|
270
|
-
|
271
|
-
#### `"overwrite"`
|
272
|
-
|
273
|
-
This overwrites existing `to_collection` method, fully enabling this library.
|
274
|
-
|
275
|
-
### `ENV['TO_COLLECTION_ALREADY_IMPLEMENTED_STRATEGY']`
|
276
|
-
Possible Values: `"raise_error"` (default), `"keep"`, `"overwrite"`
|
277
|
-
|
278
|
-
Same function as `Object.to_collection_already_implemented_strategy`.
|
279
|
-
Environment variable takes precedence over class accessor variable though.
|
280
|
-
|
281
|
-
### `ENV['TO_COLLECTION_OBJECT_INCLUDE']`
|
282
|
-
Possible Values: `"true"` (default), `"false"`
|
283
|
-
|
284
|
-
Must be set before requiring/loading library. When using bundler, ensure `require` option is set to `false` or `nil`.
|
285
|
-
|
286
|
-
`ToCollection` [super_module](https://github.com/AndyObtiva/super_module) is automatically included in `Object` except when `ENV['TO_COLLECTION_OBJECT_INCLUDE']` is set to `"false"`, providing developer with the option to **manually** include (mix in) `ToCollection` [super_module](https://github.com/AndyObtiva/super_module) into classes that need it.
|
287
|
-
|
288
|
-
Example:
|
289
|
-
|
290
|
-
Bundler would have gem require option as false:
|
254
|
+
Of course, in Ruby 2+, you may use Ruby Refinements, so simply include `Object#to_collection` via this line instead:
|
291
255
|
|
292
256
|
```ruby
|
293
|
-
|
257
|
+
using ToCollection
|
294
258
|
```
|
295
259
|
|
296
|
-
|
260
|
+
You asked for "Elegant" didn't you? I hope that was what you were looking for.
|
297
261
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
include ToCollection #enables to_collection method
|
303
|
-
end
|
304
|
-
Array.instance_eval do
|
305
|
-
include ToCollection #enables to_collection method
|
306
|
-
end
|
307
|
-
response_data = people_http_request #returns single hash or array of hashes
|
308
|
-
response_data.to_collection.each do |person_hash|
|
309
|
-
# do some work
|
310
|
-
end
|
311
|
-
```
|
262
|
+
## How It Works
|
263
|
+
|
264
|
+
A Ruby Refinement is activated via `using ToCollection` adding/overwriting the `#to_collection` method in `Object`, which
|
265
|
+
is the ancestor of all Ruby objects.
|
312
266
|
|
313
267
|
## Release Notes
|
314
268
|
|
269
|
+
### v2.0.0
|
270
|
+
|
271
|
+
- Revamped API using Ruby Refinements (safer than monkey-patching)
|
272
|
+
- Removed `super_module` gem dependency
|
273
|
+
- Dropped safety options since Ruby Refinements already handle things safely
|
274
|
+
|
315
275
|
### v1.0.1
|
316
276
|
|
317
277
|
- Updated `super_module` gem version to relax indirect `method_source` gem version dependency
|
@@ -330,5 +290,5 @@ end
|
|
330
290
|
|
331
291
|
## Copyright
|
332
292
|
|
333
|
-
Copyright (c) 2017 Andy Maleh. See LICENSE.txt for
|
293
|
+
Copyright (c) 2017-2020 Andy Maleh. See LICENSE.txt for
|
334
294
|
further details.
|
data/lib/to_collection.rb
CHANGED
@@ -1,44 +1,17 @@
|
|
1
|
-
require 'super_module'
|
1
|
+
# require 'super_module'
|
2
2
|
|
3
|
-
ToCollection
|
4
|
-
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.to_collection_already_implemented_strategy=(strategy)
|
8
|
-
@to_collection_already_implemented_strategy = strategy
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.to_collection_already_implemented_strategy
|
12
|
-
(ENV['TO_COLLECTION_ALREADY_IMPLEMENTED_STRATEGY'] ||
|
13
|
-
@to_collection_already_implemented_strategy ||
|
14
|
-
:raise_error).to_sym
|
15
|
-
end
|
16
|
-
|
17
|
-
def __to_collection__(compact=true)
|
18
|
-
collection = [self].flatten(1)
|
19
|
-
compact ? collection.compact : collection
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.define_to_collection_method
|
23
|
-
define_method(:to_collection, instance_method(:__to_collection__))
|
24
|
-
send(:remove_method, :__to_collection__)
|
25
|
-
end
|
26
|
-
|
27
|
-
case self.to_collection_already_implemented_strategy
|
28
|
-
when :raise_error
|
3
|
+
module ToCollection
|
4
|
+
refine Object do
|
29
5
|
begin
|
30
|
-
|
31
|
-
|
32
|
-
raise AlreadyImplementedError.new(message)
|
6
|
+
method(:to_collection)
|
7
|
+
puts "ToCollection Warning: Object#to_collection already exists! using ToCollection overwrites it with a Ruby Refinement."
|
33
8
|
rescue NameError
|
34
|
-
|
9
|
+
# No Op
|
10
|
+
ensure
|
11
|
+
def to_collection(compact=true)
|
12
|
+
collection = [self].flatten(1)
|
13
|
+
compact ? collection.compact : collection
|
14
|
+
end
|
35
15
|
end
|
36
|
-
when :keep
|
37
|
-
# do nothing
|
38
|
-
when :overwrite
|
39
|
-
self.define_to_collection_method
|
40
16
|
end
|
41
|
-
|
42
17
|
end
|
43
|
-
|
44
|
-
require File.expand_path(File.join(__FILE__, '..', 'ext', 'object'))
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: to_collection
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: super_module
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - '='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 1.2.2
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - '='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 1.2.2
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: jeweler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,20 +52,8 @@ dependencies:
|
|
66
52
|
- - "~>"
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: 3.5.0
|
69
|
-
description:
|
70
|
-
|
71
|
-
responses in a functional approach.\n\n Canonicalize data to treat uniformly
|
72
|
-
whether it comes in as a single object or an array of objects, dropping `nils` out
|
73
|
-
automatically.\n\n API: `object.to_collection(compact)` where `compact` is a
|
74
|
-
boolean for whether to compact collection or not. It is true by default.\n\n Example:\n\n
|
75
|
-
\ ```ruby\n city_counts = {}\n people_http_request.to_collection.each do
|
76
|
-
|person|\n city_counts[person[\"city\"]] ||= 0\n city_counts[person[\"city\"]]
|
77
|
-
+= 1\n end\n ```\n\n Wanna keep `nil` values? No problem! Just pass `false`
|
78
|
-
as an argument:\n\n ```ruby\n bad_people_count = 0\n city_counts = {}\n
|
79
|
-
\ people_http_request.to_collection(false).each do |person|\n if person.nil?\n
|
80
|
-
\ bad_people_count += 1\n else\n city_counts[person[\"city\"]]
|
81
|
-
||= 0\n city_counts[person[\"city\"]] += 1\n end\n end\n ```\n
|
82
|
-
\ "
|
55
|
+
description: ToCollection Ruby Refinement - Treat an array of objects and a singular
|
56
|
+
object uniformly as a collection of objects
|
83
57
|
email: andy.am@gmail.com
|
84
58
|
executables: []
|
85
59
|
extensions: []
|
@@ -89,7 +63,6 @@ extra_rdoc_files:
|
|
89
63
|
files:
|
90
64
|
- LICENSE
|
91
65
|
- README.md
|
92
|
-
- lib/ext/object.rb
|
93
66
|
- lib/to_collection.rb
|
94
67
|
homepage: http://github.com/AndyObtiva/to_collection
|
95
68
|
licenses:
|
@@ -110,10 +83,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
83
|
- !ruby/object:Gem::Version
|
111
84
|
version: '0'
|
112
85
|
requirements: []
|
113
|
-
|
114
|
-
rubygems_version: 2.6.10
|
86
|
+
rubygems_version: 3.1.2
|
115
87
|
signing_key:
|
116
88
|
specification_version: 4
|
117
|
-
summary: Treat an array of objects and a singular object
|
118
|
-
of objects
|
89
|
+
summary: ToCollection Ruby Refinement - Treat an array of objects and a singular object
|
90
|
+
uniformly as a collection of objects
|
119
91
|
test_files: []
|