refinements 7.7.0 → 7.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b7d7affd4176bb25ee87d3718b592a0bd2b07be2bad86d584f06f0d16dcd866
4
- data.tar.gz: 256ab9f274581c668a06949a41501c50885f9681dd6150c9b58046d59cf87de7
3
+ metadata.gz: 3df95fcb46ec44d2945b1eb3ab7dafd8ba6bb243973829d662e448ef74695302
4
+ data.tar.gz: 21d89890312770ec2c73387c05c44dc31b22de849e18c3db6b4248476ca8bbdf
5
5
  SHA512:
6
- metadata.gz: 356b4ea5575bbec34d4b2c31495c59b49ce9efe00bedcce194d458c8bdbbcf47ca87e3be00b60f910af14e2768cf8b42de909fcdec652a895d8de706652e0777
7
- data.tar.gz: 0a7d8c6bd99585868ec7b2d119f7014e1c2ebf571324d23c8be209bd364417c4106f465a4f0dd6ab012fb6f82e1024ae803ef0d27949051e6c65b4aa2d6f63dd
6
+ metadata.gz: d0cb8fa10183e03737eab0ae1780b91e2e4ce994fd0945c7e2653bacd852dae85de474a073f4b1f6b8634e685059a54a0651b46ec567defd283cfb1491988e50
7
+ data.tar.gz: a3f2ea6940f0e8c74f41f43d28d34a71892d3ddcaaf295c64ce4761b120421f80c7833bd9b48d37a90e485c3b606c38adb71e8665cf9feecad35925da485628a
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -150,7 +150,7 @@ additional liability.
150
150
 
151
151
  END OF TERMS AND CONDITIONS
152
152
 
153
- Copyright link:https://www.alchemists.io[Alchemists].
153
+ Copyright 2015 link:https://www.alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann].
154
154
 
155
155
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
156
156
  compliance with the License. You may obtain a link:https://www.apache.org/licenses/LICENSE-2.0[copy]
@@ -9,70 +9,23 @@ image::https://badge.fury.io/rb/refinements.svg[Gem Version]
9
9
  [link=https://circleci.com/gh/bkuhlmann/refinements]
10
10
  image::https://circleci.com/gh/bkuhlmann/refinements.svg?style=svg[Circle CI Status]
11
11
 
12
- A collection of refinements (enhancements) to core Ruby objects.
12
+ A collection of refinements (enhancements) to primitive Ruby objects.
13
13
 
14
14
  toc::[]
15
15
 
16
16
  == Features
17
17
 
18
- * *Arrays*:
19
- ** `#compress` - Removes `nil` and empty values without modifying itself.
20
- ** `#compress!` - Removes `nil` and empty values while modifying itself.
21
- ** `#ring` - Answers a circular array which can enumerate before, current, after elements.
22
- * *BigDecimals*:
23
- ** `#inspect` - Allows one to inspect a big decimal with numeric representation.
24
- * *DateTimes*:
25
- ** `.utc` - Answers new DateTime object for current UTC date/time.
26
- * *Files*:
27
- ** `#rewrite` - When given a file path and a block, it provides the contents of the recently read
28
- file for manipulation and immediate writing back to the same file.
29
- * *Hashes*:
30
- ** `.infinite` - Answers new hash where missing keys, even deeply nested, answer an empty hash.
31
- ** `.with_default` - Answers new hash where every top-level missing key has the same default value.
32
- ** `#except` - Answers new hash with given keys removed without modifying itself.
33
- ** `#except!` - Answers new hash with given keys removed while modifying itself.
34
- ** `#symbolize_keys` - Converts keys to symbols without modifying itself.
35
- ** `#symbolize_keys!` - Converts keys to symbols while modifying itself.
36
- ** `#deep_merge` - Merges deeply nested hashes together without modifying itself.
37
- ** `#deep_merge!` - Merges deeply nested hashes together while modifying itself.
38
- ** `#deep_symbolize_keys` - Symbolizes keys of nested hash without modifying itself. Does not handle
39
- nested arrays, though.
40
- ** `#deep_symbolize_keys!` - Symbolizes keys of nested hash while modifying itself. Does not handle
41
- nested arrays, though.
42
- ** `#recurse` - Applies block to nested hash. Does not handle nested arrays, though.
43
- ** `#rekey` - Transforms keys per mapping (size of mapping can vary) without modifying itself.
44
- ** `#rekey!` - Transforms keys per mapping (size of mapping can vary) while modifying itself.
45
- ** `#reverse_merge` - Merges calling hash into passed in hash without modifying itself.
46
- ** `#reverse_merge!` - Merges calling hash into passed in hash while modifying itself.
47
- ** `#use` - Passes each hash value as a block argument for further processing.
48
- * *Pathnames*:
49
- ** `Pathname` - Conversion function (refined from `Kernel`) which can cast `nil` into a pathname.
50
- ** `#name` - Answers file name without extension.
51
- ** `#copy` - Copies file from current location to new location.
52
- ** `#directories` - Answers all or filtered directories for current path.
53
- ** `#extensions` - Answers file extensions as an array.
54
- ** `#files` - Answers all or filtered files for current path.
55
- ** `#gsub` - Same behavior as `String#gsub` but answers a path with patterns replaced with desired
56
- substitutes.
57
- ** `#relative_parent_from` - Answers relative path from parent directory. This is a complement to
58
- `#relative_path_from`.
59
- ** `#make_ancestors` - Ensures all ancestor directories are created for a path.
60
- ** `#rewrite` - When given a block, it provides the contents of the recently read file for
61
- manipulation and immediate writing back to the same file.
62
- ** `#touch` - Updates access and modification times for path. Defaults to current time.
63
- * *Strings*:
64
- ** `#first` - Answers first character of a string or first set of characters if given a number.
65
- ** `#last` - Answers last character of a string or last set of characters if given a number.
66
- ** `#blank?` - Answers `true`/`false` based on whether string is blank or not
67
- (i.e. `<space>`, `\n`, `\t`, `\r`).
68
- ** `#up` - Answers string with only first letter upcased.
69
- ** `#down` - Answers string with only first letter downcased.
70
- ** `#camelcase` - Answers a camelcased string.
71
- ** `#snakecase` - Answers a snakecased string.
72
- ** `#titleize` - Answers titleized string.
73
- ** `#to_bool` - Answers string as a boolean.
74
- * *String IOs*:
75
- ** `#reread` - Answers full string by rewinding to beginning of string and reading all content.
18
+ Enhances the following objects:
19
+
20
+ * Array
21
+ * BigDecimal
22
+ * DateTime
23
+ * File
24
+ * Hash
25
+ * IO
26
+ * Pathname
27
+ * String
28
+ * StringIO
76
29
 
77
30
  == Requirements
78
31
 
@@ -82,8 +35,6 @@ manipulation and immediate writing back to the same file.
82
35
 
83
36
  == Setup
84
37
 
85
- === Production
86
-
87
38
  To install, run:
88
39
 
89
40
  [source,bash]
@@ -98,24 +49,6 @@ Add the following to your Gemfile file:
98
49
  gem "refinements"
99
50
  ----
100
51
 
101
- === Development
102
-
103
- To contribute, run:
104
-
105
- [source,bash]
106
- ----
107
- git clone https://github.com/bkuhlmann/refinements.git
108
- cd refinements
109
- bin/setup
110
- ----
111
-
112
- You can also use the IRB console for direct access to all objects:
113
-
114
- [source,bash]
115
- ----
116
- bin/console
117
- ----
118
-
119
52
  == Usage
120
53
 
121
54
  === Requires
@@ -127,7 +60,7 @@ If all refinements are not desired, add the following to your `+Gemfile+` instea
127
60
  gem "refinements", require: false
128
61
  ----
129
62
 
130
- then require the specific refinement, as needed. Example:
63
+ ...then require the specific refinement, as needed. Example:
131
64
 
132
65
  [source,ruby]
133
66
  ----
@@ -136,13 +69,16 @@ require "refinements/big_decimals"
136
69
  require "refinements/date_times"
137
70
  require "refinements/files"
138
71
  require "refinements/hashes"
72
+ require "refinements/ios"
139
73
  require "refinements/pathnames"
140
74
  require "refinements/strings"
75
+ require "refinements/string_ios"
141
76
  ----
142
77
 
143
78
  === Using
144
79
 
145
- Much like including/extending a module, you’ll need modify your object(s) to use the refinement(s):
80
+ Much like including/extending a module, you’ll need to modify your object(s) to use the
81
+ refinement(s):
146
82
 
147
83
  [source,ruby]
148
84
  ----
@@ -152,8 +88,10 @@ class Example
152
88
  using Refinements::DateTimes
153
89
  using Refinements::Files
154
90
  using Refinements::Hashes
91
+ using Refinements::IOs
155
92
  using Refinements::Pathnames
156
93
  using Refinements::Strings
94
+ using Refinements::StringIOs
157
95
  end
158
96
  ----
159
97
 
@@ -163,19 +101,81 @@ The following sections demonstrate how each refinement enriches your objects wit
163
101
 
164
102
  ==== Array
165
103
 
104
+ ===== #compress
105
+
106
+ Removes `nil` and empty values without mutating itself.
107
+
166
108
  [source,ruby]
167
109
  ----
168
110
  example = ["An", nil, "", "Example"]
169
- example.compress # => ["An", "Example"]
170
- example # => ["An", nil, "", "Example"]
111
+ example.compress # => ["An", "Example"]
112
+ example # => ["An", nil, "", "Example"]
113
+ ----
114
+
115
+ ===== #compress!
116
+
117
+ Removes `nil` and empty values while mutating itself.
171
118
 
119
+ [source,ruby]
120
+ ----
172
121
  example = ["An", nil, "", "Example"]
173
- example.compress! # => ["An", "Example"]
174
- example # => ["An", "Example"]
122
+ example.compress! # => ["An", "Example"]
123
+ example # => ["An", "Example"]
124
+ ----
125
+
126
+ ===== #include
127
+
128
+ Adds given array or elements without mutating itself.
129
+
130
+ [source,ruby]
131
+ ----
132
+ [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
133
+ [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
134
+ ----
135
+
136
+ ===== #intersperse
137
+
138
+ Inserts additional elements or array between all members of given array.
139
+
140
+ [source,ruby]
141
+ ----
142
+ [1, 2, 3].intersperse :a # => [1, :a, 2, :a, 3]
143
+ [1, 2, 3].intersperse :a, :b # => [1, :a, :b, 2, :a, :b, 3]
144
+ [1, 2, 3].intersperse %i[a b c] # => [1, :a, :b, :c, 2, :a, :b, :c, 3]
145
+ ----
146
+
147
+ ===== #exclude
148
+
149
+ Removes given array or elements without mutating itself.
150
+
151
+ [source,ruby]
152
+ ----
153
+ [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
154
+ [1, 2, 3, 4, 5].exclude 4, 5 # => [1, 2, 3]
155
+ ----
156
+
157
+ ===== #mean
158
+
159
+ Answers mean/average all elements within an array.
160
+
161
+ [source,ruby]
162
+ ----
163
+ [].mean # => 0
164
+ [5].mean # => 5
165
+ [1, 2, 3].mean # => 2
166
+ [1.25, 1.5, 1.75].mean # => 1.5
167
+ ----
168
+
169
+ ===== #ring
170
+
171
+ Answers a circular array which can enumerate before, current, after elements.
175
172
 
173
+ [source,ruby]
174
+ ----
176
175
  example = [1, 2, 3]
177
176
  example.ring # => #<Enumerator: ...>
178
177
  example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
178
+
179
179
  # [3 1 2]
180
180
  # [1 2 3]
181
181
  # [2 3 1]
@@ -183,6 +183,10 @@ example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
183
183
 
184
184
  ==== Big Decimal
185
185
 
186
+ ===== #inspect
187
+
188
+ Allows one to inspect a big decimal with numeric representation.
189
+
186
190
  [source,ruby]
187
191
  ----
188
192
  BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
@@ -190,6 +194,10 @@ BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
190
194
 
191
195
  ==== DateTime
192
196
 
197
+ ===== .utc
198
+
199
+ Answers new DateTime object for current UTC date/time.
200
+
193
201
  [source,ruby]
194
202
  ----
195
203
  DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867000n),+0s,2299161j)>
@@ -197,6 +205,11 @@ DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867
197
205
 
198
206
  ==== File
199
207
 
208
+ ===== .rewrite
209
+
210
+ When given a file path and a block, it provides the contents of the recently read file for
211
+ manipulation and immediate writing back to the same file.
212
+
200
213
  [source,ruby]
201
214
  ----
202
215
  File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
@@ -204,160 +217,587 @@ File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
204
217
 
205
218
  ==== Hash
206
219
 
220
+ ===== .infinite
221
+
222
+ Answers new hash where missing keys, even deeply nested, answer an empty hash.
223
+
207
224
  [source,ruby]
208
225
  ----
209
226
  example = Hash.infinite
210
- example[:a] # => {}
211
- example[:a][:b][:c] # => {}
227
+ example[:a] # => {}
228
+ example[:a][:b][:c] # => {}
229
+ ----
230
+
231
+ ===== .with_default
212
232
 
233
+ Answers new hash where every top-level missing key has the same default value.
234
+
235
+ [source,ruby]
236
+ ----
213
237
  example = Hash.with_default ""
214
238
  example[:a] # => ""
239
+
215
240
  example = Hash.with_default []
216
241
  example[:b] # => []
242
+ ----
243
+
244
+ ===== #except
217
245
 
246
+ Answers new hash with given keys removed without mutating itself.
247
+
248
+ [source,ruby]
249
+ ----
218
250
  example = {a: 1, b: 2, c: 3}
219
- example.except :a, :b # => {c: 3}
220
- example # => {a: 1, b: 2, c: 3}
251
+ example.except :a, :b # => {c: 3}
252
+ example # => {a: 1, b: 2, c: 3}
253
+ ----
254
+
255
+ ===== #except!
221
256
 
257
+ Answers new hash with given keys removed while mutating itself.
258
+
259
+ [source,ruby]
260
+ ----
222
261
  example = {a: 1, b: 2, c: 3}
223
- example.except! :a, :b # => {c: 3}
224
- example # => {c: 3}
262
+ example.except! :a, :b # => {c: 3}
263
+ example # => {c: 3}
264
+ ----
265
+
266
+ ===== #flatten_keys
225
267
 
268
+ Flattens nested keys as top-level keys without mutating itself. Does not handle nested arrays,
269
+ though.
270
+
271
+ [source,ruby]
272
+ ----
273
+ {a: {b: 1}}.flatten_keys prefix: :test # => {test_a_b: 1}
274
+ {a: {b: 1}}.flatten_keys delimiter: :| # => {:"a|b" => 1}
275
+
276
+ {a: {b: 1}}.flatten_keys cast: :to_s # => {"a_b" => 1}
277
+ {"a" => {"b" => 1}}.flatten_keys cast: :to_sym # => {a_b: 1}
278
+
279
+ example = {a: {b: 1}}
280
+ example.flatten_keys # => {a_b: 1}
281
+ example # => {a: {b: 1}}
282
+ ----
283
+
284
+ ===== #flatten_keys!
285
+
286
+ Flattens nested keys as top-level keys while mutating itself. Does not handle nested arrays,
287
+ though.
288
+
289
+ [source,ruby]
290
+ ----
291
+ example = {a: {b: 1}}
292
+ example.flatten_keys! # => {a_b: 1}
293
+ example # => {a_b: 1}
294
+ ----
295
+
296
+ ===== #stringify_keys
297
+
298
+ Converts keys to strings without mutating itself.
299
+
300
+ [source,ruby]
301
+ ----
302
+ example = {a: 1, b: 2}
303
+ example.stringify_keys # => {"a" => 1, "b" => 2}
304
+ example # => {a: 1, b: 2}
305
+ ----
306
+
307
+ ===== #stringify_keys!
308
+
309
+ Converts keys to strings while mutating itself.
310
+
311
+ [source,ruby]
312
+ ----
313
+ example = {a: 1, b: 2}
314
+ example.stringify_keys! # => {"a" => 1, "b" => 2}
315
+ example # => {"a" => 1, "b" => 2}
316
+ ----
317
+
318
+ ===== #symbolize_keys
319
+
320
+ Converts keys to symbols without mutating itself.
321
+
322
+ [source,ruby]
323
+ ----
226
324
  example = {"a" => 1, "b" => 2}
227
- example.symbolize_keys # => {a: 1, b: 2}
228
- example # => {"a" => 1, "b" => 2}
325
+ example.symbolize_keys # => {a: 1, b: 2}
326
+ example # => {"a" => 1, "b" => 2}
327
+ ----
328
+
329
+ ===== #symbolize_keys!
229
330
 
331
+ Converts keys to symbols while mutating itself.
332
+
333
+ [source,ruby]
334
+ ----
230
335
  example = {"a" => 1, "b" => 2}
231
- example.symbolize_keys! # => {a: 1, b: 2}
232
- example # => {a: 1, b: 2}
336
+ example.symbolize_keys! # => {a: 1, b: 2}
337
+ example # => {a: 1, b: 2}
338
+ ----
233
339
 
234
- example = {a: 1, b: 2, c: 3}
235
- example.slice :a, :c # => {a: 1, c: 3}
236
- example # => {a: 1, b: 2, c: 3}
340
+ ===== #deep_merge
237
341
 
238
- example = {a: 1, b: 2, c: 3}
239
- example.slice! :a, :c # => {a: 1, c: 3}
240
- example # => {a: 1, c: 3}
342
+ Merges deeply nested hashes together without mutating itself.
241
343
 
344
+ [source,ruby]
345
+ ----
242
346
  example = {a: "A", b: {one: "One", two: "Two"}}
243
- example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
244
- example # => {a: "A", b: {one: "One", two: "Two"}}
347
+ example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
348
+ example # => {a: "A", b: {one: "One", two: "Two"}}
349
+ ----
350
+
351
+ ===== #deep_merge!
245
352
 
353
+ Merges deeply nested hashes together while mutating itself.
354
+
355
+ [source,ruby]
356
+ ----
246
357
  example = {a: "A", b: {one: "One", two: "Two"}}
247
- example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
248
- example # => {a: "A", b: {one: 1, two: "Two"}}
358
+ example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
359
+ example # => {a: "A", b: {one: 1, two: "Two"}}
360
+ ----
361
+
362
+ ===== #deep_stringify_keys
249
363
 
364
+ Stringifies keys of nested hash without mutating itself. Does not handle nested arrays, though.
365
+
366
+ [source,ruby]
367
+ ----
368
+ example = {a: {b: 2}}
369
+ example.deep_stringify_keys # => {"a" => {"b" => 1}}
370
+ example # => {a: {b: 2}}
371
+ ----
372
+
373
+ ===== #deep_stringify_keys!
374
+
375
+ Stringifies keys of nested hash while mutating itself. Does not handle nested arrays, though.
376
+
377
+ [source,ruby]
378
+ ----
379
+ example = {a: {b: 2}}
380
+ example.deep_stringify_keys! # => {"a" => {"b" => 1}}
381
+ example # => {"a" => {"b" => 1}}
382
+ ----
383
+
384
+ ===== #deep_symbolize_keys
385
+
386
+ Symbolizes keys of nested hash without mutating itself. Does not handle nested arrays, though.
387
+
388
+ [source,ruby]
389
+ ----
250
390
  example = {"a" => {"b" => 2}}
251
- example.deep_symbolize_keys # => {a: {b: 1}}
252
- example # => {"a" => {"b" => 2}}
391
+ example.deep_symbolize_keys # => {a: {b: 1}}
392
+ example # => {"a" => {"b" => 2}}
393
+ ----
394
+
395
+ ===== #deep_symbolize_keys!
396
+
397
+ Symbolizes keys of nested hash while mutating itself. Does not handle nested arrays, though.
253
398
 
399
+ [source,ruby]
400
+ ----
254
401
  example = {"a" => {"b" => 2}}
255
- example.deep_symbolize_keys! # => {a: {b: 1}}
256
- example # => {a: {b: 1}}
402
+ example.deep_symbolize_keys! # => {a: {b: 1}}
403
+ example # => {a: {b: 1}}
404
+ ----
257
405
 
406
+ ===== #recurse
407
+
408
+ Recursively iterates over the hash and any hash value by applying the given block to it. Does not
409
+ handle nested arrays, though.
410
+
411
+ [source,ruby]
412
+ ----
258
413
  example = {"a" => {"b" => 1}}
259
- example.recurse(&:symbolize_keys) # => {a: {b: 1}}
260
- example.recurse(&:invert) # => {{"b" => 1} => "a"}
414
+ example.recurse(&:symbolize_keys) # => {a: {b: 1}}
415
+ example.recurse(&:invert) # => {{"b" => 1} => "a"}
416
+ ----
417
+
418
+ ===== #rekey
261
419
 
420
+ Transforms keys per mapping (size of mapping can vary) without mutating itself.
421
+
422
+ [source,ruby]
423
+ ----
262
424
  example = {a: 1, b: 2, c: 3}
263
- example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
264
- example # => {a: 1, b: 2, c: 3}
425
+ example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
426
+ example # => {a: 1, b: 2, c: 3}
427
+ ----
428
+
429
+ ===== #rekey!
265
430
 
431
+ Transforms keys per mapping (size of mapping can vary) while mutating itself.
432
+
433
+ [source,ruby]
434
+ ----
266
435
  example = {a: 1, b: 2, c: 3}
267
- example.rekey! a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
268
- example # => {amber: 1, blue: 2, c: 3}
436
+ example.rekey! a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
437
+ example # => {amber: 1, blue: 2, c: 3}
438
+ ----
439
+
440
+ ===== #reverse_merge
269
441
 
442
+ Merges calling hash into passed in hash without mutating itself.
443
+
444
+ [source,ruby]
445
+ ----
270
446
  example = {a: 1, b: 2}
271
- example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
272
- example # => {a: 1, b: 2}
447
+ example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
448
+ example # => {a: 1, b: 2}
449
+ ----
450
+
451
+ ===== #reverse_merge!
273
452
 
453
+ Merges calling hash into passed in hash while mutating itself.
454
+
455
+ [source,ruby]
456
+ ----
274
457
  example = {a: 1, b: 2}
275
- example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
276
- example # => {a: 1, b: 2, c: 3}
458
+ example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
459
+ example # => {a: 1, b: 2, c: 3}
460
+ ----
461
+
462
+ ===== #use
463
+
464
+ Passes each hash value as a block argument for further processing.
277
465
 
466
+ [source,ruby]
467
+ ----
278
468
  example = {unit: "221B", street: "Baker Street", city: "London", country: "UK"}
279
469
  example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
280
470
  ----
281
471
 
472
+ ==== IO
473
+
474
+ ===== .void
475
+
476
+ Answers an IO stream which points to `/dev/null` in order to ignore any reads or writes to the
477
+ stream. When given a block, the stream will automatically close upon block exit. When not given a
478
+ block, you'll need to close the stream manually.
479
+
480
+ [source,ruby]
481
+ ----
482
+ io = IO.void
483
+ io.closed? # => false
484
+
485
+ io = IO.void { |void| void.write "nevermore" }
486
+ io.closed? # => true
487
+ ----
488
+
489
+ ===== #squelch
490
+
491
+ Temporarily ignores any reads/writes for current stream for all code executed within the block. When
492
+ not given a block, it answers itself.
493
+
494
+ [source,ruby]
495
+ ----
496
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
497
+ io.squelch { io.write "Test" }
498
+ io.reread # => ""
499
+ ----
500
+
501
+ ===== #redirect
502
+
503
+ Redirects current stream to other stream when given a block. Without a block, the original stream is
504
+ answered instead.
505
+
506
+ [source,ruby]
507
+ ----
508
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
509
+ other = IO.new IO.sysopen(Pathname("other.txt").to_s, "w+")
510
+
511
+ io.redirect other # => `io`
512
+
513
+ io.redirect(other) { |stream| stream.write "test" }
514
+ .close # => ""
515
+ other.close # => "test"
516
+ ----
517
+
518
+ ===== #reread
519
+
520
+ Answers full stream by rewinding to beginning of stream and reading all content.
521
+
522
+ [source,ruby]
523
+ ----
524
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
525
+ io.write "This is a test."
526
+
527
+ io.reread # => "This is a test."
528
+ io.reread 4 # => "This"
529
+
530
+ buffer = "".dup
531
+ io.reread(buffer: buffer)
532
+ buffer # => "This is a test."
533
+ ----
534
+
282
535
  ==== Pathname
283
536
 
537
+ ===== Pathname
538
+
539
+ Enhances the conversion function -- refined from `Kernel` -- which casts `nil` into a pathname in
540
+ order to avoid: `TypeError (no implicit conversion of nil into String)`. The pathname is still
541
+ invalid but at least you have an instance of `Pathname`, which behaves like a _Null Object_, that
542
+ can still be used to construct a valid path.
543
+
284
544
  [source,ruby]
285
545
  ----
286
546
  Pathname(nil) # => Pathname("")
547
+ ----
548
+
549
+ ===== #name
287
550
 
551
+ Answers file name without extension.
552
+
553
+ [source,ruby]
554
+ ----
288
555
  Pathname("example.txt").name # => Pathname("example")
556
+ ----
557
+
558
+ ===== #copy
289
559
 
560
+ Copies file from current location to new location.
561
+
562
+ [source,ruby]
563
+ ----
290
564
  Pathname("input.txt").copy Pathname("output.txt")
565
+ ----
566
+
567
+ ===== #directories
568
+
569
+ Answers all or filtered directories for current path.
570
+
571
+ [source,ruby]
572
+ ----
573
+ Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
574
+ Pathname("/example").directories "a*" # => [Pathname("a")]
575
+ Pathname("/example").directories flag: File::FNM_DOTMATCH # => [Pathname(".."), Pathname(".")]
576
+ ----
577
+
578
+ ===== #extensions
291
579
 
292
- Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
293
- Pathname("/example").directories "a*" # => [Pathname("a")]
294
- Pathname("/example").directories flag: File::FNM_DOTMATCH # => [Pathname(".."), Pathname(".")]
580
+ Answers file extensions as an array.
295
581
 
582
+ [source,ruby]
583
+ ----
296
584
  Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
585
+ ----
586
+
587
+ ===== #files
588
+
589
+ Answers all or filtered files for current path.
590
+
591
+ [source,ruby]
592
+ ----
593
+ Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
594
+ Pathname("/example").files "*.png" # => [Pathname("a.png")]
595
+ Pathname("/example").files flag: File::FNM_DOTMATCH # => [Pathname(".ruby-version")]
596
+ ----
597
+
598
+ ===== #gsub
599
+
600
+ Same behavior as `String#gsub` but answers a path with patterns replaced with desired substitutes.
297
601
 
298
- Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
299
- Pathname("/example").files "*.png" # => [Pathname("a.png")]
300
- Pathname("/example").files flag: File::FNM_DOTMATCH # => [Pathname(".ruby-version")]
602
+ [source,ruby]
603
+ ----
604
+ Pathname("/a/path/some/path").gsub("path", "test")
605
+ # => Pathname("/a/test/some/test")
606
+
607
+ Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
608
+ # => Pathname("/test/some/test")
609
+ ----
610
+
611
+ ===== #relative_parent
612
+
613
+ Answers relative path from parent directory. This is a complement to `#relative_path_from`.
614
+
615
+ [source,ruby]
616
+ ----
617
+ Pathname("/one/two/three").relative_parent("/one") # => Pathname "two"
618
+ ----
301
619
 
302
- Pathname("/a/path/some/path").gsub("path", "test") # => Pathname("/a/test/some/test")
303
- Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test") # => Pathname("/test/some/test")
620
+ ===== #make_ancestors
304
621
 
305
- Pathname("/one/two/three").relative_parent_from("/one") # => Pathname "two"
622
+ Ensures all ancestor directories are created for a path.
306
623
 
624
+ [source,ruby]
625
+ ----
307
626
  Pathname("/one/two").make_ancestors
308
- Pathname("/one").exist? # => true
309
- Pathname("/one/two").exist? # => false
627
+ Pathname("/one").exist? # => true
628
+ Pathname("/one/two").exist? # => false
629
+ ----
630
+
631
+ ===== #mkdir
632
+
633
+ Modifies default behavior by always answering itself (even when directory exists) and not throwing
634
+ errors when directory exists.
635
+
636
+ [source,ruby]
637
+ ----
638
+ Pathname("/one").mkdir # => Pathname("/one")
639
+ Pathname("/one").mkdir.mkdir # => Pathname("/one")
640
+ ----
641
+
642
+ ===== #rewrite
643
+
644
+ When given a block, it provides the contents of the recently read file for manipulation and
645
+ immediate writing back to the same file.
310
646
 
647
+ [source,ruby]
648
+ ----
311
649
  Pathname("/test.txt").rewrite { |content| content.sub "[placeholder]", "example" }
650
+ ----
312
651
 
652
+ ===== #touch
653
+
654
+ Updates access and modification times for path. Defaults to current time.
655
+
656
+ [source,ruby]
657
+ ----
313
658
  Pathname("example.txt").touch
314
659
  Pathname("example.txt").touch at: Time.now - 1
315
660
  ----
316
661
 
317
662
  ==== String
318
663
 
664
+ ===== #first
665
+
666
+ Answers first character of a string or first set of characters if given a number.
667
+
319
668
  [source,ruby]
320
669
  ----
321
- "example".first # => "e"
322
- "example".first 4 # => "exam"
670
+ "example".first # => "e"
671
+ "example".first 4 # => "exam"
672
+ ----
673
+
674
+ ===== #last
323
675
 
324
- "instant".last # => "t"
325
- "instant".last 3 # => "ant"
676
+ Answers last character of a string or last set of characters if given a number.
326
677
 
678
+ [source,ruby]
679
+ ----
680
+ "instant".last # => "t"
681
+ "instant".last 3 # => "ant"
682
+ ----
683
+
684
+ ===== #blank?
685
+
686
+ Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`, and/or `\r`.
687
+
688
+ [source,ruby]
689
+ ----
327
690
  " \n\t\r".blank? # => true
691
+ ----
692
+
693
+ ===== #up
694
+
695
+ Answers string with only first letter upcased.
328
696
 
697
+ [source,ruby]
698
+ ----
329
699
  "example".up # => "Example"
700
+ ----
701
+
702
+ ===== #down
703
+
704
+ Answers string with only first letter downcased.
330
705
 
706
+ [source,ruby]
707
+ ----
331
708
  "EXAMPLE".down # => "eXAMPLE"
709
+ ----
710
+
711
+ ===== #indent
712
+
713
+ Answers string indented by two spaces by default.
332
714
 
715
+ [source,ruby]
716
+ ----
717
+ "example".indent # => " example"
718
+ "example".indent 0 # => "example"
719
+ "example".indent -1 # => "example"
720
+ "example".indent 2 # => " example"
721
+ "example".indent 3, padding: " " # => " example"
722
+ ----
723
+
724
+ ===== #camelcase
725
+
726
+ Answers a camelcased string.
727
+
728
+ [source,ruby]
729
+ ----
333
730
  "this_is_an_example".camelcase # => "ThisIsAnExample"
731
+ ----
732
+
733
+ ===== #snakecase
734
+
735
+ Answers a snakecased string.
334
736
 
737
+ [source,ruby]
738
+ ----
335
739
  "ThisIsAnExample".snakecase # => "this_is_an_example"
740
+ ----
741
+
742
+ ===== #titleize
743
+
744
+ Answers titleized string.
336
745
 
746
+ [source,ruby]
747
+ ----
337
748
  "ThisIsAnExample".titleize # => "This Is An Example"
749
+ ----
750
+
751
+ ===== #to_bool
752
+
753
+ Answers string as a boolean.
338
754
 
339
- "true".to_bool # => true
340
- "yes".to_bool # => true
341
- "1".to_bool # => true
342
- "".to_bool # => false
343
- "example".to_bool # => false
755
+ [source,ruby]
756
+ ----
757
+ "true".to_bool # => true
758
+ "yes".to_bool # => true
759
+ "1".to_bool # => true
760
+ "".to_bool # => false
761
+ "example".to_bool # => false
344
762
  ----
345
763
 
346
764
  ==== String IO
347
765
 
766
+ ===== #reread
767
+
768
+ Answers full string by rewinding to beginning of string and reading all content.
769
+
348
770
  [source,ruby]
349
771
  ----
350
772
  io = StringIO.new
351
773
  io.write "This is a test."
352
- io.reread # => "This is a test."
353
774
 
354
- io.reread(4) => "This"
775
+ io.reread # => "This is a test."
776
+ io.reread 4 # => "This"
355
777
 
356
778
  buffer = "".dup
357
779
  io.reread(buffer: buffer)
358
780
  buffer # => "This is a test."
359
781
  ----
360
782
 
783
+ == Development
784
+
785
+ To contribute, run:
786
+
787
+ [source,bash]
788
+ ----
789
+ git clone https://github.com/bkuhlmann/refinements.git
790
+ cd refinements
791
+ bin/setup
792
+ ----
793
+
794
+ You can also use the IRB console for direct access to all objects:
795
+
796
+ [source,bash]
797
+ ----
798
+ bin/console
799
+ ----
800
+
361
801
  == Tests
362
802
 
363
803
  To test, run:
@@ -6,6 +6,7 @@ require "refinements/big_decimals"
6
6
  require "refinements/date_times"
7
7
  require "refinements/files"
8
8
  require "refinements/hashes"
9
+ require "refinements/ios"
9
10
  require "refinements/pathnames"
10
11
  require "refinements/strings"
11
12
  require "refinements/string_ios"
@@ -11,6 +11,22 @@ module Refinements
11
11
  replace compress
12
12
  end
13
13
 
14
+ def include *elements
15
+ self + elements.flatten
16
+ end
17
+
18
+ def intersperse *elements
19
+ product([elements]).tap(&:pop).flatten.push last
20
+ end
21
+
22
+ def exclude *elements
23
+ self - elements.flatten
24
+ end
25
+
26
+ def mean
27
+ size.zero? ? 0 : sum(0) / size
28
+ end
29
+
14
30
  def ring &block
15
31
  [last, *self, first].each_cons 3, &block
16
32
  end
@@ -21,6 +21,33 @@ module Refinements
21
21
  replace except(*keys)
22
22
  end
23
23
 
24
+ # :reek:TooManyStatements
25
+ def flatten_keys prefix: nil, delimiter: "_", cast: :to_sym
26
+ fail StandardError, "Unknown cast: #{cast}." unless %i[to_sym to_s].include? cast
27
+
28
+ reduce({}) do |flat, (key, value)|
29
+ flat_key = prefix ? "#{prefix}#{delimiter}#{key}" : key
30
+
31
+ next flat.merge flat_key.public_send(cast) => value unless value.is_a? self.class
32
+
33
+ flat.merge(
34
+ recurse { value.flatten_keys prefix: flat_key, delimiter: delimiter, cast: cast }
35
+ )
36
+ end
37
+ end
38
+
39
+ def flatten_keys! prefix: nil, delimiter: "_", cast: :to_sym
40
+ replace flatten_keys(prefix: prefix, delimiter: delimiter, cast: cast)
41
+ end
42
+
43
+ def stringify_keys
44
+ reduce({}) { |hash, (key, value)| hash.merge key.to_s => value }
45
+ end
46
+
47
+ def stringify_keys!
48
+ replace stringify_keys
49
+ end
50
+
24
51
  def symbolize_keys
25
52
  reduce({}) { |hash, (key, value)| hash.merge key.to_sym => value }
26
53
  end
@@ -30,13 +57,9 @@ module Refinements
30
57
  end
31
58
 
32
59
  def deep_merge other
33
- dup.deep_merge! other
34
- end
35
-
36
- def deep_merge! other
37
60
  clazz = self.class
38
61
 
39
- merge! other do |_key, this_value, other_value|
62
+ merge other do |_key, this_value, other_value|
40
63
  if this_value.is_a?(clazz) && other_value.is_a?(clazz)
41
64
  this_value.deep_merge other_value
42
65
  else
@@ -45,12 +68,24 @@ module Refinements
45
68
  end
46
69
  end
47
70
 
71
+ def deep_merge! other
72
+ replace deep_merge(other)
73
+ end
74
+
75
+ def deep_stringify_keys
76
+ recurse(&:stringify_keys)
77
+ end
78
+
79
+ def deep_stringify_keys!
80
+ replace deep_stringify_keys
81
+ end
82
+
48
83
  def deep_symbolize_keys
49
84
  recurse(&:symbolize_keys)
50
85
  end
51
86
 
52
87
  def deep_symbolize_keys!
53
- recurse(&:symbolize_keys!)
88
+ replace deep_symbolize_keys
54
89
  end
55
90
 
56
91
  def recurse &block
@@ -75,12 +110,12 @@ module Refinements
75
110
 
76
111
  def reverse_merge other
77
112
  warn "[DEPRECATION]: #reverse_merge is deprecated, use #merge instead."
78
- other.merge self
113
+ merge(other) { |_key, old_value, _new_value| old_value }
79
114
  end
80
115
 
81
116
  def reverse_merge! other
82
117
  warn "[DEPRECATION]: #reverse_merge! is deprecated, use #merge! instead."
83
- merge!(other) { |_key, old_value, _new_value| old_value }
118
+ replace reverse_merge(other)
84
119
  end
85
120
 
86
121
  def use &block
@@ -5,7 +5,7 @@ module Refinements
5
5
  module Identity
6
6
  NAME = "refinements"
7
7
  LABEL = "Refinements"
8
- VERSION = "7.7.0"
8
+ VERSION = "7.12.0"
9
9
  VERSION_LABEL = "#{LABEL} #{VERSION}"
10
10
  end
11
11
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Refinements
4
+ module IOs
5
+ refine IO.singleton_class do
6
+ def void
7
+ new(sysopen("/dev/null", "w+")).then do |io|
8
+ return io unless block_given?
9
+
10
+ yield io
11
+ io.tap(&:close)
12
+ end
13
+ end
14
+ end
15
+
16
+ refine IO do
17
+ def squelch &block
18
+ self.class.void.then { |void| redirect(void, &block) }
19
+ end
20
+
21
+ def redirect other
22
+ return self unless block_given?
23
+
24
+ backup = dup
25
+ reopen other
26
+ yield self
27
+ reopen backup
28
+ end
29
+
30
+ def reread length = nil, buffer: nil
31
+ tap(&:rewind).read length, buffer
32
+ end
33
+ end
34
+ end
35
+ end
@@ -39,8 +39,14 @@ module Refinements
39
39
  self.class.new to_s.gsub(pattern, replacement)
40
40
  end
41
41
 
42
- def relative_parent_from root
43
- relative_path_from(root).parent
42
+ def relative_parent root_dir
43
+ relative_path_from(root_dir).parent
44
+ end
45
+
46
+ def relative_parent_from root_dir
47
+ warn "[DEPRECATION]: Pathname#relative_parent_from is deprecated, " \
48
+ "use Pathname#relative_parent instead."
49
+ relative_parent root_dir
44
50
  end
45
51
 
46
52
  def make_ancestors
@@ -48,6 +54,12 @@ module Refinements
48
54
  self
49
55
  end
50
56
 
57
+ # rubocop:disable Style/RedundantSelf
58
+ def mkdir
59
+ self.exist? ? self : super and self
60
+ end
61
+ # rubocop:enable Style/RedundantSelf
62
+
51
63
  def rewrite
52
64
  read.then { |content| write yield(content) if block_given? }
53
65
  self
@@ -50,6 +50,12 @@ module Refinements
50
50
  first.downcase + self[1, size]
51
51
  end
52
52
 
53
+ def indent multiplier = 1, padding: " "
54
+ return self if multiplier.negative?
55
+
56
+ padding * multiplier + self
57
+ end
58
+
53
59
  def camelcase
54
60
  return up unless match? DELIMITERS
55
61
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: refinements
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.7.0
4
+ version: 7.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -28,7 +28,7 @@ cert_chain:
28
28
  2XV8FRa7/JimI07sPLC13eLY3xd/aYTi85Z782KIA4j0G8XEEWAX0ouBhlXPocZv
29
29
  QWc=
30
30
  -----END CERTIFICATE-----
31
- date: 2020-08-05 00:00:00.000000000 Z
31
+ date: 2020-11-04 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler-audit
@@ -44,6 +44,20 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '0.6'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler-leak
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.2'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.2'
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: gemsmith
49
63
  requirement: !ruby/object:Gem::Requirement
@@ -162,14 +176,14 @@ dependencies:
162
176
  requirements:
163
177
  - - "~>"
164
178
  - !ruby/object:Gem::Version
165
- version: '0.83'
179
+ version: '0.89'
166
180
  type: :development
167
181
  prerelease: false
168
182
  version_requirements: !ruby/object:Gem::Requirement
169
183
  requirements:
170
184
  - - "~>"
171
185
  - !ruby/object:Gem::Version
172
- version: '0.83'
186
+ version: '0.89'
173
187
  - !ruby/object:Gem::Dependency
174
188
  name: rubocop-performance
175
189
  requirement: !ruby/object:Gem::Requirement
@@ -218,14 +232,14 @@ dependencies:
218
232
  requirements:
219
233
  - - "~>"
220
234
  - !ruby/object:Gem::Version
221
- version: '0.18'
235
+ version: '0.19'
222
236
  type: :development
223
237
  prerelease: false
224
238
  version_requirements: !ruby/object:Gem::Requirement
225
239
  requirements:
226
240
  - - "~>"
227
241
  - !ruby/object:Gem::Version
228
- version: '0.18'
242
+ version: '0.19'
229
243
  description:
230
244
  email:
231
245
  - brooke@alchemists.io
@@ -244,6 +258,7 @@ files:
244
258
  - lib/refinements/files.rb
245
259
  - lib/refinements/hashes.rb
246
260
  - lib/refinements/identity.rb
261
+ - lib/refinements/ios.rb
247
262
  - lib/refinements/pathnames.rb
248
263
  - lib/refinements/string_ios.rb
249
264
  - lib/refinements/strings.rb
metadata.gz.sig CHANGED
Binary file