Skip to content

Commit 2619313

Browse files
committed
Rewrite internals, remove Active Support dependency
1 parent c0964ef commit 2619313

File tree

5 files changed

+128
-56
lines changed

5 files changed

+128
-56
lines changed

.ruby-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.1.4

Gemfile.lock

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
PATH
22
remote: .
33
specs:
4-
hash_with_dot_access (1.2.0)
5-
activesupport (>= 5.0.0, < 8.0)
4+
hash_with_dot_access (2.0.0)
65

76
GEM
87
remote: https://rubygems.org/
98
specs:
10-
activesupport (7.0.0)
11-
concurrent-ruby (~> 1.0, >= 1.0.2)
12-
i18n (>= 1.6, < 2)
13-
minitest (>= 5.1)
14-
tzinfo (~> 2.0)
15-
concurrent-ruby (1.1.9)
16-
i18n (1.8.11)
17-
concurrent-ruby (~> 1.0)
18-
minitest (5.15.0)
19-
rake (13.0.6)
20-
tzinfo (2.0.4)
21-
concurrent-ruby (~> 1.0)
9+
rake (13.2.1)
2210

2311
PLATFORMS
2412
ruby
@@ -27,6 +15,3 @@ DEPENDENCIES
2715
bundler
2816
hash_with_dot_access!
2917
rake (~> 13.0)
30-
31-
BUNDLED WITH
32-
2.1.4

hash_with_dot_access.gemspec

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ Gem::Specification.new do |spec|
1717
end
1818
spec.require_paths = ["lib"]
1919

20-
spec.add_runtime_dependency "activesupport", [">= 5.0.0", "< 8.0"]
21-
2220
spec.add_development_dependency "bundler"
2321
spec.add_development_dependency "rake", "~> 13.0"
2422
end

lib/hash_with_dot_access.rb

Lines changed: 124 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,150 @@
1-
require "active_support/core_ext/hash/indifferent_access"
2-
31
module HashWithDotAccess
4-
class Hash < ActiveSupport::HashWithIndifferentAccess
5-
def respond_to_missing?(key, *)
2+
module Utils
3+
def self.normalized_value(obj, value)
4+
return value if value.instance_of?(obj.class)
5+
6+
case value
7+
when ::Hash
8+
obj.class.new(value)
9+
when Array
10+
value = value.dup if value.frozen?
11+
value.map! { normalized_value(obj, _1) }
12+
else
13+
value
14+
end
15+
end
16+
end
17+
18+
class Hash < ::Hash
19+
class << self
20+
undef_method :[]
21+
end
22+
23+
def initialize(hsh = nil)
24+
super
25+
return unless hsh
26+
27+
update(hsh)
28+
self.default_proc = hsh.default_proc
29+
self.default = hsh.default
30+
end
31+
32+
def respond_to_missing?(key, *args)
33+
return false unless args.empty?
34+
635
return true if "#{key}".end_with?("=")
736

837
key?(key)
938
end
1039

11-
def method_missing(key, *args)
12-
if "#{key}".end_with?("=")
13-
self["#{key}".chop] = args.first
40+
def key?(key) = super(key.to_s)
41+
42+
alias_method :has_key?, :key?
43+
alias_method :include?, :key?
44+
alias_method :member?, :key?
45+
46+
# save previous method
47+
alias_method :_assign, :[]=
48+
49+
def [](key) = super(key.to_s)
50+
51+
def []=(key, value)
52+
_assign(key.to_s, Utils.normalized_value(self, value))
53+
end
54+
55+
alias_method :store, :[]=
56+
57+
def fetch(key, *args) = super(key.to_s, *args)
58+
59+
def assoc(key, *args) = super(key.to_s)
60+
61+
def values_at(*keys) = super(*keys.map!(&:to_s))
62+
63+
def fetch_values(*keys) = super(*keys.map!(&:to_s))
64+
65+
def method_missing(method_name, *args)
66+
key = method_name.to_s
67+
if key.end_with?("=")
68+
key_chop = key.chop
69+
self.class.define_method(key) { |value| self[key_chop] = value }
70+
self[key.chop] = args.first
1471
elsif self.key?(key)
72+
self.class.define_method(key) { self[key] }
1573
self[key]
1674
elsif default_proc
75+
super unless args.empty?
1776
default_proc.call(self, key)
1877
else
78+
super unless args.empty?
1979
default
2080
end
2181
end
2282

23-
def update(other_hash)
24-
if other_hash.is_a? HashWithDotAccess::Hash
25-
super(other_hash)
26-
else
27-
other_hash.to_hash.each_pair do |key, value|
28-
if block_given? && key?(key)
29-
value = yield(convert_key(key), self[key], value)
83+
def update(*other_hashes)
84+
other_hashes.each do |other_hash|
85+
if other_hash.is_a? HashWithDotAccess::Hash
86+
super(other_hash)
87+
else
88+
other_hash.to_hash.each do |key, value|
89+
key = key.to_s
90+
if block_given? && key?(key)
91+
value = yield(key, self[key], value)
92+
end
93+
_assign(key, Utils.normalized_value(self, value))
3094
end
31-
regular_writer(convert_key(key), convert_value(value))
3295
end
33-
self
3496
end
97+
98+
self
3599
end
36100

37-
private
101+
alias_method :merge!, :update
38102

39-
def convert_value(value, options = {}) # :doc:
40-
if value.is_a? ::Hash
41-
if options[:for] == :to_hash
42-
value.to_hash
43-
else
44-
value.with_dot_access
45-
end
46-
elsif value.is_a?(Array)
47-
if options[:for] != :assignment || value.frozen?
48-
value = value.dup
49-
end
50-
value.map! { |e| convert_value(e, options) }
51-
else
52-
value
53-
end
103+
def merge(...) = dup.update(...)
104+
105+
def replace(...)
106+
clear
107+
update(...)
108+
end
109+
110+
def dig(*args)
111+
super(args[0].to_s, *args[1..])
112+
end
113+
114+
def delete(key) = super(key.to_s)
115+
116+
def except(*keys) = super(*keys.map!(&:to_s))
117+
118+
def slice(*keys) = self.class.new(super(*keys.map!(&:to_s)))
119+
120+
def select(...)
121+
return to_enum(:select) unless block_given?
122+
123+
dup.tap { _1.select!(...) }
124+
end
125+
126+
def reject(...)
127+
return to_enum(:reject) unless block_given?
128+
129+
dup.tap { _1.reject!(...) }
130+
end
131+
132+
def transform_values(...)
133+
return to_enum(:transform_values) unless block_given?
134+
135+
dup.tap { _1.transform_values!(...) }
136+
end
137+
138+
def compact
139+
dup.tap { _1.compact! }
54140
end
55141
end
56-
end
57142

58-
class Hash
59-
def with_dot_access
60-
HashWithDotAccess::Hash.new(self)
143+
module Refinements
144+
refine ::Hash do
145+
def as_dots
146+
HashWithDotAccess::Hash.new(self)
147+
end
148+
end
61149
end
62150
end

lib/hash_with_dot_access/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module HashWithDotAccess
2-
VERSION = "1.2.0"
2+
VERSION = "2.0.0"
33
end

0 commit comments

Comments
 (0)