subroutine 2.1.2 → 2.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
  SHA256:
3
- metadata.gz: 63080af90148b6faaff42be6f9753d6f5ef36f3f8ebe650a1372905836f5e208
4
- data.tar.gz: 9522cbaf937f5bdfa85fbb629ad8a1f3f014dce6ea42784ef68b39c4ecebad49
3
+ metadata.gz: 8695d158b7e6ab0464d8e7b4a6c9a641b5dde81f422ff139c29eab8bc8512e75
4
+ data.tar.gz: 61a393835d542a613f91335581c114fbd44764809ed78c2f4bd14f463b3c604d
5
5
  SHA512:
6
- metadata.gz: a76f25b779fd8a9ccc3958febe5b68906d7260f052b5200d6b080680f9f80f79debebe2bf35ee199f6996cccd827f0844e3710d30f0ee367dd248c6900f45c74
7
- data.tar.gz: c3e50c34de7e4f656168cec625bccb1bede1fcd4dbbdd5bef7d9d0dabf9a2695a470dd749b2ec5785448b6cd45c0c3454b469d49a157e9d19fffc2ada78b75ce
6
+ metadata.gz: '011484de567ba987afdc22abcd3aa198ae1cf62ecca93c42412cacab2ef14832d5eb343d64150cbed7f8fc06526709a05918a4a5e0cd8f655e4c6d903cc9c40f'
7
+ data.tar.gz: 40bda69b27c0ec4fd2ca152136918809da4a5b1793b9732bc8e0910714213a4696230a21fc3872e76294d75b6550ba106c52ec0a262d334b2b2da4c8b06bc132
@@ -0,0 +1,23 @@
1
+ name: build
2
+ on: [push, pull_request]
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ continue-on-error: ${{ matrix.experimental }}
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ ruby-version: [2.7.5, 2.7.6]
11
+ experimental: [false]
12
+ include:
13
+ - ruby-version: 3.0
14
+ experimental: true
15
+ - ruby-version: 3.1
16
+ experimental: true
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby-version }}
22
+ bundler-cache: true # runs `bundle install` and caches installed gems automatically
23
+ - run: bundle exec rake test
data/CHANGELOG.MD CHANGED
@@ -1,3 +1,7 @@
1
+ ## Subroutine 2.2
2
+
3
+ Add `type` validation for Output.
4
+
1
5
  ## Subroutine 2.0
2
6
 
3
7
  The updates between 1.0 and 2.0 are relatively minor and are focused more on cleaning up the codebase and extending the use of the 0.9->1.0 refactor. There are, however, breaking changes to how associations are loaded. The association is no longer loaded via `find()` but rather `find_by!(id:)`. Given this, a major version was released.
data/README.md CHANGED
@@ -21,7 +21,7 @@ class SignupOp < ::Subroutine::Op
21
21
  validates :company_name, presence: true
22
22
 
23
23
  outputs :user
24
- outputs :business
24
+ outputs :business, type: Business # validate that output type is an instance of Business
25
25
 
26
26
  protected
27
27
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Subroutine
4
+ module Outputs
5
+ class InvalidOutputTypeError < StandardError
6
+
7
+ def initialize(name:, expected_type:, actual_type:)
8
+ super("Invalid output type for '#{name}' expected #{expected_type} but got #{actual_type}")
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -4,6 +4,7 @@ require "active_support/concern"
4
4
  require "subroutine/outputs/configuration"
5
5
  require "subroutine/outputs/output_not_set_error"
6
6
  require "subroutine/outputs/unknown_output_error"
7
+ require "subroutine/outputs/invalid_output_type_error"
7
8
 
8
9
  module Subroutine
9
10
  module Outputs
@@ -39,16 +40,6 @@ module Subroutine
39
40
  @outputs = {} # don't do with_indifferent_access because it will turn provided objects into with_indifferent_access objects, which may not be the desired behavior
40
41
  end
41
42
 
42
- def output_provided?(name)
43
- name = name.to_sym
44
-
45
- unless output_configurations.key?(name)
46
- raise ::Subroutine::Outputs::UnknownOutputError, name
47
- end
48
-
49
- outputs.key?(name)
50
- end
51
-
52
43
  def output(name, value)
53
44
  name = name.to_sym
54
45
  unless output_configurations.key?(name)
@@ -70,8 +61,33 @@ module Subroutine
70
61
  if config.required? && !output_provided?(name)
71
62
  raise ::Subroutine::Outputs::OutputNotSetError, name
72
63
  end
64
+ unless valid_output_type?(name)
65
+ name = name.to_sym
66
+ raise ::Subroutine::Outputs::InvalidOutputTypeError.new(
67
+ name: name,
68
+ actual_type: outputs[name].class,
69
+ expected_type: output_configurations[name][:type]
70
+ )
71
+ end
73
72
  end
74
73
  end
75
74
 
75
+ def output_provided?(name)
76
+ name = name.to_sym
77
+
78
+ outputs.key?(name)
79
+ end
80
+
81
+ def valid_output_type?(name)
82
+ name = name.to_sym
83
+
84
+ return true unless output_configurations.key?(name)
85
+
86
+ output_configuration = output_configurations[name]
87
+ return true unless output_configuration[:type]
88
+ return true if !output_configuration.required? && outputs[name].nil?
89
+
90
+ outputs[name].is_a?(output_configuration[:type])
91
+ end
76
92
  end
77
93
  end
@@ -3,8 +3,8 @@
3
3
  module Subroutine
4
4
 
5
5
  MAJOR = 2
6
- MINOR = 1
7
- PATCH = 2
6
+ MINOR = 2
7
+ PATCH = 0
8
8
  PRE = nil
9
9
 
10
10
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
@@ -264,30 +264,6 @@ module Subroutine
264
264
  assert_equal Hash, value.class
265
265
  end
266
266
 
267
- def test_it_raises_an_error_if_an_output_is_not_defined_but_is_set
268
- op = ::MissingOutputOp.new
269
- assert_raises ::Subroutine::Outputs::UnknownOutputError do
270
- op.submit
271
- end
272
- end
273
-
274
- def test_it_raises_an_error_if_not_all_outputs_were_set
275
- op = ::MissingOutputSetOp.new
276
- assert_raises ::Subroutine::Outputs::OutputNotSetError do
277
- op.submit
278
- end
279
- end
280
-
281
- def test_it_does_not_raise_an_error_if_output_is_not_set_and_is_not_required
282
- op = ::OutputNotRequiredOp.new
283
- op.submit
284
- end
285
-
286
- def test_it_does_not_raise_an_error_if_the_perform_is_not_a_success
287
- op = ::NoOutputNoSuccessOp.new
288
- refute op.submit
289
- end
290
-
291
267
  def test_it_does_not_omit_the_backtrace_from_the_original_error
292
268
  op = ::ErrorTraceOp.new
293
269
  begin
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module Subroutine
6
+ class OutputsTest < TestCase
7
+ class MissingOutputOp < ::Subroutine::Op
8
+ def perform
9
+ output :foo, 'bar'
10
+ end
11
+ end
12
+
13
+ class MissingOutputSetOp < ::Subroutine::Op
14
+ outputs :foo
15
+ def perform
16
+ true
17
+ end
18
+ end
19
+
20
+ class OutputNotRequiredOp < ::Subroutine::Op
21
+ outputs :foo, required: false
22
+ def perform
23
+ true
24
+ end
25
+ end
26
+
27
+ class NoOutputNoSuccessOp < ::Subroutine::Op
28
+ outputs :foo
29
+
30
+ def perform
31
+ errors.add(:foo, 'bar')
32
+ end
33
+ end
34
+
35
+ class OutputWithTypeValidationNotRequired < ::Subroutine::Op
36
+ outputs :value, type: String, required: false
37
+
38
+ def perform; end
39
+ end
40
+
41
+ class OutputWithTypeValidationRequired < ::Subroutine::Op
42
+ outputs :value, type: String, required: true
43
+
44
+ def perform; end
45
+ end
46
+
47
+ def test_it_raises_an_error_if_an_output_is_not_defined_but_is_set
48
+ op = MissingOutputOp.new
49
+ assert_raises ::Subroutine::Outputs::UnknownOutputError do
50
+ op.submit
51
+ end
52
+ end
53
+
54
+ def test_it_raises_an_error_if_not_all_outputs_were_set
55
+ op = MissingOutputSetOp.new
56
+ assert_raises ::Subroutine::Outputs::OutputNotSetError do
57
+ op.submit
58
+ end
59
+ end
60
+
61
+ def test_it_does_not_raise_an_error_if_output_is_not_set_and_is_not_required
62
+ op = OutputNotRequiredOp.new
63
+ op.submit
64
+ end
65
+
66
+ def test_it_does_not_raise_an_error_if_the_perform_is_not_a_success
67
+ op = NoOutputNoSuccessOp.new
68
+ refute op.submit
69
+ end
70
+
71
+ ###################
72
+ # type validation #
73
+ ###################
74
+
75
+ def test_it_does_not_raise_an_error_if_output_is_set_to_the_right_type
76
+ op = OutputWithTypeValidationNotRequired.new
77
+ op.send(:output, :value, 'foo')
78
+ assert op.submit
79
+ end
80
+
81
+ def test_it_raises_an_error_if_output_is_not_set_to_the_right_type
82
+ op = OutputWithTypeValidationNotRequired.new
83
+ op.send(:output, :value, 1)
84
+ assert_raises ::Subroutine::Outputs::InvalidOutputTypeError do
85
+ op.submit
86
+ end
87
+ end
88
+
89
+ def test_it_does_not_raise_an_error_if_output_is_set_to_nil_when_there_is_type_validation_and_not_required
90
+ op = OutputWithTypeValidationNotRequired.new
91
+ op.send(:output, :value, nil)
92
+ op.submit
93
+ end
94
+
95
+ def test_it_raises_an_error_if_output_is_set_to_nil_when_there_is_type_validation_and_is_required
96
+ op = OutputWithTypeValidationRequired.new
97
+ op.send(:output, :value, nil)
98
+ assert_raises ::Subroutine::Outputs::InvalidOutputTypeError do
99
+ op.submit
100
+ end
101
+ end
102
+ end
103
+ end
data/test/support/ops.rb CHANGED
@@ -417,41 +417,6 @@ class FalsePerformOp < ::Subroutine::Op
417
417
 
418
418
  end
419
419
 
420
- class MissingOutputOp < ::Subroutine::Op
421
-
422
- def perform
423
- output :foo, "bar"
424
- end
425
-
426
- end
427
-
428
- class MissingOutputSetOp < ::Subroutine::Op
429
-
430
- outputs :foo
431
- def perform
432
- true
433
- end
434
-
435
- end
436
-
437
- class OutputNotRequiredOp < ::Subroutine::Op
438
-
439
- outputs :foo, required: false
440
- def perform
441
- true
442
- end
443
-
444
- end
445
-
446
- class NoOutputNoSuccessOp < ::Subroutine::Op
447
-
448
- outputs :foo
449
- def perform
450
- errors.add(:foo, "bar")
451
- end
452
-
453
- end
454
-
455
420
  class ErrorTraceOp < ::Subroutine::Op
456
421
 
457
422
  class SomeObject
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: 2.1.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-07 00:00:00.000000000 Z
11
+ date: 2022-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -157,10 +157,10 @@ executables: []
157
157
  extensions: []
158
158
  extra_rdoc_files: []
159
159
  files:
160
+ - ".github/workflows/build.yml"
160
161
  - ".gitignore"
161
162
  - ".ruby-gemset"
162
163
  - ".ruby-version"
163
- - ".travis.yml"
164
164
  - CHANGELOG.MD
165
165
  - Gemfile
166
166
  - LICENSE.txt
@@ -187,6 +187,7 @@ files:
187
187
  - lib/subroutine/op.rb
188
188
  - lib/subroutine/outputs.rb
189
189
  - lib/subroutine/outputs/configuration.rb
190
+ - lib/subroutine/outputs/invalid_output_type_error.rb
190
191
  - lib/subroutine/outputs/output_not_set_error.rb
191
192
  - lib/subroutine/outputs/unknown_output_error.rb
192
193
  - lib/subroutine/type_caster.rb
@@ -196,6 +197,7 @@ files:
196
197
  - test/subroutine/auth_test.rb
197
198
  - test/subroutine/base_test.rb
198
199
  - test/subroutine/fields_test.rb
200
+ - test/subroutine/outputs_test.rb
199
201
  - test/subroutine/type_caster_test.rb
200
202
  - test/support/ops.rb
201
203
  - test/test_helper.rb
@@ -203,7 +205,7 @@ homepage: https://github.com/mnelson/subroutine
203
205
  licenses:
204
206
  - MIT
205
207
  metadata: {}
206
- post_install_message:
208
+ post_install_message:
207
209
  rdoc_options: []
208
210
  require_paths:
209
211
  - lib
@@ -219,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
221
  version: '0'
220
222
  requirements: []
221
223
  rubygems_version: 3.1.6
222
- signing_key:
224
+ signing_key:
223
225
  specification_version: 4
224
226
  summary: Feature-driven operation objects.
225
227
  test_files:
@@ -233,6 +235,7 @@ test_files:
233
235
  - test/subroutine/auth_test.rb
234
236
  - test/subroutine/base_test.rb
235
237
  - test/subroutine/fields_test.rb
238
+ - test/subroutine/outputs_test.rb
236
239
  - test/subroutine/type_caster_test.rb
237
240
  - test/support/ops.rb
238
241
  - test/test_helper.rb
data/.travis.yml DELETED
@@ -1,20 +0,0 @@
1
- language: ruby
2
- sudo: false
3
-
4
- rvm:
5
- - 2.4.6
6
- - 2.5.5
7
- - 2.6.3
8
-
9
- gemfile:
10
- - gemfiles/am41.gemfile
11
- - gemfiles/am42.gemfile
12
- - gemfiles/am50.gemfile
13
- - gemfiles/am51.gemfile
14
- - gemfiles/am52.gemfile
15
- - gemfiles/am60.gemfile
16
-
17
- matrix:
18
- exclude:
19
- - rvm: 2.4.6
20
- gemfile: gemfiles/am60.gemfile