diff --git a/lib/rackstash/class_registry.rb b/lib/rackstash/class_registry.rb index 953f45e..a3dff1e 100644 --- a/lib/rackstash/class_registry.rb +++ b/lib/rackstash/class_registry.rb @@ -25,17 +25,40 @@ module Rackstash # # @param spec [Class,String,Symbol] Either a class (in which case it is # returned directly) or the name of a registered class. - # @raise [KeyError] when giving a `String` or `Symbol` but no registered - # class was found for it # @raise [TypeError] when giving an invalid object + # @return [Class, nil] the registered class (when giving a `String` or + # `Symbol`) or the given class (when giving a `Class`) or `nil` if no + # registered class could be found + # @see #fetch + def [](spec) + fetch(spec, nil) + end + + # Retrieve the registered class for a given name. If the argument is already + # a class, we return it unchanged. + # + # @param spec [Class,String,Symbol] either a class (in which case it is + # returned directly) or the name of a registered class + # @param default [Object] the default value that is returned if no + # registered class could be found for the given `spec` and no block was + # given. + # @yield if no registered class could be found for the given `spec`, we will + # run the optional block and return its result + # @yieldparam spec [Symbol] the requested class specification as a `Symbol` + # @raise [KeyError] when giving a `String` or `Symbol` but no registered + # class was found for it and no default was specified + # @raise [TypeError] when giving an invalid `spec` object # @return [Class] the registered class (when giving a `String` or `Symbol`) # or the given class (when giving a `Class`) - def [](spec) + def fetch(spec, default = UNDEFINED) case spec when Class spec when String, Symbol, ->(s) { s.respond_to?(:to_sym) } - @registry.fetch(spec.to_sym) do + @registry.fetch(spec.to_sym) do |key| + next yield(key) if block_given? + next default unless UNDEFINED.equal? default + raise KeyError, "No #{@object_type} was registered for #{spec.inspect}" end else diff --git a/lib/rackstash/encoder.rb b/lib/rackstash/encoder.rb index 405752e..84f6956 100644 --- a/lib/rackstash/encoder.rb +++ b/lib/rackstash/encoder.rb @@ -81,7 +81,7 @@ module Rackstash if encoder_spec.respond_to?(:encode) && !encoder_spec.is_a?(String) encoder_spec else - registry[encoder_spec].new(*args, &block) + registry.fetch(encoder_spec).new(*args, &block) end end end diff --git a/lib/rackstash/filter.rb b/lib/rackstash/filter.rb index e160980..2cd7ecd 100644 --- a/lib/rackstash/filter.rb +++ b/lib/rackstash/filter.rb @@ -94,7 +94,7 @@ module Rackstash else args << kwargs unless kwargs.empty? - filter = registry[filter_spec].new(*args, &block) + filter = registry.fetch(filter_spec).new(*args, &block) conditional_filter(filter, only_if: only_if, not_if: not_if) end end diff --git a/spec/rackstash/class_registry_spec.rb b/spec/rackstash/class_registry_spec.rb index cb21cbc..b3c68d2 100644 --- a/spec/rackstash/class_registry_spec.rb +++ b/spec/rackstash/class_registry_spec.rb @@ -37,19 +37,53 @@ describe Rackstash::ClassRegistry do expect(registry[String]).to equal String end + it 'returns nil on unknown names' do + expect(registry[:unknown]).to be nil + expect(registry['invalid']).to be nil + end + end + + describe '#fetch' do + before do + registry[:class] = klass + end + + it 'returns the class for a String' do + expect(registry.fetch('class')).to equal klass + end + + it 'returns the class for a Symbol' do + expect(registry.fetch(:class)).to equal klass + end + + it 'returns an actual class' do + expect(registry.fetch(klass)).to equal klass + expect(registry.fetch(String)).to equal String + end + it 'raises a KeyError on unknown names' do - expect { registry[:unknown] } + expect { registry.fetch(:unknown) } .to raise_error(KeyError, 'No value was registered for :unknown') - expect { registry['invalid'] } + expect { registry.fetch('invalid') } .to raise_error(KeyError, 'No value was registered for "invalid"') end + it 'returns the default value with unknown names' do + expect(registry.fetch(:unknown, 'Hello World')).to eql 'Hello World' + expect(registry.fetch('invalid', 'Hello World')).to eql 'Hello World' + end + + it 'calls the block and returns its value with unknown names' do + expect { |b| registry.fetch('invalid', &b) }.to yield_with_args(:invalid) + expect(registry.fetch('invalid') { |e| e.upcase }).to eql :INVALID + end + it 'raises a TypeError on invalid names' do - expect { registry[0] } + expect { registry.fetch(0) } .to raise_error(TypeError, '0 can not be used to describe values') - expect { registry[nil] } + expect { registry.fetch(nil) } .to raise_error(TypeError, 'nil can not be used to describe values') - expect { registry[true] } + expect { registry.fetch(true) } .to raise_error(TypeError, 'true can not be used to describe values') end end @@ -88,7 +122,7 @@ describe Rackstash::ClassRegistry do expect(registry[:class]).to equal klass expect(registry.clear).to equal registry - expect { registry[:class] }.to raise_error(KeyError) + expect(registry[:class]).to be nil end end @@ -147,7 +181,7 @@ describe Rackstash::ClassRegistry do hash = registry.to_h hash[:alias] = klass - expect { registry[:alias] }.to raise_error(KeyError) + expect(registry[:alias]).to be nil end end end