otoindiff 0.1.0 → 0.2.1
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 +18 -0
- data/README.md +32 -0
- data/Rakefile +8 -0
- data/bin/benchmark +9 -0
- data/lib/otoindiff/disabled.rb +43 -0
- data/lib/otoindiff/version.rb +1 -1
- data/lib/otoindiff.rb +25 -33
- data/sig/otoindiff.rbs +4 -0
- metadata +7 -22
- /data/benchmarks/{oto_benchmarks.rb → benchmark.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1aabb24819d8d4ac57b6694ac105527a9a9cf4b8faff156130928a635e288a91
|
|
4
|
+
data.tar.gz: 6c7bc3fbb207a33667448fb2af8223ab1562a00895f0940fca148cc12edfd92d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c370cca113c9e7e0120a866dcfbc9ce92637488d06338c0623bccb7ddbfe58a9afd8af1d7e31bb0e598fb2585053263beb820d3acf7571608966e47e00a910a6
|
|
7
|
+
data.tar.gz: 6c16fa6b2b110ea8ab20475fa6c1ddd5c81e5da003d2a6be201cf63e43fc301bc94d779c70b44f0f744ffa62d25eb8fcdf99046bd943860b8a2913f5fc4ad922
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.2.1] - 2026-10-15
|
|
4
|
+
|
|
5
|
+
- Fix `dig` raising `NoMethodError` instead of Ruby's `TypeError` when the path
|
|
6
|
+
continues past a value that has no `#dig` (e.g. `{ a: 1 }.dig(:a, :x)`), both
|
|
7
|
+
globally and under `using Otoindiff::Disabled`.
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-10-15
|
|
10
|
+
|
|
11
|
+
- Add `Otoindiff::Disabled` refinement to opt a single class out of indifferent
|
|
12
|
+
access (`using Otoindiff::Disabled`) while the rest of the code base keeps it.
|
|
13
|
+
- Fix i18n lookups always returning "Translation missing": hashes with a default proc
|
|
14
|
+
(such as the i18n backend's translations store) now receive the caller's key instead
|
|
15
|
+
of a converted one, so entries are no longer stored under the wrong key type.
|
|
16
|
+
- Fix `fetch` with a default value or block ignoring a key stored as the other type
|
|
17
|
+
(`{ foo: 1 }.fetch('foo', 0)` now returns `1`).
|
|
18
|
+
- Fix `dig` returning `nil` when traversing into arrays or other non-Hash objects.
|
|
19
|
+
- Fix `false` values being returned as `nil` when accessed with the other key type.
|
|
20
|
+
|
|
3
21
|
## [0.1.0] - 2024-12-12
|
|
4
22
|
|
|
5
23
|
- Initial release
|
data/README.md
CHANGED
|
@@ -15,3 +15,35 @@ Add this line to your application's Gemfile:
|
|
|
15
15
|
```ruby
|
|
16
16
|
gem 'otoindiff'
|
|
17
17
|
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Requiring the gem enables indifferent access for every `Hash`:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
hash = { foo: 'bar', 'baz' => 'qux' }
|
|
25
|
+
hash['foo'] # => "bar"
|
|
26
|
+
hash[:baz] # => "qux"
|
|
27
|
+
hash.fetch('foo') # => "bar"
|
|
28
|
+
hash.dig('foo') # => "bar"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Opting a class out
|
|
32
|
+
|
|
33
|
+
To keep plain Hash behaviour in a single class, activate the
|
|
34
|
+
`Otoindiff::Disabled` refinement inside it. The rest of the code base stays
|
|
35
|
+
indifferent:
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
class StrictParser
|
|
39
|
+
using Otoindiff::Disabled
|
|
40
|
+
|
|
41
|
+
def call(hash)
|
|
42
|
+
hash['foo'] # => nil for { foo: 'bar' }; only the String key matches
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Refinements are lexical: they apply to `[]`, `fetch` and `dig` calls written
|
|
48
|
+
inside that class body, not to hashes the class hands to other code.
|
|
49
|
+
|
data/Rakefile
CHANGED
data/bin/benchmark
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Otoindiff
|
|
4
|
+
# Refinement that restores plain Hash key access where it is activated.
|
|
5
|
+
#
|
|
6
|
+
# otoindiff is enabled globally on require. Activate this refinement in a
|
|
7
|
+
# class (or file) that needs strict String/Symbol key distinction; Hash calls
|
|
8
|
+
# written lexically inside it bypass the indifferent lookup.
|
|
9
|
+
#
|
|
10
|
+
# @example Opt a single class out
|
|
11
|
+
# class StrictParser
|
|
12
|
+
# using Otoindiff::Disabled
|
|
13
|
+
#
|
|
14
|
+
# def call(hash)
|
|
15
|
+
# hash['foo'] # only matches the String key 'foo'
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
module Disabled
|
|
19
|
+
refine Hash do
|
|
20
|
+
def [](key)
|
|
21
|
+
original_brackets(key)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def fetch(key, *args, &block)
|
|
25
|
+
original_fetch(key, *args, &block)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Native #dig (on Hash, Array, Struct) dispatches to the globally patched
|
|
29
|
+
# Hash#dig of nested hashes, so walk the path one key at a time to keep
|
|
30
|
+
# every level strict.
|
|
31
|
+
def dig(key, *rest)
|
|
32
|
+
[key, *rest].reduce(self) do |current, k|
|
|
33
|
+
break nil if current.nil?
|
|
34
|
+
|
|
35
|
+
next current.original_brackets(k) if current.is_a?(Hash)
|
|
36
|
+
raise TypeError, "#{current.class} does not have #dig method" unless current.respond_to?(:dig)
|
|
37
|
+
|
|
38
|
+
current.dig(k)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/otoindiff/version.rb
CHANGED
data/lib/otoindiff.rb
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'otoindiff/version'
|
|
4
4
|
|
|
5
|
-
require 'active_support'
|
|
6
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
|
7
|
-
|
|
8
5
|
# Extends Ruby's Hash class with more flexible key access methods
|
|
9
6
|
#
|
|
10
7
|
# This extension provides enhanced hash key lookup capabilities:
|
|
@@ -27,33 +24,22 @@ class Hash
|
|
|
27
24
|
# Retrieve a hash value with flexible key type conversion
|
|
28
25
|
#
|
|
29
26
|
# @param key [Object] The key to retrieve
|
|
30
|
-
# @return [Object, nil] The value associated with the key, or
|
|
27
|
+
# @return [Object, nil] The value associated with the key, or the hash's default if not found
|
|
31
28
|
def [](key)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if key.is_a?(String) || key.is_a?(Symbol)
|
|
35
|
-
original_brackets(key.to_s) || original_brackets(key.to_sym)
|
|
36
|
-
else
|
|
37
|
-
original_brackets(key)
|
|
38
|
-
end
|
|
29
|
+
original_brackets(otoindiff_key(key))
|
|
39
30
|
end
|
|
40
31
|
|
|
41
32
|
# Dig into a nested hash with flexible key type conversion
|
|
42
33
|
#
|
|
43
|
-
# @param
|
|
34
|
+
# @param key [Object] The first key to retrieve
|
|
35
|
+
# @param rest [Array<Object>] Remaining path of keys, passed on to the nested object's #dig
|
|
44
36
|
# @return [Object, nil] The nested value, or nil if path is invalid
|
|
45
|
-
def dig(*
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
def dig(key, *rest)
|
|
38
|
+
value = self[key]
|
|
39
|
+
return value if rest.empty? || value.nil?
|
|
40
|
+
raise TypeError, "#{value.class} does not have #dig method" unless value.respond_to?(:dig)
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
current.original_brackets(key) ||
|
|
51
|
-
current.original_brackets(key.to_s) ||
|
|
52
|
-
current.original_brackets(key.to_sym)
|
|
53
|
-
else
|
|
54
|
-
current.original_brackets(key)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
42
|
+
value.dig(*rest)
|
|
57
43
|
end
|
|
58
44
|
|
|
59
45
|
# Fetch a hash value with flexible key type conversion and error handling
|
|
@@ -63,16 +49,22 @@ class Hash
|
|
|
63
49
|
# @return [Object] The value associated with the key
|
|
64
50
|
# @raise [KeyError] If key is not found and no default is provided
|
|
65
51
|
def fetch(key, *args, &block)
|
|
66
|
-
|
|
52
|
+
original_fetch(otoindiff_key(key), *args, &block)
|
|
53
|
+
end
|
|
67
54
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# Resolve a String/Symbol key to whichever form is actually stored.
|
|
58
|
+
# Falls back to the caller's key so defaults and default procs receive it unchanged.
|
|
59
|
+
def otoindiff_key(key)
|
|
60
|
+
return key if key?(key)
|
|
61
|
+
|
|
62
|
+
alt = case key
|
|
63
|
+
when String then key.to_sym
|
|
64
|
+
when Symbol then key.to_s
|
|
65
|
+
end
|
|
66
|
+
alt && key?(alt) ? alt : key
|
|
77
67
|
end
|
|
78
68
|
end
|
|
69
|
+
|
|
70
|
+
require_relative 'otoindiff/disabled'
|
data/sig/otoindiff.rbs
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
module Otoindiff
|
|
2
2
|
VERSION: String
|
|
3
3
|
|
|
4
|
+
# Refinement restoring plain Hash key access where activated with `using`
|
|
5
|
+
module Disabled
|
|
6
|
+
end
|
|
7
|
+
|
|
4
8
|
# Extended methods for Hash class with flexible key access
|
|
5
9
|
module HashExtensions
|
|
6
10
|
# Retrieve a value with flexible key type conversion
|
metadata
CHANGED
|
@@ -1,29 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: otoindiff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- bugloper
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: activesupport
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - "~>"
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '8.0'
|
|
20
|
-
type: :runtime
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - "~>"
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: '8.0'
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
27
12
|
description: The otoindiff gem modifies all Ruby Hash objects to support indifferent
|
|
28
13
|
access by default, allowing seamless use of string or symbol keys interchangeably.
|
|
29
14
|
email:
|
|
@@ -35,11 +20,13 @@ files:
|
|
|
35
20
|
- CHANGELOG.md
|
|
36
21
|
- README.md
|
|
37
22
|
- Rakefile
|
|
38
|
-
- benchmarks/
|
|
23
|
+
- benchmarks/benchmark.rb
|
|
24
|
+
- bin/benchmark
|
|
39
25
|
- bin/console
|
|
40
26
|
- bin/release
|
|
41
27
|
- bin/setup
|
|
42
28
|
- lib/otoindiff.rb
|
|
29
|
+
- lib/otoindiff/disabled.rb
|
|
43
30
|
- lib/otoindiff/version.rb
|
|
44
31
|
- sig/otoindiff.rbs
|
|
45
32
|
homepage: https://github.com/bugloper/otoindiff
|
|
@@ -50,7 +37,6 @@ metadata:
|
|
|
50
37
|
source_code_uri: https://github.com/bugloper/otoindiff
|
|
51
38
|
changelog_uri: https://github.com/bugloper/otoindiff/blob/main/CHANGELOG.md
|
|
52
39
|
rubygems_mfa_required: 'false'
|
|
53
|
-
post_install_message:
|
|
54
40
|
rdoc_options: []
|
|
55
41
|
require_paths:
|
|
56
42
|
- lib
|
|
@@ -65,8 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
65
51
|
- !ruby/object:Gem::Version
|
|
66
52
|
version: '0'
|
|
67
53
|
requirements: []
|
|
68
|
-
rubygems_version:
|
|
69
|
-
signing_key:
|
|
54
|
+
rubygems_version: 4.0.16
|
|
70
55
|
specification_version: 4
|
|
71
56
|
summary: Enhances Ruby hashes with default indifferent access.
|
|
72
57
|
test_files: []
|
|
File without changes
|