Skip to content

Commit 6093281

Browse files
authored
Merge pull request rails#50151 from kmcphillips/inheritable-options-hash-behaviour
Improve `ActiveSupport::InheritableOptions` hash-like behaviour
2 parents ed2bc92 + 9b03df5 commit 6093281

File tree

4 files changed

+177
-8
lines changed

4 files changed

+177
-8
lines changed

activesupport/lib/active_support/ordered_options.rb

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,52 @@ def inspect
9292
# h.boy # => 'John'
9393
class InheritableOptions < OrderedOptions
9494
def initialize(parent = nil)
95-
if parent.kind_of?(OrderedOptions)
95+
@parent = parent
96+
if @parent.kind_of?(OrderedOptions)
9697
# use the faster _get when dealing with OrderedOptions
97-
super() { |h, k| parent._get(k) }
98-
elsif parent
99-
super() { |h, k| parent[k] }
98+
super() { |h, k| @parent._get(k) }
99+
elsif @parent
100+
super() { |h, k| @parent[k] }
100101
else
101102
super()
103+
@parent = {}
102104
end
103105
end
104106

107+
def to_h
108+
@parent.merge(self)
109+
end
110+
111+
def ==(other)
112+
to_h == other.to_h
113+
end
114+
115+
def inspect
116+
"#<#{self.class.name} #{to_h.inspect}>"
117+
end
118+
119+
alias_method :own_key?, :key?
120+
private :own_key?
121+
122+
def key?(key)
123+
super || @parent.key?(key)
124+
end
125+
126+
def overridden?(key)
127+
!!(@parent && @parent.key?(key) && own_key?(key.to_sym))
128+
end
129+
105130
def inheritable_copy
106131
self.class.new(self)
107132
end
133+
134+
def to_a
135+
entries
136+
end
137+
138+
def each(&block)
139+
to_h.each(&block)
140+
self
141+
end
108142
end
109143
end

activesupport/test/ordered_options_test.rb

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def test_inheritable_options_with_bang
134134
assert_raises(KeyError) { a.non_existing_key! }
135135
end
136136

137-
def test_inspect
137+
def test_ordered_option_inspect
138138
a = ActiveSupport::OrderedOptions.new
139139
assert_equal "#<ActiveSupport::OrderedOptions {}>", a.inspect
140140

@@ -143,4 +143,139 @@ def test_inspect
143143

144144
assert_equal "#<ActiveSupport::OrderedOptions {:foo=>:bar, :baz=>:quz}>", a.inspect
145145
end
146+
147+
def test_inheritable_option_inspect
148+
object = ActiveSupport::InheritableOptions.new(one: "first value")
149+
assert_equal "#<ActiveSupport::InheritableOptions {:one=>\"first value\"}>", object.inspect
150+
151+
object[:two] = "second value"
152+
object["three"] = "third value"
153+
assert_equal "#<ActiveSupport::InheritableOptions {:one=>\"first value\", :two=>\"second value\", :three=>\"third value\"}>", object.inspect
154+
end
155+
156+
def test_ordered_options_to_h
157+
object = ActiveSupport::OrderedOptions.new
158+
assert_equal({}, object.to_h)
159+
object.one = "first value"
160+
object[:two] = "second value"
161+
object["three"] = "third value"
162+
163+
assert_equal({ one: "first value", two: "second value", three: "third value" }, object.to_h)
164+
end
165+
166+
def test_inheritable_options_to_h
167+
object = ActiveSupport::InheritableOptions.new(one: "first value")
168+
assert_equal({ one: "first value" }, object.to_h)
169+
170+
object[:two] = "second value"
171+
object["three"] = "third value"
172+
173+
assert_equal({ one: "first value", two: "second value", three: "third value" }, object.to_h)
174+
end
175+
176+
def test_ordered_options_dup
177+
object = ActiveSupport::OrderedOptions.new
178+
object.one = "first value"
179+
object[:two] = "second value"
180+
object["three"] = "third value"
181+
182+
duplicate = object.dup
183+
assert_equal object, duplicate
184+
assert_not_equal object.object_id, duplicate.object_id
185+
end
186+
187+
def test_inheritable_options_dup
188+
object = ActiveSupport::InheritableOptions.new(one: "first value")
189+
object[:two] = "second value"
190+
object["three"] = "third value"
191+
192+
duplicate = object.dup
193+
assert_equal object, duplicate
194+
assert_not_equal object.object_id, duplicate.object_id
195+
end
196+
197+
def test_ordered_options_key
198+
object = ActiveSupport::OrderedOptions.new
199+
object.one = "first value"
200+
object[:two] = "second value"
201+
object["three"] = "third value"
202+
203+
assert object.key?(:one)
204+
assert_not object.key?("one")
205+
assert object.key?(:two)
206+
assert_not object.key?("two")
207+
assert object.key?(:three)
208+
assert_not object.key?("three")
209+
assert_not object.key?(:four)
210+
end
211+
212+
def test_inheritable_options_key
213+
object = ActiveSupport::InheritableOptions.new(one: "first value")
214+
object[:two] = "second value"
215+
object["three"] = "third value"
216+
217+
assert object.key?(:one)
218+
assert_not object.key?("one")
219+
assert object.key?(:two)
220+
assert_not object.key?("two")
221+
assert object.key?(:three)
222+
assert_not object.key?("three")
223+
assert_not object.key?(:four)
224+
end
225+
226+
def test_inheritable_options_overridden
227+
object = ActiveSupport::InheritableOptions.new(one: "first value", two: "second value", three: "third value")
228+
object["one"] = "first value override"
229+
object[:two] = "second value override"
230+
231+
assert object.overridden?(:one)
232+
assert_equal "first value override", object.one
233+
assert object.overridden?(:two)
234+
assert_equal "second value override", object.two
235+
assert_not object.overridden?(:three)
236+
assert_equal "third value", object.three
237+
end
238+
239+
def test_inheritable_options_overridden_with_nil
240+
object = ActiveSupport::InheritableOptions.new
241+
object["one"] = "first value override"
242+
object[:two] = "second value override"
243+
244+
assert_not object.overridden?(:one)
245+
assert_equal "first value override", object.one
246+
assert_not object.overridden?(:two)
247+
assert_equal "second value override", object.two
248+
end
249+
250+
def test_inheritable_options_each
251+
object = ActiveSupport::InheritableOptions.new(one: "first value", two: "second value")
252+
object["one"] = "first value override"
253+
object[:three] = "third value"
254+
255+
count = 0
256+
keys = []
257+
object.each do |key, value|
258+
count += 1
259+
keys << key
260+
end
261+
assert_equal 3, count
262+
assert_equal [:one, :two, :three], keys
263+
end
264+
265+
def test_inheritable_options_to_a
266+
object = ActiveSupport::InheritableOptions.new(one: "first value", two: "second value")
267+
object["one"] = "first value override"
268+
object[:three] = "third value"
269+
270+
assert_equal [[:one, "first value override"], [:two, "second value"], [:three, "third value"]], object.entries
271+
assert_equal [[:one, "first value override"], [:two, "second value"], [:three, "third value"]], object.to_a
272+
end
273+
274+
def test_inheritable_options_count
275+
object = ActiveSupport::InheritableOptions.new(one: "first value", two: "second value")
276+
object["one"] = "first value override"
277+
object[:three] = "third value"
278+
279+
assert_equal 3, object.count
280+
end
146281
end

railties/lib/rails/commands/credentials/credentials_command.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ def edit
2020
load_generators
2121

2222
if environment_specified?
23-
@content_path = "config/credentials/#{environment}.yml.enc" unless config.key?(:content_path)
24-
@key_path = "config/credentials/#{environment}.key" unless config.key?(:key_path)
23+
@content_path = "config/credentials/#{environment}.yml.enc" unless config.overridden?(:content_path)
24+
@key_path = "config/credentials/#{environment}.key" unless config.overridden?(:key_path)
2525
end
2626

2727
ensure_encryption_key_has_been_added

railties/test/application/configuration_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3124,7 +3124,7 @@ class ::DummySerializer < ActiveJob::Serializers::ObjectSerializer; end
31243124
test "active record job queue is set" do
31253125
app "development"
31263126

3127-
assert_equal ActiveSupport::InheritableOptions.new(destroy: :active_record_destroy), ActiveRecord.queues
3127+
assert_equal({}, ActiveRecord.queues)
31283128
end
31293129

31303130
test "destroy association async job should be loaded in configs" do

0 commit comments

Comments
 (0)