From 12c06e7ddc82496d2409c74c989fc18fcff7568d Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Fri, 2 May 2014 16:50:02 -0500 Subject: [PATCH 1/4] Create interface filter --- benchmarks/filters.rb | 1 + lib/active_interaction.rb | 1 + .../filters/interface_filter.rb | 42 +++++++++++++++ .../filters/interface_filter_spec.rb | 54 +++++++++++++++++++ .../integration/interface_interaction_spec.rb | 10 ++++ 5 files changed, 108 insertions(+) create mode 100644 lib/active_interaction/filters/interface_filter.rb create mode 100644 spec/active_interaction/filters/interface_filter_spec.rb create mode 100644 spec/active_interaction/integration/interface_interaction_spec.rb diff --git a/benchmarks/filters.rb b/benchmarks/filters.rb index abcdc4cc..9a766da5 100644 --- a/benchmarks/filters.rb +++ b/benchmarks/filters.rb @@ -26,6 +26,7 @@ float: [0.0, '0.0', 0], hash: [Hash.new], # TODO integer: [0, '0', 0.0], + interface: [Object.new], model: [Object.new], # TODO: Reconstantizing. string: [''], # TODO: Without strip. symbol: [:'', ''], diff --git a/lib/active_interaction.rb b/lib/active_interaction.rb index 06355d69..062a8038 100644 --- a/lib/active_interaction.rb +++ b/lib/active_interaction.rb @@ -30,6 +30,7 @@ require 'active_interaction/filters/float_filter' require 'active_interaction/filters/hash_filter' require 'active_interaction/filters/integer_filter' +require 'active_interaction/filters/interface_filter' require 'active_interaction/filters/model_filter' require 'active_interaction/filters/string_filter' require 'active_interaction/filters/symbol_filter' diff --git a/lib/active_interaction/filters/interface_filter.rb b/lib/active_interaction/filters/interface_filter.rb new file mode 100644 index 00000000..b7d7adac --- /dev/null +++ b/lib/active_interaction/filters/interface_filter.rb @@ -0,0 +1,42 @@ +# coding: utf-8 + +module ActiveInteraction + class Base + # @!method self.interface(*attributes, options = {}) + # Creates accessors for the attributes and ensures that values passed to + # the attributes implement an interface. + # + # @!macro filter_method_params + # @option options [Array] :methods ([]) the methods that make up + # this interface + # + # @example + # interface :anything + # @example + # interface :lengthy, + # methods: [:length] + end + + # @private + class InterfaceFilter < Filter + def cast(value) + matches?(value) ? value : super + end + + private + + # @param object [Object] + # + # @return [Boolean] + def matches?(object) + methods.all? { |method| object.respond_to?(method) } + rescue NoMethodError + false + end + + # @return [Array] + def methods + options.fetch(:methods, []) + end + end +end diff --git a/spec/active_interaction/filters/interface_filter_spec.rb b/spec/active_interaction/filters/interface_filter_spec.rb new file mode 100644 index 00000000..415ca032 --- /dev/null +++ b/spec/active_interaction/filters/interface_filter_spec.rb @@ -0,0 +1,54 @@ +# coding: utf-8 + +require 'spec_helper' + +describe ActiveInteraction::InterfaceFilter, :filter do + include_context 'filters' + it_behaves_like 'a filter' + + before { options[:methods] = [:each] } + + describe '#cast' do + let(:result) { filter.cast(value) } + + context 'with an Object' do + let(:value) { Object.new } + + it 'raises an error' do + expect do + result + end.to raise_error ActiveInteraction::InvalidValueError + end + end + + context 'with an Array' do + let(:value) { [] } + + it 'returns an Array' do + expect(result).to eql value + end + end + + context 'with an Hash' do + let(:value) { {} } + + it 'returns an Hash' do + expect(result).to eql value + end + end + + context 'with an Range' do + let(:value) { (0..0) } + + it 'returns an Range' do + expect(result).to eql value + end + end + end + + describe '#database_column_type' do + it 'returns :string' do + expect(filter.database_column_type).to eql :string + end + end +end diff --git a/spec/active_interaction/integration/interface_interaction_spec.rb b/spec/active_interaction/integration/interface_interaction_spec.rb new file mode 100644 index 00000000..0689f4c4 --- /dev/null +++ b/spec/active_interaction/integration/interface_interaction_spec.rb @@ -0,0 +1,10 @@ +# coding: utf-8 + +require 'spec_helper' + +describe 'InterfaceInteraction' do + it_behaves_like 'an interaction', + :interface, + -> { [[], {}, (0..0)] }, + methods: [:each] +end From ea364477e51cb73d51b60090e44165c85fc24e5f Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Fri, 2 May 2014 17:56:31 -0500 Subject: [PATCH 2/4] Use a better example for interface documentation and tests --- .../filters/interface_filter.rb | 8 +++---- .../filters/interface_filter_spec.rb | 24 +++++++------------ .../integration/interface_interaction_spec.rb | 6 +++-- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/active_interaction/filters/interface_filter.rb b/lib/active_interaction/filters/interface_filter.rb index b7d7adac..1c77db37 100644 --- a/lib/active_interaction/filters/interface_filter.rb +++ b/lib/active_interaction/filters/interface_filter.rb @@ -7,14 +7,14 @@ class Base # the attributes implement an interface. # # @!macro filter_method_params - # @option options [Array] :methods ([]) the methods that make up - # this interface + # @option options [Array] :methods ([]) the methods that objects + # conforming to this interface should respond to # # @example # interface :anything # @example - # interface :lengthy, - # methods: [:length] + # interface :serializer, + # methods: [:dump, :load] end # @private diff --git a/spec/active_interaction/filters/interface_filter_spec.rb b/spec/active_interaction/filters/interface_filter_spec.rb index 415ca032..584c8097 100644 --- a/spec/active_interaction/filters/interface_filter_spec.rb +++ b/spec/active_interaction/filters/interface_filter_spec.rb @@ -1,12 +1,14 @@ # coding: utf-8 require 'spec_helper' +require 'json' +require 'yaml' describe ActiveInteraction::InterfaceFilter, :filter do include_context 'filters' it_behaves_like 'a filter' - before { options[:methods] = [:each] } + before { options[:methods] = [:dump, :load] } describe '#cast' do let(:result) { filter.cast(value) } @@ -15,35 +17,25 @@ let(:value) { Object.new } it 'raises an error' do - expect do - result - end.to raise_error ActiveInteraction::InvalidValueError + expect { result }.to raise_error ActiveInteraction::InvalidValueError end end - context 'with an Array' do - let(:value) { [] } + context 'with JSON' do + let(:value) { JSON } it 'returns an Array' do expect(result).to eql value end end - context 'with an Hash' do - let(:value) { {} } + context 'with YAML' do + let(:value) { YAML } it 'returns an Hash' do expect(result).to eql value end end - - context 'with an Range' do - let(:value) { (0..0) } - - it 'returns an Range' do - expect(result).to eql value - end - end end describe '#database_column_type' do diff --git a/spec/active_interaction/integration/interface_interaction_spec.rb b/spec/active_interaction/integration/interface_interaction_spec.rb index 0689f4c4..ea30b813 100644 --- a/spec/active_interaction/integration/interface_interaction_spec.rb +++ b/spec/active_interaction/integration/interface_interaction_spec.rb @@ -1,10 +1,12 @@ # coding: utf-8 require 'spec_helper' +require 'json' +require 'yaml' describe 'InterfaceInteraction' do it_behaves_like 'an interaction', :interface, - -> { [[], {}, (0..0)] }, - methods: [:each] + -> { [JSON, YAML].sample }, + methods: [:dump, :load] end From ee30a0fbd1518617831b176161f12ea0a0895e87 Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Sat, 3 May 2014 09:35:56 -0500 Subject: [PATCH 3/4] Add translation for interface filter --- lib/active_interaction/locale/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/active_interaction/locale/en.yml b/lib/active_interaction/locale/en.yml index 02693edf..60ac73d4 100644 --- a/lib/active_interaction/locale/en.yml +++ b/lib/active_interaction/locale/en.yml @@ -16,6 +16,7 @@ en: float: float hash: hash integer: integer + interface: interface model: model string: string symbol: symbol From a5d81d8f48c19a0014e51a1ea12f619f9ebb0c7d Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Sat, 3 May 2014 09:36:44 -0500 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff214e64..07aa4340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # [Master][] +- Add an interface filter. - Add missing translation for symbol filters. # [1.2.1][] (2014-05-02)