refinements 7.4.0 → 7.9.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: aa83a3ce542b62b6d89204aea8ac2411565a401f26150bfcdc64a2d4334d0313
4
- data.tar.gz: c34503ce9aa7b522eac87ff66384fc8c1815c5907e4048a6023208f948a33cd1
3
+ metadata.gz: ba7c2934d38986ae19d3a41bdc1305164ebe2355bb30afa925eebbeb9746f962
4
+ data.tar.gz: 1945d2226c6ca304aa9958635aab6a87880b66e43566691c3ab509f5b2e77f6b
5
5
  SHA512:
6
- metadata.gz: 8bc6f8633db7a9caed51998e190aeccb77b74a755d83a8a982e93d7c4c9576044598e626b9457fb40da667aff76c9d87314ad42f4e2815d8287435eee5d71e2a
7
- data.tar.gz: c23828f5179b57747cd0a173baa7deeee2fc1513791ecf1042612a23addf8443c7c012c6f316596b197a8765904e66d93f31141037271673e50bf2a6b9b56da8
6
+ metadata.gz: 34e601f3bfe0ebe6b35ddf54dea67ef9c33d7436fae5103a2ce03106a34026f1920a6f06369ba2516ceb0a550bb6868fcd5491084cca5b6dd20ed746b4772a39
7
+ data.tar.gz: 8e4d5de5f29f28df044333dbaa34fb0a6d9b34911e3e911bd5593caf4dfeb52c0c0767f5a01d164542c54a4d936453b14f6131c055234a5911d73c80673c7d14
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -15,62 +15,22 @@ toc::[]
15
15
 
16
16
  == Features
17
17
 
18
- * *Arrays*:
19
- ** `#compress` - Removes `nil` and empty values without modifying itself.
20
- ** `#compress!` - Removes `nil` and empty values while modifying itself.
21
- ** `#ring` - Answers a circular array which can enumerate before, current, after elements.
22
- * *BigDecimals*:
23
- ** `#inspect` - Allows one to inspect a big decimal with numeric representation.
24
- * *DateTimes*:
25
- ** `.utc` - Answers new DateTime object for current UTC date/time.
26
- * *Files*:
27
- ** `#rewrite` - When given a file path and a block, it provides the contents of the recently read
28
- file for manipulation and immediate writing back to the same file.
29
- * *Hashes*:
30
- ** `#except` - Answers new hash with given keys removed without modifying calling hash.
31
- ** `#except!` - Answers new hash with given keys removed while modifying calling hash.
32
- ** `#symbolize_keys` - Converts keys to symbols without modifying itself.
33
- ** `#symbolize_keys!` - Converts keys to symbols while modifying itself.
34
- ** `#deep_merge` - Merges deeply nested hashes together without modifying itself.
35
- ** `#deep_merge!` - Merges deeply nested hashes together while modifying itself.
36
- ** `#deep_symbolize_keys` - Symbolizes keys of nested hash without modifying itself. Does not handle
37
- nested arrays, though.
38
- ** `#deep_symbolize_keys!` - Symbolizes keys of nested hash while modifying itself. Does not handle
39
- nested arrays, though.
40
- ** `#recurse` - Applies block to nested hash. Does not handle nested arrays, though.
41
- ** `#rekey` - Transforms keys per mapping (size of mapping can vary).
42
- ** `#reverse_merge` - Merges calling hash into passed in hash without modifying calling hash.
43
- ** `#reverse_merge!` - Merges calling hash into passed in hash while modifying calling hash.
44
- ** `#use` - Passes each hash value as a block argument for further processing.
45
- * *Pathnames*:
46
- ** `#name` - Answers file name without extension.
47
- ** `#copy` - Copies file from current location to new location.
48
- ** `#directories` - Answers all or filtered directories for current path.
49
- ** `#extensions` - Answers file extensions as an array.
50
- ** `#files` - Answers all or filtered files for current path.
51
- ** `#relative_parent_from` - Answers relative path from parent directory. This is a complement to
52
- `#relative_path_from`.
53
- ** `#make_ancestors` - Ensures all ancestor directories are created for a path.
54
- ** `#rewrite` - When given a block, it provides the contents of the recently read file for
55
- manipulation and immediate writing back to the same file.
56
- ** `#touch` - Updates access and modification times to current time for path.
57
- * *Strings*:
58
- ** `#first` - Answers first character of a string or first set of characters if given a number.
59
- ** `#last` - Answers last character of a string or last set of characters if given a number.
60
- ** `#blank?` - Answers `true`/`false` based on whether string is blank or not
61
- (i.e. `<space>`, `\n`, `\t`, `\r`).
62
- ** `#up` - Answers string with only first letter upcased.
63
- ** `#down` - Answers string with only first letter downcased.
64
- ** `#camelcase` - Answers a camelcased string.
65
- ** `#snakecase` - Answers a snakecased string.
66
- ** `#titleize` - Answers titleized string.
67
- ** `#to_bool` - Answers string as a boolean.
18
+ Enhances the following objects:
19
+
20
+ * Array
21
+ * BigDecimal
22
+ * DateTime
23
+ * File
24
+ * Hash
25
+ * Pathname
26
+ * String
27
+ * StringIO
68
28
 
69
29
  == Requirements
70
30
 
71
- . https://www.ruby-lang.org[Ruby 2.7.x].
72
- . A solid understanding of https://www.youtube.com/watch?v=qXC9Gk4dCEw[Ruby refinements and lexical
73
- scope].
31
+ . https://www.ruby-lang.org[Ruby].
32
+ . A solid understanding of link:https://www.alchemists.io/articles/ruby_refinements[Ruby refinements
33
+ and lexical scope].
74
34
 
75
35
  == Setup
76
36
 
@@ -130,6 +90,7 @@ require "refinements/files"
130
90
  require "refinements/hashes"
131
91
  require "refinements/pathnames"
132
92
  require "refinements/strings"
93
+ require "refinements/string_ios"
133
94
  ----
134
95
 
135
96
  === Using
@@ -146,6 +107,7 @@ class Example
146
107
  using Refinements::Hashes
147
108
  using Refinements::Pathnames
148
109
  using Refinements::Strings
110
+ using Refinements::StringIOs
149
111
  end
150
112
  ----
151
113
 
@@ -155,19 +117,58 @@ The following sections demonstrate how each refinement enriches your objects wit
155
117
 
156
118
  ==== Array
157
119
 
120
+ ===== #compress
121
+
122
+ Removes `nil` and empty values without modifying itself.
123
+
158
124
  [source,ruby]
159
125
  ----
160
126
  example = ["An", nil, "", "Example"]
161
- example.compress # => ["An", "Example"]
162
- example # => ["An", nil, "", "Example"]
127
+ example.compress # => ["An", "Example"]
128
+ example # => ["An", nil, "", "Example"]
129
+ ----
130
+
131
+ ===== #compress!
163
132
 
133
+ Removes `nil` and empty values while modifying itself.
134
+
135
+ [source,ruby]
136
+ ----
164
137
  example = ["An", nil, "", "Example"]
165
- example.compress! # => ["An", "Example"]
166
- example # => ["An", "Example"]
138
+ example.compress! # => ["An", "Example"]
139
+ example # => ["An", "Example"]
140
+ ----
141
+
142
+ ===== #include
143
+
144
+ Adds given array or elements without modifying itself.
145
+
146
+ [source,ruby]
147
+ ----
148
+ [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
149
+ [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
150
+ ----
151
+
152
+ ===== #exclude
153
+
154
+ Removes given array or elements without modifying itself.
155
+
156
+ [source,ruby]
157
+ ----
158
+ [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
159
+ [1, 2, 3, 4, 5].exclude 4, 5 # => [1, 2, 3]
160
+ ----
161
+
162
+ ===== #ring
167
163
 
164
+ Answers a circular array which can enumerate before, current, after elements.
165
+
166
+ [source,ruby]
167
+ ----
168
168
  example = [1, 2, 3]
169
169
  example.ring # => #<Enumerator: ...>
170
170
  example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
171
+
171
172
  # [3 1 2]
172
173
  # [1 2 3]
173
174
  # [2 3 1]
@@ -175,6 +176,10 @@ example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
175
176
 
176
177
  ==== Big Decimal
177
178
 
179
+ ===== #inspect
180
+
181
+ Allows one to inspect a big decimal with numeric representation.
182
+
178
183
  [source,ruby]
179
184
  ----
180
185
  BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
@@ -182,6 +187,10 @@ BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
182
187
 
183
188
  ==== DateTime
184
189
 
190
+ ===== .utc
191
+
192
+ Answers new DateTime object for current UTC date/time.
193
+
185
194
  [source,ruby]
186
195
  ----
187
196
  DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867000n),+0s,2299161j)>
@@ -189,6 +198,11 @@ DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867
189
198
 
190
199
  ==== File
191
200
 
201
+ ===== .rewrite
202
+
203
+ When given a file path and a block, it provides the contents of the recently read file for
204
+ manipulation and immediate writing back to the same file.
205
+
192
206
  [source,ruby]
193
207
  ----
194
208
  File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
@@ -196,122 +210,432 @@ File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
196
210
 
197
211
  ==== Hash
198
212
 
213
+ ===== .infinite
214
+
215
+ Answers new hash where missing keys, even deeply nested, answer an empty hash.
216
+
217
+ [source,ruby]
218
+ ----
219
+ example = Hash.infinite
220
+ example[:a] # => {}
221
+ example[:a][:b][:c] # => {}
222
+ ----
223
+
224
+ ===== .with_default
225
+
226
+ Answers new hash where every top-level missing key has the same default value.
227
+
228
+ [source,ruby]
229
+ ----
230
+ example = Hash.with_default ""
231
+ example[:a] # => ""
232
+
233
+ example = Hash.with_default []
234
+ example[:b] # => []
235
+ ----
236
+
237
+ ===== #except
238
+
239
+ Answers new hash with given keys removed without modifying itself.
240
+
199
241
  [source,ruby]
200
242
  ----
201
243
  example = {a: 1, b: 2, c: 3}
202
- example.except :a, :b # => {c: 3}
203
- example # => {a: 1, b: 2, c: 3}
244
+ example.except :a, :b # => {c: 3}
245
+ example # => {a: 1, b: 2, c: 3}
246
+ ----
247
+
248
+ ===== #except!
249
+
250
+ Answers new hash with given keys removed while modifying itself.
204
251
 
252
+ [source,ruby]
253
+ ----
205
254
  example = {a: 1, b: 2, c: 3}
206
- example.except! :a, :b # => {c: 3}
207
- example # => {c: 3}
255
+ example.except! :a, :b # => {c: 3}
256
+ example # => {c: 3}
257
+ ----
258
+
259
+ ===== #flatten_keys
260
+
261
+ Flattens nested keys as top-level keys without modifying itself. Does not handle nested arrays,
262
+ though.
263
+
264
+ [source,ruby]
265
+ ----
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}}
275
+ ----
208
276
 
277
+ ===== #flatten_keys!
278
+
279
+ Flattens nested keys as top-level keys while modifying itself. Does not handle nested arrays,
280
+ though.
281
+
282
+ [source,ruby]
283
+ ----
284
+ example = {a: {b: 1}}
285
+ example.flatten_keys! # => {a_b: 1}
286
+ example # => {a_b: 1}
287
+ ----
288
+
289
+ ===== #symbolize_keys
290
+
291
+ Converts keys to symbols without modifying itself.
292
+
293
+ [source,ruby]
294
+ ----
209
295
  example = {"a" => 1, "b" => 2}
210
- example.symbolize_keys # => {a: 1, b: 2}
211
- example # => {"a" => 1, "b" => 2}
296
+ example.symbolize_keys # => {a: 1, b: 2}
297
+ example # => {"a" => 1, "b" => 2}
298
+ ----
212
299
 
300
+ ===== #symbolize_keys!
301
+
302
+ Converts keys to symbols while modifying itself.
303
+
304
+ [source,ruby]
305
+ ----
213
306
  example = {"a" => 1, "b" => 2}
214
- example.symbolize_keys! # => {a: 1, b: 2}
215
- example # => {a: 1, b: 2}
307
+ example.symbolize_keys! # => {a: 1, b: 2}
308
+ example # => {a: 1, b: 2}
309
+ ----
216
310
 
217
- example = {a: 1, b: 2, c: 3}
218
- example.slice :a, :c # => {a: 1, c: 3}
219
- example # => {a: 1, b: 2, c: 3}
311
+ ===== #deep_merge
220
312
 
221
- example = {a: 1, b: 2, c: 3}
222
- example.slice! :a, :c # => {a: 1, c: 3}
223
- example # => {a: 1, c: 3}
313
+ Merges deeply nested hashes together without modifying itself.
224
314
 
315
+ [source,ruby]
316
+ ----
225
317
  example = {a: "A", b: {one: "One", two: "Two"}}
226
- example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
227
- 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"}}
320
+ ----
321
+
322
+ ===== #deep_merge!
323
+
324
+ Merges deeply nested hashes together while modifying itself.
228
325
 
326
+ [source,ruby]
327
+ ----
229
328
  example = {a: "A", b: {one: "One", two: "Two"}}
230
- example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
231
- example # => {a: "A", b: {one: 1, 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"}}
331
+ ----
232
332
 
333
+ ===== #deep_symbolize_keys
334
+
335
+ Symbolizes keys of nested hash without modifying itself. Does not handle nested arrays, though.
336
+
337
+ [source,ruby]
338
+ ----
233
339
  example = {"a" => {"b" => 2}}
234
- example.deep_symbolize_keys # => {a: {b: 1}}
235
- example # => {"a" => {"b" => 2}}
340
+ example.deep_symbolize_keys # => {a: {b: 1}}
341
+ example # => {"a" => {"b" => 2}}
342
+ ----
343
+
344
+ ===== #deep_symbolize_keys!
236
345
 
346
+ Symbolizes keys of nested hash while modifying itself. Does not handle nested arrays, though.
347
+
348
+ [source,ruby]
349
+ ----
237
350
  example = {"a" => {"b" => 2}}
238
- example.deep_symbolize_keys! # => {a: {b: 1}}
239
- example # => {a: {b: 1}}
351
+ example.deep_symbolize_keys! # => {a: {b: 1}}
352
+ example # => {a: {b: 1}}
353
+ ----
354
+
355
+ ===== #recurse
356
+
357
+ Applies block to nested hash. Does not handle nested arrays, though.
240
358
 
359
+ [source,ruby]
360
+ ----
241
361
  example = {"a" => {"b" => 1}}
242
- example.recurse(&:symbolize_keys) # => {a: {b: 1}}
243
- example.recurse(&:invert) # => {{"b" => 1} => "a"}
362
+ example.recurse(&:symbolize_keys) # => {a: {b: 1}}
363
+ example.recurse(&:invert) # => {{"b" => 1} => "a"}
364
+ ----
244
365
 
366
+ ===== #rekey
367
+
368
+ Transforms keys per mapping (size of mapping can vary) without modifying itself.
369
+
370
+ [source,ruby]
371
+ ----
372
+ example = {a: 1, b: 2, c: 3}
373
+ example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
374
+ example # => {a: 1, b: 2, c: 3}
375
+ ----
376
+
377
+ ===== #rekey!
378
+
379
+ Transforms keys per mapping (size of mapping can vary) while modifying itself.
380
+
381
+ [source,ruby]
382
+ ----
245
383
  example = {a: 1, b: 2, c: 3}
246
- example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
384
+ example.rekey! a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
385
+ example # => {amber: 1, blue: 2, c: 3}
386
+ ----
387
+
388
+ ===== #reverse_merge
389
+
390
+ Merges calling hash into passed in hash without modifying itself.
247
391
 
392
+ [source,ruby]
393
+ ----
248
394
  example = {a: 1, b: 2}
249
- example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
250
- example # => {a: 1, b: 2}
395
+ example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
396
+ example # => {a: 1, b: 2}
397
+ ----
398
+
399
+ ===== #reverse_merge!
251
400
 
401
+ Merges calling hash into passed in hash while modifying itself.
402
+
403
+ [source,ruby]
404
+ ----
252
405
  example = {a: 1, b: 2}
253
- example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
254
- example # => {a: 1, b: 2, c: 3}
406
+ example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
407
+ example # => {a: 1, b: 2, c: 3}
408
+ ----
255
409
 
410
+ ===== #use
411
+
412
+ Passes each hash value as a block argument for further processing.
413
+
414
+ [source,ruby]
415
+ ----
256
416
  example = {unit: "221B", street: "Baker Street", city: "London", country: "UK"}
257
417
  example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
258
418
  ----
259
419
 
260
420
  ==== Pathname
261
421
 
422
+ ===== Pathname
423
+
424
+ Conversion function (refined from `Kernel`) which can cast `nil` into a pathname.
425
+
426
+ [source,ruby]
427
+ ----
428
+ Pathname(nil) # => Pathname("")
429
+ ----
430
+
431
+ ===== #name
432
+
433
+ Answers file name without extension.
434
+
262
435
  [source,ruby]
263
436
  ----
264
437
  Pathname("example.txt").name # => Pathname("example")
438
+ ----
439
+
440
+ ===== #copy
441
+
442
+ Copies file from current location to new location.
265
443
 
444
+ [source,ruby]
445
+ ----
266
446
  Pathname("input.txt").copy Pathname("output.txt")
447
+ ----
448
+
449
+ ===== #directories
267
450
 
268
- Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
269
- Pathname("/example").directories "a*" # => [Pathname("a")]
451
+ Answers all or filtered directories for current path.
270
452
 
453
+ [source,ruby]
454
+ ----
455
+ Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
456
+ Pathname("/example").directories "a*" # => [Pathname("a")]
457
+ Pathname("/example").directories flag: File::FNM_DOTMATCH # => [Pathname(".."), Pathname(".")]
458
+ ----
459
+
460
+ ===== #extensions
461
+
462
+ Answers file extensions as an array.
463
+
464
+ [source,ruby]
465
+ ----
271
466
  Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
467
+ ----
272
468
 
273
- Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
274
- Pathname("/example").files "*.png" # => [Pathname("a.png")]
469
+ ===== #files
275
470
 
276
- Pathname("/one/two/three").relative_parent_from("/one") # => Pathname "two"
471
+ Answers all or filtered files for current path.
472
+
473
+ [source,ruby]
474
+ ----
475
+ Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
476
+ Pathname("/example").files "*.png" # => [Pathname("a.png")]
477
+ Pathname("/example").files flag: File::FNM_DOTMATCH # => [Pathname(".ruby-version")]
478
+ ----
479
+
480
+ ===== #gsub
481
+
482
+ Same behavior as `String#gsub` but answers a path with patterns replaced with desired substitutes.
483
+
484
+ [source,ruby]
485
+ ----
486
+ Pathname("/a/path/some/path").gsub("path", "test")
487
+ # => Pathname("/a/test/some/test")
277
488
 
489
+ Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
490
+ # => Pathname("/test/some/test")
491
+ ----
492
+
493
+ ===== #relative_parent
494
+
495
+ Answers relative path from parent directory. This is a complement to `#relative_path_from`.
496
+
497
+ [source,ruby]
498
+ ----
499
+ Pathname("/one/two/three").relative_parent("/one") # => Pathname "two"
500
+ ----
501
+
502
+ ===== #make_ancestors
503
+
504
+ Ensures all ancestor directories are created for a path.
505
+
506
+ [source,ruby]
507
+ ----
278
508
  Pathname("/one/two").make_ancestors
279
- Pathname("/one").exist? # => true
280
- Pathname("/one/two").exist? # => false
509
+ Pathname("/one").exist? # => true
510
+ Pathname("/one/two").exist? # => false
511
+ ----
512
+
513
+ ===== #rewrite
281
514
 
515
+ When given a block, it provides the contents of the recently read file for manipulation and
516
+ immediate writing back to the same file.
517
+
518
+ [source,ruby]
519
+ ----
282
520
  Pathname("/test.txt").rewrite { |content| content.sub "[placeholder]", "example" }
521
+ ----
283
522
 
523
+ ===== #touch
524
+
525
+ Updates access and modification times for path. Defaults to current time.
526
+
527
+ [source,ruby]
528
+ ----
284
529
  Pathname("example.txt").touch
285
- Pathname("example.txt").touch accessed_at: Time.now - 1, modified_at: Time.now - 1
530
+ Pathname("example.txt").touch at: Time.now - 1
286
531
  ----
287
532
 
288
533
  ==== String
289
534
 
535
+ ===== #first
536
+
537
+ Answers first character of a string or first set of characters if given a number.
538
+
539
+ [source,ruby]
540
+ ----
541
+ "example".first # => "e"
542
+ "example".first 4 # => "exam"
543
+ ----
544
+
545
+ ===== #last
546
+
547
+ Answers last character of a string or last set of characters if given a number.
548
+
290
549
  [source,ruby]
291
550
  ----
292
- "example".first # => "e"
293
- "example".first 4 # => "exam"
551
+ "instant".last # => "t"
552
+ "instant".last 3 # => "ant"
553
+ ----
294
554
 
295
- "instant".last # => "t"
296
- "instant".last 3 # => "ant"
555
+ ===== #blank?
297
556
 
557
+ Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`, and/or `\r`.
558
+
559
+ [source,ruby]
560
+ ----
298
561
  " \n\t\r".blank? # => true
562
+ ----
563
+
564
+ ===== #up
565
+
566
+ Answers string with only first letter upcased.
299
567
 
568
+ [source,ruby]
569
+ ----
300
570
  "example".up # => "Example"
571
+ ----
572
+
573
+ ===== #down
301
574
 
575
+ Answers string with only first letter downcased.
576
+
577
+ [source,ruby]
578
+ ----
302
579
  "EXAMPLE".down # => "eXAMPLE"
580
+ ----
581
+
582
+ ===== #camelcase
303
583
 
584
+ Answers a camelcased string.
585
+
586
+ [source,ruby]
587
+ ----
304
588
  "this_is_an_example".camelcase # => "ThisIsAnExample"
589
+ ----
590
+
591
+ ===== #snakecase
592
+
593
+ Answers a snakecased string.
305
594
 
595
+ [source,ruby]
596
+ ----
306
597
  "ThisIsAnExample".snakecase # => "this_is_an_example"
598
+ ----
599
+
600
+ ===== #titleize
307
601
 
602
+ Answers titleized string.
603
+
604
+ [source,ruby]
605
+ ----
308
606
  "ThisIsAnExample".titleize # => "This Is An Example"
607
+ ----
608
+
609
+ ===== #to_bool
610
+
611
+ Answers string as a boolean.
612
+
613
+ [source,ruby]
614
+ ----
615
+ "true".to_bool # => true
616
+ "yes".to_bool # => true
617
+ "1".to_bool # => true
618
+ "".to_bool # => false
619
+ "example".to_bool # => false
620
+ ----
621
+
622
+ ==== String IO
623
+
624
+ ===== #reread
625
+
626
+ Answers full string by rewinding to beginning of string and reading all content.
627
+
628
+ [source,ruby]
629
+ ----
630
+ io = StringIO.new
631
+ io.write "This is a test."
632
+
633
+ io.reread # => "This is a test."
634
+ io.reread 4 # => "This"
309
635
 
310
- "true".to_bool # => true
311
- "yes".to_bool # => true
312
- "1".to_bool # => true
313
- "".to_bool # => false
314
- "example".to_bool # => false
636
+ buffer = "".dup
637
+ io.reread(buffer: buffer)
638
+ buffer # => "This is a test."
315
639
  ----
316
640
 
317
641
  == Tests
@@ -8,3 +8,4 @@ require "refinements/files"
8
8
  require "refinements/hashes"
9
9
  require "refinements/pathnames"
10
10
  require "refinements/strings"
11
+ require "refinements/string_ios"
@@ -11,6 +11,14 @@ module Refinements
11
11
  replace compress
12
12
  end
13
13
 
14
+ def include *elements
15
+ self + elements.flatten
16
+ end
17
+
18
+ def exclude *elements
19
+ self - elements.flatten
20
+ end
21
+
14
22
  def ring &block
15
23
  [last, *self, first].each_cons 3, &block
16
24
  end
@@ -4,6 +4,7 @@ module Refinements
4
4
  module Files
5
5
  refine File.singleton_class do
6
6
  def rewrite path
7
+ warn "[DEPRECATION]: File.rewrite is deprecated, use Pathname#rewrite instead."
7
8
  read(path).then { |content| write path, yield(content) }
8
9
  end
9
10
  end
@@ -2,6 +2,16 @@
2
2
 
3
3
  module Refinements
4
4
  module Hashes
5
+ refine Hash.singleton_class do
6
+ def infinite
7
+ new { |new_hash, missing_key| new_hash[missing_key] = new(&new_hash.default_proc) }
8
+ end
9
+
10
+ def with_default value
11
+ new { |new_hash, missing_key| new_hash[missing_key] = value }
12
+ end
13
+ end
14
+
5
15
  refine Hash do
6
16
  def except *keys
7
17
  reject { |key, _value| keys.include? key }
@@ -11,6 +21,25 @@ module Refinements
11
21
  replace except(*keys)
12
22
  end
13
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
+
14
43
  def symbolize_keys
15
44
  reduce({}) { |hash, (key, value)| hash.merge key.to_sym => value }
16
45
  end
@@ -20,13 +49,9 @@ module Refinements
20
49
  end
21
50
 
22
51
  def deep_merge other
23
- dup.deep_merge! other
24
- end
25
-
26
- def deep_merge! other
27
52
  clazz = self.class
28
53
 
29
- merge! other do |_key, this_value, other_value|
54
+ merge other do |_key, this_value, other_value|
30
55
  if this_value.is_a?(clazz) && other_value.is_a?(clazz)
31
56
  this_value.deep_merge other_value
32
57
  else
@@ -35,12 +60,16 @@ module Refinements
35
60
  end
36
61
  end
37
62
 
63
+ def deep_merge! other
64
+ replace deep_merge(other)
65
+ end
66
+
38
67
  def deep_symbolize_keys
39
68
  recurse(&:symbolize_keys)
40
69
  end
41
70
 
42
71
  def deep_symbolize_keys!
43
- recurse(&:symbolize_keys!)
72
+ replace deep_symbolize_keys
44
73
  end
45
74
 
46
75
  def recurse &block
@@ -65,12 +94,12 @@ module Refinements
65
94
 
66
95
  def reverse_merge other
67
96
  warn "[DEPRECATION]: #reverse_merge is deprecated, use #merge instead."
68
- other.merge self
97
+ merge(other) { |_key, old_value, _new_value| old_value }
69
98
  end
70
99
 
71
100
  def reverse_merge! other
72
101
  warn "[DEPRECATION]: #reverse_merge! is deprecated, use #merge! instead."
73
- merge!(other) { |_key, old_value, _new_value| old_value }
102
+ replace reverse_merge(other)
74
103
  end
75
104
 
76
105
  def use &block
@@ -5,7 +5,7 @@ module Refinements
5
5
  module Identity
6
6
  NAME = "refinements"
7
7
  LABEL = "Refinements"
8
- VERSION = "7.4.0"
8
+ VERSION = "7.9.0"
9
9
  VERSION_LABEL = "#{LABEL} #{VERSION}"
10
10
  end
11
11
  end
@@ -4,6 +4,14 @@ require "pathname"
4
4
 
5
5
  module Refinements
6
6
  module Pathnames
7
+ refine Kernel do
8
+ def Pathname object
9
+ return super(String(object)) unless object
10
+
11
+ super
12
+ end
13
+ end
14
+
7
15
  refine Pathname do
8
16
  def name
9
17
  basename extname
@@ -15,20 +23,30 @@ module Refinements
15
23
  self
16
24
  end
17
25
 
18
- def directories pattern = "*"
19
- glob(pattern).select(&:directory?).sort
26
+ def directories pattern = "*", flag: File::FNM_SYSCASE
27
+ glob(pattern, flag).select(&:directory?).sort
20
28
  end
21
29
 
22
30
  def extensions
23
31
  basename.to_s.split(/(?=\.)+/).tap(&:shift)
24
32
  end
25
33
 
26
- def files pattern = "*"
27
- glob(pattern).select(&:file?).sort
34
+ def files pattern = "*", flag: File::FNM_SYSCASE
35
+ glob(pattern, flag).select(&:file?).sort
36
+ end
37
+
38
+ def gsub pattern, replacement
39
+ self.class.new to_s.gsub(pattern, replacement)
40
+ end
41
+
42
+ def relative_parent root_dir
43
+ relative_path_from(root_dir).parent
28
44
  end
29
45
 
30
- def relative_parent_from root
31
- relative_path_from(root).parent
46
+ def relative_parent_from root_dir
47
+ warn "[DEPRECATION]: Pathname#relative_parent_from is deprecated, " \
48
+ "use Pathname#relative_parent instead."
49
+ relative_parent root_dir
32
50
  end
33
51
 
34
52
  def make_ancestors
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Refinements
6
+ module StringIOs
7
+ refine StringIO do
8
+ def reread length = nil, buffer: nil
9
+ tap(&:rewind).read length, buffer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,9 +2,12 @@
2
2
 
3
3
  module Refinements
4
4
  module Strings
5
+ DELIMITERS = %r([a-z][A-Z]|\s*-\s*|\s*/\s*|\s*:+\s*|\s*_\s*|\s+).freeze
6
+
5
7
  refine String.singleton_class do
6
8
  def delimiters
7
- %r([a-z][A-Z]|\s*\-\s*|\s*\/\s*|\s*\:+\s*|\s*\_\s*|\s+)
9
+ warn "[DEPRECATION]: .delimiters is deprecated, use DELIMITERS instead."
10
+ DELIMITERS
8
11
  end
9
12
  end
10
13
 
@@ -17,20 +20,18 @@ module Refinements
17
20
  return self[0] if max.zero?
18
21
  return "" if max.negative?
19
22
 
20
- self[0..(max - 1)]
23
+ self[..(max - 1)]
21
24
  end
22
25
 
23
- # :reek:TooManyStatements
24
26
  def last number = 0
25
27
  return self if empty?
26
28
 
27
29
  min = Integer number
28
- max = size - 1
29
30
 
30
- return self[max] if min.zero?
31
+ return self[size - 1] if min.zero?
31
32
  return "" if min.negative?
32
33
 
33
- self[(min + 1)..max]
34
+ self[(min + 1)..]
34
35
  end
35
36
 
36
37
  def blank?
@@ -50,33 +51,27 @@ module Refinements
50
51
  end
51
52
 
52
53
  def camelcase
53
- if match? self.class.delimiters
54
- split(%r(\s*\-\s*|\s*\/\s*|\s*\:+\s*)).then { |parts| combine parts, :up, "::" }
55
- .then { |text| text.split(/\s*\_\s*|\s+/) }
56
- .then { |parts| combine parts, :up }
57
- else
58
- up
59
- end
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 }
60
59
  end
61
60
 
62
61
  def snakecase
63
- if match? self.class.delimiters
64
- split(%r(\s*\-\s*|\s*\/\s*|\s*\:+\s*)).then { |parts| combine parts, :down, "/" }
65
- .then { |txt| txt.split(/(?=[A-Z])|\s*\_\s*|\s+/) }
66
- .then { |parts| combine parts, :down, "_" }
67
- else
68
- downcase
69
- end
62
+ return downcase unless match? DELIMITERS
63
+
64
+ split(%r(\s*-\s*|\s*/\s*|\s*:+\s*)).then { |parts| combine parts, :down, "/" }
65
+ .then { |text| text.split(/(?=[A-Z])|\s*_\s*|\s+/) }
66
+ .then { |parts| combine parts, :down, "_" }
70
67
  end
71
68
 
72
69
  def titleize
73
- if match? self.class.delimiters
74
- split(/(?=[A-Z])|\s*\_\s*|\s*\-\s*|\s+/).then { |parts| combine parts, :up, " " }
75
- .then { |text| text.split %r(\s*\/\s*|\s*\:+\s*) }
76
- .then { |parts| combine parts, :up, "/" }
77
- else
78
- capitalize
79
- end
70
+ return capitalize unless match? DELIMITERS
71
+
72
+ split(/(?=[A-Z])|\s*_\s*|\s*-\s*|\s+/).then { |parts| combine parts, :up, " " }
73
+ .then { |text| text.split %r(\s*/\s*|\s*:+\s*) }
74
+ .then { |parts| combine parts, :up, "/" }
80
75
  end
81
76
 
82
77
  def to_bool
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: refinements
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.4.0
4
+ version: 7.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
@@ -28,7 +28,7 @@ cert_chain:
28
28
  2XV8FRa7/JimI07sPLC13eLY3xd/aYTi85Z782KIA4j0G8XEEWAX0ouBhlXPocZv
29
29
  QWc=
30
30
  -----END CERTIFICATE-----
31
- date: 2020-05-21 00:00:00.000000000 Z
31
+ date: 2020-09-19 00:00:00.000000000 Z
32
32
  dependencies:
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler-audit
@@ -50,28 +50,28 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '14.0'
53
+ version: '14.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.0'
60
+ version: '14.2'
61
61
  - !ruby/object:Gem::Dependency
62
- name: git-cop
62
+ name: git-lint
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '4.0'
67
+ version: '1.0'
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: '4.0'
74
+ version: '1.0'
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: guard-rspec
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -162,14 +162,14 @@ dependencies:
162
162
  requirements:
163
163
  - - "~>"
164
164
  - !ruby/object:Gem::Version
165
- version: '0.83'
165
+ version: '0.89'
166
166
  type: :development
167
167
  prerelease: false
168
168
  version_requirements: !ruby/object:Gem::Requirement
169
169
  requirements:
170
170
  - - "~>"
171
171
  - !ruby/object:Gem::Version
172
- version: '0.83'
172
+ version: '0.89'
173
173
  - !ruby/object:Gem::Dependency
174
174
  name: rubocop-performance
175
175
  requirement: !ruby/object:Gem::Requirement
@@ -218,15 +218,15 @@ dependencies:
218
218
  requirements:
219
219
  - - "~>"
220
220
  - !ruby/object:Gem::Version
221
- version: '0.18'
221
+ version: '0.19'
222
222
  type: :development
223
223
  prerelease: false
224
224
  version_requirements: !ruby/object:Gem::Requirement
225
225
  requirements:
226
226
  - - "~>"
227
227
  - !ruby/object:Gem::Version
228
- version: '0.18'
229
- description:
228
+ version: '0.19'
229
+ description:
230
230
  email:
231
231
  - brooke@alchemists.io
232
232
  executables: []
@@ -245,6 +245,7 @@ files:
245
245
  - lib/refinements/hashes.rb
246
246
  - lib/refinements/identity.rb
247
247
  - lib/refinements/pathnames.rb
248
+ - lib/refinements/string_ios.rb
248
249
  - lib/refinements/strings.rb
249
250
  homepage: https://www.alchemists.io/projects/refinements
250
251
  licenses:
@@ -254,7 +255,7 @@ metadata:
254
255
  changelog_uri: https://www.alchemists.io/projects/refinements/changes.html
255
256
  documentation_uri: https://www.alchemists.io/projects/refinements
256
257
  source_code_uri: https://github.com/bkuhlmann/refinements
257
- post_install_message:
258
+ post_install_message:
258
259
  rdoc_options: []
259
260
  require_paths:
260
261
  - lib
@@ -269,8 +270,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
270
  - !ruby/object:Gem::Version
270
271
  version: '0'
271
272
  requirements: []
272
- rubygems_version: 3.1.3
273
- signing_key:
273
+ rubygems_version: 3.1.4
274
+ signing_key:
274
275
  specification_version: 4
275
276
  summary: A collection of refinements to core Ruby objects.
276
277
  test_files: []
metadata.gz.sig CHANGED
Binary file