refinements 7.9.0 → 7.14.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: ba7c2934d38986ae19d3a41bdc1305164ebe2355bb30afa925eebbeb9746f962
4
- data.tar.gz: 1945d2226c6ca304aa9958635aab6a87880b66e43566691c3ab509f5b2e77f6b
3
+ metadata.gz: 4abbbd79616d97836ca58503bb4638e2638e14732e76e7c00b3f5c033f708edc
4
+ data.tar.gz: 516c79b5361a7512ca4e63c72303d8fb0d2cb85c693bc9aa13c36ef767580f10
5
5
  SHA512:
6
- metadata.gz: 34e601f3bfe0ebe6b35ddf54dea67ef9c33d7436fae5103a2ce03106a34026f1920a6f06369ba2516ceb0a550bb6868fcd5491084cca5b6dd20ed746b4772a39
7
- data.tar.gz: 8e4d5de5f29f28df044333dbaa34fb0a6d9b34911e3e911bd5593caf4dfeb52c0c0767f5a01d164542c54a4d936453b14f6131c055234a5911d73c80673c7d14
6
+ metadata.gz: 2f15aa4b466d6e610a2ffc45ad16285d27107c93a4260d214abcee42e66005951a5f2a708da6b04a28826ab3abd0a85ad0e1a707782b6ba5c51ef5cb0b705ec7
7
+ data.tar.gz: ec214191217bb870ca264fbfe3fa31d57b6c37c28e0f92806f779d3ea8400fbac11ee4aa38c82d6d10d7b07187a2360a7aa810ef802e6d219a217043cd76e69c
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]
@@ -6,10 +6,12 @@
6
6
 
7
7
  [link=http://badge.fury.io/rb/refinements]
8
8
  image::https://badge.fury.io/rb/refinements.svg[Gem Version]
9
+ [link=https://www.alchemists.io/projects/code_quality]
10
+ image::https://img.shields.io/badge/code_style-alchemists-brightgreen.svg[Alchemists Style Guide]
9
11
  [link=https://circleci.com/gh/bkuhlmann/refinements]
10
12
  image::https://circleci.com/gh/bkuhlmann/refinements.svg?style=svg[Circle CI Status]
11
13
 
12
- A collection of refinements (enhancements) to core Ruby objects.
14
+ A collection of refinements (enhancements) to primitive Ruby objects.
13
15
 
14
16
  toc::[]
15
17
 
@@ -22,6 +24,7 @@ Enhances the following objects:
22
24
  * DateTime
23
25
  * File
24
26
  * Hash
27
+ * IO
25
28
  * Pathname
26
29
  * String
27
30
  * StringIO
@@ -34,8 +37,6 @@ Enhances the following objects:
34
37
 
35
38
  == Setup
36
39
 
37
- === Production
38
-
39
40
  To install, run:
40
41
 
41
42
  [source,bash]
@@ -50,24 +51,6 @@ Add the following to your Gemfile file:
50
51
  gem "refinements"
51
52
  ----
52
53
 
53
- === Development
54
-
55
- To contribute, run:
56
-
57
- [source,bash]
58
- ----
59
- git clone https://github.com/bkuhlmann/refinements.git
60
- cd refinements
61
- bin/setup
62
- ----
63
-
64
- You can also use the IRB console for direct access to all objects:
65
-
66
- [source,bash]
67
- ----
68
- bin/console
69
- ----
70
-
71
54
  == Usage
72
55
 
73
56
  === Requires
@@ -79,7 +62,7 @@ If all refinements are not desired, add the following to your `+Gemfile+` instea
79
62
  gem "refinements", require: false
80
63
  ----
81
64
 
82
- then require the specific refinement, as needed. Example:
65
+ ...then require the specific refinement, as needed. Example:
83
66
 
84
67
  [source,ruby]
85
68
  ----
@@ -88,6 +71,7 @@ require "refinements/big_decimals"
88
71
  require "refinements/date_times"
89
72
  require "refinements/files"
90
73
  require "refinements/hashes"
74
+ require "refinements/ios"
91
75
  require "refinements/pathnames"
92
76
  require "refinements/strings"
93
77
  require "refinements/string_ios"
@@ -95,7 +79,8 @@ require "refinements/string_ios"
95
79
 
96
80
  === Using
97
81
 
98
- Much like including/extending a module, you’ll need modify your object(s) to use the refinement(s):
82
+ Much like including/extending a module, you’ll need to modify your object(s) to use the
83
+ refinement(s):
99
84
 
100
85
  [source,ruby]
101
86
  ----
@@ -105,6 +90,7 @@ class Example
105
90
  using Refinements::DateTimes
106
91
  using Refinements::Files
107
92
  using Refinements::Hashes
93
+ using Refinements::IOs
108
94
  using Refinements::Pathnames
109
95
  using Refinements::Strings
110
96
  using Refinements::StringIOs
@@ -119,7 +105,7 @@ The following sections demonstrate how each refinement enriches your objects wit
119
105
 
120
106
  ===== #compress
121
107
 
122
- Removes `nil` and empty values without modifying itself.
108
+ Removes `nil` and empty values without mutating itself.
123
109
 
124
110
  [source,ruby]
125
111
  ----
@@ -130,7 +116,7 @@ example # => ["An", nil, "", "Example"]
130
116
 
131
117
  ===== #compress!
132
118
 
133
- Removes `nil` and empty values while modifying itself.
119
+ Removes `nil` and empty values while mutating itself.
134
120
 
135
121
  [source,ruby]
136
122
  ----
@@ -139,24 +125,47 @@ example.compress! # => ["An", "Example"]
139
125
  example # => ["An", "Example"]
140
126
  ----
141
127
 
142
- ===== #include
128
+ ===== #excluding
129
+
130
+ Removes given array or elements without mutating itself.
131
+
132
+ [source,ruby]
133
+ ----
134
+ [1, 2, 3, 4, 5].excluding [4, 5] # => [1, 2, 3]
135
+ [1, 2, 3, 4, 5].excluding 4, 5 # => [1, 2, 3]
136
+ ----
137
+
138
+ ===== #including
143
139
 
144
- Adds given array or elements without modifying itself.
140
+ Adds given array or elements without mutating itself.
145
141
 
146
142
  [source,ruby]
147
143
  ----
148
- [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
149
- [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
144
+ [1, 2, 3].including [4, 5] # => [1, 2, 3, 4, 5]
145
+ [1, 2, 3].including 4, 5 # => [1, 2, 3, 4, 5]
150
146
  ----
151
147
 
152
- ===== #exclude
148
+ ===== #intersperse
153
149
 
154
- Removes given array or elements without modifying itself.
150
+ Inserts additional elements or array between all members of given array.
155
151
 
156
152
  [source,ruby]
157
153
  ----
158
- [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
159
- [1, 2, 3, 4, 5].exclude 4, 5 # => [1, 2, 3]
154
+ [1, 2, 3].intersperse :a # => [1, :a, 2, :a, 3]
155
+ [1, 2, 3].intersperse :a, :b # => [1, :a, :b, 2, :a, :b, 3]
156
+ [1, 2, 3].intersperse %i[a b c] # => [1, :a, :b, :c, 2, :a, :b, :c, 3]
157
+ ----
158
+
159
+ ===== #mean
160
+
161
+ Answers mean/average all elements within an array.
162
+
163
+ [source,ruby]
164
+ ----
165
+ [].mean # => 0
166
+ [5].mean # => 5
167
+ [1, 2, 3].mean # => 2
168
+ [1.25, 1.5, 1.75].mean # => 1.5
160
169
  ----
161
170
 
162
171
  ===== #ring
@@ -234,127 +243,128 @@ example = Hash.with_default []
234
243
  example[:b] # => []
235
244
  ----
236
245
 
237
- ===== #except
246
+ ===== #deep_merge
238
247
 
239
- Answers new hash with given keys removed without modifying itself.
248
+ Merges deeply nested hashes together without mutating itself.
240
249
 
241
250
  [source,ruby]
242
251
  ----
243
- example = {a: 1, b: 2, c: 3}
244
- example.except :a, :b # => {c: 3}
245
- example # => {a: 1, b: 2, c: 3}
252
+ example = {a: "A", b: {one: "One", two: "Two"}}
253
+ example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
254
+ example # => {a: "A", b: {one: "One", two: "Two"}}
246
255
  ----
247
256
 
248
- ===== #except!
257
+ ===== #deep_merge!
249
258
 
250
- Answers new hash with given keys removed while modifying itself.
259
+ Merges deeply nested hashes together while mutating itself.
251
260
 
252
261
  [source,ruby]
253
262
  ----
254
- example = {a: 1, b: 2, c: 3}
255
- example.except! :a, :b # => {c: 3}
256
- example # => {c: 3}
263
+ example = {a: "A", b: {one: "One", two: "Two"}}
264
+ example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
265
+ example # => {a: "A", b: {one: 1, two: "Two"}}
257
266
  ----
258
267
 
259
- ===== #flatten_keys
268
+ ===== #deep_stringify_keys
260
269
 
261
- Flattens nested keys as top-level keys without modifying itself. Does not handle nested arrays,
262
- though.
270
+ Stringifies keys of nested hash without mutating itself. Does not handle nested arrays, though.
263
271
 
264
272
  [source,ruby]
265
273
  ----
266
- {a: {b: 1}}.flatten_keys prefix: :test # => {test_a_b: 1}
267
- {a: {b: 1}}.flatten_keys delimiter: :| # => {:"a|b" => 1}
268
-
269
- {a: {b: 1}}.flatten_keys cast: :to_s # => {"a_b" => 1}
270
- {"a" => {"b" => 1}}.flatten_keys cast: :to_sym # => {a_b: 1}
271
-
272
- example = {a: {b: 1}}
273
- example.flatten_keys # => {a_b: 1}
274
- example # => {a: {b: 1}}
274
+ example = {a: {b: 2}}
275
+ example.deep_stringify_keys # => {"a" => {"b" => 1}}
276
+ example # => {a: {b: 2}}
275
277
  ----
276
278
 
277
- ===== #flatten_keys!
279
+ ===== #deep_stringify_keys!
278
280
 
279
- Flattens nested keys as top-level keys while modifying itself. Does not handle nested arrays,
280
- though.
281
+ Stringifies keys of nested hash while mutating itself. Does not handle nested arrays, though.
281
282
 
282
283
  [source,ruby]
283
284
  ----
284
- example = {a: {b: 1}}
285
- example.flatten_keys! # => {a_b: 1}
286
- example # => {a_b: 1}
285
+ example = {a: {b: 2}}
286
+ example.deep_stringify_keys! # => {"a" => {"b" => 1}}
287
+ example # => {"a" => {"b" => 1}}
287
288
  ----
288
289
 
289
- ===== #symbolize_keys
290
+ ===== #deep_symbolize_keys
290
291
 
291
- Converts keys to symbols without modifying itself.
292
+ Symbolizes keys of nested hash without mutating itself. Does not handle nested arrays, though.
292
293
 
293
294
  [source,ruby]
294
295
  ----
295
- example = {"a" => 1, "b" => 2}
296
- example.symbolize_keys # => {a: 1, b: 2}
297
- example # => {"a" => 1, "b" => 2}
296
+ example = {"a" => {"b" => 2}}
297
+ example.deep_symbolize_keys # => {a: {b: 1}}
298
+ example # => {"a" => {"b" => 2}}
298
299
  ----
299
300
 
300
- ===== #symbolize_keys!
301
+ ===== #deep_symbolize_keys!
301
302
 
302
- Converts keys to symbols while modifying itself.
303
+ Symbolizes keys of nested hash while mutating itself. Does not handle nested arrays, though.
303
304
 
304
305
  [source,ruby]
305
306
  ----
306
- example = {"a" => 1, "b" => 2}
307
- example.symbolize_keys! # => {a: 1, b: 2}
308
- example # => {a: 1, b: 2}
307
+ example = {"a" => {"b" => 2}}
308
+ example.deep_symbolize_keys! # => {a: {b: 1}}
309
+ example # => {a: {b: 1}}
309
310
  ----
310
311
 
311
- ===== #deep_merge
312
+ ===== #except
312
313
 
313
- Merges deeply nested hashes together without modifying itself.
314
+ Answers new hash with given keys removed without mutating itself.
314
315
 
315
316
  [source,ruby]
316
317
  ----
317
- example = {a: "A", b: {one: "One", two: "Two"}}
318
- example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
319
- example # => {a: "A", b: {one: "One", two: "Two"}}
318
+ example = {a: 1, b: 2, c: 3}
319
+ example.except :a, :b # => {c: 3}
320
+ example # => {a: 1, b: 2, c: 3}
320
321
  ----
321
322
 
322
- ===== #deep_merge!
323
+ ===== #except!
323
324
 
324
- Merges deeply nested hashes together while modifying itself.
325
+ Answers new hash with given keys removed while mutating itself.
325
326
 
326
327
  [source,ruby]
327
328
  ----
328
- example = {a: "A", b: {one: "One", two: "Two"}}
329
- example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
330
- example # => {a: "A", b: {one: 1, two: "Two"}}
329
+ example = {a: 1, b: 2, c: 3}
330
+ example.except! :a, :b # => {c: 3}
331
+ example # => {c: 3}
331
332
  ----
332
333
 
333
- ===== #deep_symbolize_keys
334
+ ===== #flatten_keys
334
335
 
335
- Symbolizes keys of nested hash without modifying itself. Does not handle nested arrays, though.
336
+ Flattens nested keys as top-level keys without mutating itself. Does not handle nested arrays,
337
+ though.
336
338
 
337
339
  [source,ruby]
338
340
  ----
339
- example = {"a" => {"b" => 2}}
340
- example.deep_symbolize_keys # => {a: {b: 1}}
341
- example # => {"a" => {"b" => 2}}
341
+ {a: {b: 1}}.flatten_keys prefix: :test # => {test_a_b: 1}
342
+ {a: {b: 1}}.flatten_keys delimiter: :| # => {:"a|b" => 1}
343
+
344
+ {a: {b: 1}}.flatten_keys cast: :to_s # => {"a_b" => 1}
345
+ {"a" => {"b" => 1}}.flatten_keys cast: :to_sym # => {a_b: 1}
346
+
347
+ example = {a: {b: 1}}
348
+ example.flatten_keys # => {a_b: 1}
349
+ example # => {a: {b: 1}}
342
350
  ----
343
351
 
344
- ===== #deep_symbolize_keys!
352
+ ===== #flatten_keys!
345
353
 
346
- Symbolizes keys of nested hash while modifying itself. Does not handle nested arrays, though.
354
+ Flattens nested keys as top-level keys while mutating itself. Does not handle nested arrays,
355
+ though.
347
356
 
348
357
  [source,ruby]
349
358
  ----
350
- example = {"a" => {"b" => 2}}
351
- example.deep_symbolize_keys! # => {a: {b: 1}}
352
- example # => {a: {b: 1}}
359
+ example = {a: {b: 1}}
360
+ example.flatten_keys! # => {a_b: 1}
361
+ example # => {a_b: 1}
353
362
  ----
354
363
 
355
364
  ===== #recurse
356
365
 
357
- Applies block to nested hash. Does not handle nested arrays, though.
366
+ Recursively iterates over the hash and any hash value by applying the given block to it. Does not
367
+ handle nested arrays, though.
358
368
 
359
369
  [source,ruby]
360
370
  ----
@@ -365,7 +375,7 @@ example.recurse(&:invert) # => {{"b" => 1} => "a"}
365
375
 
366
376
  ===== #rekey
367
377
 
368
- Transforms keys per mapping (size of mapping can vary) without modifying itself.
378
+ Transforms keys per mapping (size of mapping can vary) without mutating itself.
369
379
 
370
380
  [source,ruby]
371
381
  ----
@@ -376,7 +386,7 @@ example # => {a: 1, b: 2, c: 3}
376
386
 
377
387
  ===== #rekey!
378
388
 
379
- Transforms keys per mapping (size of mapping can vary) while modifying itself.
389
+ Transforms keys per mapping (size of mapping can vary) while mutating itself.
380
390
 
381
391
  [source,ruby]
382
392
  ----
@@ -387,7 +397,7 @@ example # => {amber: 1, blue: 2, c: 3}
387
397
 
388
398
  ===== #reverse_merge
389
399
 
390
- Merges calling hash into passed in hash without modifying itself.
400
+ Merges calling hash into passed in hash without mutating itself.
391
401
 
392
402
  [source,ruby]
393
403
  ----
@@ -398,7 +408,7 @@ example # => {a: 1, b: 2}
398
408
 
399
409
  ===== #reverse_merge!
400
410
 
401
- Merges calling hash into passed in hash while modifying itself.
411
+ Merges calling hash into passed in hash while mutating itself.
402
412
 
403
413
  [source,ruby]
404
414
  ----
@@ -407,6 +417,50 @@ example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
407
417
  example # => {a: 1, b: 2, c: 3}
408
418
  ----
409
419
 
420
+ ===== #stringify_keys
421
+
422
+ Converts keys to strings without mutating itself.
423
+
424
+ [source,ruby]
425
+ ----
426
+ example = {a: 1, b: 2}
427
+ example.stringify_keys # => {"a" => 1, "b" => 2}
428
+ example # => {a: 1, b: 2}
429
+ ----
430
+
431
+ ===== #stringify_keys!
432
+
433
+ Converts keys to strings while mutating itself.
434
+
435
+ [source,ruby]
436
+ ----
437
+ example = {a: 1, b: 2}
438
+ example.stringify_keys! # => {"a" => 1, "b" => 2}
439
+ example # => {"a" => 1, "b" => 2}
440
+ ----
441
+
442
+ ===== #symbolize_keys
443
+
444
+ Converts keys to symbols without mutating itself.
445
+
446
+ [source,ruby]
447
+ ----
448
+ example = {"a" => 1, "b" => 2}
449
+ example.symbolize_keys # => {a: 1, b: 2}
450
+ example # => {"a" => 1, "b" => 2}
451
+ ----
452
+
453
+ ===== #symbolize_keys!
454
+
455
+ Converts keys to symbols while mutating itself.
456
+
457
+ [source,ruby]
458
+ ----
459
+ example = {"a" => 1, "b" => 2}
460
+ example.symbolize_keys! # => {a: 1, b: 2}
461
+ example # => {a: 1, b: 2}
462
+ ----
463
+
410
464
  ===== #use
411
465
 
412
466
  Passes each hash value as a block argument for further processing.
@@ -417,24 +471,97 @@ example = {unit: "221B", street: "Baker Street", city: "London", country: "UK"}
417
471
  example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
418
472
  ----
419
473
 
474
+ ==== IO
475
+
476
+ ===== .void
477
+
478
+ Answers an IO stream which points to `/dev/null` in order to ignore any reads or writes to the
479
+ stream. When given a block, the stream will automatically close upon block exit. When not given a
480
+ block, you'll need to close the stream manually.
481
+
482
+ [source,ruby]
483
+ ----
484
+ io = IO.void
485
+ io.closed? # => false
486
+
487
+ io = IO.void { |void| void.write "nevermore" }
488
+ io.closed? # => true
489
+ ----
490
+
491
+ ===== #redirect
492
+
493
+ Redirects current stream to other stream when given a block. Without a block, the original stream is
494
+ answered instead.
495
+
496
+ [source,ruby]
497
+ ----
498
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
499
+ other = IO.new IO.sysopen(Pathname("other.txt").to_s, "w+")
500
+
501
+ io.redirect other # => `io`
502
+
503
+ io.redirect(other) { |stream| stream.write "test" }
504
+ .close # => ""
505
+ other.close # => "test"
506
+ ----
507
+
508
+ ===== #reread
509
+
510
+ Answers full stream by rewinding to beginning of stream and reading all content.
511
+
512
+ [source,ruby]
513
+ ----
514
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
515
+ io.write "This is a test."
516
+
517
+ io.reread # => "This is a test."
518
+ io.reread 4 # => "This"
519
+
520
+ buffer = "".dup
521
+ io.reread(buffer: buffer)
522
+ buffer # => "This is a test."
523
+ ----
524
+
525
+ ===== #squelch
526
+
527
+ Temporarily ignores any reads/writes for current stream for all code executed within the block. When
528
+ not given a block, it answers itself.
529
+
530
+ [source,ruby]
531
+ ----
532
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
533
+ io.squelch { io.write "Test" }
534
+ io.reread # => ""
535
+ ----
536
+
420
537
  ==== Pathname
421
538
 
422
539
  ===== Pathname
423
540
 
424
- Conversion function (refined from `Kernel`) which can cast `nil` into a pathname.
541
+ Enhances the conversion function -- refined from `Kernel` -- which casts `nil` into a pathname in
542
+ order to avoid: `TypeError (no implicit conversion of nil into String)`. The pathname is still
543
+ invalid but at least you have an instance of `Pathname`, which behaves like a _Null Object_, that
544
+ can still be used to construct a valid path.
425
545
 
426
546
  [source,ruby]
427
547
  ----
428
548
  Pathname(nil) # => Pathname("")
429
549
  ----
430
550
 
431
- ===== #name
551
+ ===== #change_dir
432
552
 
433
- Answers file name without extension.
553
+ Inherits and wraps `Dir.chdir` behavior by changing to directory of current path. See
554
+ link:https://rubyapi.org/2.7/o/s?q=Dir.chdir[Dir.chdir] for details.
434
555
 
435
556
  [source,ruby]
436
557
  ----
437
- Pathname("example.txt").name # => Pathname("example")
558
+ Pathname.pwd # => "/"
559
+ Pathname("/test").make_dir.change_dir # => Pathname "/test"
560
+ Pathname.pwd # => "/test"
561
+
562
+ Pathname.pwd # => "/"
563
+ Pathname("/test").make_dir.change_dir { # Implementation details } # => Pathname "/test"
564
+ Pathname.pwd # => "/"
438
565
  ----
439
566
 
440
567
  ===== #copy
@@ -490,6 +617,48 @@ Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
490
617
  # => Pathname("/test/some/test")
491
618
  ----
492
619
 
620
+ ===== #make_ancestors
621
+
622
+ Ensures all ancestor directories are created for a path.
623
+
624
+ [source,ruby]
625
+ ----
626
+ Pathname("/one/two").make_ancestors
627
+ Pathname("/one").exist? # => true
628
+ Pathname("/one/two").exist? # => false
629
+ ----
630
+
631
+ ===== #make_dir
632
+
633
+ Provides alternative `#mkdir` behavior by always answering itself (even when directory exists) and
634
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
635
+
636
+ [source,ruby]
637
+ ----
638
+ Pathname("/one").make_dir # => Pathname("/one")
639
+ Pathname("/one").make_dir.make_dir # => Pathname("/one")
640
+ ----
641
+
642
+ ===== #make_path
643
+
644
+ Provides alternative `#mkpath` behavior by always answering itself (even when full path exists) and
645
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
646
+
647
+ [source,ruby]
648
+ ----
649
+ Pathname("/one/two/three").make_path # => Pathname("/one/two/three")
650
+ Pathname("/one/two/three").make_path.make_path # => Pathname("/one/two/three")
651
+ ----
652
+
653
+ ===== #name
654
+
655
+ Answers file name without extension.
656
+
657
+ [source,ruby]
658
+ ----
659
+ Pathname("example.txt").name # => Pathname("example")
660
+ ----
661
+
493
662
  ===== #relative_parent
494
663
 
495
664
  Answers relative path from parent directory. This is a complement to `#relative_path_from`.
@@ -499,15 +668,37 @@ Answers relative path from parent directory. This is a complement to `#relative_
499
668
  Pathname("/one/two/three").relative_parent("/one") # => Pathname "two"
500
669
  ----
501
670
 
502
- ===== #make_ancestors
671
+ ===== #remove_dir
503
672
 
504
- Ensures all ancestor directories are created for a path.
673
+ Provides alternative `#rmdir` behavior by always answering itself (even when full path exists) and
674
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
505
675
 
506
676
  [source,ruby]
507
677
  ----
508
- Pathname("/one/two").make_ancestors
509
- Pathname("/one").exist? # => true
510
- Pathname("/one/two").exist? # => false
678
+ Pathname("/test").make_dir.remove_dir.exist? # => false
679
+ Pathname("/test").remove_dir # => Pathname("/test")
680
+ Pathname("/test").remove_dir.remove_dir # => Pathname("/test")
681
+ ----
682
+
683
+ ===== #remove_tree
684
+
685
+ Provides alternative `#rmtree` behavior by always answering itself (even when full path exists) and
686
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
687
+
688
+ [source,ruby]
689
+ ----
690
+ parent_path = Pathname "/one"
691
+ child_path = parent_path.join "two"
692
+
693
+ child_path.make_path
694
+ child_path.remove_tree # => Pathname "/one/two"
695
+ child_path.exist? # => false
696
+ paremt_path.exist? # => true
697
+
698
+ child_path.make_path
699
+ parent_path.remove_tree # => Pathname "/one"
700
+ child_path.exist? # => false
701
+ parent_path.exist? # => false
511
702
  ----
512
703
 
513
704
  ===== #rewrite
@@ -532,60 +723,64 @@ Pathname("example.txt").touch at: Time.now - 1
532
723
 
533
724
  ==== String
534
725
 
535
- ===== #first
726
+ ===== #blank?
536
727
 
537
- Answers first character of a string or first set of characters if given a number.
728
+ Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`, and/or `\r`.
538
729
 
539
730
  [source,ruby]
540
731
  ----
541
- "example".first # => "e"
542
- "example".first 4 # => "exam"
732
+ " \n\t\r".blank? # => true
543
733
  ----
544
734
 
545
- ===== #last
735
+ ===== #camelcase
546
736
 
547
- Answers last character of a string or last set of characters if given a number.
737
+ Answers a camelcased string.
548
738
 
549
739
  [source,ruby]
550
740
  ----
551
- "instant".last # => "t"
552
- "instant".last 3 # => "ant"
741
+ "this_is_an_example".camelcase # => "ThisIsAnExample"
553
742
  ----
554
743
 
555
- ===== #blank?
744
+ ===== #down
556
745
 
557
- Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`, and/or `\r`.
746
+ Answers string with only first letter downcased.
558
747
 
559
748
  [source,ruby]
560
749
  ----
561
- " \n\t\r".blank? # => true
750
+ "EXAMPLE".down # => "eXAMPLE"
562
751
  ----
563
752
 
564
- ===== #up
753
+ ===== #first
565
754
 
566
- Answers string with only first letter upcased.
755
+ Answers first character of a string or first set of characters if given a number.
567
756
 
568
757
  [source,ruby]
569
758
  ----
570
- "example".up # => "Example"
759
+ "example".first # => "e"
760
+ "example".first 4 # => "exam"
571
761
  ----
572
762
 
573
- ===== #down
763
+ ===== #indent
574
764
 
575
- Answers string with only first letter downcased.
765
+ Answers string indented by two spaces by default.
576
766
 
577
767
  [source,ruby]
578
768
  ----
579
- "EXAMPLE".down # => "eXAMPLE"
769
+ "example".indent # => " example"
770
+ "example".indent 0 # => "example"
771
+ "example".indent -1 # => "example"
772
+ "example".indent 2 # => " example"
773
+ "example".indent 3, padding: " " # => " example"
580
774
  ----
581
775
 
582
- ===== #camelcase
776
+ ===== #last
583
777
 
584
- Answers a camelcased string.
778
+ Answers last character of a string or last set of characters if given a number.
585
779
 
586
780
  [source,ruby]
587
781
  ----
588
- "this_is_an_example".camelcase # => "ThisIsAnExample"
782
+ "instant".last # => "t"
783
+ "instant".last 3 # => "ant"
589
784
  ----
590
785
 
591
786
  ===== #snakecase
@@ -619,6 +814,15 @@ Answers string as a boolean.
619
814
  "example".to_bool # => false
620
815
  ----
621
816
 
817
+ ===== #up
818
+
819
+ Answers string with only first letter upcased.
820
+
821
+ [source,ruby]
822
+ ----
823
+ "example".up # => "Example"
824
+ ----
825
+
622
826
  ==== String IO
623
827
 
624
828
  ===== #reread
@@ -638,6 +842,24 @@ io.reread(buffer: buffer)
638
842
  buffer # => "This is a test."
639
843
  ----
640
844
 
845
+ == Development
846
+
847
+ To contribute, run:
848
+
849
+ [source,bash]
850
+ ----
851
+ git clone https://github.com/bkuhlmann/refinements.git
852
+ cd refinements
853
+ bin/setup
854
+ ----
855
+
856
+ You can also use the IRB console for direct access to all objects:
857
+
858
+ [source,bash]
859
+ ----
860
+ bin/console
861
+ ----
862
+
641
863
  == Tests
642
864
 
643
865
  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,12 +11,30 @@ module Refinements
11
11
  replace compress
12
12
  end
13
13
 
14
+ def exclude *elements
15
+ warn "[DEPRECATION]: #exclude is deprecated, use #excluding instead."
16
+ excluding(*elements)
17
+ end
18
+
19
+ def excluding *elements
20
+ self - elements.flatten
21
+ end
22
+
14
23
  def include *elements
24
+ warn "[DEPRECATION]: #include is deprecated, use #including instead."
25
+ including(*elements)
26
+ end
27
+
28
+ def including *elements
15
29
  self + elements.flatten
16
30
  end
17
31
 
18
- def exclude *elements
19
- self - elements.flatten
32
+ def intersperse *elements
33
+ product([elements]).tap(&:pop).flatten.push last
34
+ end
35
+
36
+ def mean
37
+ size.zero? ? 0 : sum(0) / size
20
38
  end
21
39
 
22
40
  def ring &block
@@ -13,6 +13,38 @@ module Refinements
13
13
  end
14
14
 
15
15
  refine Hash do
16
+ def deep_merge other
17
+ clazz = self.class
18
+
19
+ merge other do |_key, this_value, other_value|
20
+ if this_value.is_a?(clazz) && other_value.is_a?(clazz)
21
+ this_value.deep_merge other_value
22
+ else
23
+ other_value
24
+ end
25
+ end
26
+ end
27
+
28
+ def deep_merge! other
29
+ replace deep_merge(other)
30
+ end
31
+
32
+ def deep_stringify_keys
33
+ recurse(&:stringify_keys)
34
+ end
35
+
36
+ def deep_stringify_keys!
37
+ replace deep_stringify_keys
38
+ end
39
+
40
+ def deep_symbolize_keys
41
+ recurse(&:symbolize_keys)
42
+ end
43
+
44
+ def deep_symbolize_keys!
45
+ replace deep_symbolize_keys
46
+ end
47
+
16
48
  def except *keys
17
49
  reject { |key, _value| keys.include? key }
18
50
  end
@@ -40,38 +72,6 @@ module Refinements
40
72
  replace flatten_keys(prefix: prefix, delimiter: delimiter, cast: cast)
41
73
  end
42
74
 
43
- def symbolize_keys
44
- reduce({}) { |hash, (key, value)| hash.merge key.to_sym => value }
45
- end
46
-
47
- def symbolize_keys!
48
- replace symbolize_keys
49
- end
50
-
51
- def deep_merge other
52
- clazz = self.class
53
-
54
- merge other do |_key, this_value, other_value|
55
- if this_value.is_a?(clazz) && other_value.is_a?(clazz)
56
- this_value.deep_merge other_value
57
- else
58
- other_value
59
- end
60
- end
61
- end
62
-
63
- def deep_merge! other
64
- replace deep_merge(other)
65
- end
66
-
67
- def deep_symbolize_keys
68
- recurse(&:symbolize_keys)
69
- end
70
-
71
- def deep_symbolize_keys!
72
- replace deep_symbolize_keys
73
- end
74
-
75
75
  def recurse &block
76
76
  return self unless block_given?
77
77
 
@@ -102,6 +102,22 @@ module Refinements
102
102
  replace reverse_merge(other)
103
103
  end
104
104
 
105
+ def stringify_keys
106
+ reduce({}) { |hash, (key, value)| hash.merge key.to_s => value }
107
+ end
108
+
109
+ def stringify_keys!
110
+ replace stringify_keys
111
+ end
112
+
113
+ def symbolize_keys
114
+ reduce({}) { |hash, (key, value)| hash.merge key.to_sym => value }
115
+ end
116
+
117
+ def symbolize_keys!
118
+ replace symbolize_keys
119
+ end
120
+
105
121
  def use &block
106
122
  return [] unless block_given?
107
123
 
@@ -5,7 +5,7 @@ module Refinements
5
5
  module Identity
6
6
  NAME = "refinements"
7
7
  LABEL = "Refinements"
8
- VERSION = "7.9.0"
8
+ VERSION = "7.14.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 redirect other
18
+ return self unless block_given?
19
+
20
+ backup = dup
21
+ reopen other
22
+ yield self
23
+ reopen backup
24
+ end
25
+
26
+ def reread length = nil, buffer: nil
27
+ tap(&:rewind).read length, buffer
28
+ end
29
+
30
+ def squelch &block
31
+ self.class.void.then { |void| redirect(void, &block) }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -13,8 +13,8 @@ module Refinements
13
13
  end
14
14
 
15
15
  refine Pathname do
16
- def name
17
- basename extname
16
+ def change_dir &block
17
+ block_given? ? Dir.chdir(self, &block) : (Dir.chdir self and self)
18
18
  end
19
19
 
20
20
  def copy to
@@ -39,6 +39,28 @@ module Refinements
39
39
  self.class.new to_s.gsub(pattern, replacement)
40
40
  end
41
41
 
42
+ def make_ancestors
43
+ dirname.mkpath
44
+ self
45
+ end
46
+
47
+ def make_dir
48
+ exist? ? self : mkdir and self
49
+ end
50
+
51
+ def make_path
52
+ mkpath
53
+ self
54
+ end
55
+
56
+ def mkdir
57
+ exist? ? self : super and self
58
+ end
59
+
60
+ def name
61
+ basename extname
62
+ end
63
+
42
64
  def relative_parent root_dir
43
65
  relative_path_from(root_dir).parent
44
66
  end
@@ -49,8 +71,12 @@ module Refinements
49
71
  relative_parent root_dir
50
72
  end
51
73
 
52
- def make_ancestors
53
- dirname.mkpath
74
+ def remove_dir
75
+ exist? ? (rmdir and self) : self
76
+ end
77
+
78
+ def remove_tree
79
+ rmtree if exist?
54
80
  self
55
81
  end
56
82
 
@@ -12,6 +12,24 @@ module Refinements
12
12
  end
13
13
 
14
14
  refine String do
15
+ def blank?
16
+ match?(/\A\s*\z/)
17
+ end
18
+
19
+ def camelcase
20
+ return up unless match? DELIMITERS
21
+
22
+ split(%r(\s*-\s*|\s*/\s*|\s*:+\s*)).then { |parts| combine parts, :up, "::" }
23
+ .then { |text| text.split(/\s*_\s*|\s+/) }
24
+ .then { |parts| combine parts, :up }
25
+ end
26
+
27
+ def down
28
+ return self if empty?
29
+
30
+ first.downcase + self[1, size]
31
+ end
32
+
15
33
  def first number = 0
16
34
  return self if empty?
17
35
 
@@ -23,6 +41,12 @@ module Refinements
23
41
  self[..(max - 1)]
24
42
  end
25
43
 
44
+ def indent multiplier = 1, padding: " "
45
+ return self if multiplier.negative?
46
+
47
+ padding * multiplier + self
48
+ end
49
+
26
50
  def last number = 0
27
51
  return self if empty?
28
52
 
@@ -34,30 +58,6 @@ module Refinements
34
58
  self[(min + 1)..]
35
59
  end
36
60
 
37
- def blank?
38
- match?(/\A\s*\z/)
39
- end
40
-
41
- def up
42
- return self if empty?
43
-
44
- first.upcase + self[1, size]
45
- end
46
-
47
- def down
48
- return self if empty?
49
-
50
- first.downcase + self[1, size]
51
- end
52
-
53
- def camelcase
54
- return up unless match? DELIMITERS
55
-
56
- split(%r(\s*-\s*|\s*/\s*|\s*:+\s*)).then { |parts| combine parts, :up, "::" }
57
- .then { |text| text.split(/\s*_\s*|\s+/) }
58
- .then { |parts| combine parts, :up }
59
- end
60
-
61
61
  def snakecase
62
62
  return downcase unless match? DELIMITERS
63
63
 
@@ -78,6 +78,12 @@ module Refinements
78
78
  %w[true yes on t y 1].include? downcase.strip
79
79
  end
80
80
 
81
+ def up
82
+ return self if empty?
83
+
84
+ first.upcase + self[1, size]
85
+ end
86
+
81
87
  private
82
88
 
83
89
  # :reek:DuplicateMethodCall
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.9.0
4
+ version: 7.14.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-09-19 00:00:00.000000000 Z
31
+ date: 2020-11-14 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler-audit
@@ -36,42 +36,28 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.6'
39
+ version: '0.7'
40
40
  type: :development
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.6'
46
+ version: '0.7'
47
47
  - !ruby/object:Gem::Dependency
48
- name: gemsmith
48
+ name: bundler-leak
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '14.2'
53
+ version: '0.2'
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '14.2'
61
- - !ruby/object:Gem::Dependency
62
- name: git-lint
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '1.0'
68
- type: :development
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '1.0'
60
+ version: '0.2'
75
61
  - !ruby/object:Gem::Dependency
76
62
  name: guard-rspec
77
63
  requirement: !ruby/object:Gem::Requirement
@@ -148,42 +134,42 @@ dependencies:
148
134
  requirements:
149
135
  - - "~>"
150
136
  - !ruby/object:Gem::Version
151
- version: '3.9'
137
+ version: '3.10'
152
138
  type: :development
153
139
  prerelease: false
154
140
  version_requirements: !ruby/object:Gem::Requirement
155
141
  requirements:
156
142
  - - "~>"
157
143
  - !ruby/object:Gem::Version
158
- version: '3.9'
144
+ version: '3.10'
159
145
  - !ruby/object:Gem::Dependency
160
146
  name: rubocop
161
147
  requirement: !ruby/object:Gem::Requirement
162
148
  requirements:
163
149
  - - "~>"
164
150
  - !ruby/object:Gem::Version
165
- version: '0.89'
151
+ version: '1.3'
166
152
  type: :development
167
153
  prerelease: false
168
154
  version_requirements: !ruby/object:Gem::Requirement
169
155
  requirements:
170
156
  - - "~>"
171
157
  - !ruby/object:Gem::Version
172
- version: '0.89'
158
+ version: '1.3'
173
159
  - !ruby/object:Gem::Dependency
174
160
  name: rubocop-performance
175
161
  requirement: !ruby/object:Gem::Requirement
176
162
  requirements:
177
163
  - - "~>"
178
164
  - !ruby/object:Gem::Version
179
- version: '1.5'
165
+ version: '1.8'
180
166
  type: :development
181
167
  prerelease: false
182
168
  version_requirements: !ruby/object:Gem::Requirement
183
169
  requirements:
184
170
  - - "~>"
185
171
  - !ruby/object:Gem::Version
186
- version: '1.5'
172
+ version: '1.8'
187
173
  - !ruby/object:Gem::Dependency
188
174
  name: rubocop-rake
189
175
  requirement: !ruby/object:Gem::Requirement
@@ -204,14 +190,14 @@ dependencies:
204
190
  requirements:
205
191
  - - "~>"
206
192
  - !ruby/object:Gem::Version
207
- version: '1.39'
193
+ version: '2.0'
208
194
  type: :development
209
195
  prerelease: false
210
196
  version_requirements: !ruby/object:Gem::Requirement
211
197
  requirements:
212
198
  - - "~>"
213
199
  - !ruby/object:Gem::Version
214
- version: '1.39'
200
+ version: '2.0'
215
201
  - !ruby/object:Gem::Dependency
216
202
  name: simplecov
217
203
  requirement: !ruby/object:Gem::Requirement
@@ -244,6 +230,7 @@ files:
244
230
  - lib/refinements/files.rb
245
231
  - lib/refinements/hashes.rb
246
232
  - lib/refinements/identity.rb
233
+ - lib/refinements/ios.rb
247
234
  - lib/refinements/pathnames.rb
248
235
  - lib/refinements/string_ios.rb
249
236
  - lib/refinements/strings.rb
metadata.gz.sig CHANGED
Binary file