refinements 7.8.0 → 7.13.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: dd72c4e1fda257b53dcd80a052db0ce99cd5b2987e531bea93f577e6b3b131f9
4
- data.tar.gz: 67b83319903a39425640eb0534eab280e7cb138e588476c635c5192afb08758d
3
+ metadata.gz: 58f24ccfa83d2f2af820c05d19c575e371ed5c6471177c8c58648006cf3ca945
4
+ data.tar.gz: 7fccb86818487e2de337969b42c8ec81f52e28bc1a3edb1d8cc0bf2c206ee2b0
5
5
  SHA512:
6
- metadata.gz: 8fab91775e301f8765dd3156ab91e6abdf9395bdf767fbf859f80a5d3ea2bbebabef8dbe9e5e5a65e33443082a13e127ce3d85c1384b3939d753347384dea99e
7
- data.tar.gz: 74934f4fbb6336ad4c434961c865b826675a71b76f846faae7635e6e09d3aa99bd74a9c74d6f0289f2d63a0c3352c9e21aecb60e35c2485664879520b20a755d
6
+ metadata.gz: 773c5bf918f8e7f958dc602b9c6d7edefc29d644d7d928db0f21e2fa93616781e075b1c4743281b025daf8335c13761d460d149caa470c8000a11aecc91f25f8
7
+ data.tar.gz: 1cbe58132380e683a0e47813fe676440055fa2a9af1bd582bf8661c3778b1aa354cda5d3939f07b69a6190f72b28e9635890aaa6810af7c9255fef27c025e1a5
@@ -1,3 +1 @@
1
- !�������PW�F�nk���~9�z��Z�3�o�GŚ��kw�+�~�� XP���r4xvq�p]���Ͱ�?��AMJM��Oc�y.π���iQlP^��΅g7��d � :�/oJ��ݱ�Fl_N_: kI':�M���KE�W�P!
2
- �k2����]
3
- �RC���^��&��.����7W��T8-��:!�� /�?��5"Ix+��nOho�컎��r+���F���6m��%2P��f�
1
+ _����G��M��p@��V}��\0����j���6<ʑR�-^ o�nHŽ�Άwl��? �2���BQܹ��q��'������ݧ\��]�(�nO�+N1��3_4AN���}&~;��uÄ���
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,75 +6,28 @@
6
6
 
7
7
  [link=http://badge.fury.io/rb/refinements]
8
8
  image::https://badge.fury.io/rb/refinements.svg[Gem Version]
9
+ [link=https://www.alchemists.io/projects/code_quality]
10
+ image::https://img.shields.io/badge/code_style-alchemists-brightgreen.svg[Alchemists Style Guide]
9
11
  [link=https://circleci.com/gh/bkuhlmann/refinements]
10
12
  image::https://circleci.com/gh/bkuhlmann/refinements.svg?style=svg[Circle CI Status]
11
13
 
12
- A collection of refinements (enhancements) to core Ruby objects.
14
+ A collection of refinements (enhancements) to primitive Ruby objects.
13
15
 
14
16
  toc::[]
15
17
 
16
18
  == Features
17
19
 
18
- * *Arrays*:
19
- ** `#compress` - Removes `nil` and empty values without modifying itself.
20
- ** `#compress!` - Removes `nil` and empty values while modifying itself.
21
- ** `#include` - Adds given array or elements without modifying itself.
22
- ** `#exclude` - Removes given array or elements without modifying itself.
23
- ** `#ring` - Answers a circular array which can enumerate before, current, after elements.
24
- * *BigDecimals*:
25
- ** `#inspect` - Allows one to inspect a big decimal with numeric representation.
26
- * *DateTimes*:
27
- ** `.utc` - Answers new DateTime object for current UTC date/time.
28
- * *Files*:
29
- ** `#rewrite` - When given a file path and a block, it provides the contents of the recently read
30
- file for manipulation and immediate writing back to the same file.
31
- * *Hashes*:
32
- ** `.infinite` - Answers new hash where missing keys, even deeply nested, answer an empty hash.
33
- ** `.with_default` - Answers new hash where every top-level missing key has the same default value.
34
- ** `#except` - Answers new hash with given keys removed without modifying itself.
35
- ** `#except!` - Answers new hash with given keys removed while modifying itself.
36
- ** `#symbolize_keys` - Converts keys to symbols without modifying itself.
37
- ** `#symbolize_keys!` - Converts keys to symbols while modifying itself.
38
- ** `#deep_merge` - Merges deeply nested hashes together without modifying itself.
39
- ** `#deep_merge!` - Merges deeply nested hashes together while modifying itself.
40
- ** `#deep_symbolize_keys` - Symbolizes keys of nested hash without modifying itself. Does not handle
41
- nested arrays, though.
42
- ** `#deep_symbolize_keys!` - Symbolizes keys of nested hash while modifying itself. Does not handle
43
- nested arrays, though.
44
- ** `#recurse` - Applies block to nested hash. Does not handle nested arrays, though.
45
- ** `#rekey` - Transforms keys per mapping (size of mapping can vary) without modifying itself.
46
- ** `#rekey!` - Transforms keys per mapping (size of mapping can vary) while modifying itself.
47
- ** `#reverse_merge` - Merges calling hash into passed in hash without modifying itself.
48
- ** `#reverse_merge!` - Merges calling hash into passed in hash while modifying itself.
49
- ** `#use` - Passes each hash value as a block argument for further processing.
50
- * *Pathnames*:
51
- ** `Pathname` - Conversion function (refined from `Kernel`) which can cast `nil` into a pathname.
52
- ** `#name` - Answers file name without extension.
53
- ** `#copy` - Copies file from current location to new location.
54
- ** `#directories` - Answers all or filtered directories for current path.
55
- ** `#extensions` - Answers file extensions as an array.
56
- ** `#files` - Answers all or filtered files for current path.
57
- ** `#gsub` - Same behavior as `String#gsub` but answers a path with patterns replaced with desired
58
- substitutes.
59
- ** `#relative_parent` - Answers relative path from parent directory. This is a complement to
60
- `#relative_path_from`.
61
- ** `#make_ancestors` - Ensures all ancestor directories are created for a path.
62
- ** `#rewrite` - When given a block, it provides the contents of the recently read file for
63
- manipulation and immediate writing back to the same file.
64
- ** `#touch` - Updates access and modification times for path. Defaults to current time.
65
- * *Strings*:
66
- ** `#first` - Answers first character of a string or first set of characters if given a number.
67
- ** `#last` - Answers last character of a string or last set of characters if given a number.
68
- ** `#blank?` - Answers `true`/`false` based on whether string is blank or not
69
- (i.e. `<space>`, `\n`, `\t`, `\r`).
70
- ** `#up` - Answers string with only first letter upcased.
71
- ** `#down` - Answers string with only first letter downcased.
72
- ** `#camelcase` - Answers a camelcased string.
73
- ** `#snakecase` - Answers a snakecased string.
74
- ** `#titleize` - Answers titleized string.
75
- ** `#to_bool` - Answers string as a boolean.
76
- * *String IOs*:
77
- ** `#reread` - Answers full string by rewinding to beginning of string and reading all content.
20
+ Enhances the following objects:
21
+
22
+ * Array
23
+ * BigDecimal
24
+ * DateTime
25
+ * File
26
+ * Hash
27
+ * IO
28
+ * Pathname
29
+ * String
30
+ * StringIO
78
31
 
79
32
  == Requirements
80
33
 
@@ -84,8 +37,6 @@ manipulation and immediate writing back to the same file.
84
37
 
85
38
  == Setup
86
39
 
87
- === Production
88
-
89
40
  To install, run:
90
41
 
91
42
  [source,bash]
@@ -100,24 +51,6 @@ Add the following to your Gemfile file:
100
51
  gem "refinements"
101
52
  ----
102
53
 
103
- === Development
104
-
105
- To contribute, run:
106
-
107
- [source,bash]
108
- ----
109
- git clone https://github.com/bkuhlmann/refinements.git
110
- cd refinements
111
- bin/setup
112
- ----
113
-
114
- You can also use the IRB console for direct access to all objects:
115
-
116
- [source,bash]
117
- ----
118
- bin/console
119
- ----
120
-
121
54
  == Usage
122
55
 
123
56
  === Requires
@@ -129,7 +62,7 @@ If all refinements are not desired, add the following to your `+Gemfile+` instea
129
62
  gem "refinements", require: false
130
63
  ----
131
64
 
132
- then require the specific refinement, as needed. Example:
65
+ ...then require the specific refinement, as needed. Example:
133
66
 
134
67
  [source,ruby]
135
68
  ----
@@ -138,13 +71,16 @@ require "refinements/big_decimals"
138
71
  require "refinements/date_times"
139
72
  require "refinements/files"
140
73
  require "refinements/hashes"
74
+ require "refinements/ios"
141
75
  require "refinements/pathnames"
142
76
  require "refinements/strings"
77
+ require "refinements/string_ios"
143
78
  ----
144
79
 
145
80
  === Using
146
81
 
147
- Much like including/extending a module, you’ll need modify your object(s) to use the refinement(s):
82
+ Much like including/extending a module, you’ll need to modify your object(s) to use the
83
+ refinement(s):
148
84
 
149
85
  [source,ruby]
150
86
  ----
@@ -154,8 +90,10 @@ class Example
154
90
  using Refinements::DateTimes
155
91
  using Refinements::Files
156
92
  using Refinements::Hashes
93
+ using Refinements::IOs
157
94
  using Refinements::Pathnames
158
95
  using Refinements::Strings
96
+ using Refinements::StringIOs
159
97
  end
160
98
  ----
161
99
 
@@ -165,25 +103,81 @@ The following sections demonstrate how each refinement enriches your objects wit
165
103
 
166
104
  ==== Array
167
105
 
106
+ ===== #compress
107
+
108
+ Removes `nil` and empty values without mutating itself.
109
+
168
110
  [source,ruby]
169
111
  ----
170
112
  example = ["An", nil, "", "Example"]
171
- example.compress # => ["An", "Example"]
172
- example # => ["An", nil, "", "Example"]
113
+ example.compress # => ["An", "Example"]
114
+ example # => ["An", nil, "", "Example"]
115
+ ----
116
+
117
+ ===== #compress!
118
+
119
+ Removes `nil` and empty values while mutating itself.
173
120
 
121
+ [source,ruby]
122
+ ----
174
123
  example = ["An", nil, "", "Example"]
175
- example.compress! # => ["An", "Example"]
176
- example # => ["An", "Example"]
124
+ example.compress! # => ["An", "Example"]
125
+ example # => ["An", "Example"]
126
+ ----
127
+
128
+ ===== #exclude
129
+
130
+ Removes given array or elements without mutating itself.
131
+
132
+ [source,ruby]
133
+ ----
134
+ [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
135
+ [1, 2, 3, 4, 5].exclude 4, 5 # => [1, 2, 3]
136
+ ----
137
+
138
+ ===== #include
139
+
140
+ Adds given array or elements without mutating itself.
141
+
142
+ [source,ruby]
143
+ ----
144
+ [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
145
+ [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
146
+ ----
147
+
148
+ ===== #intersperse
149
+
150
+ Inserts additional elements or array between all members of given array.
151
+
152
+ [source,ruby]
153
+ ----
154
+ [1, 2, 3].intersperse :a # => [1, :a, 2, :a, 3]
155
+ [1, 2, 3].intersperse :a, :b # => [1, :a, :b, 2, :a, :b, 3]
156
+ [1, 2, 3].intersperse %i[a b c] # => [1, :a, :b, :c, 2, :a, :b, :c, 3]
157
+ ----
177
158
 
178
- [1, 2, 3].include [4, 5] # => [1, 2, 3, 4, 5]
179
- [1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
159
+ ===== #mean
180
160
 
181
- [1, 2, 3, 4, 5].exclude [4, 5] # => [1, 2, 3]
182
- [1, 2, 3, 4, 5].include 4, 5 # => [1, 2, 3, 4, 5]
161
+ Answers mean/average all elements within an array.
183
162
 
163
+ [source,ruby]
164
+ ----
165
+ [].mean # => 0
166
+ [5].mean # => 5
167
+ [1, 2, 3].mean # => 2
168
+ [1.25, 1.5, 1.75].mean # => 1.5
169
+ ----
170
+
171
+ ===== #ring
172
+
173
+ Answers a circular array which can enumerate before, current, after elements.
174
+
175
+ [source,ruby]
176
+ ----
184
177
  example = [1, 2, 3]
185
178
  example.ring # => #<Enumerator: ...>
186
179
  example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
180
+
187
181
  # [3 1 2]
188
182
  # [1 2 3]
189
183
  # [2 3 1]
@@ -191,6 +185,10 @@ example.ring { |(before, current, after)| puts "#{before} #{current} #{after}" }
191
185
 
192
186
  ==== Big Decimal
193
187
 
188
+ ===== #inspect
189
+
190
+ Allows one to inspect a big decimal with numeric representation.
191
+
194
192
  [source,ruby]
195
193
  ----
196
194
  BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
@@ -198,6 +196,10 @@ BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
198
196
 
199
197
  ==== DateTime
200
198
 
199
+ ===== .utc
200
+
201
+ Answers new DateTime object for current UTC date/time.
202
+
201
203
  [source,ruby]
202
204
  ----
203
205
  DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867000n),+0s,2299161j)>
@@ -205,6 +207,11 @@ DateTime.utc # => #<DateTime: 2019-12-31T18:17:00+00:00 ((2458849j,65820s,181867
205
207
 
206
208
  ==== File
207
209
 
210
+ ===== .rewrite
211
+
212
+ When given a file path and a block, it provides the contents of the recently read file for
213
+ manipulation and immediate writing back to the same file.
214
+
208
215
  [source,ruby]
209
216
  ----
210
217
  File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
@@ -212,160 +219,647 @@ File.rewrite("/test.txt") { |content| content.gsub "[placeholder]", "example" }
212
219
 
213
220
  ==== Hash
214
221
 
222
+ ===== .infinite
223
+
224
+ Answers new hash where missing keys, even deeply nested, answer an empty hash.
225
+
215
226
  [source,ruby]
216
227
  ----
217
228
  example = Hash.infinite
218
- example[:a] # => {}
219
- example[:a][:b][:c] # => {}
229
+ example[:a] # => {}
230
+ example[:a][:b][:c] # => {}
231
+ ----
232
+
233
+ ===== .with_default
234
+
235
+ Answers new hash where every top-level missing key has the same default value.
220
236
 
237
+ [source,ruby]
238
+ ----
221
239
  example = Hash.with_default ""
222
240
  example[:a] # => ""
241
+
223
242
  example = Hash.with_default []
224
243
  example[:b] # => []
244
+ ----
225
245
 
226
- example = {a: 1, b: 2, c: 3}
227
- example.except :a, :b # => {c: 3}
228
- example # => {a: 1, b: 2, c: 3}
229
-
230
- example = {a: 1, b: 2, c: 3}
231
- example.except! :a, :b # => {c: 3}
232
- example # => {c: 3}
246
+ ===== #deep_merge
233
247
 
234
- example = {"a" => 1, "b" => 2}
235
- example.symbolize_keys # => {a: 1, b: 2}
236
- example # => {"a" => 1, "b" => 2}
248
+ Merges deeply nested hashes together without mutating itself.
237
249
 
238
- example = {"a" => 1, "b" => 2}
239
- example.symbolize_keys! # => {a: 1, b: 2}
240
- example # => {a: 1, b: 2}
250
+ [source,ruby]
251
+ ----
252
+ example = {a: "A", b: {one: "One", two: "Two"}}
253
+ example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
254
+ example # => {a: "A", b: {one: "One", two: "Two"}}
255
+ ----
241
256
 
242
- example = {a: 1, b: 2, c: 3}
243
- example.slice :a, :c # => {a: 1, c: 3}
244
- example # => {a: 1, b: 2, c: 3}
257
+ ===== #deep_merge!
245
258
 
246
- example = {a: 1, b: 2, c: 3}
247
- example.slice! :a, :c # => {a: 1, c: 3}
248
- example # => {a: 1, c: 3}
259
+ Merges deeply nested hashes together while mutating itself.
249
260
 
261
+ [source,ruby]
262
+ ----
250
263
  example = {a: "A", b: {one: "One", two: "Two"}}
251
- example.deep_merge b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
252
- example # => {a: "A", b: {one: "One", two: "Two"}}
264
+ example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
265
+ example # => {a: "A", b: {one: 1, two: "Two"}}
266
+ ----
253
267
 
254
- example = {a: "A", b: {one: "One", two: "Two"}}
255
- example.deep_merge! b: {one: 1} # => {a: "A", b: {one: 1, two: "Two"}}
256
- example # => {a: "A", b: {one: 1, two: "Two"}}
268
+ ===== #deep_stringify_keys
269
+
270
+ Stringifies keys of nested hash without mutating itself. Does not handle nested arrays, though.
271
+
272
+ [source,ruby]
273
+ ----
274
+ example = {a: {b: 2}}
275
+ example.deep_stringify_keys # => {"a" => {"b" => 1}}
276
+ example # => {a: {b: 2}}
277
+ ----
278
+
279
+ ===== #deep_stringify_keys!
280
+
281
+ Stringifies keys of nested hash while mutating itself. Does not handle nested arrays, though.
282
+
283
+ [source,ruby]
284
+ ----
285
+ example = {a: {b: 2}}
286
+ example.deep_stringify_keys! # => {"a" => {"b" => 1}}
287
+ example # => {"a" => {"b" => 1}}
288
+ ----
257
289
 
290
+ ===== #deep_symbolize_keys
291
+
292
+ Symbolizes keys of nested hash without mutating itself. Does not handle nested arrays, though.
293
+
294
+ [source,ruby]
295
+ ----
258
296
  example = {"a" => {"b" => 2}}
259
- example.deep_symbolize_keys # => {a: {b: 1}}
260
- example # => {"a" => {"b" => 2}}
297
+ example.deep_symbolize_keys # => {a: {b: 1}}
298
+ example # => {"a" => {"b" => 2}}
299
+ ----
300
+
301
+ ===== #deep_symbolize_keys!
302
+
303
+ Symbolizes keys of nested hash while mutating itself. Does not handle nested arrays, though.
261
304
 
305
+ [source,ruby]
306
+ ----
262
307
  example = {"a" => {"b" => 2}}
263
- example.deep_symbolize_keys! # => {a: {b: 1}}
264
- example # => {a: {b: 1}}
308
+ example.deep_symbolize_keys! # => {a: {b: 1}}
309
+ example # => {a: {b: 1}}
310
+ ----
311
+
312
+ ===== #except
313
+
314
+ Answers new hash with given keys removed without mutating itself.
315
+
316
+ [source,ruby]
317
+ ----
318
+ example = {a: 1, b: 2, c: 3}
319
+ example.except :a, :b # => {c: 3}
320
+ example # => {a: 1, b: 2, c: 3}
321
+ ----
322
+
323
+ ===== #except!
324
+
325
+ Answers new hash with given keys removed while mutating itself.
326
+
327
+ [source,ruby]
328
+ ----
329
+ example = {a: 1, b: 2, c: 3}
330
+ example.except! :a, :b # => {c: 3}
331
+ example # => {c: 3}
332
+ ----
333
+
334
+ ===== #flatten_keys
265
335
 
336
+ Flattens nested keys as top-level keys without mutating itself. Does not handle nested arrays,
337
+ though.
338
+
339
+ [source,ruby]
340
+ ----
341
+ {a: {b: 1}}.flatten_keys prefix: :test # => {test_a_b: 1}
342
+ {a: {b: 1}}.flatten_keys delimiter: :| # => {:"a|b" => 1}
343
+
344
+ {a: {b: 1}}.flatten_keys cast: :to_s # => {"a_b" => 1}
345
+ {"a" => {"b" => 1}}.flatten_keys cast: :to_sym # => {a_b: 1}
346
+
347
+ example = {a: {b: 1}}
348
+ example.flatten_keys # => {a_b: 1}
349
+ example # => {a: {b: 1}}
350
+ ----
351
+
352
+ ===== #flatten_keys!
353
+
354
+ Flattens nested keys as top-level keys while mutating itself. Does not handle nested arrays,
355
+ though.
356
+
357
+ [source,ruby]
358
+ ----
359
+ example = {a: {b: 1}}
360
+ example.flatten_keys! # => {a_b: 1}
361
+ example # => {a_b: 1}
362
+ ----
363
+
364
+ ===== #recurse
365
+
366
+ Recursively iterates over the hash and any hash value by applying the given block to it. Does not
367
+ handle nested arrays, though.
368
+
369
+ [source,ruby]
370
+ ----
266
371
  example = {"a" => {"b" => 1}}
267
- example.recurse(&:symbolize_keys) # => {a: {b: 1}}
268
- example.recurse(&:invert) # => {{"b" => 1} => "a"}
372
+ example.recurse(&:symbolize_keys) # => {a: {b: 1}}
373
+ example.recurse(&:invert) # => {{"b" => 1} => "a"}
374
+ ----
269
375
 
376
+ ===== #rekey
377
+
378
+ Transforms keys per mapping (size of mapping can vary) without mutating itself.
379
+
380
+ [source,ruby]
381
+ ----
270
382
  example = {a: 1, b: 2, c: 3}
271
- example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
272
- example # => {a: 1, b: 2, c: 3}
383
+ example.rekey a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
384
+ example # => {a: 1, b: 2, c: 3}
385
+ ----
386
+
387
+ ===== #rekey!
273
388
 
389
+ Transforms keys per mapping (size of mapping can vary) while mutating itself.
390
+
391
+ [source,ruby]
392
+ ----
274
393
  example = {a: 1, b: 2, c: 3}
275
- example.rekey! a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
276
- example # => {amber: 1, blue: 2, c: 3}
394
+ example.rekey! a: :amber, b: :blue # => {amber: 1, blue: 2, c: 3}
395
+ example # => {amber: 1, blue: 2, c: 3}
396
+ ----
397
+
398
+ ===== #reverse_merge
399
+
400
+ Merges calling hash into passed in hash without mutating itself.
401
+
402
+ [source,ruby]
403
+ ----
404
+ example = {a: 1, b: 2}
405
+ example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
406
+ example # => {a: 1, b: 2}
407
+ ----
408
+
409
+ ===== #reverse_merge!
277
410
 
411
+ Merges calling hash into passed in hash while mutating itself.
412
+
413
+ [source,ruby]
414
+ ----
415
+ example = {a: 1, b: 2}
416
+ example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
417
+ example # => {a: 1, b: 2, c: 3}
418
+ ----
419
+
420
+ ===== #stringify_keys
421
+
422
+ Converts keys to strings without mutating itself.
423
+
424
+ [source,ruby]
425
+ ----
278
426
  example = {a: 1, b: 2}
279
- example.reverse_merge a: 0, c: 3 # => {a: 1, b: 2, c: 3}
280
- example # => {a: 1, b: 2}
427
+ example.stringify_keys # => {"a" => 1, "b" => 2}
428
+ example # => {a: 1, b: 2}
429
+ ----
430
+
431
+ ===== #stringify_keys!
281
432
 
433
+ Converts keys to strings while mutating itself.
434
+
435
+ [source,ruby]
436
+ ----
282
437
  example = {a: 1, b: 2}
283
- example.reverse_merge! a: 0, c: 3 # => {a: 1, b: 2, c: 3}
284
- example # => {a: 1, b: 2, c: 3}
438
+ example.stringify_keys! # => {"a" => 1, "b" => 2}
439
+ example # => {"a" => 1, "b" => 2}
440
+ ----
441
+
442
+ ===== #symbolize_keys
443
+
444
+ Converts keys to symbols without mutating itself.
445
+
446
+ [source,ruby]
447
+ ----
448
+ example = {"a" => 1, "b" => 2}
449
+ example.symbolize_keys # => {a: 1, b: 2}
450
+ example # => {"a" => 1, "b" => 2}
451
+ ----
452
+
453
+ ===== #symbolize_keys!
285
454
 
455
+ Converts keys to symbols while mutating itself.
456
+
457
+ [source,ruby]
458
+ ----
459
+ example = {"a" => 1, "b" => 2}
460
+ example.symbolize_keys! # => {a: 1, b: 2}
461
+ example # => {a: 1, b: 2}
462
+ ----
463
+
464
+ ===== #use
465
+
466
+ Passes each hash value as a block argument for further processing.
467
+
468
+ [source,ruby]
469
+ ----
286
470
  example = {unit: "221B", street: "Baker Street", city: "London", country: "UK"}
287
471
  example.use { |unit, street| "#{unit} #{street}" } # => "221B Baker Street"
288
472
  ----
289
473
 
474
+ ==== IO
475
+
476
+ ===== .void
477
+
478
+ Answers an IO stream which points to `/dev/null` in order to ignore any reads or writes to the
479
+ stream. When given a block, the stream will automatically close upon block exit. When not given a
480
+ block, you'll need to close the stream manually.
481
+
482
+ [source,ruby]
483
+ ----
484
+ io = IO.void
485
+ io.closed? # => false
486
+
487
+ io = IO.void { |void| void.write "nevermore" }
488
+ io.closed? # => true
489
+ ----
490
+
491
+ ===== #redirect
492
+
493
+ Redirects current stream to other stream when given a block. Without a block, the original stream is
494
+ answered instead.
495
+
496
+ [source,ruby]
497
+ ----
498
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
499
+ other = IO.new IO.sysopen(Pathname("other.txt").to_s, "w+")
500
+
501
+ io.redirect other # => `io`
502
+
503
+ io.redirect(other) { |stream| stream.write "test" }
504
+ .close # => ""
505
+ other.close # => "test"
506
+ ----
507
+
508
+ ===== #reread
509
+
510
+ Answers full stream by rewinding to beginning of stream and reading all content.
511
+
512
+ [source,ruby]
513
+ ----
514
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
515
+ io.write "This is a test."
516
+
517
+ io.reread # => "This is a test."
518
+ io.reread 4 # => "This"
519
+
520
+ buffer = "".dup
521
+ io.reread(buffer: buffer)
522
+ buffer # => "This is a test."
523
+ ----
524
+
525
+ ===== #squelch
526
+
527
+ Temporarily ignores any reads/writes for current stream for all code executed within the block. When
528
+ not given a block, it answers itself.
529
+
530
+ [source,ruby]
531
+ ----
532
+ io = IO.new IO.sysopen(Pathname("test.txt").to_s, "w+")
533
+ io.squelch { io.write "Test" }
534
+ io.reread # => ""
535
+ ----
536
+
290
537
  ==== Pathname
291
538
 
539
+ ===== Pathname
540
+
541
+ Enhances the conversion function -- refined from `Kernel` -- which casts `nil` into a pathname in
542
+ order to avoid: `TypeError (no implicit conversion of nil into String)`. The pathname is still
543
+ invalid but at least you have an instance of `Pathname`, which behaves like a _Null Object_, that
544
+ can still be used to construct a valid path.
545
+
292
546
  [source,ruby]
293
547
  ----
294
548
  Pathname(nil) # => Pathname("")
549
+ ----
295
550
 
296
- Pathname("example.txt").name # => Pathname("example")
551
+ ===== #change_dir
552
+
553
+ Inherits and wraps `Dir.chdir` behavior by changing to directory of current path. See
554
+ link:https://rubyapi.org/2.7/o/s?q=Dir.chdir[Dir.chdir] for details.
297
555
 
556
+ [source,ruby]
557
+ ----
558
+ Pathname.pwd # => "/"
559
+ Pathname("/test").make_dir.change_dir # => Pathname "/test"
560
+ Pathname.pwd # => "/test"
561
+
562
+ Pathname.pwd # => "/"
563
+ Pathname("/test").make_dir.change_dir { # Implementation details } # => Pathname "/test"
564
+ Pathname.pwd # => "/"
565
+ ----
566
+
567
+ ===== #copy
568
+
569
+ Copies file from current location to new location.
570
+
571
+ [source,ruby]
572
+ ----
298
573
  Pathname("input.txt").copy Pathname("output.txt")
574
+ ----
575
+
576
+ ===== #directories
299
577
 
300
- Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
301
- Pathname("/example").directories "a*" # => [Pathname("a")]
302
- Pathname("/example").directories flag: File::FNM_DOTMATCH # => [Pathname(".."), Pathname(".")]
578
+ Answers all or filtered directories for current path.
303
579
 
580
+ [source,ruby]
581
+ ----
582
+ Pathname("/example").directories # => [Pathname("a"), Pathname("b")]
583
+ Pathname("/example").directories "a*" # => [Pathname("a")]
584
+ Pathname("/example").directories flag: File::FNM_DOTMATCH # => [Pathname(".."), Pathname(".")]
585
+ ----
586
+
587
+ ===== #extensions
588
+
589
+ Answers file extensions as an array.
590
+
591
+ [source,ruby]
592
+ ----
304
593
  Pathname("example.txt.erb").extensions # => [".txt", ".erb"]
594
+ ----
595
+
596
+ ===== #files
597
+
598
+ Answers all or filtered files for current path.
599
+
600
+ [source,ruby]
601
+ ----
602
+ Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
603
+ Pathname("/example").files "*.png" # => [Pathname("a.png")]
604
+ Pathname("/example").files flag: File::FNM_DOTMATCH # => [Pathname(".ruby-version")]
605
+ ----
606
+
607
+ ===== #gsub
608
+
609
+ Same behavior as `String#gsub` but answers a path with patterns replaced with desired substitutes.
610
+
611
+ [source,ruby]
612
+ ----
613
+ Pathname("/a/path/some/path").gsub("path", "test")
614
+ # => Pathname("/a/test/some/test")
305
615
 
306
- Pathname("/example").files # => [Pathname("a.txt"), Pathname("a.png")]
307
- Pathname("/example").files "*.png" # => [Pathname("a.png")]
308
- Pathname("/example").files flag: File::FNM_DOTMATCH # => [Pathname(".ruby-version")]
616
+ Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
617
+ # => Pathname("/test/some/test")
618
+ ----
309
619
 
310
- Pathname("/a/path/some/path").gsub("path", "test") # => Pathname("/a/test/some/test")
311
- Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test") # => Pathname("/test/some/test")
620
+ ===== #make_ancestors
312
621
 
313
- Pathname("/one/two/three").relative_parent_from("/one") # => Pathname "two"
622
+ Ensures all ancestor directories are created for a path.
314
623
 
624
+ [source,ruby]
625
+ ----
315
626
  Pathname("/one/two").make_ancestors
316
- Pathname("/one").exist? # => true
317
- Pathname("/one/two").exist? # => false
627
+ Pathname("/one").exist? # => true
628
+ Pathname("/one/two").exist? # => false
629
+ ----
630
+
631
+ ===== #make_dir
632
+
633
+ Provides alternative `#mkdir` behavior by always answering itself (even when directory exists) and
634
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
635
+
636
+ [source,ruby]
637
+ ----
638
+ Pathname("/one").make_dir # => Pathname("/one")
639
+ Pathname("/one").make_dir.make_dir # => Pathname("/one")
640
+ ----
641
+
642
+ ===== #make_path
643
+
644
+ Provides alternative `#mkpath` behavior by always answering itself (even when full path exists) and
645
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
646
+
647
+ [source,ruby]
648
+ ----
649
+ Pathname("/one/two/three").make_path # => Pathname("/one/two/three")
650
+ Pathname("/one/two/three").make_path.make_path # => Pathname("/one/two/three")
651
+ ----
652
+
653
+ ===== #name
654
+
655
+ Answers file name without extension.
656
+
657
+ [source,ruby]
658
+ ----
659
+ Pathname("example.txt").name # => Pathname("example")
660
+ ----
661
+
662
+ ===== #relative_parent
663
+
664
+ Answers relative path from parent directory. This is a complement to `#relative_path_from`.
665
+
666
+ [source,ruby]
667
+ ----
668
+ Pathname("/one/two/three").relative_parent("/one") # => Pathname "two"
669
+ ----
318
670
 
671
+ ===== #remove_dir
672
+
673
+ Provides alternative `#rmdir` behavior by always answering itself (even when full path exists) and
674
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
675
+
676
+ [source,ruby]
677
+ ----
678
+ Pathname("/test").make_dir.remove_dir.exist? # => false
679
+ Pathname("/test").remove_dir # => Pathname("/test")
680
+ Pathname("/test").remove_dir.remove_dir # => Pathname("/test")
681
+ ----
682
+
683
+ ===== #remove_tree
684
+
685
+ Provides alternative `#rmtree` behavior by always answering itself (even when full path exists) and
686
+ not throwing errors when directory does exist in order to ensure the pathname can be chained.
687
+
688
+ [source,ruby]
689
+ ----
690
+ parent_path = Pathname "/one"
691
+ child_path = parent_path.join "two"
692
+
693
+ child_path.make_path
694
+ child_path.remove_tree # => Pathname "/one/two"
695
+ child_path.exist? # => false
696
+ paremt_path.exist? # => true
697
+
698
+ child_path.make_path
699
+ parent_path.remove_tree # => Pathname "/one"
700
+ child_path.exist? # => false
701
+ parent_path.exist? # => false
702
+ ----
703
+
704
+ ===== #rewrite
705
+
706
+ When given a block, it provides the contents of the recently read file for manipulation and
707
+ immediate writing back to the same file.
708
+
709
+ [source,ruby]
710
+ ----
319
711
  Pathname("/test.txt").rewrite { |content| content.sub "[placeholder]", "example" }
712
+ ----
713
+
714
+ ===== #touch
715
+
716
+ Updates access and modification times for path. Defaults to current time.
320
717
 
718
+ [source,ruby]
719
+ ----
321
720
  Pathname("example.txt").touch
322
721
  Pathname("example.txt").touch at: Time.now - 1
323
722
  ----
324
723
 
325
724
  ==== String
326
725
 
726
+ ===== #blank?
727
+
728
+ Answers `true`/`false` based on whether string is blank, `<space>`, `\n`, `\t`, and/or `\r`.
729
+
327
730
  [source,ruby]
328
731
  ----
329
- "example".first # => "e"
330
- "example".first 4 # => "exam"
732
+ " \n\t\r".blank? # => true
733
+ ----
331
734
 
332
- "instant".last # => "t"
333
- "instant".last 3 # => "ant"
735
+ ===== #camelcase
334
736
 
335
- " \n\t\r".blank? # => true
737
+ Answers a camelcased string.
336
738
 
337
- "example".up # => "Example"
739
+ [source,ruby]
740
+ ----
741
+ "this_is_an_example".camelcase # => "ThisIsAnExample"
742
+ ----
338
743
 
744
+ ===== #down
745
+
746
+ Answers string with only first letter downcased.
747
+
748
+ [source,ruby]
749
+ ----
339
750
  "EXAMPLE".down # => "eXAMPLE"
751
+ ----
340
752
 
341
- "this_is_an_example".camelcase # => "ThisIsAnExample"
753
+ ===== #first
754
+
755
+ Answers first character of a string or first set of characters if given a number.
756
+
757
+ [source,ruby]
758
+ ----
759
+ "example".first # => "e"
760
+ "example".first 4 # => "exam"
761
+ ----
762
+
763
+ ===== #indent
764
+
765
+ Answers string indented by two spaces by default.
766
+
767
+ [source,ruby]
768
+ ----
769
+ "example".indent # => " example"
770
+ "example".indent 0 # => "example"
771
+ "example".indent -1 # => "example"
772
+ "example".indent 2 # => " example"
773
+ "example".indent 3, padding: " " # => " example"
774
+ ----
775
+
776
+ ===== #last
777
+
778
+ Answers last character of a string or last set of characters if given a number.
779
+
780
+ [source,ruby]
781
+ ----
782
+ "instant".last # => "t"
783
+ "instant".last 3 # => "ant"
784
+ ----
785
+
786
+ ===== #snakecase
342
787
 
788
+ Answers a snakecased string.
789
+
790
+ [source,ruby]
791
+ ----
343
792
  "ThisIsAnExample".snakecase # => "this_is_an_example"
793
+ ----
794
+
795
+ ===== #titleize
796
+
797
+ Answers titleized string.
344
798
 
799
+ [source,ruby]
800
+ ----
345
801
  "ThisIsAnExample".titleize # => "This Is An Example"
802
+ ----
803
+
804
+ ===== #to_bool
805
+
806
+ Answers string as a boolean.
807
+
808
+ [source,ruby]
809
+ ----
810
+ "true".to_bool # => true
811
+ "yes".to_bool # => true
812
+ "1".to_bool # => true
813
+ "".to_bool # => false
814
+ "example".to_bool # => false
815
+ ----
346
816
 
347
- "true".to_bool # => true
348
- "yes".to_bool # => true
349
- "1".to_bool # => true
350
- "".to_bool # => false
351
- "example".to_bool # => false
817
+ ===== #up
818
+
819
+ Answers string with only first letter upcased.
820
+
821
+ [source,ruby]
822
+ ----
823
+ "example".up # => "Example"
352
824
  ----
353
825
 
354
826
  ==== String IO
355
827
 
828
+ ===== #reread
829
+
830
+ Answers full string by rewinding to beginning of string and reading all content.
831
+
356
832
  [source,ruby]
357
833
  ----
358
834
  io = StringIO.new
359
835
  io.write "This is a test."
360
- io.reread # => "This is a test."
361
836
 
362
- io.reread(4) => "This"
837
+ io.reread # => "This is a test."
838
+ io.reread 4 # => "This"
363
839
 
364
840
  buffer = "".dup
365
841
  io.reread(buffer: buffer)
366
842
  buffer # => "This is a test."
367
843
  ----
368
844
 
845
+ == Development
846
+
847
+ To contribute, run:
848
+
849
+ [source,bash]
850
+ ----
851
+ git clone https://github.com/bkuhlmann/refinements.git
852
+ cd refinements
853
+ bin/setup
854
+ ----
855
+
856
+ You can also use the IRB console for direct access to all objects:
857
+
858
+ [source,bash]
859
+ ----
860
+ bin/console
861
+ ----
862
+
369
863
  == Tests
370
864
 
371
865
  To test, run: