refinements 7.8.0 → 7.13.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: 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: