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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecda2000911c11e9c9d062c641b463191810717826f019df27d75c61d41dd0c7
4
- data.tar.gz: 5eb00d7c4cf95854d2d32385a3fe5a9d347d69bf7dbf0eed0e706e57bbff45f1
3
+ metadata.gz: 637e088cea35038c9cea8b54e127e795ddb06c1d7c0011e55accd5930cf2217d
4
+ data.tar.gz: '059758659229885856daaa52dfcfd33e6b4bdad6e29923e71e3dd887f7de390d'
5
5
  SHA512:
6
- metadata.gz: 9892d5e1391446ca9f1a792f4870575e84bfb5c45118b82c636c0c6d6fe7d6f59c22d089811c56ee7fc4056b7728bca2d331e8fd80eabd1ac0c65e388e35055a
7
- data.tar.gz: 631f5da0c0b9dd3afeb4204988bfdf79210975b1e6826bce45a09563473cbe62a41efabe23192edf83678874004f93e9d0b1eecf3cb81cc461d534a0bb753579
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.0...HEAD
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
  [![Gem Version](https://badge.fury.io/rb/everythingrb.svg)](https://badge.fury.io/rb/everythingrb)
4
+ ![Ruby Version](https://img.shields.io/badge/ruby-3.3.7-ruby)
4
5
  [![Tests](https://github.com/itsthedevman/everythingrb/actions/workflows/main.yml/badge.svg)](https://github.com/everythingrb/sortsmith/actions/workflows/main.yml)
5
- ![Ruby Version](https://img.shields.io/badge/ruby-3.3.6-ruby)
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 (requires Ruby 3.2+).
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 (requires Ruby 3.2+).
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
- ## Requirements
314
+ #### `with_quotes` / `in_quotes`
315
+ Wraps the string in double quotes
193
316
 
194
- - Ruby 3.0+
195
- - Ruby 3.2+ for `to_istruct` functionality
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 [Object] Block that filters and transforms array elements
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
- filter_map(&block).join(join_with)
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
- # to_istruct relies on Data class
30
- if defined?(Data)
31
- #
32
- # Converts hash to an immutable Data structure
33
- #
34
- # @return [Data]
35
- #
36
- def to_istruct
37
- recurse = lambda do |input|
38
- case input
39
- when Hash
40
- input.to_istruct
41
- when Array
42
- input.map(&recurse)
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
@@ -72,4 +72,15 @@ class String
72
72
  def to_struct
73
73
  to_h&.to_struct
74
74
  end
75
+
76
+ #
77
+ # Returns self wrapped in double quotes.
78
+ #
79
+ # @return [String]
80
+ #
81
+ def with_quotes
82
+ %("#{self}")
83
+ end
84
+
85
+ alias_method :in_quotes, :with_quotes
75
86
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Everythingrb
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
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.0
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-02-17 00:00:00.000000000 Z
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