Skip to content

Commit

Permalink
Strict ignore unhandled keys (#122)
Browse files Browse the repository at this point in the history
* add :ignore as strict option for ignoring unhandled keys

* working defaults ip

* fix issue where inputs with alternate key and a default value were being ignored

* spec updates

* update readme strict mode options, bump version to 3.4.3

* remove space

* typo

* ip with decanter branch ignore strict

* remove comment

* remove extra space

* switch to minor version 3.5.0

* update readme, typo

* remove extra test

* bundle
  • Loading branch information
dianacamacho authored Jan 23, 2021
1 parent 2f18945 commit 74b30db
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
decanter (3.4.2)
decanter (3.5.0)
actionpack (>= 4.2.10)
activesupport
rails-html-sanitizer (>= 1.0.4)
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ input :start_date, :date, parse_format: '%Y-%m-%d'

### Exceptions

By default, `Decanter#decant` will raise an exception when unexpected parameters are passed. To override this behavior, you can disable strict mode:
By default, `Decanter#decant` will raise an exception when unexpected parameters are passed. To override this behavior, you can change the strict mode option to one of:

- `true` (default): unhandled keys will raise an unexpected parameters exception
- `false`: all parameter key-value pairs will be included in the result
- `:ignore`: unhandled keys will be excluded from the decanted result

```ruby
class TripDecanter < Decanter::Base
Expand Down
20 changes: 14 additions & 6 deletions lib/decanter/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def ignore(*args)
end

def strict(mode)
raise(ArgumentError, "#{self.name}: Unknown strict value #{mode}") unless [true, false].include? mode
raise(ArgumentError, "#{self.name}: Unknown strict value #{mode}") unless [:ignore, true, false].include? mode
@strict_mode = mode
end

Expand All @@ -71,8 +71,9 @@ def default_keys
.map { |input| [input[:key], input[:options][DEFAULT_VALUE_KEY]] }
.to_h

# parse default values
handled_keys(default_result)
# parse handled default values, including keys
# with defaults not already managed by handled_keys
default_result.merge(handled_keys(default_result))
end

def default_value_inputs
Expand Down Expand Up @@ -121,14 +122,21 @@ def unhandled_keys(args)
.map { |handler| "#{handler[:name]}_attributes".to_sym }

return {} unless unhandled_keys.any?
raise(UnhandledKeysError, "#{self.name} received unhandled keys: #{unhandled_keys.join(', ')}.") if strict_mode
args.select { |key| unhandled_keys.include? key.to_sym }

case strict_mode
when :ignore
p "#{self.name} ignoring unhandled keys: #{unhandled_keys.join(', ')}."
{}
when true
raise(UnhandledKeysError, "#{self.name} received unhandled keys: #{unhandled_keys.join(', ')}.")
else
args.select { |key| unhandled_keys.include? key.to_sym }
end
end

def handled_keys(args)
arg_keys = args.keys.map(&:to_sym)
inputs, assocs = handlers.values.partition { |handler| handler[:type] == :input }

{}.merge(
# Inputs
inputs.select { |handler| (arg_keys & handler[:name]).any? }
Expand Down
2 changes: 1 addition & 1 deletion lib/decanter/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Decanter
VERSION = '3.4.2'.freeze
VERSION = '3.5.0'.freeze
end
34 changes: 31 additions & 3 deletions spec/decanter/decanter_core_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,9 @@ def self.name

context 'when there are unhandled keys' do

before(:each) { allow(dummy).to receive(:handlers).and_return({}) }

context 'and strict mode is true' do

before(:each) { allow(dummy).to receive(:handlers).and_return({}) }
before(:each) { dummy.strict true }

context 'when there are no ignored keys' do
Expand All @@ -327,10 +326,18 @@ def self.name
end
end

context 'and strict mode is false' do
context 'and strict mode is :ignore' do

it 'returns a hash without the unhandled keys and values' do
dummy.strict :ignore
expect(dummy.unhandled_keys(args)).to match({})
end
end

context 'and strict mode is false' do
it 'returns a hash with the unhandled keys and values' do
dummy.strict false
allow(dummy).to receive(:handlers).and_return({})
expect(dummy.unhandled_keys(args)).to match(args)
end
end
Expand Down Expand Up @@ -546,6 +553,27 @@ def self.name
end

context 'with args' do
context 'when strict mode is set to :ignore' do
context 'and params include unhandled keys' do
let(:decanter) {
Class.new(Decanter::Base) do
input :name, :string
input :description, :string
end
}

let(:args) { { name: 'My Trip', description: 'My Trip Description', foo: 'bar' } }

it 'returns a hash with the declared key-value pairs, ignores unhandled key-value pairs' do
decanter.strict :ignore
decanted_params = decanter.decant(args)

expect(decanted_params).not_to match(args)
expect(decanted_params.keys).not_to include([:foo])
end
end
end

context 'when inputs are required' do
let(:decanter) {
Class.new(Decanter::Base) do
Expand Down

0 comments on commit 74b30db

Please sign in to comment.