coach 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f4c3a75e36f5a68ae2833e84b8bc6ccc45acbde8a137644fad05960620ae1d9
4
- data.tar.gz: fcb6e844520cd5d19bcab21acc7b3e50b02708c3f750eb078dd52f844d09c3ae
3
+ metadata.gz: f314e7cc1779f326294cede2142167c325fd5182cc403b17dcdf2ffa4a0ab2f0
4
+ data.tar.gz: c29c7bc00999c22d65ed1da8268761ff1633f936e58e856dd9f2b3dad189ce80
5
5
  SHA512:
6
- metadata.gz: c98ecef9fe5dc20158a6285c8d7f0c4c7bf0c9d7e1529c5c4a8c639cbab57a1cd17f3a43164eaffbd33c81441203904b899d282bebb55b280c3e544c2c9d4284
7
- data.tar.gz: ef8d52b4fb9596707ee21f7e6908ed7bc2b47a242e7452b507e0c90efa84d5ce8b25b0f6b61a9722636d801b368c5318c06617ae796c65dfd619a599e461692c
6
+ metadata.gz: da2a45e51025660adc160604297d3614fea894b79b203be1ee8b337832281d59d4a4f8e3e4aa222209754251763cecced1e225a039921e9f8a979a2b741410e6
7
+ data.tar.gz: fc581d18446b2fbab925e49a4cb984d06d7112f1e90bde8dffb07ae124d0a061a9f6c107afd4addc1c8058ec5be503316d5a7437042b9d9c3ffbf602c6522af4
@@ -11,7 +11,7 @@ references:
11
11
  - type: cache-restore
12
12
  key: coach-bundler-{{ checksum "coach.gemspec" }}-{{ checksum "~/RAILS_VERSION.txt" }}
13
13
 
14
- - run: gem install bundler
14
+ - run: gem install bundler -v 1.11.2
15
15
 
16
16
  - run: bundle install --path vendor/bundle
17
17
 
@@ -33,30 +33,6 @@ references:
33
33
 
34
34
  - run: bundle exec rubocop
35
35
  jobs:
36
- build-ruby22-rails515:
37
- docker:
38
- - image: ruby:2.2
39
- environment:
40
- - RAILS_VERSION=5.1.5
41
- steps: *steps
42
- build-ruby22-rails4210:
43
- docker:
44
- - image: ruby:2.2
45
- environment:
46
- - RAILS_VERSION=4.2.10
47
- steps: *steps
48
- build-ruby23-rails515:
49
- docker:
50
- - image: ruby:2.3
51
- environment:
52
- - RAILS_VERSION=5.1.5
53
- steps: *steps
54
- build-ruby23-rails4210:
55
- docker:
56
- - image: ruby:2.3
57
- environment:
58
- - RAILS_VERSION=4.2.10
59
- steps: *steps
60
36
  build-ruby24-rails515:
61
37
  docker:
62
38
  - image: ruby:2.4
@@ -86,10 +62,6 @@ workflows:
86
62
  version: 2
87
63
  tests:
88
64
  jobs:
89
- - build-ruby22-rails515
90
- - build-ruby22-rails4210
91
- - build-ruby23-rails515
92
- - build-ruby23-rails4210
93
65
  - build-ruby24-rails515
94
66
  - build-ruby24-rails4210
95
67
  - build-ruby25-rails515
@@ -4,7 +4,10 @@ inherit_gem:
4
4
  gc_ruboconfig: rubocop.yml
5
5
 
6
6
  AllCops:
7
- TargetRubyVersion: 2.2
7
+ TargetRubyVersion: 2.4
8
+
9
+ Metrics/MethodLength:
10
+ Max: 15
8
11
 
9
12
  Style/RescueStandardError:
10
13
  Exclude:
@@ -1,5 +1,35 @@
1
1
  # CHANGELOG
2
2
 
3
+ # Unreleased
4
+
5
+ No unreleased changes.
6
+
7
+ # 2.0.0 / 2019-06-13
8
+
9
+ ## Breaking changes
10
+
11
+ * [#70](https://github.com/gocardless/coach/pull/70) The following deprecated event names have been removed:
12
+ * `coach.handler.start`
13
+ * `coach.middleware.start`
14
+ * `coach.middleware.finish`
15
+ * `coach.handler.finish`
16
+ * `coach.request`
17
+
18
+ * [#56](https://github.com/gocardless/coach/pull/56) Support for Ruby 2.2 and 2.3 has been
19
+ dropped. See our [compatibility policy](https://github.com/gocardless/coach/blob/master/docs/COMPATIBILITY.md) for more information.
20
+
21
+ ## Other changes
22
+
23
+ * [#59](https://github.com/gocardless/coach/pull/59) Request data included in the
24
+ `request.coach` event includes a `session_ip` field which replaces the erroneously named
25
+ `session_id`. The latter is deprecated and will be removed in a future release.
26
+
27
+ * [#60](https://github.com/gocardless/coach/pull/60) Add `Middleware.requires?`, which
28
+ behaves like `Middleware.provides?` but for requirements.
29
+
30
+ * [#52](https://github.com/gocardless/coach/pull/52) Add `duration_seconds` to statistic
31
+ logging. The `duration` field is now deprecated and will be removed in a future release.
32
+
3
33
  # 1.0.0 / 2018-04-19
4
34
 
5
35
  ## Breaking changes
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
4
6
 
5
- gem "gc_ruboconfig", "~> 2.3.4"
6
7
  gem "rails", "~> #{ENV['RAILS_VERSION']}" if ENV["RAILS_VERSION"]
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Coach
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/coach.svg)](http://badge.fury.io/rb/coach)
4
- [![Build Status](https://travis-ci.org/gocardless/coach.svg?branch=master)](https://travis-ci.org/gocardless/coach)
4
+ [![CircleCI](https://circleci.com/gh/gocardless/coach.svg?style=svg)](https://circleci.com/gh/gocardless/coach)
5
5
  [![Code Climate](https://codeclimate.com/github/gocardless/coach.svg)](https://codeclimate.com/github/gocardless/coach)
6
6
 
7
7
  Coach improves your controller code by encouraging:
@@ -13,6 +13,8 @@ Coach improves your controller code by encouraging:
13
13
  - **Testability** - Test each middleware in isolation, with effortless mocking of test
14
14
  data and natural RSpec matchers.
15
15
 
16
+ For our policy on compatibility with Ruby and Rails versions, see [COMPATIBILITY.md](docs/COMPATIBILITY.md).
17
+
16
18
  # Installation
17
19
 
18
20
  To get started, just add Coach to your `Gemfile`, and then run `bundle`:
@@ -21,7 +23,7 @@ To get started, just add Coach to your `Gemfile`, and then run `bundle`:
21
23
  gem 'coach'
22
24
  ```
23
25
 
24
- Coach works with Ruby versions 2.2 and onwards.
26
+ Coach works with Ruby versions 2.4 and onwards.
25
27
 
26
28
  ## Coach by example
27
29
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path("lib", __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require "coach/version"
@@ -10,7 +12,7 @@ Gem::Specification.new do |spec|
10
12
  spec.homepage = "https://github.com/gocardless/coach"
11
13
  spec.email = %w[developers@gocardless.com]
12
14
  spec.license = "MIT"
13
- spec.required_ruby_version = ">= 2.2"
15
+ spec.required_ruby_version = ">= 2.4"
14
16
 
15
17
  spec.files = `git ls-files -z`.split("\x0")
16
18
  spec.test_files = spec.files.grep(%r{^spec/})
@@ -19,8 +21,9 @@ Gem::Specification.new do |spec|
19
21
  spec.add_dependency "actionpack", ">= 4.2"
20
22
  spec.add_dependency "activesupport", ">= 4.2"
21
23
 
24
+ spec.add_development_dependency "gc_ruboconfig", "= 2.4.0"
22
25
  spec.add_development_dependency "pry", "~> 0.10"
23
26
  spec.add_development_dependency "rspec", "~> 3.2"
24
27
  spec.add_development_dependency "rspec-its", "~> 1.2"
25
- spec.add_development_dependency "rspec_junit_formatter", "~> 0.3.0"
28
+ spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.0"
26
29
  end
@@ -0,0 +1,17 @@
1
+ # Compatibility
2
+
3
+ Our goal as Coach maintainers is for the library to be compatible with all supported versions of Ruby and Rails.
4
+
5
+ Specifically, any CRuby/MRI version that has not received an End of Life notice ([e.g. this notice for Ruby 2.1](https://www.ruby-lang.org/en/news/2017/04/01/support-of-ruby-2-1-has-ended/)) is supported. Similarly, any version of Rails listed as currently supported on [this page](http://guides.rubyonrails.org/maintenance_policy.html) is one we aim to support in Coach.
6
+
7
+ To that end, [our build matrix](../.circleci/config.yml) includes all these versions.
8
+
9
+ Any time Coach doesn't work on a supported combination of Ruby and Rails, it's a bug, and can be reported [here](https://github.com/gocardless/coach/issues).
10
+
11
+ # Deprecation
12
+
13
+ Whenever a version of Ruby or Rails falls out of support, we will mirror that change in Coach by updating the build matrix and releasing a new major version.
14
+
15
+ At that point, we will close any issues that only affect the unsupported version, and may choose to remove any workarounds from the code that are only necessary for the unsupported version.
16
+
17
+ We will then bump the major version of Coach, to indicate the break in compatibility. Even if the new version of Coach happens to work on the unsupported version of Ruby or Rails, we consider compatibility to be broken at this point.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support"
2
4
  require "action_dispatch"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Coach
2
4
  module Errors
3
5
  class MiddlewareDependencyNotMet < StandardError
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "coach/errors"
2
4
  require "active_support/core_ext/object/try"
3
5
 
@@ -8,10 +10,10 @@ module Coach
8
10
  def initialize(middleware, config = {})
9
11
  @root_item = MiddlewareItem.new(middleware, config)
10
12
  validate!
11
- rescue Coach::Errors::MiddlewareDependencyNotMet => error
13
+ rescue Coach::Errors::MiddlewareDependencyNotMet => e
12
14
  # Remove noise of validation stack trace, reset to the handler callsite
13
- error.backtrace.clear.concat(Thread.current.backtrace)
14
- raise error
15
+ e.backtrace.clear.concat(Thread.current.backtrace)
16
+ raise e
15
17
  end
16
18
 
17
19
  # Run validation on the root of the middleware chain
@@ -28,8 +30,8 @@ module Coach
28
30
 
29
31
  event = build_event(context)
30
32
 
31
- publish_start(event.dup)
32
- instrumented_call(event) do
33
+ publish("start_handler.coach", event.dup)
34
+ instrument("finish_handler.coach", event) do
33
35
  begin
34
36
  response = chain.instrument.call
35
37
  ensure
@@ -87,28 +89,5 @@ module Coach
87
89
  request: context[:request],
88
90
  }
89
91
  end
90
-
91
- def publish_start(event)
92
- if notifier.listening?("coach.handler.start")
93
- ActiveSupport::Deprecation.warn("The 'coach.handler.start' event has been " \
94
- "renamed to 'start_handler.coach' and the old name will be removed in a " \
95
- "future version.")
96
- publish("coach.handler.start", event)
97
- end
98
- publish("start_handler.coach", event)
99
- end
100
-
101
- def instrumented_call(event, &block)
102
- if notifier.listening?("coach.handler.finish")
103
- ActiveSupport::Deprecation.warn("The 'coach.handler.find' event has been " \
104
- "renamed to 'finish_handler.coach' and the old name will be removed in a " \
105
- "future version.")
106
- instrument("coach.handler.finish", event) do
107
- instrument("finish_handler.coach", event, &block)
108
- end
109
- else
110
- instrument("finish_handler.coach", event, &block)
111
- end
112
- end
113
92
  end
114
93
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "coach/middleware_item"
2
4
 
3
5
  module Coach
@@ -40,6 +42,10 @@ module Coach
40
42
  end
41
43
  end
42
44
 
45
+ def self.requires?(provision)
46
+ requirements.include?(provision)
47
+ end
48
+
43
49
  attr_reader :next_middleware, :config
44
50
 
45
51
  # Middleware gets access to a shared context, which is populated by other
@@ -73,14 +79,10 @@ module Coach
73
79
  # Use ActiveSupport to instrument the execution of the subsequent chain.
74
80
  def instrument
75
81
  proc do
76
- publish_start
82
+ ActiveSupport::Notifications.publish("start_middleware.coach", middleware_event)
77
83
 
78
- if ActiveSupport::Notifications.notifier.listening?("coach.middleware.finish")
79
- instrument_deprecated { call }
80
- else
81
- ActiveSupport::Notifications.
82
- instrument("finish_middleware.coach", middleware_event) { call }
83
- end
84
+ ActiveSupport::Notifications.
85
+ instrument("finish_middleware.coach", middleware_event) { call }
84
86
  end
85
87
  end
86
88
 
@@ -106,28 +108,5 @@ module Coach
106
108
  request: request,
107
109
  }
108
110
  end
109
-
110
- def publish_start
111
- if ActiveSupport::Notifications.notifier.listening?("coach.middleware.start")
112
- ActiveSupport::Deprecation.warn("The 'coach.middleware.start' event has " \
113
- "been renamed to 'start_middleware.coach' and the old name will be " \
114
- "removed in a future version.")
115
- ActiveSupport::Notifications.
116
- publish("coach.middleware.start", middleware_event)
117
- end
118
- ActiveSupport::Notifications.
119
- publish("start_middleware.coach", middleware_event)
120
- end
121
-
122
- def instrument_deprecated(&block)
123
- ActiveSupport::Deprecation.warn("The 'coach.middleware.finish' event has " \
124
- "been renamed to 'finish_middleware.coach' and the old name will be " \
125
- "removed in a future version.")
126
- ActiveSupport::Notifications.
127
- instrument("coach.middleware.finish", middleware_event) do
128
- ActiveSupport::Notifications.
129
- instrument("finish_middleware.coach", middleware_event, &block)
130
- end
131
- end
132
111
  end
133
112
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "coach/errors"
2
4
  require "coach/middleware_validator"
3
5
 
@@ -13,7 +15,7 @@ module Coach
13
15
  def build_middleware(context, successor)
14
16
  @middleware.
15
17
  new(context,
16
- successor && successor.instrument,
18
+ successor&.instrument,
17
19
  config)
18
20
  end
19
21
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "coach/errors"
2
4
 
3
5
  module Coach
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "request_benchmark"
2
4
  require_relative "request_serializer"
3
5
 
@@ -43,6 +45,7 @@ module Coach
43
45
 
44
46
  def unsubscribe!
45
47
  return unless active?
48
+
46
49
  while @subscriptions.any?
47
50
  ActiveSupport::Notifications.unsubscribe(@subscriptions.pop)
48
51
  end
@@ -63,15 +66,13 @@ module Coach
63
66
  end
64
67
 
65
68
  def subscribe(event, &block)
66
- # New key formats don't include a period. If they do, they're the old deprecated
67
- # format. No need to warn here since the warnings will show up from elsewhere.
68
- key = event.include?(".") ? "coach.#{event}" : "#{event}.coach"
69
- ActiveSupport::Notifications.subscribe(key, &block)
69
+ ActiveSupport::Notifications.subscribe("#{event}.coach", &block)
70
70
  end
71
71
 
72
72
  def log_middleware_finish(event, start, finish)
73
73
  benchmark_for_request = @benchmarks[event[:request].uuid]
74
74
  return unless benchmark_for_request.present?
75
+
75
76
  benchmark_for_request.notify(event[:middleware], start, finish)
76
77
  end
77
78
 
@@ -87,11 +88,6 @@ module Coach
87
88
  serialized = RequestSerializer.new(event[:request]).serialize.
88
89
  merge(benchmark.stats).
89
90
  merge(event.slice(:response, :metadata))
90
- if ActiveSupport::Notifications.notifier.listening?("coach.request")
91
- ActiveSupport::Deprecation.warn("The 'coach.request' event has been renamed " \
92
- "to 'request.coach' and the old name will be removed in a future version.")
93
- ActiveSupport::Notifications.publish("coach.request", serialized)
94
- end
95
91
  ActiveSupport::Notifications.publish("request.coach", serialized)
96
92
  end
97
93
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Coach
2
4
  # This class is built to aggregate data during the course of the request. It relies on
3
5
  # 'start_middleware.coach' and 'finish_middleware.coach' events to register the
@@ -32,8 +34,13 @@ module Coach
32
34
  endpoint_name: @endpoint_name,
33
35
  started_at: @start,
34
36
  duration: format_ms(@duration),
37
+ duration_seconds: @duration,
35
38
  chain: sorted_chain.map do |event|
36
- { name: event[:name], duration: format_ms(event[:duration]) }
39
+ {
40
+ name: event[:name],
41
+ duration: format_ms(event[:duration]),
42
+ duration_seconds: event[:duration],
43
+ }
37
44
  end,
38
45
  }
39
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Coach
2
4
  class RequestSerializer
3
5
  def self.header_rules
@@ -14,6 +16,7 @@ module Coach
14
16
  # Applies sanitizing rules. Expects `header` to be in 'http_header_name' form.
15
17
  def self.apply_header_rule(header, value)
16
18
  return value if header_rules[header].nil?
19
+
17
20
  header_rules[header].call(value)
18
21
  end
19
22
 
@@ -39,7 +42,8 @@ module Coach
39
42
 
40
43
  # Extra request info
41
44
  headers: filtered_headers,
42
- session_id: @request.remote_ip,
45
+ session_id: @request.remote_ip, # TODO: remove in a future release
46
+ session_ip: @request.remote_ip,
43
47
  }
44
48
  end
45
49
 
@@ -54,6 +58,7 @@ module Coach
54
58
  def filtered_headers
55
59
  header_value_pairs = @request.filtered_env.map do |key, value|
56
60
  next unless key =~ /^HTTP_/
61
+
57
62
  [key.downcase, self.class.apply_header_rule(key.downcase, value)]
58
63
  end.compact
59
64
 
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "handler"
2
4
  require_relative "errors"
3
5
 
4
6
  module Coach
5
7
  class Router
6
8
  ACTION_TRAITS = {
7
- index: { method: :get },
8
- show: { method: :get, url: ":id" },
9
- create: { method: :post },
10
- update: { method: :put, url: ":id" },
9
+ index: { method: :get },
10
+ show: { method: :get, url: ":id" },
11
+ create: { method: :post },
12
+ update: { method: :put, url: ":id" },
11
13
  destroy: { method: :delete, url: ":id" },
12
14
  }.each_value(&:freeze).freeze
13
15
 
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rspec/expectations"
2
4
  require "coach/middleware"
3
5
 
4
6
  # Middleware stubbing ######################################
5
7
 
6
- # rubocop:disable Metrics/MethodLength
7
8
  # rubocop:disable Metrics/AbcSize
8
9
  def build_middleware(name)
9
10
  Class.new(Coach::Middleware) do
@@ -28,7 +29,6 @@ def build_middleware(name)
28
29
  end
29
30
  end
30
31
  # rubocop:enable Metrics/AbcSize
31
- # rubocop:enable Metrics/MethodLength
32
32
 
33
33
  def null_middleware
34
34
  double(call: nil)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Coach
2
- VERSION = "1.0.0".freeze
4
+ VERSION = "2.0.0"
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  require "coach/handler"
@@ -123,27 +125,25 @@ describe Coach::Handler do
123
125
  before { terminal_middleware.uses(middleware_a) }
124
126
 
125
127
  describe "notifications" do
126
- before do
127
- Coach::Notifications.subscribe!
128
-
129
- # Prevent RequestSerializer from erroring due to insufficient request mock
130
- allow(Coach::RequestSerializer).
131
- to receive(:new).
132
- and_return(instance_double("Coach::RequestSerializer", serialize: {}))
133
- end
134
-
135
128
  subject(:coach_events) do
136
129
  events = []
137
130
  subscription = ActiveSupport::Notifications.
138
- subscribe(/\.coach$/) do |name, *_args|
139
- events << name
140
- end
131
+ subscribe(/\.coach$/) { |name, *_args| events << name }
141
132
 
142
133
  handler.call({})
143
134
  ActiveSupport::Notifications.unsubscribe(subscription)
144
135
  events
145
136
  end
146
137
 
138
+ before do
139
+ Coach::Notifications.subscribe!
140
+
141
+ # Prevent RequestSerializer from erroring due to insufficient request mock
142
+ allow(Coach::RequestSerializer).
143
+ to receive(:new).
144
+ and_return(instance_double("Coach::RequestSerializer", serialize: {}))
145
+ end
146
+
147
147
  it { is_expected.to include("start_handler.coach") }
148
148
  it { is_expected.to include("start_middleware.coach") }
149
149
  it { is_expected.to include("request.coach") }
@@ -160,7 +160,7 @@ describe Coach::Handler do
160
160
 
161
161
  begin
162
162
  handler.call({})
163
- rescue
163
+ rescue StandardError
164
164
  :continue_anyway
165
165
  end
166
166
  ActiveSupport::Notifications.unsubscribe(subscription)
@@ -172,7 +172,7 @@ describe Coach::Handler do
172
172
  before { terminal_middleware.uses(middleware_a, callback: explosive_action) }
173
173
 
174
174
  it "captures the error event with the metadata" do
175
- is_expected.
175
+ expect(coach_events).
176
176
  to include(["finish_handler.coach", hash_including(
177
177
  response: { status: 500 },
178
178
  metadata: { A: true },
@@ -183,72 +183,6 @@ describe Coach::Handler do
183
183
  expect { handler.call({}) }.to raise_error(StandardError, "AH")
184
184
  end
185
185
  end
186
-
187
- context "deprecations" do
188
- subject(:coach_events) do
189
- events = []
190
- subscription = ActiveSupport::Notifications.
191
- subscribe(/^coach\./) do |name, *_args|
192
- events << name
193
- end
194
-
195
- handler.call({})
196
- ActiveSupport::Notifications.unsubscribe(subscription)
197
- events
198
- end
199
-
200
- let!(:deprecations_silenced) do
201
- ActiveSupport::Deprecation.silenced
202
- end
203
-
204
- before do
205
- ActiveSupport::Deprecation.silenced = true
206
- end
207
-
208
- after do
209
- ActiveSupport::Deprecation.silenced = deprecations_silenced
210
- end
211
-
212
- it { is_expected.to include("coach.handler.start") }
213
- it { is_expected.to include("coach.middleware.start") }
214
- it { is_expected.to include("coach.request") }
215
- it { is_expected.to include("coach.middleware.finish") }
216
- it { is_expected.to include("coach.handler.finish") }
217
-
218
- context "when an exception is raised in the chain" do
219
- subject(:coach_events) do
220
- events = []
221
- subscription = ActiveSupport::Notifications.
222
- subscribe(/^coach\./) do |name, *args|
223
- events << [name, args.last]
224
- end
225
-
226
- begin
227
- handler.call({})
228
- rescue
229
- :continue_anyway
230
- end
231
- ActiveSupport::Notifications.unsubscribe(subscription)
232
- events
233
- end
234
-
235
- let(:explosive_action) { -> { raise "AH" } }
236
-
237
- before { terminal_middleware.uses(middleware_a, callback: explosive_action) }
238
-
239
- it "captures the error event with the metadata" do
240
- is_expected.
241
- to include(["coach.handler.finish", hash_including(
242
- response: { status: 500 },
243
- metadata: { A: true },
244
- )])
245
- end
246
-
247
- it "bubbles the error to the next handler" do
248
- expect { handler.call({}) }.to raise_error(StandardError, "AH")
249
- end
250
- end
251
- end
252
186
  end
253
187
  end
254
188
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "coach/middleware"
2
4
 
3
5
  describe Coach::Middleware do
@@ -35,6 +37,29 @@ describe Coach::Middleware do
35
37
  end
36
38
  end
37
39
 
40
+ describe ".requires?" do
41
+ context "given names it does require" do
42
+ before { middleware_class.requires(:foo, :bar) }
43
+
44
+ it "returns true" do
45
+ # rubocop:disable RSpec/PredicateMatcher
46
+ expect(middleware_class.requires?(:foo)).to be_truthy
47
+ expect(middleware_class.requires?(:bar)).to be_truthy
48
+ # rubocop:enable RSpec/PredicateMatcher
49
+ end
50
+ end
51
+
52
+ context "given names it doesn't require" do
53
+ before { middleware_class.requires(:foo) }
54
+
55
+ it "returns false" do
56
+ # rubocop:disable RSpec/PredicateMatcher
57
+ expect(middleware_class.requires?(:bar)).to be_falsy
58
+ # rubocop:enable RSpec/PredicateMatcher
59
+ end
60
+ end
61
+ end
62
+
38
63
  describe "#provide" do
39
64
  before { middleware_class.provides(:foo) }
40
65
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
  require "coach/middleware_validator"
3
5
 
@@ -37,6 +39,7 @@ describe Coach::MiddlewareValidator do
37
39
  head_middleware.requires :c
38
40
  middleware_c.provides :c
39
41
  end
42
+
40
43
  it { is_expected.to_not raise_error }
41
44
  end
42
45
 
@@ -48,6 +51,7 @@ describe Coach::MiddlewareValidator do
48
51
  middleware_a.provides :a
49
52
  middleware_b.requires :a
50
53
  end
54
+
51
55
  it { is_expected.to_not raise_error }
52
56
  end
53
57
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
  require "coach/notifications"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
  require "coach/request_benchmark"
3
5
 
@@ -24,6 +26,7 @@ describe Coach::RequestBenchmark do
24
26
 
25
27
  it "computes overall duration" do
26
28
  expect(stats[:duration]).to eq(5000)
29
+ expect(stats[:duration_seconds]).to eq(5.0)
27
30
  end
28
31
 
29
32
  it "captures the endpoint_name" do
@@ -35,11 +38,11 @@ describe Coach::RequestBenchmark do
35
38
  end
36
39
 
37
40
  it "computes duration of middleware with no children" do
38
- expect(stats[:chain]).to include(name: "B", duration: 1000)
41
+ expect(stats[:chain]).to include(name: "B", duration: 1000, duration_seconds: 1.0)
39
42
  end
40
43
 
41
44
  it "adjusts duration of middleware for their children" do
42
- expect(stats[:chain]).to include(name: "A", duration: 2000)
45
+ expect(stats[:chain]).to include(name: "A", duration: 2000, duration_seconds: 2.0)
43
46
  end
44
47
 
45
48
  it "correctly orders chain" do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
  require "active_support/core_ext/object/try"
3
5
  require "coach/request_serializer"
@@ -40,12 +42,12 @@ describe Coach::RequestSerializer do
40
42
  subject(:request_serializer) { described_class.new(mock_request) }
41
43
 
42
44
  let(:mock_request) do
43
- instance_double("ActionDispatch::Request", format: nil,
44
- remote_ip: nil,
45
- uuid: nil,
46
- method: nil,
45
+ instance_double("ActionDispatch::Request", format: nil,
46
+ remote_ip: nil,
47
+ uuid: nil,
48
+ method: nil,
47
49
  filtered_parameters: nil,
48
- filtered_env: {
50
+ filtered_env: {
49
51
  "foo" => "bar",
50
52
  "HTTP_foo" => "bar",
51
53
  })
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  require "coach/router"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rspec/its"
2
4
  require "pry"
3
5
  require "coach"
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: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GoCardless
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-19 00:00:00.000000000 Z
11
+ date: 2019-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: gc_ruboconfig
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 2.4.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.4.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: pry
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +100,14 @@ dependencies:
86
100
  requirements:
87
101
  - - "~>"
88
102
  - !ruby/object:Gem::Version
89
- version: 0.3.0
103
+ version: 0.4.0
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
- version: 0.3.0
110
+ version: 0.4.0
97
111
  description:
98
112
  email:
99
113
  - developers@gocardless.com
@@ -111,6 +125,7 @@ files:
111
125
  - LICENSE.txt
112
126
  - README.md
113
127
  - coach.gemspec
128
+ - docs/COMPATIBILITY.md
114
129
  - lib/coach.rb
115
130
  - lib/coach/errors.rb
116
131
  - lib/coach/handler.rb
@@ -143,15 +158,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
143
158
  requirements:
144
159
  - - ">="
145
160
  - !ruby/object:Gem::Version
146
- version: '2.2'
161
+ version: '2.4'
147
162
  required_rubygems_version: !ruby/object:Gem::Requirement
148
163
  requirements:
149
164
  - - ">="
150
165
  - !ruby/object:Gem::Version
151
166
  version: '0'
152
167
  requirements: []
153
- rubyforge_project:
154
- rubygems_version: 2.7.4
168
+ rubygems_version: 3.0.2
155
169
  signing_key:
156
170
  specification_version: 4
157
171
  summary: Alternative controllers built with middleware