subroutine 4.4.0 → 4.5.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 +4 -4
- data/lib/subroutine/op.rb +1 -1
- data/lib/subroutine/version.rb +1 -1
- data/subroutine.gemspec +5 -2
- metadata +6 -53
- data/.bundler-version +0 -1
- data/.github/CODEOWNERS +0 -1
- data/.github/dependabot.yml +0 -24
- data/.github/workflows/build.yml +0 -27
- data/.gitignore +0 -16
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/Appraisals +0 -26
- data/CHANGELOG.MD +0 -189
- data/Gemfile +0 -8
- data/LICENSE.txt +0 -22
- data/README.md +0 -88
- data/Rakefile +0 -10
- data/gemfiles/rails_6.1.gemfile +0 -10
- data/gemfiles/rails_6.1.gemfile.lock +0 -177
- data/gemfiles/rails_7.0.gemfile +0 -10
- data/gemfiles/rails_7.0.gemfile.lock +0 -174
- data/gemfiles/rails_7.1.gemfile +0 -9
- data/gemfiles/rails_7.1.gemfile.lock +0 -189
- data/gemfiles/rails_7.2.gemfile +0 -9
- data/gemfiles/rails_7.2.gemfile.lock +0 -191
- data/gemfiles/rails_8.0.gemfile +0 -9
- data/gemfiles/rails_8.0.gemfile.lock +0 -204
- data/test/subroutine/association_test.rb +0 -364
- data/test/subroutine/auth_test.rb +0 -148
- data/test/subroutine/base_test.rb +0 -328
- data/test/subroutine/fields_test.rb +0 -218
- data/test/subroutine/outputs_test.rb +0 -162
- data/test/subroutine/type_caster_test.rb +0 -510
- data/test/support/ops.rb +0 -516
- data/test/test_helper.rb +0 -17
data/test/support/ops.rb
DELETED
@@ -1,516 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "subroutine/auth"
|
4
|
-
require "subroutine/association_fields"
|
5
|
-
|
6
|
-
## Models ##
|
7
|
-
|
8
|
-
class User
|
9
|
-
|
10
|
-
include ::ActiveModel::Model
|
11
|
-
|
12
|
-
attr_accessor :id
|
13
|
-
attr_accessor :email_address
|
14
|
-
attr_accessor :password
|
15
|
-
|
16
|
-
validates :email_address, presence: true
|
17
|
-
|
18
|
-
def self.all
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.find(id)
|
23
|
-
new(id: id)
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.find_by(params)
|
27
|
-
new(params)
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.type_for_attribute(attribute)
|
31
|
-
case attribute
|
32
|
-
when :id
|
33
|
-
Struct.new(:type).new(:integer)
|
34
|
-
else
|
35
|
-
Struct.new(:type).new(:string)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
class StringIdUser < ::User
|
42
|
-
|
43
|
-
def self.type_for_attribute(attribute)
|
44
|
-
Struct.new(:type).new(:string)
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
class AdminUser < ::User
|
50
|
-
|
51
|
-
validates :email_address, format: { with: /@admin\.com/, message: "has gotta be @admin.com" }
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
class Account
|
56
|
-
|
57
|
-
include ::ActiveModel::Model
|
58
|
-
|
59
|
-
attr_accessor :id
|
60
|
-
|
61
|
-
def self.all
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.find(id)
|
66
|
-
new(id: id)
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
## Ops ##
|
72
|
-
|
73
|
-
class SignupOp < ::Subroutine::Op
|
74
|
-
|
75
|
-
string :email, aka: :email_address
|
76
|
-
string :password
|
77
|
-
|
78
|
-
validates :email, presence: true
|
79
|
-
validates :password, presence: true
|
80
|
-
|
81
|
-
outputs :perform_called
|
82
|
-
outputs :perform_finished
|
83
|
-
|
84
|
-
outputs :created_user
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def perform
|
89
|
-
output :perform_called, true
|
90
|
-
u = build_user
|
91
|
-
|
92
|
-
unless u.valid?
|
93
|
-
inherit_errors(u)
|
94
|
-
return false
|
95
|
-
end
|
96
|
-
|
97
|
-
output :perform_finished, true
|
98
|
-
output :created_user, u
|
99
|
-
true
|
100
|
-
end
|
101
|
-
|
102
|
-
def build_user
|
103
|
-
u = user_class.new
|
104
|
-
u.email_address = email
|
105
|
-
u.password = password
|
106
|
-
u
|
107
|
-
end
|
108
|
-
|
109
|
-
def user_class
|
110
|
-
::User
|
111
|
-
end
|
112
|
-
|
113
|
-
end
|
114
|
-
|
115
|
-
class AdminSignupOp < ::SignupOp
|
116
|
-
|
117
|
-
field :privileges, default: "min"
|
118
|
-
|
119
|
-
protected
|
120
|
-
|
121
|
-
def user_class
|
122
|
-
::AdminUser
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
class BusinessSignupOp < ::Subroutine::Op
|
128
|
-
|
129
|
-
string :business_name
|
130
|
-
|
131
|
-
fields_from ::SignupOp
|
132
|
-
|
133
|
-
end
|
134
|
-
|
135
|
-
class DefaultsOp < ::Subroutine::Op
|
136
|
-
|
137
|
-
field :foo, default: "foo"
|
138
|
-
field :bar, default: "bar"
|
139
|
-
field :baz, default: false
|
140
|
-
|
141
|
-
end
|
142
|
-
|
143
|
-
class ExceptFooBarOp < ::Subroutine::Op
|
144
|
-
|
145
|
-
fields_from ::DefaultsOp, except: %i[foo bar]
|
146
|
-
|
147
|
-
end
|
148
|
-
|
149
|
-
class OnlyFooBarOp < ::Subroutine::Op
|
150
|
-
|
151
|
-
fields_from ::DefaultsOp, only: %i[foo bar]
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
class InheritedDefaultsOp < ::DefaultsOp
|
156
|
-
|
157
|
-
field :bar, default: "barstool", allow_overwrite: true
|
158
|
-
|
159
|
-
end
|
160
|
-
|
161
|
-
class GroupedDefaultsOp < ::Subroutine::Op
|
162
|
-
|
163
|
-
fields_from ::DefaultsOp, group: "inherited"
|
164
|
-
|
165
|
-
end
|
166
|
-
|
167
|
-
class TypeCastOp < ::Subroutine::Op
|
168
|
-
|
169
|
-
integer :integer_input
|
170
|
-
number :number_input
|
171
|
-
decimal :decimal_input
|
172
|
-
string :string_input
|
173
|
-
boolean :boolean_input
|
174
|
-
date :date_input
|
175
|
-
time :time_input, default: -> { Time.now }
|
176
|
-
time :precise_time_input, precision: :high
|
177
|
-
iso_date :iso_date_input
|
178
|
-
iso_time :iso_time_input
|
179
|
-
object :object_input
|
180
|
-
object :no_indifferent_object_input, bypass_indifferent_assignment: true
|
181
|
-
array :array_input, default: "foo"
|
182
|
-
array :type_array_input, of: :integer
|
183
|
-
file :file_input
|
184
|
-
foreign_key :fk_input_owner_id
|
185
|
-
foreign_key :fk_input_email_address, foreign_key_type: :string
|
186
|
-
|
187
|
-
end
|
188
|
-
|
189
|
-
class OpWithAuth < ::Subroutine::Op
|
190
|
-
|
191
|
-
include ::Subroutine::Auth
|
192
|
-
def perform
|
193
|
-
true
|
194
|
-
end
|
195
|
-
|
196
|
-
end
|
197
|
-
|
198
|
-
class MissingAuthOp < OpWithAuth
|
199
|
-
end
|
200
|
-
|
201
|
-
class RequireUserOp < OpWithAuth
|
202
|
-
|
203
|
-
require_user!
|
204
|
-
|
205
|
-
string :some_input
|
206
|
-
|
207
|
-
end
|
208
|
-
|
209
|
-
class RequireNoUserOp < OpWithAuth
|
210
|
-
|
211
|
-
require_no_user!
|
212
|
-
|
213
|
-
end
|
214
|
-
|
215
|
-
class NoUserRequirementsOp < OpWithAuth
|
216
|
-
|
217
|
-
no_user_requirements!
|
218
|
-
|
219
|
-
end
|
220
|
-
|
221
|
-
class DifferentUserClassOp < OpWithAuth
|
222
|
-
|
223
|
-
self.user_class_name = "AdminUser"
|
224
|
-
require_user!
|
225
|
-
|
226
|
-
end
|
227
|
-
|
228
|
-
class CustomAuthorizeOp < OpWithAuth
|
229
|
-
|
230
|
-
require_user!
|
231
|
-
authorize :authorize_user_is_correct
|
232
|
-
|
233
|
-
protected
|
234
|
-
|
235
|
-
def authorize_user_is_correct
|
236
|
-
unauthorized! unless current_user.email_address.to_s =~ /example\.com$/ # rubocop:disable Performance/RegexpMatch
|
237
|
-
end
|
238
|
-
|
239
|
-
end
|
240
|
-
|
241
|
-
class PolicyOp < OpWithAuth
|
242
|
-
|
243
|
-
class FakePolicy
|
244
|
-
|
245
|
-
def user_can_access?
|
246
|
-
true
|
247
|
-
end
|
248
|
-
|
249
|
-
def user_can_do_it
|
250
|
-
false
|
251
|
-
end
|
252
|
-
|
253
|
-
end
|
254
|
-
|
255
|
-
require_user!
|
256
|
-
|
257
|
-
policy :user_can_access?
|
258
|
-
policy :user_can_do_it
|
259
|
-
|
260
|
-
def policy
|
261
|
-
@policy ||= FakePolicy.new
|
262
|
-
end
|
263
|
-
|
264
|
-
end
|
265
|
-
|
266
|
-
class IfConditionalPolicyOp < OpWithAuth
|
267
|
-
|
268
|
-
class FakePolicy
|
269
|
-
|
270
|
-
def user_can_access?
|
271
|
-
false
|
272
|
-
end
|
273
|
-
|
274
|
-
end
|
275
|
-
|
276
|
-
require_user!
|
277
|
-
boolean :check_policy
|
278
|
-
validates :check_policy, inclusion: { in: [true, false] }
|
279
|
-
policy :user_can_access?, if: :check_policy
|
280
|
-
|
281
|
-
def policy
|
282
|
-
@policy ||= FakePolicy.new
|
283
|
-
end
|
284
|
-
|
285
|
-
end
|
286
|
-
|
287
|
-
class UnlessConditionalPolicyOp < OpWithAuth
|
288
|
-
|
289
|
-
class FakePolicy
|
290
|
-
|
291
|
-
def user_can_access?
|
292
|
-
false
|
293
|
-
end
|
294
|
-
|
295
|
-
end
|
296
|
-
|
297
|
-
require_user!
|
298
|
-
boolean :unless_check_policy
|
299
|
-
validates :unless_check_policy, inclusion: { in: [true, false] }
|
300
|
-
policy :user_can_access?, unless: :unless_check_policy
|
301
|
-
|
302
|
-
def policy
|
303
|
-
@policy ||= FakePolicy.new
|
304
|
-
end
|
305
|
-
|
306
|
-
end
|
307
|
-
|
308
|
-
class ParentInheritanceOp < ::Subroutine::Op
|
309
|
-
class EarlyInheritanceOp < ParentInheritanceOp
|
310
|
-
integer :debit_cents
|
311
|
-
end
|
312
|
-
|
313
|
-
integer :amount_cents
|
314
|
-
|
315
|
-
class LateInheritanceOp < ParentInheritanceOp
|
316
|
-
integer :debit_cents
|
317
|
-
end
|
318
|
-
|
319
|
-
end
|
320
|
-
|
321
|
-
class OuterInheritanceOp < ParentInheritanceOp
|
322
|
-
|
323
|
-
integer :credit_cents
|
324
|
-
|
325
|
-
end
|
326
|
-
|
327
|
-
class OpWithAssociation < ::Subroutine::Op
|
328
|
-
|
329
|
-
include ::Subroutine::AssociationFields
|
330
|
-
|
331
|
-
def perform
|
332
|
-
false
|
333
|
-
end
|
334
|
-
|
335
|
-
end
|
336
|
-
|
337
|
-
class SimpleAssociationOp < ::OpWithAssociation
|
338
|
-
|
339
|
-
association :user
|
340
|
-
|
341
|
-
end
|
342
|
-
|
343
|
-
class SafeAssociationOp < ::OpWithAssociation
|
344
|
-
|
345
|
-
association :user, raise_on_miss: false
|
346
|
-
|
347
|
-
end
|
348
|
-
|
349
|
-
class SimpleAssociationWithStringIdOp < ::OpWithAssociation
|
350
|
-
|
351
|
-
association :string_id_user
|
352
|
-
|
353
|
-
end
|
354
|
-
|
355
|
-
class UnscopedSimpleAssociationOp < ::OpWithAssociation
|
356
|
-
|
357
|
-
association :user, unscoped: true, allow_overwrite: true
|
358
|
-
|
359
|
-
end
|
360
|
-
|
361
|
-
class PolymorphicAssociationOp < ::OpWithAssociation
|
362
|
-
|
363
|
-
association :admin, polymorphic: true
|
364
|
-
|
365
|
-
end
|
366
|
-
|
367
|
-
class AssociationWithClassOp < ::OpWithAssociation
|
368
|
-
|
369
|
-
association :admin, class_name: "AdminUser"
|
370
|
-
|
371
|
-
end
|
372
|
-
|
373
|
-
class AssociationWithForeignKeyOp < ::OpWithAssociation
|
374
|
-
|
375
|
-
association :user, foreign_key: "owner_id"
|
376
|
-
|
377
|
-
end
|
378
|
-
|
379
|
-
class AssociationWithFindByKeyOp < ::OpWithAssociation
|
380
|
-
|
381
|
-
association :user, find_by: "email_address", foreign_key_type: :string
|
382
|
-
|
383
|
-
end
|
384
|
-
|
385
|
-
class AssociationWithImplicitStringFindByOp < ::OpWithAssociation
|
386
|
-
|
387
|
-
association :user, find_by: "email_address"
|
388
|
-
|
389
|
-
end
|
390
|
-
|
391
|
-
class AssociationWithFindByAndForeignKeyOp < ::OpWithAssociation
|
392
|
-
|
393
|
-
association :user, foreign_key: "email_address", find_by: "email_address"
|
394
|
-
|
395
|
-
end
|
396
|
-
|
397
|
-
class ExceptAssociationOp < ::Subroutine::Op
|
398
|
-
|
399
|
-
fields_from ::PolymorphicAssociationOp, except: %i[admin]
|
400
|
-
|
401
|
-
end
|
402
|
-
|
403
|
-
class OnlyAssociationOp < ::Subroutine::Op
|
404
|
-
|
405
|
-
fields_from ::PolymorphicAssociationOp, only: %i[admin]
|
406
|
-
|
407
|
-
end
|
408
|
-
|
409
|
-
class InheritedSimpleAssociation < ::Subroutine::Op
|
410
|
-
|
411
|
-
fields_from SimpleAssociationOp
|
412
|
-
|
413
|
-
end
|
414
|
-
|
415
|
-
class InheritedUnscopedAssociation < ::Subroutine::Op
|
416
|
-
|
417
|
-
fields_from UnscopedSimpleAssociationOp
|
418
|
-
|
419
|
-
end
|
420
|
-
|
421
|
-
class InheritedPolymorphicAssociationOp < ::Subroutine::Op
|
422
|
-
|
423
|
-
fields_from PolymorphicAssociationOp
|
424
|
-
|
425
|
-
end
|
426
|
-
|
427
|
-
class GroupedParamAssociationOp < ::OpWithAssociation
|
428
|
-
|
429
|
-
association :user, group: :info
|
430
|
-
|
431
|
-
end
|
432
|
-
|
433
|
-
class GroupedPolymorphicParamAssociationOp < ::OpWithAssociation
|
434
|
-
|
435
|
-
association :user, polymorphic: true, group: :info
|
436
|
-
|
437
|
-
end
|
438
|
-
|
439
|
-
class GroupedInputsFromOp < ::Subroutine::Op
|
440
|
-
|
441
|
-
fields_from GroupedParamAssociationOp, group: :inherited
|
442
|
-
|
443
|
-
end
|
444
|
-
|
445
|
-
class FalsePerformOp < ::Subroutine::Op
|
446
|
-
|
447
|
-
def perform
|
448
|
-
false
|
449
|
-
end
|
450
|
-
|
451
|
-
end
|
452
|
-
|
453
|
-
class ErrorTraceOp < ::Subroutine::Op
|
454
|
-
|
455
|
-
class SomeObject
|
456
|
-
|
457
|
-
include ::ActiveModel::Model
|
458
|
-
include ::ActiveModel::Validations::Callbacks
|
459
|
-
|
460
|
-
def foo
|
461
|
-
errors.add(:base, "Failure of things")
|
462
|
-
raise Subroutine::Failure, self
|
463
|
-
end
|
464
|
-
|
465
|
-
def bar
|
466
|
-
foo
|
467
|
-
end
|
468
|
-
|
469
|
-
end
|
470
|
-
|
471
|
-
class SubOp < ::Subroutine::Op
|
472
|
-
|
473
|
-
def perform
|
474
|
-
SomeObject.new.bar
|
475
|
-
end
|
476
|
-
|
477
|
-
end
|
478
|
-
|
479
|
-
def perform
|
480
|
-
SubOp.submit!
|
481
|
-
end
|
482
|
-
|
483
|
-
end
|
484
|
-
|
485
|
-
class CustomFailureClassOp < ::Subroutine::Op
|
486
|
-
|
487
|
-
class Failure < StandardError
|
488
|
-
|
489
|
-
attr_reader :record
|
490
|
-
def initialize(record)
|
491
|
-
@record = record
|
492
|
-
errors = @record.errors.full_messages.join(", ")
|
493
|
-
super(errors)
|
494
|
-
end
|
495
|
-
|
496
|
-
end
|
497
|
-
|
498
|
-
failure_class Failure
|
499
|
-
|
500
|
-
def perform
|
501
|
-
errors.add(:base, "Will never work")
|
502
|
-
end
|
503
|
-
|
504
|
-
end
|
505
|
-
|
506
|
-
class PrefixedInputsOp < ::Subroutine::Op
|
507
|
-
|
508
|
-
string :user_email_address
|
509
|
-
|
510
|
-
def perform
|
511
|
-
u = AdminUser.new(email_address: user_email_address)
|
512
|
-
u.valid?
|
513
|
-
inherit_errors(u, prefix: :user_)
|
514
|
-
end
|
515
|
-
|
516
|
-
end
|
data/test/test_helper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "subroutine"
|
4
|
-
require "minitest/autorun"
|
5
|
-
require "minitest/unit"
|
6
|
-
|
7
|
-
require "minitest/reporters"
|
8
|
-
require "mocha/minitest"
|
9
|
-
|
10
|
-
require "byebug"
|
11
|
-
require "action_controller"
|
12
|
-
|
13
|
-
Minitest::Reporters.use!([Minitest::Reporters::DefaultReporter.new])
|
14
|
-
|
15
|
-
class TestCase < ::Minitest::Test; end
|
16
|
-
|
17
|
-
require_relative "support/ops"
|