resource-struct 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -1
- data/CHANGELOG.md +18 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +75 -37
- data/README.md +3 -3
- data/lib/resource_struct/extensions/indifferent_lookup.rb +47 -34
- data/lib/resource_struct/flex_struct.rb +1 -12
- data/lib/resource_struct/strict_struct.rb +8 -1
- data/lib/resource_struct/version.rb +1 -1
- metadata +6 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dbe0071df5f0b590203edc5208102dd5f8f8436ef41525067b3c3e740b84357e
|
|
4
|
+
data.tar.gz: 267154989b507ecd1ce651682d17437275721c64c24533ea201a73e7892a03a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb4d3626e03fd029e8305c4adc635f5e8b361dc468caa4d84167079b57e7916bbe7a3f2d0b83d29eefb45a0e4f89c7c8859eaf8f35141e338742b5f8119dcf44
|
|
7
|
+
data.tar.gz: 8f1b47a618fefc03bea375c50bf7030fc2b4dcb0efa1f6ca5f98c11156a2d60b9c65411de7cbd8e6c9388dbcfc62a9736a167fd17367b095d84c2162baeafc30
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-07-03
|
|
4
|
+
### Breaking
|
|
5
|
+
- Symbol hash keys are now canonicalized to strings internally. This means:
|
|
6
|
+
- `Struct#to_h`, `#to_hash`, and `#inspect` return string keys even when the input hash used symbols.
|
|
7
|
+
- Hashes containing both a symbol and string key for the same logical property (e.g. `{ foo: 1, "foo" => 2 }`) will keep only one value after canonicalization.
|
|
8
|
+
- Marshalled data from previous versions that used symbol keys will load with string keys.
|
|
9
|
+
- Raised minimum Ruby version to 3.3.
|
|
10
|
+
- `StrictStruct#to_h` / `#to_hash` now return a shallow copy instead of the internal mutable hash.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Canonicalize symbol keys to strings internally so symbol/string key collisions are handled consistently and cached nested structs have stable identity.
|
|
14
|
+
- README typos (`ResouceStruct`) and GitHub URL placeholder.
|
|
15
|
+
- Removed unused `bindir` / `executables` configuration from the gemspec.
|
|
16
|
+
- Fixed GitHub Actions pull_request trigger so pushes to PR branches (including force pushes) re-run CI.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Updated RuboCop and CI to current Ruby versions (3.3, 3.4, 4.0) and action versions.
|
|
20
|
+
|
|
3
21
|
## [0.4.0] - 2022-01-09
|
|
4
22
|
### Feature
|
|
5
23
|
- Better support for `ArgumentError` on `FlexStruct`
|
data/Gemfile
CHANGED
|
@@ -5,10 +5,11 @@ source "https://rubygems.org"
|
|
|
5
5
|
# Specify your gem's dependencies in resource-struct.gemspec
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
|
-
gem "
|
|
8
|
+
gem "irb"
|
|
9
|
+
gem "rake", "~> 13.2"
|
|
9
10
|
|
|
10
11
|
gem "rspec", "~> 3.0"
|
|
11
12
|
|
|
12
|
-
gem "rubocop", "~> 1.
|
|
13
|
+
gem "rubocop", "~> 1.75"
|
|
13
14
|
gem "rubocop-rake"
|
|
14
15
|
gem "rubocop-rspec"
|
data/Gemfile.lock
CHANGED
|
@@ -1,61 +1,99 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
resource-struct (0.
|
|
4
|
+
resource-struct (0.5.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
|
-
ast (2.4.
|
|
10
|
-
diff-lcs (1.
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
ast (2.4.3)
|
|
10
|
+
diff-lcs (1.6.2)
|
|
11
|
+
erb (6.0.4)
|
|
12
|
+
io-console (0.8.2)
|
|
13
|
+
irb (1.18.0)
|
|
14
|
+
pp (>= 0.6.0)
|
|
15
|
+
prism (>= 1.3.0)
|
|
16
|
+
rdoc (>= 4.0.0)
|
|
17
|
+
reline (>= 0.4.2)
|
|
18
|
+
json (2.20.0)
|
|
19
|
+
language_server-protocol (3.17.0.6)
|
|
20
|
+
lint_roller (1.1.0)
|
|
21
|
+
logger (1.7.0)
|
|
22
|
+
parallel (2.1.0)
|
|
23
|
+
parser (3.3.11.1)
|
|
13
24
|
ast (~> 2.4.1)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
racc
|
|
26
|
+
pp (0.6.4)
|
|
27
|
+
prettyprint
|
|
28
|
+
prettyprint (0.2.0)
|
|
29
|
+
prism (1.9.0)
|
|
30
|
+
racc (1.8.1)
|
|
31
|
+
rainbow (3.1.1)
|
|
32
|
+
rake (13.4.2)
|
|
33
|
+
rbs (4.0.3)
|
|
34
|
+
logger
|
|
35
|
+
prism (>= 1.6.0)
|
|
36
|
+
tsort
|
|
37
|
+
rdoc (8.0.0)
|
|
38
|
+
erb
|
|
39
|
+
prism (>= 1.6.0)
|
|
40
|
+
rbs (>= 4.0.0)
|
|
41
|
+
tsort
|
|
42
|
+
regexp_parser (2.12.0)
|
|
43
|
+
reline (0.6.3)
|
|
44
|
+
io-console (~> 0.5)
|
|
45
|
+
rspec (3.13.2)
|
|
46
|
+
rspec-core (~> 3.13.0)
|
|
47
|
+
rspec-expectations (~> 3.13.0)
|
|
48
|
+
rspec-mocks (~> 3.13.0)
|
|
49
|
+
rspec-core (3.13.6)
|
|
50
|
+
rspec-support (~> 3.13.0)
|
|
51
|
+
rspec-expectations (3.13.5)
|
|
25
52
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
26
|
-
rspec-support (~> 3.
|
|
27
|
-
rspec-mocks (3.
|
|
53
|
+
rspec-support (~> 3.13.0)
|
|
54
|
+
rspec-mocks (3.13.8)
|
|
28
55
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
29
|
-
rspec-support (~> 3.
|
|
30
|
-
rspec-support (3.
|
|
31
|
-
rubocop (1.
|
|
32
|
-
|
|
33
|
-
|
|
56
|
+
rspec-support (~> 3.13.0)
|
|
57
|
+
rspec-support (3.13.7)
|
|
58
|
+
rubocop (1.88.1)
|
|
59
|
+
json (~> 2.3)
|
|
60
|
+
language_server-protocol (~> 3.17.0.2)
|
|
61
|
+
lint_roller (~> 1.1.0)
|
|
62
|
+
parallel (>= 1.10)
|
|
63
|
+
parser (>= 3.3.0.2)
|
|
34
64
|
rainbow (>= 2.2.2, < 4.0)
|
|
35
|
-
regexp_parser (>=
|
|
36
|
-
|
|
37
|
-
rubocop-ast (>= 1.12.0, < 2.0)
|
|
65
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
66
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
38
67
|
ruby-progressbar (~> 1.7)
|
|
39
|
-
unicode-display_width (>=
|
|
40
|
-
rubocop-ast (1.
|
|
41
|
-
parser (>= 3.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
rubocop (
|
|
46
|
-
|
|
47
|
-
|
|
68
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
69
|
+
rubocop-ast (1.49.1)
|
|
70
|
+
parser (>= 3.3.7.2)
|
|
71
|
+
prism (~> 1.7)
|
|
72
|
+
rubocop-rake (0.7.1)
|
|
73
|
+
lint_roller (~> 1.1)
|
|
74
|
+
rubocop (>= 1.72.1)
|
|
75
|
+
rubocop-rspec (3.10.2)
|
|
76
|
+
lint_roller (~> 1.1)
|
|
77
|
+
regexp_parser (>= 2.0)
|
|
78
|
+
rubocop (~> 1.86, >= 1.86.2)
|
|
79
|
+
ruby-progressbar (1.13.0)
|
|
80
|
+
tsort (0.2.0)
|
|
81
|
+
unicode-display_width (3.2.0)
|
|
82
|
+
unicode-emoji (~> 4.1)
|
|
83
|
+
unicode-emoji (4.2.0)
|
|
48
84
|
|
|
49
85
|
PLATFORMS
|
|
86
|
+
arm64-darwin-25
|
|
50
87
|
x86_64-darwin-18
|
|
51
88
|
x86_64-darwin-19
|
|
52
89
|
x86_64-linux
|
|
53
90
|
|
|
54
91
|
DEPENDENCIES
|
|
55
|
-
|
|
92
|
+
irb
|
|
93
|
+
rake (~> 13.2)
|
|
56
94
|
resource-struct!
|
|
57
95
|
rspec (~> 3.0)
|
|
58
|
-
rubocop (~> 1.
|
|
96
|
+
rubocop (~> 1.75)
|
|
59
97
|
rubocop-rake
|
|
60
98
|
rubocop-rspec
|
|
61
99
|
|
data/README.md
CHANGED
|
@@ -7,11 +7,11 @@ This is a gem for working with JSON resources from a network source with indiffe
|
|
|
7
7
|
Instead of overriding Hash implementation, this wraps a Hash with indifferent access (by symbol or string keys).
|
|
8
8
|
This makes it fast at runtime, while still providing the necessary lookup method of choice.
|
|
9
9
|
|
|
10
|
-
There are two types `
|
|
10
|
+
There are two types `ResourceStruct::StrictStruct` and `ResourceStruct::FlexStruct`.
|
|
11
11
|
|
|
12
12
|
`ResourceStruct::StrictStruct` provides a way of wrapping a Hash such that accesses to invalid keys will raise an exception through the method lookup method; it also is immutable.
|
|
13
13
|
|
|
14
|
-
`
|
|
14
|
+
`ResourceStruct::FlexStruct` provides a way of wrapping a Hash such that it returns nil instead of raising an exception when the key is not present in the hash.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -71,7 +71,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
|
71
71
|
|
|
72
72
|
## Contributing
|
|
73
73
|
|
|
74
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
|
74
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/AlexRiedler/resource-struct.
|
|
75
75
|
|
|
76
76
|
## License
|
|
77
77
|
|
|
@@ -13,10 +13,11 @@ module ResourceStruct
|
|
|
13
13
|
def_delegators :@hash, :to_h, :to_hash, :to_s, :as_json, :to_json
|
|
14
14
|
|
|
15
15
|
def initialize(hash = {})
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
hash = {} if hash.nil?
|
|
17
|
+
raise ::ArgumentError, "first argument must be a Hash, found #{hash.class.name}" unless hash.is_a?(Hash)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
@hash = ___canonicalize_hash(hash)
|
|
20
|
+
@ro_struct = {}
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def inspect
|
|
@@ -24,24 +25,23 @@ module ResourceStruct
|
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def ==(other)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
other_hash = case other
|
|
29
|
+
when Hash then other
|
|
30
|
+
when LooseStruct, FirmStruct then other.instance_variable_get(:@hash)
|
|
31
|
+
else return false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
___all_keys_equal(other_hash)
|
|
30
35
|
end
|
|
31
36
|
|
|
32
37
|
def dig(key, *sub_keys)
|
|
33
38
|
ckey = ___convert_key(key)
|
|
34
39
|
|
|
35
|
-
result =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
elsif key.is_a?(String) && @hash.key?(key.to_sym)
|
|
41
|
-
@ro_struct[ckey] = ___convert_value(@hash[key.to_sym])
|
|
42
|
-
elsif key.is_a?(Symbol) && @hash.key?(key.to_s)
|
|
43
|
-
@ro_struct[ckey] = ___convert_value(@hash[key.to_s])
|
|
44
|
-
end
|
|
40
|
+
result = if @ro_struct.key?(ckey)
|
|
41
|
+
@ro_struct[ckey]
|
|
42
|
+
elsif @hash.key?(ckey)
|
|
43
|
+
@ro_struct[ckey] = ___convert_value(@hash[ckey])
|
|
44
|
+
end
|
|
45
45
|
|
|
46
46
|
return result if sub_keys.empty?
|
|
47
47
|
|
|
@@ -54,18 +54,35 @@ module ResourceStruct
|
|
|
54
54
|
alias [] dig
|
|
55
55
|
|
|
56
56
|
def marshal_dump
|
|
57
|
-
{
|
|
58
|
-
data: @hash
|
|
59
|
-
}
|
|
57
|
+
{ data: @hash }
|
|
60
58
|
end
|
|
61
59
|
|
|
62
60
|
def marshal_load(obj)
|
|
63
61
|
@ro_struct = {}
|
|
64
|
-
@hash = obj[:data]
|
|
62
|
+
@hash = ___canonicalize_hash(obj[:data] || {})
|
|
65
63
|
end
|
|
66
64
|
|
|
67
65
|
private
|
|
68
66
|
|
|
67
|
+
def ___canonicalize_hash(hash)
|
|
68
|
+
hash.each_with_object({}) do |(key, value), memo|
|
|
69
|
+
memo[___convert_key(key)] = ___canonicalize_value(value)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def ___canonicalize_value(value)
|
|
74
|
+
case value
|
|
75
|
+
when LooseStruct, FirmStruct
|
|
76
|
+
value.instance_variable_get(:@hash)
|
|
77
|
+
when ::Array
|
|
78
|
+
value.map { |v| ___canonicalize_value(v) }
|
|
79
|
+
when Hash
|
|
80
|
+
___canonicalize_hash(value)
|
|
81
|
+
else
|
|
82
|
+
value
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
69
86
|
def ___convert_value(value)
|
|
70
87
|
case value
|
|
71
88
|
when ::Array
|
|
@@ -78,9 +95,7 @@ module ResourceStruct
|
|
|
78
95
|
end
|
|
79
96
|
|
|
80
97
|
def ___key?(key)
|
|
81
|
-
@hash.key?(key)
|
|
82
|
-
@hash.key?(___convert_key(key)) ||
|
|
83
|
-
key.is_a?(String) && @hash.key?(key.to_sym)
|
|
98
|
+
@hash.key?(___convert_key(key))
|
|
84
99
|
end
|
|
85
100
|
|
|
86
101
|
def ___convert_key(key)
|
|
@@ -90,17 +105,15 @@ module ResourceStruct
|
|
|
90
105
|
def ___all_keys_equal(other)
|
|
91
106
|
return false unless @hash.count == other.count
|
|
92
107
|
|
|
93
|
-
@hash.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
acc && other.key?(ck) && value == other[ck]
|
|
103
|
-
end
|
|
108
|
+
@hash.all? do |k, _|
|
|
109
|
+
other_value = if other.key?(k)
|
|
110
|
+
other[k]
|
|
111
|
+
elsif k.is_a?(String) && other.key?(k.to_sym)
|
|
112
|
+
other[k.to_sym]
|
|
113
|
+
else
|
|
114
|
+
return false
|
|
115
|
+
end
|
|
116
|
+
self[k] == other_value
|
|
104
117
|
end
|
|
105
118
|
end
|
|
106
119
|
end
|
|
@@ -22,18 +22,7 @@ module ResourceStruct
|
|
|
22
22
|
def []=(key, value)
|
|
23
23
|
ckey = ___convert_key(key)
|
|
24
24
|
@ro_struct.delete(ckey)
|
|
25
|
-
|
|
26
|
-
value = value.instance_variable_get(:@hash) if value.is_a?(FlexStruct) || value.is_a?(StrictStruct)
|
|
27
|
-
|
|
28
|
-
if @hash.key?(key)
|
|
29
|
-
@hash[key] = value
|
|
30
|
-
elsif key.is_a?(String) && @hash.key?(key.to_sym)
|
|
31
|
-
@hash[key.to_sym] = value
|
|
32
|
-
elsif key.is_a?(Symbol) && @hash.key?(key.to_s)
|
|
33
|
-
@hash[key.to_s] = value
|
|
34
|
-
else
|
|
35
|
-
@hash[key] = value
|
|
36
|
-
end
|
|
25
|
+
@hash[ckey] = ___canonicalize_value(value)
|
|
37
26
|
end
|
|
38
27
|
|
|
39
28
|
def method_missing(name, *args)
|
|
@@ -22,7 +22,14 @@ module ResourceStruct
|
|
|
22
22
|
class StrictStruct
|
|
23
23
|
include ::ResourceStruct::Extensions::IndifferentLookup
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
# StrictStruct is documented as immutable. Return a shallow copy so callers
|
|
26
|
+
# cannot mutate the internal canonicalized hash through #to_h / #to_hash.
|
|
27
|
+
def to_h
|
|
28
|
+
@hash.dup
|
|
29
|
+
end
|
|
30
|
+
alias to_hash to_h
|
|
31
|
+
|
|
32
|
+
def method_missing(name, *args, &)
|
|
26
33
|
args_length = args.length
|
|
27
34
|
return self[name] if ___key?(name) && args_length.zero?
|
|
28
35
|
return !!self[name[...-1]] if name.end_with?("?") && args_length.zero?
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: resource-struct
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Riedler
|
|
8
|
-
|
|
9
|
-
bindir: exe
|
|
8
|
+
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
12
|
description: Openstruct like access without all the headaches of Hash method overrides
|
|
14
13
|
etc...
|
|
@@ -41,7 +40,7 @@ metadata:
|
|
|
41
40
|
homepage_uri: https://github.com/AlexRiedler/resource-struct
|
|
42
41
|
source_code_uri: https://github.com/AlexRiedler/resource-struct
|
|
43
42
|
changelog_uri: https://raw.githubusercontent.com/AlexRiedler/resource-struct/master/CHANGELOG.md
|
|
44
|
-
|
|
43
|
+
rubygems_mfa_required: 'true'
|
|
45
44
|
rdoc_options: []
|
|
46
45
|
require_paths:
|
|
47
46
|
- lib
|
|
@@ -49,15 +48,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
49
48
|
requirements:
|
|
50
49
|
- - ">="
|
|
51
50
|
- !ruby/object:Gem::Version
|
|
52
|
-
version:
|
|
51
|
+
version: 3.3.0
|
|
53
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
53
|
requirements:
|
|
55
54
|
- - ">="
|
|
56
55
|
- !ruby/object:Gem::Version
|
|
57
56
|
version: '0'
|
|
58
57
|
requirements: []
|
|
59
|
-
rubygems_version:
|
|
60
|
-
signing_key:
|
|
58
|
+
rubygems_version: 4.0.15
|
|
61
59
|
specification_version: 4
|
|
62
60
|
summary: Ruby structs for resource responses
|
|
63
61
|
test_files: []
|