trailblazer 1.1.2 → 2.0.0.beta1
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/.travis.yml +10 -7
- data/CHANGES.md +108 -0
- data/COMM-LICENSE +91 -0
- data/Gemfile +18 -4
- data/LICENSE.txt +7 -20
- data/README.md +55 -15
- data/Rakefile +21 -2
- data/draft-1.2.rb +7 -0
- data/lib/trailblazer.rb +17 -4
- data/lib/trailblazer/dsl.rb +47 -0
- data/lib/trailblazer/operation/auto_inject.rb +47 -0
- data/lib/trailblazer/operation/builder.rb +18 -18
- data/lib/trailblazer/operation/callback.rb +31 -38
- data/lib/trailblazer/operation/contract.rb +46 -0
- data/lib/trailblazer/operation/controller.rb +45 -27
- data/lib/trailblazer/operation/guard.rb +24 -0
- data/lib/trailblazer/operation/model.rb +41 -33
- data/lib/trailblazer/operation/nested.rb +43 -0
- data/lib/trailblazer/operation/params.rb +13 -0
- data/lib/trailblazer/operation/persist.rb +13 -0
- data/lib/trailblazer/operation/policy.rb +26 -72
- data/lib/trailblazer/operation/present.rb +19 -0
- data/lib/trailblazer/operation/procedural/contract.rb +15 -0
- data/lib/trailblazer/operation/procedural/validate.rb +22 -0
- data/lib/trailblazer/operation/pundit.rb +42 -0
- data/lib/trailblazer/operation/representer.rb +25 -92
- data/lib/trailblazer/operation/rescue.rb +23 -0
- data/lib/trailblazer/operation/resolver.rb +18 -24
- data/lib/trailblazer/operation/validate.rb +50 -0
- data/lib/trailblazer/operation/wrap.rb +37 -0
- data/lib/trailblazer/version.rb +1 -1
- data/test/{operation/controller_test.rb → controller_test.rb} +8 -4
- data/test/docs/auto_inject_test.rb +30 -0
- data/test/docs/contract_test.rb +429 -0
- data/test/docs/dry_test.rb +31 -0
- data/test/docs/guard_test.rb +143 -0
- data/test/docs/nested_test.rb +117 -0
- data/test/docs/policy_test.rb +2 -0
- data/test/docs/pundit_test.rb +109 -0
- data/test/docs/representer_test.rb +268 -0
- data/test/docs/rescue_test.rb +153 -0
- data/test/docs/wrap_test.rb +174 -0
- data/test/gemfiles/Gemfile.ruby-1.9 +3 -0
- data/test/gemfiles/Gemfile.ruby-2.0 +12 -0
- data/test/gemfiles/Gemfile.ruby-2.3 +12 -0
- data/test/module_test.rb +22 -15
- data/test/operation/builder_test.rb +66 -18
- data/test/operation/callback_test.rb +70 -0
- data/test/operation/contract_test.rb +385 -15
- data/test/operation/dsl/callback_test.rb +18 -30
- data/test/operation/dsl/contract_test.rb +209 -19
- data/test/operation/dsl/representer_test.rb +42 -15
- data/test/operation/guard_test.rb +1 -147
- data/test/operation/model_test.rb +105 -0
- data/test/operation/params_test.rb +36 -0
- data/test/operation/persist_test.rb +44 -0
- data/test/operation/pipedream_test.rb +59 -0
- data/test/operation/pipetree_test.rb +104 -0
- data/test/operation/present_test.rb +24 -0
- data/test/operation/pundit_test.rb +104 -0
- data/test/{representer_test.rb → operation/representer_test.rb} +58 -42
- data/test/operation/resolver_test.rb +34 -70
- data/test/operation_test.rb +57 -189
- data/test/test_helper.rb +23 -3
- data/trailblazer.gemspec +8 -7
- metadata +91 -59
- data/gemfiles/Gemfile.rails.lock +0 -130
- data/gemfiles/Gemfile.reform-2.0 +0 -6
- data/gemfiles/Gemfile.reform-2.1 +0 -7
- data/lib/trailblazer/autoloading.rb +0 -15
- data/lib/trailblazer/endpoint.rb +0 -31
- data/lib/trailblazer/operation.rb +0 -175
- data/lib/trailblazer/operation/collection.rb +0 -6
- data/lib/trailblazer/operation/dispatch.rb +0 -3
- data/lib/trailblazer/operation/model/dsl.rb +0 -29
- data/lib/trailblazer/operation/model/external.rb +0 -34
- data/lib/trailblazer/operation/policy/guard.rb +0 -35
- data/lib/trailblazer/operation/uploaded_file.rb +0 -77
- data/test/callback_test.rb +0 -104
- data/test/collection_test.rb +0 -57
- data/test/model_test.rb +0 -148
- data/test/operation/external_model_test.rb +0 -71
- data/test/operation/policy_test.rb +0 -97
- data/test/operation/reject_test.rb +0 -34
- data/test/rollback_test.rb +0 -47
@@ -1,35 +0,0 @@
|
|
1
|
-
module Trailblazer
|
2
|
-
# Policy::Guard is a very simple policy implementation.
|
3
|
-
# It adds #evaluate_policy to Operation#setup! and calls whatever
|
4
|
-
# you provided to ::policy.
|
5
|
-
#
|
6
|
-
# http://trailblazer.to/gems/operation/policy.html#guard
|
7
|
-
module Operation::Policy
|
8
|
-
module Guard
|
9
|
-
def self.included(includer)
|
10
|
-
includer.extend(DSL) # Provides ::policy(CallableObject)
|
11
|
-
includer.extend(ClassMethods)
|
12
|
-
includer.send(:include, Setup)
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
def policy(callable=nil, &block)
|
17
|
-
self.policy_config = Uber::Options::Value.new(callable || block)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def evaluate_policy(params)
|
22
|
-
call_policy(params) or raise policy_exception
|
23
|
-
end
|
24
|
-
|
25
|
-
# Override if you want your own policy invocation, e.g. with more args.
|
26
|
-
def call_policy(params)
|
27
|
-
self.class.policy_config.(self, params)
|
28
|
-
end
|
29
|
-
|
30
|
-
def policy_exception
|
31
|
-
NotAuthorizedError.new
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'trailblazer/operation'
|
2
|
-
require 'action_dispatch/http/upload'
|
3
|
-
require 'tempfile'
|
4
|
-
|
5
|
-
module Trailblazer
|
6
|
-
# TODO: document:
|
7
|
-
# to_hash
|
8
|
-
# from_hash
|
9
|
-
# initialize/tmp_dir
|
10
|
-
class Operation::UploadedFile
|
11
|
-
def initialize(uploaded, options={})
|
12
|
-
@uploaded = uploaded
|
13
|
-
@options = options
|
14
|
-
@tmp_dir = options[:tmp_dir]
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_hash
|
18
|
-
path = persist!
|
19
|
-
|
20
|
-
hash = {
|
21
|
-
filename: @uploaded.original_filename,
|
22
|
-
type: @uploaded.content_type,
|
23
|
-
tempfile_path: path
|
24
|
-
}
|
25
|
-
|
26
|
-
cleanup!
|
27
|
-
|
28
|
-
hash
|
29
|
-
end
|
30
|
-
|
31
|
-
# Returns a ActionDispatch::Http::UploadedFile as if the upload was in the same request.
|
32
|
-
def self.from_hash(hash)
|
33
|
-
suffix = File.extname(hash[:filename])
|
34
|
-
|
35
|
-
# we need to create a Tempfile to make Http::UploadedFile work.
|
36
|
-
tmp = Tempfile.new(["bla", suffix]) # always force file suffix to avoid problems with imagemagick etc.
|
37
|
-
file = File.open(hash[:tempfile_path])# doesn't close automatically :( # fixme: introduce strategy (Tempfile:=>slow, File:=> hopefully less memory footprint)
|
38
|
-
tmp.write(file.read) # DISCUSS: We need Tempfile.new(<File>) to avoid this slow and memory-consuming mechanics.
|
39
|
-
|
40
|
-
file.close # TODO: can we test that?
|
41
|
-
File.unlink(file)
|
42
|
-
|
43
|
-
ActionDispatch::Http::UploadedFile.new(hash.merge(tempfile: tmp))
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
attr_reader :tmp_dir
|
48
|
-
|
49
|
-
# convert Tempfile from Rails upload into persistent "temp" file so it is available in workers.
|
50
|
-
def persist!
|
51
|
-
path = @uploaded.path # original Tempfile path (from Rails).
|
52
|
-
path = path_with_tmp_dir(path)
|
53
|
-
|
54
|
-
path = path + "_trailblazer_upload"
|
55
|
-
|
56
|
-
FileUtils.mv(@uploaded.path, path) # move Rails upload file into persistent `path`.
|
57
|
-
path
|
58
|
-
end
|
59
|
-
|
60
|
-
def path_with_tmp_dir(path)
|
61
|
-
return path unless tmp_dir # if tmp_dir set, create path in it.
|
62
|
-
|
63
|
-
@with_tmp_dir = Tempfile.new(File.basename(path), tmp_dir)
|
64
|
-
@with_tmp_dir.path # use Tempfile to create nested dirs (os-dependent.)
|
65
|
-
end
|
66
|
-
|
67
|
-
def delete!(file)
|
68
|
-
file.close
|
69
|
-
file.unlink # the Rails uploaded file is already unlinked since moved.
|
70
|
-
end
|
71
|
-
|
72
|
-
def cleanup!
|
73
|
-
delete!(@uploaded.tempfile) if @uploaded.respond_to?(:tempfile) # this is Rails' uploaded file, not sure if we need to do that. in 3.2, we don't have UploadedFile#close, yet.
|
74
|
-
delete!(@with_tmp_dir) if @with_tmp_dir # we used that file to create a tmp file path below tmp_dir.
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
data/test/callback_test.rb
DELETED
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require "trailblazer/operation/callback"
|
3
|
-
|
4
|
-
# callbacks are tested in Disposable::Callback::Group.
|
5
|
-
class OperationCallbackTest < MiniTest::Spec
|
6
|
-
Song = Struct.new(:name)
|
7
|
-
|
8
|
-
class Create < Trailblazer::Operation
|
9
|
-
include Trailblazer::Operation::Callback
|
10
|
-
|
11
|
-
contract do
|
12
|
-
property :name
|
13
|
-
end
|
14
|
-
|
15
|
-
callback do
|
16
|
-
on_change :notify_me!
|
17
|
-
on_change :notify_you!
|
18
|
-
end
|
19
|
-
|
20
|
-
# TODO: always dispatch, pass params.
|
21
|
-
|
22
|
-
def process(params)
|
23
|
-
@model = Song.new
|
24
|
-
|
25
|
-
validate(params, @model) do
|
26
|
-
callback!
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def dispatched
|
31
|
-
@dispatched ||= []
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
def notify_me!(*)
|
36
|
-
dispatched << :notify_me!
|
37
|
-
end
|
38
|
-
|
39
|
-
def notify_you!(*)
|
40
|
-
dispatched << :notify_you!
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
class Update < Create
|
46
|
-
# TODO: allow skipping groups.
|
47
|
-
# skip_dispatch :notify_me!
|
48
|
-
|
49
|
-
callback do
|
50
|
-
remove! :on_change, :notify_me!
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
it "invokes all callbacks" do
|
56
|
-
op = Create.({"name"=>"Keep On Running"})
|
57
|
-
op.dispatched.must_equal [:notify_me!, :notify_you!]
|
58
|
-
end
|
59
|
-
|
60
|
-
it "does not invoke removed callbacks" do
|
61
|
-
op = Update.({"name"=>"Keep On Running"})
|
62
|
-
op.dispatched.must_equal [:notify_you!]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# TODO: remove in 1.2.
|
67
|
-
require "trailblazer/operation/dispatch"
|
68
|
-
class OperationDeprecatedDispatchTest < MiniTest::Spec
|
69
|
-
Song = Struct.new(:name)
|
70
|
-
|
71
|
-
class Create < Trailblazer::Operation
|
72
|
-
include Trailblazer::Operation::Dispatch
|
73
|
-
|
74
|
-
contract do
|
75
|
-
property :name
|
76
|
-
end
|
77
|
-
|
78
|
-
callback do
|
79
|
-
on_change :notify_me!
|
80
|
-
end
|
81
|
-
|
82
|
-
def process(params)
|
83
|
-
@model = Song.new
|
84
|
-
|
85
|
-
validate(params, @model) do
|
86
|
-
dispatch!
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def dispatched
|
91
|
-
@dispatched ||= []
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
def notify_me!(*)
|
96
|
-
dispatched << :notify_me!
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
it "invokes all callbacks [deprecated]" do
|
101
|
-
op = Create.({"name"=>"Keep On Running"})
|
102
|
-
op.dispatched.must_equal [:notify_me!]
|
103
|
-
end
|
104
|
-
end
|
data/test/collection_test.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
require "trailblazer/operation/collection"
|
3
|
-
require "trailblazer/operation/model"
|
4
|
-
|
5
|
-
class CollectionTest < MiniTest::Spec
|
6
|
-
Song = Struct.new(:title, :id) do
|
7
|
-
class << self
|
8
|
-
attr_accessor :all_records
|
9
|
-
|
10
|
-
def all
|
11
|
-
all_records
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
class CreateOperation < Trailblazer::Operation
|
18
|
-
include Model
|
19
|
-
model Song
|
20
|
-
action :create
|
21
|
-
|
22
|
-
contract do
|
23
|
-
property :title
|
24
|
-
validates :title, presence: true
|
25
|
-
end
|
26
|
-
|
27
|
-
def process(params)
|
28
|
-
validate(params[:song]) do |f|
|
29
|
-
f.sync
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class FetchCollectionOperation < CreateOperation
|
35
|
-
include Trailblazer::Operation::Collection
|
36
|
-
|
37
|
-
model Song
|
38
|
-
|
39
|
-
contract do
|
40
|
-
property :title
|
41
|
-
end
|
42
|
-
|
43
|
-
def model!(params)
|
44
|
-
Song.all
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# ::present.
|
49
|
-
it do
|
50
|
-
Song.all_records = [
|
51
|
-
CreateOperation.(song: {title: "Blue Rondo a la Turk"}).model,
|
52
|
-
CreateOperation.(song: {title: "Mercy Day For Mr. Vengeance"}).model
|
53
|
-
]
|
54
|
-
op = FetchCollectionOperation.present(user_id: 0)
|
55
|
-
op.model.must_equal Song.all_records
|
56
|
-
end
|
57
|
-
end
|
data/test/model_test.rb
DELETED
@@ -1,148 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'trailblazer/operation'
|
3
|
-
|
4
|
-
class ModelTest < MiniTest::Spec
|
5
|
-
Song = Struct.new(:title, :id) do
|
6
|
-
class << self
|
7
|
-
attr_accessor :find_result # TODO: eventually, replace with AR test.
|
8
|
-
attr_accessor :all_records
|
9
|
-
|
10
|
-
def find(id)
|
11
|
-
find_result
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class CreateOperation < Trailblazer::Operation
|
17
|
-
include Model
|
18
|
-
model Song
|
19
|
-
action :create
|
20
|
-
|
21
|
-
contract do
|
22
|
-
property :title
|
23
|
-
validates :title, presence: true
|
24
|
-
end
|
25
|
-
|
26
|
-
def process(params)
|
27
|
-
validate(params[:song]) do |f|
|
28
|
-
f.sync
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
# creates model for you.
|
35
|
-
it { CreateOperation.(song: {title: "Blue Rondo a la Turk"}).model.title.must_equal "Blue Rondo a la Turk" }
|
36
|
-
# exposes #model.
|
37
|
-
it { CreateOperation.(song: {title: "Blue Rondo a la Turk"}).model.must_be_instance_of Song }
|
38
|
-
|
39
|
-
class ModifyingCreateOperation < CreateOperation
|
40
|
-
def process(params)
|
41
|
-
model.instance_eval { def genre; "Punkrock"; end }
|
42
|
-
|
43
|
-
validate(params[:song]) do |f|
|
44
|
-
f.sync
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# lets you modify model.
|
50
|
-
it { ModifyingCreateOperation.(song: {title: "Blue Rondo a la Turk"}).model.title.must_equal "Blue Rondo a la Turk" }
|
51
|
-
it { ModifyingCreateOperation.(song: {title: "Blue Rondo a la Turk"}).model.genre.must_equal "Punkrock" }
|
52
|
-
|
53
|
-
# Update
|
54
|
-
class UpdateOperation < CreateOperation
|
55
|
-
action :update
|
56
|
-
end
|
57
|
-
|
58
|
-
# finds model and updates.
|
59
|
-
it do
|
60
|
-
song = CreateOperation.(song: {title: "Anchor End"}).model
|
61
|
-
Song.find_result = song
|
62
|
-
|
63
|
-
UpdateOperation.(id: song.id, song: {title: "The Rip"}).model.title.must_equal "The Rip"
|
64
|
-
song.title.must_equal "The Rip"
|
65
|
-
end
|
66
|
-
|
67
|
-
# Find == Update
|
68
|
-
class FindOperation < CreateOperation
|
69
|
-
action :find
|
70
|
-
end
|
71
|
-
|
72
|
-
# finds model and updates.
|
73
|
-
it do
|
74
|
-
song = CreateOperation.(song: {title: "Anchor End"}).model
|
75
|
-
Song.find_result = song
|
76
|
-
|
77
|
-
FindOperation.(id: song.id, song: {title: "The Rip"}).model.title.must_equal "The Rip"
|
78
|
-
song.title.must_equal "The Rip"
|
79
|
-
end
|
80
|
-
|
81
|
-
|
82
|
-
class DefaultCreateOperation < Trailblazer::Operation
|
83
|
-
include Model
|
84
|
-
model Song
|
85
|
-
|
86
|
-
def process(params)
|
87
|
-
self
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# uses :create as default if not set via ::action.
|
92
|
-
it { DefaultCreateOperation.({}).model.must_equal Song.new }
|
93
|
-
|
94
|
-
# model Song, :action
|
95
|
-
class ModelUpdateOperation < CreateOperation
|
96
|
-
model Song, :update
|
97
|
-
end
|
98
|
-
|
99
|
-
# allows ::model, :action.
|
100
|
-
it do
|
101
|
-
Song.find_result = song = Song.new
|
102
|
-
ModelUpdateOperation.({id: 1, song: {title: "Mercy Day For Mr. Vengeance"}}).model.must_equal song
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
# Op#setup_model!
|
108
|
-
class SetupModelOperation < CreateOperation
|
109
|
-
def setup_model!(params)
|
110
|
-
model.instance_eval { @params = params; def params; @params.to_s; end }
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
it { SetupModelOperation.(song: {title: "Emily Kane"}).model.params.must_equal "{:song=>{:title=>\"Emily Kane\"}}" }
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# no call to ::model raises error.
|
119
|
-
class NoModelOperation < Trailblazer::Operation
|
120
|
-
include Model
|
121
|
-
|
122
|
-
def process(params)
|
123
|
-
self
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# uses :create as default if not set via ::action.
|
128
|
-
it { assert_raises(RuntimeError){ NoModelOperation.({}) } }
|
129
|
-
|
130
|
-
# allow passing validate(params, model, contract_class)
|
131
|
-
class OperationWithPrivateContract < Trailblazer::Operation
|
132
|
-
include Model
|
133
|
-
model Song
|
134
|
-
|
135
|
-
class Contract < Reform::Form
|
136
|
-
property :title
|
137
|
-
end
|
138
|
-
|
139
|
-
def process(params)
|
140
|
-
validate(params[:song], model, Contract) do |f|
|
141
|
-
f.sync
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# uses private Contract class.
|
147
|
-
it { OperationWithPrivateContract.(song: {title: "Blue Rondo a la Turk"}).model.title.must_equal "Blue Rondo a la Turk" }
|
148
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
require "trailblazer/operation/model/external"
|
3
|
-
|
4
|
-
class ExternalModelTest < MiniTest::Spec
|
5
|
-
Song = Struct.new(:title, :id) do
|
6
|
-
class << self
|
7
|
-
attr_accessor :find_result # TODO: eventually, replace with AR test.
|
8
|
-
attr_accessor :all_records
|
9
|
-
|
10
|
-
def find(id)
|
11
|
-
find_result.tap do |song|
|
12
|
-
song.id = id
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end # FIXME: use from CrudTest.
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
class Bla < Trailblazer::Operation
|
22
|
-
include Model::External
|
23
|
-
model Song, :update
|
24
|
-
|
25
|
-
def process(params)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
let (:song) { Song.new("Numbers") }
|
30
|
-
|
31
|
-
before do
|
32
|
-
Song.find_result = song
|
33
|
-
end
|
34
|
-
|
35
|
-
# ::model!
|
36
|
-
it do
|
37
|
-
Bla.model!(id: 1).must_equal song
|
38
|
-
song.id.must_equal 1
|
39
|
-
end
|
40
|
-
|
41
|
-
# call style.
|
42
|
-
it do
|
43
|
-
Bla.(id: 2).model.must_equal song
|
44
|
-
song.id.must_equal 2
|
45
|
-
end
|
46
|
-
|
47
|
-
# #present.
|
48
|
-
it do
|
49
|
-
Bla.present({}).model.must_equal song
|
50
|
-
end
|
51
|
-
|
52
|
-
|
53
|
-
class OpWithBuilder < Bla
|
54
|
-
class A < self
|
55
|
-
end
|
56
|
-
|
57
|
-
builds -> (model, params) do
|
58
|
-
return A if model.id == 1 and params[:user] == 2
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe "::builds args" do
|
63
|
-
it do
|
64
|
-
OpWithBuilder.(id: 1, user: "different").must_be_instance_of OpWithBuilder
|
65
|
-
end
|
66
|
-
|
67
|
-
it do
|
68
|
-
OpWithBuilder.(id: 1, user: 2).must_be_instance_of OpWithBuilder::A
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|