subroutine 0.10.0.beta → 0.10.0.beta2
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 +5 -5
- data/.ruby-version +1 -1
- data/Gemfile +4 -2
- data/lib/subroutine/association_fields/component_configuration.rb +19 -0
- data/lib/subroutine/association_fields/configuration.rb +74 -0
- data/lib/subroutine/association_fields.rb +158 -0
- data/lib/subroutine/auth.rb +21 -16
- data/lib/subroutine/fields/configuration.rb +90 -0
- data/lib/subroutine/fields/mass_assignment_error.rb +13 -0
- data/lib/subroutine/fields.rb +146 -82
- data/lib/subroutine/op.rb +14 -38
- data/lib/subroutine/outputs/configuration.rb +39 -0
- data/lib/subroutine/outputs/output_not_set_error.rb +13 -0
- data/lib/subroutine/outputs/unknown_output_error.rb +13 -0
- data/lib/subroutine/outputs.rb +66 -0
- data/lib/subroutine/version.rb +4 -2
- data/test/subroutine/association_test.rb +18 -17
- data/test/subroutine/auth_test.rb +11 -4
- data/test/subroutine/base_test.rb +70 -58
- data/test/subroutine/fields_test.rb +49 -12
- data/test/support/ops.rb +113 -16
- metadata +12 -7
- data/lib/subroutine/association.rb +0 -131
- data/lib/subroutine/output_not_set_error.rb +0 -9
- data/lib/subroutine/unknown_output_error.rb +0 -9
data/test/support/ops.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "subroutine/auth"
|
4
|
+
require "subroutine/association_fields"
|
5
5
|
|
6
6
|
## Models ##
|
7
7
|
|
8
8
|
class User
|
9
|
+
|
9
10
|
include ::ActiveModel::Model
|
10
11
|
|
11
12
|
attr_accessor :id
|
@@ -17,15 +18,19 @@ class User
|
|
17
18
|
def self.find(id)
|
18
19
|
new(id: id)
|
19
20
|
end
|
21
|
+
|
20
22
|
end
|
21
23
|
|
22
24
|
class AdminUser < ::User
|
23
|
-
|
25
|
+
|
26
|
+
validates :email_address, format: { with: /@admin\.com/, message: "has gotta be @admin.com" }
|
27
|
+
|
24
28
|
end
|
25
29
|
|
26
30
|
## Ops ##
|
27
31
|
|
28
32
|
class SignupOp < ::Subroutine::Op
|
33
|
+
|
29
34
|
string :email, aka: :email_address
|
30
35
|
string :password
|
31
36
|
|
@@ -63,43 +68,57 @@ class SignupOp < ::Subroutine::Op
|
|
63
68
|
def user_class
|
64
69
|
::User
|
65
70
|
end
|
71
|
+
|
66
72
|
end
|
67
73
|
|
68
74
|
class AdminSignupOp < ::SignupOp
|
69
|
-
|
75
|
+
|
76
|
+
field :privileges, default: "min"
|
70
77
|
|
71
78
|
protected
|
72
79
|
|
73
80
|
def user_class
|
74
81
|
::AdminUser
|
75
82
|
end
|
83
|
+
|
76
84
|
end
|
77
85
|
|
78
86
|
class BusinessSignupOp < ::Subroutine::Op
|
87
|
+
|
79
88
|
string :business_name
|
80
89
|
|
81
90
|
inputs_from ::SignupOp
|
91
|
+
|
82
92
|
end
|
83
93
|
|
84
94
|
class DefaultsOp < ::Subroutine::Op
|
85
|
-
|
86
|
-
field :
|
95
|
+
|
96
|
+
field :foo, default: "foo"
|
97
|
+
field :bar, default: "bar"
|
87
98
|
field :baz, default: false
|
99
|
+
|
88
100
|
end
|
89
101
|
|
90
102
|
class ExceptFooBarOp < ::Subroutine::Op
|
91
|
-
|
103
|
+
|
104
|
+
inputs_from ::DefaultsOp, except: %i[foo bar]
|
105
|
+
|
92
106
|
end
|
93
107
|
|
94
108
|
class OnlyFooBarOp < ::Subroutine::Op
|
95
|
-
|
109
|
+
|
110
|
+
inputs_from ::DefaultsOp, only: %i[foo bar]
|
111
|
+
|
96
112
|
end
|
97
113
|
|
98
114
|
class InheritedDefaultsOp < ::DefaultsOp
|
99
|
-
|
115
|
+
|
116
|
+
field :bar, default: "barstool", allow_overwrite: true
|
117
|
+
|
100
118
|
end
|
101
119
|
|
102
120
|
class TypeCastOp < ::Subroutine::Op
|
121
|
+
|
103
122
|
integer :integer_input
|
104
123
|
number :number_input
|
105
124
|
decimal :decimal_input
|
@@ -110,39 +129,51 @@ class TypeCastOp < ::Subroutine::Op
|
|
110
129
|
iso_date :iso_date_input
|
111
130
|
iso_time :iso_time_input
|
112
131
|
object :object_input
|
113
|
-
array :array_input, default:
|
132
|
+
array :array_input, default: "foo"
|
114
133
|
array :type_array_input, of: :integer
|
115
134
|
file :file_input
|
135
|
+
|
116
136
|
end
|
117
137
|
|
118
138
|
class OpWithAuth < ::Subroutine::Op
|
139
|
+
|
119
140
|
include ::Subroutine::Auth
|
120
141
|
def perform
|
121
142
|
true
|
122
143
|
end
|
144
|
+
|
123
145
|
end
|
124
146
|
|
125
147
|
class MissingAuthOp < OpWithAuth
|
126
148
|
end
|
127
149
|
|
128
150
|
class RequireUserOp < OpWithAuth
|
151
|
+
|
129
152
|
require_user!
|
153
|
+
|
130
154
|
end
|
131
155
|
|
132
156
|
class RequireNoUserOp < OpWithAuth
|
157
|
+
|
133
158
|
require_no_user!
|
159
|
+
|
134
160
|
end
|
135
161
|
|
136
162
|
class NoUserRequirementsOp < OpWithAuth
|
163
|
+
|
137
164
|
no_user_requirements!
|
165
|
+
|
138
166
|
end
|
139
167
|
|
140
168
|
class DifferentUserClassOp < OpWithAuth
|
169
|
+
|
141
170
|
self.user_class_name = "AdminUser"
|
142
171
|
require_user!
|
172
|
+
|
143
173
|
end
|
144
174
|
|
145
175
|
class CustomAuthorizeOp < OpWithAuth
|
176
|
+
|
146
177
|
require_user!
|
147
178
|
authorize :authorize_user_is_correct
|
148
179
|
|
@@ -151,13 +182,17 @@ class CustomAuthorizeOp < OpWithAuth
|
|
151
182
|
def authorize_user_is_correct
|
152
183
|
unauthorized! unless current_user.email_address.to_s =~ /example\.com$/
|
153
184
|
end
|
185
|
+
|
154
186
|
end
|
155
187
|
|
156
188
|
class PolicyOp < OpWithAuth
|
189
|
+
|
157
190
|
class FakePolicy
|
191
|
+
|
158
192
|
def user_can_access?
|
159
193
|
false
|
160
194
|
end
|
195
|
+
|
161
196
|
end
|
162
197
|
|
163
198
|
require_user!
|
@@ -166,13 +201,17 @@ class PolicyOp < OpWithAuth
|
|
166
201
|
def policy
|
167
202
|
@policy ||= FakePolicy.new
|
168
203
|
end
|
204
|
+
|
169
205
|
end
|
170
206
|
|
171
207
|
class IfConditionalPolicyOp < OpWithAuth
|
208
|
+
|
172
209
|
class FakePolicy
|
210
|
+
|
173
211
|
def user_can_access?
|
174
212
|
false
|
175
213
|
end
|
214
|
+
|
176
215
|
end
|
177
216
|
|
178
217
|
require_user!
|
@@ -183,13 +222,17 @@ class IfConditionalPolicyOp < OpWithAuth
|
|
183
222
|
def policy
|
184
223
|
@policy ||= FakePolicy.new
|
185
224
|
end
|
225
|
+
|
186
226
|
end
|
187
227
|
|
188
228
|
class UnlessConditionalPolicyOp < OpWithAuth
|
229
|
+
|
189
230
|
class FakePolicy
|
231
|
+
|
190
232
|
def user_can_access?
|
191
233
|
false
|
192
234
|
end
|
235
|
+
|
193
236
|
end
|
194
237
|
|
195
238
|
require_user!
|
@@ -200,95 +243,149 @@ class UnlessConditionalPolicyOp < OpWithAuth
|
|
200
243
|
def policy
|
201
244
|
@policy ||= FakePolicy.new
|
202
245
|
end
|
246
|
+
|
203
247
|
end
|
204
248
|
|
205
249
|
class OpWithAssociation < ::Subroutine::Op
|
206
|
-
|
250
|
+
|
251
|
+
include ::Subroutine::AssociationFields
|
252
|
+
|
207
253
|
end
|
208
254
|
|
209
255
|
class SimpleAssociationOp < ::OpWithAssociation
|
256
|
+
|
210
257
|
association :user
|
258
|
+
|
211
259
|
end
|
212
260
|
|
213
261
|
class UnscopedSimpleAssociationOp < ::OpWithAssociation
|
214
|
-
|
262
|
+
|
263
|
+
association :user, unscoped: true, allow_overwrite: true
|
264
|
+
|
215
265
|
end
|
216
266
|
|
217
267
|
class PolymorphicAssociationOp < ::OpWithAssociation
|
268
|
+
|
218
269
|
association :admin, polymorphic: true
|
270
|
+
|
219
271
|
end
|
220
272
|
|
221
273
|
class AssociationWithClassOp < ::OpWithAssociation
|
222
|
-
|
274
|
+
|
275
|
+
association :admin, class_name: "AdminUser"
|
276
|
+
|
223
277
|
end
|
224
278
|
|
225
279
|
class InheritedSimpleAssociation < ::Subroutine::Op
|
280
|
+
|
226
281
|
inputs_from SimpleAssociationOp
|
282
|
+
|
227
283
|
end
|
228
284
|
|
229
285
|
class InheritedUnscopedAssociation < ::Subroutine::Op
|
286
|
+
|
230
287
|
inputs_from UnscopedSimpleAssociationOp
|
288
|
+
|
231
289
|
end
|
232
290
|
|
233
291
|
class InheritedPolymorphicAssociationOp < ::Subroutine::Op
|
292
|
+
|
234
293
|
inputs_from PolymorphicAssociationOp
|
294
|
+
|
235
295
|
end
|
236
296
|
|
237
297
|
class FalsePerformOp < ::Subroutine::Op
|
298
|
+
|
238
299
|
def perform
|
239
300
|
false
|
240
301
|
end
|
302
|
+
|
241
303
|
end
|
242
304
|
|
243
305
|
class MissingOutputOp < ::Subroutine::Op
|
306
|
+
|
244
307
|
def perform
|
245
|
-
output :foo,
|
308
|
+
output :foo, "bar"
|
246
309
|
end
|
310
|
+
|
247
311
|
end
|
248
312
|
|
249
313
|
class MissingOutputSetOp < ::Subroutine::Op
|
314
|
+
|
250
315
|
outputs :foo
|
251
316
|
def perform
|
252
317
|
true
|
253
318
|
end
|
319
|
+
|
254
320
|
end
|
255
321
|
|
256
322
|
class OutputNotRequiredOp < ::Subroutine::Op
|
323
|
+
|
257
324
|
outputs :foo, required: false
|
258
325
|
def perform
|
259
326
|
true
|
260
327
|
end
|
328
|
+
|
261
329
|
end
|
262
330
|
|
263
331
|
class NoOutputNoSuccessOp < ::Subroutine::Op
|
332
|
+
|
264
333
|
outputs :foo
|
265
334
|
def perform
|
266
|
-
errors.add(:foo,
|
335
|
+
errors.add(:foo, "bar")
|
267
336
|
end
|
337
|
+
|
268
338
|
end
|
269
339
|
|
270
340
|
class ErrorTraceOp < ::Subroutine::Op
|
341
|
+
|
271
342
|
class SomeObject
|
343
|
+
|
272
344
|
include ::ActiveModel::Model
|
273
345
|
include ::ActiveModel::Validations::Callbacks
|
274
346
|
|
275
347
|
def foo
|
276
|
-
errors.add(:base,
|
348
|
+
errors.add(:base, "Failure of things")
|
277
349
|
raise Subroutine::Failure, self
|
278
350
|
end
|
279
351
|
|
280
352
|
def bar
|
281
353
|
foo
|
282
354
|
end
|
355
|
+
|
283
356
|
end
|
284
357
|
|
285
358
|
class SubOp < ::Subroutine::Op
|
359
|
+
|
286
360
|
def perform
|
287
361
|
SomeObject.new.bar
|
288
362
|
end
|
363
|
+
|
289
364
|
end
|
290
365
|
|
291
366
|
def perform
|
292
367
|
SubOp.submit!
|
293
368
|
end
|
369
|
+
|
370
|
+
end
|
371
|
+
|
372
|
+
class CustomFailureClassOp < ::Subroutine::Op
|
373
|
+
|
374
|
+
class Failure < StandardError
|
375
|
+
|
376
|
+
attr_reader :record
|
377
|
+
def initialize(record)
|
378
|
+
@record = record
|
379
|
+
errors = @record.errors.full_messages.join(", ")
|
380
|
+
super(errors)
|
381
|
+
end
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
failure_class Failure
|
386
|
+
|
387
|
+
def perform
|
388
|
+
errors.add(:base, "Will never work")
|
389
|
+
end
|
390
|
+
|
294
391
|
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.10.0.
|
4
|
+
version: 0.10.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Nelson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-11-
|
11
|
+
date: 2019-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -144,14 +144,20 @@ files:
|
|
144
144
|
- gemfiles/am52.gemfile
|
145
145
|
- gemfiles/am60.gemfile
|
146
146
|
- lib/subroutine.rb
|
147
|
-
- lib/subroutine/
|
147
|
+
- lib/subroutine/association_fields.rb
|
148
|
+
- lib/subroutine/association_fields/component_configuration.rb
|
149
|
+
- lib/subroutine/association_fields/configuration.rb
|
148
150
|
- lib/subroutine/auth.rb
|
149
151
|
- lib/subroutine/failure.rb
|
150
152
|
- lib/subroutine/fields.rb
|
153
|
+
- lib/subroutine/fields/configuration.rb
|
154
|
+
- lib/subroutine/fields/mass_assignment_error.rb
|
151
155
|
- lib/subroutine/op.rb
|
152
|
-
- lib/subroutine/
|
156
|
+
- lib/subroutine/outputs.rb
|
157
|
+
- lib/subroutine/outputs/configuration.rb
|
158
|
+
- lib/subroutine/outputs/output_not_set_error.rb
|
159
|
+
- lib/subroutine/outputs/unknown_output_error.rb
|
153
160
|
- lib/subroutine/type_caster.rb
|
154
|
-
- lib/subroutine/unknown_output_error.rb
|
155
161
|
- lib/subroutine/version.rb
|
156
162
|
- subroutine.gemspec
|
157
163
|
- test/subroutine/association_test.rb
|
@@ -180,8 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
186
|
- !ruby/object:Gem::Version
|
181
187
|
version: 1.3.1
|
182
188
|
requirements: []
|
183
|
-
|
184
|
-
rubygems_version: 2.6.14.4
|
189
|
+
rubygems_version: 3.0.6
|
185
190
|
signing_key:
|
186
191
|
specification_version: 4
|
187
192
|
summary: Feature-driven operation objects.
|
@@ -1,131 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "active_support/concern"
|
3
|
-
|
4
|
-
module Subroutine
|
5
|
-
module Association
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
class << self
|
10
|
-
alias_method :field_without_associations, :field
|
11
|
-
alias_method :field, :field_with_associations
|
12
|
-
end
|
13
|
-
|
14
|
-
alias_method :setup_fields_without_association, :setup_fields
|
15
|
-
alias_method :setup_fields, :setup_fields_with_association
|
16
|
-
end
|
17
|
-
|
18
|
-
module ClassMethods
|
19
|
-
def field_with_associations(*args)
|
20
|
-
opts = args.extract_options!
|
21
|
-
if opts[:association]
|
22
|
-
args.each do |arg|
|
23
|
-
association(arg, opts)
|
24
|
-
end
|
25
|
-
else
|
26
|
-
field_without_associations(*args, opts)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# association :user
|
31
|
-
# - user_id
|
32
|
-
# - user_type => "User"
|
33
|
-
|
34
|
-
# association :user, polymorphic: true
|
35
|
-
# - user_id
|
36
|
-
# - user_type
|
37
|
-
# - user => polymorphic_lookup(user_type, user_id)
|
38
|
-
|
39
|
-
# association :inbound_user_request, as: :request
|
40
|
-
# - inbound_user_request_id
|
41
|
-
# - inbound_user_request_type => "InboundUserRequest"
|
42
|
-
# - request => polymorphic_lookup(inbound_user_request_type, inbound_user_request_id)
|
43
|
-
|
44
|
-
# association :inbound_user_request, foreign_key: :request_id
|
45
|
-
# - request_id
|
46
|
-
# - request_type
|
47
|
-
# - inbound_user_request => polymorphic_lookup(request_type, request_id)
|
48
|
-
|
49
|
-
# Other options:
|
50
|
-
# - unscoped => set true if the record should be looked up via Type.unscoped
|
51
|
-
|
52
|
-
def association(field, options = {})
|
53
|
-
if options[:as] && options[:foreign_key]
|
54
|
-
raise ArgumentError, ':as and :foreign_key options should be provided together to an association invocation'
|
55
|
-
end
|
56
|
-
|
57
|
-
class_name = options[:class_name]
|
58
|
-
|
59
|
-
poly = options[:polymorphic] || !class_name.nil?
|
60
|
-
as = options[:as] || field
|
61
|
-
unscoped = !!options[:unscoped]
|
62
|
-
|
63
|
-
klass = class_name.to_s if class_name
|
64
|
-
|
65
|
-
foreign_key_method = (options[:foreign_key] || "#{field}_id").to_s
|
66
|
-
foreign_type_method = foreign_key_method.gsub(/_id$/, '_type')
|
67
|
-
|
68
|
-
if poly
|
69
|
-
string foreign_type_method
|
70
|
-
else
|
71
|
-
class_eval <<-EV, __FILE__, __LINE__ + 1
|
72
|
-
def #{foreign_type_method}
|
73
|
-
#{as.to_s.camelize.inspect}
|
74
|
-
end
|
75
|
-
EV
|
76
|
-
end
|
77
|
-
|
78
|
-
integer foreign_key_method
|
79
|
-
|
80
|
-
field_without_associations as, options.merge(association: true, field_writer: false, field_reader: false)
|
81
|
-
|
82
|
-
class_eval <<-EV, __FILE__, __LINE__ + 1
|
83
|
-
try(:silence_redefinition_of_method, :#{as})
|
84
|
-
def #{as}
|
85
|
-
return @#{as} if defined?(@#{as})
|
86
|
-
@#{as} = polymorphic_instance(#{klass.nil? ? foreign_type_method : klass.to_s}, #{foreign_key_method}, #{unscoped.inspect})
|
87
|
-
end
|
88
|
-
|
89
|
-
try(:silence_redefinition_of_method, :#{as}=)
|
90
|
-
def #{as}=(r)
|
91
|
-
@#{as} = r
|
92
|
-
#{poly || klass ? "send('#{foreign_type_method}=', r.nil? ? nil : #{klass.nil? ? 'r.class.name' : klass.to_s.inspect})" : ''}
|
93
|
-
send('#{foreign_key_method}=', r.nil? ? nil : r.id)
|
94
|
-
r
|
95
|
-
end
|
96
|
-
|
97
|
-
try(:silence_redefinition_of_method, :#{as}_field_provided?)
|
98
|
-
def #{as}_field_provided?
|
99
|
-
field_provided?('#{foreign_key_method}')#{poly ? "&& field_provided?('#{foreign_type_method}')" : ""}
|
100
|
-
end
|
101
|
-
EV
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def setup_fields_with_association(*args)
|
106
|
-
setup_fields_without_association(*args)
|
107
|
-
|
108
|
-
_fields.each_pair do |field, config|
|
109
|
-
next unless config[:association]
|
110
|
-
next if config[:mass_assignable] == false
|
111
|
-
next unless @original_params.key?(field)
|
112
|
-
|
113
|
-
send("#{field}=", @original_params[field]) # this gets the _id and _type into the params hash
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def polymorphic_instance(_type, _id, _unscoped = false)
|
118
|
-
return nil unless _type && _id
|
119
|
-
|
120
|
-
klass = _type
|
121
|
-
klass = klass.classify.constantize if klass.is_a?(String)
|
122
|
-
|
123
|
-
return nil unless klass
|
124
|
-
|
125
|
-
scope = klass.all
|
126
|
-
scope = scope.unscoped if _unscoped
|
127
|
-
|
128
|
-
scope.find(_id)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|