All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
from: option to attr_predicate - Map a predicate to a differently-named source. Use @ prefix for instance variables (e.g., from: :@started_at), omit for methods (e.g., from: :error_messages). This enables patterns like attr_predicate :started, from: :@started_at and attr_predicate :errored, from: :error_messages.private: option to attr_predicate - Define predicates as private methods with attr_predicate :verified, private: true.Hash#value_where to Hash#find_value and Hash#values_where to Hash#select_values - The new names better align with Ruby conventions and clearly express the methods’ purpose of finding values that match a condition.String#to_h to String#parse_json - This change improves compatibility with Ruby’s type coercion expectations and avoids conflicts with methods like Array(obj) that rely on standard to_a/to_h behavior. The method parses JSON strings with symbolized keys by default and returns nil for invalid JSON.require "date" to ensure Date and DateTime classes are properly loaded before extending them.attr_predicate no longer falls back to method calls - For performance reasons (~5x faster), attr_predicate now assumes direct instance variable access by default. The previous behavior checked instance_variable_defined? and respond_to? on every call, which was slow. Struct, OpenStruct, and Data classes are automatically detected and use method access. For other cases where you need method delegation, use the new from: option explicitly (e.g., attr_predicate :errored, from: :error_messages).attr_predicate empty value handling - Without ActiveSupport, values responding to empty? (arrays, hashes, strings) now return false when empty. Previously, an empty array would return true since !![] is truthy. With ActiveSupport, behavior is unchanged (uses present?).Hash.new_nested_hash - Use Ruby’s built-in Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } instead.#to_deep_h from all classes - This method has been removed from String, Hash, Array, Struct, OpenStruct, and Data classes. If you need this functionality, implement it locally in your project.String#to_a - This method was removed along with the JSON parsing refactor.Hash#compact_blank_merge and Hash#compact_blank_merge! - Merge only present (non-blank) values when ActiveSupport is loaded. Filters out nil, empty strings, empty arrays, false, and other blank values according to ActiveSupport’s definition.with_index parameter to Hash#join_map for API consistency with Array#join_map.Hash#merge_compact to Hash#compact_merge - Updated method naming for consistency with other operation-first methods like compact_prefix, trim_nils, etc. The old method names will be removed in this version.Hash#merge_compact! to Hash#compact_merge! - In-place version follows the same naming convention.Hash#merge_compact and Hash#merge_compact! - These methods have been renamed to Hash#compact_merge and Hash#compact_merge! respectively for naming consistency.Hash#select_values, Hash#select_values!, Hash#reject_values, Hash#reject_values!, and Hash#filter_values, Hash#filter_values! have been removed as planned. These methods were deprecated in v0.8.3. Use the standard Ruby alternatives instead:
hash.select_values { |v| condition } → hash.select { |k, v| condition }
hash.reject_values { |v| condition } → hash.reject { |k, v| condition }
hash.reject_values(&:blank?) → hash.compact_blank (with ActiveSupport)Deprecated Hash value filtering methods - Hash#select_values, Hash#reject_values, Hash#select_values! and Hash#reject_values! are now deprecated and will be removed in v0.9.0. These methods largely duplicate existing Ruby/ActiveSupport functionality:
hash.reject_values(&:blank?) → use hash.compact_blank insteadhash.select_values { |v| condition } → use hash.select { |k, v| condition }
hash.reject_values { |v| condition } → use hash.reject { |k, v| condition }
See Issue #61 for full details.
Hash#rename_key_unordered and Hash#rename_key_unordered! to not create new key-value pairs when the original key doesn’t exist. Previously, these methods would incorrectly add the new_key to the hash even when old_key was missing.# In config/initializers/everythingrb.rb
Rails.application.configure do
config.everythingrb.extensions = [:array, :string, :hash]
end
Hash#merge_if and Hash#merge_if! - Merge key-value pairs based on a conditionHash#merge_if_values and Hash#merge_if_values! - Merge based on values onlyHash#merge_compact and Hash#merge_compact! - Merge only non-nil valuesString#to_camelcase - Converts strings to camelCase/PascalCase while handling spaces, hyphens, underscores, and special characters
:lower) and uppercase first letter (:upper), which is defaultArray#deep_freeze and Hash#deep_freeze methods to prevent accidental freezing of classes and singleton objects. This creates a safer API for the 1.0.0 milestone.Everythingrb::InspectQuotable and Everythingrb::StringQuotable modules for consistent quote functionalityTrueClass and FalseClass (boolean values)NilClassNumericRangeRegexpTime, Date, and DateTime
Data and Struct classesHash#select_values - Returns a new hash with entries where the block returns true for the valueHash#select_values! - Same as select_values but modifies the hash in placeHash#reject_values - Returns a new hash with entries where the block returns false for the valueHash#reject_values! - Same as reject_values but modifies the hash in placefilter_values and filter_values! as aliases for select_values and select_values! respectivelyAdded Kernel#morph as an alias for then (and yield_self) that better communicates transformation intent:
# Instead of this:
value.then { |v| transform_somehow(v) }
# You can write this:
value.morph { |v| transform_somehow(v) }
in_quotes as the primary method with with_quotes as an aliasprivate in Hash when ActiveSupport is enabled. This unintentionally caused other public methods to be privateReplaced method-based with_key approach with direct parameter:
The chainable .with_key method approach has been replaced with a more straightforward parameter-based approach.
Before:
hash.transform_values.with_key { |value, key| "#{key}:#{value}" }
hash.transform_values!.with_key { |value, key| "#{key}:#{value}" }
After:
hash.transform_values(with_key: true) { |value, key| "#{key}:#{value}" }
hash.transform_values!(with_key: true) { |value, key| "#{key}:#{value}" }
Hash#deep_transform_values(with_key: true)Hash#deep_transform_values!(with_key: true)BREAKING:
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.
Before:
hash.transform_values.with_key { |key, value| "#{key}: #{value}" }
After:
hash.transform_values.with_key { |value, key| "#{key}: #{value}" }
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|.
Hash#transform and Hash#transform! for transforming a hash’s keys and values at the same time.Hash#transform_values.with_key to yield |value, key| instead of |key, value| for consistency with Ruby conventions.Hash methods for renaming keys:
#rename_key - Renames a key in the hash while preserving the original order of elements#rename_key! - Same as #rename_key but modifies the hash in place#rename_keys - Renames multiple keys in the hash while preserving the original order of elements#rename_keys! - Same as #rename_keys but modifies the hash in place#rename_key_unordered - Renames a key without preserving element order (faster operation)#rename_key_unordered! - Same as #rename_key_unordered but modifies the hash in placedepth parameter to Hash.new_nested_hash to control nesting behaviorsHash#value_where error when nothing is foundArray#to_or_sentence, creates a sentence with “or” connector between items#with_key method to Hash#transform_values and Hash#transform_values!, grants access to both keys and values during transformationsEnumerable#group_by_key, group an array of hashes by their keysHash#new_nested_hash, creates a new Hash that automatically initializes the value to a hashHash#value_where and Hash#values_where, easily find values in a hash based on key-value conditionscompact_prefix - Removes nil values from the beginning of an arraycompact_suffix - Removes nil values from the end of an arraytrim_nils - Removes nil values from both ends of an arraycompact_blank_prefix - Removes blank values from the beginningcompact_blank_suffix - Removes blank values from the endtrim_blanks - Removes blank values from both endsHash#to_struct on Ruby 3.2 would raise an exception if called on an empty HashSymbol#with_quotes and Symbol#in_quotes
Array#key_map and Array#dig_map for mapping over Hash
with_index: keyword argument to Array#join_map. Defaults to false
Enumerable#join_map
Array#deep_freeze and Hash#deep_freeze to recursively freeze the underlying valueswith_quotes / in_quotes to String
Data definition check for to_istruct
flake.nix to use 3.4#presence support to Module.attr_predicate if ActiveSupport is loaded.ActiveSupport into their own test process. Files that end with _active_support will be tested separately with ActiveSupport loadedStruct support to Module.attr_predicate
Array#join_map method that combines filter_map and join operationsHash#join_map method for consistent interface with Array implementationHash#to_istruct for converting hashes to immutable Data structures (Ruby 3.2+)Hash#to_struct for recursive hash to Struct conversionHash#to_ostruct for recursive hash to OpenStruct conversionModule#attr_predicate for generating boolean accessor methodsOpenStruct with:
blank? and present? methods when ActiveSupport is availablemap and filter_map methodsjoin_map method consistent with Array/Hash implementationsString class with:
to_h and to_a methods for JSON parsing with nil fallback on errorto_istruct, to_ostruct, and to_struct conversion methodseach to each_pair in OpenStruct for better enumerable compatibility