decanter 0.7.0 → 0.7.1

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
  SHA1:
3
- metadata.gz: 20aabb357aad0ae6ac3571bdc051640eee091e0a
4
- data.tar.gz: 7e1015a86d9e56d0f647bd2c561b40795b471a2d
3
+ metadata.gz: a1cea76ec8e01a183736aeb145f1b58cb8f00298
4
+ data.tar.gz: 370986b00b379fc188bc327a76e4411038f0c4b9
5
5
  SHA512:
6
- metadata.gz: ee971b831f97166213985551f11c36f22f6b4eddb89acb8e1559ab0344172ac08a7ddb88cc10ead3a744add6d950d0d127e79ee3129e2e0e4984b62529f53cdb
7
- data.tar.gz: 394c5b2fe99e781fc393b1b27580269a202189261044d57b30a370e1ef2cc2d06c298238726d0a09f2988ca39d29b8649403a4dec3658f811e3e15890a8c7d1e
6
+ metadata.gz: 0e17c3aba3e202f20638f80993d73f9a7773b6890eb46006c470a972a8f7cf7a0ce87fd07713097a40fa48482430dfc3b897a9126e14f0c49297ca1e49fa941a
7
+ data.tar.gz: af705b120764f79bff09350351830f8908b2fcb73cd74463bde2bd66dc898c63673c30fd361ff71fbbe528d512bace6d2eef4d08d6ee954f60780807ce381507
@@ -25,7 +25,7 @@ engines:
25
25
  csslint:
26
26
  enabled: true
27
27
  brakeman:
28
- enabled: true
28
+ enabled: false
29
29
  bundler-audit:
30
30
  enabled: true
31
31
  ratings:
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- decanter (0.6.2)
4
+ decanter (0.7.0)
5
5
  activesupport
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Decanter
2
2
  ===
3
3
 
4
- [![Code Climate](https://codeclimate.com/github/LaunchPadLab/decanter/badges/gpa.svg)](https://codeclimate.com/github/LaunchPadLab/decanter) [![Test Coverage](https://codeclimate.com/github/LaunchPadLab/decanter/badges/coverage.svg)](https://codeclimate.com/github/LaunchPadLab/decanter/coverage)
4
+ [![Code Climate](https://codeclimate.com/github/LaunchPadLab/decanter/badges/gpa.svg?ignore=me)](https://codeclimate.com/github/LaunchPadLab/decanter) [![Test Coverage](https://codeclimate.com/github/LaunchPadLab/decanter/badges/coverage.svg?ignore=me)](https://codeclimate.com/github/LaunchPadLab/decanter/coverage)
5
5
  ---
6
6
 
7
7
 
@@ -2,18 +2,36 @@ require 'active_support/all'
2
2
 
3
3
  module Decanter
4
4
 
5
- @@decanters = {}
5
+ class << self
6
6
 
7
- def self.register(decanter)
8
- @@decanters[decanter.name.demodulize] = decanter
9
- end
7
+ def decanter_for(klass_or_sym)
8
+ case klass_or_sym
9
+ when Class
10
+ klass_or_sym.name
11
+ when Symbol
12
+ klass_or_sym.to_s.singularize.camelize
13
+ else
14
+ raise ArgumentError.new("cannot lookup decanter for #{klass_or_sym} with class #{klass_or_sym.class}")
15
+ end.concat('Decanter').constantize
16
+ end
17
+
18
+ def decanter_from(klass_or_string)
19
+ constant =
20
+ case klass_or_string
21
+ when Class
22
+ klass_or_string
23
+ when String
24
+ klass_or_string.constantize
25
+ else
26
+ raise ArgumentError.new("cannot find decanter from #{klass_or_string} with class #{klass_or_string.class}")
27
+ end
28
+
29
+ unless constant.ancestors.include? Decanter::Base
30
+ raise ArgumentError.new("#{constant.name} is not a decanter")
31
+ end
10
32
 
11
- def self.decanter_for(klass_or_sym)
12
- name = klass_or_sym.is_a?(Class) ?
13
- klass_or_sym.name :
14
- klass_or_sym.to_s.singularize.camelize
15
- full_name = name.include?('Decanter') ? name : "#{name}Decanter"
16
- @@decanters[full_name] || (raise NameError.new("unknown decanter #{name}Decanter"))
33
+ constant
34
+ end
17
35
  end
18
36
 
19
37
  ActiveSupport.run_load_hooks(:decanter, self)
@@ -3,8 +3,5 @@ require 'decanter/core'
3
3
  module Decanter
4
4
  class Base
5
5
  include Core
6
- def self.inherited(subclass)
7
- Decanter.register(subclass)
8
- end
9
6
  end
10
7
  end
@@ -25,22 +25,20 @@ module Decanter
25
25
  end
26
26
 
27
27
  def has_many(assoc, **options)
28
- name = ["#{assoc}_attributes".to_sym]
29
- handlers[name] = {
28
+ handlers[assoc] = {
30
29
  assoc: assoc,
31
- key: options.fetch(:key, name.first),
32
- name: name,
30
+ key: options.fetch(:key, assoc),
31
+ name: assoc,
33
32
  options: options,
34
33
  type: :has_many
35
34
  }
36
35
  end
37
36
 
38
37
  def has_one(assoc, **options)
39
- name = ["#{assoc}_attributes".to_sym]
40
- handlers[name] = {
38
+ handlers[assoc] = {
41
39
  assoc: assoc,
42
- key: options.fetch(:key, name.first),
43
- name: name,
40
+ key: options.fetch(:key, assoc),
41
+ name: assoc,
44
42
  options: options,
45
43
  type: :has_one
46
44
  }
@@ -59,80 +57,118 @@ module Decanter
59
57
 
60
58
  # protected
61
59
 
62
- def unhandled_keys(args)
63
- unhandled_keys = args.keys.map(&:to_sym) - handlers.keys.flatten.uniq
64
-
65
- if unhandled_keys.any?
66
- case strict_mode
67
- when true
68
- p "#{self.name} ignoring unhandled keys: #{unhandled_keys.join(', ')}."
69
- {}
70
- when :with_exception
71
- raise ArgumentError.new("#{self.name} received unhandled keys: #{unhandled_keys.join(', ')}.")
72
- else
73
- args.select { |key| unhandled_keys.include? key }
74
- end
75
- else
60
+ def unhandled_keys(args)
61
+ unhandled_keys = args.keys.map(&:to_sym) -
62
+ handlers.keys.flatten.uniq -
63
+ handlers.values
64
+ .select { |handler| handler[:type] != :input }
65
+ .map { |handler| "#{handler[:name]}_attributes".to_sym }
66
+
67
+ if unhandled_keys.any?
68
+ case strict_mode
69
+ when true
70
+ p "#{self.name} ignoring unhandled keys: #{unhandled_keys.join(', ')}."
76
71
  {}
72
+ when :with_exception
73
+ raise ArgumentError.new("#{self.name} received unhandled keys: #{unhandled_keys.join(', ')}.")
74
+ else
75
+ args.select { |key| unhandled_keys.include? key }
77
76
  end
77
+ else
78
+ {}
78
79
  end
80
+ end
79
81
 
80
- def handled_keys(args)
81
- handlers.values
82
- .select { |handler| (args.keys.map(&:to_sym) & handler[:name]).any? }
83
- .reduce({}) { |memo, handler| memo.merge handle(handler, args) }
84
- end
82
+ def handled_keys(args)
83
+ arg_keys = args.keys.map(&:to_sym)
84
+ inputs, assocs = handlers.values.partition { |handler| handler[:type] == :input }
85
+
86
+ {}.merge(
87
+ # Inputs
88
+ inputs.select { |handler| (arg_keys & handler[:name]).any? }
89
+ .reduce({}) { |memo, handler| memo.merge handle_input(handler, args) }
90
+ ).merge(
91
+ # Associations
92
+ assocs.reduce({}) { |memo, handler| memo.merge handle_association(handler, args) }
93
+ )
94
+ end
85
95
 
86
- def handle(handler, args)
87
- values = args.values_at(*handler[:name])
88
- values = values.length == 1 ? values.first : values
89
- self.send("handle_#{handler[:type]}", handler, values)
90
- end
96
+ def handle(handler, args)
97
+ values = args.values_at(*handler[:name])
98
+ values = values.length == 1 ? values.first : values
99
+ self.send("handle_#{handler[:type]}", handler, values)
100
+ end
101
+
102
+ def handle_input(handler, args)
103
+ values = args.values_at(*handler[:name])
104
+ values = values.length == 1 ? values.first : values
105
+ parse(handler[:key], handler[:parser], values, handler[:options])
106
+ end
91
107
 
92
- def handle_input(handler, values)
93
- parse(handler[:key], handler[:parser], values, handler[:options])
108
+ def handle_association(handler, args)
109
+ assoc_handlers = [
110
+ handler,
111
+ handler.merge({
112
+ key: handler[:options].fetch(:key, "#{handler[:name]}_attributes").to_sym,
113
+ name: "#{handler[:name]}_attributes".to_sym
114
+ })
115
+ ]
116
+
117
+ assoc_handler_names = assoc_handlers.map { |_handler| _handler[:name] }
118
+
119
+ case args.values_at(*assoc_handler_names).compact.length
120
+ when 0
121
+ {}
122
+ when 1
123
+ _handler = assoc_handlers.detect { |_handler| args.has_key?(_handler[:name]) }
124
+ self.send("handle_#{_handler[:type]}", _handler, args[_handler[:name]])
125
+ else
126
+ raise ArgumentError.new("Handler #{handler[:name]} matches multiple keys: #{assoc_handler_names}.")
94
127
  end
128
+ end
95
129
 
96
- def handle_has_many(handler, values)
97
- decanter = decanter_for_handler(handler)
98
- if values.is_a?(Hash)
99
- parsed_values = values.map do |index, input_values|
100
- next if input_values.nil?
101
- decanter.decant(input_values)
102
- end
103
- return { handler[:key] => parsed_values }
104
- else
105
- {
106
- handler[:key] => values.compact.map { |value| decanter.decant(value) }
107
- }
130
+ def handle_has_many(handler, values)
131
+ decanter = decanter_for_handler(handler)
132
+ if values.is_a?(Hash)
133
+ parsed_values = values.map do |index, input_values|
134
+ next if input_values.nil?
135
+ decanter.decant(input_values)
108
136
  end
137
+ return { handler[:key] => parsed_values }
138
+ else
139
+ {
140
+ handler[:key] => values.compact.map { |value| decanter.decant(value) }
141
+ }
109
142
  end
143
+ end
110
144
 
111
- def handle_has_one(handler, values)
112
- {
113
- handler[:key] => decanter_for_handler(handler).decant(values)
114
- }
115
- end
145
+ def handle_has_one(handler, values)
146
+ { handler[:key] => decanter_for_handler(handler).decant(values) }
147
+ end
116
148
 
117
- def decanter_for_handler(handler)
118
- Decanter::decanter_for(handler[:options][:decanter] || handler[:assoc])
149
+ def decanter_for_handler(handler)
150
+ if specified_decanter = handler[:options][:decanter]
151
+ Decanter::decanter_from(specified_decanter)
152
+ else
153
+ Decanter::decanter_for(handler[:assoc])
119
154
  end
155
+ end
120
156
 
121
- def parse(key, parser, values, options)
122
- parser ?
123
- ValueParser.value_parser_for(parser)
124
- .parse(key, values, options)
125
- :
126
- { key => values }
127
- end
157
+ def parse(key, parser, values, options)
158
+ parser ?
159
+ ValueParser.value_parser_for(parser)
160
+ .parse(key, values, options)
161
+ :
162
+ { key => values }
163
+ end
128
164
 
129
- def handlers
130
- @handlers ||= {}
131
- end
165
+ def handlers
166
+ @handlers ||= {}
167
+ end
132
168
 
133
- def strict_mode
134
- @strict_mode ||= {}
135
- end
169
+ def strict_mode
170
+ @strict_mode ||= {}
171
+ end
136
172
  end
137
173
  end
138
174
  end
@@ -36,8 +36,11 @@ module Decanter
36
36
  end
37
37
 
38
38
  def decant(args, options={})
39
- options.fetch(:decanter, Decanter.decanter_for(self))
40
- .decant(args)
39
+ if specified_decanter = options[:decanter]
40
+ Decanter.decanter_from(specified_decanter)
41
+ else
42
+ Decanter.decanter_for(self)
43
+ end.decant(args)
41
44
  end
42
45
  end
43
46
 
@@ -11,7 +11,6 @@ class Decanter::Railtie < Rails::Railtie
11
11
 
12
12
  config.to_prepare do
13
13
  Dir[
14
- File.expand_path(Rails.root.join("app/decanters/*")),
15
14
  File.expand_path(Rails.root.join("lib/decanter/parsers/*"))
16
15
  ].each { |file| require file }
17
16
  end
@@ -1,3 +1,3 @@
1
1
  module Decanter
2
- VERSION = '0.7.0'
2
+ VERSION = '0.7.1'
3
3
  end
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: 0.7.0
4
+ version: 0.7.1
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: 2016-02-26 00:00:00.000000000 Z
12
+ date: 2016-03-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport