everythingrb 0.2.0 → 0.2.2
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 +32 -1
- data/README.md +132 -7
- data/lib/everythingrb/core/array.rb +63 -5
- data/lib/everythingrb/core/enumerable.rb +37 -0
- data/lib/everythingrb/core/hash.rb +30 -19
- data/lib/everythingrb/core/string.rb +11 -0
- data/lib/everythingrb/version.rb +1 -1
- data/lib/everythingrb.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 637e088cea35038c9cea8b54e127e795ddb06c1d7c0011e55accd5930cf2217d
|
4
|
+
data.tar.gz: '059758659229885856daaa52dfcfd33e6b4bdad6e29923e71e3dd887f7de390d'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97b3766b8382f7e160e5996ce03497368770450cc76d91acfa094c80dc9812ae1d27ed66d95988e9918bdd3b6887b84bcc52ed4df70aacac5453872bab0104ca
|
7
|
+
data.tar.gz: f4991d65bf9ef6a3398e0808fa4d794816e4e53874ee712a66f18728ff6cd495d7f2f1f2a86ee40af5a3e5a435b78ff10defca50ea120bd423af30cf5953a90e
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
<!--
|
8
9
|
## [Unreleased]
|
9
10
|
|
10
11
|
### Added
|
@@ -12,6 +13,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
12
13
|
### Changed
|
13
14
|
|
14
15
|
### Removed
|
16
|
+
-->
|
17
|
+
|
18
|
+
## [Unreleased]
|
19
|
+
|
20
|
+
### Added
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
|
24
|
+
### Removed
|
25
|
+
|
26
|
+
## [0.2.2] - 12025-03-03
|
27
|
+
|
28
|
+
### Added
|
29
|
+
|
30
|
+
- Added `Array#key_map` and `Array#dig_map` for mapping over `Hash`
|
31
|
+
- Added `with_index:` keyword argument to `Array#join_map`. Defaults to `false`
|
32
|
+
- Added `Enumerable#join_map`
|
33
|
+
- Added `Array#deep_freeze` and `Hash#deep_freeze` to recursively freeze the underlying values
|
34
|
+
|
35
|
+
## [0.2.1] - 12025-03-01
|
36
|
+
|
37
|
+
### Added
|
38
|
+
|
39
|
+
- Added `with_quotes` / `in_quotes` to `String`
|
40
|
+
|
41
|
+
### Removed
|
42
|
+
|
43
|
+
- Removed `Data` definition check for `to_istruct`
|
15
44
|
|
16
45
|
|
17
46
|
## [0.2.0] - 12025-02-17
|
@@ -68,7 +97,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
68
97
|
|
69
98
|
- Added alias `each` to `each_pair` in OpenStruct for better enumerable compatibility
|
70
99
|
|
71
|
-
[unreleased]: https://github.com/itsthedevman/everythingrb/compare/v0.2.
|
100
|
+
[unreleased]: https://github.com/itsthedevman/everythingrb/compare/v0.2.2...HEAD
|
101
|
+
[0.2.2]: https://github.com/itsthedevman/everythingrb/compare/v0.2.1...v0.2.2
|
102
|
+
[0.2.1]: https://github.com/itsthedevman/everythingrb/compare/v0.2.0...v0.2.1
|
72
103
|
[0.2.0]: https://github.com/itsthedevman/everythingrb/compare/v0.1.2...v0.2.0
|
73
104
|
[0.1.2]: https://github.com/itsthedevman/everythingrb/compare/v0.1.1...v0.1.2
|
74
105
|
[0.1.1]: https://github.com/itsthedevman/everythingrb/compare/v0.1.0...v0.1.1
|
data/README.md
CHANGED
@@ -1,11 +1,61 @@
|
|
1
1
|
# EverythingRB
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/everythingrb)
|
4
|
+

|
4
5
|
[](https://github.com/everythingrb/sortsmith/actions/workflows/main.yml)
|
5
|
-

|
6
6
|
|
7
7
|
Useful extensions to Ruby core classes that you never knew you needed until now.
|
8
8
|
|
9
|
+
## Looking for a Software Engineer?
|
10
|
+
|
11
|
+
I'm currently looking for opportunities where I can tackle meaningful problems and help build reliable software while mentoring the next generation of developers. If you're looking for a senior engineer with full-stack Rails expertise and a passion for clean, maintainable code, let's talk!
|
12
|
+
|
13
|
+
[bryan@itsthedevman.com](mailto:bryan@itsthedevman.com)
|
14
|
+
|
15
|
+
# Table of Contents
|
16
|
+
|
17
|
+
- [Compatibility](#compatibility)
|
18
|
+
- [Installation](#installation)
|
19
|
+
- [Core Extensions](#core-extensions)
|
20
|
+
- [Array](#array)
|
21
|
+
- [join_map](#join_map)
|
22
|
+
- [key_map](#key_map)
|
23
|
+
- [dig_map](#dig_map)
|
24
|
+
- [Enumerable](#enumerable)
|
25
|
+
- [join_map](#join_map-1)
|
26
|
+
- [Hash](#hash)
|
27
|
+
- [to_struct](#to_struct)
|
28
|
+
- [to_ostruct](#to_ostruct)
|
29
|
+
- [to_istruct](#to_istruct)
|
30
|
+
- [join_map](#join_map-2)
|
31
|
+
- [Module](#module)
|
32
|
+
- [attr_predicate](#attr_predicate)
|
33
|
+
- [OpenStruct](#openstruct)
|
34
|
+
- [each](#each)
|
35
|
+
- [map](#map)
|
36
|
+
- [filter_map](#filter_map)
|
37
|
+
- [join_map](#join_map-3)
|
38
|
+
- [String](#string)
|
39
|
+
- [to_h / to_a](#to_h--to_a)
|
40
|
+
- [to_istruct](#to_istruct-1)
|
41
|
+
- [to_ostruct](#to_ostruct-1)
|
42
|
+
- [to_struct](#to_struct-1)
|
43
|
+
- [to_deep_h](#to_deep_h)
|
44
|
+
- [with_quotes / in_quotes](#with_quotes--in_quotes)
|
45
|
+
- [Requirements](#requirements)
|
46
|
+
- [Contributing](#contributing)
|
47
|
+
- [License](#license)
|
48
|
+
- [Changelog](#changelog)
|
49
|
+
- [Credits](#credits)
|
50
|
+
|
51
|
+
Also see: [API Documentation](https://itsthedevman.com/docs/everythingrb)
|
52
|
+
|
53
|
+
## Compatibility
|
54
|
+
|
55
|
+
Currently tested on:
|
56
|
+
- MRI Ruby 3.2+
|
57
|
+
- NixOS (see `flake.nix` for details)
|
58
|
+
|
9
59
|
## Installation
|
10
60
|
|
11
61
|
Add this line to your application's Gemfile:
|
@@ -31,11 +81,74 @@ $ gem install everythingrb
|
|
31
81
|
### Array
|
32
82
|
|
33
83
|
#### `join_map`
|
34
|
-
Combines `filter_map` and `join` operations in one convenient method.
|
84
|
+
Combines `filter_map` and `join` operations in one convenient method. Optionally provides the index to the block.
|
35
85
|
|
36
86
|
```ruby
|
87
|
+
# Without index
|
37
88
|
[1, 2, nil, 3].join_map(" ") { |n| n&.to_s if n&.odd? }
|
38
89
|
# => "1 3"
|
90
|
+
|
91
|
+
# With index
|
92
|
+
["a", "b", "c"].join_map(", ", with_index: true) { |char, i| "#{i}:#{char}" }
|
93
|
+
# => "0:a, 1:b, 2:c"
|
94
|
+
|
95
|
+
# Default behavior without block
|
96
|
+
[1, 2, nil, 3].join_map(", ")
|
97
|
+
# => "1, 2, 3"
|
98
|
+
```
|
99
|
+
|
100
|
+
#### `key_map`
|
101
|
+
Extracts a specific key from each hash in an array.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
users = [
|
105
|
+
{ name: "Alice", age: 30 },
|
106
|
+
{ name: "Bob", age: 25 }
|
107
|
+
]
|
108
|
+
|
109
|
+
users.key_map(:name)
|
110
|
+
# => ["Alice", "Bob"]
|
111
|
+
```
|
112
|
+
|
113
|
+
#### `dig_map`
|
114
|
+
Extracts nested values from each hash in an array using the `dig` method.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
data = [
|
118
|
+
{ user: { profile: { name: "Alice" } } },
|
119
|
+
{ user: { profile: { name: "Bob" } } }
|
120
|
+
]
|
121
|
+
|
122
|
+
data.dig_map(:user, :profile, :name)
|
123
|
+
# => ["Alice", "Bob"]
|
124
|
+
```
|
125
|
+
|
126
|
+
#### `deep_freeze`
|
127
|
+
Recursively freezes an array and all of its nested elements.
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
array = ["hello", { name: "Alice" }, [1, 2, 3]]
|
131
|
+
array.deep_freeze
|
132
|
+
# => All elements and nested structures are now frozen
|
133
|
+
```
|
134
|
+
|
135
|
+
### Enumerable
|
136
|
+
|
137
|
+
#### `join_map`
|
138
|
+
Combines filtering, mapping and joining operations into one convenient method.
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
# Basic usage with arrays
|
142
|
+
[1, 2, nil, 3].join_map(", ") { |n| n&.to_s if n&.odd? }
|
143
|
+
# => "1, 3"
|
144
|
+
|
145
|
+
# Works with any Enumerable
|
146
|
+
(1..10).join_map(" | ") { |n| "num#{n}" if n.even? }
|
147
|
+
# => "num2 | num4 | num6 | num8 | num10"
|
148
|
+
|
149
|
+
# Supports with_index option
|
150
|
+
%w[a b c].join_map("-", with_index: true) { |char, i| "#{i}:#{char}" }
|
151
|
+
# => "0:a-1:b-2:c"
|
39
152
|
```
|
40
153
|
|
41
154
|
### Hash
|
@@ -62,7 +175,7 @@ config.config.api_key # => "secret"
|
|
62
175
|
```
|
63
176
|
|
64
177
|
#### `to_istruct`
|
65
|
-
Recursively converts a hash into an immutable Data structure
|
178
|
+
Recursively converts a hash into an immutable Data structure.
|
66
179
|
|
67
180
|
```ruby
|
68
181
|
hash = { person: { name: "Bob", age: 30 } }
|
@@ -79,6 +192,15 @@ Similar to Array#join_map but operates on hash values.
|
|
79
192
|
# => "a 1 b 2 d 3"
|
80
193
|
```
|
81
194
|
|
195
|
+
#### `deep_freeze`
|
196
|
+
Recursively freezes a hash and all of its nested values.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
hash = { user: { name: "Alice", roles: ["admin", "user"] } }
|
200
|
+
hash.deep_freeze
|
201
|
+
# => Hash and all nested structures are now frozen
|
202
|
+
```
|
203
|
+
|
82
204
|
### Module
|
83
205
|
|
84
206
|
#### `attr_predicate`
|
@@ -152,7 +274,7 @@ Parses JSON string into a Ruby Hash or Array.
|
|
152
274
|
```
|
153
275
|
|
154
276
|
#### `to_istruct`
|
155
|
-
Parses JSON string into an immutable Data structure
|
277
|
+
Parses JSON string into an immutable Data structure.
|
156
278
|
|
157
279
|
```ruby
|
158
280
|
'{"user": {"name": "Alice"}}'.to_istruct
|
@@ -189,10 +311,13 @@ nested_json.to_deep_h
|
|
189
311
|
# => {users: [{name: "Alice", roles: ["admin", "user"]}]}
|
190
312
|
```
|
191
313
|
|
192
|
-
|
314
|
+
#### `with_quotes` / `in_quotes`
|
315
|
+
Wraps the string in double quotes
|
193
316
|
|
194
|
-
|
195
|
-
|
317
|
+
```ruby
|
318
|
+
"Hello World".with_quotes
|
319
|
+
# => "\"Hello World\""
|
320
|
+
```
|
196
321
|
|
197
322
|
## Contributing
|
198
323
|
|
@@ -5,22 +5,80 @@ class Array
|
|
5
5
|
# Combines filter_map and join operations
|
6
6
|
#
|
7
7
|
# @param join_with [String] The delimiter to join elements with (defaults to empty string)
|
8
|
+
# @param with_index [Boolean] Whether to include the index in the block (defaults to false)
|
8
9
|
#
|
9
|
-
# @yield [
|
10
|
+
# @yield [element, index] Block that filters and transforms array elements
|
11
|
+
# @yieldparam element [Object] The current element
|
12
|
+
# @yieldparam index [Integer] The index of the current element (only if with_index: true)
|
10
13
|
#
|
11
14
|
# @return [String] Joined string of filtered and transformed elements
|
12
15
|
#
|
13
|
-
# @example
|
16
|
+
# @example Without index
|
14
17
|
# [1, 2, nil, 3].join_map(" ") { |n| n&.to_s if n&.odd? }
|
15
18
|
# # => "1 3"
|
16
19
|
#
|
17
|
-
# @example
|
20
|
+
# @example With index
|
21
|
+
# ["a", "b", "c"].join_map(", ", with_index: true) { |char, i| "#{i}:#{char}" }
|
22
|
+
# # => "0:a, 1:b, 2:c"
|
23
|
+
#
|
24
|
+
# @example Default behavior without block
|
18
25
|
# [1, 2, nil, 3].join_map(", ")
|
19
26
|
# # => "1, 2, 3"
|
20
27
|
#
|
21
|
-
def join_map(join_with = "", &block)
|
28
|
+
def join_map(join_with = "", with_index: false, &block)
|
22
29
|
block = ->(i) { i } if block.nil?
|
23
30
|
|
24
|
-
|
31
|
+
if with_index
|
32
|
+
filter_map.with_index(&block).join(join_with)
|
33
|
+
else
|
34
|
+
filter_map(&block).join(join_with)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Maps over hash keys to extract values for a specific key
|
40
|
+
#
|
41
|
+
# @param key [Symbol, String] The key to extract
|
42
|
+
#
|
43
|
+
# @return [Array] Array of values
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}].key_map(:name)
|
47
|
+
# # => ['Alice', 'Bob']
|
48
|
+
#
|
49
|
+
def key_map(key)
|
50
|
+
map { |v| v[key] }
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Maps over hash keys to extract nested values using dig
|
55
|
+
#
|
56
|
+
# @param keys [Array<Symbol, String>] The keys to dig through
|
57
|
+
#
|
58
|
+
# @return [Array] Array of nested values
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# [
|
62
|
+
# {user: {profile: {name: 'Alice'}}},
|
63
|
+
# {user: {profile: {name: 'Bob'}}}
|
64
|
+
# ].dig_map(:user, :profile, :name)
|
65
|
+
# # => ['Alice', 'Bob']
|
66
|
+
#
|
67
|
+
def dig_map(*keys)
|
68
|
+
map { |v| v.dig(*keys) }
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Recursively freezes self and all of its contents
|
73
|
+
#
|
74
|
+
# @return [self] Returns the frozen array
|
75
|
+
#
|
76
|
+
# @example Freeze an array with nested structures
|
77
|
+
# ["hello", { name: "Alice" }, [1, 2, 3]].deep_freeze
|
78
|
+
# # => All elements and nested structures are now frozen
|
79
|
+
#
|
80
|
+
def deep_freeze
|
81
|
+
each { |v| v.respond_to?(:deep_freeze) ? v.deep_freeze : v.freeze }
|
82
|
+
freeze
|
25
83
|
end
|
26
84
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Enumerable
|
4
|
+
#
|
5
|
+
# Combines filter_map and join operations
|
6
|
+
#
|
7
|
+
# @param join_with [String] The delimiter to join elements with (defaults to empty string)
|
8
|
+
# @param with_index [Boolean] Whether to include the index in the block (defaults to false)
|
9
|
+
#
|
10
|
+
# @yield [element, index] Block that filters and transforms array elements
|
11
|
+
# @yieldparam element [Object] The current element
|
12
|
+
# @yieldparam index [Integer] The index of the current element (only if with_index: true)
|
13
|
+
#
|
14
|
+
# @return [String] Joined string of filtered and transformed elements
|
15
|
+
#
|
16
|
+
# @example Without index
|
17
|
+
# [1, 2, nil, 3].join_map(" ") { |n| n&.to_s if n&.odd? }
|
18
|
+
# # => "1 3"
|
19
|
+
#
|
20
|
+
# @example With index
|
21
|
+
# ["a", "b", "c"].join_map(", ", with_index: true) { |char, i| "#{i}:#{char}" }
|
22
|
+
# # => "0:a, 1:b, 2:c"
|
23
|
+
#
|
24
|
+
# @example Default behavior without block
|
25
|
+
# [1, 2, nil, 3].join_map(", ")
|
26
|
+
# # => "1, 2, 3"
|
27
|
+
#
|
28
|
+
def join_map(join_with = "", with_index: false, &block)
|
29
|
+
block = ->(i) { i } if block.nil?
|
30
|
+
|
31
|
+
if with_index
|
32
|
+
filter_map.with_index(&block).join(join_with)
|
33
|
+
else
|
34
|
+
filter_map(&block).join(join_with)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -26,27 +26,24 @@ class Hash
|
|
26
26
|
filter_map(&block).join(join_with)
|
27
27
|
end
|
28
28
|
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
else
|
44
|
-
input
|
45
|
-
end
|
29
|
+
#
|
30
|
+
# Converts hash to an immutable Data structure
|
31
|
+
#
|
32
|
+
# @return [Data]
|
33
|
+
#
|
34
|
+
def to_istruct
|
35
|
+
recurse = lambda do |input|
|
36
|
+
case input
|
37
|
+
when Hash
|
38
|
+
input.to_istruct
|
39
|
+
when Array
|
40
|
+
input.map(&recurse)
|
41
|
+
else
|
42
|
+
input
|
46
43
|
end
|
47
|
-
|
48
|
-
Data.define(*keys.map(&:to_sym)).new(*values.map { |value| recurse.call(value) })
|
49
44
|
end
|
45
|
+
|
46
|
+
Data.define(*keys.map(&:to_sym)).new(*values.map { |value| recurse.call(value) })
|
50
47
|
end
|
51
48
|
|
52
49
|
#
|
@@ -88,4 +85,18 @@ class Hash
|
|
88
85
|
|
89
86
|
OpenStruct.new(**transform_values { |value| recurse.call(value) })
|
90
87
|
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Recursively freezes self and all of its values
|
91
|
+
#
|
92
|
+
# @return [self] Returns the frozen hash
|
93
|
+
#
|
94
|
+
# @example Freeze a hash with nested structures
|
95
|
+
# { user: { name: "Alice", roles: ["admin"] } }.deep_freeze
|
96
|
+
# # => Hash and all nested structures are now frozen
|
97
|
+
#
|
98
|
+
def deep_freeze
|
99
|
+
each_value { |v| v.respond_to?(:deep_freeze) ? v.deep_freeze : v.freeze }
|
100
|
+
freeze
|
101
|
+
end
|
91
102
|
end
|
data/lib/everythingrb/version.rb
CHANGED
data/lib/everythingrb.rb
CHANGED
@@ -5,6 +5,7 @@ require "json"
|
|
5
5
|
|
6
6
|
require_relative "everythingrb/version"
|
7
7
|
require_relative "everythingrb/core/array"
|
8
|
+
require_relative "everythingrb/core/enumerable"
|
8
9
|
require_relative "everythingrb/core/hash"
|
9
10
|
require_relative "everythingrb/core/module"
|
10
11
|
require_relative "everythingrb/core/ostruct"
|
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.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ostruct
|
@@ -58,6 +58,7 @@ files:
|
|
58
58
|
- flake.nix
|
59
59
|
- lib/everythingrb.rb
|
60
60
|
- lib/everythingrb/core/array.rb
|
61
|
+
- lib/everythingrb/core/enumerable.rb
|
61
62
|
- lib/everythingrb/core/hash.rb
|
62
63
|
- lib/everythingrb/core/module.rb
|
63
64
|
- lib/everythingrb/core/ostruct.rb
|