coach 2.3.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +49 -53
- data/.github/dependabot.yml +7 -0
- data/.rubocop.yml +4 -1
- data/.ruby-version +1 -0
- data/CHANGELOG.md +12 -0
- data/README.md +40 -5
- data/coach.gemspec +3 -2
- data/lib/coach/handler.rb +46 -34
- data/lib/coach/request_serializer.rb +1 -1
- data/lib/coach/router.rb +18 -7
- data/lib/coach/rspec.rb +1 -1
- data/lib/coach/version.rb +1 -1
- data/spec/lib/coach/handler_spec.rb +50 -2
- data/spec/lib/coach/router_spec.rb +23 -7
- data/spec/spec_helper.rb +4 -0
- data/spec/support/routes.rb +41 -0
- metadata +30 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9fbde870cfebdaad825256983d4ef36b9b413e9f22495a16ba09be11ff17f61b
|
4
|
+
data.tar.gz: ddb38d9c732b21937cd5a9f6ad7c3693531d8973b49939250771b251976054ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eac833c21c43ba291a7e68506d1378d22b64dbc2aeeb2899f02db9ae68b6a9390e7231598ed4197465807f5958decfd3403c02db01526f48d8978366ae279d2d
|
7
|
+
data.tar.gz: 8a4b8dbd37680569451d321219e3b157fc202d72a368e9855b477997c8fc42f17a026ca7fe1ce445766f8af55a77f79d1e8a81b1384855b954de15b463e38bf0
|
data/.circleci/config.yml
CHANGED
@@ -1,68 +1,64 @@
|
|
1
|
-
|
1
|
+
---
|
2
|
+
version: 2.1
|
2
3
|
|
3
4
|
references:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
- run: gem install bundler -v 1.11.2
|
15
|
-
|
16
|
-
- run: bundle install --path vendor/bundle
|
5
|
+
bundle_install: &bundle_install
|
6
|
+
run:
|
7
|
+
name: Bundle
|
8
|
+
command: |
|
9
|
+
gem install bundler --no-document && \
|
10
|
+
bundle config set no-cache 'true' && \
|
11
|
+
bundle config set jobs '4' && \
|
12
|
+
bundle config set retry '3' && \
|
13
|
+
bundle install
|
17
14
|
|
18
|
-
|
19
|
-
|
15
|
+
cache_bundle: &cache_bundle
|
16
|
+
save_cache:
|
17
|
+
key: bundle-<< parameters.ruby_version >>-<< parameters.rails_version >>-{{ checksum "coach.gemspec" }}-{{ checksum "Gemfile" }}
|
20
18
|
paths:
|
21
19
|
- vendor/bundle
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
--format RspecJunitFormatter \
|
27
|
-
--out /tmp/test-results/rspec.xml \
|
28
|
-
--format progress \
|
29
|
-
spec
|
30
|
-
|
31
|
-
- type: store_test_results
|
32
|
-
path: /tmp/test-results
|
21
|
+
restore_bundle: &restore_bundle
|
22
|
+
restore_cache:
|
23
|
+
key: bundle-<< parameters.ruby_version >>-<< parameters.rails_version >>-{{ checksum "coach.gemspec" }}-{{ checksum "Gemfile" }}
|
33
24
|
|
34
|
-
- run: bundle exec rubocop
|
35
25
|
jobs:
|
36
|
-
|
26
|
+
rspec:
|
27
|
+
working_directory: /mnt/ramdisk
|
28
|
+
parameters:
|
29
|
+
ruby_version:
|
30
|
+
type: string
|
31
|
+
rails_version:
|
32
|
+
type: string
|
37
33
|
docker:
|
38
|
-
- image: ruby
|
34
|
+
- image: cimg/ruby:<< parameters.ruby_version >>
|
39
35
|
environment:
|
40
|
-
|
41
|
-
steps:
|
42
|
-
|
43
|
-
|
44
|
-
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
-
|
57
|
-
|
58
|
-
- RAILS_VERSION=4.2.10
|
59
|
-
steps: *steps
|
36
|
+
CIRCLE_TEST_REPORTS: /tmp/circle_artifacts/
|
37
|
+
steps:
|
38
|
+
- add_ssh_keys
|
39
|
+
- checkout
|
40
|
+
- *restore_bundle
|
41
|
+
- *bundle_install
|
42
|
+
- *cache_bundle
|
43
|
+
- run:
|
44
|
+
name: Run specs
|
45
|
+
command: |
|
46
|
+
bundle exec rspec $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) --profile --format progress --format RspecJunitFormatter -o /tmp/circle_artifacts/rspec.xml
|
47
|
+
- run:
|
48
|
+
name: "Rubocop"
|
49
|
+
command: bundle exec rubocop --extra-details --display-style-guide --parallel --force-exclusion
|
50
|
+
- store_artifacts:
|
51
|
+
path: /tmp/circle_artifacts/
|
52
|
+
- store_test_results:
|
53
|
+
path: /tmp/circle_artifacts/
|
60
54
|
|
61
55
|
workflows:
|
62
56
|
version: 2
|
63
57
|
tests:
|
64
58
|
jobs:
|
65
|
-
-
|
66
|
-
|
67
|
-
|
68
|
-
|
59
|
+
- rspec:
|
60
|
+
matrix:
|
61
|
+
parameters:
|
62
|
+
ruby_version: ["2.6", "2.7", "3.0"]
|
63
|
+
rails_version: ["5.2.6", "6.0.4", "6.1.4"]
|
64
|
+
|
data/.rubocop.yml
CHANGED
@@ -4,7 +4,7 @@ inherit_gem:
|
|
4
4
|
gc_ruboconfig: rubocop.yml
|
5
5
|
|
6
6
|
AllCops:
|
7
|
-
TargetRubyVersion:
|
7
|
+
TargetRubyVersion: 3.0
|
8
8
|
|
9
9
|
Metrics/MethodLength:
|
10
10
|
Max: 15
|
@@ -26,3 +26,6 @@ Naming/MethodParameterName:
|
|
26
26
|
# These are some custom names that we want to allow, since they aren't
|
27
27
|
# uncommunicative - they're actually rather meaningful!
|
28
28
|
- as
|
29
|
+
|
30
|
+
Gemspec/RequiredRubyVersion:
|
31
|
+
Enabled: False
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.2
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
|
3
3
|
# Unreleased
|
4
4
|
|
5
|
+
# 3.0.0 / 2021-09-09
|
6
|
+
|
7
|
+
* [#105](https://github.com/gocardless/coach/pull/105) Add support for module/class names to be
|
8
|
+
passed to `Handler.new` and `Router#draw` to allow routes to be defined without loading the routes
|
9
|
+
constants, which makes using Zeitwerk much easier.
|
10
|
+
|
11
|
+
* Add Ruby 3 support
|
12
|
+
|
13
|
+
## Breaking changes
|
14
|
+
|
15
|
+
* Remove Ruby 2.4 and 2.5 support
|
16
|
+
|
5
17
|
# 2.3.0 / 2020-04-29
|
6
18
|
|
7
19
|
* [#90](https://github.com/gocardless/coach/pull/90) Instrument status `0` instead of `500` when Coach::Handler catches an exception
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ To get started, just add Coach to your `Gemfile`, and then run `bundle`:
|
|
23
23
|
gem 'coach'
|
24
24
|
```
|
25
25
|
|
26
|
-
Coach works with Ruby versions 2.
|
26
|
+
Coach works with Ruby versions 2.6 and onwards.
|
27
27
|
|
28
28
|
## Coach by example
|
29
29
|
|
@@ -59,6 +59,21 @@ Once you've booted Rails locally, the following should return `'hello world'`:
|
|
59
59
|
$ curl -XGET http://localhost:3000/hello_world
|
60
60
|
```
|
61
61
|
|
62
|
+
### Zeitwerk
|
63
|
+
|
64
|
+
The new default autoloader in Rails 6+ is [Zeitwerk](https://github.com/fxn/zeitwerk), which removes
|
65
|
+
support for autoloading constants during app boot, which that example would do - either you have to
|
66
|
+
`require "hello_world"` in your routes file, or avoid referencing the `HelloWorld` constant until
|
67
|
+
the app has booted. To avoid that, you can instead pass the module or middleware _name_ to
|
68
|
+
`Handler.new`, for example:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
Example::Application.routes.draw do
|
72
|
+
match "/hello_world",
|
73
|
+
to: Coach::Handler.new("HelloWorld"),
|
74
|
+
via: :get
|
75
|
+
```
|
76
|
+
|
62
77
|
### Building chains
|
63
78
|
|
64
79
|
Suppose we didn't want just anybody to see our `HelloWorld` endpoint. In fact, we'd like
|
@@ -136,14 +151,15 @@ end
|
|
136
151
|
# Inside config/routes.rb
|
137
152
|
Example::Application.routes.draw do
|
138
153
|
match "/hello_user",
|
139
|
-
to: Coach::Handler.new(HelloUser),
|
154
|
+
to: Coach::Handler.new("HelloUser"),
|
140
155
|
via: :get
|
141
156
|
end
|
142
157
|
```
|
143
158
|
|
144
|
-
Coach analyses your middleware chains whenever a new `Handler` is created
|
145
|
-
|
146
|
-
|
159
|
+
Coach analyses your middleware chains whenever a new `Handler` is created, or when the handler is
|
160
|
+
first used if the route is being lazy-loaded (i.e., if you're passing a string name, instead of the
|
161
|
+
route itself). If any middleware `requires :x` when its chain does not provide `:x`, we'll error out
|
162
|
+
before the app even starts with the error:
|
147
163
|
|
148
164
|
```ruby
|
149
165
|
Coach::Errors::MiddlewareDependencyNotMet: HelloUser requires keys [user] that are not provided by the middleware chain
|
@@ -270,6 +286,25 @@ users resource being mapped to:
|
|
270
286
|
| `PUT` | `/users/:id` | Update user details |
|
271
287
|
| `POST` | `/users/:id/actions/disable` | Custom action routed to the given path suffix |
|
272
288
|
|
289
|
+
If you're using Zeitwerk, you can pass the name of the module to `#draw`, instead of the module
|
290
|
+
itself.
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
# config/routes.rb
|
294
|
+
Example::Application.routes.draw do
|
295
|
+
router = Coach::Router.new(self)
|
296
|
+
router.draw("Routes::Users",
|
297
|
+
base: "/users",
|
298
|
+
actions: [
|
299
|
+
:index,
|
300
|
+
:show,
|
301
|
+
:create,
|
302
|
+
:update,
|
303
|
+
disable: { method: :post, url: "/:id/actions/disable" }
|
304
|
+
])
|
305
|
+
end
|
306
|
+
```
|
307
|
+
|
273
308
|
## Rendering
|
274
309
|
|
275
310
|
By now you'll probably agree that the rack response format isn't the nicest way to render
|
data/coach.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.homepage = "https://github.com/gocardless/coach"
|
13
13
|
spec.email = %w[developers@gocardless.com]
|
14
14
|
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = ">= 2.
|
15
|
+
spec.required_ruby_version = ">= 2.6"
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0")
|
18
18
|
spec.test_files = spec.files.grep(%r{^spec/})
|
@@ -23,9 +23,10 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency "activesupport", ">= 4.2"
|
24
24
|
spec.add_dependency "commander", "~> 4.5"
|
25
25
|
|
26
|
-
spec.add_development_dependency "gc_ruboconfig", "
|
26
|
+
spec.add_development_dependency "gc_ruboconfig", "~> 2.18.0"
|
27
27
|
spec.add_development_dependency "pry", "~> 0.10"
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.2"
|
29
29
|
spec.add_development_dependency "rspec-its", "~> 1.2"
|
30
30
|
spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.0"
|
31
|
+
spec.add_development_dependency "rubocop", "~> 1.12"
|
31
32
|
end
|
data/lib/coach/handler.rb
CHANGED
@@ -7,17 +7,20 @@ module Coach
|
|
7
7
|
class Handler
|
8
8
|
STATUS_CODE_FOR_EXCEPTIONS = 0
|
9
9
|
|
10
|
+
attr_reader :name
|
11
|
+
|
10
12
|
def initialize(middleware, config = {})
|
11
|
-
@
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
@config = config
|
14
|
+
if middleware.is_a?(String)
|
15
|
+
@name = middleware
|
16
|
+
else
|
17
|
+
@middleware = middleware
|
18
|
+
@name = middleware.name
|
19
|
+
# This triggers validation of the middleware chain, to raise any errors early on.
|
20
|
+
root_item
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
|
-
# Run validation on the root of the middleware chain
|
20
|
-
delegate :validate!, to: :@root_item
|
21
24
|
delegate :publish, :instrument, :notifier, to: ActiveSupport::Notifications
|
22
25
|
|
23
26
|
# The Rack interface to handler - builds a middleware chain based on
|
@@ -25,33 +28,31 @@ module Coach
|
|
25
28
|
# rubocop:disable Metrics/MethodLength
|
26
29
|
def call(env)
|
27
30
|
context = { request: ActionDispatch::Request.new(env) }
|
28
|
-
sequence = build_sequence(
|
31
|
+
sequence = build_sequence(root_item, context)
|
29
32
|
chain = build_request_chain(sequence, context)
|
30
33
|
|
31
34
|
event = build_event(context)
|
32
35
|
|
33
36
|
publish("start_handler.coach", event.dup)
|
34
37
|
instrument("finish_handler.coach", event) do
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
)
|
54
|
-
end
|
38
|
+
response = chain.instrument.call
|
39
|
+
rescue StandardError => e
|
40
|
+
raise
|
41
|
+
ensure
|
42
|
+
# We want to populate the response and metadata fields after the middleware
|
43
|
+
# chain has completed so that the end of the instrumentation can see them. The
|
44
|
+
# simplest way to do this is pass the event by reference to ActiveSupport, then
|
45
|
+
# modify the hash to contain this detail before the instrumentation completes.
|
46
|
+
#
|
47
|
+
# This way, the last finish_handler.coach event will have all the details.
|
48
|
+
status = response.try(:first) || STATUS_CODE_FOR_EXCEPTIONS
|
49
|
+
event.merge!(
|
50
|
+
response: {
|
51
|
+
status: status,
|
52
|
+
exception: e,
|
53
|
+
}.compact,
|
54
|
+
metadata: context.fetch(:_metadata, {}),
|
55
|
+
)
|
55
56
|
end
|
56
57
|
end
|
57
58
|
# rubocop:enable Metrics/MethodLength
|
@@ -76,11 +77,25 @@ module Coach
|
|
76
77
|
end
|
77
78
|
|
78
79
|
def inspect
|
79
|
-
"#<Coach::Handler[#{
|
80
|
+
"#<Coach::Handler[#{name}]>"
|
80
81
|
end
|
81
82
|
|
82
83
|
private
|
83
84
|
|
85
|
+
attr_reader :config
|
86
|
+
|
87
|
+
def root_item
|
88
|
+
@root_item ||= MiddlewareItem.new(middleware, config).tap(&:validate!)
|
89
|
+
rescue Coach::Errors::MiddlewareDependencyNotMet => e
|
90
|
+
# Remove noise of validation stack trace, reset to the handler callsite
|
91
|
+
e.backtrace.clear.concat(Thread.current.backtrace)
|
92
|
+
raise e
|
93
|
+
end
|
94
|
+
|
95
|
+
def middleware
|
96
|
+
@middleware ||= ActiveSupport::Dependencies.constantize(name)
|
97
|
+
end
|
98
|
+
|
84
99
|
# Remove middleware that have been included multiple times with the same
|
85
100
|
# config, leaving only the first instance
|
86
101
|
def dedup_sequence(sequence)
|
@@ -89,10 +104,7 @@ module Coach
|
|
89
104
|
|
90
105
|
# Event to send with notifications
|
91
106
|
def build_event(context)
|
92
|
-
{
|
93
|
-
middleware: @root_item.middleware.name,
|
94
|
-
request: context[:request],
|
95
|
-
}
|
107
|
+
{ middleware: name, request: context[:request] }
|
96
108
|
end
|
97
109
|
end
|
98
110
|
end
|
data/lib/coach/router.rb
CHANGED
@@ -17,14 +17,11 @@ module Coach
|
|
17
17
|
@mapper = mapper
|
18
18
|
end
|
19
19
|
|
20
|
-
def draw(
|
20
|
+
def draw(namespace, base: nil, as: nil, constraints: nil, actions: [])
|
21
21
|
action_traits(actions).each do |action, traits|
|
22
|
-
|
23
|
-
# match is found. Without this, globally defined constants such as
|
24
|
-
# `Process` will be picked up before consts that need to be autoloaded.
|
25
|
-
route = routes.const_get(camel(action), false)
|
22
|
+
handler = build_handler(namespace, action)
|
26
23
|
match(action_url(base, traits),
|
27
|
-
to:
|
24
|
+
to: handler,
|
28
25
|
via: traits[:method],
|
29
26
|
as: as,
|
30
27
|
constraints: constraints)
|
@@ -37,6 +34,20 @@ module Coach
|
|
37
34
|
|
38
35
|
private
|
39
36
|
|
37
|
+
def build_handler(namespace, action)
|
38
|
+
action_name = camel(action)
|
39
|
+
|
40
|
+
if namespace.is_a?(String)
|
41
|
+
route_name = "#{namespace}::#{action_name}"
|
42
|
+
Handler.new(route_name)
|
43
|
+
else
|
44
|
+
# Passing false to const_get prevents it searching ancestors until a
|
45
|
+
# match is found. Without this, globally defined constants such as
|
46
|
+
# `Process` will be picked up before consts that need to be autoloaded.
|
47
|
+
Handler.new(namespace.const_get(action_name, false))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
40
51
|
# Receives an array of symbols that represent actions for which the default traits
|
41
52
|
# should be used, and then lastly an optional trait configuration.
|
42
53
|
#
|
@@ -60,7 +71,7 @@ module Coach
|
|
60
71
|
|
61
72
|
# Applies trait url to base, removing duplicate /'s
|
62
73
|
def action_url(base, traits)
|
63
|
-
[base, traits[:url]].compact.join("/").
|
74
|
+
[base, traits[:url]].compact.join("/").squeeze("/")
|
64
75
|
end
|
65
76
|
|
66
77
|
# Turns a snake_case string/symbol into a CamelCase
|
data/lib/coach/rspec.rb
CHANGED
data/lib/coach/version.rb
CHANGED
@@ -20,8 +20,8 @@ describe Coach::Handler do
|
|
20
20
|
|
21
21
|
describe "#call" do
|
22
22
|
context "with multiple middleware" do
|
23
|
-
let(:a_double) { double }
|
24
|
-
let(:b_double) { double }
|
23
|
+
let(:a_double) { double.as_null_object }
|
24
|
+
let(:b_double) { double.as_null_object }
|
25
25
|
|
26
26
|
before do
|
27
27
|
terminal_middleware.uses(middleware_a, callback: a_double)
|
@@ -34,6 +34,54 @@ describe Coach::Handler do
|
|
34
34
|
result = handler.call({})
|
35
35
|
expect(result).to eq(%w[A{} B{} Terminal{:handler=>true}])
|
36
36
|
end
|
37
|
+
|
38
|
+
context "with an invalid chain" do
|
39
|
+
before { terminal_middleware.requires(:not_available) }
|
40
|
+
|
41
|
+
it "raises an error" do
|
42
|
+
expect { handler }.to raise_error(Coach::Errors::MiddlewareDependencyNotMet)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "lazy-loading the middleware" do
|
47
|
+
subject(:handler) { described_class.new(terminal_middleware.name, handler: true) }
|
48
|
+
|
49
|
+
before do
|
50
|
+
allow(ActiveSupport::Dependencies).to receive(:constantize).and_call_original
|
51
|
+
allow(ActiveSupport::Dependencies).to receive(:constantize).
|
52
|
+
with(terminal_middleware.name).
|
53
|
+
and_return(terminal_middleware)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "does not load the route when initialized" do
|
57
|
+
expect(ActiveSupport::Dependencies).
|
58
|
+
to_not receive(:constantize).with(terminal_middleware.name)
|
59
|
+
|
60
|
+
handler
|
61
|
+
end
|
62
|
+
|
63
|
+
it "calls through the middleware chain" do
|
64
|
+
expect(a_double).to receive(:call)
|
65
|
+
expect(b_double).to receive(:call)
|
66
|
+
|
67
|
+
result = handler.call({})
|
68
|
+
|
69
|
+
expect(result).to eq(%w[A{} B{} Terminal{:handler=>true}])
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with an invalid chain" do
|
73
|
+
before { terminal_middleware.requires(:not_available) }
|
74
|
+
|
75
|
+
it "does not raise on initialize" do
|
76
|
+
expect { handler }.to_not raise_error
|
77
|
+
end
|
78
|
+
|
79
|
+
it "raises on first call" do
|
80
|
+
expect { handler.call({}) }.
|
81
|
+
to raise_error(Coach::Errors::MiddlewareDependencyNotMet)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
37
85
|
end
|
38
86
|
|
39
87
|
describe "notifications" do
|
@@ -10,13 +10,8 @@ describe Coach::Router do
|
|
10
10
|
|
11
11
|
let(:mapper) { instance_double("ActionDispatch::Routing::Mapper") }
|
12
12
|
|
13
|
-
let(:
|
14
|
-
|
15
|
-
%i[Index Show Create Update Destroy Refund].each do |class_name|
|
16
|
-
routes_module.const_set(class_name, Class.new)
|
17
|
-
end
|
18
|
-
routes_module
|
19
|
-
end
|
13
|
+
let(:routes) { %i[Index Show Create Update Destroy Refund] }
|
14
|
+
let(:resource_routes) { Routes::Thing }
|
20
15
|
|
21
16
|
before do
|
22
17
|
allow(Coach::Handler).to receive(:new) { |route| route }
|
@@ -84,6 +79,27 @@ describe Coach::Router do
|
|
84
79
|
it "raises NameError" do
|
85
80
|
expect { draw }.to raise_error(NameError)
|
86
81
|
end
|
82
|
+
|
83
|
+
context "when passing a string for the namespace" do
|
84
|
+
subject(:router) { described_class.new(mapper) }
|
85
|
+
|
86
|
+
let(:resource_routes) { Routes::Thing.name }
|
87
|
+
|
88
|
+
before do
|
89
|
+
allow(ActiveSupport::Dependencies).to receive(:constantize).and_call_original
|
90
|
+
|
91
|
+
routes.each do |class_name|
|
92
|
+
allow(ActiveSupport::Dependencies).to receive(:constantize).
|
93
|
+
with("Routes::Thing::#{class_name}").
|
94
|
+
and_return(Routes::Thing.const_get(class_name))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it "does not raise an error" do
|
99
|
+
expect(mapper).to receive(:match).with("/resource/:id/process", anything)
|
100
|
+
expect { draw }.to_not raise_error
|
101
|
+
end
|
102
|
+
end
|
87
103
|
end
|
88
104
|
end
|
89
105
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,6 +5,10 @@ require "pry"
|
|
5
5
|
require "coach"
|
6
6
|
require "coach/rspec"
|
7
7
|
|
8
|
+
Dir[Pathname(__FILE__).dirname.join("support", "**", "*.rb")].
|
9
|
+
sort.
|
10
|
+
each { |path| require path }
|
11
|
+
|
8
12
|
RSpec.configure do |config|
|
9
13
|
config.expect_with :rspec do |expectations|
|
10
14
|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Routes
|
4
|
+
module Thing
|
5
|
+
class Index < Coach::Middleware
|
6
|
+
def call
|
7
|
+
[200, {}, []]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Show < Coach::Middleware
|
12
|
+
def call
|
13
|
+
[200, {}, []]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Create < Coach::Middleware
|
18
|
+
def call
|
19
|
+
[200, {}, []]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Update < Coach::Middleware
|
24
|
+
def call
|
25
|
+
[200, {}, []]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Destroy < Coach::Middleware
|
30
|
+
def call
|
31
|
+
[200, {}, []]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Refund < Coach::Middleware
|
36
|
+
def call
|
37
|
+
[200, {}, []]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coach
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GoCardless
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: gc_ruboconfig
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.
|
61
|
+
version: 2.18.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 2.
|
68
|
+
version: 2.18.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,7 +122,21 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 0.4.0
|
125
|
-
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.12'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.12'
|
139
|
+
description:
|
126
140
|
email:
|
127
141
|
- developers@gocardless.com
|
128
142
|
executables:
|
@@ -131,10 +145,12 @@ extensions: []
|
|
131
145
|
extra_rdoc_files: []
|
132
146
|
files:
|
133
147
|
- ".circleci/config.yml"
|
148
|
+
- ".github/dependabot.yml"
|
134
149
|
- ".gitignore"
|
135
150
|
- ".rspec"
|
136
151
|
- ".rubocop.yml"
|
137
152
|
- ".rubocop_todo.yml"
|
153
|
+
- ".ruby-version"
|
138
154
|
- CHANGELOG.md
|
139
155
|
- Gemfile
|
140
156
|
- LICENSE.txt
|
@@ -166,11 +182,12 @@ files:
|
|
166
182
|
- spec/lib/coach/request_serializer_spec.rb
|
167
183
|
- spec/lib/coach/router_spec.rb
|
168
184
|
- spec/spec_helper.rb
|
185
|
+
- spec/support/routes.rb
|
169
186
|
homepage: https://github.com/gocardless/coach
|
170
187
|
licenses:
|
171
188
|
- MIT
|
172
189
|
metadata: {}
|
173
|
-
post_install_message:
|
190
|
+
post_install_message:
|
174
191
|
rdoc_options: []
|
175
192
|
require_paths:
|
176
193
|
- lib
|
@@ -178,15 +195,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
178
195
|
requirements:
|
179
196
|
- - ">="
|
180
197
|
- !ruby/object:Gem::Version
|
181
|
-
version: '2.
|
198
|
+
version: '2.6'
|
182
199
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
200
|
requirements:
|
184
201
|
- - ">="
|
185
202
|
- !ruby/object:Gem::Version
|
186
203
|
version: '0'
|
187
204
|
requirements: []
|
188
|
-
rubygems_version: 3.
|
189
|
-
signing_key:
|
205
|
+
rubygems_version: 3.2.22
|
206
|
+
signing_key:
|
190
207
|
specification_version: 4
|
191
208
|
summary: Alternative controllers built with middleware
|
192
209
|
test_files:
|
@@ -199,3 +216,4 @@ test_files:
|
|
199
216
|
- spec/lib/coach/request_serializer_spec.rb
|
200
217
|
- spec/lib/coach/router_spec.rb
|
201
218
|
- spec/spec_helper.rb
|
219
|
+
- spec/support/routes.rb
|