subroutine 0.5.3 → 0.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
  SHA1:
3
- metadata.gz: 51dd4d01f29eee0ec20fedb8cd5fc0de95ce73db
4
- data.tar.gz: 8dad3a9f2520e5512c2132a56ed75867f9c4b4fa
3
+ metadata.gz: 388f424f1515f93ce602dd4b6578288733a0c7e8
4
+ data.tar.gz: 8514ac581bf6afa707d12801a45f017833cd3e2b
5
5
  SHA512:
6
- metadata.gz: bedcc9b19e8e29542920bfb858a2022440d99486b85da42f9d7aed895487e24fc249bfc379301f5e07f7348af769a0e3dced6873746c030bd51b117d3c2b4e23
7
- data.tar.gz: 49c40b9764b62942b64623b1891fb1626e6c6756d627b99c3fa10f62f8d1f7c792a55286fbcedf4ee5ad3d969387e67303fcfb982fe0519f077bdf6d0c76026d
6
+ metadata.gz: e008b4415a368b7df088f4049cf08714951fdce842c53c9ddd11c31401ded7e2cc42997325a62012f753adeca942765d86c0f33df6fa1fc4534471a9512b432a
7
+ data.tar.gz: cf77b24680e08978e7b927c7b4999da80b72bbcd9247811052ed4d7eca49ec32f79c7db3750159dcb3718d7cab9b8ac37b9ab7647f6e04e85d306ab98016a91b
data/lib/subroutine/op.rb CHANGED
@@ -3,16 +3,14 @@ require 'active_support/core_ext/object/duplicable'
3
3
  require 'active_support/core_ext/object/deep_dup'
4
4
  require 'active_model'
5
5
 
6
- require "subroutine/failure"
7
- require "subroutine/type_caster"
8
- require "subroutine/filtered_errors"
9
- require "subroutine/output_not_set_error"
10
- require "subroutine/unknown_output_error"
6
+ require 'subroutine/failure'
7
+ require 'subroutine/type_caster'
8
+ require 'subroutine/filtered_errors'
9
+ require 'subroutine/output_not_set_error'
10
+ require 'subroutine/unknown_output_error'
11
11
 
12
12
  module Subroutine
13
-
14
13
  class Op
15
-
16
14
  include ::ActiveModel::Model
17
15
  include ::ActiveModel::Validations::Callbacks
18
16
 
@@ -21,9 +19,7 @@ module Subroutine
21
19
  }.freeze
22
20
 
23
21
  class << self
24
-
25
- ::Subroutine::TypeCaster::TYPES.values.flatten.each do |caster|
26
-
22
+ ::Subroutine::TypeCaster.casters.each_key do |caster|
27
23
  next if method_defined?(caster)
28
24
 
29
25
  class_eval <<-EV, __FILE__, __LINE__ + 1
@@ -46,15 +42,12 @@ module Subroutine
46
42
  _field(f, options)
47
43
  end
48
44
  end
49
-
50
- alias_method :fields, :field
45
+ alias fields field
51
46
 
52
47
  def outputs(*names)
53
48
  options = names.extract_options!
54
49
  names.each do |name|
55
- self._outputs = self._outputs.merge({
56
- name.to_sym => DEFAULT_OUTPUT_OPTIONS.merge(options)
57
- })
50
+ self._outputs = _outputs.merge(name.to_sym => DEFAULT_OUTPUT_OPTIONS.merge(options))
58
51
 
59
52
  class_eval <<-EV, __FILE__, __LINE__ + 1
60
53
  def #{name}
@@ -69,7 +62,7 @@ module Subroutine
69
62
  _ignore_errors(f)
70
63
  end
71
64
  end
72
- alias_method :ignore_errors, :ignore_error
65
+ alias ignore_errors ignore_error
73
66
 
74
67
  def inputs_from(*ops)
75
68
  options = ops.extract_options!
@@ -98,7 +91,6 @@ module Subroutine
98
91
  child._error_ignores = self._error_ignores.dup
99
92
  end
100
93
 
101
-
102
94
  def submit!(*args)
103
95
  op = new(*args)
104
96
  op.submit!
@@ -115,23 +107,21 @@ module Subroutine
115
107
  protected
116
108
 
117
109
  def _field(field_name, options = {})
118
- self._fields[field_name.to_sym] = options
110
+ _fields[field_name.to_sym] = options
119
111
 
120
112
  if options[:aka]
121
113
  Array(options[:aka]).each do |as|
122
- self._error_map[as.to_sym] = field_name.to_sym
114
+ _error_map[as.to_sym] = field_name.to_sym
123
115
  end
124
116
  end
125
117
 
126
- if options[:ignore_errors]
127
- _ignore_errors(field_name)
128
- end
118
+ _ignore_errors(field_name) if options[:ignore_errors]
129
119
 
130
120
  class_eval <<-EV, __FILE__, __LINE__ + 1
131
121
 
132
122
  def #{field_name}=(v)
133
123
  config = #{field_name}_config
134
- v = type_caster.cast(v, config[:type])
124
+ v = ::Subroutine::TypeCaster.cast(v, config[:type])
135
125
  @params["#{field_name}"] = v
136
126
  end
137
127
 
@@ -140,7 +130,7 @@ module Subroutine
140
130
  end
141
131
 
142
132
  def #{field_name}_config
143
- self._fields[:#{field_name}]
133
+ _fields[:#{field_name}]
144
134
  end
145
135
 
146
136
  EV
@@ -148,7 +138,7 @@ module Subroutine
148
138
  end
149
139
 
150
140
  def _ignore_errors(field_name)
151
- self._error_ignores[field_name.to_sym] = true
141
+ _error_ignores[field_name.to_sym] = true
152
142
  end
153
143
 
154
144
  end
@@ -234,10 +224,6 @@ module Subroutine
234
224
 
235
225
  protected
236
226
 
237
- def type_caster
238
- @type_caster ||= ::Subroutine::TypeCaster.new
239
- end
240
-
241
227
  # these enable you to 1) add log output or 2) add performance monitoring such as skylight.
242
228
  def observe_submission
243
229
  yield
@@ -251,17 +237,11 @@ module Subroutine
251
237
  yield
252
238
  end
253
239
 
254
-
255
240
  def validate_and_perform
256
- bool = observe_validation do
257
- valid?
258
- end
259
-
241
+ bool = observe_validation{ valid? }
260
242
  return false unless bool
261
243
 
262
- observe_perform do
263
- perform
264
- end
244
+ observe_perform{ perform }
265
245
  end
266
246
 
267
247
  # implement this in your concrete class.
@@ -271,7 +251,7 @@ module Subroutine
271
251
 
272
252
  # check if a specific field was provided
273
253
  def field_provided?(key)
274
- @params.has_key?(key)
254
+ @params.key?(key)
275
255
  end
276
256
 
277
257
  # applies the errors in error_object to self
@@ -281,30 +261,27 @@ module Subroutine
281
261
 
282
262
  error_object.each do |k,v|
283
263
 
284
- next if self._error_ignores[k.to_sym]
264
+ next if _error_ignores[k.to_sym]
285
265
 
286
- if respond_to?("#{k}")
266
+ if respond_to?(k)
287
267
  errors.add(k, v)
288
- elsif self._error_map[k.to_sym]
289
- errors.add(self._error_map[k.to_sym], v)
268
+ elsif _error_map[k.to_sym]
269
+ errors.add(_error_map[k.to_sym], v)
290
270
  else
291
271
  errors.add(:base, error_object.full_message(k,v))
292
272
  end
293
-
294
273
  end
295
274
 
296
275
  false
297
276
  end
298
277
 
299
-
300
278
  # if you want to use strong parameters or something in your form object you can do so here.
301
279
  # by default we just slice the inputs to the defined fields
302
280
  def sanitize_params(inputs)
303
281
  out = {}.with_indifferent_access
304
- self._fields.each_pair do |field, config|
305
- if inputs.has_key?(field)
306
- out[field] = type_caster.cast(inputs[field], config[:type])
307
- end
282
+ _fields.each_pair do |field, config|
283
+ next unless inputs.key?(field)
284
+ out[field] = ::Subroutine::TypeCaster.cast(inputs[field], config[:type])
308
285
  end
309
286
 
310
287
  out
@@ -313,23 +290,20 @@ module Subroutine
313
290
  def sanitize_defaults
314
291
  defaults = {}.with_indifferent_access
315
292
 
316
- self._fields.each_pair do |field, config|
317
- unless config[:default].nil?
318
- deflt = config[:default]
319
- if deflt.respond_to?(:call)
320
- deflt = deflt.call
321
- elsif deflt.duplicable? # from active_support
322
- # Some classes of default values need to be duplicated, or the instance field value will end up referencing
323
- # the class global default value, and potentially modify it.
324
- deflt = deflt.deep_dup # from active_support
325
- end
326
- defaults[field] = type_caster.cast(deflt, config[:type])
293
+ _fields.each_pair do |field, config|
294
+ next if config[:default].nil?
295
+ deflt = config[:default]
296
+ if deflt.respond_to?(:call)
297
+ deflt = deflt.call
298
+ elsif deflt.duplicable? # from active_support
299
+ # Some classes of default values need to be duplicated, or the instance field value will end up referencing
300
+ # the class global default value, and potentially modify it.
301
+ deflt = deflt.deep_dup # from active_support
327
302
  end
303
+ defaults[field] = ::Subroutine::TypeCaster.cast(deflt, config[:type])
328
304
  end
329
305
 
330
306
  defaults
331
307
  end
332
-
333
308
  end
334
-
335
309
  end
@@ -6,128 +6,97 @@ require 'active_support/core_ext/object/try'
6
6
  require 'active_support/core_ext/array/wrap'
7
7
 
8
8
  module Subroutine
9
- class TypeCaster
9
+ module TypeCaster
10
10
 
11
+ def casters
12
+ @casters ||= {}
13
+ end
14
+ module_function :casters
11
15
 
12
- TYPES = {
13
- :integer => [:int, :integer, :epoch],
14
- :number => [:number, :float],
15
- :decimal => [:decimal, :big_decimal],
16
- :string => [:string, :text],
17
- :boolean => [:bool, :boolean],
18
- :iso_date => [:iso_date],
19
- :iso_time => [:iso_time],
20
- :date => [:date],
21
- :time => [:time, :timestamp],
22
- :hash => [:object, :hashmap, :dict],
23
- :array => [:array]
24
- }
25
-
26
-
27
- def cast(value, type)
28
- return value if value.nil? || type.nil?
29
-
30
- case type.to_sym
31
- when *TYPES[:integer]
32
- cast_number(value, :to_i)
33
- when *TYPES[:number]
34
- cast_number(value, :to_f)
35
- when *TYPES[:decimal]
36
- cast_number(value, :to_d, :to_f)
37
- when *TYPES[:string]
38
- cast_string(value)
39
- when *TYPES[:boolean]
40
- cast_boolean(value)
41
- when *TYPES[:iso_date]
42
- t = cast_iso_time(value)
43
- t ? t.split('T')[0] : t
44
- when *TYPES[:date]
45
- cast_date(value).try(:to_date)
46
- when *TYPES[:iso_time]
47
- cast_iso_time(value)
48
- when *TYPES[:time]
49
- cast_time(value)
50
- when *TYPES[:hash]
51
- cast_hash(value)
52
- when *TYPES[:array]
53
- cast_array(value)
54
- else
55
- value
16
+ def register(*names, &block)
17
+ names.each do |n|
18
+ casters[n] = block
56
19
  end
57
20
  end
21
+ module_function :register
58
22
 
59
- protected
60
-
61
- def cast_number(value, *meths)
62
- return nil if value.blank?
63
- meth = meths.detect{|m| value.respond_to?(m) }
64
- meth ? value.send(meth) : value
65
- end
23
+ def cast(value, type, *args)
24
+ return value if value.nil? || type.nil?
66
25
 
67
- def cast_string(value)
68
- String(value)
26
+ caster = casters[type]
27
+ caster ? caster.call(value, *args) : value
69
28
  end
29
+ module_function :cast
70
30
 
71
- def cast_boolean(value)
72
- !!(cast_string(value) =~ /^(yes|true|1|ok)$/)
73
- end
31
+ end
32
+ end
74
33
 
75
- def cast_time(value)
76
- return nil unless value.present?
77
- ::Time.parse(cast_string(value))
78
- end
34
+ Subroutine::TypeCaster.register :number do |value, *meths|
35
+ next nil if value.blank?
36
+ meth = meths.detect{|m| value.respond_to?(m) }
37
+ meth ? value.send(meth) : value.to_f
38
+ end
79
39
 
80
- def cast_date(value)
81
- return nil unless value.present?
82
- ::Date.parse(cast_string(value))
83
- end
40
+ Subroutine::TypeCaster.register :integer, :int, :epoch do |value|
41
+ Subroutine::TypeCaster.cast(value, :number, :to_i)
42
+ end
84
43
 
85
- def cast_iso_time(value)
86
- return nil unless value.present?
87
- t = nil
88
- t ||= value if value.is_a?(::Time)
89
- t ||= value if value.try(:acts_like?, :time)
90
- t ||= ::Time.parse(cast_string(value))
91
- t.utc.iso8601
92
- end
44
+ Subroutine::TypeCaster.register :decimal, :big_decimal do |value|
45
+ Subroutine::TypeCaster.cast(value, :number, :to_d, :to_f)
46
+ end
93
47
 
94
- def cast_iso_date(value)
95
- return nil unless value.present?
96
- d = nil
97
- d ||= value if value.is_a?(::Date)
98
- d ||= value if value.try(:acts_like?, :date)
99
- d ||= ::Date.parse(cast_string(value))
100
- d.iso8601
101
- end
48
+ Subroutine::TypeCaster.register :string, :text do |value|
49
+ String(value)
50
+ end
102
51
 
103
- def cast_hash(value)
104
- _cast_hash(value).try(:stringify_keys)
105
- end
52
+ Subroutine::TypeCaster.register :boolean, :bool do |value|
53
+ !!(String(value) =~ /^(yes|true|1|ok)$/)
54
+ end
106
55
 
107
- def _cast_hash(value)
108
- return _cast_action_controller_query_params(value) if is_action_controller_query_params?(value)
109
- return value if value.is_a?(Hash)
110
- return {} if value.blank?
111
- return value.to_hash if value.respond_to?(:to_hash)
112
- return value.to_h if value.respond_to?(:to_h)
113
- return ::Hash[value.to_a] if value.respond_to?(:to_a)
114
- {}
115
- end
56
+ Subroutine::TypeCaster.register :iso_date do |value|
57
+ next nil unless value.present?
58
+ d = nil
59
+ d ||= value if value.is_a?(::Date)
60
+ d ||= value if value.try(:acts_like?, :date)
61
+ d ||= ::Date.parse(String(value))
62
+ d.iso8601
63
+ end
116
64
 
117
- def _cast_action_controller_query_params(value)
118
- value = value.to_hash
119
- value.each_pair{|k,v| value[k] = _cast_action_controller_query_params(v) if is_action_controller_query_params?(v) }
120
- value
121
- end
65
+ Subroutine::TypeCaster.register :iso_time do |value|
66
+ next nil unless value.present?
67
+ t = nil
68
+ t ||= value if value.is_a?(::Time)
69
+ t ||= value if value.try(:acts_like?, :time)
70
+ t ||= ::Time.parse(String(value))
71
+ t.utc.iso8601
72
+ end
122
73
 
123
- def is_action_controller_query_params?(value)
124
- value.class.name == "ActionController::Parameters"
125
- end
74
+ Subroutine::TypeCaster.register :date do |value|
75
+ next nil unless value.present?
76
+ ::Date.parse(String(value))
77
+ end
126
78
 
127
- def cast_array(value)
128
- return [] if value.blank?
129
- ::Array.wrap(value)
130
- end
79
+ Subroutine::TypeCaster.register :time, :timestamp, :datetime do |value|
80
+ next nil unless value.present?
81
+ ::Time.parse(String(value))
82
+ end
131
83
 
84
+ Subroutine::TypeCaster.register :hash, :object, :hashmap, :dict do |value|
85
+ if value.class.name == 'ActionController::Parameters'
86
+ value = value.to_hash
87
+ value.each_pair { |k, v| value[k] = Subroutine::TypeCaster.cast(v, :hash) if v.class.name == 'ActionController::Parameters' }
88
+ next value
132
89
  end
90
+
91
+ next value if value.is_a?(Hash)
92
+ next {} if value.blank?
93
+ next value.to_hash if value.respond_to?(:to_hash)
94
+ next value.to_h if value.respond_to?(:to_h)
95
+ next ::Hash[value.to_a] if value.respond_to?(:to_a)
96
+ {}
97
+ end
98
+
99
+ Subroutine::TypeCaster.register :array do |value|
100
+ next [] if value.blank?
101
+ ::Array.wrap(value)
133
102
  end
@@ -1,8 +1,8 @@
1
1
  module Subroutine
2
2
 
3
3
  MAJOR = 0
4
- MINOR = 5
5
- PATCH = 3
4
+ MINOR = 6
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
data/test/support/ops.rb CHANGED
@@ -119,7 +119,6 @@ class TypeCastOp < ::Subroutine::Op
119
119
  iso_time :iso_time_input
120
120
  object :object_input
121
121
  array :array_input, :default => 'foo'
122
-
123
122
  end
124
123
 
125
124
  class OpWithAuth < ::Subroutine::Op
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subroutine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-23 00:00:00.000000000 Z
11
+ date: 2018-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel