everythingrb 0.2.3 → 0.2.4

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: 8567a1a0f80fd1582946019cd0c378f916648f70d9a9087944f83f5ba29669be
4
- data.tar.gz: 8f42ce110e7c57529f591615d7612d75556497fc3e80fe56f0ece352847df709
3
+ metadata.gz: a31c21db03be7c59f60dacc8136cea0d28e0298f4b53cb7a89c0934d1d7617f0
4
+ data.tar.gz: 3ba88a496f226383284c234892c49fc976e7bc695489e1bef0ff3512bb7b2c16
5
5
  SHA512:
6
- metadata.gz: 065ef8975736ca530d915f4d7780b1a35a6e85834f735aadbc244f5c05bd39845be26bd07102e52e649e9946769b255fb50d951ea4b335204d55c75eae213828
7
- data.tar.gz: 6edcdc737cd2dda4395d5b685c463c3af0d2fedab7d1737193105a43ce4365e0b63bdbeb7bac336868b0dea1e9857d9e0d33b55ba0f693ab818f607611ca864d
6
+ metadata.gz: fa926d8fb5e356bb3ea0c6bf87ad2bbe847897a042075166a78d0dea39e27015cf35d49570a7db79fe489be2bb0dd324c5383412f5b1d60d06e1e60722c5e969
7
+ data.tar.gz: 04cea9d92d4f851c2eb3d0a928319c583cc55c2c5376177371c5da0d70ab41d5dbd9c8a7dc70e2c113f20e41ae216c46bcd74d5e6b56a51913d5aa1842177ee6
data/CHANGELOG.md CHANGED
@@ -23,6 +23,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
23
23
 
24
24
  ### Removed
25
25
 
26
+ ## [0.2.4] - 12025-03-20
27
+
28
+ ### Changed
29
+
30
+ - Improved documentation
31
+ - Fixed an issue with `Hash#to_struct` on Ruby 3.2 would raise an exception if called on an empty Hash
32
+
26
33
  ## [0.2.3] - 12025-03-09
27
34
 
28
35
  ### Added
@@ -104,7 +111,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
104
111
 
105
112
  - Added alias `each` to `each_pair` in OpenStruct for better enumerable compatibility
106
113
 
107
- [unreleased]: https://github.com/itsthedevman/everythingrb/compare/v0.2.3...HEAD
114
+ [unreleased]: https://github.com/itsthedevman/everythingrb/compare/v0.2.4...HEAD
115
+ [0.2.3]: https://github.com/itsthedevman/everythingrb/compare/v0.2.3...v0.2.4
108
116
  [0.2.3]: https://github.com/itsthedevman/everythingrb/compare/v0.2.2...v0.2.3
109
117
  [0.2.2]: https://github.com/itsthedevman/everythingrb/compare/v0.2.1...v0.2.2
110
118
  [0.2.1]: https://github.com/itsthedevman/everythingrb/compare/v0.2.0...v0.2.1
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  ![Ruby Version](https://img.shields.io/badge/ruby-3.3.7-ruby)
5
5
  [![Tests](https://github.com/itsthedevman/everythingrb/actions/workflows/main.yml/badge.svg)](https://github.com/everythingrb/sortsmith/actions/workflows/main.yml)
6
6
 
7
- Useful extensions to Ruby core classes that you never knew you needed until now.
7
+ Super handy extensions to Ruby core classes that you never knew you needed until now. Write more expressive, readable, and maintainable code with less boilerplate.
8
8
 
9
9
  ## Looking for a Software Engineer?
10
10
 
@@ -14,36 +14,24 @@ I'm currently looking for opportunities where I can tackle meaningful problems a
14
14
 
15
15
  # Table of Contents
16
16
 
17
+ - [Introduction](#introduction)
17
18
  - [Compatibility](#compatibility)
18
19
  - [Installation](#installation)
20
+ - [Features](#features)
21
+ - [Data Structure Conversions](#data-structure-conversions)
22
+ - [Collection Processing](#collection-processing)
23
+ - [JSON & String Handling](#json--string-handling)
24
+ - [Object Freezing](#object-freezing)
25
+ - [Predicate Methods](#predicate-methods)
19
26
  - [Core Extensions](#core-extensions)
20
27
  - [Array](#array)
21
- - [join_map](#join_map)
22
- - [key_map](#key_map)
23
- - [dig_map](#dig_map)
24
28
  - [Enumerable](#enumerable)
25
- - [join_map](#join_map-1)
26
29
  - [Hash](#hash)
27
- - [to_struct](#to_struct)
28
- - [to_ostruct](#to_ostruct)
29
- - [to_istruct](#to_istruct)
30
- - [join_map](#join_map-2)
31
30
  - [Module](#module)
32
- - [attr_predicate](#attr_predicate)
33
31
  - [OpenStruct](#openstruct)
34
- - [each](#each)
35
- - [map](#map)
36
- - [filter_map](#filter_map)
37
- - [join_map](#join_map-3)
38
32
  - [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
33
  - [Symbol](#symbol)
46
- - [with_quotes / in_quotes](#with_quotes--in_quotes-1)
34
+ - [Advanced Usage](#advanced-usage)
47
35
  - [Requirements](#requirements)
48
36
  - [Contributing](#contributing)
49
37
  - [License](#license)
@@ -52,6 +40,12 @@ I'm currently looking for opportunities where I can tackle meaningful problems a
52
40
 
53
41
  Also see: [API Documentation](https://itsthedevman.com/docs/everythingrb)
54
42
 
43
+ ## Introduction
44
+
45
+ EverythingRB adds powerful, intuitive extensions to Ruby's core classes that help you write cleaner, more expressive code. It focuses on common patterns that typically require multiple method calls or temporary variables, turning them into single fluid operations.
46
+
47
+ Whether you're transforming data, working with JSON, or building complex object structures, EverythingRB makes your code more readable and maintainable with minimal effort.
48
+
55
49
  ## Compatibility
56
50
 
57
51
  Currently tested on:
@@ -78,6 +72,115 @@ Or install it yourself as:
78
72
  $ gem install everythingrb
79
73
  ```
80
74
 
75
+ ## Features
76
+
77
+ ### Data Structure Conversions
78
+
79
+ Easily convert between different Ruby data structures:
80
+
81
+ ```ruby
82
+ # Convert any hash to an OpenStruct, Struct, or Data (immutable) object
83
+ config = { server: { host: "example.com", port: 443 } }.to_ostruct
84
+ config.server.host # => "example.com"
85
+
86
+ # Parse JSON directly to your preferred structure
87
+ '{"user":{"name":"Alice"}}'.to_istruct.user.name # => "Alice"
88
+ '{"items":[1,2,3]}'.to_struct.items # => [1, 2, 3]
89
+ ```
90
+
91
+ ### Collection Processing
92
+
93
+ Process collections with elegant, chainable methods:
94
+
95
+ ```ruby
96
+ # Extract specific data from arrays of hashes in one step
97
+ users = [{ name: "Alice", roles: ["admin"] }, { name: "Bob", roles: ["user"] }]
98
+ users.key_map(:name) # => ["Alice", "Bob"]
99
+ users.dig_map(:roles, 0) # => ["admin", "user"]
100
+
101
+ # Filter, map, and join in a single operation
102
+ [1, 2, nil, 3, 4].join_map(" | ") { |n| "Item #{n}" if n&.odd? }
103
+ # => "Item 1 | Item 3"
104
+ ```
105
+
106
+ ### JSON & String Handling
107
+
108
+ Work with JSON and strings more naturally:
109
+
110
+ ```ruby
111
+ # Parse JSON with symbolized keys
112
+ '{"name": "Alice"}'.to_h # => { name: "Alice" }
113
+
114
+ # Recursively parse nested JSON strings
115
+ nested = '{"user":"{\"profile\":\"{\\\"name\\\":\\\"Bob\\\"}\"}"}'
116
+ nested.to_deep_h # => { user: { profile: { name: "Bob" } } }
117
+
118
+ # Format strings with quotes
119
+ "hello".with_quotes # => "\"hello\""
120
+ ```
121
+
122
+ ### Object Freezing
123
+
124
+ Freeze nested structures with a single call:
125
+
126
+ ```ruby
127
+ config = {
128
+ api: {
129
+ key: "secret",
130
+ endpoints: ["v1", "v2"]
131
+ }
132
+ }.deep_freeze
133
+
134
+ # Everything is frozen!
135
+ config.frozen? # => true
136
+ config[:api].frozen? # => true
137
+ config[:api][:endpoints].frozen? # => true
138
+ config[:api][:endpoints][0].frozen? # => true
139
+ ```
140
+
141
+ ### Predicate Methods
142
+
143
+ Create boolean accessors with minimal code:
144
+
145
+ ```ruby
146
+ class User
147
+ attr_accessor :admin, :verified
148
+ attr_predicate :admin, :verified
149
+ end
150
+
151
+ user = User.new
152
+ user.admin = true
153
+ user.admin? # => true
154
+ user.verified? # => false
155
+
156
+ # Works with Struct and Data objects too
157
+ Person = Struct.new(:active)
158
+ Person.attr_predicate(:active)
159
+
160
+ person = Person.new(true)
161
+ person.active? # => true
162
+ ```
163
+
164
+ **ActiveSupport Integration:** When ActiveSupport is loaded, predicate methods automatically use `present?` instead of just checking truthiness:
165
+
166
+ ```ruby
167
+ # With ActiveSupport loaded
168
+ class Product
169
+ attr_accessor :tags, :category
170
+ attr_predicate :tags, :category
171
+ end
172
+
173
+ product = Product.new
174
+ product.tags = []
175
+ product.tags? # => false (empty array is not "present")
176
+
177
+ product.tags = ["sale"]
178
+ product.tags? # => true (non-empty array is "present")
179
+
180
+ product.category = ""
181
+ product.category? # => false (blank string is not "present")
182
+ ```
183
+
81
184
  ## Core Extensions
82
185
 
83
186
  ### Array
@@ -331,6 +434,89 @@ Wraps the symbol in double quotes
331
434
  # => :"\"hello_world\""
332
435
  ```
333
436
 
437
+ ## Advanced Usage
438
+
439
+ See how EverythingRB transforms your code from verbose to elegant:
440
+
441
+ ### Extracting Data from Nested JSON
442
+
443
+ **Before:**
444
+ ```ruby
445
+ # Standard Ruby approach
446
+ json_data = '[{"user":{"name":"Alice","role":"admin"}},{"user":{"name":"Bob","role":"guest"}}]'
447
+
448
+ parsed_data = JSON.parse(json_data, symbolize_names: true)
449
+ names = parsed_data.map { |item| item[:user][:name] }
450
+ result = names.join(", ")
451
+ # => "Alice, Bob"
452
+ ```
453
+
454
+ **After:**
455
+ ```ruby
456
+ # With EverythingRB
457
+ json_data = '[{"user":{"name":"Alice","role":"admin"}},{"user":{"name":"Bob","role":"guest"}}]'
458
+ result = json_data.to_a.dig_map(:user, :name).join(", ")
459
+ # => "Alice, Bob"
460
+ ```
461
+
462
+ ### Freezing Nested Configurations
463
+
464
+ **Before:**
465
+ ```ruby
466
+ # Standard Ruby approach
467
+ config_json = File.read("config.json")
468
+ config = JSON.parse(config_json, symbolize_names: true)
469
+
470
+ deep_freeze = lambda do |obj|
471
+ case obj
472
+ when Hash
473
+ obj.each_value { |v| deep_freeze.call(v) }
474
+ obj.freeze
475
+ when Array
476
+ obj.each { |v| deep_freeze.call(v) }
477
+ obj.freeze
478
+ else
479
+ obj.freeze
480
+ end
481
+ end
482
+
483
+ frozen_config = deep_freeze.call(config)
484
+ ```
485
+
486
+ **After:**
487
+ ```ruby
488
+ # With EverythingRB
489
+ config_json = File.read("config.json")
490
+ frozen_config = config_json.to_h.deep_freeze
491
+ ```
492
+
493
+ ### Filtering and Formatting Nested Collections
494
+
495
+ **Before:**
496
+ ```ruby
497
+ # Standard Ruby approach
498
+ users_json = '[{"user":{"name":"Alice","admin":true,"active":true}},{"user":{"name":"Bob","admin":true,"active":false}}]'
499
+
500
+ users = JSON.parse(users_json, symbolize_names: true)
501
+ active_admins = users.map { |u| u[:user] }.select { |u| u[:admin] && u[:active] }
502
+ admin_names = active_admins.map { |u| u[:name] }.join(", ")
503
+ # => "Alice"
504
+ ```
505
+
506
+ **After:**
507
+ ```ruby
508
+ # With EverythingRB
509
+ users_json = '[{"user":{"name":"Alice","admin":true,"active":true}},{"user":{"name":"Bob","admin":true,"active":false}}]'
510
+ admin_names = users_json.to_a.key_map(:user).join_map(", ") do |user|
511
+ user[:name] if user[:admin] && user[:active]
512
+ end
513
+ # => "Alice"
514
+ ```
515
+
516
+ ## Requirements
517
+
518
+ - Ruby 3.2 or higher
519
+
334
520
  ## Contributing
335
521
 
336
522
  1. Fork it
data/flake.lock CHANGED
@@ -20,11 +20,11 @@
20
20
  },
21
21
  "nixpkgs": {
22
22
  "locked": {
23
- "lastModified": 1736883708,
24
- "narHash": "sha256-uQ+NQ0/xYU0N1CnXsa2zghgNaOPxWpMJXSUJJ9W7140=",
23
+ "lastModified": 1742422364,
24
+ "narHash": "sha256-mNqIplmEohk5jRkqYqG19GA8MbQ/D4gQSK0Mu4LvfRQ=",
25
25
  "owner": "NixOS",
26
26
  "repo": "nixpkgs",
27
- "rev": "eb62e6aa39ea67e0b8018ba8ea077efe65807dc8",
27
+ "rev": "a84ebe20c6bc2ecbcfb000a50776219f48d134cc",
28
28
  "type": "github"
29
29
  },
30
30
  "original": {
data/flake.nix CHANGED
@@ -6,8 +6,14 @@
6
6
  flake-utils.url = "github:numtide/flake-utils";
7
7
  };
8
8
 
9
- outputs = { self, nixpkgs, flake-utils }:
10
- flake-utils.lib.eachDefaultSystem (system:
9
+ outputs =
10
+ {
11
+ self,
12
+ nixpkgs,
13
+ flake-utils,
14
+ }:
15
+ flake-utils.lib.eachDefaultSystem (
16
+ system:
11
17
  let
12
18
  pkgs = nixpkgs.legacyPackages.${system};
13
19
  in
@@ -1,5 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # Extensions to Ruby's core Array class
5
+ #
6
+ # This module adds convenient mapping, joining, and freezing functionality
7
+ # to all Arrays in your application.
8
+ #
9
+ # @example Using the extensions
10
+ # numbers = [1, 2, nil, 3]
11
+ #
12
+ # # Filter out nils and format odd numbers
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"]
18
+ #
3
19
  class Array
4
20
  #
5
21
  # Combines filter_map and join operations
@@ -40,11 +56,11 @@ class Array
40
56
  #
41
57
  # @param key [Symbol, String] The key to extract
42
58
  #
43
- # @return [Array] Array of values
59
+ # @return [Array] Array of values extracted from each hash
44
60
  #
45
61
  # @example
46
- # [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}].key_map(:name)
47
- # # => ['Alice', 'Bob']
62
+ # [{name: "Alice", age: 30}, {name: "Bob", age: 25}].key_map(:name)
63
+ # # => ["Alice", "Bob"]
48
64
  #
49
65
  def key_map(key)
50
66
  map { |v| v[key] }
@@ -59,10 +75,10 @@ class Array
59
75
  #
60
76
  # @example
61
77
  # [
62
- # {user: {profile: {name: 'Alice'}}},
63
- # {user: {profile: {name: 'Bob'}}}
78
+ # {user: {profile: {name: "Alice"}}},
79
+ # {user: {profile: {name: "Bob"}}}
64
80
  # ].dig_map(:user, :profile, :name)
65
- # # => ['Alice', 'Bob']
81
+ # # => ["Alice", "Bob"]
66
82
  #
67
83
  def dig_map(*keys)
68
84
  map { |v| v.dig(*keys) }
@@ -1,5 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # Extensions to Ruby's core Enumerable module
5
+ #
6
+ # These additions make working with any enumerable collection more expressive
7
+ # by combining common operations into convenient methods.
8
+ #
9
+ # @example Using join_map with a Range
10
+ # (1..5).join_map(" | ") { |n| "item-#{n}" if n.even? }
11
+ # # => "item-2 | item-4"
12
+ #
3
13
  module Enumerable
4
14
  #
5
15
  # Combines filter_map and join operations
@@ -7,7 +17,7 @@ module Enumerable
7
17
  # @param join_with [String] The delimiter to join elements with (defaults to empty string)
8
18
  # @param with_index [Boolean] Whether to include the index in the block (defaults to false)
9
19
  #
10
- # @yield [element, index] Block that filters and transforms array elements
20
+ # @yield [element, index] Block that filters and transforms elements
11
21
  # @yieldparam element [Object] The current element
12
22
  # @yieldparam index [Integer] The index of the current element (only if with_index: true)
13
23
  #
@@ -21,9 +31,9 @@ module Enumerable
21
31
  # ["a", "b", "c"].join_map(", ", with_index: true) { |char, i| "#{i}:#{char}" }
22
32
  # # => "0:a, 1:b, 2:c"
23
33
  #
24
- # @example Default behavior without block
25
- # [1, 2, nil, 3].join_map(", ")
26
- # # => "1, 2, 3"
34
+ # @example Using with other enumerables
35
+ # (1..10).join_map(" | ") { |n| "num#{n}" if n.even? }
36
+ # # => "num2 | num4 | num6 | num8 | num10"
27
37
  #
28
38
  def join_map(join_with = "", with_index: false, &block)
29
39
  block = ->(i) { i } if block.nil?
@@ -1,24 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # Extensions to Ruby's core Hash class
5
+ #
6
+ # These additions make working with hashes more convenient by adding
7
+ # conversion methods to different data structures and string formatting helpers.
8
+ #
9
+ # @example Converting to different structures
10
+ # user = { name: "Alice", roles: ["admin"] }
11
+ # user.to_struct # => #<struct name="Alice", roles=["admin"]>
12
+ # user.to_ostruct # => #<OpenStruct name="Alice", roles=["admin"]>
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"
17
+ #
3
18
  class Hash
4
19
  #
5
- # Combines filter_map and join operations
20
+ # A minimal empty struct for Ruby 3.2+ compatibility
21
+ #
22
+ # Ruby 3.2 enforces stricter argument handling for Struct. This means trying to create
23
+ # a Struct from an empty Hash will result in an ArgumentError being raised.
24
+ # This is trying to keep a consistent experience with that version and newer versions.
25
+ #
26
+ # @return [Struct] A struct with a single nil-valued field
27
+ #
28
+ # @api private
6
29
  #
7
- # @see Array#join_map
30
+ EMPTY_STRUCT = Struct.new(:_).new(nil)
31
+
32
+ #
33
+ # Combines filter_map and join operations
8
34
  #
9
35
  # @param join_with [String] The delimiter to join elements with (defaults to empty string)
10
36
  #
11
- # @yield [Object] Block that filters and transforms hash values
37
+ # @yield [key, value] Block that filters and transforms hash entries
38
+ # @yieldparam key [Object] The current key
39
+ # @yieldparam value [Object] The current value
12
40
  #
13
- # @return [String] Joined string of filtered and transformed values
41
+ # @return [String] Joined string of filtered and transformed entries
14
42
  #
15
43
  # @example
16
- # { a: 1, b: 2, c: nil, d: 3 }.join_map(" ") { |v| v&.to_s if v&.odd? }
17
- # # => "1 3"
44
+ # { a: 1, b: nil, c: 2, d: nil, e: 3 }.join_map(", ") { |k, v| "#{k}-#{v}" if v }
45
+ # # => "a-1, c-2, e-3"
18
46
  #
19
- # @example
20
- # { a: 1, b: 2, c: nil, d: 3 }.join_map(", ")
21
- # # => "a, 2, b, 2, c, d, 3"
47
+ # @example Without a block
48
+ # { a: 1, b: nil, c: 2 }.join_map(" ")
49
+ # # => "a 1 b c 2"
22
50
  #
23
51
  def join_map(join_with = "", &block)
24
52
  block = ->(kv_pair) { kv_pair.compact } if block.nil?
@@ -29,7 +57,13 @@ class Hash
29
57
  #
30
58
  # Converts hash to an immutable Data structure
31
59
  #
32
- # @return [Data]
60
+ # @return [Data] An immutable Data object with the same structure
61
+ #
62
+ # @example
63
+ # hash = { person: { name: "Bob", age: 30 } }
64
+ # data = hash.to_istruct
65
+ # data.person.name # => "Bob"
66
+ # data.class # => Data
33
67
  #
34
68
  def to_istruct
35
69
  recurse = lambda do |input|
@@ -49,9 +83,18 @@ class Hash
49
83
  #
50
84
  # Converts hash to a Struct recursively
51
85
  #
52
- # @return [Struct]
86
+ # @return [Struct] A struct with methods matching hash keys
87
+ #
88
+ # @example
89
+ # hash = { user: { name: "Alice", roles: ["admin"] } }
90
+ # struct = hash.to_struct
91
+ # struct.user.name # => "Alice"
92
+ # struct.class # => Struct
53
93
  #
54
94
  def to_struct
95
+ # For Ruby 3.2, it raises if you attempt to create a Struct with no keys
96
+ return EMPTY_STRUCT if RUBY_VERSION.start_with?("3.2") && empty?
97
+
55
98
  recurse = lambda do |value|
56
99
  case value
57
100
  when Hash
@@ -69,7 +112,12 @@ class Hash
69
112
  #
70
113
  # Converts hash to an OpenStruct recursively
71
114
  #
72
- # @return [OpenStruct]
115
+ # @return [OpenStruct] An OpenStruct with methods matching hash keys
116
+ #
117
+ # @example
118
+ # hash = { config: { api_key: "secret" } }
119
+ # config = hash.to_ostruct
120
+ # config.config.api_key # => "secret"
73
121
  #
74
122
  def to_ostruct
75
123
  recurse = lambda do |value|
@@ -91,7 +139,7 @@ class Hash
91
139
  #
92
140
  # @return [self] Returns the frozen hash
93
141
  #
94
- # @example Freeze a hash with nested structures
142
+ # @example
95
143
  # { user: { name: "Alice", roles: ["admin"] } }.deep_freeze
96
144
  # # => Hash and all nested structures are now frozen
97
145
  #
@@ -1,5 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # Extensions to Ruby's core Module class
5
+ #
6
+ # These additions provide a convenient way to create boolean-style accessor
7
+ # methods for any class.
8
+ #
9
+ # @example Creating predicate methods
10
+ # class User
11
+ # attr_accessor :admin
12
+ # attr_predicate :admin
13
+ # end
14
+ #
15
+ # user = User.new
16
+ # user.admin = true
17
+ # user.admin? # => true
18
+ #
3
19
  class Module
4
20
  #
5
21
  # Creates predicate (boolean) methods that return true/false
@@ -8,7 +24,7 @@ class Module
8
24
  #
9
25
  # Note: If ActiveSupport is loaded, this will check if the value is present? instead of truthy
10
26
  #
11
- # @param *attributes [Array<Symbol, String>] Attribute names
27
+ # @param attributes [Array<Symbol, String>] Attribute names
12
28
  #
13
29
  # @return [nil]
14
30
  #
@@ -1,11 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # Extensions to Ruby's OpenStruct class
5
+ #
6
+ # These additions make OpenStructs way more flexible with enumeration
7
+ # methods and ActiveSupport integration.
8
+ #
9
+ # @example Using enumeration methods
10
+ # person = OpenStruct.new(name: "Alice", age: 30)
11
+ # person.map { |k, v| "#{k} is #{v}" } # => ["name is Alice", "age is 30"]
12
+ #
3
13
  class OpenStruct
14
+ # ActiveSupport integrations
4
15
  if defined?(ActiveSupport)
5
16
  #
6
17
  # Checks if the OpenStruct has no attributes
7
18
  #
8
- # @return [Boolean]
19
+ # @return [Boolean] true if the OpenStruct has no attributes
9
20
  #
10
21
  def blank?
11
22
  @table.blank?
@@ -14,7 +25,7 @@ class OpenStruct
14
25
  #
15
26
  # Checks if the OpenStruct has any attributes
16
27
  #
17
- # @return [Boolean]
28
+ # @return [Boolean] true if the OpenStruct has attributes
18
29
  #
19
30
  def present?
20
31
  @table.present?
@@ -26,7 +37,15 @@ class OpenStruct
26
37
  #
27
38
  # Maps over OpenStruct entries and returns an array
28
39
  #
29
- # @return [Enumerator, Array] Returns a new array, or enumerator if block is nil
40
+ # @yield [key, value] Block that transforms each key-value pair
41
+ # @yieldparam key [Symbol] The attribute name
42
+ # @yieldparam value [Object] The attribute value
43
+ #
44
+ # @return [Array, Enumerator] Results of mapping or an Enumerator if no block given
45
+ #
46
+ # @example
47
+ # struct = OpenStruct.new(a: 1, b: 2)
48
+ # struct.map { |key, value| [key, value * 2] } # => [[:a, 2], [:b, 4]]
30
49
  #
31
50
  def map(&)
32
51
  @table.map(&)
@@ -35,7 +54,15 @@ class OpenStruct
35
54
  #
36
55
  # Maps over OpenStruct entries and returns an array without nil values
37
56
  #
38
- # @return [Enumerator, Array] Returns a new array, or enumerator if block is nil
57
+ # @yield [key, value] Block that transforms each key-value pair
58
+ # @yieldparam key [Symbol] The attribute name
59
+ # @yieldparam value [Object] The attribute value
60
+ #
61
+ # @return [Array, Enumerator] Non-nil results of mapping or an Enumerator if no block given
62
+ #
63
+ # @example
64
+ # struct = OpenStruct.new(a: 1, b: nil, c: 2)
65
+ # struct.filter_map { |key, value| value * 2 if value } # => [2, 4]
39
66
  #
40
67
  def filter_map(&block)
41
68
  return enum_for(:filter_map) unless block
@@ -48,16 +75,18 @@ class OpenStruct
48
75
  #
49
76
  # @param join_with [String] The delimiter to join elements with (defaults to empty string)
50
77
  #
51
- # @yield [Object] Block that filters and transforms hash elements
78
+ # @yield [key, value] Block that filters and transforms OpenStruct entries
79
+ # @yieldparam key [Symbol] The attribute name
80
+ # @yieldparam value [Object] The attribute value
52
81
  #
53
- # @return [String] Joined string of filtered and transformed elements
82
+ # @return [String] Joined string of filtered and transformed entries
54
83
  #
55
84
  # @example
56
85
  # object = OpenStruct.new(a: 1, b: nil, c: 3)
57
86
  # object.join_map(" ") { |k, v| "#{k}-#{v}" if v }
58
87
  # # => "a-1 c-3"
59
88
  #
60
- # @example
89
+ # @example Default behavior without block
61
90
  # object = OpenStruct.new(a: 1, b: nil, c: 3)
62
91
  # object.join_map(", ")
63
92
  # # => "a, 1, b, c, 3"
@@ -69,7 +98,9 @@ class OpenStruct
69
98
  end
70
99
 
71
100
  #
72
- # @return [self]
101
+ # Returns self (identity method for consistent interfaces)
102
+ #
103
+ # @return [self] Returns the OpenStruct
73
104
  #
74
105
  def to_ostruct
75
106
  self
@@ -1,10 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # Extensions to Ruby's core String class
5
+ #
6
+ # These additions make working with JSON strings easy by providing methods for conversion
7
+ # to various Ruby data structures. Plus some nice formatting helpers that saves tons of typing
8
+ #
9
+ # @example Converting JSON to different structures
10
+ # json = '{"user": {"name": "Alice", "admin": true}}'
11
+ # json.to_h # => {user: {name: "Alice", admin: true}}
12
+ # json.to_istruct.user.name # => "Alice"
13
+ # json.to_ostruct.user.name # => "Alice"
14
+ #
3
15
  class String
4
16
  #
5
17
  # Converts JSON string to Hash, returning nil if it failed
6
18
  #
7
- # @return [Hash, nil] Parsed JSON as hash
19
+ # @return [Hash, nil] Parsed JSON as hash or nil if invalid JSON
20
+ #
21
+ # @example
22
+ # '{"name": "Alice"}'.to_h # => {name: "Alice"}
23
+ # "invalid json".to_h # => nil
8
24
  #
9
25
  def to_h
10
26
  JSON.parse(self, symbolize_names: true)
@@ -18,7 +34,14 @@ class String
18
34
  # Deep parsing of nested JSON strings
19
35
  # Recursively attempts to parse string values as JSON
20
36
  #
21
- # @return [Hash] Deeply parsed hash
37
+ # @return [Hash] Deeply parsed hash with all nested JSON strings converted
38
+ #
39
+ # @example
40
+ # nested_json = '{
41
+ # "user": "{\"name\":\"Alice\",\"roles\":[\"admin\"]}"
42
+ # }'
43
+ # nested_json.to_deep_h
44
+ # # => {user: {name: "Alice", roles: ["admin"]}}
22
45
  #
23
46
  def to_deep_h
24
47
  recursive_convert = lambda do |object|
@@ -48,7 +71,11 @@ class String
48
71
  # Attempts to parse JSON and convert to Data struct.
49
72
  # Returns nil if string does not contain valid JSON
50
73
  #
51
- # @return [nil, Data]
74
+ # @return [Data, nil] Immutable Data structure or nil if invalid JSON
75
+ #
76
+ # @example
77
+ # '{"name": "Alice"}'.to_istruct # => #<data name="Alice">
78
+ # "not json".to_istruct # => nil
52
79
  #
53
80
  def to_istruct
54
81
  to_h&.to_istruct
@@ -58,7 +85,12 @@ class String
58
85
  # Attempts to parse JSON and convert to OpenStruct.
59
86
  # Returns nil if string does not contain valid JSON
60
87
  #
61
- # @return [nil, OpenStruct]
88
+ # @return [OpenStruct, nil] OpenStruct or nil if invalid JSON
89
+ #
90
+ # @example
91
+ # '{"name": "Alice"}'.to_ostruct # => #<OpenStruct name="Alice">
92
+ # "not json".to_ostruct # => nil
93
+ #
62
94
  def to_ostruct
63
95
  to_h&.to_ostruct
64
96
  end
@@ -67,16 +99,24 @@ class String
67
99
  # Attempts to parse JSON and convert to Struct.
68
100
  # Returns nil if string does not contain valid JSON
69
101
  #
70
- # @return [nil, Struct]
102
+ # @return [Struct, nil] Struct or nil if invalid JSON
103
+ #
104
+ # @example
105
+ # '{"name": "Alice"}'.to_struct # => #<struct name="Alice">
106
+ # "not json".to_struct # => nil
71
107
  #
72
108
  def to_struct
73
109
  to_h&.to_struct
74
110
  end
75
111
 
76
112
  #
77
- # Returns self wrapped in double quotes.
113
+ # Returns self wrapped in double quotes
114
+ #
115
+ # @return [String] The string with surrounding double quotes
78
116
  #
79
- # @return [String]
117
+ # @example
118
+ # "Hello World".with_quotes # => "\"Hello World\""
119
+ # "Quote \"me\"".with_quotes # => "\"Quote \\\"me\\\"\""
80
120
  #
81
121
  def with_quotes
82
122
  %("#{self}")
@@ -1,10 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # Extensions to Ruby's core Symbol class
5
+ #
6
+ # These additions provide handy formatting helpers for symbols.
7
+ #
8
+ # @example
9
+ # :hello_world.with_quotes # => :"\"hello_world\""
10
+ #
3
11
  class Symbol
4
12
  #
5
- # Returns self wrapped in double quotes.
13
+ # Returns self wrapped in double quotes
6
14
  #
7
- # @return [Symbol]
15
+ # @return [Symbol] The symbol with surrounding double quotes
16
+ #
17
+ # @example
18
+ # :hello_world.with_quotes # => :"\"hello_world\""
19
+ # :hello_world.in_quotes # => :"\"hello_world\""
8
20
  #
9
21
  def with_quotes
10
22
  :"\"#{self}\""
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #
4
+ # EverythingRB - Super handy extensions to Ruby's core classes
5
+ #
6
+ # @author Bryan "itsthedevman"
7
+ #
3
8
  module Everythingrb
4
- VERSION = "0.2.3"
9
+ # Current version of the everythingrb gem
10
+ VERSION = "0.2.4"
5
11
  end
data/lib/everythingrb.rb CHANGED
@@ -12,5 +12,26 @@ require_relative "everythingrb/core/ostruct"
12
12
  require_relative "everythingrb/core/string"
13
13
  require_relative "everythingrb/core/symbol"
14
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
+ #
15
36
  module Everythingrb
16
37
  end
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.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-10 00:00:00.000000000 Z
11
+ date: 2025-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ostruct