From b4c7cd331873e639533393373dc92eb6ecaf4c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20Kopi=C5=84ski?= Date: Thu, 27 Nov 2014 05:08:00 +0100 Subject: [PATCH] Clash: multiple bang notation calls Added inheritance Added multiple bang notation merging Minor performace improvements - ends_with? is faster than regexp --- lib/hashie/clash.rb | 25 ++++++++++++++----------- spec/hashie/clash_spec.rb | 26 ++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/lib/hashie/clash.rb b/lib/hashie/clash.rb index 4bb755e3..7a99550e 100644 --- a/lib/hashie/clash.rb +++ b/lib/hashie/clash.rb @@ -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 @@ -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 diff --git a/spec/hashie/clash_spec.rb b/spec/hashie/clash_spec.rb index e30dd5c9..52a2af5a 100644 --- a/spec/hashie/clash_spec.rb +++ b/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' @@ -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