subroutine 0.3.4 → 0.4.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: d28f248f1e76c10fb53fcbf1fc376a7f2c6800cd
4
- data.tar.gz: b81a6050e1c2245e545b39dd99d396f80925a92e
3
+ metadata.gz: 3ce8addef08d4ac3a2acc33ebd1336e1acbeadf4
4
+ data.tar.gz: 461466c26f1da36c13d468c2cdf7d7251b8ef7f6
5
5
  SHA512:
6
- metadata.gz: 27f2215a662339b46a5bd7a73a1822915d95a9144fc28f09dac0bd632020629d2ca6ec6aab6497a5c7b3452946b816dd8cdb5fbe99e96a359ac11e9f205915c6
7
- data.tar.gz: 260a8d6f175d715175376c8072d25318b0db4c467cff433c95458ede1788bd985c9ef0619e0ad3db4d707ef3978820a259e0af5c22b58edc51a60014533c18d2
6
+ metadata.gz: 3562274bd7a30c17d62530fd4ae8e7031326e44a2d2c6ac94fd329200bac3e9b20f3c13e4fa7aee9b50597b1fd3377fbf04a2f5fbc23978ccbb599ab3b2f30b1
7
+ data.tar.gz: 0ac228d98a9cd17ff9b9dc33649eaaf434579e96c641b2e0560d45c602a98bfad6d04debe89cdf99b2c77aed9217d3657036dbfeb96921b09309888acedefbab
data/lib/subroutine/op.rb CHANGED
@@ -4,6 +4,8 @@ require 'active_model'
4
4
  require "subroutine/failure"
5
5
  require "subroutine/type_caster"
6
6
  require "subroutine/filtered_errors"
7
+ require "subroutine/output_not_set_error"
8
+ require "subroutine/unknown_output_error"
7
9
 
8
10
  module Subroutine
9
11
 
@@ -12,6 +14,10 @@ module Subroutine
12
14
  include ::ActiveModel::Model
13
15
  include ::ActiveModel::Validations::Callbacks
14
16
 
17
+ DEFAULT_OUTPUT_OPTIONS = {
18
+ required: true
19
+ }.freeze
20
+
15
21
  class << self
16
22
 
17
23
  ::Subroutine::TypeCaster::TYPES.values.flatten.each do |caster|
@@ -41,6 +47,18 @@ module Subroutine
41
47
 
42
48
  alias_method :fields, :field
43
49
 
50
+ def output(name, options = {})
51
+ self._outputs = self._outputs.merge({
52
+ name.to_sym => DEFAULT_OUTPUT_OPTIONS.merge(options)
53
+ })
54
+
55
+ class_eval <<-EV, __FILE__, __LINE__ + 1
56
+ def #{name}
57
+ @outputs[:#{name}]
58
+ end
59
+ EV
60
+ end
61
+
44
62
  def ignore_error(*field_names)
45
63
  field_names.each do |f|
46
64
  _ignore_errors(f)
@@ -124,6 +142,9 @@ module Subroutine
124
142
  end
125
143
 
126
144
 
145
+ class_attribute :_outputs
146
+ self._outputs = {}
147
+
127
148
  class_attribute :_fields
128
149
  self._fields = {}
129
150
 
@@ -141,12 +162,20 @@ module Subroutine
141
162
  @original_params = inputs.with_indifferent_access
142
163
  @params = sanitize_params(@original_params)
143
164
  @defaults = sanitize_defaults
165
+ @outputs = {}
144
166
  end
145
167
 
146
168
  def errors
147
169
  @filtered_errors ||= Subroutine::FilteredErrors.new(super)
148
170
  end
149
171
 
172
+ def output(name, value)
173
+ unless _outputs.key?(name.to_sym)
174
+ raise ::Subroutine::UnknownOutputError.new(name)
175
+ end
176
+ @outputs[name.to_sym] = value
177
+ end
178
+
150
179
  def submit!
151
180
  unless submit
152
181
  raise ::Subroutine::Failure.new(self)
@@ -156,10 +185,20 @@ module Subroutine
156
185
 
157
186
  # the action which should be invoked upon form submission (from the controller)
158
187
  def submit
159
- observe_submission do
188
+ result = observe_submission do
160
189
  validate_and_perform
161
190
  end
162
191
 
192
+ if result
193
+ _outputs.each_pair do |name, config|
194
+ if config[:required] && !@outputs.key?(name)
195
+ raise ::Subroutine::OutputNotSetError.new(name)
196
+ end
197
+ end
198
+ end
199
+
200
+ result
201
+
163
202
  rescue Exception => e
164
203
 
165
204
  if e.respond_to?(:record)
@@ -0,0 +1,8 @@
1
+ module Subroutine
2
+ class OutputNotSetError < StandardError
3
+ def initialize(name)
4
+ super("Expected output '#{name}' to be set upon completion of perform but was not.")
5
+ end
6
+ end
7
+
8
+ end
@@ -0,0 +1,8 @@
1
+ module Subroutine
2
+ class UnknownOutputError < StandardError
3
+ def initialize(name)
4
+ super("Unknown output '#{name}'")
5
+ end
6
+ end
7
+
8
+ end
@@ -1,8 +1,8 @@
1
1
  module Subroutine
2
2
 
3
3
  MAJOR = 0
4
- MINOR = 3
5
- PATCH = 4
4
+ MINOR = 4
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
@@ -195,5 +195,36 @@ module Subroutine
195
195
  assert_equal(BigDecimal("25.3"), op.params_with_defaults["decimal_input"])
196
196
  end
197
197
 
198
+ def test_it_allow_retrival_of_outputs
199
+ op = ::SignupOp.submit!(:email => 'foo@bar.com', :password => 'password123')
200
+ u = op.created_user
201
+
202
+ assert_equal "foo@bar.com", u.email_address
203
+ end
204
+
205
+ def test_it_raises_an_error_if_an_output_is_not_defined_but_is_set
206
+ op = ::MissingOutputOp.new
207
+ assert_raises ::Subroutine::UnknownOutputError do
208
+ op.submit
209
+ end
210
+ end
211
+
212
+ def test_it_raises_an_error_if_not_all_outputs_were_set
213
+ op = ::MissingOutputSetOp.new
214
+ assert_raises ::Subroutine::OutputNotSetError do
215
+ op.submit
216
+ end
217
+ end
218
+
219
+ def test_it_does_not_raise_an_error_if_output_is_not_set_and_is_not_required
220
+ op = ::OutputNotRequiredOp.new
221
+ op.submit
222
+ end
223
+
224
+ def test_it_does_not_raise_an_error_if_the_perform_is_not_a_success
225
+ op = ::NoOutputNoSuccessOp.new
226
+ refute op.submit
227
+ end
228
+
198
229
  end
199
230
  end
@@ -164,6 +164,9 @@ module Subroutine
164
164
  assert_equal 2020, op.date_input.year
165
165
  assert_equal 5, op.date_input.month
166
166
  assert_equal 3, op.date_input.day
167
+
168
+ op.date_input = false
169
+ assert_nil op.date_input
167
170
  end
168
171
 
169
172
 
data/test/support/ops.rb CHANGED
@@ -28,15 +28,15 @@ class SignupOp < ::Subroutine::Op
28
28
  validates :email, :presence => true
29
29
  validates :password, :presence => true
30
30
 
31
- attr_reader :perform_called
32
- attr_reader :perform_finished
31
+ output :perform_called
32
+ output :perform_finished
33
33
 
34
- attr_reader :created_user
34
+ output :created_user
35
35
 
36
36
  protected
37
37
 
38
38
  def perform
39
- @perform_called = true
39
+ output :perform_called, true
40
40
  u = build_user
41
41
 
42
42
  unless u.valid?
@@ -44,9 +44,8 @@ class SignupOp < ::Subroutine::Op
44
44
  return false
45
45
  end
46
46
 
47
- @perform_finished = true
48
- @created_user = u
49
-
47
+ output :perform_finished, true
48
+ output :created_user, u
50
49
  true
51
50
  end
52
51
 
@@ -201,3 +200,30 @@ end
201
200
  class InheritedPolymorphicAssociationOp < ::Subroutine::Op
202
201
  inputs_from PolymorphicAssociationOp
203
202
  end
203
+
204
+ class MissingOutputOp < ::Subroutine::Op
205
+ def perform
206
+ output :foo, "bar"
207
+ end
208
+ end
209
+
210
+ class MissingOutputSetOp < ::Subroutine::Op
211
+ output :foo
212
+ def perform
213
+ true
214
+ end
215
+ end
216
+
217
+ class OutputNotRequiredOp < ::Subroutine::Op
218
+ output :foo, required: false
219
+ def perform
220
+ true
221
+ end
222
+ end
223
+
224
+ class NoOutputNoSuccessOp < ::Subroutine::Op
225
+ output :foo
226
+ def perform
227
+ false
228
+ end
229
+ end
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.3.4
4
+ version: 0.4.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: 2017-04-04 00:00:00.000000000 Z
11
+ date: 2017-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -119,7 +119,9 @@ files:
119
119
  - lib/subroutine/failure.rb
120
120
  - lib/subroutine/filtered_errors.rb
121
121
  - lib/subroutine/op.rb
122
+ - lib/subroutine/output_not_set_error.rb
122
123
  - lib/subroutine/type_caster.rb
124
+ - lib/subroutine/unknown_output_error.rb
123
125
  - lib/subroutine/version.rb
124
126
  - subroutine.gemspec
125
127
  - test/subroutine/association_test.rb