subroutine 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28f40979839b106e9e9c4d4714815f29c32cc2bd
4
- data.tar.gz: 5f7724cd96e176c19ed230ca410fcb7ed55d577f
3
+ metadata.gz: 212d37192891dfad2e6fced663590d50f37302ee
4
+ data.tar.gz: 2ded356bfcfe49f9b697aba9784325fe2ce4426a
5
5
  SHA512:
6
- metadata.gz: 670db3c5d3b73bc2791b1c38bf1eabd117d319df84fa5f392daf44698d4b759b8bfd20b465efaf06aafb966618fa0ae679a4fa3ffa39b67aad0a9daeec032ccc
7
- data.tar.gz: e76615aaed90eaeafd518c32865bdf9338c40e80c90332a0eca932d510bd80e271d95b69fe43b56e37fd0a229348d9ba74f8660acf009f6f5ea0ee3440243c5b
6
+ metadata.gz: b4dc8ba20210de9eb5d2260f5cc98f95fe6a9c74e9a0ee625434a683a1773273efdc5461e2356238ca63bd7457c9554748f35fecad40a2153b665b81953ac5d1
7
+ data.tar.gz: cf30411572f31668031cc96ac76cb0ce4edb6132b22f9990a38023d32e312b53468179a31dea8604e25e54e0ac69189a7df13f338559c000d8980bb4aada2a2e
data/README.md CHANGED
@@ -154,9 +154,26 @@ class MyOp < ::Subroutine::Op
154
154
  end
155
155
  ```
156
156
 
157
+ Since ops can use other ops, sometimes it's nice to explicitly state the inputs are valid. To "inherit" all the inputs from another op, simply use `inputs_from`.
158
+
159
+ ```ruby
160
+ class MyOp < ::Subroutine::Op
161
+ string :token
162
+ inputs_from MyOtherOp
163
+
164
+ protected
165
+
166
+ def perform
167
+ verify_token!
168
+ MyOtherOp.submit! params.except(:token)
169
+ end
170
+
171
+ end
172
+ ```
173
+
157
174
  #### Validations
158
175
 
159
- Since Ops inlcude ActiveModel::Model, validations can be used just like any other ActiveModel object.
176
+ Since Ops include ActiveModel::Model, validations can be used just like any other ActiveModel object.
160
177
 
161
178
  ```ruby
162
179
  class MyOp < ::Subroutine::Op
data/lib/subroutine/op.rb CHANGED
@@ -96,15 +96,12 @@ module Subroutine
96
96
 
97
97
  def #{field_name}=(v)
98
98
  config = #{field_name}_config
99
- @#{field_name} = type_caster.cast(v, config[:type])
99
+ v = type_caster.cast(v, config[:type])
100
+ @params["#{field_name}"] = v
100
101
  end
101
102
 
102
103
  def #{field_name}
103
- return @#{field_name} if defined?(@#{field_name})
104
- config = #{field_name}_config
105
- deflt = config[:default]
106
- deflt = deflt.call if deflt.respond_to?(:call)
107
- type_caster.cast(deflt, config[:type])
104
+ @params["#{field_name}"]
108
105
  end
109
106
 
110
107
  def #{field_name}_config
@@ -137,7 +134,7 @@ module Subroutine
137
134
 
138
135
  def initialize(inputs = {})
139
136
  @original_params = inputs.with_indifferent_access
140
- @params = {}
137
+ @params = sanitize_params(@original_params)
141
138
  end
142
139
 
143
140
  def errors
@@ -154,10 +151,6 @@ module Subroutine
154
151
  # the action which should be invoked upon form submission (from the controller)
155
152
  def submit
156
153
  observe_submission do
157
- @params = filter_params(@original_params)
158
-
159
- set_accessors(@params)
160
-
161
154
  validate_and_perform
162
155
  end
163
156
 
@@ -173,15 +166,6 @@ module Subroutine
173
166
 
174
167
  protected
175
168
 
176
- # ensure that our type caster has the opportunity to cast each key
177
- def params
178
- out = {}
179
- @params.keys.each do |k|
180
- out[k] = send(k)
181
- end
182
- out
183
- end
184
-
185
169
  def type_caster
186
170
  @type_caster ||= ::Subroutine::TypeCaster.new
187
171
  end
@@ -247,15 +231,19 @@ module Subroutine
247
231
 
248
232
  # if you want to use strong parameters or something in your form object you can do so here.
249
233
  # by default we just slice the inputs to the defined fields
250
- def filter_params(inputs)
251
- inputs.slice(*_fields.keys)
252
- end
253
-
254
-
255
- def set_accessors(inputs)
256
- inputs.each do |key, value|
257
- send("#{key}=", value) if respond_to?("#{key}=")
234
+ def sanitize_params(inputs)
235
+ out = {}.with_indifferent_access
236
+ self._fields.each_pair do |field, config|
237
+ if inputs.has_key?(field)
238
+ out[field] = type_caster.cast(inputs[field], config[:type])
239
+ elsif config[:default]
240
+ deflt = config[:default]
241
+ deflt = deflt.call if deflt.respond_to?(:call)
242
+ out[field] = type_caster.cast(deflt, config[:type])
243
+ end
258
244
  end
245
+
246
+ out
259
247
  end
260
248
 
261
249
  end
@@ -1,5 +1,6 @@
1
1
  require 'date'
2
2
  require 'time'
3
+ require 'bigdecimal'
3
4
  require 'active_support/core_ext/object/blank'
4
5
  require 'active_support/core_ext/object/try'
5
6
  require 'active_support/core_ext/array/wrap'
@@ -10,7 +11,8 @@ module Subroutine
10
11
 
11
12
  TYPES = {
12
13
  :integer => [:int, :integer, :epoch],
13
- :number => [:number, :float, :decimal],
14
+ :number => [:number, :float],
15
+ :decimal => [:decimal, :big_decimal],
14
16
  :string => [:string, :text],
15
17
  :boolean => [:bool, :boolean],
16
18
  :iso_date => [:iso_date],
@@ -29,7 +31,10 @@ module Subroutine
29
31
  when *TYPES[:integer]
30
32
  cast_number(value).try(:to_i)
31
33
  when *TYPES[:number]
32
- cast_number(value)
34
+ cast_number(value).try(:to_f)
35
+ when *TYPES[:decimal]
36
+ d = cast_number(value)
37
+ d ? BigDecimal(d.to_s) : nil
33
38
  when *TYPES[:string]
34
39
  cast_string(value)
35
40
  when *TYPES[:boolean]
@@ -57,7 +62,7 @@ module Subroutine
57
62
  def cast_number(value)
58
63
  val = cast_string(value).strip
59
64
  return nil if val.blank?
60
- val.to_f
65
+ val
61
66
  end
62
67
 
63
68
  def cast_string(value)
@@ -1,8 +1,8 @@
1
1
  module Subroutine
2
2
 
3
3
  MAJOR = 0
4
- MINOR = 1
5
- PATCH = 4
4
+ MINOR = 2
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
@@ -144,5 +144,29 @@ module Subroutine
144
144
  assert_equal [], op.errors[:whatever]
145
145
  end
146
146
 
147
+ def test_it_sets_the_params_immediately_and_includes_defaults
148
+ op = ::AdminSignupOp.new(email: "foo")
149
+ assert_equal({
150
+ "priveleges" => "min",
151
+ "email" => "foo"
152
+ }, op.params)
153
+ end
154
+
155
+ def test_it_overrides_defaults_with_nils
156
+ op = ::AdminSignupOp.new(email: "foo", priveleges: nil)
157
+ assert_equal({
158
+ "priveleges" => nil,
159
+ "email" => "foo"
160
+ }, op.params)
161
+ end
162
+
163
+ def test_it_casts_params_on_the_way_in
164
+ op = ::TypeCastOp.new(integer_input: "25")
165
+ assert_equal(25, op.params["integer_input"])
166
+
167
+ op.decimal_input = "25.3"
168
+ assert_equal(BigDecimal("25.3"), op.params["decimal_input"])
169
+ end
170
+
147
171
  end
148
172
  end
@@ -115,8 +115,8 @@ module Subroutine
115
115
  op.object_input = {foo: 'bar'}
116
116
  assert_equal({'foo' => 'bar'}, op.object_input)
117
117
 
118
- op.object_input = {"foo" => {:bar => :baz}}
119
- assert_equal({"foo" => {:bar => :baz}}, op.object_input)
118
+ op.object_input = {"foo" => {"bar" => :baz}}
119
+ assert_equal({"foo" => {"bar" => :baz}}, op.object_input)
120
120
  end
121
121
 
122
122
  def test_array_inputs
@@ -132,8 +132,8 @@ module Subroutine
132
132
  op.array_input = ['foo']
133
133
  assert_equal ['foo'], op.array_input
134
134
 
135
- op.array_input = {:bar => true}
136
- assert_equal [{:bar => true}], op.array_input
135
+ op.array_input = {"bar" => true}
136
+ assert_equal [{"bar" => true}], op.array_input
137
137
  end
138
138
 
139
139
  def test_date_inputs
data/test/support/ops.rb CHANGED
@@ -98,6 +98,7 @@ class TypeCastOp < ::Subroutine::Op
98
98
 
99
99
  integer :integer_input
100
100
  number :number_input
101
+ decimal :decimal_input
101
102
  string :string_input
102
103
  boolean :boolean_input
103
104
  date :date_input
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subroutine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.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: 2015-10-03 00:00:00.000000000 Z
11
+ date: 2016-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 4.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 4.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.7'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.7'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '10.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: minitest-reporters
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  description: An interface for creating feature-driven operations.
@@ -87,8 +87,8 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
- - ".gitignore"
91
- - ".travis.yml"
90
+ - .gitignore
91
+ - .travis.yml
92
92
  - Gemfile
93
93
  - LICENSE.txt
94
94
  - README.md
@@ -120,17 +120,17 @@ require_paths:
120
120
  - lib
121
121
  required_ruby_version: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - ">="
123
+ - - '>='
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - ">="
128
+ - - '>='
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
131
  requirements: []
132
132
  rubyforge_project:
133
- rubygems_version: 2.4.6
133
+ rubygems_version: 2.0.14.1
134
134
  signing_key:
135
135
  specification_version: 4
136
136
  summary: Feature-driven operation objects.