everythingrb 0.6.1 → 0.8.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
- data/CHANGELOG.md +65 -1
- data/README.md +469 -46
- data/lib/everythingrb/all.rb +8 -0
- data/lib/everythingrb/array.rb +5 -21
- data/lib/everythingrb/boolean.rb +33 -0
- data/lib/everythingrb/data.rb +7 -0
- data/lib/everythingrb/date.rb +31 -0
- data/lib/everythingrb/enumerable.rb +4 -2
- data/lib/everythingrb/extensions/quotable.rb +82 -0
- data/lib/everythingrb/extensions.rb +3 -0
- data/lib/everythingrb/hash.rb +247 -24
- data/lib/everythingrb/kernel.rb +35 -0
- data/lib/everythingrb/nil.rb +15 -0
- data/lib/everythingrb/numeric.rb +18 -0
- data/lib/everythingrb/ostruct.rb +11 -1
- data/lib/everythingrb/prelude.rb +1 -0
- data/lib/everythingrb/range.rb +20 -0
- data/lib/everythingrb/regexp.rb +19 -0
- data/lib/everythingrb/string.rb +42 -9
- data/lib/everythingrb/struct.rb +7 -0
- data/lib/everythingrb/symbol.rb +3 -3
- data/lib/everythingrb/time.rb +19 -0
- data/lib/everythingrb/version.rb +1 -1
- metadata +12 -2
data/README.md
CHANGED
@@ -4,18 +4,33 @@
|
|
4
4
|

|
5
5
|
[](https://github.com/everythingrb/sortsmith/actions/workflows/main.yml)
|
6
6
|
|
7
|
-
Super handy extensions to Ruby core classes that make your code more expressive, readable, and fun to write.
|
7
|
+
Super handy extensions to Ruby core classes that make your code more expressive, readable, and fun to write. Stop writing boilerplate and start writing code that *actually matters*!
|
8
|
+
|
9
|
+
## Express Your Intent, Not Your Logic
|
10
|
+
|
11
|
+
We've all been there - writing the same tedious patterns over and over:
|
8
12
|
|
9
13
|
```ruby
|
14
|
+
# BEFORE
|
10
15
|
users = [{ name: "Alice", role: "admin" }, { name: "Bob", role: "user" }]
|
16
|
+
admin_users = users.select { |u| u[:role] == "admin" }
|
17
|
+
admin_names = admin_users.map { |u| u[:name] }
|
18
|
+
result = admin_names.join(", ")
|
19
|
+
# => "Alice"
|
20
|
+
```
|
11
21
|
|
12
|
-
|
13
|
-
admin_names = users.select { |u| u[:role] == "admin" }.map { |u| u[:name] }.join(", ")
|
22
|
+
With EverythingRB, you can write code that actually says what you mean:
|
14
23
|
|
15
|
-
|
24
|
+
```ruby
|
25
|
+
# AFTER
|
16
26
|
users.join_map(", ") { |u| u[:name] if u[:role] == "admin" }
|
27
|
+
# => "Alice"
|
17
28
|
```
|
18
29
|
|
30
|
+
*Methods used: [`join_map`](https://itsthedevman.com/docs/everythingrb/Array.html#join_map-instance_method)*
|
31
|
+
|
32
|
+
Because life's too short to write all that boilerplate!
|
33
|
+
|
19
34
|
## Installation
|
20
35
|
|
21
36
|
```ruby
|
@@ -47,7 +62,7 @@ config.server.port # => 443
|
|
47
62
|
|
48
63
|
### Cherry-Pick Extensions
|
49
64
|
|
50
|
-
If you only need specific extensions
|
65
|
+
If you only need specific extensions (or you're a minimalist at heart):
|
51
66
|
|
52
67
|
```ruby
|
53
68
|
require "everythingrb/prelude" # Required base module
|
@@ -64,111 +79,486 @@ require "everythingrb/string" # Just String extensions
|
|
64
79
|
|
65
80
|
Available modules:
|
66
81
|
- `array`: Array extensions (join_map, key_map, etc.)
|
67
|
-
- `
|
82
|
+
- `boolean`: Boolean extensions (in_quotes, with_quotes)
|
83
|
+
- `data`: Data extensions (to_deep_h, in_quotes)
|
84
|
+
- `date`: Date and DateTime extensions (in_quotes)
|
68
85
|
- `enumerable`: Enumerable extensions (join_map, group_by_key)
|
69
|
-
- `hash`: Hash extensions (to_ostruct,
|
86
|
+
- `hash`: Hash extensions (to_ostruct, transform_values(with_key: true), etc.)
|
87
|
+
- `kernel`: Kernel extensions (morph alias for then)
|
70
88
|
- `module`: Extensions like attr_predicate
|
89
|
+
- `nil`: NilClass extensions (in_quotes)
|
90
|
+
- `numeric`: Numeric extensions (in_quotes)
|
71
91
|
- `ostruct`: OpenStruct extensions (map, join_map, etc.)
|
72
|
-
- `
|
73
|
-
- `
|
92
|
+
- `range`: Range extensions (in_quotes)
|
93
|
+
- `regexp`: Regexp extensions (in_quotes)
|
94
|
+
- `string`: String extensions (to_h, to_ostruct, to_camelcase, etc.)
|
95
|
+
- `struct`: Struct extensions (to_deep_h, in_quotes)
|
74
96
|
- `symbol`: Symbol extensions (with_quotes)
|
97
|
+
- `time`: Time extensions (in_quotes)
|
75
98
|
|
76
99
|
## What's Included
|
77
100
|
|
78
|
-
EverythingRB extends Ruby's core classes with intuitive methods that simplify common patterns.
|
79
|
-
|
80
101
|
### Data Structure Conversions
|
81
102
|
|
103
|
+
Stop writing complicated parsers and nested transformations:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
# BEFORE
|
107
|
+
json_string = '{"user":{"name":"Alice","roles":["admin"]}}'
|
108
|
+
parsed = JSON.parse(json_string)
|
109
|
+
result = OpenStruct.new(
|
110
|
+
user: OpenStruct.new(
|
111
|
+
name: parsed["user"]["name"],
|
112
|
+
roles: parsed["user"]["roles"]
|
113
|
+
)
|
114
|
+
)
|
115
|
+
result.user.name # => "Alice"
|
116
|
+
```
|
117
|
+
|
118
|
+
With EverythingRB, it's one elegant step:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
# AFTER
|
122
|
+
'{"user":{"name":"Alice","roles":["admin"]}}'.to_ostruct.user.name # => "Alice"
|
123
|
+
```
|
124
|
+
|
125
|
+
*Methods used: [`to_ostruct`](https://itsthedevman.com/docs/everythingrb/String.html#to_ostruct-instance_method)*
|
126
|
+
|
82
127
|
Convert between data structures with ease:
|
83
128
|
|
84
129
|
```ruby
|
85
|
-
#
|
86
|
-
|
130
|
+
# BEFORE
|
131
|
+
config_hash = { server: { host: "example.com", port: 443 } }
|
132
|
+
ServerConfig = Struct.new(:host, :port)
|
133
|
+
Config = Struct.new(:server)
|
134
|
+
config = Config.new(ServerConfig.new(config_hash[:server][:host], config_hash[:server][:port]))
|
135
|
+
```
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
# AFTER
|
139
|
+
config = { server: { host: "example.com", port: 443 } }.to_struct
|
87
140
|
config.server.host # => "example.com"
|
141
|
+
```
|
142
|
+
|
143
|
+
*Methods used: [`to_struct`](https://itsthedevman.com/docs/everythingrb/Hash.html#to_struct-instance_method)*
|
88
144
|
|
89
|
-
|
90
|
-
|
145
|
+
Deep conversion to plain hashes is just as easy:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
# BEFORE
|
149
|
+
data = OpenStruct.new(user: Data.define(:name).new(name: "Bob"))
|
150
|
+
result = {
|
151
|
+
user: {
|
152
|
+
name: data.user.name
|
153
|
+
}
|
154
|
+
}
|
155
|
+
```
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
# AFTER
|
159
|
+
data = OpenStruct.new(user: Data.define(:name).new(name: "Bob"))
|
160
|
+
data.to_deep_h # => {user: {name: "Bob"}}
|
91
161
|
```
|
92
162
|
|
93
|
-
|
163
|
+
*Methods used: [`to_deep_h`](https://itsthedevman.com/docs/everythingrb/OpenStruct.html#to_deep_h-instance_method)*
|
164
|
+
|
165
|
+
**Extensions:** [`to_struct`](https://itsthedevman.com/docs/everythingrb/Hash.html#to_struct-instance_method), [`to_ostruct`](https://itsthedevman.com/docs/everythingrb/Hash.html#to_ostruct-instance_method), [`to_istruct`](https://itsthedevman.com/docs/everythingrb/Hash.html#to_istruct-instance_method), [`to_h`](https://itsthedevman.com/docs/everythingrb/String.html#to_h-instance_method), [`to_deep_h`](https://itsthedevman.com/docs/everythingrb/Hash.html#to_deep_h-instance_method)
|
94
166
|
|
95
167
|
### Collection Processing
|
96
168
|
|
97
|
-
Extract and transform data
|
169
|
+
Extract and transform data with elegant, expressive code:
|
98
170
|
|
99
171
|
```ruby
|
100
|
-
#
|
172
|
+
# BEFORE
|
101
173
|
users = [{ name: "Alice", roles: ["admin"] }, { name: "Bob", roles: ["user"] }]
|
174
|
+
names = users.map { |user| user[:name] }
|
175
|
+
# => ["Alice", "Bob"]
|
176
|
+
```
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
# AFTER
|
102
180
|
users.key_map(:name) # => ["Alice", "Bob"]
|
103
|
-
|
181
|
+
```
|
182
|
+
|
183
|
+
*Methods used: [`key_map`](https://itsthedevman.com/docs/everythingrb/Array.html#key_map-instance_method)*
|
184
|
+
|
185
|
+
Simplify nested data extraction:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
# BEFORE
|
189
|
+
users = [
|
190
|
+
{user: {profile: {name: "Alice"}}},
|
191
|
+
{user: {profile: {name: "Bob"}}}
|
192
|
+
]
|
193
|
+
names = users.map { |u| u.dig(:user, :profile, :name) }
|
194
|
+
# => ["Alice", "Bob"]
|
195
|
+
```
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
# AFTER
|
199
|
+
users.dig_map(:user, :profile, :name) # => ["Alice", "Bob"]
|
200
|
+
```
|
201
|
+
|
202
|
+
*Methods used: [`dig_map`](https://itsthedevman.com/docs/everythingrb/Array.html#dig_map-instance_method)*
|
203
|
+
|
204
|
+
Combine filter, map, and join operations in one step:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
# BEFORE
|
208
|
+
data = [1, 2, nil, 3, 4]
|
209
|
+
result = data.compact.filter_map { |n| "Item #{n}" if n.odd? }.join(" | ")
|
210
|
+
# => "Item 1 | Item 3"
|
211
|
+
```
|
104
212
|
|
105
|
-
|
213
|
+
```ruby
|
214
|
+
# AFTER
|
106
215
|
[1, 2, nil, 3, 4].join_map(" | ") { |n| "Item #{n}" if n&.odd? }
|
107
216
|
# => "Item 1 | Item 3"
|
217
|
+
```
|
108
218
|
|
109
|
-
|
110
|
-
|
219
|
+
*Methods used: [`join_map`](https://itsthedevman.com/docs/everythingrb/Array.html#join_map-instance_method)*
|
220
|
+
|
221
|
+
Group elements with natural syntax:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
# BEFORE
|
225
|
+
users = [
|
226
|
+
{name: "Alice", department: {name: "Engineering"}},
|
227
|
+
{name: "Bob", department: {name: "Sales"}},
|
228
|
+
{name: "Charlie", department: {name: "Engineering"}}
|
229
|
+
]
|
230
|
+
users.group_by { |user| user[:department][:name] }
|
231
|
+
# => {"Engineering"=>[{name: "Alice",...}, {name: "Charlie",...}], "Sales"=>[{name: "Bob",...}]}
|
111
232
|
```
|
112
233
|
|
113
|
-
|
234
|
+
```ruby
|
235
|
+
# AFTER
|
236
|
+
users.group_by_key(:department, :name)
|
237
|
+
# => {"Engineering"=>[{name: "Alice",...}, {name: "Charlie",...}], "Sales"=>[{name: "Bob",...}]}
|
238
|
+
```
|
114
239
|
|
115
|
-
|
240
|
+
*Methods used: [`group_by_key`](https://itsthedevman.com/docs/everythingrb/Enumerable.html#group_by_key-instance_method)*
|
116
241
|
|
117
|
-
|
242
|
+
Create natural language lists:
|
118
243
|
|
119
244
|
```ruby
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
245
|
+
# BEFORE
|
246
|
+
options = ["red", "blue", "green"]
|
247
|
+
# The default to_sentence uses "and"
|
248
|
+
options.to_sentence # => "red, blue, and green"
|
249
|
+
|
250
|
+
# Need "or" instead? Time for string surgery
|
251
|
+
if options.size <= 2
|
252
|
+
options.to_sentence(words_connector: " or ")
|
253
|
+
else
|
254
|
+
# Replace the last "and" with "or" - careful with i18n!
|
255
|
+
options.to_sentence.sub(/,?\s+and\s+/, ", or ")
|
256
|
+
end
|
257
|
+
# => "red, blue, or green"
|
258
|
+
```
|
126
259
|
|
127
|
-
|
128
|
-
|
129
|
-
|
260
|
+
```ruby
|
261
|
+
# AFTER
|
262
|
+
["red", "blue", "green"].to_or_sentence # => "red, blue, or green"
|
130
263
|
```
|
131
264
|
|
132
|
-
|
265
|
+
*Methods used: [`to_or_sentence`](https://itsthedevman.com/docs/everythingrb/Array.html#to_or_sentence-instance_method)*
|
266
|
+
|
267
|
+
**Extensions:** [`join_map`](https://itsthedevman.com/docs/everythingrb/Array.html#join_map-instance_method), [`key_map`](https://itsthedevman.com/docs/everythingrb/Array.html#key_map-instance_method), [`dig_map`](https://itsthedevman.com/docs/everythingrb/Array.html#dig_map-instance_method), [`to_or_sentence`](https://itsthedevman.com/docs/everythingrb/Array.html#to_or_sentence-instance_method), [`group_by_key`](https://itsthedevman.com/docs/everythingrb/Enumerable.html#group_by_key-instance_method)
|
133
268
|
|
134
269
|
### Hash Convenience
|
135
270
|
|
136
271
|
Work with hashes more intuitively:
|
137
272
|
|
138
273
|
```ruby
|
139
|
-
#
|
140
|
-
stats =
|
274
|
+
# BEFORE
|
275
|
+
stats = {}
|
276
|
+
stats[:server] ||= {}
|
277
|
+
stats[:server][:region] ||= {}
|
278
|
+
stats[:server][:region][:us_east] ||= {}
|
279
|
+
stats[:server][:region][:us_east][:errors] ||= []
|
141
280
|
stats[:server][:region][:us_east][:errors] << "Connection timeout"
|
281
|
+
```
|
282
|
+
|
283
|
+
```ruby
|
284
|
+
# AFTER
|
285
|
+
stats = Hash.new_nested_hash(depth: 3)
|
286
|
+
(stats[:server][:region][:us_east][:errors] ||= []) << "Connection timeout"
|
142
287
|
# No need to initialize each level first!
|
288
|
+
```
|
289
|
+
|
290
|
+
*Methods used: [`new_nested_hash`](https://itsthedevman.com/docs/everythingrb/Hash.html#new_nested_hash-class_method)*
|
291
|
+
|
292
|
+
Transform values with access to their keys:
|
143
293
|
|
144
|
-
|
294
|
+
```ruby
|
295
|
+
# BEFORE
|
296
|
+
users = {alice: {name: "Alice"}, bob: {name: "Bob"}}
|
297
|
+
result = {}
|
298
|
+
users.each do |key, value|
|
299
|
+
result[key] = "User #{key}: #{value[:name]}"
|
300
|
+
end
|
301
|
+
# => {alice: "User alice: Alice", bob: "User bob: Bob"}
|
302
|
+
```
|
303
|
+
|
304
|
+
```ruby
|
305
|
+
# AFTER
|
145
306
|
users.transform_values(with_key: true) { |v, k| "User #{k}: #{v[:name]}" }
|
307
|
+
# => {alice: "User alice: Alice", bob: "User bob: Bob"}
|
308
|
+
```
|
309
|
+
|
310
|
+
*Methods used: [`transform_values(with_key: true)`](https://itsthedevman.com/docs/everythingrb/Hash.html#transform_values-instance_method)*
|
311
|
+
|
312
|
+
Find values based on conditions:
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
# BEFORE
|
316
|
+
users = {
|
317
|
+
alice: {name: "Alice", role: "admin"},
|
318
|
+
bob: {name: "Bob", role: "user"},
|
319
|
+
charlie: {name: "Charlie", role: "admin"}
|
320
|
+
}
|
321
|
+
admins = users.select { |_k, v| v[:role] == "admin" }.values
|
322
|
+
# => [{name: "Alice", role: "admin"}, {name: "Charlie", role: "admin"}]
|
323
|
+
```
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
# AFTER
|
327
|
+
users.values_where { |_k, v| v[:role] == "admin" }
|
328
|
+
# => [{name: "Alice", role: "admin"}, {name: "Charlie", role: "admin"}]
|
329
|
+
```
|
330
|
+
|
331
|
+
*Methods used: [`values_where`](https://itsthedevman.com/docs/everythingrb/Hash.html#values_where-instance_method)*
|
332
|
+
|
333
|
+
Just want the first match? Even simpler:
|
334
|
+
|
335
|
+
```ruby
|
336
|
+
# BEFORE
|
337
|
+
users.find { |_k, v| v[:role] == "admin" }&.last
|
338
|
+
# => {name: "Alice", role: "admin"}
|
339
|
+
```
|
340
|
+
|
341
|
+
```ruby
|
342
|
+
# AFTER
|
343
|
+
users.value_where { |_k, v| v[:role] == "admin" }
|
344
|
+
# => {name: "Alice", role: "admin"}
|
345
|
+
```
|
346
|
+
|
347
|
+
*Methods used: [`value_where`](https://itsthedevman.com/docs/everythingrb/Hash.html#value_where-instance_method)*
|
348
|
+
|
349
|
+
Rename keys while preserving order:
|
146
350
|
|
147
|
-
|
148
|
-
|
351
|
+
```ruby
|
352
|
+
# BEFORE
|
353
|
+
config = {api_key: "secret", timeout: 30}
|
354
|
+
new_config = config.each_with_object({}) do |(key, value), hash|
|
355
|
+
new_key =
|
356
|
+
case key
|
357
|
+
when :api_key
|
358
|
+
:key
|
359
|
+
when :timeout
|
360
|
+
:request_timeout
|
361
|
+
else
|
362
|
+
key
|
363
|
+
end
|
364
|
+
|
365
|
+
hash[new_key] = value
|
366
|
+
end
|
367
|
+
# => {key: "secret", request_timeout: 30}
|
368
|
+
```
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
# AFTER
|
372
|
+
config = {api_key: "secret", timeout: 30}
|
373
|
+
config.rename_keys(api_key: :key, timeout: :request_timeout)
|
374
|
+
# => {key: "secret", request_timeout: 30}
|
375
|
+
```
|
376
|
+
|
377
|
+
*Methods used: [`rename_keys`](https://itsthedevman.com/docs/everythingrb/Hash.html#rename_keys-instance_method)*
|
378
|
+
|
379
|
+
Filter hash by values:
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
# BEFORE
|
383
|
+
result = {a: 1, b: nil, c: 2}.select { |_k, v| v.is_a?(Integer) && v > 1 }
|
384
|
+
# => {c: 2}
|
149
385
|
```
|
150
386
|
|
151
|
-
|
387
|
+
```ruby
|
388
|
+
# AFTER
|
389
|
+
{a: 1, b: nil, c: 2}.select_values { |v| v.is_a?(Integer) && v > 1 }
|
390
|
+
# => {c: 2}
|
391
|
+
```
|
392
|
+
|
393
|
+
*Methods used: [`select_values`](https://itsthedevman.com/docs/everythingrb/Hash.html#select_values-instance_method)*
|
394
|
+
|
395
|
+
Conditionally merge hashes with clear intent:
|
396
|
+
|
397
|
+
```ruby
|
398
|
+
# BEFORE
|
399
|
+
user_params = {name: "Alice", role: "user"}
|
400
|
+
filtered = {verified: true, admin: true}.select { |k, v| v == true && k == :verified }
|
401
|
+
user_params.merge(filtered)
|
402
|
+
# => {name: "Alice", role: "user", verified: true}
|
403
|
+
```
|
404
|
+
|
405
|
+
```ruby
|
406
|
+
# AFTER
|
407
|
+
user_params = {name: "Alice", role: "user"}
|
408
|
+
user_params.merge_if(verified: true, admin: true) { |k, v| v == true && k == :verified }
|
409
|
+
# => {name: "Alice", role: "user", verified: true}
|
410
|
+
```
|
411
|
+
|
412
|
+
*Methods used: [`merge_if`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_if-instance_method)*
|
413
|
+
|
414
|
+
The nil-filtering pattern we've all written dozens of times:
|
415
|
+
|
416
|
+
```ruby
|
417
|
+
# BEFORE
|
418
|
+
params = {sort: "created_at"}
|
419
|
+
filtered = {filter: "active", search: nil}.compact
|
420
|
+
params.merge(filtered)
|
421
|
+
# => {sort: "created_at", filter: "active"}
|
422
|
+
```
|
423
|
+
|
424
|
+
```ruby
|
425
|
+
# AFTER
|
426
|
+
params = {sort: "created_at"}
|
427
|
+
params.merge_compact(filter: "active", search: nil)
|
428
|
+
# => {sort: "created_at", filter: "active"}
|
429
|
+
```
|
430
|
+
|
431
|
+
*Methods used: [`merge_compact`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_compact-instance_method)*
|
432
|
+
|
433
|
+
**Extensions:** [`new_nested_hash`](https://itsthedevman.com/docs/everythingrb/Hash.html#new_nested_hash-class_method), [`transform_values(with_key: true)`](https://itsthedevman.com/docs/everythingrb/Hash.html#transform_values-instance_method), [`value_where`](https://itsthedevman.com/docs/everythingrb/Hash.html#value_where-instance_method), [`values_where`](https://itsthedevman.com/docs/everythingrb/Hash.html#values_where-instance_method), [`rename_key`](https://itsthedevman.com/docs/everythingrb/Hash.html#rename_key-instance_method), [`rename_keys`](https://itsthedevman.com/docs/everythingrb/Hash.html#rename_keys-instance_method), [`select_values`](https://itsthedevman.com/docs/everythingrb/Hash.html#select_values-instance_method), [`reject_values`](https://itsthedevman.com/docs/everythingrb/Hash.html#reject_values-instance_method), [`merge_if`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_if-instance_method), [`merge_if!`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_if%21-instance_method), [`merge_if_values`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_if_values-instance_method), [`merge_if_values!`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_if_values%21-instance_method), [`merge_compact`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_compact-instance_method), [`merge_compact!`](https://itsthedevman.com/docs/everythingrb/Hash.html#merge_compact%21-instance_method)
|
152
434
|
|
153
435
|
### Array Cleaning
|
154
436
|
|
155
437
|
Clean up array boundaries while preserving internal structure:
|
156
438
|
|
157
439
|
```ruby
|
158
|
-
#
|
440
|
+
# BEFORE
|
441
|
+
data = [nil, nil, 1, nil, 2, nil, nil]
|
442
|
+
data.drop_while(&:nil?).reverse.drop_while(&:nil?).reverse
|
443
|
+
# => [1, nil, 2]
|
444
|
+
```
|
445
|
+
|
446
|
+
```ruby
|
447
|
+
# AFTER
|
159
448
|
[nil, nil, 1, nil, 2, nil, nil].trim_nils # => [1, nil, 2]
|
449
|
+
```
|
160
450
|
|
161
|
-
|
451
|
+
*Methods used: [`trim_nils`](https://itsthedevman.com/docs/everythingrb/Array.html#trim_nils-instance_method)*
|
452
|
+
|
453
|
+
With ActiveSupport, remove blank values too:
|
454
|
+
|
455
|
+
```ruby
|
456
|
+
# BEFORE
|
457
|
+
data = [nil, "", 1, "", 2, nil, ""]
|
458
|
+
data.drop_while(&:blank?).reverse.drop_while(&:blank?).reverse
|
459
|
+
# => [1, "", 2]
|
460
|
+
```
|
461
|
+
|
462
|
+
```ruby
|
463
|
+
# AFTER
|
162
464
|
[nil, "", 1, "", 2, nil, ""].trim_blanks # => [1, "", 2]
|
163
465
|
```
|
164
466
|
|
165
|
-
|
467
|
+
*Methods used: [`trim_blanks`](https://itsthedevman.com/docs/everythingrb/Array.html#trim_blanks-instance_method)*
|
468
|
+
|
469
|
+
**Extensions:** [`trim_nils`](https://itsthedevman.com/docs/everythingrb/Array.html#trim_nils-instance_method), [`compact_prefix`](https://itsthedevman.com/docs/everythingrb/Array.html#compact_prefix-instance_method), [`compact_suffix`](https://itsthedevman.com/docs/everythingrb/Array.html#compact_suffix-instance_method), [`trim_blanks`](https://itsthedevman.com/docs/everythingrb/Array.html#trim_blanks-instance_method) (with ActiveSupport)
|
470
|
+
|
471
|
+
### String Formatting
|
472
|
+
|
473
|
+
Format strings and other values consistently:
|
474
|
+
|
475
|
+
```ruby
|
476
|
+
# BEFORE
|
477
|
+
def format_value(value)
|
478
|
+
case value
|
479
|
+
when String
|
480
|
+
"\"#{value}\""
|
481
|
+
when Symbol
|
482
|
+
"\"#{value}\""
|
483
|
+
when Numeric
|
484
|
+
"\"#{value}\""
|
485
|
+
when NilClass
|
486
|
+
"\"nil\""
|
487
|
+
when Array, Hash
|
488
|
+
"\"#{value.inspect}\""
|
489
|
+
else
|
490
|
+
"\"#{value}\""
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
selection = nil
|
495
|
+
message = "You selected #{format_value(selection)}"
|
496
|
+
```
|
497
|
+
|
498
|
+
```ruby
|
499
|
+
# AFTER
|
500
|
+
"hello".in_quotes # => "\"hello\""
|
501
|
+
42.in_quotes # => "\"42\""
|
502
|
+
nil.in_quotes # => "\"nil\""
|
503
|
+
:symbol.in_quotes # => "\"symbol\""
|
504
|
+
[1, 2].in_quotes # => "\"[1, 2]\""
|
505
|
+
Time.now.in_quotes # => "\"2025-05-04 12:34:56 +0000\""
|
506
|
+
|
507
|
+
message = "You selected #{selection.in_quotes}"
|
508
|
+
```
|
509
|
+
|
510
|
+
*Methods used: [`in_quotes`](https://itsthedevman.com/docs/everythingrb/Everythingrb/InspectQuotable.html#in_quotes-instance_method), [`with_quotes`](https://itsthedevman.com/docs/everythingrb/Everythingrb/InspectQuotable.html#with_quotes-instance_method)*
|
511
|
+
|
512
|
+
Convert strings to camelCase with ease:
|
513
|
+
|
514
|
+
```ruby
|
515
|
+
# BEFORE
|
516
|
+
name = "user_profile_settings"
|
517
|
+
pascal_case = name.gsub(/[-_\s]+([a-z])/i) { $1.upcase }.gsub(/[-_\s]/, '')
|
518
|
+
pascal_case[0].upcase!
|
519
|
+
pascal_case
|
520
|
+
# => "UserProfileSettings"
|
521
|
+
|
522
|
+
camel_case = name.gsub(/[-_\s]+([a-z])/i) { $1.upcase }.gsub(/[-_\s]/, '')
|
523
|
+
camel_case[0].downcase!
|
524
|
+
camel_case
|
525
|
+
# => "userProfileSettings"
|
526
|
+
```
|
527
|
+
|
528
|
+
```ruby
|
529
|
+
# AFTER
|
530
|
+
"user_profile_settings".to_camelcase # => "UserProfileSettings"
|
531
|
+
"user_profile_settings".to_camelcase(:lower) # => "userProfileSettings"
|
532
|
+
|
533
|
+
# Handles all kinds of input consistently
|
534
|
+
"please-WAIT while_loading...".to_camelcase # => "PleaseWaitWhileLoading"
|
535
|
+
```
|
536
|
+
|
537
|
+
*Methods used: [`to_camelcase`](https://itsthedevman.com/docs/everythingrb/String.html#to_camelcase-instance_method)*
|
538
|
+
|
539
|
+
**Extensions:** [`in_quotes`](https://itsthedevman.com/docs/everythingrb/Everythingrb/InspectQuotable.html#in_quotes-instance_method), [`with_quotes`](https://itsthedevman.com/docs/everythingrb/Everythingrb/InspectQuotable.html#with_quotes-instance_method) (alias), [`to_camelcase`](https://itsthedevman.com/docs/everythingrb/String.html#to_camelcase-instance_method)
|
166
540
|
|
167
541
|
### Boolean Methods
|
168
542
|
|
169
543
|
Create predicate methods with minimal code:
|
170
544
|
|
171
545
|
```ruby
|
546
|
+
# BEFORE
|
547
|
+
class User
|
548
|
+
attr_accessor :admin
|
549
|
+
|
550
|
+
def admin?
|
551
|
+
!!@admin
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
user = User.new
|
556
|
+
user.admin = true
|
557
|
+
user.admin? # => true
|
558
|
+
```
|
559
|
+
|
560
|
+
```ruby
|
561
|
+
# AFTER
|
172
562
|
class User
|
173
563
|
attr_accessor :admin
|
174
564
|
attr_predicate :admin
|
@@ -177,8 +567,21 @@ end
|
|
177
567
|
user = User.new
|
178
568
|
user.admin = true
|
179
569
|
user.admin? # => true
|
570
|
+
```
|
571
|
+
|
572
|
+
*Methods used: [`attr_predicate`](https://itsthedevman.com/docs/everythingrb/Module.html#attr_predicate-instance_method)*
|
573
|
+
|
574
|
+
Works with Data objects too:
|
575
|
+
|
576
|
+
```ruby
|
577
|
+
# BEFORE
|
578
|
+
Person = Data.define(:active) do
|
579
|
+
def active?
|
580
|
+
!!active
|
581
|
+
end
|
582
|
+
end
|
180
583
|
|
181
|
-
#
|
584
|
+
# AFTER
|
182
585
|
Person = Data.define(:active)
|
183
586
|
Person.attr_predicate(:active)
|
184
587
|
|
@@ -186,7 +589,27 @@ person = Person.new(active: false)
|
|
186
589
|
person.active? # => false
|
187
590
|
```
|
188
591
|
|
189
|
-
|
592
|
+
*Methods used: [`attr_predicate`](https://itsthedevman.com/docs/everythingrb/Module.html#attr_predicate-instance_method)*
|
593
|
+
|
594
|
+
**Extensions:** [`attr_predicate`](https://itsthedevman.com/docs/everythingrb/Module.html#attr_predicate-instance_method)
|
595
|
+
|
596
|
+
### Value Transformation
|
597
|
+
|
598
|
+
Chain transformations with a more descriptive syntax:
|
599
|
+
|
600
|
+
```ruby
|
601
|
+
# BEFORE
|
602
|
+
result = value.then { |v| transform_it(v) }
|
603
|
+
```
|
604
|
+
|
605
|
+
```ruby
|
606
|
+
# AFTER
|
607
|
+
result = value.morph { |v| transform_it(v) }
|
608
|
+
```
|
609
|
+
|
610
|
+
*Methods used: [`morph`](https://itsthedevman.com/docs/everythingrb/Kernel.html#morph-instance_method)*
|
611
|
+
|
612
|
+
**Extensions:** [`morph`](https://itsthedevman.com/docs/everythingrb/Kernel.html#morph-instance_method) (alias for `then`/`yield_self`)
|
190
613
|
|
191
614
|
## Full Documentation
|
192
615
|
|
data/lib/everythingrb/all.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "array"
|
4
|
+
require_relative "boolean"
|
4
5
|
require_relative "data"
|
6
|
+
require_relative "date"
|
5
7
|
require_relative "enumerable"
|
6
8
|
require_relative "hash"
|
9
|
+
require_relative "kernel"
|
7
10
|
require_relative "module"
|
11
|
+
require_relative "nil"
|
12
|
+
require_relative "numeric"
|
8
13
|
require_relative "ostruct"
|
14
|
+
require_relative "range"
|
15
|
+
require_relative "regexp"
|
9
16
|
require_relative "string"
|
10
17
|
require_relative "struct"
|
11
18
|
require_relative "symbol"
|
19
|
+
require_relative "time"
|