refinements 7.6.0 → 7.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b33464363d548d0cc888f7f3b1efac924eb2490a3846353589d892900d03de0d
4
- data.tar.gz: da1d401505c092c0b2e8850f476affb1932b79db770b4f11c263300e208f3457
3
+ metadata.gz: a5a299dfa7a3355d5cb068cc6638ed41ca9ac4980ed69f6aabb0e1608cc96e95
4
+ data.tar.gz: 4b12b5237fc97f5609677b8f010156ef9a1d00d5004fe48d1cfa4d32df15f602
5
5
  SHA512:
6
- metadata.gz: 6c8072c3a3d8348e871ed72c7519295fb4ade95e2463bf56424f42689909dc7113805fbc817012196a395442af811f4d215a5bc89cf8952bd4506b0a4cd49536
7
- data.tar.gz: 7797a5f506eb95d5999234c6e506ef9b0f4b949cfa41f831fcf883425fea7cb3da3b3ff3ef72f5c218236c006c38aeb2a957127ccf5177748fc3cac4291498ba
6
+ metadata.gz: 248e66b7141e5e29f68c60aae0a3eac49934830053e9e5ce7082b0164e63b42ee9c536d8b46d4f86c7f570a85f1838415939b5955d66bd93f5df2eeefe66a5d7
7
+ data.tar.gz: 399fc17b0857236d4d58668857d690ddb63deba8fd9de10c372f2d3618c93edb31a9574f166c01d6aee884d4d856f067dfc2b68eddedb80d90d70a656595d82d
@@ -1,2 +1,2 @@
1
- ���8XoF���A�>����L�d�oG)KV���h���u�o���ڊziˍ�`����\��~R�U��
2
- ǧ6�kQ)õ���;+���GOD��tw�ůlV�� j���i��z`���)&�&�`�t'������rY��O���vb�A�/b]���?B_DR#S��V�w��c�(�C�ӯn�?r�։������VCSw){Їa$c~#��} Ow&�#;�">��"B�Cm��l9��=i�o��
1
+ ^%���b�ץ���nyo��Df���Zv���D��zK�w��OVbO
2
+ ��p��V�/x��W��:"�Tz.�\�͙�*卪�%�NՇfY�!�YH��(i��M��J4��Ļ����͗�~-w�y�(���&^K*L�� {_�2ɻ�W��Ie%���ڳqH��J��9~t��{WdzؘRN\H�����q/Cyy��h�� U V�B��� �����X�����]��~�uA� ,N
data.tar.gz.sig CHANGED
Binary file
@@ -9,66 +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
- ** `#relative_parent_from` - Answers relative path from parent directory. This is a complement to
56
- `#relative_path_from`.
57
- ** `#make_ancestors` - Ensures all ancestor directories are created for a path.
58
- ** `#rewrite` - When given a block, it provides the contents of the recently read file for
59
- manipulation and immediate writing back to the same file.
60
- ** `#touch` - Updates access and modification times for path. Defaults to current time.
61
- * *Strings*:
62
- ** `#first` - Answers first character of a string or first set of characters if given a number.
63
- ** `#last` - Answers last character of a string or last set of characters if given a number.
64
- ** `#blank?` - Answers `true`/`false` based on whether string is blank or not
65
- (i.e. `<space>`, `\n`, `\t`, `\r`).
66
- ** `#up` - Answers string with only first letter upcased.
67
- ** `#down` - Answers string with only first letter downcased.
68
- ** `#camelcase` - Answers a camelcased string.
69
- ** `#snakecase` - Answers a snakecased string.
70
- ** `#titleize` - Answers titleized string.
71
- ** `#to_bool` - Answers string as a boolean.
18
+ Enhances the following objects:
19
+
20
+ * Array
21
+ * BigDecimal
22
+ * DateTime
23
+ * File
24
+ * Hash
25
+ * IO
26
+ * Pathname
27
+ * String
28
+ * StringIO
72
29
 
73
30
  == Requirements
74
31
 
@@ -123,7 +80,7 @@ If all refinements are not desired, add the following to your `+Gemfile+` instea
123
80
  gem "refinements", require: false
124
81
  ----
125
82
 
126
- then require the specific refinement, as needed. Example:
83
+ ...then require the specific refinement, as needed. Example:
127
84
 
128
85
  [source,ruby]
129
86
  ----
@@ -132,13 +89,16 @@ require "refinements/big_decimals"
132
89
  require "refinements/date_times"
133
90
  require "refinements/files"
134
91
  require "refinements/hashes"
92
+ require "refinements/ios"
135
93
  require "refinements/pathnames"
136
94
  require "refinements/strings"
95
+ require "refinements/string_ios"
137
96
  ----
138
97
 
139
98
  === Using
140
99
 
141
- Much like including/extending a module, you’ll need modify your object(s) to use the refinement(s):
100
+ Much like including/extending a module, you’ll need to modify your object(s) to use the
101
+ refinement(s):
142
102
 
143
103
  [source,ruby]
144
104
  ----
@@ -148,8 +108,10 @@ class Example
148
108
  using Refinements::DateTimes
149
109
  using Refinements::Files
150
110
  using Refinements::Hashes
111
+ using Refinements::IOs
151
112
  using Refinements::Pathnames
152
113
  using Refinements::Strings
114
+ using Refinements::StringIOs
153
115
  end
154
116
  ----
155
117
 
@@ -159,19 +121,58 @@ The following sections demonstrate how each refinement enriches your objects wit
159
121
 
160
122
  ==== Array
161
123
 
124
+ ===== #compress
125
+
126
+ Removes `nil` and empty values without mutating itself.
127
+
162
128
  [source,ruby]
163
129
  ----
164
130
  example = ["An", nil, "", "Example"]
165
- example.compress # => ["An", "Example"]
166
- example # => ["An", nil, "", "Example"]
131
+ example.compress # => ["An", "Example"]
132
+ example # => ["An", nil, "", "Example"]
133
+ ----
167
134
 
135
+ ===== #compress!
136
+
137
+ Removes `nil` and empty values while mutating itself.
138
+
139
+ [source,ruby]
140
+ ----
168
141
  example = ["An", nil, "", "Example"]
169
- example.compress! # => ["An", "Example"]
170
- example # => ["An", "Example"]
142
+ example.compress! # => ["An", "Example"]
143
+ example # => ["An", "Example"]
144
+ ----
171
145
 
146
+ ===== #include
147
+
148
+ Adds given array or elements without mutating itself.
149
+
150
+ [source,ruby]
151
+ ----
152
+ [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
153
+ [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
154
+ ----
155
+
156
+ ===== #exclude
157
+
158
+ Removes given array or elements without mutating itself.
159
+
160
+ [source,ruby]
161
+ ----
162
+ [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
163
+ [1, 2, 3, 4, 5].exclude 4, 5 # => [1, 2, 3]
164
+ ----
165
+
166
+ ===== #ring
167
+
168
+ Answers a circular array which can enumerate before, current, after elements.
169
+
170
+ [source,ruby]
171
+ ----
172
172
  example = [1, 2, 3]
173
173
  example.ring # => #<Enumerator: ...>
174
174
  example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
175
+
175
176
  # [3 1 2]
176
177
  # [1 2 3]
177
178
  # [2 3 1]
@@ -179,6 +180,10 @@ example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
179
180
 
180
181
  ==== Big Decimal
181
182
 
183
+ ===== #inspect
184
+
185
+ Allows one to inspect a big decimal with numeric representation.
186
+
182
187
  [source,ruby]
183
188
  ----
184
189
  BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
@@ -186,6 +191,10 @@ BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
186
191
 
187
192
  ==== DateTime
188
193
 
194
+ ===== .utc
195
+
196
+ Answers new DateTime object for current UTC date/time.
197
+
189
198
  [source,ruby]
190
199
  ----
191
200
  DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867000n),+0s,2299161j)>
@@ -193,6 +202,11 @@ DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867
193
202
 
194
203
  ==== File
195
204
 
205
+ ===== .rewrite
206
+
207
+ When given a file path and a block, it provides the contents of the recently read file for
208
+ manipulation and immediate writing back to the same file.
209
+
196
210
  [source,ruby]
197
211
  ----
198
212
  File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
@@ -200,138 +214,556 @@ File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
200
214
 
201
215
  ==== Hash
202
216
 
217
+ ===== .infinite
218
+
219
+ Answers new hash where missing keys, even deeply nested, answer an empty hash.
220
+
203
221
  [source,ruby]
204
222
  ----
205
223
  example = Hash.infinite
206
- example[:a] # => {}
207
- example[:a][:b][:c] # => {}
224
+ example[:a] # => {}
225
+ example[:a][:b][:c] # => {}
226
+ ----
208
227
 
228
+ ===== .with_default
229
+
230
+ Answers new hash where every top-level missing key has the same default value.
231
+
232
+ [source,ruby]
233
+ ----
209
234
  example = Hash.with_default ""
210
235
  example[:a] # => ""
236
+
211
237
  example = Hash.with_default []
212
238
  example[:b] # => []
239
+ ----
240
+
241
+ ===== #except
242
+
243
+ Answers new hash with given keys removed without mutating itself.
213
244
 
245
+ [source,ruby]
246
+ ----
214
247
  example = {a: 1, b: 2, c: 3}
215
- example.except :a, :b # => {c: 3}
216
- example # => {a: 1, b: 2, c: 3}
248
+ example.except :a, :b # => {c: 3}
249
+ example # => {a: 1, b: 2, c: 3}
250
+ ----
251
+
252
+ ===== #except!
253
+
254
+ Answers new hash with given keys removed while mutating itself.
217
255
 
256
+ [source,ruby]
257
+ ----
218
258
  example = {a: 1, b: 2, c: 3}
219
- example.except! :a, :b # => {c: 3}
220
- example # => {c: 3}
259
+ example.except! :a, :b # => {c: 3}
260
+ example # => {c: 3}
261
+ ----
262
+
263
+ ===== #flatten_keys
264
+
265
+ Flattens nested keys as top-level keys without mutating itself. Does not handle nested arrays,
266
+ though.
267
+
268
+ [source,ruby]
269
+ ----
270
+ {a: {b: 1}}.flatten_keys prefix: :test # => {test_a_b: 1}
271
+ {a: {b: 1}}.flatten_keys delimiter: :| # => {:"a|b" => 1}
272
+
273
+ {a: {b: 1}}.flatten_keys cast: :to_s # => {"a_b" => 1}
274
+ {"a" => {"b" => 1}}.flatten_keys cast: :to_sym # => {a_b: 1}
275
+
276
+ example = {a: {b: 1}}
277
+ example.flatten_keys # => {a_b: 1}
278
+ example # => {a: {b: 1}}
279
+ ----
280
+
281
+ ===== #flatten_keys!
282
+
283
+ Flattens nested keys as top-level keys while mutating itself. Does not handle nested arrays,
284
+ though.
285
+
286
+ [source,ruby]
287
+ ----
288
+ example = {a: {b: 1}}
289
+ example.flatten_keys! # => {a_b: 1}
290
+ example # => {a_b: 1}
291
+ ----
292
+
293
+ ===== #stringify_keys
294
+
295
+ Converts keys to strings without mutating itself.
296
+
297
+ [source,ruby]
298
+ ----
299
+ example = {a: 1, b: 2}
300
+ example.stringify_keys # => {"a" => 1, "b" => 2}
301
+ example # => {a: 1, b: 2}
302
+ ----
221
303
 
304
+ ===== #stringify_keys!
305
+
306
+ Converts keys to strings while mutating itself.
307
+
308
+ [source,ruby]
309
+ ----
310
+ example = {a: 1, b: 2}
311
+ example.stringify_keys! # => {"a" => 1, "b" => 2}
312
+ example # => {"a" => 1, "b" => 2}
313
+ ----
314
+
315
+ ===== #symbolize_keys
316
+
317
+ Converts keys to symbols without mutating itself.
318
+
319
+ [source,ruby]
320
+ ----
222
321
  example = {"a" => 1, "b" => 2}
223
- example.symbolize_keys # => {a: 1, b: 2}
224
- example # => {"a" => 1, "b" => 2}
322
+ example.symbolize_keys # => {a: 1, b: 2}
323
+ example # => {"a" => 1, "b" => 2}
324
+ ----
325
+
326
+ ===== #symbolize_keys!
225
327
 
328
+ Converts keys to symbols while mutating itself.
329
+
330
+ [source,ruby]
331
+ ----
226
332
  example = {"a" => 1, "b" => 2}
227
- example.symbolize_keys! # => {a: 1, b: 2}
228
- example # => {a: 1, b: 2}
333
+ example.symbolize_keys! # => {a: 1, b: 2}
334
+ example # => {a: 1, b: 2}
335
+ ----
229
336
 
230
- example = {a: 1, b: 2, c: 3}
231
- example.slice :a, :c # => {a: 1, c: 3}
232
- example # => {a: 1, b: 2, c: 3}
337
+ ===== #deep_merge
233
338
 
234
- example = {a: 1, b: 2, c: 3}
235
- example.slice! :a, :c # => {a: 1, c: 3}
236
- example # => {a: 1, c: 3}
339
+ Merges deeply nested hashes together without mutating itself.
237
340
 
341
+ [source,ruby]
342
+ ----
238
343
  example = {a: "A", b: {one: "One", two: "Two"}}
239
- example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
240
- example # => {a: "A", b: {one: "One", two: "Two"}}
344
+ example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
345
+ example # => {a: "A", b: {one: "One", two: "Two"}}
346
+ ----
347
+
348
+ ===== #deep_merge!
349
+
350
+ Merges deeply nested hashes together while mutating itself.
241
351
 
352
+ [source,ruby]
353
+ ----
242
354
  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: 1, two: "Two"}}
355
+ example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
356
+ example # => {a: "A", b: {one: 1, two: "Two"}}
357
+ ----
358
+
359
+ ===== #deep_stringify_keys
245
360
 
361
+ Stringifies keys of nested hash without mutating itself. Does not handle nested arrays, though.
362
+
363
+ [source,ruby]
364
+ ----
365
+ example = {a: {b: 2}}
366
+ example.deep_stringify_keys # => {"a" => {"b" => 1}}
367
+ example # => {a: {b: 2}}
368
+ ----
369
+
370
+ ===== #deep_stringify_keys!
371
+
372
+ Stringifies keys of nested hash while mutating itself. Does not handle nested arrays, though.
373
+
374
+ [source,ruby]
375
+ ----
376
+ example = {a: {b: 2}}
377
+ example.deep_stringify_keys! # => {"a" => {"b" => 1}}
378
+ example # => {"a" => {"b" => 1}}
379
+ ----
380
+
381
+ ===== #deep_symbolize_keys
382
+
383
+ Symbolizes keys of nested hash without mutating itself. Does not handle nested arrays, though.
384
+
385
+ [source,ruby]
386
+ ----
246
387
  example = {"a" => {"b" => 2}}
247
- example.deep_symbolize_keys # => {a: {b: 1}}
248
- example # => {"a" => {"b" => 2}}
388
+ example.deep_symbolize_keys # => {a: {b: 1}}
389
+ example # => {"a" => {"b" => 2}}
390
+ ----
391
+
392
+ ===== #deep_symbolize_keys!
393
+
394
+ Symbolizes keys of nested hash while mutating itself. Does not handle nested arrays, though.
249
395
 
396
+ [source,ruby]
397
+ ----
250
398
  example = {"a" => {"b" => 2}}
251
- example.deep_symbolize_keys! # => {a: {b: 1}}
252
- example # => {a: {b: 1}}
399
+ example.deep_symbolize_keys! # => {a: {b: 1}}
400
+ example # => {a: {b: 1}}
401
+ ----
402
+
403
+ ===== #recurse
404
+
405
+ Recursively iterates over the hash and any hash value by applying the given block to it. Does not
406
+ handle nested arrays, though.
253
407
 
408
+ [source,ruby]
409
+ ----
254
410
  example = {"a" => {"b" => 1}}
255
- example.recurse(&:symbolize_keys) # => {a: {b: 1}}
256
- example.recurse(&:invert) # => {{"b" => 1} => "a"}
411
+ example.recurse(&:symbolize_keys) # => {a: {b: 1}}
412
+ example.recurse(&:invert) # => {{"b" => 1} => "a"}
413
+ ----
414
+
415
+ ===== #rekey
257
416
 
417
+ Transforms keys per mapping (size of mapping can vary) without mutating itself.
418
+
419
+ [source,ruby]
420
+ ----
258
421
  example = {a: 1, b: 2, c: 3}
259
- example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
260
- example # => {a: 1, b: 2, c: 3}
422
+ example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
423
+ example # => {a: 1, b: 2, c: 3}
424
+ ----
425
+
426
+ ===== #rekey!
261
427
 
428
+ Transforms keys per mapping (size of mapping can vary) while mutating itself.
429
+
430
+ [source,ruby]
431
+ ----
262
432
  example = {a: 1, b: 2, c: 3}
263
- example.rekey! a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
264
- example # => {amber: 1, blue: 2, c: 3}
433
+ example.rekey! a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
434
+ example # => {amber: 1, blue: 2, c: 3}
435
+ ----
265
436
 
437
+ ===== #reverse_merge
438
+
439
+ Merges calling hash into passed in hash without mutating itself.
440
+
441
+ [source,ruby]
442
+ ----
266
443
  example = {a: 1, b: 2}
267
- example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
268
- example # => {a: 1, b: 2}
444
+ example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
445
+ example # => {a: 1, b: 2}
446
+ ----
269
447
 
448
+ ===== #reverse_merge!
449
+
450
+ Merges calling hash into passed in hash while mutating itself.
451
+
452
+ [source,ruby]
453
+ ----
270
454
  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, c: 3}
455
+ example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
456
+ example # => {a: 1, b: 2, c: 3}
457
+ ----
458
+
459
+ ===== #use
460
+
461
+ Passes each hash value as a block argument for further processing.
273
462
 
463
+ [source,ruby]
464
+ ----
274
465
  example = {unit: "221B", street: "Baker Street", city: "London", country: "UK"}
275
466
  example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
276
467
  ----
277
468
 
469
+ ==== IO
470
+
471
+ ===== .void
472
+
473
+ Answers an IO stream which points to `/dev/null` in order to ignore any reads or writes to the
474
+ stream. When given a block, the stream will automatically close upon block exit. When not given a
475
+ block, you'll need to close the stream manually.
476
+
477
+ [source,ruby]
478
+ ----
479
+ io = IO.void
480
+ io.closed? # => false
481
+
482
+ io = IO.void { |void| void.write "nevermore" }
483
+ io.closed? # => true
484
+ ----
485
+
486
+ ===== #squelch
487
+
488
+ Temporarily ignores any reads/writes for current stream for all code executed within the block. When
489
+ not given a block, it answers itself.
490
+
491
+ [source,ruby]
492
+ ----
493
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
494
+ io.squelch { io.write "Test" }
495
+ io.reread # => ""
496
+ ----
497
+
498
+ ===== #redirect
499
+
500
+ Redirects current stream to other stream when given a block. Without a block, the original stream is
501
+ answered instead.
502
+
503
+ [source,ruby]
504
+ ----
505
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
506
+ other = IO.new IO.sysopen(Pathname("other.txt").to_s, "w+")
507
+
508
+ io.redirect other # => `io`
509
+
510
+ io.redirect(other) { |stream| stream.write "test" }
511
+ .close # => ""
512
+ other.close # => "test"
513
+ ----
514
+
515
+ ===== #reread
516
+
517
+ Answers full stream by rewinding to beginning of stream and reading all content.
518
+
519
+ [source,ruby]
520
+ ----
521
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
522
+ io.write "This is a test."
523
+
524
+ io.reread # => "This is a test."
525
+ io.reread 4 # => "This"
526
+
527
+ buffer = "".dup
528
+ io.reread(buffer: buffer)
529
+ buffer # => "This is a test."
530
+ ----
531
+
278
532
  ==== Pathname
279
533
 
534
+ ===== Pathname
535
+
536
+ Enhances the conversion function -- refined from `Kernel` -- which casts `nil` into a pathname in
537
+ order to avoid: `TypeError (no implicit conversion of nil into String)`. The pathname is still
538
+ invalid but at least you have an instance of `Pathname`, which behaves like a _Null Object_, that
539
+ can still be used to construct a valid path.
540
+
280
541
  [source,ruby]
281
542
  ----
282
543
  Pathname(nil) # => Pathname("")
544
+ ----
545
+
546
+ ===== #name
547
+
548
+ Answers file name without extension.
283
549
 
550
+ [source,ruby]
551
+ ----
284
552
  Pathname("example.txt").name # => Pathname("example")
553
+ ----
554
+
555
+ ===== #copy
285
556
 
557
+ Copies file from current location to new location.
558
+
559
+ [source,ruby]
560
+ ----
286
561
  Pathname("input.txt").copy Pathname("output.txt")
562
+ ----
563
+
564
+ ===== #directories
565
+
566
+ Answers all or filtered directories for current path.
567
+
568
+ [source,ruby]
569
+ ----
570
+ Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
571
+ Pathname("/example").directories "a*" # => [Pathname("a")]
572
+ Pathname("/example").directories flag: File::FNM_DOTMATCH # => [Pathname(".."), Pathname(".")]
573
+ ----
574
+
575
+ ===== #extensions
287
576
 
288
- Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
289
- Pathname("/example").directories "a*" # => [Pathname("a")]
577
+ Answers file extensions as an array.
290
578
 
579
+ [source,ruby]
580
+ ----
291
581
  Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
582
+ ----
583
+
584
+ ===== #files
585
+
586
+ Answers all or filtered files for current path.
587
+
588
+ [source,ruby]
589
+ ----
590
+ Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
591
+ Pathname("/example").files "*.png" # => [Pathname("a.png")]
592
+ Pathname("/example").files flag: File::FNM_DOTMATCH # => [Pathname(".ruby-version")]
593
+ ----
594
+
595
+ ===== #gsub
596
+
597
+ Same behavior as `String#gsub` but answers a path with patterns replaced with desired substitutes.
598
+
599
+ [source,ruby]
600
+ ----
601
+ Pathname("/a/path/some/path").gsub("path", "test")
602
+ # => Pathname("/a/test/some/test")
603
+
604
+ Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
605
+ # => Pathname("/test/some/test")
606
+ ----
607
+
608
+ ===== #relative_parent
609
+
610
+ Answers relative path from parent directory. This is a complement to `#relative_path_from`.
292
611
 
293
- Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
294
- Pathname("/example").files "*.png" # => [Pathname("a.png")]
612
+ [source,ruby]
613
+ ----
614
+ Pathname("/one/two/three").relative_parent("/one") # => Pathname "two"
615
+ ----
295
616
 
296
- Pathname("/one/two/three").relative_parent_from("/one") # => Pathname "two"
617
+ ===== #make_ancestors
297
618
 
619
+ Ensures all ancestor directories are created for a path.
620
+
621
+ [source,ruby]
622
+ ----
298
623
  Pathname("/one/two").make_ancestors
299
- Pathname("/one").exist? # => true
300
- Pathname("/one/two").exist? # => false
624
+ Pathname("/one").exist? # => true
625
+ Pathname("/one/two").exist? # => false
626
+ ----
627
+
628
+ ===== #rewrite
301
629
 
630
+ When given a block, it provides the contents of the recently read file for manipulation and
631
+ immediate writing back to the same file.
632
+
633
+ [source,ruby]
634
+ ----
302
635
  Pathname("/test.txt").rewrite { |content| content.sub "[placeholder]", "example" }
636
+ ----
637
+
638
+ ===== #touch
303
639
 
640
+ Updates access and modification times for path. Defaults to current time.
641
+
642
+ [source,ruby]
643
+ ----
304
644
  Pathname("example.txt").touch
305
645
  Pathname("example.txt").touch at: Time.now - 1
306
646
  ----
307
647
 
308
648
  ==== String
309
649
 
650
+ ===== #first
651
+
652
+ Answers first character of a string or first set of characters if given a number.
653
+
310
654
  [source,ruby]
311
655
  ----
312
- "example".first # => "e"
313
- "example".first 4 # => "exam"
656
+ "example".first # => "e"
657
+ "example".first 4 # => "exam"
658
+ ----
314
659
 
315
- "instant".last # => "t"
316
- "instant".last 3 # => "ant"
660
+ ===== #last
317
661
 
662
+ Answers last character of a string or last set of characters if given a number.
663
+
664
+ [source,ruby]
665
+ ----
666
+ "instant".last # => "t"
667
+ "instant".last 3 # => "ant"
668
+ ----
669
+
670
+ ===== #blank?
671
+
672
+ Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`, and/or `\r`.
673
+
674
+ [source,ruby]
675
+ ----
318
676
  " \n\t\r".blank? # => true
677
+ ----
678
+
679
+ ===== #up
680
+
681
+ Answers string with only first letter upcased.
319
682
 
683
+ [source,ruby]
684
+ ----
320
685
  "example".up # => "Example"
686
+ ----
687
+
688
+ ===== #down
321
689
 
690
+ Answers string with only first letter downcased.
691
+
692
+ [source,ruby]
693
+ ----
322
694
  "EXAMPLE".down # => "eXAMPLE"
695
+ ----
696
+
697
+ ===== #indent
698
+
699
+ Answers string indented by two spaces by default.
700
+
701
+ [source,ruby]
702
+ ----
703
+ "example".indent # => " example"
704
+ "example".indent 0 # => "example"
705
+ "example".indent -1 # => "example"
706
+ "example".indent 2 # => " example"
707
+ "example".indent 3, padding: " " # => " example"
708
+ ----
709
+
710
+ ===== #camelcase
323
711
 
712
+ Answers a camelcased string.
713
+
714
+ [source,ruby]
715
+ ----
324
716
  "this_is_an_example".camelcase # => "ThisIsAnExample"
717
+ ----
718
+
719
+ ===== #snakecase
325
720
 
721
+ Answers a snakecased string.
722
+
723
+ [source,ruby]
724
+ ----
326
725
  "ThisIsAnExample".snakecase # => "this_is_an_example"
726
+ ----
327
727
 
728
+ ===== #titleize
729
+
730
+ Answers titleized string.
731
+
732
+ [source,ruby]
733
+ ----
328
734
  "ThisIsAnExample".titleize # => "This Is An Example"
735
+ ----
736
+
737
+ ===== #to_bool
738
+
739
+ Answers string as a boolean.
740
+
741
+ [source,ruby]
742
+ ----
743
+ "true".to_bool # => true
744
+ "yes".to_bool # => true
745
+ "1".to_bool # => true
746
+ "".to_bool # => false
747
+ "example".to_bool # => false
748
+ ----
749
+
750
+ ==== String IO
751
+
752
+ ===== #reread
753
+
754
+ Answers full string by rewinding to beginning of string and reading all content.
755
+
756
+ [source,ruby]
757
+ ----
758
+ io = StringIO.new
759
+ io.write "This is a test."
760
+
761
+ io.reread # => "This is a test."
762
+ io.reread 4 # => "This"
329
763
 
330
- "true".to_bool # => true
331
- "yes".to_bool # => true
332
- "1".to_bool # => true
333
- "".to_bool # => false
334
- "example".to_bool # => false
764
+ buffer = "".dup
765
+ io.reread(buffer: buffer)
766
+ buffer # => "This is a test."
335
767
  ----
336
768
 
337
769
  == Tests
@@ -6,5 +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"
12
+ require "refinements/string_ios"
@@ -11,6 +11,14 @@ module Refinements
11
11
  replace compress
12
12
  end
13
13
 
14
+ def include *elements
15
+ self + elements.flatten
16
+ end
17
+
18
+ def exclude *elements
19
+ self - elements.flatten
20
+ end
21
+
14
22
  def ring &block
15
23
  [last, *self, first].each_cons 3, &block
16
24
  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.6.0"
8
+ VERSION = "7.11.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
@@ -23,20 +23,30 @@ module Refinements
23
23
  self
24
24
  end
25
25
 
26
- def directories pattern = "*"
27
- glob(pattern).select(&:directory?).sort
26
+ def directories pattern = "*", flag: File::FNM_SYSCASE
27
+ glob(pattern, flag).select(&:directory?).sort
28
28
  end
29
29
 
30
30
  def extensions
31
31
  basename.to_s.split(/(?=\.)+/).tap(&:shift)
32
32
  end
33
33
 
34
- def files pattern = "*"
35
- glob(pattern).select(&:file?).sort
34
+ def files pattern = "*", flag: File::FNM_SYSCASE
35
+ glob(pattern, flag).select(&:file?).sort
36
36
  end
37
37
 
38
- def relative_parent_from root
39
- relative_path_from(root).parent
38
+ def gsub pattern, replacement
39
+ self.class.new to_s.gsub(pattern, replacement)
40
+ end
41
+
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
40
50
  end
41
51
 
42
52
  def make_ancestors
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Refinements
6
+ module StringIOs
7
+ refine StringIO do
8
+ def reread length = nil, buffer: nil
9
+ tap(&:rewind).read length, buffer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,9 +2,12 @@
2
2
 
3
3
  module Refinements
4
4
  module Strings
5
+ DELIMITERS = %r([a-z][A-Z]|\s*-\s*|\s*/\s*|\s*:+\s*|\s*_\s*|\s+).freeze
6
+
5
7
  refine String.singleton_class do
6
8
  def delimiters
7
- %r([a-z][A-Z]|\s*-\s*|\s*/\s*|\s*:+\s*|\s*_\s*|\s+)
9
+ warn "[DEPRECATION]: .delimiters is deprecated, use DELIMITERS instead."
10
+ DELIMITERS
8
11
  end
9
12
  end
10
13
 
@@ -47,8 +50,14 @@ module Refinements
47
50
  first.downcase + self[1, size]
48
51
  end
49
52
 
53
+ def indent multiplier = 1, padding: " "
54
+ return self if multiplier.negative?
55
+
56
+ padding * multiplier + self
57
+ end
58
+
50
59
  def camelcase
51
- return up unless match? self.class.delimiters
60
+ return up unless match? DELIMITERS
52
61
 
53
62
  split(%r(\s*-\s*|\s*/\s*|\s*:+\s*)).then { |parts| combine parts, :up, "::" }
54
63
  .then { |text| text.split(/\s*_\s*|\s+/) }
@@ -56,7 +65,7 @@ module Refinements
56
65
  end
57
66
 
58
67
  def snakecase
59
- return downcase unless match? self.class.delimiters
68
+ return downcase unless match? DELIMITERS
60
69
 
61
70
  split(%r(\s*-\s*|\s*/\s*|\s*:+\s*)).then { |parts| combine parts, :down, "/" }
62
71
  .then { |text| text.split(/(?=[A-Z])|\s*_\s*|\s+/) }
@@ -64,7 +73,7 @@ module Refinements
64
73
  end
65
74
 
66
75
  def titleize
67
- return capitalize unless match? self.class.delimiters
76
+ return capitalize unless match? DELIMITERS
68
77
 
69
78
  split(/(?=[A-Z])|\s*_\s*|\s*-\s*|\s+/).then { |parts| combine parts, :up, " " }
70
79
  .then { |text| text.split %r(\s*/\s*|\s*:+\s*) }
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.6.0
4
+ version: 7.11.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-07-04 00:00:00.000000000 Z
31
+ date: 2020-10-06 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler-audit
@@ -162,14 +162,14 @@ dependencies:
162
162
  requirements:
163
163
  - - "~>"
164
164
  - !ruby/object:Gem::Version
165
- version: '0.83'
165
+ version: '0.89'
166
166
  type: :development
167
167
  prerelease: false
168
168
  version_requirements: !ruby/object:Gem::Requirement
169
169
  requirements:
170
170
  - - "~>"
171
171
  - !ruby/object:Gem::Version
172
- version: '0.83'
172
+ version: '0.89'
173
173
  - !ruby/object:Gem::Dependency
174
174
  name: rubocop-performance
175
175
  requirement: !ruby/object:Gem::Requirement
@@ -218,14 +218,14 @@ dependencies:
218
218
  requirements:
219
219
  - - "~>"
220
220
  - !ruby/object:Gem::Version
221
- version: '0.18'
221
+ version: '0.19'
222
222
  type: :development
223
223
  prerelease: false
224
224
  version_requirements: !ruby/object:Gem::Requirement
225
225
  requirements:
226
226
  - - "~>"
227
227
  - !ruby/object:Gem::Version
228
- version: '0.18'
228
+ version: '0.19'
229
229
  description:
230
230
  email:
231
231
  - brooke@alchemists.io
@@ -244,7 +244,9 @@ files:
244
244
  - lib/refinements/files.rb
245
245
  - lib/refinements/hashes.rb
246
246
  - lib/refinements/identity.rb
247
+ - lib/refinements/ios.rb
247
248
  - lib/refinements/pathnames.rb
249
+ - lib/refinements/string_ios.rb
248
250
  - lib/refinements/strings.rb
249
251
  homepage: https://www.alchemists.io/projects/refinements
250
252
  licenses:
metadata.gz.sig CHANGED
Binary file