everythingrb 0.9.0 → 1.0.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.
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "benchmark_helper"
4
+
5
+ BenchmarkHelper.header("String Extension Benchmarks")
6
+
7
+ # Test data
8
+ simple_json = '{"name": "Alice", "age": 30}'
9
+ nested_json = '{"user": {"profile": {"name": "Alice"}, "settings": {"theme": "dark"}}}'
10
+ large_json = "{" + (1..100).map { |i| %("key#{i}": #{i}) }.join(", ") + "}"
11
+ invalid_json = "not valid json"
12
+
13
+ simple_string = "hello_world"
14
+ complex_string = "welcome to the jungle!"
15
+ mixed_string = "please-WAIT while_loading..."
16
+ special_chars = "test@#$%^&*()string_with-special.chars!"
17
+
18
+ # ============================================================================
19
+ # parse_json benchmarks
20
+ # ============================================================================
21
+
22
+ BenchmarkHelper.run("parse_json - simple JSON") do |x|
23
+ x.report("parse_json") { simple_json.parse_json }
24
+ x.report("parse_json(symbolize: false)") { simple_json.parse_json(symbolize_names: false) }
25
+ end
26
+
27
+ BenchmarkHelper.run("parse_json - nested JSON") do |x|
28
+ x.report("parse_json") { nested_json.parse_json }
29
+ end
30
+
31
+ BenchmarkHelper.run("parse_json - large JSON (100 keys)") do |x|
32
+ x.report("parse_json") { large_json.parse_json }
33
+ end
34
+
35
+ BenchmarkHelper.run("parse_json - invalid JSON") do |x|
36
+ x.report("parse_json (returns nil)") { invalid_json.parse_json }
37
+ end
38
+
39
+ # ============================================================================
40
+ # to_istruct / to_ostruct / to_struct benchmarks
41
+ # ============================================================================
42
+
43
+ BenchmarkHelper.run("JSON to struct conversions - simple") do |x|
44
+ x.report("to_istruct") { simple_json.to_istruct }
45
+ x.report("to_ostruct") { simple_json.to_ostruct }
46
+ x.report("to_struct") { simple_json.to_struct }
47
+ end
48
+
49
+ BenchmarkHelper.run("JSON to struct conversions - nested") do |x|
50
+ x.report("to_istruct") { nested_json.to_istruct }
51
+ x.report("to_ostruct") { nested_json.to_ostruct }
52
+ x.report("to_struct") { nested_json.to_struct }
53
+ end
54
+
55
+ # ============================================================================
56
+ # to_camelcase benchmarks
57
+ # ============================================================================
58
+
59
+ BenchmarkHelper.run("to_camelcase - simple underscore string") do |x|
60
+ x.report("to_camelcase(:upper)") { simple_string.to_camelcase }
61
+ x.report("to_camelcase(:lower)") { simple_string.to_camelcase(:lower) }
62
+ end
63
+
64
+ BenchmarkHelper.run("to_camelcase - complex string with spaces") do |x|
65
+ x.report("to_camelcase(:upper)") { complex_string.to_camelcase }
66
+ x.report("to_camelcase(:lower)") { complex_string.to_camelcase(:lower) }
67
+ end
68
+
69
+ BenchmarkHelper.run("to_camelcase - mixed formatting") do |x|
70
+ x.report("to_camelcase(:upper)") { mixed_string.to_camelcase }
71
+ end
72
+
73
+ BenchmarkHelper.run("to_camelcase - special characters") do |x|
74
+ x.report("to_camelcase(:upper)") { special_chars.to_camelcase }
75
+ end
76
+
77
+ # ============================================================================
78
+ # in_quotes / with_quotes benchmarks
79
+ # ============================================================================
80
+
81
+ BenchmarkHelper.run("in_quotes / with_quotes") do |x|
82
+ x.report("short string in_quotes") { "hello".in_quotes }
83
+ x.report("medium string in_quotes") { complex_string.in_quotes }
84
+ x.report("with_quotes (alias)") { complex_string.with_quotes }
85
+ end
@@ -188,49 +188,4 @@ class Array
188
188
  to_sentence(options)
189
189
  end
190
190
  end
191
-
192
- #
193
- # Recursively converts all elements that respond to #to_h
194
- #
195
- # Maps over the array and calls #to_deep_h on any Hash/String elements,
196
- # #to_h on any objects that respond to it, and handles nested arrays.
197
- #
198
- # @return [Array] A new array with all convertible elements deeply converted
199
- #
200
- # @example Converting arrays with mixed object types
201
- # users = [
202
- # {name: "Alice", roles: ["admin"]},
203
- # OpenStruct.new(name: "Bob", active: true),
204
- # Data.define(:name).new(name: "Carol")
205
- # ]
206
- # users.to_deep_h
207
- # # => [
208
- # # {name: "Alice", roles: ["admin"]},
209
- # # {name: "Bob", active: true},
210
- # # {name: "Carol"}
211
- # # ]
212
- #
213
- # @example With nested arrays and JSON strings
214
- # data = [
215
- # {profile: '{"level":"expert"}'},
216
- # [OpenStruct.new(id: 1), OpenStruct.new(id: 2)]
217
- # ]
218
- # data.to_deep_h
219
- # # => [{profile: {level: "expert"}}, [{id: 1}, {id: 2}]]
220
- #
221
- def to_deep_h
222
- map do |value|
223
- case value
224
- when Hash
225
- value.to_deep_h
226
- when Array
227
- value.to_deep_h
228
- when String
229
- # If the string is not valid JSON, #to_deep_h will return `nil`
230
- value.to_deep_h || value
231
- else
232
- value.respond_to?(:to_h) ? value.to_h : value
233
- end
234
- end
235
- end
236
191
  end
@@ -4,27 +4,8 @@
4
4
  # Extensions to Ruby's core Data class
5
5
  #
6
6
  # Provides:
7
- # - #to_deep_h: Recursively convert to hash with all nested objects
8
7
  # - #in_quotes, #with_quotes: Wrap object in quotes
9
8
  #
10
9
  class Data
11
10
  include Everythingrb::InspectQuotable
12
-
13
- #
14
- # Recursively converts the Data object and all nested objects to hashes
15
- #
16
- # This method traverses the entire Data structure, converting not just
17
- # the top-level Data object but also nested Data objects, Structs, OpenStructs,
18
- # and any other objects that implement `to_h`.
19
- #
20
- # @return [Hash] A deeply converted hash of the Data object
21
- #
22
- # @example
23
- # Person = Data.define(:name, :profile)
24
- # person = Person.new(name: "Alice", profile: {roles: ["admin"]})
25
- # person.to_deep_h # => {name: "Alice", profile: {roles: ["admin"]}}
26
- #
27
- def to_deep_h
28
- to_h.to_deep_h
29
- end
30
11
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "date"
4
+
3
5
  #
4
6
  # Extensions to Ruby's core Date class
5
7
  #
@@ -8,9 +8,8 @@
8
8
  # - #join_map: Combine filter_map and join operations
9
9
  # - #transform_values.with_key: Transform values with access to keys
10
10
  # - #transform, #transform!: Transform keys and values
11
- # - #value_where, #values_where: Find values based on conditions
11
+ # - #find_value, #select_values: Find values based on conditions
12
12
  # - #rename_key, #rename_keys: Rename hash keys while preserving order
13
- # - ::new_nested_hash: Create automatically nesting hashes
14
13
  # - #merge_if, #merge_if!: Conditionally merge based on key-value pairs
15
14
  # - #merge_if_values, #merge_if_values!: Conditionally merge based on values
16
15
  # - #compact_merge, #compact_merge!: Merge only non-nil values
@@ -37,59 +36,6 @@ class Hash
37
36
  #
38
37
  EMPTY_STRUCT = Struct.new(:_).new(nil)
39
38
 
40
- #
41
- # Creates a new Hash that automatically initializes missing keys with nested hashes
42
- #
43
- # This method creates a hash where any missing key access will automatically
44
- # create another nested hash with the same behavior. You can control the nesting
45
- # depth with the depth parameter.
46
- #
47
- # @param depth [Integer, nil] The maximum nesting depth for automatic hash creation
48
- # When nil (default), creates unlimited nesting depth
49
- # When 0, behaves like a regular hash (returns nil for missing keys)
50
- # When > 0, automatically creates hashes only up to the specified level
51
- #
52
- # @return [Hash] A hash that creates nested hashes for missing keys
53
- #
54
- # @note This implementation is not thread-safe for concurrent modifications of deeply
55
- # nested structures. If you need thread safety, consider using a mutex when modifying
56
- # the deeper levels of the hash.
57
- #
58
- # @example Unlimited nesting (default behavior)
59
- # users = Hash.new_nested_hash
60
- # users[:john][:role] = "admin" # No need to initialize users[:john] first
61
- # users # => {john: {role: "admin"}}
62
- #
63
- # @example Deep nesting without initialization
64
- # stats = Hash.new_nested_hash
65
- # stats[:server][:region][:us_east][:errors] = ["Error"]
66
- # stats # => {server: {region: {us_east: {errors: ["Error"]}}}}
67
- #
68
- # @example Limited nesting depth
69
- # hash = Hash.new_nested_hash(depth: 1)
70
- # hash[:user][:name] = "Alice" # Works fine - only one level of auto-creation
71
- #
72
- # # This pattern works correctly with limited nesting:
73
- # (hash[:user][:roles] ||= []) << "admin"
74
- # hash # => {user: {name: "Alice", roles: ["admin"]}}
75
- #
76
- # @note While unlimited nesting is convenient, it can interfere with common Ruby
77
- # patterns like ||= when initializing values at deep depths. Use the depth
78
- # parameter to control this behavior.
79
- #
80
- def self.new_nested_hash(depth: nil)
81
- new do |hash, key|
82
- next if depth == 0
83
-
84
- hash[key] =
85
- if depth.nil?
86
- new_nested_hash
87
- else
88
- new_nested_hash(depth: depth - 1)
89
- end
90
- end
91
- end
92
-
93
39
  #
94
40
  # Combines filter_map and join operations
95
41
  #
@@ -127,53 +73,6 @@ class Hash
127
73
  end
128
74
  end
129
75
 
130
- #
131
- # Recursively converts all values that respond to #to_h
132
- #
133
- # Similar to #to_h but recursively traverses the Hash structure
134
- # and calls #to_h on any object that responds to it. Useful for
135
- # normalizing nested data structures and parsing nested JSON.
136
- #
137
- # @return [Hash] A deeply converted hash with all nested objects
138
- #
139
- # @example Converting nested Data objects
140
- # user = { name: "Alice", metadata: Data.define(:source).new(source: "API") }
141
- # user.to_deep_h # => {name: "Alice", metadata: {source: "API"}}
142
- #
143
- # @example Parsing nested JSON strings
144
- # nested = { profile: '{"role":"admin"}' }
145
- # nested.to_deep_h # => {profile: {role: "admin"}}
146
- #
147
- # @example Mixed nested structures
148
- # data = {
149
- # config: OpenStruct.new(api_key: "secret"),
150
- # users: [
151
- # Data.define(:name).new(name: "Bob"),
152
- # {role: "admin"}
153
- # ]
154
- # }
155
- # data.to_deep_h
156
- # # => {
157
- # # config: {api_key: "secret"},
158
- # # users: [{name: "Bob"}, {role: "admin"}]
159
- # # }
160
- #
161
- def to_deep_h
162
- transform_values do |value|
163
- case value
164
- when Hash
165
- value.to_deep_h
166
- when Array
167
- value.to_deep_h
168
- when String
169
- # If the string is not valid JSON, #to_deep_h will return `nil`
170
- value.to_deep_h || value
171
- else
172
- value.respond_to?(:to_h) ? value.to_h : value
173
- end
174
- end
175
- end
176
-
177
76
  #
178
77
  # Converts hash to an immutable Data structure
179
78
  #
@@ -512,10 +411,10 @@ class Hash
512
411
  # bob: {name: "Bob", role: "user"},
513
412
  # charlie: {name: "Charlie", role: "admin"}
514
413
  # }
515
- # users.value_where { |k, v| v[:role] == "admin" } # => {name: "Alice", role: "admin"}
414
+ # users.find_value { |k, v| v[:role] == "admin" } # => {name: "Alice", role: "admin"}
516
415
  #
517
- def value_where(&block)
518
- return to_enum(:value_where) if block.nil?
416
+ def find_value(&block)
417
+ return to_enum(:find_value) if block.nil?
519
418
 
520
419
  find(&block)&.last
521
420
  end
@@ -537,11 +436,11 @@ class Hash
537
436
  # bob: {name: "Bob", role: "user"},
538
437
  # charlie: {name: "Charlie", role: "admin"}
539
438
  # }
540
- # users.values_where { |k, v| v[:role] == "admin" }
439
+ # users.select_values { |k, v| v[:role] == "admin" }
541
440
  # # => [{name: "Alice", role: "admin"}, {name: "Charlie", role: "admin"}]
542
441
  #
543
- def values_where(&block)
544
- return to_enum(:values_where) if block.nil?
442
+ def select_values(&block)
443
+ return to_enum(:select_values) if block.nil?
545
444
 
546
445
  select(&block).values
547
446
  end
@@ -20,17 +20,26 @@
20
20
  #
21
21
  class Module
22
22
  #
23
- # Creates predicate (boolean) methods that return true/false
24
- # Similar to attr_reader, attr_writer, etc. Designed to work with
25
- # regular classes, Struct, and Data objects.
23
+ # Creates predicate (boolean) methods that return true/false based on an attribute's value.
24
+ # Similar to attr_reader, attr_writer, etc. Designed to work with regular classes, Struct,
25
+ # and Data objects.
26
26
  #
27
- # Note: If ActiveSupport is loaded, this will check if the value is present? instead of truthy
27
+ # Values are evaluated as follows:
28
+ # - nil and false are always false
29
+ # - With ActiveSupport: uses +present?+ (empty strings, arrays, hashes are false)
30
+ # - Without ActiveSupport: checks +empty?+ if available, otherwise uses truthiness
28
31
  #
29
32
  # @param attributes [Array<Symbol, String>] Attribute names
33
+ # @param opts [Hash] Options hash
34
+ # @option opts [Symbol, String, nil] :from Source ivar or method to read from. Use @ prefix
35
+ # for instance variables (e.g., :@started_at), omit for methods (e.g., :status). When
36
+ # specified, only one attribute may be provided (ambiguous mapping otherwise).
37
+ # @option opts [Boolean] :private If true, defines the predicate as a private method
30
38
  #
31
39
  # @return [nil]
32
40
  #
33
41
  # @raise [ArgumentError] If a predicate method of the same name already exists
42
+ # @raise [ArgumentError] If from: is specified with multiple attributes
34
43
  #
35
44
  # @example With a regular class
36
45
  # class User
@@ -50,24 +59,80 @@ class Module
50
59
  # person = Person.new(active: true)
51
60
  # person.active? # => true
52
61
  #
53
- def attr_predicate(*attributes)
62
+ # @example Mapping to a different ivar with from:
63
+ # class Task
64
+ # attr_accessor :started_at, :stopped_at
65
+ # attr_predicate :started, from: :@started_at
66
+ # attr_predicate :finished, from: :@stopped_at
67
+ # end
68
+ #
69
+ # task = Task.new
70
+ # task.started? # => false
71
+ # task.started_at = Time.now
72
+ # task.started? # => true
73
+ #
74
+ # @example Mapping to a method with from:
75
+ # class Job
76
+ # attr_accessor :error_messages
77
+ # attr_predicate :errored, from: :error_messages
78
+ # end
79
+ #
80
+ # job = Job.new
81
+ # job.errored? # => false
82
+ # job.error_messages = ["Something went wrong"]
83
+ # job.errored? # => true
84
+ #
85
+ # @example Private predicate method
86
+ # class Account
87
+ # attr_accessor :verified
88
+ # attr_predicate :verified, private: true
89
+ # end
90
+ #
91
+ # account = Account.new
92
+ # account.verified? # => NoMethodError (private method)
93
+ #
94
+ def attr_predicate(*attributes, **opts)
95
+ from = opts[:from]
96
+ private_method = !!opts[:private]
97
+
98
+ if from && attributes.size > 1
99
+ raise ArgumentError, "Cannot use from: option with multiple attributes - each predicate needs its own source mapping"
100
+ end
101
+
54
102
  attributes.each do |attribute|
55
103
  if method_defined?(:"#{attribute}?")
56
104
  raise ArgumentError, "Cannot create predicate method on #{self.class} - #{attribute}? is already defined. Please choose a different name or remove the existing method."
57
105
  end
58
106
 
59
- module_eval <<-RUBY, __FILE__, __LINE__ + 1
60
- def #{attribute}?
61
- value =
62
- if instance_variable_defined?(:@#{attribute})
63
- @#{attribute}
64
- elsif respond_to?(:#{attribute})
65
- self.#{attribute}
66
- end
107
+ signature = "def #{attribute}?"
108
+ signature.prepend("private ") if private_method
109
+
110
+ # Performance note:
111
+ # This was originally checked if an instance variable or method was defined, both of which are sllllooooowwwww
112
+ # Now as of 1.0.0, this assumes an instance variable (with exceptions) by default
113
+ getter =
114
+ if from
115
+ from.to_s.start_with?("@") ? from : "self.#{from}"
116
+ elsif self < Struct || self < OpenStruct || self < Data
117
+ "self.#{attribute}"
118
+ else
119
+ "@#{attribute}"
120
+ end
121
+
122
+ checker =
123
+ if defined?(ActiveSupport)
124
+ "!!value.presence"
125
+ else
126
+ # Handle empty arrays/hashes/strings
127
+ "value.respond_to?(:empty?) ? !value.empty? : !!value"
128
+ end
67
129
 
130
+ module_eval <<~RUBY, __FILE__, __LINE__ + 1
131
+ #{signature}
132
+ value = #{getter}
68
133
  return false if value.nil?
69
134
 
70
- defined?(ActiveSupport) ? !!value.presence : !!value
135
+ #{checker}
71
136
  end
72
137
  RUBY
73
138
  end
@@ -7,7 +7,6 @@
7
7
  # - #map, #filter_map: Enumeration methods for OpenStruct entries
8
8
  # - #join_map: Combine filter_map and join operations
9
9
  # - #blank?, #present?: ActiveSupport integrations when available
10
- # - #to_deep_h: Recursively convert to hash with all nested objects
11
10
  # - #in_quotes, #with_quotes: Wrap struct in quotes
12
11
  #
13
12
  # @example
@@ -117,23 +116,4 @@ class OpenStruct
117
116
  def to_ostruct
118
117
  self
119
118
  end
120
-
121
- #
122
- # Recursively converts the OpenStruct and all nested objects to hashes
123
- #
124
- # This method will convert the OpenStruct and all nested OpenStructs,
125
- # Structs, Data objects, and other convertible objects to plain hashes.
126
- #
127
- # @return [Hash] A deeply converted hash of the OpenStruct
128
- #
129
- # @example
130
- # person = OpenStruct.new(
131
- # name: "Alice",
132
- # address: OpenStruct.new(city: "New York", country: "USA")
133
- # )
134
- # person.to_deep_h # => {name: "Alice", address: {city: "New York", country: "USA"}}
135
- #
136
- def to_deep_h
137
- to_h.to_deep_h
138
- end
139
119
  end
@@ -4,8 +4,7 @@
4
4
  # Extensions to Ruby's core String class
5
5
  #
6
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
7
+ # - #parse_json: Parse JSON strings with error handling
9
8
  # - #to_ostruct, #to_istruct, #to_struct: Convert JSON to data structures
10
9
  # - #with_quotes, #in_quotes: Wrap strings in quotes
11
10
  # - #to_camelcase: Convert strings to camelCase or PascalCase
@@ -21,61 +20,36 @@ class String
21
20
  include Everythingrb::StringQuotable
22
21
 
23
22
  #
24
- # Converts JSON string to Hash, returning nil if it failed
23
+ # Parses the string as JSON and returns the result
25
24
  #
26
- # @return [Hash, nil] Parsed JSON as hash or nil if invalid JSON
25
+ # Safely parses JSON with symbolized keys by default. Returns nil
26
+ # instead of raising an exception if the string is not valid JSON.
27
27
  #
28
- # @example
29
- # '{"name": "Alice"}'.to_h # => {name: "Alice"}
30
- # "invalid json".to_h # => nil
28
+ # @param opts [Hash] Options to pass to JSON.parse
29
+ # @option opts [Boolean] :symbolize_names (true) Whether to symbolize keys
31
30
  #
32
- def to_h
33
- JSON.parse(self, symbolize_names: true)
34
- rescue JSON::ParserError
35
- nil
36
- end
37
-
38
- alias_method :to_a, :to_h
39
-
31
+ # @return [Hash, Array, nil] Parsed JSON or nil if invalid
40
32
  #
41
- # Deep parsing of nested JSON strings
42
- # Recursively attempts to parse string values as JSON
33
+ # @example Basic usage
34
+ # '{"name": "Alice"}'.parse_json # => {name: "Alice"}
43
35
  #
44
- # @return [Hash] Deeply parsed hash with all nested JSON strings converted
45
- # @return [nil] If the string is not valid JSON at the top level
36
+ # @example With nested data
37
+ # '{"user": {"roles": ["admin"]}}'.parse_json
38
+ # # => {user: {roles: ["admin"]}}
46
39
  #
47
- # @note If nested JSON strings fail to parse, they remain as strings
48
- # rather than causing the entire operation to fail
40
+ # @example Invalid JSON returns nil
41
+ # "not json".parse_json # => nil
49
42
  #
50
- # @example
51
- # nested_json = '{
52
- # "user": "{\"name\":\"Alice\",\"roles\":[\"admin\"]}"
53
- # }'
54
- # nested_json.to_deep_h
55
- # # => {user: {name: "Alice", roles: ["admin"]}}
56
- #
57
- def to_deep_h
58
- recursive_convert = lambda do |object|
59
- case object
60
- when Array
61
- object.map { |v| recursive_convert.call(v) }
62
- when String
63
- result = object.to_deep_h
64
-
65
- # Nested JSON
66
- if result.is_a?(Array) || result.is_a?(Hash)
67
- recursive_convert.call(result)
68
- else
69
- object
70
- end
71
- when Hash
72
- object.transform_values { |v| recursive_convert.call(v) }
73
- else
74
- object
75
- end
76
- end
43
+ # @example Disable symbolized keys
44
+ # '{"name": "Alice"}'.parse_json(symbolize_names: false)
45
+ # # => {"name" => "Alice"}
46
+ #
47
+ def parse_json(**opts)
48
+ opts[:symbolize_names] = true unless opts.key?(:symbolize_names)
77
49
 
78
- recursive_convert.call(to_h)
50
+ JSON.parse(self, opts)
51
+ rescue JSON::ParserError
52
+ nil
79
53
  end
80
54
 
81
55
  #
@@ -89,7 +63,7 @@ class String
89
63
  # "not json".to_istruct # => nil
90
64
  #
91
65
  def to_istruct
92
- to_h&.to_istruct
66
+ parse_json&.to_istruct
93
67
  end
94
68
 
95
69
  #
@@ -103,7 +77,7 @@ class String
103
77
  # "not json".to_ostruct # => nil
104
78
  #
105
79
  def to_ostruct
106
- to_h&.to_ostruct
80
+ parse_json&.to_ostruct
107
81
  end
108
82
 
109
83
  #
@@ -117,7 +91,7 @@ class String
117
91
  # "not json".to_struct # => nil
118
92
  #
119
93
  def to_struct
120
- to_h&.to_struct
94
+ parse_json&.to_struct
121
95
  end
122
96
 
123
97
  #
@@ -4,7 +4,6 @@
4
4
  # Extensions to Ruby's core Struct class
5
5
  #
6
6
  # Provides:
7
- # - #to_deep_h: Recursively convert to hash with all nested objects
8
7
  # - #in_quotes, #with_quotes: Wrap struct in quotes
9
8
  #
10
9
  # @example
@@ -12,27 +11,7 @@
12
11
  #
13
12
  # Person = Struct.new(:name, :profile)
14
13
  # person = Person.new("Alice", {roles: ["admin"]})
15
- # person.to_deep_h # => {name: "Alice", profile: {roles: ["admin"]}}
16
14
  #
17
15
  class Struct
18
16
  include Everythingrb::InspectQuotable
19
-
20
- #
21
- # Recursively converts the Struct and all nested objects to hashes
22
- #
23
- # This method traverses the entire Struct structure, converting not just
24
- # the top-level Struct but also nested Structs, OpenStructs, Data objects,
25
- # and any other objects that implement `to_h`.
26
- #
27
- # @return [Hash] A deeply converted hash of the Struct
28
- #
29
- # @example
30
- # Address = Struct.new(:city, :country)
31
- # Person = Struct.new(:name, :address)
32
- # person = Person.new("Alice", Address.new("New York", "USA"))
33
- # person.to_deep_h # => {name: "Alice", address: {city: "New York", country: "USA"}}
34
- #
35
- def to_deep_h
36
- to_h.to_deep_h
37
- end
38
17
  end
@@ -7,5 +7,5 @@
7
7
  #
8
8
  module Everythingrb
9
9
  # Current version of the everythingrb gem
10
- VERSION = "0.9.0"
10
+ VERSION = "1.0.0"
11
11
  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.9.0
4
+ version: 1.0.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-08-02 00:00:00.000000000 Z
11
+ date: 2026-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ostruct
@@ -54,6 +54,16 @@ files:
54
54
  - LICENSE.txt
55
55
  - README.md
56
56
  - Rakefile
57
+ - benchmarks/array_benchmark.rb
58
+ - benchmarks/benchmark_helper.rb
59
+ - benchmarks/enumerable_benchmark.rb
60
+ - benchmarks/hash_benchmark.rb
61
+ - benchmarks/kernel_benchmark.rb
62
+ - benchmarks/module_benchmark.rb
63
+ - benchmarks/ostruct_benchmark.rb
64
+ - benchmarks/quotable_benchmark.rb
65
+ - benchmarks/run_all.rb
66
+ - benchmarks/string_benchmark.rb
57
67
  - flake.lock
58
68
  - flake.nix
59
69
  - lib/everythingrb.rb