refinements 7.6.0 → 7.11.0

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