everythingrb 0.3.1 → 0.5.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 +55 -4
- data/README.md +47 -0
- data/lib/everythingrb/all.rb +11 -0
- data/lib/everythingrb/{core/array.rb → array.rb} +10 -11
- data/lib/everythingrb/data.rb +23 -0
- data/lib/everythingrb/{core/enumerable.rb → enumerable.rb} +7 -5
- data/lib/everythingrb/{core/hash.rb → hash.rb} +216 -26
- data/lib/everythingrb/{core/module.rb → module.rb} +6 -4
- data/lib/everythingrb/{core/ostruct.rb → ostruct.rb} +25 -4
- data/lib/everythingrb/prelude.rb +30 -0
- data/lib/everythingrb/{core/string.rb → string.rb} +10 -7
- data/lib/everythingrb/struct.rb +31 -0
- data/lib/everythingrb/{core/symbol.rb → symbol.rb} +4 -1
- data/lib/everythingrb/version.rb +1 -1
- data/lib/everythingrb.rb +2 -35
- metadata +15 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 320458b0c0e09c8556129b456eb191ff588a6b2277b5da46a5273dc36c4f3a50
|
4
|
+
data.tar.gz: 824f8c91fbe4749022a8a5f2caf6d6f76714a6d7faf747a4f25818342d5d5b39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac7ed45151941a1e124372ebfb1394fb8176f4703bc903fa634d3672a251c8a4e497f8555bc1433848512d7e8edb04926c8a043420d3337041c7fc00e9e7eebd
|
7
|
+
data.tar.gz: b0d711b08f5ec75aa07ab009587784a926f2e5832a35037da89a96fa5d800a29e4e4b1c3beb81ba6b86b3d5821252aeda2ab2f124234f859af477cbeb186a8cb
|
data/CHANGELOG.md
CHANGED
@@ -23,6 +23,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
23
23
|
|
24
24
|
### Removed
|
25
25
|
|
26
|
+
## [0.5.0] - 12025-04-17
|
27
|
+
|
28
|
+
**BREAKING:**
|
29
|
+
|
30
|
+
The parameter order in `Hash#transform_values.with_key` has been changed to yield `|value, key|` instead of `|key, value|` to maintain consistency with Ruby's standard enumeration methods like `each_with_index`.
|
31
|
+
|
32
|
+
**Before:**
|
33
|
+
```ruby
|
34
|
+
hash.transform_values.with_key { |key, value| "#{key}: #{value}" }
|
35
|
+
```
|
36
|
+
|
37
|
+
**After:**
|
38
|
+
```ruby
|
39
|
+
hash.transform_values.with_key { |value, key| "#{key}: #{value}" }
|
40
|
+
```
|
41
|
+
|
42
|
+
This change aligns our method signatures with Ruby's conventions and matches our other methods like `join_map(with_index: true)` which yields `|value, index|`.
|
43
|
+
|
44
|
+
### Added
|
45
|
+
|
46
|
+
- Added `Hash#transform` and `Hash#transform!` for transforming a hash's keys and values at the same time.
|
47
|
+
|
48
|
+
### Changed
|
49
|
+
- Changed parameter order in `Hash#transform_values.with_key` to yield `|value, key|` instead of `|key, value|` for consistency with Ruby conventions.
|
50
|
+
|
51
|
+
### Removed
|
52
|
+
|
53
|
+
|
54
|
+
## [0.4.0] - 12025-04-11
|
55
|
+
|
56
|
+
### Added
|
57
|
+
|
58
|
+
- Added new `Hash` methods for renaming keys:
|
59
|
+
- `#rename_key` - Renames a key in the hash while preserving the original order of elements
|
60
|
+
- `#rename_key!` - Same as `#rename_key` but modifies the hash in place
|
61
|
+
- `#rename_keys` - Renames multiple keys in the hash while preserving the original order of elements
|
62
|
+
- `#rename_keys!` - Same as `#rename_keys` but modifies the hash in place
|
63
|
+
- `#rename_key_unordered` - Renames a key without preserving element order (faster operation)
|
64
|
+
- `#rename_key_unordered!` - Same as `#rename_key_unordered` but modifies the hash in place
|
65
|
+
- Added `to_deep_h` to core Ruby classes for consistent deep hash conversion:
|
66
|
+
- `Struct#to_deep_h` - Recursively converts Struct objects and all nested values to hashes
|
67
|
+
- `OpenStruct#to_deep_h` - Recursively converts OpenStruct objects and all nested values to hashes
|
68
|
+
- `Data#to_deep_h` - Recursively converts Data objects and all nested values to hashes
|
69
|
+
- Added `depth` parameter to `Hash.new_nested_hash` to control nesting behaviors
|
70
|
+
|
71
|
+
### Changed
|
72
|
+
|
73
|
+
- Reorganized internal file structure for better modularity with full backward compatibility
|
74
|
+
- Updated documentation headers to each module file explaining available extensions
|
75
|
+
|
76
|
+
### Removed
|
77
|
+
|
26
78
|
## [0.3.1] - 12025-04-09
|
27
79
|
|
28
80
|
### Added
|
@@ -74,7 +126,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
74
126
|
|
75
127
|
- Added `Symbol#with_quotes` and `Symbol#in_quotes`
|
76
128
|
|
77
|
-
|
78
129
|
## [0.2.2] - 12025-03-03
|
79
130
|
|
80
131
|
### Added
|
@@ -94,7 +145,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
94
145
|
|
95
146
|
- Removed `Data` definition check for `to_istruct`
|
96
147
|
|
97
|
-
|
98
148
|
## [0.2.0] - 12025-02-17
|
99
149
|
|
100
150
|
### Added
|
@@ -119,7 +169,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
119
169
|
|
120
170
|
- Separated out tests that require `ActiveSupport` into their own test process. Files that end with `_active_support` will be tested separately with ActiveSupport loaded
|
121
171
|
|
122
|
-
|
123
172
|
## [0.1.1] - 12025-02-07
|
124
173
|
|
125
174
|
### Added
|
@@ -149,7 +198,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
149
198
|
|
150
199
|
- Added alias `each` to `each_pair` in OpenStruct for better enumerable compatibility
|
151
200
|
|
152
|
-
[unreleased]: https://github.com/itsthedevman/everythingrb/compare/v0.
|
201
|
+
[unreleased]: https://github.com/itsthedevman/everythingrb/compare/v0.5.0...HEAD
|
202
|
+
[0.5.0]: https://github.com/itsthedevman/everythingrb/compare/v0.4.0...v0.5.0
|
203
|
+
[0.4.0]: https://github.com/itsthedevman/everythingrb/compare/v0.3.1...v0.4.0
|
153
204
|
[0.3.1]: https://github.com/itsthedevman/everythingrb/compare/v0.3.0...v0.3.1
|
154
205
|
[0.3.0]: https://github.com/itsthedevman/everythingrb/compare/v0.2.5...v0.3.0
|
155
206
|
[0.2.5]: https://github.com/itsthedevman/everythingrb/compare/v0.2.4...v0.2.5
|
data/README.md
CHANGED
@@ -25,6 +25,53 @@ gem "everythingrb"
|
|
25
25
|
gem install everythingrb
|
26
26
|
```
|
27
27
|
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
There are two ways to use EverythingRB:
|
31
|
+
|
32
|
+
### Load Everything (Default)
|
33
|
+
|
34
|
+
The simplest approach - just require and go:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require "everythingrb"
|
38
|
+
|
39
|
+
# Now you have access to all extensions!
|
40
|
+
users = [{name: "Alice"}, {name: "Bob"}]
|
41
|
+
users.key_map(:name).join(", ") # => "Alice, Bob"
|
42
|
+
|
43
|
+
config = {server: {port: 443}}.to_ostruct
|
44
|
+
config.server.port # => 443
|
45
|
+
```
|
46
|
+
|
47
|
+
### Cherry-Pick Extensions
|
48
|
+
|
49
|
+
If you only need specific extensions, you can load just what you want:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
require "everythingrb/prelude" # Required base module
|
53
|
+
require "everythingrb/array" # Just Array extensions
|
54
|
+
require "everythingrb/string" # Just String extensions
|
55
|
+
|
56
|
+
# Now you have access to only the extensions you loaded
|
57
|
+
["a", "b"].join_map(" | ") { |s| s.upcase } # => "A | B"
|
58
|
+
'{"name": "Alice"}'.to_ostruct.name # => "Alice"
|
59
|
+
|
60
|
+
# But Hash extensions aren't loaded yet
|
61
|
+
{}.to_ostruct # => NoMethodError
|
62
|
+
```
|
63
|
+
|
64
|
+
Available modules:
|
65
|
+
- `array`: Array extensions (join_map, key_map, etc.)
|
66
|
+
- `data`: Data extensions (to_deep_h)
|
67
|
+
- `enumerable`: Enumerable extensions (join_map, group_by_key)
|
68
|
+
- `hash`: Hash extensions (to_ostruct, deep_freeze, etc.)
|
69
|
+
- `module`: Extensions like attr_predicate
|
70
|
+
- `ostruct`: OpenStruct extensions (map, join_map, etc.)
|
71
|
+
- `string`: String extensions (to_h, to_ostruct, etc.)
|
72
|
+
- `struct`: Struct extensions (to_deep_h)
|
73
|
+
- `symbol`: Symbol extensions (with_quotes)
|
74
|
+
|
28
75
|
## What's Included
|
29
76
|
|
30
77
|
EverythingRB extends Ruby's core classes with intuitive methods that simplify common patterns.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "array"
|
4
|
+
require_relative "data"
|
5
|
+
require_relative "enumerable"
|
6
|
+
require_relative "hash"
|
7
|
+
require_relative "module"
|
8
|
+
require_relative "ostruct"
|
9
|
+
require_relative "string"
|
10
|
+
require_relative "struct"
|
11
|
+
require_relative "symbol"
|
@@ -3,18 +3,17 @@
|
|
3
3
|
#
|
4
4
|
# Extensions to Ruby's core Array class
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Provides:
|
7
|
+
# - #join_map: Combine filter_map and join operations in one step
|
8
|
+
# - #key_map, #dig_map: Extract values from arrays of hashes
|
9
|
+
# - #deep_freeze: Recursively freeze array and contents
|
10
|
+
# - #compact_prefix, #compact_suffix, #trim_nils: Clean up array boundaries
|
11
|
+
# - ActiveSupport integrations: #trim_blanks and more when ActiveSupport is loaded
|
8
12
|
#
|
9
|
-
# @example
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# numbers.join_map(", ") { |n| "odd: #{n}" if n&.odd? }
|
14
|
-
# # => "odd: 1, odd: 3"
|
15
|
-
#
|
16
|
-
# users = [{name: "Alice", role: "admin"}, {name: "Bob", role: "user"}]
|
17
|
-
# users.key_map(:name) # => ["Alice", "Bob"]
|
13
|
+
# @example
|
14
|
+
# require "everythingrb/array"
|
15
|
+
# ["foo", nil, "bar"].join_map(", ") { |s| s&.upcase } # => "FOO, BAR"
|
16
|
+
# [{name: "Alice"}, {name: "Bob"}].key_map(:name) # => ["Alice", "Bob"]
|
18
17
|
#
|
19
18
|
class Array
|
20
19
|
#
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Extensions to Ruby's core Data class
|
5
|
+
#
|
6
|
+
# Provides:
|
7
|
+
# - #to_deep_h: Recursively convert to hash with all nested objects
|
8
|
+
#
|
9
|
+
class Data
|
10
|
+
#
|
11
|
+
# Recursively converts the Data object and all nested objects to hashes
|
12
|
+
#
|
13
|
+
# @return [Hash] A deeply converted hash of the Data object
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# Person = Data.define(:name, :profile)
|
17
|
+
# person = Person.new(name: "Alice", profile: {roles: ["admin"]})
|
18
|
+
# person.to_deep_h # => {name: "Alice", profile: {roles: ["admin"]}}
|
19
|
+
#
|
20
|
+
def to_deep_h
|
21
|
+
to_h.to_deep_h
|
22
|
+
end
|
23
|
+
end
|
@@ -3,12 +3,14 @@
|
|
3
3
|
#
|
4
4
|
# Extensions to Ruby's core Enumerable module
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Provides:
|
7
|
+
# - #join_map: Combine filter_map and join operations
|
8
|
+
# - #group_by_key: Group elements by a given key or nested keys
|
8
9
|
#
|
9
|
-
# @example
|
10
|
-
#
|
11
|
-
# # => "item-2 | item-4"
|
10
|
+
# @example
|
11
|
+
# require "everythingrb/enumerable"
|
12
|
+
# (1..5).join_map(" | ") { |n| "item-#{n}" if n.even? } # => "item-2 | item-4"
|
13
|
+
# users.group_by_key(:role) # Groups users by their role
|
12
14
|
#
|
13
15
|
module Enumerable
|
14
16
|
#
|
@@ -3,17 +3,20 @@
|
|
3
3
|
#
|
4
4
|
# Extensions to Ruby's core Hash class
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Provides:
|
7
|
+
# - #to_struct, #to_ostruct, #to_istruct: Convert hashes to different structures
|
8
|
+
# - #join_map: Combine filter_map and join operations
|
9
|
+
# - #deep_freeze: Recursively freeze hash and contents
|
10
|
+
# - #transform_values.with_key: Transform values with access to keys
|
11
|
+
# - #transform, #transform!: Transform keys and values
|
12
|
+
# - #value_where, #values_where: Find values based on conditions
|
13
|
+
# - #rename_key, #rename_keys: Rename hash keys while preserving order
|
14
|
+
# - ::new_nested_hash: Create automatically nesting hashes
|
8
15
|
#
|
9
|
-
# @example
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# # Filtering and joining hash entries
|
15
|
-
# { a: 1, b: nil, c: 3 }.join_map(", ") { |k, v| "#{k}:#{v}" if v }
|
16
|
-
# # => "a:1, c:3"
|
16
|
+
# @example
|
17
|
+
# require "everythingrb/hash"
|
18
|
+
# config = {server: {port: 443}}.to_ostruct
|
19
|
+
# config.server.port # => 443
|
17
20
|
#
|
18
21
|
class Hash
|
19
22
|
#
|
@@ -33,26 +36,49 @@ class Hash
|
|
33
36
|
# Creates a new Hash that automatically initializes missing keys with nested hashes
|
34
37
|
#
|
35
38
|
# This method creates a hash where any missing key access will automatically
|
36
|
-
# create another nested hash with the same behavior
|
37
|
-
#
|
39
|
+
# create another nested hash with the same behavior. You can control the nesting
|
40
|
+
# depth with the depth parameter.
|
41
|
+
#
|
42
|
+
# @param depth [Integer, nil] The maximum nesting depth for automatic hash creation
|
43
|
+
# When nil (default), creates unlimited nesting depth
|
44
|
+
# When 0, behaves like a regular hash (returns nil for missing keys)
|
45
|
+
# When > 0, automatically creates hashes only up to the specified level
|
38
46
|
#
|
39
|
-
# @return [Hash] A hash that
|
47
|
+
# @return [Hash] A hash that creates nested hashes for missing keys
|
40
48
|
#
|
41
|
-
# @example
|
49
|
+
# @example Unlimited nesting (default behavior)
|
42
50
|
# users = Hash.new_nested_hash
|
43
51
|
# users[:john][:role] = "admin" # No need to initialize users[:john] first
|
44
52
|
# users # => {john: {role: "admin"}}
|
45
53
|
#
|
46
54
|
# @example Deep nesting without initialization
|
47
55
|
# stats = Hash.new_nested_hash
|
48
|
-
#
|
49
|
-
# stats # => {server: {region: {us_east: {errors: ["
|
50
|
-
#
|
51
|
-
# @
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
+
# stats[:server][:region][:us_east][:errors] = ["Error"]
|
57
|
+
# stats # => {server: {region: {us_east: {errors: ["Error"]}}}}
|
58
|
+
#
|
59
|
+
# @example Limited nesting depth
|
60
|
+
# hash = Hash.new_nested_hash(depth: 1)
|
61
|
+
# hash[:user][:name] = "Alice" # Works fine - only one level of auto-creation
|
62
|
+
#
|
63
|
+
# # This pattern works correctly with limited nesting:
|
64
|
+
# (hash[:user][:roles] ||= []) << "admin"
|
65
|
+
# hash # => {user: {name: "Alice", roles: ["admin"]}}
|
66
|
+
#
|
67
|
+
# @note While unlimited nesting is convenient, it can interfere with common Ruby
|
68
|
+
# patterns like ||= when initializing values at deep depths. Use the depth
|
69
|
+
# parameter to control this behavior.
|
70
|
+
#
|
71
|
+
def self.new_nested_hash(depth: nil)
|
72
|
+
new do |hash, key|
|
73
|
+
next if depth == 0
|
74
|
+
|
75
|
+
hash[key] =
|
76
|
+
if depth.nil?
|
77
|
+
new_nested_hash
|
78
|
+
else
|
79
|
+
new_nested_hash(depth: depth - 1)
|
80
|
+
end
|
81
|
+
end
|
56
82
|
end
|
57
83
|
|
58
84
|
#
|
@@ -249,7 +275,7 @@ class Hash
|
|
249
275
|
# # => {a: 2, b: 4}
|
250
276
|
#
|
251
277
|
# @example Using with_key to access keys during transformation
|
252
|
-
# {a: 1, b: 2}.transform_values.with_key { |
|
278
|
+
# {a: 1, b: 2}.transform_values.with_key { |v, k| "#{k}_#{v}" }
|
253
279
|
# # => {a: "a_1", b: "b_2"}
|
254
280
|
#
|
255
281
|
def transform_values(&block)
|
@@ -279,7 +305,7 @@ class Hash
|
|
279
305
|
#
|
280
306
|
# @example Using with_key to access keys during in-place transformation
|
281
307
|
# hash = {a: 1, b: 2}
|
282
|
-
# hash.transform_values!.with_key { |
|
308
|
+
# hash.transform_values!.with_key { |v, k| "#{k}_#{v}" }
|
283
309
|
# # => {a: "a_1", b: "b_2"}
|
284
310
|
#
|
285
311
|
def transform_values!(&block)
|
@@ -288,6 +314,49 @@ class Hash
|
|
288
314
|
og_transform_values!(&block)
|
289
315
|
end
|
290
316
|
|
317
|
+
#
|
318
|
+
# Transforms keys and values to create a new hash
|
319
|
+
#
|
320
|
+
# @yield [key, value] Block that returns a new key-value pair
|
321
|
+
# @yieldparam key [Object] The original key
|
322
|
+
# @yieldparam value [Object] The original value
|
323
|
+
# @yieldreturn [Array] Two-element array containing the new key and value
|
324
|
+
#
|
325
|
+
# @return [Hash] A new hash with transformed keys and values
|
326
|
+
# @return [Enumerator] If no block is given
|
327
|
+
#
|
328
|
+
# @example Transform both keys and values
|
329
|
+
# {a: 1, b: 2}.transform { |k, v| ["#{k}_key", v * 2] }
|
330
|
+
# # => {a_key: 2, b_key: 4}
|
331
|
+
#
|
332
|
+
def transform(&block)
|
333
|
+
return to_enum(:transform) if block.nil?
|
334
|
+
|
335
|
+
to_h(&block)
|
336
|
+
end
|
337
|
+
|
338
|
+
#
|
339
|
+
# Transforms keys and values in place
|
340
|
+
#
|
341
|
+
# @yield [key, value] Block that returns a new key-value pair
|
342
|
+
# @yieldparam key [Object] The original key
|
343
|
+
# @yieldparam value [Object] The original value
|
344
|
+
# @yieldreturn [Array] Two-element array containing the new key and value
|
345
|
+
#
|
346
|
+
# @return [self] The transformed hash
|
347
|
+
# @return [Enumerator] If no block is given
|
348
|
+
#
|
349
|
+
# @example Transform both keys and values in place
|
350
|
+
# hash = {a: 1, b: 2}
|
351
|
+
# hash.transform! { |k, v| ["#{k}_key", v * 2] }
|
352
|
+
# # => {a_key: 2, b_key: 4}
|
353
|
+
#
|
354
|
+
def transform!(&block)
|
355
|
+
return to_enum(:transform!) if block.nil?
|
356
|
+
|
357
|
+
replace(transform(&block))
|
358
|
+
end
|
359
|
+
|
291
360
|
#
|
292
361
|
# Returns the first value where the key-value pair satisfies the given condition
|
293
362
|
#
|
@@ -339,6 +408,127 @@ class Hash
|
|
339
408
|
select(&block).values
|
340
409
|
end
|
341
410
|
|
411
|
+
#
|
412
|
+
# Renames a key in the hash while preserving the original order of elements
|
413
|
+
#
|
414
|
+
# @param old_key [Object] The key to rename
|
415
|
+
# @param new_key [Object] The new key to use
|
416
|
+
#
|
417
|
+
# @return [Hash] A new hash with the key renamed
|
418
|
+
#
|
419
|
+
# @example Renames a single key
|
420
|
+
# {a: 1, b: 2, c: 3}.rename_key(:b, :middle)
|
421
|
+
# # => {a: 1, middle: 2, c: 3}
|
422
|
+
#
|
423
|
+
def rename_key(old_key, new_key)
|
424
|
+
rename_keys(old_key => new_key)
|
425
|
+
end
|
426
|
+
|
427
|
+
#
|
428
|
+
# Renames a key in the hash in place while preserving the original order of elements
|
429
|
+
#
|
430
|
+
# @param old_key [Object] The key to rename
|
431
|
+
# @param new_key [Object] The new key to use
|
432
|
+
#
|
433
|
+
# @return [self] The modified hash
|
434
|
+
#
|
435
|
+
# @example Renames a key in place
|
436
|
+
# hash = {a: 1, b: 2, c: 3}
|
437
|
+
# hash.rename_key!(:b, :middle)
|
438
|
+
# # => {a: 1, middle: 2, c: 3}
|
439
|
+
#
|
440
|
+
def rename_key!(old_key, new_key)
|
441
|
+
rename_keys!(old_key => new_key)
|
442
|
+
end
|
443
|
+
|
444
|
+
#
|
445
|
+
# Renames multiple keys in the hash while preserving the original order of elements
|
446
|
+
#
|
447
|
+
# This method maintains the original order of all keys in the hash, renaming
|
448
|
+
# only the specified keys while keeping their positions unchanged.
|
449
|
+
#
|
450
|
+
# @param keys [Hash] A mapping of old_key => new_key pairs
|
451
|
+
#
|
452
|
+
# @return [Hash] A new hash with keys renamed
|
453
|
+
#
|
454
|
+
# @example Renames multiple keys
|
455
|
+
# {a: 1, b: 2, c: 3, d: 4}.rename_keys(a: :first, c: :third)
|
456
|
+
# # => {first: 1, b: 2, third: 3, d: 4}
|
457
|
+
#
|
458
|
+
def rename_keys(**keys)
|
459
|
+
# I tried multiple different ways to rename the key while preserving the order, this was the fastest
|
460
|
+
transform_keys do |key|
|
461
|
+
keys.key?(key) ? keys[key] : key
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
#
|
466
|
+
# Renames multiple keys in the hash in place while preserving the original order of elements
|
467
|
+
#
|
468
|
+
# This method maintains the original order of all keys in the hash, renaming
|
469
|
+
# only the specified keys while keeping their positions unchanged.
|
470
|
+
#
|
471
|
+
# @param keys [Hash] A mapping of old_key => new_key pairs
|
472
|
+
#
|
473
|
+
# @return [self] The modified hash
|
474
|
+
#
|
475
|
+
# @example Rename multiple keys in place
|
476
|
+
# hash = {a: 1, b: 2, c: 3, d: 4}
|
477
|
+
# hash.rename_keys!(a: :first, c: :third)
|
478
|
+
# # => {first: 1, b: 2, third: 3, d: 4}
|
479
|
+
#
|
480
|
+
def rename_keys!(**keys)
|
481
|
+
# I tried multiple different ways to rename the key while preserving the order, this was the fastest
|
482
|
+
transform_keys! do |key|
|
483
|
+
keys.key?(key) ? keys[key] : key
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
#
|
488
|
+
# Renames a key in the hash without preserving element order (faster)
|
489
|
+
#
|
490
|
+
# This method is significantly faster than #rename_key but does not
|
491
|
+
# guarantee that the order of elements in the hash will be preserved.
|
492
|
+
#
|
493
|
+
# @param old_key [Object] The key to rename
|
494
|
+
# @param new_key [Object] The new key to use
|
495
|
+
#
|
496
|
+
# @return [Hash] A new hash with the key renamed
|
497
|
+
#
|
498
|
+
# @example Rename a single key without preserving order
|
499
|
+
# {a: 1, b: 2, c: 3}.rename_key_unordered(:b, :middle)
|
500
|
+
# # => {a: 1, c: 3, middle: 2} # Order may differ
|
501
|
+
#
|
502
|
+
def rename_key_unordered(old_key, new_key)
|
503
|
+
# Fun thing I learned. For small hashes, using #except is 1.5x faster than using dup and delete.
|
504
|
+
# But as the hash becomes larger, the performance improvements become diminished until they're roughly the same.
|
505
|
+
# Neat!
|
506
|
+
hash = except(old_key)
|
507
|
+
hash[new_key] = self[old_key]
|
508
|
+
hash
|
509
|
+
end
|
510
|
+
|
511
|
+
#
|
512
|
+
# Renames a key in the hash in place without preserving element order (faster)
|
513
|
+
#
|
514
|
+
# This method is significantly faster than #rename_key! but does not
|
515
|
+
# guarantee that the order of elements in the hash will be preserved.
|
516
|
+
#
|
517
|
+
# @param old_key [Object] The key to rename
|
518
|
+
# @param new_key [Object] The new key to use
|
519
|
+
#
|
520
|
+
# @return [self] The modified hash
|
521
|
+
#
|
522
|
+
# @example Rename a key in place without preserving order
|
523
|
+
# hash = {a: 1, b: 2, c: 3}
|
524
|
+
# hash.rename_key_unordered!(:b, :middle)
|
525
|
+
# # => {a: 1, c: 3, middle: 2} # Order may differ
|
526
|
+
#
|
527
|
+
def rename_key_unordered!(old_key, new_key)
|
528
|
+
self[new_key] = delete(old_key)
|
529
|
+
self
|
530
|
+
end
|
531
|
+
|
342
532
|
private
|
343
533
|
|
344
534
|
def transform_values_enumerator
|
@@ -350,7 +540,7 @@ class Hash
|
|
350
540
|
raise ArgumentError, "Missing block for Hash#transform_values.with_key" if block.nil?
|
351
541
|
|
352
542
|
original_hash.each_pair.with_object({}) do |(key, value), output|
|
353
|
-
output[key] = block.call(
|
543
|
+
output[key] = block.call(value, key)
|
354
544
|
end
|
355
545
|
end
|
356
546
|
|
@@ -366,7 +556,7 @@ class Hash
|
|
366
556
|
raise ArgumentError, "Missing block for Hash#transform_values!.with_key" if block.nil?
|
367
557
|
|
368
558
|
original_hash.each_pair do |key, value|
|
369
|
-
original_hash[key] = block.call(
|
559
|
+
original_hash[key] = block.call(value, key)
|
370
560
|
end
|
371
561
|
|
372
562
|
original_hash
|
@@ -3,10 +3,12 @@
|
|
3
3
|
#
|
4
4
|
# Extensions to Ruby's core Module class
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Provides:
|
7
|
+
# - #attr_predicate: Create boolean-style accessor methods
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# require "everythingrb/module"
|
8
11
|
#
|
9
|
-
# @example Creating predicate methods
|
10
12
|
# class User
|
11
13
|
# attr_accessor :admin
|
12
14
|
# attr_predicate :admin
|
@@ -14,7 +16,7 @@
|
|
14
16
|
#
|
15
17
|
# user = User.new
|
16
18
|
# user.admin = true
|
17
|
-
# user.admin?
|
19
|
+
# user.admin? # => true
|
18
20
|
#
|
19
21
|
class Module
|
20
22
|
#
|
@@ -3,12 +3,17 @@
|
|
3
3
|
#
|
4
4
|
# Extensions to Ruby's OpenStruct class
|
5
5
|
#
|
6
|
-
#
|
7
|
-
# methods
|
6
|
+
# Provides:
|
7
|
+
# - #map, #filter_map: Enumeration methods for OpenStruct entries
|
8
|
+
# - #join_map: Combine filter_map and join operations
|
9
|
+
# - #blank?, #present?: ActiveSupport integrations when available
|
10
|
+
# - #to_deep_h: Recursively convert to hash with all nested objects
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# require "everythingrb/ostruct"
|
8
14
|
#
|
9
|
-
# @example Using enumeration methods
|
10
15
|
# person = OpenStruct.new(name: "Alice", age: 30)
|
11
|
-
# person.map { |k, v| "#{k}
|
16
|
+
# person.map { |k, v| "#{k}: #{v}" } # => ["name: Alice", "age: 30"]
|
12
17
|
#
|
13
18
|
class OpenStruct
|
14
19
|
# ActiveSupport integrations
|
@@ -105,4 +110,20 @@ class OpenStruct
|
|
105
110
|
def to_ostruct
|
106
111
|
self
|
107
112
|
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Recursively converts the OpenStruct and all nested objects to hashes
|
116
|
+
#
|
117
|
+
# @return [Hash] A deeply converted hash of the OpenStruct
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# person = OpenStruct.new(
|
121
|
+
# name: "Alice",
|
122
|
+
# address: OpenStruct.new(city: "New York", country: "USA")
|
123
|
+
# )
|
124
|
+
# person.to_deep_h # => {name: "Alice", address: {city: "New York", country: "USA"}}
|
125
|
+
#
|
126
|
+
def to_deep_h
|
127
|
+
to_h.to_deep_h
|
128
|
+
end
|
108
129
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ostruct"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
#
|
7
|
+
# EverythingRB - Super handy extensions to Ruby's core classes
|
8
|
+
#
|
9
|
+
# This gem enhances Ruby's built-in classes with useful methods that make
|
10
|
+
# your code more expressive and fun to write. Just require "everythingrb"
|
11
|
+
# and all the extensions are automatically available!
|
12
|
+
#
|
13
|
+
# @author Bryan "itsthedevman"
|
14
|
+
# @since 0.1.0
|
15
|
+
#
|
16
|
+
# @example Basic usage
|
17
|
+
# # In your Gemfile
|
18
|
+
# gem "everythingrb"
|
19
|
+
#
|
20
|
+
# # In your code
|
21
|
+
# require "everythingrb"
|
22
|
+
#
|
23
|
+
# # Now you have access to all the extensions!
|
24
|
+
# users = [{name: "Alice"}, {name: "Bob"}]
|
25
|
+
# users.key_map(:name).join(", ") # => "Alice, Bob"
|
26
|
+
#
|
27
|
+
module Everythingrb
|
28
|
+
end
|
29
|
+
|
30
|
+
require_relative "version"
|
@@ -3,14 +3,17 @@
|
|
3
3
|
#
|
4
4
|
# Extensions to Ruby's core String class
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Provides:
|
7
|
+
# - #to_h, #to_a: Convert JSON strings to Hash/Array with error handling
|
8
|
+
# - #to_deep_h: Recursively parse nested JSON strings
|
9
|
+
# - #to_ostruct, #to_istruct, #to_struct: Convert JSON to data structures
|
10
|
+
# - #with_quotes, #in_quotes: Wrap strings in quotes
|
8
11
|
#
|
9
|
-
# @example
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# @example
|
13
|
+
# require "everythingrb/string"
|
14
|
+
#
|
15
|
+
# '{"user": {"name": "Alice"}}'.to_ostruct.user.name # => "Alice"
|
16
|
+
# "Hello".with_quotes # => "\"Hello\""
|
14
17
|
#
|
15
18
|
class String
|
16
19
|
#
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Extensions to Ruby's core Struct class
|
5
|
+
#
|
6
|
+
# Provides:
|
7
|
+
# - #to_deep_h: Recursively convert to hash with all nested objects
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# require "everythingrb/struct"
|
11
|
+
#
|
12
|
+
# Person = Struct.new(:name, :profile)
|
13
|
+
# person = Person.new("Alice", {roles: ["admin"]})
|
14
|
+
# person.to_deep_h # => {name: "Alice", profile: {roles: ["admin"]}}
|
15
|
+
#
|
16
|
+
class Struct
|
17
|
+
#
|
18
|
+
# Recursively converts the Struct and all nested objects to hashes
|
19
|
+
#
|
20
|
+
# @return [Hash] A deeply converted hash of the Struct
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# Address = Struct.new(:city, :country)
|
24
|
+
# Person = Struct.new(:name, :address)
|
25
|
+
# person = Person.new("Alice", Address.new("New York", "USA"))
|
26
|
+
# person.to_deep_h # => {name: "Alice", address: {city: "New York", country: "USA"}}
|
27
|
+
#
|
28
|
+
def to_deep_h
|
29
|
+
to_h.to_deep_h
|
30
|
+
end
|
31
|
+
end
|
@@ -3,9 +3,12 @@
|
|
3
3
|
#
|
4
4
|
# Extensions to Ruby's core Symbol class
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# Provides:
|
7
|
+
# - #with_quotes, #in_quotes: Wrap symbols in quotes
|
7
8
|
#
|
8
9
|
# @example
|
10
|
+
# require "everythingrb/symbol"
|
11
|
+
#
|
9
12
|
# :hello_world.with_quotes # => :"\"hello_world\""
|
10
13
|
#
|
11
14
|
class Symbol
|
data/lib/everythingrb/version.rb
CHANGED
data/lib/everythingrb.rb
CHANGED
@@ -1,37 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require_relative "everythingrb/version"
|
7
|
-
require_relative "everythingrb/core/array"
|
8
|
-
require_relative "everythingrb/core/enumerable"
|
9
|
-
require_relative "everythingrb/core/hash"
|
10
|
-
require_relative "everythingrb/core/module"
|
11
|
-
require_relative "everythingrb/core/ostruct"
|
12
|
-
require_relative "everythingrb/core/string"
|
13
|
-
require_relative "everythingrb/core/symbol"
|
14
|
-
|
15
|
-
#
|
16
|
-
# EverythingRB - Super handy extensions to Ruby's core classes
|
17
|
-
#
|
18
|
-
# This gem enhances Ruby's built-in classes with useful methods that make
|
19
|
-
# your code more expressive and fun to write. Just require "everythingrb"
|
20
|
-
# and all the extensions are automatically available!
|
21
|
-
#
|
22
|
-
# @author Bryan "itsthedevman"
|
23
|
-
# @since 0.1.0
|
24
|
-
#
|
25
|
-
# @example Basic usage
|
26
|
-
# # In your Gemfile
|
27
|
-
# gem "everythingrb"
|
28
|
-
#
|
29
|
-
# # In your code
|
30
|
-
# require "everythingrb"
|
31
|
-
#
|
32
|
-
# # Now you have access to all the extensions!
|
33
|
-
# users = [{name: "Alice"}, {name: "Bob"}]
|
34
|
-
# users.key_map(:name).join(", ") # => "Alice, Bob"
|
35
|
-
#
|
36
|
-
module Everythingrb
|
37
|
-
end
|
3
|
+
require_relative "everythingrb/prelude"
|
4
|
+
require_relative "everythingrb/all"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: everythingrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ostruct
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '2.
|
33
|
+
version: '2.10'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '2.
|
40
|
+
version: '2.10'
|
41
41
|
description: EverythingRB extends Ruby core classes with useful methods for combining
|
42
42
|
operations (join_map), converting data structures (to_struct, to_ostruct, to_istruct),
|
43
43
|
and handling JSON with nested parsing support.
|
@@ -57,13 +57,17 @@ files:
|
|
57
57
|
- flake.lock
|
58
58
|
- flake.nix
|
59
59
|
- lib/everythingrb.rb
|
60
|
-
- lib/everythingrb/
|
61
|
-
- lib/everythingrb/
|
62
|
-
- lib/everythingrb/
|
63
|
-
- lib/everythingrb/
|
64
|
-
- lib/everythingrb/
|
65
|
-
- lib/everythingrb/
|
66
|
-
- lib/everythingrb/
|
60
|
+
- lib/everythingrb/all.rb
|
61
|
+
- lib/everythingrb/array.rb
|
62
|
+
- lib/everythingrb/data.rb
|
63
|
+
- lib/everythingrb/enumerable.rb
|
64
|
+
- lib/everythingrb/hash.rb
|
65
|
+
- lib/everythingrb/module.rb
|
66
|
+
- lib/everythingrb/ostruct.rb
|
67
|
+
- lib/everythingrb/prelude.rb
|
68
|
+
- lib/everythingrb/string.rb
|
69
|
+
- lib/everythingrb/struct.rb
|
70
|
+
- lib/everythingrb/symbol.rb
|
67
71
|
- lib/everythingrb/version.rb
|
68
72
|
homepage: https://github.com/itsthedevman/everythingrb
|
69
73
|
licenses:
|