Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clash: cannot nest twice even when key is Clash class #240

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 14 additions & 11 deletions lib/hashie/clash.rb
Expand Up @@ -54,7 +54,9 @@ def merge_store(key, *args) #:nodoc:
case args.length
when 1
val = args.first
val = self[key].merge(val) if self[key].is_a?(::Hash) && val.is_a?(::Hash)
if self[key].is_a?(::Hash) && val.is_a?(::Hash)
val = self.class.new(self[key]).merge(val)
end
else
val = args
end
Expand All @@ -64,22 +66,23 @@ def merge_store(key, *args) #:nodoc:
end

def method_missing(name, *args) #:nodoc:
name = name.to_s
if name.match(/!$/) && args.empty?
if args.empty? && name.to_s.end_with?('!')
key = name[0...-1].to_sym

if self[key].nil?
self[key] = Clash.new({}, self)
elsif self[key].is_a?(::Hash) && !self[key].is_a?(Clash)
self[key] = Clash.new(self[key], self)
case self[key]
when NilClass
self[key] = self.class.new({}, self)
when Clash
self[key]
when Hash
self[key] = self.class.new(self[key], self)
else
fail ChainError, 'Tried to chain into a non-hash key.'
end

self[key]
elsif args.any?
key = name.to_sym
merge_store(key, *args)
merge_store(name, *args)
else
super
end
end
end
Expand Down
26 changes: 24 additions & 2 deletions spec/hashie/clash_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'

describe Hashie::Clash do
subject { Hashie::Clash.new }

it 'is able to set an attribute via method_missing' do
subject.foo('bar')
expect(subject[:foo]).to eq 'bar'
Expand Down Expand Up @@ -45,4 +43,28 @@
expect(subject[:foo]).to be_nil
expect(subject[:hello]).to be_nil
end

it 'merges multiple bang notation calls' do
subject.where!.foo(123)
subject.where!.bar(321)
expect(subject).to eq(where: { foo: 123, bar: 321 })
end

it 'raises an exception when method is missing' do
expect { subject.boo }.to raise_error(NoMethodError)
end

describe 'when inherited' do
subject { Class.new(described_class).new }

it 'bang nodes are instances of a subclass' do
subject.where!.foo(123)
expect(subject[:where]).to be_instance_of(subject.class)
end

it 'merged nodes are instances of a subclass' do
subject.where(abc: 'def').where(hgi: 123)
expect(subject[:where]).to be_instance_of(subject.class)
end
end
end