decanter 3.4.1 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91c0d17331090df0653fd6750102bddf1506bd74f73920e8a4281d61cf3190b0
4
- data.tar.gz: 620711a2e9819afe1a66055b41e70afdfb113b637362053784d53cc79df4f541
3
+ metadata.gz: 697f969bd6cdcac1487d237135cd4f1860ff9aa79abece975305d7ca7f0d5504
4
+ data.tar.gz: 7ab9d647d3c90e9c5186f4f0b486115b3d17f3107990a7984827d87e2f4843f8
5
5
  SHA512:
6
- metadata.gz: 2da563150e6a55e066f08200245175b69e8d404e4a56a99af1ea9a211ff4d3f140feec4658d97c0e09ea8f7e73f42e08d819f36e2fbac0815852fb629142bce1
7
- data.tar.gz: a03440c46bb573f6e42692b2eea31d576e57495bdb0d54f6cc1b1722b973496c251de053e92c0ed56614fa35d912c5b14f2e1782ffe879c3b17c0891bbc4dbf0
6
+ metadata.gz: 286e79ac8ebdbd3b75cc667fadd77b2fc6966f54274f06e282fc9d94250cf3075eb2f6a9e31295f1d51efb50b1b5757507de98cc6816a23b9871af7c3e32ab2a
7
+ data.tar.gz: b4cfff1c6ba4acc7f3244674e6d2a741dfbee1d5e03cdf392365bcbe4ba684f4592e1921143e7041e28d600b67cc1814110ac973c809bbea5c076a872092c652
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- decanter (3.4.1)
4
+ decanter (3.6.0)
5
5
  actionpack (>= 4.2.10)
6
6
  activesupport
7
7
  rails-html-sanitizer (>= 1.0.4)
data/README.md CHANGED
@@ -101,6 +101,7 @@ If this option is not provided, autodetect logic is used to determine if the pro
101
101
  - `nil` or not provided: will try to autodetect single vs collection
102
102
  - `true` will always treat the incoming params args as *collection*
103
103
  - `false` will always treat incoming params args as *single object*
104
+ - `truthy` will raise an error
104
105
 
105
106
  ### Nested resources
106
107
 
@@ -144,7 +145,11 @@ input :start_date, :date, parse_format: '%Y-%m-%d'
144
145
 
145
146
  ### Exceptions
146
147
 
147
- By default, `Decanter#decant` will raise an exception when unexpected parameters are passed. To override this behavior, you can disable strict mode:
148
+ 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:
149
+
150
+ - `true` (default): unhandled keys will raise an unexpected parameters exception
151
+ - `false`: all parameter key-value pairs will be included in the result
152
+ - `:ignore`: unhandled keys will be excluded from the decanted result
148
153
 
149
154
  ```ruby
150
155
  class TripDecanter < Decanter::Base
@@ -275,11 +280,14 @@ TripDecanter.decant({ name: 'Vacation 2020' })
275
280
 
276
281
  You can generate a local copy of the default configuration with `rails generate decanter:install`. This will create an initializer where you can do global configuration:
277
282
 
283
+ Setting strict mode to :ignore will log out any unhandled keys. To avoid excessive logging, the global configuration can be set to `log_unhandled_keys = false`
284
+
278
285
  ```ruby
279
286
  # ./config/initializers/decanter.rb
280
287
 
281
288
  Decanter.config do |config|
282
289
  config.strict = false
290
+ config.log_unhandled_keys = false
283
291
  end
284
292
  ```
285
293
 
data/lib/decanter/base.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require 'decanter/core'
2
+ require 'decanter/collection_detection'
2
3
 
3
4
  module Decanter
4
5
  class Base
5
6
  include Core
7
+ include CollectionDetection
6
8
  end
7
9
  end
@@ -0,0 +1,26 @@
1
+ module Decanter
2
+ module CollectionDetection
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ def decant(args, **options)
9
+ return super(args) unless collection?(args, options[:is_collection])
10
+
11
+ args.map { |resource| super(resource) }
12
+ end
13
+
14
+ private
15
+
16
+ # leveraging the approach used in the [fast JSON API gem](https://github.com/Netflix/fast_jsonapi#collection-serialization)
17
+ def collection?(args, collection_option = nil)
18
+ raise(ArgumentError, "#{name}: Unknown collection option value: #{collection_option}") unless [true, false, nil].include? collection_option
19
+
20
+ return collection_option unless collection_option.nil?
21
+
22
+ args.respond_to?(:size) && !args.respond_to?(:each_pair)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,10 +1,11 @@
1
1
  module Decanter
2
2
  class Configuration
3
3
 
4
- attr_accessor :strict
4
+ attr_accessor :strict, :log_unhandled_keys
5
5
 
6
6
  def initialize
7
7
  @strict = true
8
+ @log_unhandled_keys = true
8
9
  end
9
10
  end
10
11
  end
data/lib/decanter/core.rb CHANGED
@@ -50,10 +50,15 @@ module Decanter
50
50
  end
51
51
 
52
52
  def strict(mode)
53
- raise(ArgumentError, "#{self.name}: Unknown strict value #{mode}") unless [true, false].include? mode
53
+ raise(ArgumentError, "#{self.name}: Unknown strict value #{mode}") unless [:ignore, true, false].include? mode
54
54
  @strict_mode = mode
55
55
  end
56
56
 
57
+ def log_unhandled_keys(mode)
58
+ raise(ArgumentError, "#{self.name}: Unknown log_unhandled_keys value #{mode}") unless [true, false].include? mode
59
+ @log_unhandled_keys_mode = mode
60
+ end
61
+
57
62
  def decant(args)
58
63
  return handle_empty_args if args.blank?
59
64
  return empty_required_input_error unless required_input_keys_present?(args)
@@ -71,8 +76,9 @@ module Decanter
71
76
  .map { |input| [input[:key], input[:options][DEFAULT_VALUE_KEY]] }
72
77
  .to_h
73
78
 
74
- # parse default values
75
- handled_keys(default_result)
79
+ # parse handled default values, including keys
80
+ # with defaults not already managed by handled_keys
81
+ default_result.merge(handled_keys(default_result))
76
82
  end
77
83
 
78
84
  def default_value_inputs
@@ -121,14 +127,21 @@ module Decanter
121
127
  .map { |handler| "#{handler[:name]}_attributes".to_sym }
122
128
 
123
129
  return {} unless unhandled_keys.any?
124
- raise(UnhandledKeysError, "#{self.name} received unhandled keys: #{unhandled_keys.join(', ')}.") if strict_mode
125
- args.select { |key| unhandled_keys.include? key.to_sym }
130
+
131
+ case strict_mode
132
+ when :ignore
133
+ p "#{self.name} ignoring unhandled keys: #{unhandled_keys.join(', ')}." if log_unhandled_keys_mode
134
+ {}
135
+ when true
136
+ raise(UnhandledKeysError, "#{self.name} received unhandled keys: #{unhandled_keys.join(', ')}.")
137
+ else
138
+ args.select { |key| unhandled_keys.include? key.to_sym }
139
+ end
126
140
  end
127
141
 
128
142
  def handled_keys(args)
129
143
  arg_keys = args.keys.map(&:to_sym)
130
144
  inputs, assocs = handlers.values.partition { |handler| handler[:type] == :input }
131
-
132
145
  {}.merge(
133
146
  # Inputs
134
147
  inputs.select { |handler| (arg_keys & handler[:name]).any? }
@@ -221,6 +234,11 @@ module Decanter
221
234
  @strict_mode.nil? ? Decanter.configuration.strict : @strict_mode
222
235
  end
223
236
 
237
+ def log_unhandled_keys_mode
238
+ return !!(Decanter.configuration.log_unhandled_keys) if @log_unhandled_keys_mode.nil?
239
+ !!@log_unhandled_keys_mode
240
+ end
241
+
224
242
  # Helpers
225
243
 
226
244
  private
@@ -1,6 +1,5 @@
1
1
  module Decanter
2
2
  module Extensions
3
-
4
3
  def self.included(base)
5
4
  base.extend(ClassMethods)
6
5
  end
@@ -34,29 +33,13 @@ module Decanter
34
33
  .save!(context: options[:context])
35
34
  end
36
35
 
37
- def decant(args, options={})
38
- is_collection?(args, options[:is_collection]) ? decant_collection(args, options) : decant_args(args, options)
39
- end
40
-
41
- def decant_collection(args, options)
42
- args.map { |resource| decant_args(resource, options) }
43
- end
44
-
45
- def decant_args(args, options)
46
- if specified_decanter = options[:decanter]
36
+ def decant(args, options = {})
37
+ if (specified_decanter = options[:decanter])
47
38
  Decanter.decanter_from(specified_decanter)
48
39
  else
49
40
  Decanter.decanter_for(self)
50
41
  end.decant(args)
51
42
  end
52
-
53
- private
54
-
55
- # leveraging the approach used in the [fast JSON API gem](https://github.com/Netflix/fast_jsonapi#collection-serialization)
56
- def is_collection?(args, collection_option=nil)
57
- return collection_option[:is_collection] unless collection_option.nil?
58
- args.respond_to?(:size) && !args.respond_to?(:each_pair)
59
- end
60
43
  end
61
44
 
62
45
  module ActiveRecordExtensions
@@ -1,3 +1,3 @@
1
1
  module Decanter
2
- VERSION = '3.4.1'.freeze
2
+ VERSION = '3.6.0'.freeze
3
3
  end
data/lib/decanter.rb CHANGED
@@ -13,7 +13,7 @@ module Decanter
13
13
  klass_or_sym.to_s.singularize.camelize
14
14
  else
15
15
  raise ArgumentError.new("cannot lookup decanter for #{klass_or_sym} with class #{klass_or_sym.class}")
16
- end.concat('Decanter')
16
+ end + 'Decanter'
17
17
  begin
18
18
  decanter_name.constantize
19
19
  rescue
@@ -57,9 +57,8 @@ end
57
57
 
58
58
  require 'decanter/version'
59
59
  require 'decanter/configuration'
60
- require 'decanter/core'
61
60
  require 'decanter/base'
62
61
  require 'decanter/extensions'
63
62
  require 'decanter/exceptions'
64
63
  require 'decanter/parser'
65
- require 'decanter/railtie' if defined?(::Rails)
64
+ require 'decanter/railtie' if defined?(::Rails)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decanter
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.1
4
+ version: 3.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Francis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-11-18 00:00:00.000000000 Z
12
+ date: 2021-09-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -152,6 +152,7 @@ files:
152
152
  - decanter.gemspec
153
153
  - lib/decanter.rb
154
154
  - lib/decanter/base.rb
155
+ - lib/decanter/collection_detection.rb
155
156
  - lib/decanter/configuration.rb
156
157
  - lib/decanter/core.rb
157
158
  - lib/decanter/exceptions.rb