Module: Decanter::Core::ClassMethods
- Defined in:
- lib/decanter/core.rb
Instance Method Summary collapse
-
#decant(args) ⇒ Object
Take a parameter hash, and handle it with the various decanters defined.
- #decanter_for_handler(handler) ⇒ Object
- #empty_required_input_error(name = nil) ⇒ Object
- #handle(handler, values) ⇒ Object
- #handle_empty_args ⇒ Object
- #handled_keys(args) ⇒ Object
-
#handler(name, options) ⇒ Object
Add a parameter handler to the class.
- #handlers ⇒ Object
-
#has_many(name, **options) ⇒ Object
Declare a _has many_ association for a parameter.
-
#has_one(name, **options) ⇒ Object
Declare a _has one_ association for a parameter.
-
#ignore(*args) ⇒ Object
List of parameters to ignore.
-
#input(name, parsers = nil, **options) ⇒ Object
Declare an ordinary parameter transformation.
- #keys_to_ignore ⇒ Object
- #parse(parsers, values, options) ⇒ Object
- #required_input_keys_present?(args = {}) ⇒ Boolean
- #required_inputs ⇒ Object
-
#strict(mode) ⇒ Object
Set a level of strictness when dealing with parameters that are present but not expected.
- #strict_mode ⇒ Object
-
#unhandled_keys(args) ⇒ Object
protected.
Instance Method Details
#decant(args) ⇒ Object
Take a parameter hash, and handle it with the various decanters defined.
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/decanter/core.rb', line 79 def decant(args) return handle_empty_args if args.blank? return empty_required_input_error unless required_input_keys_present?(args) if args.is_a?(ActionController::Parameters) args.permit! args = args.to_h end args = args.deep_symbolize_keys handled_keys(args).merge(unhandled_keys(args)) end |
#decanter_for_handler(handler) ⇒ Object
160 161 162 163 164 165 166 |
# File 'lib/decanter/core.rb', line 160 def decanter_for_handler(handler) if (specified_decanter = handler[:options][:decanter]) Decanter.decanter_from(specified_decanter) else Decanter.decanter_for(handler[:assoc]) end end |
#empty_required_input_error(name = nil) ⇒ Object
106 107 108 |
# File 'lib/decanter/core.rb', line 106 def empty_required_input_error(name = nil) raise MissingRequiredInputValue, "No value found for required argument #{name}" end |
#handle(handler, values) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/decanter/core.rb', line 143 def handle(handler, values) decanter = decanter_for_handler(handler) unless handler[:type] == :input val = case handler[:type] when :input parse(handler[:parsers], values, handler[:options]) when :has_one decanter.decant(values) when :has_many # should sort here, really. values = values.values if values.is_a?(Hash) values.compact.map { |v| decanter.decant(v) } end { handler[:key] => val } end |
#handle_empty_args ⇒ Object
168 169 170 |
# File 'lib/decanter/core.rb', line 168 def handle_empty_args required_inputs.any? ? empty_required_input_error : {} end |
#handled_keys(args) ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/decanter/core.rb', line 129 def handled_keys(args) handlers.reduce({}) do |m, h| name, handler = *h values = args.values_at(*name) values = values.length == 1 ? values.first : values if handler[:options][:required] && Array(values).all?(&:blank?) empty_required_input_error(name) end m.merge handle(handler, values) end end |
#handler(name, options) ⇒ Object
Add a parameter handler to the class. Takes a name, and a set of options. This is a generic method for any sort of handler, e.g.
handle :foo, type: :input, parsers: [:string], as: :bar
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/decanter/core.rb', line 38 def handler(name, ) name = .fetch(:as, name) parsers = .delete(:parsers) if Array(name).length > 1 && parsers.blank? raise ArgumentError, "#{name} no parser specified for input with multiple values." end if handlers.key?(name) raise ArgumentError, "Handler for #{name} already defined" end handlers[name] = { key: .fetch(:key, Array(name).first), assoc: .delete(:assoc), type: .delete(:type), options: , parsers: Array(parsers) } end |
#handlers ⇒ Object
190 191 192 |
# File 'lib/decanter/core.rb', line 190 def handlers @handlers ||= {} end |
#has_many(name, **options) ⇒ Object
Declare a _has many_ association for a parameter.
20 21 22 23 24 |
# File 'lib/decanter/core.rb', line 20 def has_many(name, **) [:type] = :has_many [:assoc] = name handler(name, ) end |
#has_one(name, **options) ⇒ Object
Declare a _has one_ association for a parameter.
27 28 29 30 31 |
# File 'lib/decanter/core.rb', line 27 def has_one(name, **) [:type] = :has_one [:assoc] = name handler(name, ) end |
#ignore(*args) ⇒ Object
List of parameters to ignore.
61 62 63 |
# File 'lib/decanter/core.rb', line 61 def ignore(*args) keys_to_ignore.push(*args) end |
#input(name, parsers = nil, **options) ⇒ Object
Declare an ordinary parameter transformation.
11 12 13 14 15 |
# File 'lib/decanter/core.rb', line 11 def input(name, parsers = nil, **) [:type] = :input [:parsers] = parsers handler(name, ) end |
#keys_to_ignore ⇒ Object
194 195 196 |
# File 'lib/decanter/core.rb', line 194 def keys_to_ignore @keys_to_ignore ||= [] end |
#parse(parsers, values, options) ⇒ Object
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/decanter/core.rb', line 172 def parse(parsers, values, ) return values if parsers.nil? Parser.parsers_for(parsers).each do |parser| unless values.is_a?(Hash) values = parser.parse(values, ) next end # For hashes, we operate the parser on each member values.each do |k, v| values[k] = parser.parse(v, ) end end values end |
#required_input_keys_present?(args = {}) ⇒ Boolean
98 99 100 101 102 103 104 |
# File 'lib/decanter/core.rb', line 98 def required_input_keys_present?(args = {}) return true unless required_inputs.any? compact_inputs = required_inputs.compact compact_inputs.all? do |input| args.keys.map(&:to_sym).include?(input) && !args[input].nil? end end |
#required_inputs ⇒ Object
92 93 94 95 96 |
# File 'lib/decanter/core.rb', line 92 def required_inputs handlers.map do |name, handler| name if handler[:options][:required] end end |
#strict(mode) ⇒ Object
Set a level of strictness when dealing with parameters that are present but not expected.
with_exception: Raise an exception true: Delete the parameter false: Allow the parameter through
72 73 74 75 |
# File 'lib/decanter/core.rb', line 72 def strict(mode) raise(ArgumentError, "#{name}: Unknown strict value #{mode}") unless [:with_exception, true, false].include? mode @strict_mode = mode end |
#strict_mode ⇒ Object
198 199 200 |
# File 'lib/decanter/core.rb', line 198 def strict_mode @strict_mode.nil? ? Decanter.configuration.strict : @strict_mode end |
#unhandled_keys(args) ⇒ Object
protected
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/decanter/core.rb', line 112 def unhandled_keys(args) unhandled = args.keys unhandled -= keys_to_ignore unhandled -= handlers.keys.flatten return {} unless unhandled.any? case strict_mode when true {} when :with_exception raise(UnhandledKeysError, "#{name} received unhandled keys: #{unhandled.join(', ')}.") else args.select { |key| unhandled.include? key } end end |