trailblazer-endpoint 0.0.2 → 0.0.7
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/.gitignore +16 -0
- data/Appraisals +5 -0
- data/CHANGES.md +28 -0
- data/README.md +40 -5
- data/Rakefile +7 -1
- data/gemfiles/rails_app.gemfile +12 -0
- data/lib/trailblazer/endpoint.rb +55 -16
- data/lib/trailblazer/endpoint/adapter.rb +30 -121
- data/lib/trailblazer/endpoint/builder.rb +1 -1
- data/lib/trailblazer/endpoint/controller.rb +223 -0
- data/lib/trailblazer/endpoint/dsl.rb +31 -0
- data/lib/trailblazer/endpoint/options.rb +92 -0
- data/lib/trailblazer/endpoint/protocol.rb +7 -11
- data/lib/trailblazer/endpoint/protocol/cipher.rb +27 -0
- data/lib/trailblazer/endpoint/protocol/controller.rb +93 -0
- data/lib/trailblazer/endpoint/protocol/find_process_model.rb +15 -0
- data/lib/trailblazer/endpoint/version.rb +1 -1
- data/test/adapter/api_test.rb +6 -11
- data/test/adapter/web_test.rb +2 -5
- data/test/config_test.rb +128 -0
- data/test/docs/controller_test.rb +340 -58
- data/test/endpoint_test.rb +1 -1
- data/test/rails-app/.gitignore +8 -2
- data/test/rails-app/.ruby-version +1 -0
- data/test/rails-app/Gemfile +21 -9
- data/test/rails-app/Gemfile.lock +173 -118
- data/test/rails-app/app/concepts/app/api/v1/representer/errors.rb +16 -0
- data/test/rails-app/app/concepts/auth/jwt.rb +35 -0
- data/test/rails-app/app/concepts/auth/operation/authenticate.rb +32 -0
- data/test/rails-app/app/concepts/auth/operation/policy.rb +9 -0
- data/test/rails-app/app/concepts/song/cell/create.rb +4 -0
- data/test/rails-app/app/concepts/song/cell/new.rb +4 -0
- data/test/rails-app/app/concepts/song/operation/create.rb +17 -0
- data/test/rails-app/app/concepts/song/operation/show.rb +10 -0
- data/test/rails-app/app/concepts/song/representer.rb +5 -0
- data/test/rails-app/app/concepts/song/view/create.erb +1 -0
- data/test/rails-app/app/concepts/song/view/new.erb +1 -0
- data/test/rails-app/app/controllers/api/v1/songs_controller.rb +41 -0
- data/test/rails-app/app/controllers/application_controller.rb +8 -1
- data/test/rails-app/app/controllers/application_controller/api.rb +107 -0
- data/test/rails-app/app/controllers/application_controller/web.rb +45 -0
- data/test/rails-app/app/controllers/auth_controller.rb +44 -0
- data/test/rails-app/app/controllers/home_controller.rb +5 -0
- data/test/rails-app/app/controllers/songs_controller.rb +245 -13
- data/test/rails-app/app/models/song.rb +6 -0
- data/test/rails-app/app/models/user.rb +7 -0
- data/test/rails-app/bin/bundle +114 -0
- data/test/rails-app/bin/rails +4 -0
- data/test/rails-app/bin/rake +4 -0
- data/test/rails-app/bin/setup +33 -0
- data/test/rails-app/config/application.rb +26 -3
- data/test/rails-app/config/credentials.yml.enc +1 -0
- data/test/rails-app/config/database.yml +2 -2
- data/test/rails-app/config/environments/development.rb +7 -17
- data/test/rails-app/config/environments/production.rb +28 -23
- data/test/rails-app/config/environments/test.rb +10 -12
- data/test/rails-app/config/initializers/application_controller_renderer.rb +6 -4
- data/test/rails-app/config/initializers/cors.rb +16 -0
- data/test/rails-app/config/initializers/trailblazer.rb +2 -0
- data/test/rails-app/config/locales/en.yml +11 -1
- data/test/rails-app/config/master.key +1 -0
- data/test/rails-app/config/routes.rb +26 -4
- data/test/rails-app/db/schema.rb +15 -0
- data/test/rails-app/test/controllers/api_songs_controller_test.rb +87 -0
- data/test/rails-app/test/controllers/songs_controller_test.rb +146 -144
- data/test/rails-app/test/test_helper.rb +7 -1
- data/test/test_helper.rb +0 -2
- data/trailblazer-endpoint.gemspec +2 -1
- metadata +73 -22
- data/test/rails-app/config/initializers/cookies_serializer.rb +0 -5
- data/test/rails-app/config/initializers/new_framework_defaults.rb +0 -24
- data/test/rails-app/config/initializers/session_store.rb +0 -3
- data/test/rails-app/config/secrets.yml +0 -22
- data/test/rails-app/test/helpers/.keep +0 -0
- data/test/rails-app/test/integration/.keep +0 -0
- data/test/rails-app/test/mailers/.keep +0 -0
- data/test/rails-app/vendor/assets/javascripts/.keep +0 -0
- data/test/rails-app/vendor/assets/stylesheets/.keep +0 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
class Trailblazer::Endpoint::Protocol
|
2
|
+
class FindProcessModel < Trailblazer::Activity::Railway
|
3
|
+
# step :find_process_model?, Output(:failure) => Id("End.success")
|
4
|
+
step :find_process_model#, Output(:failure) => End(:not_found) # DISCUSS: currently, {End.failure} implies {not_found}.
|
5
|
+
|
6
|
+
# DISCUSS: should the implementation remain in {Activity}?
|
7
|
+
# def find_process_model?(ctx, find_process_model:, **)
|
8
|
+
# find_process_model
|
9
|
+
# end
|
10
|
+
|
11
|
+
def find_process_model(ctx, process_model_class:, process_model_id:, **)
|
12
|
+
ctx[:process_model] = process_model_class.find_by(id: process_model_id)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/test/adapter/api_test.rb
CHANGED
@@ -12,14 +12,13 @@ class AdapterAPITest < Minitest::Spec
|
|
12
12
|
protocol: protocol, # do we cover all usual routes?
|
13
13
|
adapter: Trailblazer::Endpoint::Adapter::API,
|
14
14
|
scope_domain_ctx: false,
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
{Output(:not_found) => Track(:not_found)}
|
19
|
-
end
|
15
|
+
protocol_block: -> { {Output(:not_found) => Track(:not_found)} }
|
16
|
+
)
|
20
17
|
|
21
18
|
# success
|
22
19
|
assert_route endpoint, {}, :authenticate, :policy, :model, :validate, :success, status: 200
|
20
|
+
# created, when passing 201
|
21
|
+
assert_route endpoint, {success_status: 201}, :authenticate, :policy, :model, :validate, :success, status: 201
|
23
22
|
# authentication error
|
24
23
|
assert_route endpoint, {authenticate: false}, :authenticate, :fail_fast, status: 401 # fail_fast == protocol error
|
25
24
|
# policy error
|
@@ -47,12 +46,8 @@ class AdapterAPITest < Minitest::Spec
|
|
47
46
|
protocol: protocol, # do we cover all usual routes?
|
48
47
|
adapter: adapter,
|
49
48
|
scope_domain_ctx: false,
|
50
|
-
|
51
|
-
)
|
52
|
-
|
53
|
-
|
54
|
-
{Output(:not_found) => Track(:not_found)}
|
55
|
-
end
|
49
|
+
protocol_block: -> { {Output(:not_found) => Track(:not_found)} }
|
50
|
+
)
|
56
51
|
|
57
52
|
class TestErrors < Struct.new(:message)
|
58
53
|
def ==(b)
|
data/test/adapter/web_test.rb
CHANGED
@@ -19,11 +19,8 @@ class AdapterWebTest < Minitest::Spec
|
|
19
19
|
protocol: protocol, # do we cover all usual routes?
|
20
20
|
adapter: Trailblazer::Endpoint::Adapter::Web,
|
21
21
|
scope_domain_ctx: false,
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
{Output(:not_found) => Track(:not_found)}
|
26
|
-
end
|
22
|
+
protocol_block: -> { {Output(:not_found) => Track(:not_found)} }
|
23
|
+
)
|
27
24
|
|
28
25
|
# success
|
29
26
|
assert_route(endpoint, {}, :authenticate, :policy, :model, :validate, :success)
|
data/test/config_test.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
require "trailblazer/endpoint/options"
|
4
|
+
|
5
|
+
class ConfigTest < Minitest::Spec
|
6
|
+
Controller = Struct.new(:params)
|
7
|
+
|
8
|
+
it "what" do
|
9
|
+
ApplicationController.options_for(:options_for_endpoint, {}).inspect.must_equal %{{:find_process_model=>true, :request=>true}}
|
10
|
+
|
11
|
+
# inherits endpoint options from ApplicationController
|
12
|
+
ApeController.options_for(:options_for_endpoint, {}).inspect.must_equal %{{:find_process_model=>true, :request=>true}}
|
13
|
+
# defines its own domain options, none in ApplicationController
|
14
|
+
ApeController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:current_user=>\"Yo\"}}
|
15
|
+
|
16
|
+
# 3-rd level, inherit everything from 2-nd level
|
17
|
+
ApeBabeController.options_for(:options_for_endpoint, {}).inspect.must_equal %{{:find_process_model=>true, :request=>true}}
|
18
|
+
ApeBabeController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:current_user=>\"Yo\"}}
|
19
|
+
|
20
|
+
# 4t-h level, also inherit everything from 2-nd level
|
21
|
+
ApeBabeKidController.options_for(:options_for_endpoint, {}).inspect.must_equal %{{:find_process_model=>true, :request=>true}}
|
22
|
+
ApeBabeKidController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:current_user=>\"Yo\"}}
|
23
|
+
|
24
|
+
BoringController.options_for(:options_for_endpoint, {}).inspect.must_equal %{{:find_process_model=>true, :request=>true, :xml=>"<XML"}}
|
25
|
+
BoringController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:policy=>\"Ehm\"}}
|
26
|
+
|
27
|
+
OverridingController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:redis=>\"Arrr\"}}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "raises helpful exception with unknown directive" do
|
31
|
+
assert_raises KeyError do
|
32
|
+
ApplicationController.options_for(:unknown_options, {})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class ApplicationController
|
37
|
+
def self.options_for_endpoint(ctx, **)
|
38
|
+
{
|
39
|
+
find_process_model: true,
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.request_options(ctx, **)
|
44
|
+
{
|
45
|
+
request: true,
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
extend Trailblazer::Endpoint::Controller
|
50
|
+
directive :options_for_endpoint, method(:options_for_endpoint), method(:request_options)
|
51
|
+
end
|
52
|
+
|
53
|
+
class ApeController < ApplicationController
|
54
|
+
def self.options_for_domain_ctx(ctx, **)
|
55
|
+
{
|
56
|
+
current_user: "Yo",
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
61
|
+
end
|
62
|
+
|
63
|
+
class ApeBabeController < ApeController
|
64
|
+
# def self.options_for_domain_ctx(ctx, **)
|
65
|
+
# {policy: "Ehm"}
|
66
|
+
# end
|
67
|
+
|
68
|
+
# directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
69
|
+
end
|
70
|
+
|
71
|
+
class ApeBabeKidController < ApeController
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
class BoringController < ApplicationController
|
76
|
+
def self.options_for_domain_ctx(ctx, **) {policy: "Ehm",} end
|
77
|
+
def self.options_for_endpoint(ctx, **) {xml: "<XML",} end
|
78
|
+
|
79
|
+
directive :options_for_endpoint, method(:options_for_endpoint) #, inherit: ApplicationController
|
80
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
81
|
+
end
|
82
|
+
|
83
|
+
class OverridingController < BoringController
|
84
|
+
def self.options_for_domain_ctx(ctx, **)
|
85
|
+
{
|
86
|
+
redis: "Arrr",
|
87
|
+
}
|
88
|
+
end
|
89
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx), inherit: false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class RuntimeOptionsTest < Minitest::Spec
|
94
|
+
class ApplicationController
|
95
|
+
def self.options_for_endpoint(ctx, controller:, **)
|
96
|
+
{
|
97
|
+
option: true,
|
98
|
+
params: controller[:params],
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
# You can access variables set prior to this options directive.
|
103
|
+
def self.request_options(ctx, controller:, params:, **)
|
104
|
+
{
|
105
|
+
my_params: params.inspect,
|
106
|
+
option: nil,
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
extend Trailblazer::Endpoint::Controller
|
111
|
+
directive :options_for_endpoint, method(:options_for_endpoint), method(:request_options)
|
112
|
+
end
|
113
|
+
|
114
|
+
it do
|
115
|
+
ApplicationController.options_for(:options_for_endpoint, controller: {params: {id: 1}}).inspect.must_equal %{{:option=>nil, :params=>{:id=>1}, :my_params=>\"{:id=>1}\"}}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class OptionsTest < Minitest::Spec
|
120
|
+
# Options#merge_with
|
121
|
+
it "works with empty {merged}" do
|
122
|
+
Trailblazer::Endpoint::Options.merge_with({}, {a: 1, b: 2}).inspect.must_equal %{{:a=>1, :b=>2}}
|
123
|
+
end
|
124
|
+
|
125
|
+
it "keys in merged have precedence, but unknown {merged} keys are discarded" do
|
126
|
+
Trailblazer::Endpoint::Options.merge_with({a: 3, d: 4}, {a: 1, b: 2}).inspect.must_equal %{{:a=>3, :b=>2}}
|
127
|
+
end
|
128
|
+
end
|
@@ -1,92 +1,374 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class DocsControllerTest < Minitest::Spec
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
class ApplicationController
|
5
|
+
def self.options_for_endpoint(ctx, controller:, **)
|
6
|
+
{
|
7
|
+
find_process_model: true,
|
8
|
+
**controller.instance_variable_get(:@params)[:params],
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.request_options(ctx, **)
|
13
|
+
{
|
14
|
+
request: true,
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.options_for_flow_options(ctx, **)
|
19
|
+
{
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.options_for_block_options(ctx, controller:, **)
|
24
|
+
{
|
25
|
+
success_block: ->(ctx, seq:, **) { controller.instance_exec { render seq << :success_block } },
|
26
|
+
failure_block: ->(ctx, seq:, **) { controller.instance_exec { render seq << :failure_block } },
|
27
|
+
protocol_failure_block: ->(ctx, seq:, **) { controller.instance_exec { render seq << :protocol_failure_block } }
|
28
|
+
}
|
8
29
|
end
|
9
30
|
|
10
|
-
|
11
|
-
|
31
|
+
|
32
|
+
extend Trailblazer::Endpoint::Controller
|
33
|
+
|
34
|
+
# include Trailblazer::Endpoint::Controller::InstanceMethods # {#endpoint_for}
|
35
|
+
include Trailblazer::Endpoint::Controller::InstanceMethods::DSL # {#endpoint}
|
36
|
+
|
37
|
+
include Trailblazer::Endpoint::Controller::Rails
|
38
|
+
include Trailblazer::Endpoint::Controller::Rails::Process
|
39
|
+
|
40
|
+
directive :options_for_endpoint, method(:options_for_endpoint), method(:request_options)
|
41
|
+
directive :options_for_flow_options, method(:options_for_flow_options)
|
42
|
+
directive :options_for_block_options, method(:options_for_block_options)
|
43
|
+
|
44
|
+
def process(action_name, **params)
|
45
|
+
@params = params
|
46
|
+
send_action(action_name)
|
47
|
+
@render
|
48
|
+
end
|
49
|
+
|
50
|
+
def render(text)
|
51
|
+
@render = text
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
Protocol = Class.new(Trailblazer::Endpoint::Protocol) do
|
58
|
+
include T.def_steps(:authenticate, :policy)
|
59
|
+
end
|
60
|
+
|
61
|
+
endpoint protocol: Protocol, adapter: Trailblazer::Endpoint::Adapter::Web,
|
62
|
+
scope_domain_ctx: true
|
12
63
|
end
|
13
64
|
|
65
|
+
class HtmlController < ApplicationController
|
66
|
+
private def endpoint_for(*)
|
67
|
+
protocol = Class.new(Trailblazer::Endpoint::Protocol) do
|
68
|
+
include T.def_steps(:authenticate, :policy)
|
69
|
+
end
|
70
|
+
|
71
|
+
endpoint =
|
72
|
+
Trailblazer::Endpoint.build(
|
73
|
+
domain_activity: Minitest::Spec.new(nil).activity, # FIXME
|
74
|
+
protocol: protocol,
|
75
|
+
adapter: Trailblazer::Endpoint::Adapter::Web,
|
76
|
+
scope_domain_ctx: true,
|
77
|
+
|
78
|
+
) do
|
79
|
+
{Output(:not_found) => Track(:not_found)}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.options_for_domain_ctx(ctx, seq:, controller:, **)
|
84
|
+
{
|
85
|
+
current_user: "Yo",
|
86
|
+
seq: seq,
|
87
|
+
**controller.instance_variable_get(:@params)[:params],
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
14
92
|
|
15
|
-
|
16
|
-
|
17
|
-
@___activity = activity
|
18
|
-
@endpoint = endpoint
|
19
|
-
@seq = []
|
93
|
+
private def _endpoint(action, seq: [], &block)
|
94
|
+
endpoint(action, seq: seq, &block)
|
20
95
|
end
|
21
96
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
97
|
+
# all standard routes are user-defined
|
98
|
+
def view
|
99
|
+
_endpoint "view?" do |ctx, seq:, **|
|
100
|
+
render "success" + ctx[:current_user] + seq.inspect
|
101
|
+
end.failure do |ctx, seq:, **|
|
102
|
+
render "failure" + ctx[:current_user] + seq.inspect
|
103
|
+
|
104
|
+
end.protocol_failure do |ctx, seq:, **|
|
105
|
+
render "protocol_failure" + ctx[:current_user] + seq.inspect
|
27
106
|
end
|
107
|
+
end
|
28
108
|
|
29
|
-
|
30
|
-
|
31
|
-
|
109
|
+
# standard use-case: only success
|
110
|
+
def show
|
111
|
+
_endpoint "view?" do |ctx, seq:, **|
|
112
|
+
render "success" + ctx[:current_user] + seq.inspect
|
113
|
+
end
|
32
114
|
end
|
33
115
|
|
34
|
-
|
35
|
-
|
36
|
-
|
116
|
+
# standard use case: {success} and {failure}
|
117
|
+
def update
|
118
|
+
_endpoint "view?" do |ctx, seq:, **|
|
119
|
+
render "success" + ctx[:current_user] + seq.inspect
|
120
|
+
end.Or do |ctx, seq:, **|
|
121
|
+
render "Fail!" + ctx[:current_user] + seq.inspect
|
122
|
+
end
|
37
123
|
end
|
38
124
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
125
|
+
end # HtmlController
|
126
|
+
|
127
|
+
it "what" do
|
128
|
+
# success
|
129
|
+
controller = HtmlController.new
|
130
|
+
controller.process(:view, params: {}).must_equal %{successYo[:authenticate, :policy, :model, :validate]}
|
45
131
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
flow_options: {},
|
132
|
+
# failure
|
133
|
+
controller = HtmlController.new
|
134
|
+
controller.process(:view, params: {validate: false}).must_equal %{failureYo[:authenticate, :policy, :model, :validate]}
|
50
135
|
|
51
|
-
|
136
|
+
# protocol_failure
|
137
|
+
controller = HtmlController.new
|
138
|
+
controller.process(:view, params: {authenticate: false}).must_equal %{protocol_failureYo[:authenticate]}
|
139
|
+
end
|
52
140
|
|
53
|
-
|
54
|
-
|
55
|
-
|
141
|
+
it "only success_block is user-defined" do
|
142
|
+
# success
|
143
|
+
controller = HtmlController.new
|
144
|
+
controller.process(:show, params: {}).must_equal %{successYo[:authenticate, :policy, :model, :validate]}
|
145
|
+
|
146
|
+
# failure
|
147
|
+
controller = HtmlController.new
|
148
|
+
# from controller-default
|
149
|
+
controller.process(:show, params: {validate: false}).must_equal [:authenticate, :policy, :model, :validate, :failure_block]
|
150
|
+
|
151
|
+
# protocol_failure
|
152
|
+
controller = HtmlController.new
|
153
|
+
# from controller-default
|
154
|
+
controller.process(:show, params: {authenticate: false}).must_equal [:authenticate, :protocol_failure_block]
|
155
|
+
end
|
156
|
+
|
157
|
+
it "success/Or" do
|
158
|
+
# success
|
159
|
+
controller = HtmlController.new
|
160
|
+
controller.process(:update, params: {}).must_equal %{successYo[:authenticate, :policy, :model, :validate]}
|
161
|
+
|
162
|
+
# failure
|
163
|
+
controller = HtmlController.new
|
164
|
+
# from controller-default
|
165
|
+
controller.process(:update, params: {validate: false}).must_equal %{Fail!Yo[:authenticate, :policy, :model, :validate]}
|
166
|
+
|
167
|
+
# protocol_failure
|
168
|
+
controller = HtmlController.new
|
169
|
+
# from controller-default
|
170
|
+
controller.process(:update, params: {authenticate: false}).must_equal [:authenticate, :protocol_failure_block]
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
# Test if {domain_ctx} is automatically wrapped via Context() so that we can use string-keys.
|
175
|
+
# TODO: test if aliases etc are properly passed.
|
176
|
+
class OptionsController < HtmlController
|
177
|
+
def self.options_for_domain_ctx(ctx, seq:, controller:, **)
|
178
|
+
{
|
179
|
+
"contract.params" => Object, # string-key should usually break if not wrapped
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.options_for_endpoint(ctx, controller:, **)
|
184
|
+
{
|
185
|
+
current_user: "Yogi",
|
186
|
+
process_model: Class,
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
191
|
+
directive :options_for_endpoint, method(:options_for_endpoint), inherit: false
|
192
|
+
|
193
|
+
def view
|
194
|
+
_endpoint "view?" do |ctx, seq:, **|
|
195
|
+
render "success" + ctx["contract.params"].to_s + seq.inspect
|
196
|
+
end
|
56
197
|
end
|
198
|
+
end # OptionsController
|
199
|
+
|
200
|
+
it "allows string keys in {domain_ctx} since it gets automatically Ctx()-wrapped" do
|
201
|
+
controller = OptionsController.new
|
202
|
+
controller.process(:view, params: {}).must_equal %{successObject[:authenticate, :policy, :model, :validate]}
|
57
203
|
end
|
58
204
|
|
59
|
-
|
60
|
-
|
61
|
-
|
205
|
+
|
206
|
+
# copy from {endpoint_ctx} to {domain_ctx}
|
207
|
+
class DomainContextController < ApplicationController
|
208
|
+
private def _endpoint(action, seq: [], **options, &block)
|
209
|
+
endpoint(action, seq: seq, **options, &block)
|
62
210
|
end
|
63
211
|
|
64
|
-
|
65
|
-
|
66
|
-
domain_activity: activity,
|
67
|
-
protocol: protocol,
|
68
|
-
adapter: Trailblazer::Endpoint::Adapter::Web,
|
69
|
-
scope_domain_ctx: false,
|
212
|
+
Activity = Class.new(Trailblazer::Activity::Railway) do
|
213
|
+
step :check
|
70
214
|
|
71
|
-
|
72
|
-
|
215
|
+
def check(ctx, current_user:, seq:, process_model:, **)
|
216
|
+
seq << :check
|
217
|
+
ctx[:message] = "#{current_user} / #{process_model}"
|
218
|
+
end
|
73
219
|
end
|
74
220
|
|
75
|
-
|
76
|
-
|
77
|
-
|
221
|
+
endpoint "view?", domain_activity: Activity
|
222
|
+
endpoint "show?", domain_activity: Activity
|
223
|
+
|
78
224
|
|
79
|
-
|
80
|
-
|
81
|
-
|
225
|
+
def self.options_for_domain_ctx(ctx, seq:, controller:, **)
|
226
|
+
{
|
227
|
+
seq: seq,
|
228
|
+
}
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.options_for_endpoint(ctx, controller:, **)
|
232
|
+
{
|
233
|
+
current_user: "Yogi",
|
234
|
+
process_model: Class,
|
235
|
+
something: true,
|
236
|
+
}
|
237
|
+
end
|
238
|
+
|
239
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
240
|
+
directive :options_for_endpoint, method(:options_for_endpoint), inherit: false
|
241
|
+
|
242
|
+
def view
|
243
|
+
_endpoint "view?" do |ctx, seq:, **|
|
244
|
+
render "success" + ctx[:message].to_s + seq.inspect
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def show
|
249
|
+
# override existing domain_ctx
|
250
|
+
# make options here available in steps
|
251
|
+
_endpoint "show?", options_for_domain_ctx: {params: {id: 1}, seq: []} do |ctx, seq:, params:, **|
|
252
|
+
render "success" + ctx[:message].to_s + seq.inspect + params.inspect
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def create
|
257
|
+
# add endpoint_options
|
258
|
+
_endpoint "show?", policy: false do |ctx, seq:, params:, **|
|
259
|
+
render "success" + ctx[:message].to_s + seq.inspect + params.inspect
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# todo: test overriding endp options
|
264
|
+
# _endpoint "show?", params: {id: 1}, process_model: "it's me!" do |ctx, seq:, params:, process_model:, **|
|
265
|
+
end # DomainContextController
|
266
|
+
|
267
|
+
it "{:current_user} and {:process_model} are made available in {domain_ctx}" do
|
268
|
+
controller = DomainContextController.new
|
269
|
+
controller.process(:view, params: {}).must_equal %{successYogi / Class[:authenticate, :policy, :check]}
|
270
|
+
end
|
271
|
+
|
272
|
+
it "{:seq} is overridden, {:params} made available, in {domain_ctx}" do
|
273
|
+
controller = DomainContextController.new
|
274
|
+
# note that {seq} is not shared anymore
|
275
|
+
controller.process(:show, params: {}).must_equal %{successYogi / Class[:check]{:id=>1}}
|
276
|
+
end
|
277
|
+
|
278
|
+
it "allows passing {endpoint_options} directly" do
|
279
|
+
controller = DomainContextController.new
|
280
|
+
controller.process(:create, params: {}).must_equal [:authenticate, :policy, :protocol_failure_block]
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
# Test without DSL
|
285
|
+
class BasicController
|
286
|
+
extend Trailblazer::Endpoint::Controller
|
287
|
+
|
288
|
+
directive :options_for_block_options, Trailblazer::Endpoint::Controller.method(:options_for_block_options)
|
289
|
+
|
290
|
+
def endpoint(name, &block)
|
291
|
+
action_options = {seq: []}
|
292
|
+
|
293
|
+
Trailblazer::Endpoint::Controller.advance_endpoint_for_controller(endpoint: endpoint_for(name), block_options: self.class.options_for(:options_for_block_options, {controller: self}), config_source: self.class, **action_options)
|
294
|
+
end
|
295
|
+
|
296
|
+
def head(status)
|
297
|
+
@status = status
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
class RodaController < BasicController
|
302
|
+
endpoint("show?", protocol: ApplicationController::Protocol, adapter: Trailblazer::Endpoint::Adapter::Web, domain_activity: Class.new(Trailblazer::Activity::Railway) { def save(*); true; end; step :save })
|
303
|
+
|
304
|
+
def show
|
305
|
+
endpoint "show?"
|
306
|
+
@status
|
307
|
+
end
|
82
308
|
end
|
83
309
|
|
84
310
|
it "what" do
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
311
|
+
RodaController.new.show.must_equal 200
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
class ControllerEndpointMethodTest < Minitest::Spec
|
316
|
+
# Test {Controller::endpoint}
|
317
|
+
|
318
|
+
class Protocol < Trailblazer::Endpoint::Protocol
|
319
|
+
def policy(*); true; end
|
320
|
+
def authenticate(*); true; end
|
321
|
+
end
|
322
|
+
|
323
|
+
class BasicController
|
324
|
+
include Trailblazer::Endpoint::Controller.module(api: true, application_controller: true)
|
325
|
+
|
326
|
+
directive :options_for_block_options, Trailblazer::Endpoint::Controller.method(:options_for_block_options)
|
327
|
+
|
328
|
+
endpoint protocol: Protocol, adapter: Trailblazer::Endpoint::Adapter::Web
|
329
|
+
|
330
|
+
def head(status)
|
331
|
+
@status = status
|
332
|
+
end
|
333
|
+
|
334
|
+
def self.options_for_block_options(ctx, controller:, **)
|
335
|
+
{
|
336
|
+
success_block: ->(ctx, endpoint_ctx:, **) { controller.head("#{ctx[:op]}") },
|
337
|
+
failure_block: ->(ctx, status:, **) { },
|
338
|
+
protocol_failure_block: ->(ctx, status:, **) { }
|
339
|
+
}
|
340
|
+
end
|
341
|
+
|
342
|
+
directive :options_for_block_options, method(:options_for_block_options)
|
343
|
+
end
|
344
|
+
|
345
|
+
class RodaController < BasicController
|
346
|
+
class Create < Trailblazer::Activity::Railway
|
347
|
+
def save(ctx, **); ctx[:op] = self.class; end;
|
348
|
+
step :save
|
349
|
+
end
|
350
|
+
class Update < Create
|
351
|
+
end
|
352
|
+
|
353
|
+
# {Controller::endpoint}: {:domain_activity} defaults to {name} when not given
|
354
|
+
endpoint Create # class {name}s are ok
|
355
|
+
endpoint :update, domain_activity: Update # symbol {name} is ok
|
356
|
+
|
357
|
+
def show
|
358
|
+
endpoint Create
|
359
|
+
@status
|
360
|
+
end
|
361
|
+
|
362
|
+
def update
|
363
|
+
endpoint :update
|
364
|
+
@status
|
90
365
|
end
|
91
366
|
end
|
367
|
+
|
368
|
+
|
369
|
+
it "what" do
|
370
|
+
RodaController.new.show.must_equal %{ControllerEndpointMethodTest::RodaController::Create}
|
371
|
+
RodaController.new.update.must_equal %{ControllerEndpointMethodTest::RodaController::Update}
|
372
|
+
end
|
92
373
|
end
|
374
|
+
|