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 +4 -4
- checksums.yaml.gz.sig +1 -3
- data.tar.gz.sig +0 -0
- data/LICENSE.adoc +1 -1
- data/README.adoc +651 -157
- data/lib/refinements.rb +1 -0
- data/lib/refinements/arrays.rb +10 -2
- data/lib/refinements/hashes.rb +59 -24
- data/lib/refinements/identity.rb +1 -1
- data/lib/refinements/ios.rb +35 -0
- data/lib/refinements/pathnames.rb +31 -4
- data/lib/refinements/strings.rb +30 -24
- metadata +19 -4
- metadata.gz.sig +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58f24ccfa83d2f2af820c05d19c575e371ed5c6471177c8c58648006cf3ca945
|
4
|
+
data.tar.gz: 7fccb86818487e2de337969b42c8ec81f52e28bc1a3edb1d8cc0bf2c206ee2b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 773c5bf918f8e7f958dc602b9c6d7edefc29d644d7d928db0f21e2fa93616781e075b1c4743281b025daf8335c13761d460d149caa470c8000a11aecc91f25f8
|
7
|
+
data.tar.gz: 1cbe58132380e683a0e47813fe676440055fa2a9af1bd582bf8661c3778b1aa354cda5d3939f07b69a6190f72b28e9635890aaa6810af7c9255fef27c025e1a5
|
checksums.yaml.gz.sig
CHANGED
@@ -1,3 +1 @@
|
|
1
|
-
|
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Ž�Άw�l��? �2���B�Qܹ��q��'������ݧ\��]�(�n�O�+N�1��3_4AN���}&~;��uÄ���
|
data.tar.gz.sig
CHANGED
Binary file
|
data/LICENSE.adoc
CHANGED
@@ -150,7 +150,7 @@ additional liability.
|
|
150
150
|
|
151
151
|
END OF TERMS AND CONDITIONS
|
152
152
|
|
153
|
-
Copyright link:https://www.alchemists.io[
|
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]
|
data/README.adoc
CHANGED
@@ -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
|
14
|
+
A collection of refinements (enhancements) to primitive Ruby objects.
|
13
15
|
|
14
16
|
toc::[]
|
15
17
|
|
16
18
|
== Features
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
*
|
25
|
-
|
26
|
-
*
|
27
|
-
|
28
|
-
*
|
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
|
-
|
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
|
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
|
172
|
-
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!
|
176
|
-
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
|
-
|
179
|
-
[1, 2, 3].include 4, 5 # => [1, 2, 3, 4, 5]
|
159
|
+
===== #mean
|
180
160
|
|
181
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
239
|
-
|
240
|
-
example
|
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
|
-
|
243
|
-
example.slice :a, :c # => {a: 1, c: 3}
|
244
|
-
example # => {a: 1, b: 2, c: 3}
|
257
|
+
===== #deep_merge!
|
245
258
|
|
246
|
-
|
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}
|
252
|
-
example
|
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
|
-
|
255
|
-
|
256
|
-
|
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
|
260
|
-
example
|
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!
|
264
|
-
example
|
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)
|
268
|
-
example.recurse(&:invert)
|
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
|
272
|
-
example
|
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
|
276
|
-
example
|
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.
|
280
|
-
example
|
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.
|
284
|
-
example
|
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
|
-
|
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
|
-
|
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("
|
307
|
-
|
308
|
-
|
616
|
+
Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test")
|
617
|
+
# => Pathname("/test/some/test")
|
618
|
+
----
|
309
619
|
|
310
|
-
|
311
|
-
Pathname("/%placeholder%/some/%placeholder%").gsub("%placeholder%", "test") # => Pathname("/test/some/test")
|
620
|
+
===== #make_ancestors
|
312
621
|
|
313
|
-
|
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?
|
317
|
-
Pathname("/one/two").exist?
|
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
|
-
"
|
330
|
-
|
732
|
+
" \n\t\r".blank? # => true
|
733
|
+
----
|
331
734
|
|
332
|
-
|
333
|
-
"instant".last 3 # => "ant"
|
735
|
+
===== #camelcase
|
334
736
|
|
335
|
-
|
737
|
+
Answers a camelcased string.
|
336
738
|
|
337
|
-
|
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
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
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
|
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:
|