refinements 7.12.0 → 7.16.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: 3df95fcb46ec44d2945b1eb3ab7dafd8ba6bb243973829d662e448ef74695302
4
- data.tar.gz: 21d89890312770ec2c73387c05c44dc31b22de849e18c3db6b4248476ca8bbdf
3
+ metadata.gz: 27c7f3818bd1f3d0d3fc39cb4c8721097d5003176b54710888deba6d012b4f77
4
+ data.tar.gz: f607fea47fce94c11c3ab7dcc6603b169567133fbbe6ca76fb0af0c9fa0196e4
5
5
  SHA512:
6
- metadata.gz: d0cb8fa10183e03737eab0ae1780b91e2e4ce994fd0945c7e2653bacd852dae85de474a073f4b1f6b8634e685059a54a0651b46ec567defd283cfb1491988e50
7
- data.tar.gz: a3f2ea6940f0e8c74f41f43d28d34a71892d3ddcaaf295c64ce4761b120421f80c7833bd9b48d37a90e485c3b606c38adb71e8665cf9feecad35925da485628a
6
+ metadata.gz: da5ff60dc1e6d4055adc850bbe7aa48d02c148f17fb42c9e50f939d577d506097603c2790cf5ce040cce1cb8389e28ebd363d3318d1224d06df4fc6d36e56b3f
7
+ data.tar.gz: a5a96d51b0e95d1f603262ca8ce767969e3faca18645327f368d8ee03aed7d0fa27211d9e35a8af30bcc6ca86d6dad33d804a4c9f1b830789b39b06dc0791793
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -6,6 +6,8 @@
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
 
@@ -26,6 +28,7 @@ Enhances the following objects:
26
28
  * Pathname
27
29
  * String
28
30
  * StringIO
31
+ * Structs
29
32
 
30
33
  == Requirements
31
34
 
@@ -73,6 +76,7 @@ require "refinements/ios"
73
76
  require "refinements/pathnames"
74
77
  require "refinements/strings"
75
78
  require "refinements/string_ios"
79
+ require "refinements/structs"
76
80
  ----
77
81
 
78
82
  === Using
@@ -92,6 +96,7 @@ class Example
92
96
  using Refinements::Pathnames
93
97
  using Refinements::Strings
94
98
  using Refinements::StringIOs
99
+ using Refinements::Structs
95
100
  end
96
101
  ----
97
102
 
@@ -123,35 +128,35 @@ example.compress! # => ["An", "Example"]
123
128
  example # => ["An", "Example"]
124
129
  ----
125
130
 
126
- ===== #include
131
+ ===== #excluding
127
132
 
128
- Adds given array or elements without mutating itself.
133
+ Removes given array or elements without mutating itself.
129
134
 
130
135
  [source,ruby]
131
136
  ----
132
- [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
133
- [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
137
+ [1, 2, 3, 4, 5].excluding [4, 5] # => [1, 2, 3]
138
+ [1, 2, 3, 4, 5].excluding 4, 5 # => [1, 2, 3]
134
139
  ----
135
140
 
136
- ===== #intersperse
141
+ ===== #including
137
142
 
138
- Inserts additional elements or array between all members of given array.
143
+ Adds given array or elements without mutating itself.
139
144
 
140
145
  [source,ruby]
141
146
  ----
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]
147
+ [1, 2, 3].including [4, 5] # => [1, 2, 3, 4, 5]
148
+ [1, 2, 3].including 4, 5 # => [1, 2, 3, 4, 5]
145
149
  ----
146
150
 
147
- ===== #exclude
151
+ ===== #intersperse
148
152
 
149
- Removes given array or elements without mutating itself.
153
+ Inserts additional elements or array between all members of given array.
150
154
 
151
155
  [source,ruby]
152
156
  ----
153
- [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
154
- [1, 2, 3, 4, 5].exclude 4, 5 # => [1, 2, 3]
157
+ [1, 2, 3].intersperse :a # => [1, :a, 2, :a, 3]
158
+ [1, 2, 3].intersperse :a, :b # => [1, :a, :b, 2, :a, :b, 3]
159
+ [1, 2, 3].intersperse %i[a b c] # => [1, :a, :b, :c, 2, :a, :b, :c, 3]
155
160
  ----
156
161
 
157
162
  ===== #mean
@@ -235,106 +240,10 @@ Answers new hash where every top-level missing key has the same default value.
235
240
  [source,ruby]
236
241
  ----
237
242
  example = Hash.with_default ""
238
- example[:a] # => ""
243
+ example[:a] # => ""
239
244
 
240
245
  example = Hash.with_default []
241
- example[:b] # => []
242
- ----
243
-
244
- ===== #except
245
-
246
- Answers new hash with given keys removed without mutating itself.
247
-
248
- [source,ruby]
249
- ----
250
- 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!
256
-
257
- Answers new hash with given keys removed while mutating itself.
258
-
259
- [source,ruby]
260
- ----
261
- example = {a: 1, b: 2, c: 3}
262
- example.except! :a, :b # => {c: 3}
263
- example # => {c: 3}
264
- ----
265
-
266
- ===== #flatten_keys
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
- ----
324
- example = {"a" => 1, "b" => 2}
325
- example.symbolize_keys # => {a: 1, b: 2}
326
- example # => {"a" => 1, "b" => 2}
327
- ----
328
-
329
- ===== #symbolize_keys!
330
-
331
- Converts keys to symbols while mutating itself.
332
-
333
- [source,ruby]
334
- ----
335
- example = {"a" => 1, "b" => 2}
336
- example.symbolize_keys! # => {a: 1, b: 2}
337
- example # => {a: 1, b: 2}
246
+ example[:b] # => []
338
247
  ----
339
248
 
340
249
  ===== #deep_merge
@@ -403,6 +312,58 @@ example.deep_symbolize_keys! # => {a: {b: 1}}
403
312
  example # => {a: {b: 1}}
404
313
  ----
405
314
 
315
+ ===== #except
316
+
317
+ Answers new hash with given keys removed without mutating itself.
318
+
319
+ [source,ruby]
320
+ ----
321
+ example = {a: 1, b: 2, c: 3}
322
+ example.except :a, :b # => {c: 3}
323
+ example # => {a: 1, b: 2, c: 3}
324
+ ----
325
+
326
+ ===== #except!
327
+
328
+ Answers new hash with given keys removed while mutating itself.
329
+
330
+ [source,ruby]
331
+ ----
332
+ example = {a: 1, b: 2, c: 3}
333
+ example.except! :a, :b # => {c: 3}
334
+ example # => {c: 3}
335
+ ----
336
+
337
+ ===== #flatten_keys
338
+
339
+ Flattens nested keys as top-level keys without mutating itself. Does not handle nested arrays,
340
+ though.
341
+
342
+ [source,ruby]
343
+ ----
344
+ {a: {b: 1}}.flatten_keys prefix: :test # => {test_a_b: 1}
345
+ {a: {b: 1}}.flatten_keys delimiter: :| # => {:"a|b" => 1}
346
+
347
+ {a: {b: 1}}.flatten_keys cast: :to_s # => {"a_b" => 1}
348
+ {"a" => {"b" => 1}}.flatten_keys cast: :to_sym # => {a_b: 1}
349
+
350
+ example = {a: {b: 1}}
351
+ example.flatten_keys # => {a_b: 1}
352
+ example # => {a: {b: 1}}
353
+ ----
354
+
355
+ ===== #flatten_keys!
356
+
357
+ Flattens nested keys as top-level keys while mutating itself. Does not handle nested arrays,
358
+ though.
359
+
360
+ [source,ruby]
361
+ ----
362
+ example = {a: {b: 1}}
363
+ example.flatten_keys! # => {a_b: 1}
364
+ example # => {a_b: 1}
365
+ ----
366
+
406
367
  ===== #recurse
407
368
 
408
369
  Recursively iterates over the hash and any hash value by applying the given block to it. Does not
@@ -459,6 +420,50 @@ example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
459
420
  example # => {a: 1, b: 2, c: 3}
460
421
  ----
461
422
 
423
+ ===== #stringify_keys
424
+
425
+ Converts keys to strings without mutating itself.
426
+
427
+ [source,ruby]
428
+ ----
429
+ example = {a: 1, b: 2}
430
+ example.stringify_keys # => {"a" => 1, "b" => 2}
431
+ example # => {a: 1, b: 2}
432
+ ----
433
+
434
+ ===== #stringify_keys!
435
+
436
+ Converts keys to strings while mutating itself.
437
+
438
+ [source,ruby]
439
+ ----
440
+ example = {a: 1, b: 2}
441
+ example.stringify_keys! # => {"a" => 1, "b" => 2}
442
+ example # => {"a" => 1, "b" => 2}
443
+ ----
444
+
445
+ ===== #symbolize_keys
446
+
447
+ Converts keys to symbols without mutating itself.
448
+
449
+ [source,ruby]
450
+ ----
451
+ example = {"a" => 1, "b" => 2}
452
+ example.symbolize_keys # => {a: 1, b: 2}
453
+ example # => {"a" => 1, "b" => 2}
454
+ ----
455
+
456
+ ===== #symbolize_keys!
457
+
458
+ Converts keys to symbols while mutating itself.
459
+
460
+ [source,ruby]
461
+ ----
462
+ example = {"a" => 1, "b" => 2}
463
+ example.symbolize_keys! # => {a: 1, b: 2}
464
+ example # => {a: 1, b: 2}
465
+ ----
466
+
462
467
  ===== #use
463
468
 
464
469
  Passes each hash value as a block argument for further processing.
@@ -466,7 +471,7 @@ Passes each hash value as a block argument for further processing.
466
471
  [source,ruby]
467
472
  ----
468
473
  example = {unit: "221B", street: "Baker Street", city: "London", country: "UK"}
469
- example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
474
+ example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
470
475
  ----
471
476
 
472
477
  ==== IO
@@ -479,23 +484,8 @@ block, you'll need to close the stream manually.
479
484
 
480
485
  [source,ruby]
481
486
  ----
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 # => ""
487
+ io = IO.void # => #<IO:fd 20>
488
+ io = IO.void { |void| void.write "nevermore" } # => #<IO:(closed)>
499
489
  ----
500
490
 
501
491
  ===== #redirect
@@ -508,11 +498,8 @@ answered instead.
508
498
  io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
509
499
  other = IO.new IO.sysopen(Pathname("other.txt").to_s, "w+")
510
500
 
511
- io.redirect other # => `io`
512
-
513
- io.redirect(other) { |stream| stream.write "test" }
514
- .close # => ""
515
- other.close # => "test"
501
+ io.redirect other # => #<IO:fd 20>
502
+ io.redirect(other) { |stream| stream.write "test" } # => #<IO:fd 21>
516
503
  ----
517
504
 
518
505
  ===== #reread
@@ -528,45 +515,134 @@ io.reread # => "This is a test."
528
515
  io.reread 4 # => "This"
529
516
 
530
517
  buffer = "".dup
531
- io.reread(buffer: buffer)
532
- buffer # => "This is a test."
518
+ io.reread(buffer: buffer) # => "This is a test."
519
+ buffer # => "This is a test."
520
+ ----
521
+
522
+ ===== #squelch
523
+
524
+ Temporarily ignores any reads/writes for code executed within a block. Answers itself without any
525
+ arguments or when given a block.
526
+
527
+ [source,ruby]
528
+ ----
529
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
530
+ io.squelch # => #<IO:fd 20>
531
+ io.squelch { io.write "Test" } # => #<IO:fd 20>
532
+ io.reread # => ""
533
533
  ----
534
534
 
535
535
  ==== Pathname
536
536
 
537
537
  ===== Pathname
538
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.
539
+ Enhances the `Kernel` conversion function which casts `nil` into a pathname in order to avoid:
540
+ `TypeError (no implicit conversion of nil into String)`. The pathname remains invalid but at least
541
+ you have an instance of `Pathname`, which behaves like a _Null Object_, that can be used to
542
+ construct a valid path.
543
543
 
544
544
  [source,ruby]
545
545
  ----
546
546
  Pathname(nil) # => Pathname("")
547
547
  ----
548
548
 
549
- ===== #name
549
+ ===== .home
550
550
 
551
- Answers file name without extension.
551
+ Answers user home directory.
552
552
 
553
553
  [source,ruby]
554
554
  ----
555
- Pathname("example.txt").name # => Pathname("example")
555
+ Pathname.home # => Pathname "/Users/bkuhlmann"
556
+ ----
557
+
558
+ ===== .make_temp_dir
559
+
560
+ Wraps `Dir.mktmpdir` with the following behavior (see
561
+ link:https://rubyapi.org/o/Dir.mktmpdir#method-c-mktmpdir[Dir.mktmpdir] for details):
562
+
563
+ * *Without Block* - Answers a newly created Pathname instance which is not automatically cleaned up.
564
+ * *With Block* Yields a Pathname instance, answers result of given block, and automatidally cleans
565
+ up temporary directory after block exits.
566
+
567
+ The following examples use truncated temporary directories for illustration purposes only. In
568
+ reality, these paths will be longer depending on which operating system you are using.
569
+
570
+ [source,ruby]
571
+ ----
572
+ Pathname.make_temp_dir # => Pathname:/var/folders/T/temp-20200101-16940-r8
573
+ Pathname.make_temp_dir prefix: "prefix-" # => Pathname:/var/folders/T/prefix-20200101-16940-r8
574
+ Pathname.make_temp_dir suffix: "-suffix" # => Pathname:/var/folders/T/temp-20200101-16940-r8-suffix
575
+ Pathname.make_temp_dir prefix: "prefix-", suffix: "-suffix" # => Pathname:/var/folders/T/prefix-20200101-16940-r8-suffix
576
+ Pathname.make_temp_dir root: "/example" # => Pathname:/example/temp-20200101-16940-r8
577
+ Pathname.make_temp_dir { "I am a block result" } # => "I am a block result"
578
+ Pathname.make_temp_dir { |path| path.join "sub_dir" } # => Pathname:/var/folders/T/temp-20200101-16940-r8/sub_dir
579
+ ----
580
+
581
+ ===== .require_tree
582
+
583
+ Requires all files in given root path and corresponding nested tree structure. All files are sorted
584
+ before being required to ensure consistent behavior. Example:
585
+
586
+ [source,rby]
587
+ ----
588
+ # Before
589
+ Dir[File.join(__dir__, "support/shared_contexts/**/*.rb")].sort.each { |path| require path }
590
+
591
+ # After
592
+ Pathname.require_tree __dir__, "support/shared_contexts/**/*.rb"
593
+ ----
594
+
595
+ The following are further examples of potential usage:
596
+
597
+ [source,ruby]
598
+ ----
599
+ # Requires all files in root directory and below.
600
+ Pathname.require_tree __dir__
601
+
602
+ # Requires all files in `/test/**/*.rb` and below.
603
+ Pathname.require_tree "/test"
604
+
605
+ # Requires all files in RSpec shared examples directory structure.
606
+ Pathname.require_tree Bundler.root.join("spec"), "support/shared_examples/**/*.rb"
607
+ ----
608
+
609
+ ===== .root
610
+
611
+ Answers operating system root path.
612
+
613
+ [source,ruby]
614
+ ----
615
+ Pathname.root # => Pathname "/"
616
+ ----
617
+
618
+ ===== #change_dir
619
+
620
+ Wraps `Dir.chdir` behavior by changing to directory of current path. See
621
+ link:https://rubyapi.org/o/Dir.chdir#method-c-chdir[Dir.chdir] for details.
622
+
623
+ [source,ruby]
624
+ ----
625
+ Pathname.pwd # => "/"
626
+ Pathname("/test").make_dir.change_dir # => Pathname "/test"
627
+ Pathname.pwd # => "/test"
628
+
629
+ Pathname.pwd # => "/"
630
+ Pathname("/test").make_dir.change_dir { "example" } # => "example"
631
+ Pathname.pwd # => "/"
556
632
  ----
557
633
 
558
634
  ===== #copy
559
635
 
560
- Copies file from current location to new location.
636
+ Copies file from current location to new location while answering itself so it can be chained.
561
637
 
562
638
  [source,ruby]
563
639
  ----
564
- Pathname("input.txt").copy Pathname("output.txt")
640
+ Pathname("input.txt").copy Pathname("output.txt") # => Pathname("input.txt")
565
641
  ----
566
642
 
567
643
  ===== #directories
568
644
 
569
- Answers all or filtered directories for current path.
645
+ Answers all directories or filtered directories for current path.
570
646
 
571
647
  [source,ruby]
572
648
  ----
@@ -581,12 +657,12 @@ Answers file extensions as an array.
581
657
 
582
658
  [source,ruby]
583
659
  ----
584
- Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
660
+ Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
585
661
  ----
586
662
 
587
663
  ===== #files
588
664
 
589
- Answers all or filtered files for current path.
665
+ Answers all files or filtered files for current path.
590
666
 
591
667
  [source,ruby]
592
668
  ----
@@ -608,6 +684,48 @@ Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
608
684
  # => Pathname("/test/some/test")
609
685
  ----
610
686
 
687
+ ===== #make_ancestors
688
+
689
+ Ensures all ancestor directories are created for a path.
690
+
691
+ [source,ruby]
692
+ ----
693
+ Pathname("/one/two").make_ancestors # => Pathname("/one/two")
694
+ Pathname("/one").exist? # => true
695
+ Pathname("/one/two").exist? # => false
696
+ ----
697
+
698
+ ===== #make_dir
699
+
700
+ Provides alternative `#mkdir` behavior by always answering itself (even when directory exists) and
701
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
702
+
703
+ [source,ruby]
704
+ ----
705
+ Pathname("/one").make_dir # => Pathname("/one")
706
+ Pathname("/one").make_dir.make_dir # => Pathname("/one")
707
+ ----
708
+
709
+ ===== #make_path
710
+
711
+ Provides alternative `#mkpath` behavior by always answering itself (even when full path exists) and
712
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
713
+
714
+ [source,ruby]
715
+ ----
716
+ Pathname("/one/two/three").make_path # => Pathname("/one/two/three")
717
+ Pathname("/one/two/three").make_path.make_path # => Pathname("/one/two/three")
718
+ ----
719
+
720
+ ===== #name
721
+
722
+ Answers file name without extension.
723
+
724
+ [source,ruby]
725
+ ----
726
+ Pathname("example.txt").name # => Pathname("example")
727
+ ----
728
+
611
729
  ===== #relative_parent
612
730
 
613
731
  Answers relative path from parent directory. This is a complement to `#relative_path_from`.
@@ -617,26 +735,37 @@ Answers relative path from parent directory. This is a complement to `#relative_
617
735
  Pathname("/one/two/three").relative_parent("/one") # => Pathname "two"
618
736
  ----
619
737
 
620
- ===== #make_ancestors
738
+ ===== #remove_dir
621
739
 
622
- Ensures all ancestor directories are created for a path.
740
+ Provides alternative `#rmdir` behavior by always answering itself (even when full path exists) and
741
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
623
742
 
624
743
  [source,ruby]
625
744
  ----
626
- Pathname("/one/two").make_ancestors
627
- Pathname("/one").exist? # => true
628
- Pathname("/one/two").exist? # => false
745
+ Pathname("/test").make_dir.remove_dir.exist? # => false
746
+ Pathname("/test").remove_dir # => Pathname("/test")
747
+ Pathname("/test").remove_dir.remove_dir # => Pathname("/test")
629
748
  ----
630
749
 
631
- ===== #mkdir
750
+ ===== #remove_tree
632
751
 
633
- Modifies default behavior by always answering itself (even when directory exists) and not throwing
634
- errors when directory exists.
752
+ Provides alternative `#rmtree` behavior by always answering itself (even when full path exists) and
753
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
635
754
 
636
755
  [source,ruby]
637
756
  ----
638
- Pathname("/one").mkdir # => Pathname("/one")
639
- Pathname("/one").mkdir.mkdir # => Pathname("/one")
757
+ parent_path = Pathname "/one"
758
+ child_path = parent_path.join "two"
759
+
760
+ child_path.make_path
761
+ child_path.remove_tree # => Pathname "/one/two"
762
+ child_path.exist? # => false
763
+ paremt_path.exist? # => true
764
+
765
+ child_path.make_path
766
+ parent_path.remove_tree # => Pathname "/one"
767
+ child_path.exist? # => false
768
+ parent_path.exist? # => false
640
769
  ----
641
770
 
642
771
  ===== #rewrite
@@ -646,7 +775,8 @@ immediate writing back to the same file.
646
775
 
647
776
  [source,ruby]
648
777
  ----
649
- Pathname("/test.txt").rewrite { |content| content.sub "[placeholder]", "example" }
778
+ Pathname("/test.txt").rewrite # => Pathname("/test.txt")
779
+ Pathname("/test.txt").rewrite { |body| body.sub "[token]", "example" } # => Pathname("/test.txt")
650
780
  ----
651
781
 
652
782
  ===== #touch
@@ -655,31 +785,23 @@ Updates access and modification times for path. Defaults to current time.
655
785
 
656
786
  [source,ruby]
657
787
  ----
658
- Pathname("example.txt").touch
659
- Pathname("example.txt").touch at: Time.now - 1
788
+ Pathname("example.txt").touch # => Pathname("example.txt")
789
+ Pathname("example.txt").touch at: Time.now - 1 # => Pathname("example.txt")
660
790
  ----
661
791
 
662
- ==== String
792
+ ===== #write
663
793
 
664
- ===== #first
665
-
666
- Answers first character of a string or first set of characters if given a number.
794
+ Writes to file and answers itself so it can be chained. See `IO.write` for details on additional
795
+ options.
667
796
 
668
797
  [source,ruby]
669
798
  ----
670
- "example".first # => "e"
671
- "example".first 4 # => "exam"
799
+ Pathname("example.txt").write "test" # => Pathname("example.txt")
800
+ Pathname("example.txt").write "test", offset: 1 # => Pathname("example.txt")
801
+ Pathname("example.txt").write "test", mode: "a" # => Pathname("example.txt")
672
802
  ----
673
803
 
674
- ===== #last
675
-
676
- Answers last character of a string or last set of characters if given a number.
677
-
678
- [source,ruby]
679
- ----
680
- "instant".last # => "t"
681
- "instant".last 3 # => "ant"
682
- ----
804
+ ==== String
683
805
 
684
806
  ===== #blank?
685
807
 
@@ -690,13 +812,13 @@ Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`,
690
812
  " \n\t\r".blank? # => true
691
813
  ----
692
814
 
693
- ===== #up
815
+ ===== #camelcase
694
816
 
695
- Answers string with only first letter upcased.
817
+ Answers a camelcased string.
696
818
 
697
819
  [source,ruby]
698
820
  ----
699
- "example".up # => "Example"
821
+ "this_is_an_example".camelcase # => "ThisIsAnExample"
700
822
  ----
701
823
 
702
824
  ===== #down
@@ -708,6 +830,16 @@ Answers string with only first letter downcased.
708
830
  "EXAMPLE".down # => "eXAMPLE"
709
831
  ----
710
832
 
833
+ ===== #first
834
+
835
+ Answers first character of a string or first set of characters if given a number.
836
+
837
+ [source,ruby]
838
+ ----
839
+ "example".first # => "e"
840
+ "example".first 4 # => "exam"
841
+ ----
842
+
711
843
  ===== #indent
712
844
 
713
845
  Answers string indented by two spaces by default.
@@ -721,13 +853,14 @@ Answers string indented by two spaces by default.
721
853
  "example".indent 3, padding: " " # => " example"
722
854
  ----
723
855
 
724
- ===== #camelcase
856
+ ===== #last
725
857
 
726
- Answers a camelcased string.
858
+ Answers last character of a string or last set of characters if given a number.
727
859
 
728
860
  [source,ruby]
729
861
  ----
730
- "this_is_an_example".camelcase # => "ThisIsAnExample"
862
+ "instant".last # => "t"
863
+ "instant".last 3 # => "ant"
731
864
  ----
732
865
 
733
866
  ===== #snakecase
@@ -761,6 +894,15 @@ Answers string as a boolean.
761
894
  "example".to_bool # => false
762
895
  ----
763
896
 
897
+ ===== #up
898
+
899
+ Answers string with only first letter upcased.
900
+
901
+ [source,ruby]
902
+ ----
903
+ "example".up # => "Example"
904
+ ----
905
+
764
906
  ==== String IO
765
907
 
766
908
  ===== #reread
@@ -776,8 +918,52 @@ io.reread # => "This is a test."
776
918
  io.reread 4 # => "This"
777
919
 
778
920
  buffer = "".dup
779
- io.reread(buffer: buffer)
780
- buffer # => "This is a test."
921
+ io.reread(buffer: buffer) # => "This is a test."
922
+ buffer # => "This is a test."
923
+ ----
924
+
925
+ ==== Struct
926
+
927
+ ===== #merge
928
+
929
+ Merges multiple attributes without mutating itself.
930
+
931
+ [source,ruby]
932
+ ----
933
+ Example = Struct.new :a, :b, :c
934
+ example = Example[1, 2, 3]
935
+ example.merge a: 10 # => #<struct a=10, b=2, c=3>
936
+ example.merge a: 10, c: 30 # => #<struct a=10, b=2, c=30>
937
+ example.merge a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
938
+ example # => #<struct a=1, b=2, c=3>
939
+
940
+ Example = Struct.new :a, :b, :c, keyword_init: true
941
+ example = Example[a: 1, b: 2, c: 3]
942
+ example.merge a: 10 # => #<struct a=10, b=2, c=3>
943
+ example.merge a: 10, c: 30 # => #<struct a=10, b=2, c=30>
944
+ example.merge a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
945
+ example # => #<struct a=1, b=2, c=3>
946
+ ----
947
+
948
+ ===== #merge!
949
+
950
+ Merges multiple attributes while mutating itself.
951
+
952
+ [source,ruby]
953
+ ----
954
+ Example = Struct.new :a, :b, :c
955
+ example = Example[1, 2, 3]
956
+ example.merge! a: 10 # => #<struct a=10, b=2, c=3>
957
+ example.merge! a: 10, c: 30 # => #<struct a=10, b=2, c=30>
958
+ example.merge! a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
959
+ example # => #<struct a=10, b=20, c=30>
960
+
961
+ Example = Struct.new :a, :b, :c, keyword_init: true
962
+ example = Example[a: 1, b: 2, c: 3]
963
+ example.merge! a: 10 # => #<struct a=10, b=2, c=3>
964
+ example.merge! a: 10, c: 30 # => #<struct a=10, b=2, c=30>
965
+ example.merge! a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
966
+ example # => #<struct a=10, b=20, c=30>
781
967
  ----
782
968
 
783
969
  == Development
@@ -10,3 +10,4 @@ require "refinements/ios"
10
10
  require "refinements/pathnames"
11
11
  require "refinements/strings"
12
12
  require "refinements/string_ios"
13
+ require "refinements/structs"
@@ -11,7 +11,21 @@ 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
 
@@ -19,10 +33,6 @@ module Refinements
19
33
  product([elements]).tap(&:pop).flatten.push last
20
34
  end
21
35
 
22
- def exclude *elements
23
- self - elements.flatten
24
- end
25
-
26
36
  def mean
27
37
  size.zero? ? 0 : sum(0) / size
28
38
  end
@@ -13,49 +13,6 @@ module Refinements
13
13
  end
14
14
 
15
15
  refine Hash do
16
- def except *keys
17
- reject { |key, _value| keys.include? key }
18
- end
19
-
20
- def except! *keys
21
- replace except(*keys)
22
- end
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
-
51
- def symbolize_keys
52
- reduce({}) { |hash, (key, value)| hash.merge key.to_sym => value }
53
- end
54
-
55
- def symbolize_keys!
56
- replace symbolize_keys
57
- end
58
-
59
16
  def deep_merge other
60
17
  clazz = self.class
61
18
 
@@ -88,8 +45,35 @@ module Refinements
88
45
  replace deep_symbolize_keys
89
46
  end
90
47
 
48
+ def except *keys
49
+ reject { |key, _value| keys.include? key }
50
+ end
51
+
52
+ def except! *keys
53
+ replace except(*keys)
54
+ end
55
+
56
+ # :reek:TooManyStatements
57
+ def flatten_keys prefix: nil, delimiter: "_", cast: :to_sym
58
+ fail StandardError, "Unknown cast: #{cast}." unless %i[to_sym to_s].include? cast
59
+
60
+ reduce({}) do |flat, (key, value)|
61
+ flat_key = prefix ? "#{prefix}#{delimiter}#{key}" : key
62
+
63
+ next flat.merge flat_key.public_send(cast) => value unless value.is_a? self.class
64
+
65
+ flat.merge(
66
+ recurse { value.flatten_keys prefix: flat_key, delimiter: delimiter, cast: cast }
67
+ )
68
+ end
69
+ end
70
+
71
+ def flatten_keys! prefix: nil, delimiter: "_", cast: :to_sym
72
+ replace flatten_keys(prefix: prefix, delimiter: delimiter, cast: cast)
73
+ end
74
+
91
75
  def recurse &block
92
- return self unless block_given?
76
+ return self unless block
93
77
 
94
78
  transform = yield self
95
79
 
@@ -118,8 +102,24 @@ module Refinements
118
102
  replace reverse_merge(other)
119
103
  end
120
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
+
121
121
  def use &block
122
- return [] unless block_given?
122
+ return [] unless block
123
123
 
124
124
  block.parameters
125
125
  .map { |(_type, key)| self[key] }
@@ -5,7 +5,7 @@ module Refinements
5
5
  module Identity
6
6
  NAME = "refinements"
7
7
  LABEL = "Refinements"
8
- VERSION = "7.12.0"
8
+ VERSION = "7.16.0"
9
9
  VERSION_LABEL = "#{LABEL} #{VERSION}"
10
10
  end
11
11
  end
@@ -14,10 +14,6 @@ module Refinements
14
14
  end
15
15
 
16
16
  refine IO do
17
- def squelch &block
18
- self.class.void.then { |void| redirect(void, &block) }
19
- end
20
-
21
17
  def redirect other
22
18
  return self unless block_given?
23
19
 
@@ -30,6 +26,10 @@ module Refinements
30
26
  def reread length = nil, buffer: nil
31
27
  tap(&:rewind).read length, buffer
32
28
  end
29
+
30
+ def squelch &block
31
+ self.class.void.then { |void| redirect(void, &block) }
32
+ end
33
33
  end
34
34
  end
35
35
  end
@@ -12,9 +12,27 @@ module Refinements
12
12
  end
13
13
  end
14
14
 
15
+ refine Pathname.singleton_class do
16
+ def home
17
+ new ENV["HOME"]
18
+ end
19
+
20
+ def make_temp_dir prefix: "temp-", suffix: nil, root: nil
21
+ Dir.mktmpdir([prefix, suffix], root) { |path| block_given? ? yield(new path) : new(path) }
22
+ end
23
+
24
+ def require_tree root, pattern = "**/*.rb"
25
+ new(root).files(pattern).each { |path| require path.to_s }
26
+ end
27
+
28
+ def root
29
+ new "/"
30
+ end
31
+ end
32
+
15
33
  refine Pathname do
16
- def name
17
- basename extname
34
+ def change_dir &block
35
+ block ? Dir.chdir(self, &block) : (Dir.chdir self and self)
18
36
  end
19
37
 
20
38
  def copy to
@@ -39,6 +57,28 @@ module Refinements
39
57
  self.class.new to_s.gsub(pattern, replacement)
40
58
  end
41
59
 
60
+ def make_ancestors
61
+ dirname.mkpath
62
+ self
63
+ end
64
+
65
+ def make_dir
66
+ exist? ? self : mkdir and self
67
+ end
68
+
69
+ def make_path
70
+ mkpath
71
+ self
72
+ end
73
+
74
+ def mkdir
75
+ exist? ? self : super and self
76
+ end
77
+
78
+ def name
79
+ basename extname
80
+ end
81
+
42
82
  def relative_parent root_dir
43
83
  relative_path_from(root_dir).parent
44
84
  end
@@ -49,26 +89,28 @@ module Refinements
49
89
  relative_parent root_dir
50
90
  end
51
91
 
52
- def make_ancestors
53
- dirname.mkpath
54
- self
92
+ def remove_dir
93
+ exist? ? (rmdir and self) : self
55
94
  end
56
95
 
57
- # rubocop:disable Style/RedundantSelf
58
- def mkdir
59
- self.exist? ? self : super and self
96
+ def remove_tree
97
+ rmtree if exist?
98
+ self
60
99
  end
61
- # rubocop:enable Style/RedundantSelf
62
100
 
63
101
  def rewrite
64
102
  read.then { |content| write yield(content) if block_given? }
65
- self
66
103
  end
67
104
 
68
105
  def touch at: Time.now
69
106
  exist? ? utime(at, at) : write("")
70
107
  self
71
108
  end
109
+
110
+ def write content, offset: nil, **options
111
+ super content, offset, **options
112
+ self
113
+ end
72
114
  end
73
115
  end
74
116
  end
@@ -12,42 +12,33 @@ module Refinements
12
12
  end
13
13
 
14
14
  refine String do
15
- def first number = 0
16
- return self if empty?
17
-
18
- max = Integer number
15
+ def blank?
16
+ match?(/\A\s*\z/)
17
+ end
19
18
 
20
- return self[0] if max.zero?
21
- return "" if max.negative?
19
+ def camelcase
20
+ return up unless match? DELIMITERS
22
21
 
23
- self[..(max - 1)]
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 }
24
25
  end
25
26
 
26
- def last number = 0
27
+ def down
27
28
  return self if empty?
28
29
 
29
- min = Integer number
30
-
31
- return self[size - 1] if min.zero?
32
- return "" if min.negative?
33
-
34
- self[(min + 1)..]
35
- end
36
-
37
- def blank?
38
- match?(/\A\s*\z/)
30
+ first.downcase + self[1, size]
39
31
  end
40
32
 
41
- def up
33
+ def first number = 0
42
34
  return self if empty?
43
35
 
44
- first.upcase + self[1, size]
45
- end
36
+ max = Integer number
46
37
 
47
- def down
48
- return self if empty?
38
+ return self[0] if max.zero?
39
+ return "" if max.negative?
49
40
 
50
- first.downcase + self[1, size]
41
+ self[..(max - 1)]
51
42
  end
52
43
 
53
44
  def indent multiplier = 1, padding: " "
@@ -56,12 +47,15 @@ module Refinements
56
47
  padding * multiplier + self
57
48
  end
58
49
 
59
- def camelcase
60
- return up unless match? DELIMITERS
50
+ def last number = 0
51
+ return self if empty?
61
52
 
62
- split(%r(\s*-\s*|\s*/\s*|\s*:+\s*)).then { |parts| combine parts, :up, "::" }
63
- .then { |text| text.split(/\s*_\s*|\s+/) }
64
- .then { |parts| combine parts, :up }
53
+ min = Integer number
54
+
55
+ return self[size - 1] if min.zero?
56
+ return "" if min.negative?
57
+
58
+ self[(min + 1)..]
65
59
  end
66
60
 
67
61
  def snakecase
@@ -84,6 +78,12 @@ module Refinements
84
78
  %w[true yes on t y 1].include? downcase.strip
85
79
  end
86
80
 
81
+ def up
82
+ return self if empty?
83
+
84
+ first.upcase + self[1, size]
85
+ end
86
+
87
87
  private
88
88
 
89
89
  # :reek:DuplicateMethodCall
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Refinements
4
+ module Structs
5
+ refine Struct do
6
+ def merge **attributes
7
+ dup.merge! attributes
8
+ end
9
+
10
+ def merge! **attributes
11
+ to_h.merge(attributes).each { |key, value| self[key] = value }
12
+ self
13
+ end
14
+ end
15
+ end
16
+ end
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.12.0
4
+ version: 7.16.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-11-04 00:00:00.000000000 Z
31
+ date: 2020-11-28 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler-audit
@@ -36,14 +36,14 @@ 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
48
  name: bundler-leak
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -64,28 +64,28 @@ dependencies:
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '14.2'
67
+ version: '14.8'
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '14.2'
74
+ version: '14.8'
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: git-lint
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '1.0'
81
+ version: '1.3'
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '1.0'
88
+ version: '1.3'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: guard-rspec
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -162,42 +162,42 @@ dependencies:
162
162
  requirements:
163
163
  - - "~>"
164
164
  - !ruby/object:Gem::Version
165
- version: '3.9'
165
+ version: '3.10'
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: '3.9'
172
+ version: '3.10'
173
173
  - !ruby/object:Gem::Dependency
174
174
  name: rubocop
175
175
  requirement: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - "~>"
178
178
  - !ruby/object:Gem::Version
179
- version: '0.89'
179
+ version: '1.3'
180
180
  type: :development
181
181
  prerelease: false
182
182
  version_requirements: !ruby/object:Gem::Requirement
183
183
  requirements:
184
184
  - - "~>"
185
185
  - !ruby/object:Gem::Version
186
- version: '0.89'
186
+ version: '1.3'
187
187
  - !ruby/object:Gem::Dependency
188
188
  name: rubocop-performance
189
189
  requirement: !ruby/object:Gem::Requirement
190
190
  requirements:
191
191
  - - "~>"
192
192
  - !ruby/object:Gem::Version
193
- version: '1.5'
193
+ version: '1.8'
194
194
  type: :development
195
195
  prerelease: false
196
196
  version_requirements: !ruby/object:Gem::Requirement
197
197
  requirements:
198
198
  - - "~>"
199
199
  - !ruby/object:Gem::Version
200
- version: '1.5'
200
+ version: '1.8'
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: rubocop-rake
203
203
  requirement: !ruby/object:Gem::Requirement
@@ -218,14 +218,14 @@ dependencies:
218
218
  requirements:
219
219
  - - "~>"
220
220
  - !ruby/object:Gem::Version
221
- version: '1.39'
221
+ version: '2.0'
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: '1.39'
228
+ version: '2.0'
229
229
  - !ruby/object:Gem::Dependency
230
230
  name: simplecov
231
231
  requirement: !ruby/object:Gem::Requirement
@@ -262,6 +262,7 @@ files:
262
262
  - lib/refinements/pathnames.rb
263
263
  - lib/refinements/string_ios.rb
264
264
  - lib/refinements/strings.rb
265
+ - lib/refinements/structs.rb
265
266
  homepage: https://www.alchemists.io/projects/refinements
266
267
  licenses:
267
268
  - Apache-2.0
metadata.gz.sig CHANGED
Binary file