subroutine 2.0.0.beta2 → 2.1.1

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: bc8eb530552fea8e2bacd033372826e11c57734d9695973ebca956c76aa2ed93
4
- data.tar.gz: 908764a3fc127881b4c719c2c5523ae280771683e765ea8f47ddda52bed76a33
3
+ metadata.gz: 359d2ea93dea5768e77277086229a0dd6e38c90c6f05866e443980a45afd98f9
4
+ data.tar.gz: a1282dec003600a234fd8e8a076570f91813681d4eb3afdd84c4193ad8b115bf
5
5
  SHA512:
6
- metadata.gz: 4de2ad64fede40a510afe5b0af073eb6fae1800a61e2f9387337c1d46475ec439c1c35cb393ecececb3a5954b7c9e1b32be10e6be963dc7ce3fb840d40a3b368
7
- data.tar.gz: 9ec24f1a6ce47edb502bded197096dec4d1ff444c4d3b0fda64291111aa7a29e67e7bd4f8e01a018c72795117c40e16fa3c68131b64db346e3c1073611c8134e
6
+ metadata.gz: e01d4ab80fce0047950af6511d5b626e740f1a7e1157e283f09a911dbeaab21af01ae5b173c750e7078f57c28f058000e428df4eca784e522496cc8053fb2617
7
+ data.tar.gz: 423ddf621546c4d74c1934f476aab6e0da728379490ac7b6d8f0b420b8dde3d101e8a1f0cdb8369908d87dd34fd21ef119627e10c78acd7d88aac8064b65216b
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.5.7
1
+ 2.7.5
data/CHANGELOG.MD CHANGED
@@ -1,3 +1,9 @@
1
+ ## Subroutine 2.0
2
+
3
+ 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.
4
+
5
+ **Note:** 2.0.0 was released with a bug and subsequently yanked. 2.0.1 is the first available 2.x version.
6
+
1
7
  ## Subroutine 1.0
2
8
 
3
9
  A massive refactor took place between 0.9 and 1.0, including breaking changes. The goal was to reduce complexity, simplify backtraces, and increase the overall safety and reliability of the library.
@@ -9,11 +9,13 @@ module Subroutine
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
- class_attribute :authorization_declared, instance_writer: false
13
- self.authorization_declared = false
12
+ class_attribute :authorization_checks
13
+ self.authorization_checks = []
14
14
 
15
15
  class_attribute :user_class_name, instance_writer: false
16
16
  self.user_class_name = "User"
17
+
18
+ validate :validate_authorization_checks, unless: :skip_auth_checks?
17
19
  end
18
20
 
19
21
  module ClassMethods
@@ -22,28 +24,24 @@ module Subroutine
22
24
  [user_class_name, "Integer", "NilClass"].compact
23
25
  end
24
26
 
25
- def authorize(validation_name)
26
- validate validation_name, unless: :skip_auth_checks?
27
+ def authorization_declared?
28
+ authorization_checks.any?
29
+ end
30
+
31
+ def authorize(check_name)
32
+ self.authorization_checks += [check_name.to_sym]
27
33
  end
28
34
 
29
35
  def no_user_requirements!
30
- self.authorization_declared = true
36
+ authorize :authorize_user_not_required
31
37
  end
32
38
 
33
39
  def require_user!
34
- self.authorization_declared = true
35
-
36
- validate unless: :skip_auth_checks? do
37
- unauthorized! unless current_user.present?
38
- end
40
+ authorize :authorize_user_required
39
41
  end
40
42
 
41
43
  def require_no_user!
42
- self.authorization_declared = true
43
-
44
- validate unless: :skip_auth_checks? do
45
- unauthorized! :empty_unauthorized if current_user.present?
46
- end
44
+ authorize :authorize_no_user_required
47
45
  end
48
46
 
49
47
  # policy :can_update_user
@@ -57,33 +55,45 @@ module Subroutine
57
55
  if_conditionals = Array(opts[:if])
58
56
  unless_conditionals = Array(opts[:unless])
59
57
 
60
- validate unless: :skip_auth_checks? do
61
- run_it = true
62
- # http://guides.rubyonrails.org/active_record_validations.html#combining-validation-conditions
58
+ meths.each do |meth|
59
+ normalized_meth = meth.to_s[0...-1] if meth.to_s.end_with?("?")
60
+ auth_method_name = :"authorize_#{policy_name}_#{normalized_meth}"
63
61
 
64
- # The validation only runs when all the :if conditions
65
- if if_conditionals.present?
66
- run_it &&= if_conditionals.all? { |i| send(i) }
67
- end
62
+ define_method auth_method_name do
63
+ run_it = true
64
+ # http://guides.rubyonrails.org/active_record_validations.html#combining-validation-conditions
68
65
 
69
- # and none of the :unless conditions are evaluated to true.
70
- if unless_conditionals.present?
71
- run_it &&= unless_conditionals.none? { |u| send(u) }
72
- end
66
+ # The validation only runs when all the :if conditions evaluate to true
67
+ if if_conditionals.present?
68
+ run_it &&= if_conditionals.all? { |i| send(i) }
69
+ end
70
+
71
+ # and none of the :unless conditions are evaluated to true.
72
+ if unless_conditionals.present?
73
+ run_it &&= unless_conditionals.none? { |u| send(u) }
74
+ end
75
+
76
+ return unless run_it
77
+
78
+ p = send(policy_name)
79
+ unauthorized! unless p
73
80
 
74
- next unless run_it
81
+ result = if p.respond_to?("#{normalized_meth}?")
82
+ p.send("#{normalized_meth}?")
83
+ else
84
+ p.send(normalized_meth)
85
+ end
75
86
 
76
- p = send(policy_name)
77
- if !p || meths.any? { |m| !(p.respond_to?("#{m}?") ? p.send("#{m}?") : p.send(m)) }
78
- unauthorized! opts[:error]
87
+ unauthorized! opts[:error] unless result
79
88
  end
89
+
90
+ authorize auth_method_name
80
91
  end
81
92
  end
82
-
83
93
  end
84
94
 
85
95
  def initialize(*args, &block)
86
- raise Subroutine::Auth::AuthorizationNotDeclaredError unless self.class.authorization_declared
96
+ raise Subroutine::Auth::AuthorizationNotDeclaredError unless self.class.authorization_declared?
87
97
 
88
98
  @skip_auth_checks = false
89
99
 
@@ -124,5 +134,23 @@ module Subroutine
124
134
  raise ::Subroutine::Auth::NotAuthorizedError, reason
125
135
  end
126
136
 
137
+ def validate_authorization_checks
138
+ authorization_checks.each do |check|
139
+ send(check)
140
+ end
141
+ end
142
+
143
+ def authorize_user_not_required
144
+ true
145
+ end
146
+
147
+ def authorize_user_required
148
+ unauthorized! unless current_user.present?
149
+ end
150
+
151
+ def authorize_no_user_required
152
+ unauthorized! :empty_unauthorized if current_user.present?
153
+ end
154
+
127
155
  end
128
156
  end
@@ -216,9 +216,9 @@ module Subroutine
216
216
  field_provided?(name) ? all_params[name] : all_default_params[name]
217
217
  end
218
218
 
219
- def set_field(name, value, track_provided: true)
219
+ def set_field(name, value, opts = {})
220
220
  config = get_field_config(name)
221
- @provided_fields[name] = true if track_provided
221
+ @provided_fields[name] = true unless opts[:track_provided] == false
222
222
  value = attempt_cast(value, config) do |e|
223
223
  "Error during assignment of field `#{name}`: #{e}"
224
224
  end
@@ -3,9 +3,9 @@
3
3
  module Subroutine
4
4
 
5
5
  MAJOR = 2
6
- MINOR = 0
7
- PATCH = 0
8
- PRE = "beta2"
6
+ MINOR = 1
7
+ PATCH = 1
8
+ PRE = nil
9
9
 
10
10
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
11
11
 
@@ -57,6 +57,16 @@ module Subroutine
57
57
  end
58
58
  end
59
59
 
60
+ def test_authorization_checks_are_registered_on_the_class
61
+ assert_equal false, MissingAuthOp.authorization_declared?
62
+
63
+ assert_equal true, CustomAuthorizeOp.authorization_declared?
64
+ assert_equal [:authorize_user_required, :authorize_user_is_correct], CustomAuthorizeOp.authorization_checks
65
+
66
+ assert_equal true, NoUserRequirementsOp.authorization_declared?
67
+ assert_equal [:authorize_user_not_required], NoUserRequirementsOp.authorization_checks
68
+ end
69
+
60
70
  def test_the_current_user_can_be_defined_by_an_id
61
71
  user = CustomAuthorizeOp.new(1).current_user
62
72
  assert_equal 1, user.id
@@ -92,6 +102,10 @@ module Subroutine
92
102
  op.submit!
93
103
  end
94
104
 
105
+ def policy_invocations_are_registered_as_authorization_methods
106
+ assert PolicyOp.authorization_checks.include?(:authorize_policy_user_can_access)
107
+ end
108
+
95
109
  def test_it_runs_policies_with_conditionals
96
110
  # if: false
97
111
  op = IfConditionalPolicyOp.new(user, check_policy: false)
@@ -136,5 +136,12 @@ module Subroutine
136
136
  assert_equal({}.with_indifferent_access, op.without_inherited_params)
137
137
  end
138
138
 
139
+ def test_fields_are_inherited_to_subclasses
140
+ assert_equal(%i[amount_cents], ParentInheritanceOp.field_configurations.keys.sort)
141
+ assert_equal(%i[debit_cents], ParentInheritanceOp::EarlyInheritanceOp.field_configurations.keys.sort)
142
+ assert_equal(%i[amount_cents debit_cents], ParentInheritanceOp::LateInheritanceOp.field_configurations.keys.sort)
143
+ assert_equal(%i[amount_cents credit_cents], OuterInheritanceOp.field_configurations.keys.sort)
144
+ end
145
+
139
146
  end
140
147
  end
data/test/support/ops.rb CHANGED
@@ -284,10 +284,33 @@ class UnlessConditionalPolicyOp < OpWithAuth
284
284
 
285
285
  end
286
286
 
287
+ class ParentInheritanceOp < ::Subroutine::Op
288
+ class EarlyInheritanceOp < ParentInheritanceOp
289
+ integer :debit_cents
290
+ end
291
+
292
+ integer :amount_cents
293
+
294
+ class LateInheritanceOp < ParentInheritanceOp
295
+ integer :debit_cents
296
+ end
297
+
298
+ end
299
+
300
+ class OuterInheritanceOp < ParentInheritanceOp
301
+
302
+ integer :credit_cents
303
+
304
+ end
305
+
287
306
  class OpWithAssociation < ::Subroutine::Op
288
307
 
289
308
  include ::Subroutine::AssociationFields
290
309
 
310
+ def perform
311
+ false
312
+ end
313
+
291
314
  end
292
315
 
293
316
  class SimpleAssociationOp < ::OpWithAssociation
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.0.0.beta2
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-17 00:00:00.000000000 Z
11
+ date: 2022-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -214,11 +214,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
214
214
  version: '0'
215
215
  required_rubygems_version: !ruby/object:Gem::Requirement
216
216
  requirements:
217
- - - ">"
217
+ - - ">="
218
218
  - !ruby/object:Gem::Version
219
- version: 1.3.1
219
+ version: '0'
220
220
  requirements: []
221
- rubygems_version: 3.3.7
221
+ rubygems_version: 3.1.6
222
222
  signing_key:
223
223
  specification_version: 4
224
224
  summary: Feature-driven operation objects.