trailblazer-endpoint 0.0.4 → 0.0.5
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 +6 -0
- data/Rakefile +7 -1
- data/gemfiles/rails_app.gemfile +12 -0
- data/lib/trailblazer/endpoint.rb +20 -5
- data/lib/trailblazer/endpoint/adapter.rb +30 -121
- data/lib/trailblazer/endpoint/builder.rb +1 -1
- data/lib/trailblazer/endpoint/controller.rb +203 -1
- data/lib/trailblazer/endpoint/dsl.rb +6 -3
- data/lib/trailblazer/endpoint/options.rb +13 -44
- data/lib/trailblazer/endpoint/protocol.rb +5 -8
- 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 +25 -0
- data/test/docs/controller_test.rb +160 -73
- 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 +11 -9
- data/test/rails-app/Gemfile.lock +137 -121
- 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/operation/create.rb +13 -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/controllers/api/v1/songs_controller.rb +35 -0
- data/test/rails-app/app/controllers/application_controller.rb +6 -1
- data/test/rails-app/app/controllers/application_controller/api.rb +105 -0
- data/test/rails-app/app/controllers/application_controller/web.rb +30 -0
- data/test/rails-app/app/controllers/songs_controller.rb +15 -17
- data/test/rails-app/app/models/song.rb +3 -0
- data/test/rails-app/app/models/user.rb +5 -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 +8 -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 +8 -3
- data/test/rails-app/db/schema.rb +15 -0
- data/test/rails-app/test/controllers/api_songs_controller_test.rb +83 -0
- data/test/rails-app/test/controllers/songs_controller_test.rb +36 -144
- data/test/rails-app/test/test_helper.rb +7 -1
- data/test/test_helper.rb +0 -2
- data/trailblazer-endpoint.gemspec +1 -0
- metadata +52 -21
- 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
@@ -2,7 +2,7 @@ module Trailblazer
|
|
2
2
|
class Endpoint
|
3
3
|
module DSL
|
4
4
|
# Run before the endpoint is invoked. This collects the blocks from the controller.
|
5
|
-
class Runtime < Struct.new(:
|
5
|
+
class Runtime < Struct.new(:options, :success_block, :failure_block, :protocol_failure_block)
|
6
6
|
|
7
7
|
def failure(&block)
|
8
8
|
self.failure_block = block
|
@@ -17,8 +17,11 @@ module Trailblazer
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# #call
|
20
|
-
def to_args
|
21
|
-
return
|
20
|
+
def to_args(default_block_options)
|
21
|
+
return options,
|
22
|
+
success_block: success_block || default_block_options[:success_block],
|
23
|
+
failure_block: failure_block || default_block_options[:failure_block],
|
24
|
+
protocol_failure_block: protocol_failure_block || default_block_options[:protocol_failure_block]
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
@@ -1,28 +1,7 @@
|
|
1
|
-
#
|
1
|
+
# DISCUSS: the generic inheritance/Options logic might be extracted to trailblazer-config or something.
|
2
|
+
# it is completely independent and could be helpful for many other configurations.
|
2
3
|
module Trailblazer
|
3
4
|
class Endpoint
|
4
|
-
def self.Normalizer(target:, options:)
|
5
|
-
normalizer = Class.new(Trailblazer::Activity::Railway) do
|
6
|
-
# inject an empty {} for all options.
|
7
|
-
# options.collect do |(method_name => option)|
|
8
|
-
# step Normalizer.DefaultToEmptyHash(config_name), id: :"default_#{config_name}"
|
9
|
-
# end
|
10
|
-
end
|
11
|
-
|
12
|
-
Normalizer::State.new(normalizer, options)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.Normalizer___(options, base_class: Trailblazer::Activity::Path)
|
16
|
-
normalizer = Class.new(base_class) do
|
17
|
-
# inject an empty {} for all options.
|
18
|
-
# options.collect do |(method_name => option)|
|
19
|
-
# step Normalizer.DefaultToEmptyHash(config_name), id: :"default_#{config_name}"
|
20
|
-
# end
|
21
|
-
end
|
22
|
-
|
23
|
-
Normalizer.add(normalizer, nil, options)
|
24
|
-
end
|
25
|
-
|
26
5
|
module Options
|
27
6
|
module DSL
|
28
7
|
def directive(directive_name, *callables, inherit: superclass)
|
@@ -35,6 +14,7 @@ module Trailblazer
|
|
35
14
|
@normalizers[directive_name] = Trailblazer::Endpoint::Normalizer.Options(directive_name, *callables, **options) # DISCUSS: allow multiple calls?
|
36
15
|
end
|
37
16
|
|
17
|
+
# Called in {Endpoint::Controller}.
|
38
18
|
def self.extended(extended) # TODO: let's hope this is only called once per hierachy :)
|
39
19
|
extended.instance_variable_set(:@normalizers, {})
|
40
20
|
end
|
@@ -49,7 +29,7 @@ module Trailblazer
|
|
49
29
|
end
|
50
30
|
|
51
31
|
def options_for(directive_name, runtime_options)
|
52
|
-
normalizer = @normalizers
|
32
|
+
normalizer = @normalizers.fetch(directive_name)
|
53
33
|
|
54
34
|
ctx = Trailblazer::Context(runtime_options, {})
|
55
35
|
|
@@ -59,7 +39,15 @@ module Trailblazer
|
|
59
39
|
_, options = ctx.decompose
|
60
40
|
options
|
61
41
|
end
|
62
|
-
|
42
|
+
|
43
|
+
|
44
|
+
# Merge {merged} into {hash}, but only keys that exist in {hash}.
|
45
|
+
def self.merge_with(merged, hash)
|
46
|
+
keys = hash.keys
|
47
|
+
merged = keys.collect { |key| merged.key?(key) ? [key, merged[key]] : nil }.compact.to_h
|
48
|
+
hash.merge(merged)
|
49
|
+
end
|
50
|
+
end # Options
|
63
51
|
|
64
52
|
module Normalizer
|
65
53
|
def self.Options(directive_name, *callables, base_class: Trailblazer::Activity::Path)
|
@@ -110,16 +98,6 @@ module Trailblazer
|
|
110
98
|
end
|
111
99
|
end
|
112
100
|
|
113
|
-
def self.CallDirectiveMethod(target, config_name)
|
114
|
-
->((ctx, flow_options), *) {
|
115
|
-
config = target.send(config_name, ctx, **ctx) # e.g. ApplicationController.options_for_endpoint
|
116
|
-
|
117
|
-
ctx[config_name] = ctx[config_name].merge(config)
|
118
|
-
|
119
|
-
return Trailblazer::Activity::Right, [ctx, flow_options]
|
120
|
-
}
|
121
|
-
end
|
122
|
-
|
123
101
|
def self.CallDirective(callable, option_name)
|
124
102
|
->((ctx, flow_options), *) {
|
125
103
|
config = callable.(ctx, **ctx) # e.g. ApplicationController.options_for_endpoint
|
@@ -133,14 +111,5 @@ module Trailblazer
|
|
133
111
|
}
|
134
112
|
end
|
135
113
|
end # Normalizer
|
136
|
-
|
137
|
-
module Controller
|
138
|
-
def self.extended(extended)
|
139
|
-
extended.extend Trailblazer::Endpoint::Options::DSL
|
140
|
-
extended.extend Trailblazer::Endpoint::Options::DSL::Inherit
|
141
|
-
extended.extend Trailblazer::Endpoint::Options
|
142
|
-
end
|
143
|
-
end # Controller
|
144
|
-
|
145
114
|
end
|
146
115
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "trailblazer/activity/dsl/linear"
|
2
|
+
|
1
3
|
module Trailblazer
|
2
4
|
class Endpoint
|
3
5
|
# The {Protocol} implements auth*, and calls the domain OP/WF.
|
@@ -16,13 +18,8 @@ module Trailblazer
|
|
16
18
|
class Noop < Trailblazer::Activity::Railway
|
17
19
|
end
|
18
20
|
|
19
|
-
class Failure < Trailblazer::Activity::End # DISCUSS: move to Act::Railway?
|
20
|
-
# class Authentication < Failure
|
21
|
-
# end
|
22
|
-
end
|
23
|
-
|
24
21
|
def self._Path(semantic:, &block) # DISCUSS: the problem with Path currently is https://github.com/trailblazer/trailblazer-activity-dsl-linear/issues/27
|
25
|
-
Path(track_color: semantic, end_id: "End.#{semantic}", end_task:
|
22
|
+
Path(track_color: semantic, end_id: "End.#{semantic}", end_task: Activity::End.new(semantic: semantic), &block)
|
26
23
|
end
|
27
24
|
|
28
25
|
step :authenticate, Output(:failure) => _Path(semantic: :not_authenticated) do
|
@@ -43,8 +40,8 @@ module Trailblazer
|
|
43
40
|
# termini for the Adapter this is the only way to get it working right now.
|
44
41
|
# FIXME: is this really the only way to add an {End} to all this?
|
45
42
|
@state.update_sequence do |sequence:, **|
|
46
|
-
sequence = Activity::Path::DSL.append_end(sequence, task:
|
47
|
-
sequence = Activity::Path::DSL.append_end(sequence, task:
|
43
|
+
sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :not_found), magnetic_to: :not_found, id: "End.not_found")
|
44
|
+
sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :invalid_data), magnetic_to: :invalid_data, id: "End.invalid_data")
|
48
45
|
|
49
46
|
recompile_activity!(sequence)
|
50
47
|
|
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
CHANGED
@@ -17,12 +17,22 @@ class ConfigTest < Minitest::Spec
|
|
17
17
|
ApeBabeController.options_for(:options_for_endpoint, {}).inspect.must_equal %{{:find_process_model=>true, :request=>true}}
|
18
18
|
ApeBabeController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:current_user=>\"Yo\"}}
|
19
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
|
+
|
20
24
|
BoringController.options_for(:options_for_endpoint, {}).inspect.must_equal %{{:find_process_model=>true, :request=>true, :xml=>"<XML"}}
|
21
25
|
BoringController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:policy=>\"Ehm\"}}
|
22
26
|
|
23
27
|
OverridingController.options_for(:options_for_domain_ctx, {}).inspect.must_equal %{{:redis=>\"Arrr\"}}
|
24
28
|
end
|
25
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
|
+
|
26
36
|
class ApplicationController
|
27
37
|
def self.options_for_endpoint(ctx, **)
|
28
38
|
{
|
@@ -58,6 +68,10 @@ class ConfigTest < Minitest::Spec
|
|
58
68
|
# directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
59
69
|
end
|
60
70
|
|
71
|
+
class ApeBabeKidController < ApeController
|
72
|
+
|
73
|
+
end
|
74
|
+
|
61
75
|
class BoringController < ApplicationController
|
62
76
|
def self.options_for_domain_ctx(ctx, **) {policy: "Ehm",} end
|
63
77
|
def self.options_for_endpoint(ctx, **) {xml: "<XML",} end
|
@@ -101,3 +115,14 @@ class RuntimeOptionsTest < Minitest::Spec
|
|
101
115
|
ApplicationController.options_for(:options_for_endpoint, controller: {params: {id: 1}}).inspect.must_equal %{{:option=>nil, :params=>{:id=>1}, :my_params=>\"{:id=>1}\"}}
|
102
116
|
end
|
103
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,11 +1,11 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class DocsControllerTest < Minitest::Spec
|
4
|
-
|
5
4
|
class ApplicationController
|
6
|
-
def self.options_for_endpoint(ctx, **)
|
5
|
+
def self.options_for_endpoint(ctx, controller:, **)
|
7
6
|
{
|
8
7
|
find_process_model: true,
|
8
|
+
**controller.instance_variable_get(:@params)[:params],
|
9
9
|
}
|
10
10
|
end
|
11
11
|
|
@@ -15,30 +15,52 @@ class DocsControllerTest < Minitest::Spec
|
|
15
15
|
}
|
16
16
|
end
|
17
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
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
|
18
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
|
+
|
19
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)
|
20
43
|
|
21
|
-
def process(action_name, params
|
44
|
+
def process(action_name, **params)
|
22
45
|
@params = params
|
23
|
-
|
46
|
+
send_action(action_name)
|
47
|
+
@render
|
24
48
|
end
|
25
49
|
|
26
50
|
def render(text)
|
27
51
|
@render = text
|
28
52
|
end
|
29
|
-
end
|
30
53
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
Protocol = Class.new(Trailblazer::Endpoint::Protocol) do
|
58
|
+
include T.def_steps(:authenticate, :policy)
|
36
59
|
end
|
37
60
|
|
38
|
-
|
61
|
+
endpoint protocol: Protocol, adapter: Trailblazer::Endpoint::Adapter::Web, domain_ctx_filter: Trailblazer::Endpoint.domain_ctx_filter([:current_user, :process_model]), scope_domain_ctx: true
|
39
62
|
end
|
40
63
|
|
41
|
-
|
42
64
|
class HtmlController < ApplicationController
|
43
65
|
private def endpoint_for(*)
|
44
66
|
protocol = Class.new(Trailblazer::Endpoint::Protocol) do
|
@@ -50,46 +72,31 @@ class DocsControllerTest < Minitest::Spec
|
|
50
72
|
domain_activity: Minitest::Spec.new(nil).activity, # FIXME
|
51
73
|
protocol: protocol,
|
52
74
|
adapter: Trailblazer::Endpoint::Adapter::Web,
|
53
|
-
scope_domain_ctx:
|
75
|
+
scope_domain_ctx: true,
|
54
76
|
|
55
77
|
) do
|
56
78
|
{Output(:not_found) => Track(:not_found)}
|
57
79
|
end
|
58
80
|
end
|
59
81
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
ctx = Trailblazer::Endpoint.advance_from_controller(
|
64
|
-
|
65
|
-
endpoint,
|
66
|
-
|
67
|
-
# retrieve/compute options_for_domain_ctx and options_for_endpoint
|
68
|
-
|
69
|
-
domain_ctx: {seq: seq=[], current_user: "Yo", **@params},
|
70
|
-
flow_options: {},
|
71
|
-
|
72
|
-
**options,
|
73
|
-
|
74
|
-
seq: seq,
|
82
|
+
def self.options_for_domain_ctx(ctx, seq:, controller:, **)
|
83
|
+
{
|
75
84
|
current_user: "Yo",
|
76
|
-
|
77
|
-
|
85
|
+
seq: seq,
|
86
|
+
**controller.instance_variable_get(:@params)[:params],
|
87
|
+
}
|
78
88
|
end
|
79
89
|
|
80
|
-
|
81
|
-
success_block = ->(ctx, seq:, **) { render seq << :success_block }
|
82
|
-
failure_block = ->(ctx, seq:, **) { render seq << :failure_block }
|
83
|
-
protocol_failure_block = ->(ctx, seq:, **) { render seq << :protocol_failure_block }
|
90
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
84
91
|
|
85
|
-
|
92
|
+
private def _endpoint(action, seq: [], &block)
|
93
|
+
endpoint(action, seq: seq, &block)
|
86
94
|
end
|
87
95
|
|
88
96
|
# all standard routes are user-defined
|
89
97
|
def view
|
90
98
|
_endpoint "view?" do |ctx, seq:, **|
|
91
99
|
render "success" + ctx[:current_user] + seq.inspect
|
92
|
-
|
93
100
|
end.failure do |ctx, seq:, **|
|
94
101
|
render "failure" + ctx[:current_user] + seq.inspect
|
95
102
|
|
@@ -114,16 +121,6 @@ class DocsControllerTest < Minitest::Spec
|
|
114
121
|
end
|
115
122
|
end
|
116
123
|
|
117
|
-
def process(*)
|
118
|
-
dsl = super
|
119
|
-
|
120
|
-
options, block_options = dsl.to_args
|
121
|
-
|
122
|
-
advance_endpoint(**options, **block_options)
|
123
|
-
|
124
|
-
@render
|
125
|
-
end
|
126
|
-
|
127
124
|
end # HtmlController
|
128
125
|
|
129
126
|
it "what" do
|
@@ -171,57 +168,147 @@ class DocsControllerTest < Minitest::Spec
|
|
171
168
|
# from controller-default
|
172
169
|
controller.process(:update, params: {authenticate: false}).must_equal [:authenticate, :protocol_failure_block]
|
173
170
|
end
|
174
|
-
end
|
175
171
|
|
176
|
-
class ControllerOptionsTest < Minitest::Spec
|
177
|
-
class Controller
|
178
|
-
include Trailblazer::Endpoint::Controller
|
179
172
|
|
180
|
-
|
181
|
-
|
173
|
+
# Test if {domain_ctx} is automatically wrapped via Context() so that we can use string-keys.
|
174
|
+
# TODO: test if aliases etc are properly passed.
|
175
|
+
class OptionsController < HtmlController
|
176
|
+
def self.options_for_domain_ctx(ctx, seq:, controller:, **)
|
177
|
+
{
|
178
|
+
"contract.params" => Object, # string-key should usually break if not wrapped
|
179
|
+
}
|
182
180
|
end
|
183
181
|
|
184
|
-
|
185
|
-
|
186
|
-
|
182
|
+
def self.options_for_endpoint(ctx, controller:, **)
|
183
|
+
{
|
184
|
+
current_user: "Yogi",
|
185
|
+
process_model: Class,
|
186
|
+
}
|
187
187
|
end
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
189
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
190
|
+
directive :options_for_endpoint, method(:options_for_endpoint), inherit: false
|
191
|
+
|
192
|
+
def view
|
193
|
+
_endpoint "view?" do |ctx, seq:, **|
|
194
|
+
render "success" + ctx["contract.params"].to_s + seq.inspect
|
195
|
+
end
|
192
196
|
end
|
197
|
+
end # OptionsController
|
198
|
+
|
199
|
+
it "allows string keys in {domain_ctx} since it gets automatically Ctx()-wrapped" do
|
200
|
+
controller = OptionsController.new
|
201
|
+
controller.process(:view, params: {}).must_equal %{successObject[:authenticate, :policy, :model, :validate]}
|
193
202
|
end
|
194
203
|
|
195
|
-
class ControllerThatDoesntInherit
|
196
|
-
include Trailblazer::Endpoint::Controller
|
197
204
|
|
198
|
-
|
205
|
+
# copy from {endpoint_ctx} to {domain_ctx}
|
206
|
+
class DomainContextController < ApplicationController
|
207
|
+
private def _endpoint(action, seq: [], **options, &block)
|
208
|
+
endpoint(action, seq: seq, **options, &block)
|
209
|
+
end
|
210
|
+
|
211
|
+
Activity = Class.new(Trailblazer::Activity::Railway) do
|
212
|
+
step :check
|
213
|
+
|
214
|
+
def check(ctx, current_user:, seq:, process_model:, **)
|
215
|
+
seq << :check
|
216
|
+
ctx[:message] = "#{current_user} / #{process_model}"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
endpoint "view?", domain_activity: Activity
|
221
|
+
endpoint "show?", domain_activity: Activity
|
222
|
+
|
223
|
+
|
224
|
+
def self.options_for_domain_ctx(ctx, seq:, controller:, **)
|
199
225
|
{
|
200
|
-
|
226
|
+
seq: seq,
|
201
227
|
}
|
202
228
|
end
|
203
229
|
|
204
|
-
def options_for_endpoint
|
205
|
-
|
230
|
+
def self.options_for_endpoint(ctx, controller:, **)
|
231
|
+
{
|
232
|
+
current_user: "Yogi",
|
233
|
+
process_model: Class,
|
234
|
+
something: true,
|
235
|
+
}
|
206
236
|
end
|
207
237
|
|
238
|
+
directive :options_for_domain_ctx, method(:options_for_domain_ctx)
|
239
|
+
directive :options_for_endpoint, method(:options_for_endpoint), inherit: false
|
240
|
+
|
208
241
|
def view
|
209
|
-
|
242
|
+
_endpoint "view?" do |ctx, seq:, **|
|
243
|
+
render "success" + ctx[:message].to_s + seq.inspect
|
244
|
+
end
|
210
245
|
end
|
211
246
|
|
212
|
-
|
213
|
-
|
214
|
-
|
247
|
+
def show
|
248
|
+
# override existing domain_ctx
|
249
|
+
# make options here available in steps
|
250
|
+
_endpoint "show?", options_for_domain_ctx: {params: {id: 1}, seq: []} do |ctx, seq:, params:, **|
|
251
|
+
render "success" + ctx[:message].to_s + seq.inspect + params.inspect
|
252
|
+
end
|
215
253
|
end
|
216
254
|
|
217
|
-
|
218
|
-
|
219
|
-
|
255
|
+
def create
|
256
|
+
# add endpoint_options
|
257
|
+
_endpoint "show?", policy: false do |ctx, seq:, params:, **|
|
258
|
+
render "success" + ctx[:message].to_s + seq.inspect + params.inspect
|
259
|
+
end
|
220
260
|
end
|
261
|
+
|
262
|
+
# todo: test overriding endp options
|
263
|
+
# _endpoint "show?", params: {id: 1}, process_model: "it's me!" do |ctx, seq:, params:, process_model:, **|
|
264
|
+
end # DomainContextController
|
265
|
+
|
266
|
+
it "{:current_user} and {:process_model} are made available in {domain_ctx}" do
|
267
|
+
controller = DomainContextController.new
|
268
|
+
controller.process(:view, params: {}).must_equal %{successYogi / Class[:authenticate, :policy, :check]}
|
269
|
+
end
|
270
|
+
|
271
|
+
it "{:seq} is overridden, {:params} made available, in {domain_ctx}" do
|
272
|
+
controller = DomainContextController.new
|
273
|
+
# note that {seq} is not shared anymore
|
274
|
+
controller.process(:show, params: {}).must_equal %{successYogi / Class[:check]{:id=>1}}
|
221
275
|
end
|
222
276
|
|
223
|
-
it "allows
|
224
|
-
|
277
|
+
it "allows passing {endpoint_options} directly" do
|
278
|
+
controller = DomainContextController.new
|
279
|
+
controller.process(:create, params: {}).must_equal [:authenticate, :policy, :protocol_failure_block]
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
# Test without DSL
|
284
|
+
class BasicController
|
285
|
+
extend Trailblazer::Endpoint::Controller
|
286
|
+
|
287
|
+
directive :options_for_block_options, Trailblazer::Endpoint::Controller.method(:options_for_block_options)
|
288
|
+
|
289
|
+
def endpoint(name, &block)
|
290
|
+
action_options = {seq: []}
|
291
|
+
|
292
|
+
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)
|
293
|
+
end
|
294
|
+
|
295
|
+
def head(status)
|
296
|
+
@status = status
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
class RodaController < BasicController
|
301
|
+
endpoint("show?", protocol: ApplicationController::Protocol, adapter: Trailblazer::Endpoint::Adapter::Web, domain_activity: Class.new(Trailblazer::Activity::Railway) { def save(*); true; end; step :save })
|
302
|
+
|
303
|
+
def show
|
304
|
+
endpoint "show?"
|
305
|
+
@status
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
it "what" do
|
310
|
+
RodaController.new.show.must_equal 200
|
225
311
|
end
|
226
312
|
end
|
227
313
|
|
314
|
+
|