Skip to content

Commit

Permalink
Clash: multiple bang notation calls
Browse files Browse the repository at this point in the history
Added inheritance

Added multiple bang notation merging

Minor performace improvements - ends_with? is faster than regexp
  • Loading branch information
Bartosz Kopiński committed Nov 27, 2014
1 parent 0bd90ea commit b4c7cd3
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 13 deletions.
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

0 comments on commit b4c7cd3

Please sign in to comment.