subroutine 2.1.1 → 2.2.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
  SHA256:
3
- metadata.gz: 359d2ea93dea5768e77277086229a0dd6e38c90c6f05866e443980a45afd98f9
4
- data.tar.gz: a1282dec003600a234fd8e8a076570f91813681d4eb3afdd84c4193ad8b115bf
3
+ metadata.gz: 8695d158b7e6ab0464d8e7b4a6c9a641b5dde81f422ff139c29eab8bc8512e75
4
+ data.tar.gz: 61a393835d542a613f91335581c114fbd44764809ed78c2f4bd14f463b3c604d
5
5
  SHA512:
6
- metadata.gz: e01d4ab80fce0047950af6511d5b626e740f1a7e1157e283f09a911dbeaab21af01ae5b173c750e7078f57c28f058000e428df4eca784e522496cc8053fb2617
7
- data.tar.gz: 423ddf621546c4d74c1934f476aab6e0da728379490ac7b6d8f0b420b8dde3d101e8a1f0cdb8369908d87dd34fd21ef119627e10c78acd7d88aac8064b65216b
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
 
@@ -56,7 +56,12 @@ module Subroutine
56
56
  unless_conditionals = Array(opts[:unless])
57
57
 
58
58
  meths.each do |meth|
59
- normalized_meth = meth.to_s[0...-1] if meth.to_s.end_with?("?")
59
+ normalized_meth = if normalized_meth.to_s.end_with?("?")
60
+ meth.to_s[0...-1]
61
+ else
62
+ meth
63
+ end
64
+
60
65
  auth_method_name = :"authorize_#{policy_name}_#{normalized_meth}"
61
66
 
62
67
  define_method auth_method_name do
@@ -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 = 1
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
@@ -228,13 +228,19 @@ class PolicyOp < OpWithAuth
228
228
  class FakePolicy
229
229
 
230
230
  def user_can_access?
231
+ true
232
+ end
233
+
234
+ def user_can_do_it
231
235
  false
232
236
  end
233
237
 
234
238
  end
235
239
 
236
240
  require_user!
241
+
237
242
  policy :user_can_access?
243
+ policy :user_can_do_it
238
244
 
239
245
  def policy
240
246
  @policy ||= FakePolicy.new
@@ -411,41 +417,6 @@ class FalsePerformOp < ::Subroutine::Op
411
417
 
412
418
  end
413
419
 
414
- class MissingOutputOp < ::Subroutine::Op
415
-
416
- def perform
417
- output :foo, "bar"
418
- end
419
-
420
- end
421
-
422
- class MissingOutputSetOp < ::Subroutine::Op
423
-
424
- outputs :foo
425
- def perform
426
- true
427
- end
428
-
429
- end
430
-
431
- class OutputNotRequiredOp < ::Subroutine::Op
432
-
433
- outputs :foo, required: false
434
- def perform
435
- true
436
- end
437
-
438
- end
439
-
440
- class NoOutputNoSuccessOp < ::Subroutine::Op
441
-
442
- outputs :foo
443
- def perform
444
- errors.add(:foo, "bar")
445
- end
446
-
447
- end
448
-
449
420
  class ErrorTraceOp < ::Subroutine::Op
450
421
 
451
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.1
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-06 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