refinements 7.11.0 → 7.15.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5a299dfa7a3355d5cb068cc6638ed41ca9ac4980ed69f6aabb0e1608cc96e95
4
- data.tar.gz: 4b12b5237fc97f5609677b8f010156ef9a1d00d5004fe48d1cfa4d32df15f602
3
+ metadata.gz: c4efd7acd4d8da05214aa7947c0f61f3a04c8ece8733c2bdc4dc48ce9cbad371
4
+ data.tar.gz: 5025123a8cc9e8fe23d1a0436e265c173a89477e6b5194a159a1ed9e5cb5ec9c
5
5
  SHA512:
6
- metadata.gz: 248e66b7141e5e29f68c60aae0a3eac49934830053e9e5ce7082b0164e63b42ee9c536d8b46d4f86c7f570a85f1838415939b5955d66bd93f5df2eeefe66a5d7
7
- data.tar.gz: 399fc17b0857236d4d58668857d690ddb63deba8fd9de10c372f2d3618c93edb31a9574f166c01d6aee884d4d856f067dfc2b68eddedb80d90d70a656595d82d
6
+ metadata.gz: 48228ed81040b9e9b18f7e743d3cdb64885ea53515de5d588817a8969d6d02781e7404b8a6e33e7f24c70f982c3b3f5fd72b61ceb1c87a5d2c8eb8117e544641
7
+ data.tar.gz: 1d0a4c17a13822cea9d33b2dbdc937e1ea34559910821224b41230b1ac5ab4873f55b423d456fde87866befad8494972963f92dcddf188c996a6d04e8488ba2b
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,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
 
@@ -35,8 +38,6 @@ Enhances the following objects:
35
38
 
36
39
  == Setup
37
40
 
38
- === Production
39
-
40
41
  To install, run:
41
42
 
42
43
  [source,bash]
@@ -51,24 +52,6 @@ Add the following to your Gemfile file:
51
52
  gem "refinements"
52
53
  ----
53
54
 
54
- === Development
55
-
56
- To contribute, run:
57
-
58
- [source,bash]
59
- ----
60
- git clone https://github.com/bkuhlmann/refinements.git
61
- cd refinements
62
- bin/setup
63
- ----
64
-
65
- You can also use the IRB console for direct access to all objects:
66
-
67
- [source,bash]
68
- ----
69
- bin/console
70
- ----
71
-
72
55
  == Usage
73
56
 
74
57
  === Requires
@@ -93,6 +76,7 @@ require "refinements/ios"
93
76
  require "refinements/pathnames"
94
77
  require "refinements/strings"
95
78
  require "refinements/string_ios"
79
+ require "refinements/structs"
96
80
  ----
97
81
 
98
82
  === Using
@@ -112,6 +96,7 @@ class Example
112
96
  using Refinements::Pathnames
113
97
  using Refinements::Strings
114
98
  using Refinements::StringIOs
99
+ using Refinements::Structs
115
100
  end
116
101
  ----
117
102
 
@@ -143,24 +128,47 @@ example.compress! # => ["An", "Example"]
143
128
  example # => ["An", "Example"]
144
129
  ----
145
130
 
146
- ===== #include
131
+ ===== #excluding
132
+
133
+ Removes given array or elements without mutating itself.
134
+
135
+ [source,ruby]
136
+ ----
137
+ [1, 2, 3, 4, 5].excluding [4, 5] # => [1, 2, 3]
138
+ [1, 2, 3, 4, 5].excluding 4, 5 # => [1, 2, 3]
139
+ ----
140
+
141
+ ===== #including
147
142
 
148
143
  Adds given array or elements without mutating itself.
149
144
 
150
145
  [source,ruby]
151
146
  ----
152
- [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
153
- [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
147
+ [1, 2, 3].including [4, 5] # => [1, 2, 3, 4, 5]
148
+ [1, 2, 3].including 4, 5 # => [1, 2, 3, 4, 5]
154
149
  ----
155
150
 
156
- ===== #exclude
151
+ ===== #intersperse
157
152
 
158
- Removes given array or elements without mutating itself.
153
+ Inserts additional elements or array between all members of given array.
154
+
155
+ [source,ruby]
156
+ ----
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]
160
+ ----
161
+
162
+ ===== #mean
163
+
164
+ Answers mean/average all elements within an array.
159
165
 
160
166
  [source,ruby]
161
167
  ----
162
- [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
163
- [1, 2, 3, 4, 5].exclude 4, 5 # => [1, 2, 3]
168
+ [].mean # => 0
169
+ [5].mean # => 5
170
+ [1, 2, 3].mean # => 2
171
+ [1.25, 1.5, 1.75].mean # => 1.5
164
172
  ----
165
173
 
166
174
  ===== #ring
@@ -232,106 +240,10 @@ Answers new hash where every top-level missing key has the same default value.
232
240
  [source,ruby]
233
241
  ----
234
242
  example = Hash.with_default ""
235
- example[:a] # => ""
243
+ example[:a] # => ""
236
244
 
237
245
  example = Hash.with_default []
238
- example[:b] # => []
239
- ----
240
-
241
- ===== #except
242
-
243
- Answers new hash with given keys removed without mutating itself.
244
-
245
- [source,ruby]
246
- ----
247
- 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.
255
-
256
- [source,ruby]
257
- ----
258
- example = {a: 1, b: 2, 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
- ----
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
- ----
321
- example = {"a" => 1, "b" => 2}
322
- example.symbolize_keys # => {a: 1, b: 2}
323
- example # => {"a" => 1, "b" => 2}
324
- ----
325
-
326
- ===== #symbolize_keys!
327
-
328
- Converts keys to symbols while mutating itself.
329
-
330
- [source,ruby]
331
- ----
332
- example = {"a" => 1, "b" => 2}
333
- example.symbolize_keys! # => {a: 1, b: 2}
334
- example # => {a: 1, b: 2}
246
+ example[:b] # => []
335
247
  ----
336
248
 
337
249
  ===== #deep_merge
@@ -400,6 +312,58 @@ example.deep_symbolize_keys! # => {a: {b: 1}}
400
312
  example # => {a: {b: 1}}
401
313
  ----
402
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
+
403
367
  ===== #recurse
404
368
 
405
369
  Recursively iterates over the hash and any hash value by applying the given block to it. Does not
@@ -456,6 +420,50 @@ example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
456
420
  example # => {a: 1, b: 2, c: 3}
457
421
  ----
458
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
+
459
467
  ===== #use
460
468
 
461
469
  Passes each hash value as a block argument for further processing.
@@ -463,7 +471,7 @@ Passes each hash value as a block argument for further processing.
463
471
  [source,ruby]
464
472
  ----
465
473
  example = {unit: "221B", street: "Baker Street", city: "London", country: "UK"}
466
- example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
474
+ example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
467
475
  ----
468
476
 
469
477
  ==== IO
@@ -476,23 +484,8 @@ block, you'll need to close the stream manually.
476
484
 
477
485
  [source,ruby]
478
486
  ----
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 # => ""
487
+ io = IO.void # => #<IO:fd 20>
488
+ io = IO.void { |void| void.write "nevermore" } # => #<IO:(closed)>
496
489
  ----
497
490
 
498
491
  ===== #redirect
@@ -505,11 +498,8 @@ answered instead.
505
498
  io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
506
499
  other = IO.new IO.sysopen(Pathname("other.txt").to_s, "w+")
507
500
 
508
- io.redirect other # => `io`
509
-
510
- io.redirect(other) { |stream| stream.write "test" }
511
- .close # => ""
512
- other.close # => "test"
501
+ io.redirect other # => #<IO:fd 20>
502
+ io.redirect(other) { |stream| stream.write "test" } # => #<IO:fd 21>
513
503
  ----
514
504
 
515
505
  ===== #reread
@@ -525,45 +515,65 @@ io.reread # => "This is a test."
525
515
  io.reread 4 # => "This"
526
516
 
527
517
  buffer = "".dup
528
- io.reread(buffer: buffer)
529
- 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 # => ""
530
533
  ----
531
534
 
532
535
  ==== Pathname
533
536
 
534
537
  ===== Pathname
535
538
 
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.
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.
540
543
 
541
544
  [source,ruby]
542
545
  ----
543
546
  Pathname(nil) # => Pathname("")
544
547
  ----
545
548
 
546
- ===== #name
549
+ ===== #change_dir
547
550
 
548
- Answers file name without extension.
551
+ Inherits and wraps `Dir.chdir` behavior by changing to directory of current path. See
552
+ link:https://rubyapi.org/2.7/o/s?q=Dir.chdir[Dir.chdir] for details.
549
553
 
550
554
  [source,ruby]
551
555
  ----
552
- Pathname("example.txt").name # => Pathname("example")
556
+ Pathname.pwd # => "/"
557
+ Pathname("/test").make_dir.change_dir # => Pathname "/test"
558
+ Pathname.pwd # => "/test"
559
+
560
+ Pathname.pwd # => "/"
561
+ Pathname("/test").make_dir.change_dir { "example" } # => "example"
562
+ Pathname.pwd # => "/"
553
563
  ----
554
564
 
555
565
  ===== #copy
556
566
 
557
- Copies file from current location to new location.
567
+ Copies file from current location to new location while answering itself so it can be chained.
558
568
 
559
569
  [source,ruby]
560
570
  ----
561
- Pathname("input.txt").copy Pathname("output.txt")
571
+ Pathname("input.txt").copy Pathname("output.txt") # => Pathname("input.txt")
562
572
  ----
563
573
 
564
574
  ===== #directories
565
575
 
566
- Answers all or filtered directories for current path.
576
+ Answers all directories or filtered directories for current path.
567
577
 
568
578
  [source,ruby]
569
579
  ----
@@ -578,12 +588,12 @@ Answers file extensions as an array.
578
588
 
579
589
  [source,ruby]
580
590
  ----
581
- Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
591
+ Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
582
592
  ----
583
593
 
584
594
  ===== #files
585
595
 
586
- Answers all or filtered files for current path.
596
+ Answers all files or filtered files for current path.
587
597
 
588
598
  [source,ruby]
589
599
  ----
@@ -605,6 +615,48 @@ Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
605
615
  # => Pathname("/test/some/test")
606
616
  ----
607
617
 
618
+ ===== #make_ancestors
619
+
620
+ Ensures all ancestor directories are created for a path.
621
+
622
+ [source,ruby]
623
+ ----
624
+ Pathname("/one/two").make_ancestors # => Pathname("/one/two")
625
+ Pathname("/one").exist? # => true
626
+ Pathname("/one/two").exist? # => false
627
+ ----
628
+
629
+ ===== #make_dir
630
+
631
+ Provides alternative `#mkdir` behavior by always answering itself (even when directory exists) and
632
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
633
+
634
+ [source,ruby]
635
+ ----
636
+ Pathname("/one").make_dir # => Pathname("/one")
637
+ Pathname("/one").make_dir.make_dir # => Pathname("/one")
638
+ ----
639
+
640
+ ===== #make_path
641
+
642
+ Provides alternative `#mkpath` behavior by always answering itself (even when full path exists) and
643
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
644
+
645
+ [source,ruby]
646
+ ----
647
+ Pathname("/one/two/three").make_path # => Pathname("/one/two/three")
648
+ Pathname("/one/two/three").make_path.make_path # => Pathname("/one/two/three")
649
+ ----
650
+
651
+ ===== #name
652
+
653
+ Answers file name without extension.
654
+
655
+ [source,ruby]
656
+ ----
657
+ Pathname("example.txt").name # => Pathname("example")
658
+ ----
659
+
608
660
  ===== #relative_parent
609
661
 
610
662
  Answers relative path from parent directory. This is a complement to `#relative_path_from`.
@@ -614,59 +666,74 @@ Answers relative path from parent directory. This is a complement to `#relative_
614
666
  Pathname("/one/two/three").relative_parent("/one") # => Pathname "two"
615
667
  ----
616
668
 
617
- ===== #make_ancestors
669
+ ===== #remove_dir
618
670
 
619
- Ensures all ancestor directories are created for a path.
671
+ Provides alternative `#rmdir` behavior by always answering itself (even when full path exists) and
672
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
620
673
 
621
674
  [source,ruby]
622
675
  ----
623
- Pathname("/one/two").make_ancestors
624
- Pathname("/one").exist? # => true
625
- Pathname("/one/two").exist? # => false
676
+ Pathname("/test").make_dir.remove_dir.exist? # => false
677
+ Pathname("/test").remove_dir # => Pathname("/test")
678
+ Pathname("/test").remove_dir.remove_dir # => Pathname("/test")
626
679
  ----
627
680
 
628
- ===== #rewrite
681
+ ===== #remove_tree
629
682
 
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.
683
+ Provides alternative `#rmtree` behavior by always answering itself (even when full path exists) and
684
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
632
685
 
633
686
  [source,ruby]
634
687
  ----
635
- Pathname("/test.txt").rewrite { |content| content.sub "[placeholder]", "example" }
688
+ parent_path = Pathname "/one"
689
+ child_path = parent_path.join "two"
690
+
691
+ child_path.make_path
692
+ child_path.remove_tree # => Pathname "/one/two"
693
+ child_path.exist? # => false
694
+ paremt_path.exist? # => true
695
+
696
+ child_path.make_path
697
+ parent_path.remove_tree # => Pathname "/one"
698
+ child_path.exist? # => false
699
+ parent_path.exist? # => false
636
700
  ----
637
701
 
638
- ===== #touch
702
+ ===== #rewrite
639
703
 
640
- Updates access and modification times for path. Defaults to current time.
704
+ When given a block, it provides the contents of the recently read file for manipulation and
705
+ immediate writing back to the same file.
641
706
 
642
707
  [source,ruby]
643
708
  ----
644
- Pathname("example.txt").touch
645
- Pathname("example.txt").touch at: Time.now - 1
709
+ Pathname("/test.txt").rewrite # => Pathname("/test.txt")
710
+ Pathname("/test.txt").rewrite { |body| body.sub "[token]", "example" } # => Pathname("/test.txt")
646
711
  ----
647
712
 
648
- ==== String
649
-
650
- ===== #first
713
+ ===== #touch
651
714
 
652
- Answers first character of a string or first set of characters if given a number.
715
+ Updates access and modification times for path. Defaults to current time.
653
716
 
654
717
  [source,ruby]
655
718
  ----
656
- "example".first # => "e"
657
- "example".first 4 # => "exam"
719
+ Pathname("example.txt").touch # => Pathname("example.txt")
720
+ Pathname("example.txt").touch at: Time.now - 1 # => Pathname("example.txt")
658
721
  ----
659
722
 
660
- ===== #last
723
+ ===== #write
661
724
 
662
- Answers last character of a string or last set of characters if given a number.
725
+ Writes to file and answers itself so it can be chained. See `IO.write` for details on additional
726
+ options.
663
727
 
664
728
  [source,ruby]
665
729
  ----
666
- "instant".last # => "t"
667
- "instant".last 3 # => "ant"
730
+ Pathname("example.txt").write "test" # => Pathname("example.txt")
731
+ Pathname("example.txt").write "test", offset: 1 # => Pathname("example.txt")
732
+ Pathname("example.txt").write "test", mode: "a" # => Pathname("example.txt")
668
733
  ----
669
734
 
735
+ ==== String
736
+
670
737
  ===== #blank?
671
738
 
672
739
  Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`, and/or `\r`.
@@ -676,13 +743,13 @@ Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`,
676
743
  " \n\t\r".blank? # => true
677
744
  ----
678
745
 
679
- ===== #up
746
+ ===== #camelcase
680
747
 
681
- Answers string with only first letter upcased.
748
+ Answers a camelcased string.
682
749
 
683
750
  [source,ruby]
684
751
  ----
685
- "example".up # => "Example"
752
+ "this_is_an_example".camelcase # => "ThisIsAnExample"
686
753
  ----
687
754
 
688
755
  ===== #down
@@ -694,6 +761,16 @@ Answers string with only first letter downcased.
694
761
  "EXAMPLE".down # => "eXAMPLE"
695
762
  ----
696
763
 
764
+ ===== #first
765
+
766
+ Answers first character of a string or first set of characters if given a number.
767
+
768
+ [source,ruby]
769
+ ----
770
+ "example".first # => "e"
771
+ "example".first 4 # => "exam"
772
+ ----
773
+
697
774
  ===== #indent
698
775
 
699
776
  Answers string indented by two spaces by default.
@@ -707,13 +784,14 @@ Answers string indented by two spaces by default.
707
784
  "example".indent 3, padding: " " # => " example"
708
785
  ----
709
786
 
710
- ===== #camelcase
787
+ ===== #last
711
788
 
712
- Answers a camelcased string.
789
+ Answers last character of a string or last set of characters if given a number.
713
790
 
714
791
  [source,ruby]
715
792
  ----
716
- "this_is_an_example".camelcase # => "ThisIsAnExample"
793
+ "instant".last # => "t"
794
+ "instant".last 3 # => "ant"
717
795
  ----
718
796
 
719
797
  ===== #snakecase
@@ -747,6 +825,15 @@ Answers string as a boolean.
747
825
  "example".to_bool # => false
748
826
  ----
749
827
 
828
+ ===== #up
829
+
830
+ Answers string with only first letter upcased.
831
+
832
+ [source,ruby]
833
+ ----
834
+ "example".up # => "Example"
835
+ ----
836
+
750
837
  ==== String IO
751
838
 
752
839
  ===== #reread
@@ -762,8 +849,70 @@ io.reread # => "This is a test."
762
849
  io.reread 4 # => "This"
763
850
 
764
851
  buffer = "".dup
765
- io.reread(buffer: buffer)
766
- buffer # => "This is a test."
852
+ io.reread(buffer: buffer) # => "This is a test."
853
+ buffer # => "This is a test."
854
+ ----
855
+
856
+ ==== Struct
857
+
858
+ ===== #merge
859
+
860
+ Merges multiple attributes without mutating itself.
861
+
862
+ [source,ruby]
863
+ ----
864
+ Example = Struct.new :a, :b, :c
865
+ example = Example[1, 2, 3]
866
+ example.merge a: 10 # => #<struct a=10, b=2, c=3>
867
+ example.merge a: 10, c: 30 # => #<struct a=10, b=2, c=30>
868
+ example.merge a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
869
+ example # => #<struct a=1, b=2, c=3>
870
+
871
+ Example = Struct.new :a, :b, :c, keyword_init: true
872
+ example = Example[a: 1, b: 2, c: 3]
873
+ example.merge a: 10 # => #<struct a=10, b=2, c=3>
874
+ example.merge a: 10, c: 30 # => #<struct a=10, b=2, c=30>
875
+ example.merge a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
876
+ example # => #<struct a=1, b=2, c=3>
877
+ ----
878
+
879
+ ===== #merge!
880
+
881
+ Merges multiple attributes while mutating itself.
882
+
883
+ [source,ruby]
884
+ ----
885
+ Example = Struct.new :a, :b, :c
886
+ example = Example[1, 2, 3]
887
+ example.merge! a: 10 # => #<struct a=10, b=2, c=3>
888
+ example.merge! a: 10, c: 30 # => #<struct a=10, b=2, c=30>
889
+ example.merge! a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
890
+ example # => #<struct a=10, b=20, c=30>
891
+
892
+ Example = Struct.new :a, :b, :c, keyword_init: true
893
+ example = Example[a: 1, b: 2, c: 3]
894
+ example.merge! a: 10 # => #<struct a=10, b=2, c=3>
895
+ example.merge! a: 10, c: 30 # => #<struct a=10, b=2, c=30>
896
+ example.merge! a: 10, b: 20, c: 30 # => #<struct a=10, b=20, c=30>
897
+ example # => #<struct a=10, b=20, c=30>
898
+ ----
899
+
900
+ == Development
901
+
902
+ To contribute, run:
903
+
904
+ [source,bash]
905
+ ----
906
+ git clone https://github.com/bkuhlmann/refinements.git
907
+ cd refinements
908
+ bin/setup
909
+ ----
910
+
911
+ You can also use the IRB console for direct access to all objects:
912
+
913
+ [source,bash]
914
+ ----
915
+ bin/console
767
916
  ----
768
917
 
769
918
  == Tests
@@ -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,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,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.11.0"
8
+ VERSION = "7.15.1"
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
@@ -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 ? 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,20 +71,28 @@ 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
 
57
83
  def rewrite
58
84
  read.then { |content| write yield(content) if block_given? }
59
- self
60
85
  end
61
86
 
62
87
  def touch at: Time.now
63
88
  exist? ? utime(at, at) : write("")
64
89
  self
65
90
  end
91
+
92
+ def write content, offset: nil, **options
93
+ super content, offset, **options
94
+ self
95
+ end
66
96
  end
67
97
  end
68
98
  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.11.0
4
+ version: 7.15.1
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-10-06 00:00:00.000000000 Z
31
+ date: 2020-11-21 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler-audit
@@ -36,42 +36,56 @@ 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
+ - !ruby/object:Gem::Dependency
48
+ name: bundler-leak
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.2'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.2'
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: gemsmith
49
63
  requirement: !ruby/object:Gem::Requirement
50
64
  requirements:
51
65
  - - "~>"
52
66
  - !ruby/object:Gem::Version
53
- version: '14.2'
67
+ version: '14.8'
54
68
  type: :development
55
69
  prerelease: false
56
70
  version_requirements: !ruby/object:Gem::Requirement
57
71
  requirements:
58
72
  - - "~>"
59
73
  - !ruby/object:Gem::Version
60
- version: '14.2'
74
+ version: '14.8'
61
75
  - !ruby/object:Gem::Dependency
62
76
  name: git-lint
63
77
  requirement: !ruby/object:Gem::Requirement
64
78
  requirements:
65
79
  - - "~>"
66
80
  - !ruby/object:Gem::Version
67
- version: '1.0'
81
+ version: '1.3'
68
82
  type: :development
69
83
  prerelease: false
70
84
  version_requirements: !ruby/object:Gem::Requirement
71
85
  requirements:
72
86
  - - "~>"
73
87
  - !ruby/object:Gem::Version
74
- version: '1.0'
88
+ version: '1.3'
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: guard-rspec
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -148,42 +162,42 @@ dependencies:
148
162
  requirements:
149
163
  - - "~>"
150
164
  - !ruby/object:Gem::Version
151
- version: '3.9'
165
+ version: '3.10'
152
166
  type: :development
153
167
  prerelease: false
154
168
  version_requirements: !ruby/object:Gem::Requirement
155
169
  requirements:
156
170
  - - "~>"
157
171
  - !ruby/object:Gem::Version
158
- version: '3.9'
172
+ version: '3.10'
159
173
  - !ruby/object:Gem::Dependency
160
174
  name: rubocop
161
175
  requirement: !ruby/object:Gem::Requirement
162
176
  requirements:
163
177
  - - "~>"
164
178
  - !ruby/object:Gem::Version
165
- version: '0.89'
179
+ version: '1.3'
166
180
  type: :development
167
181
  prerelease: false
168
182
  version_requirements: !ruby/object:Gem::Requirement
169
183
  requirements:
170
184
  - - "~>"
171
185
  - !ruby/object:Gem::Version
172
- version: '0.89'
186
+ version: '1.3'
173
187
  - !ruby/object:Gem::Dependency
174
188
  name: rubocop-performance
175
189
  requirement: !ruby/object:Gem::Requirement
176
190
  requirements:
177
191
  - - "~>"
178
192
  - !ruby/object:Gem::Version
179
- version: '1.5'
193
+ version: '1.8'
180
194
  type: :development
181
195
  prerelease: false
182
196
  version_requirements: !ruby/object:Gem::Requirement
183
197
  requirements:
184
198
  - - "~>"
185
199
  - !ruby/object:Gem::Version
186
- version: '1.5'
200
+ version: '1.8'
187
201
  - !ruby/object:Gem::Dependency
188
202
  name: rubocop-rake
189
203
  requirement: !ruby/object:Gem::Requirement
@@ -204,14 +218,14 @@ dependencies:
204
218
  requirements:
205
219
  - - "~>"
206
220
  - !ruby/object:Gem::Version
207
- version: '1.39'
221
+ version: '2.0'
208
222
  type: :development
209
223
  prerelease: false
210
224
  version_requirements: !ruby/object:Gem::Requirement
211
225
  requirements:
212
226
  - - "~>"
213
227
  - !ruby/object:Gem::Version
214
- version: '1.39'
228
+ version: '2.0'
215
229
  - !ruby/object:Gem::Dependency
216
230
  name: simplecov
217
231
  requirement: !ruby/object:Gem::Requirement
@@ -248,6 +262,7 @@ files:
248
262
  - lib/refinements/pathnames.rb
249
263
  - lib/refinements/string_ios.rb
250
264
  - lib/refinements/strings.rb
265
+ - lib/refinements/structs.rb
251
266
  homepage: https://www.alchemists.io/projects/refinements
252
267
  licenses:
253
268
  - Apache-2.0
metadata.gz.sig CHANGED
Binary file