Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ jobs:

tests:
strategy:
fail-fast: false
matrix:
ruby-version: [2.6, 2.7, 3.0, 3.1]
rails-version: [6.0, 6.1, 7.0]
ruby-version: ["3.1", "3.2", "3.3", "3.4"]
rails-version: ["7.0", "7.1", "7.2", "8.0"]
exclude:
- ruby-version: 2.6
rails-version: 7.0
- ruby-version: "3.1"
rails-version: "8.0"
runs-on: ubuntu-latest
env:
RAILS_VERSION: ${{ matrix.rails-version }}
Expand Down
14 changes: 11 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
inherit_from: .rubocop_todo.yml

inherit_gem:
gc_ruboconfig: rubocop.yml

AllCops:
TargetRubyVersion: 2.6
TargetRubyVersion: 3.1
NewCops: enable

Metrics/MethodLength:
Max: 15
Expand All @@ -29,3 +28,12 @@ Naming/MethodParameterName:

Gemspec/RequiredRubyVersion:
Enabled: False

RSpec/NestedGroups:
Enabled: false

RSpec/MultipleExpectations:
Enabled: false

RSpec/ExampleLength:
Max: 10
27 changes: 0 additions & 27 deletions .rubocop_todo.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.2
3.4.1
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

# Unreleased

# 4.0.0 / 2025-01-15

* Drop support for Rails < 7.0 and Ruby < 3.0

# 3.0.1 / 2022-03-09

* [#120](https://github.com/gocardless/coach/pull/120) Fixes missing method from middleware in Rails 7
Expand Down
9 changes: 8 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,11 @@ source 'https://rubygems.org'

gemspec

gem "rails", "~> #{ENV['RAILS_VERSION']}" if ENV["RAILS_VERSION"]
group :development, :test do
gem "gc_ruboconfig", "~> 5"
gem "pry", "~> 0.10"
gem "rails", "~> #{ENV['RAILS_VERSION']}" if ENV["RAILS_VERSION"]
gem "rspec", "~> 3.13"
gem "rspec-github", "~> 2.4.0"
gem "rspec-its", "~> 1.2"
end
45 changes: 21 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Coach

[![Gem Version](https://badge.fury.io/rb/coach.svg)](http://badge.fury.io/rb/coach)
[![CircleCI](https://circleci.com/gh/gocardless/coach.svg?style=svg)](https://circleci.com/gh/gocardless/coach)
[![Code Climate](https://codeclimate.com/github/gocardless/coach.svg)](https://codeclimate.com/github/gocardless/coach)

Coach improves your controller code by encouraging:

Expand All @@ -23,7 +21,7 @@ To get started, just add Coach to your `Gemfile`, and then run `bundle`:
gem 'coach'
```

Coach works with Ruby versions 2.6 and onwards.
Coach works with Ruby versions 3.1 and onwards.

## Coach by example

Expand Down Expand Up @@ -278,13 +276,13 @@ end
Default actions that conform to standard REST principles can be easily loaded, with the
users resource being mapped to:

| Method | URL | Description |
|--------|------------------------------|------------------------------------------------|
| `GET` | `/users` | Index all users |
| `GET` | `/users/:id` | Get user by ID |
| `POST` | `/users` | Create new user |
| `PUT` | `/users/:id` | Update user details |
| `POST` | `/users/:id/actions/disable` | Custom action routed to the given path suffix |
| Method | URL | Description |
| ------ | ---------------------------- | --------------------------------------------- |
| `GET` | `/users` | Index all users |
| `GET` | `/users/:id` | Get user by ID |
| `POST` | `/users` | Create new user |
| `PUT` | `/users/:id` | Update user details |
| `POST` | `/users/:id/actions/disable` | Custom action routed to the given path suffix |

If you're using Zeitwerk, you can pass the name of the module to `#draw`, instead of the module
itself.
Expand Down Expand Up @@ -328,14 +326,13 @@ middleware.
Information for how to use `ActiveSupport`s notifications can be found
[here](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html).


| Event | Arguments |
|-------------------------------|------------------------------------------------------- |
| `start_handler.coach` | `event(:middleware, :request)` |
| `start_middleware.coach` | `event(:middleware, :request)` |
| `finish_middleware.coach` | `start`, `finish`, `id`, `event(:middleware, :request)`|
| `finish_handler.coach` | `start`, `finish`, `id`, `event(:middleware, :request)`|
| `request.coach` | `event` containing request data and benchmarking |
| Event | Arguments |
| ------------------------- | ------------------------------------------------------- |
| `start_handler.coach` | `event(:middleware, :request)` |
| `start_middleware.coach` | `event(:middleware, :request)` |
| `finish_middleware.coach` | `start`, `finish`, `id`, `event(:middleware, :request)` |
| `finish_handler.coach` | `start`, `finish`, `id`, `event(:middleware, :request)` |
| `request.coach` | `event` containing request data and benchmarking |

Of special interest is `request.coach`, which publishes statistics on an entire
middleware chain and request. This data is particularly useful for logging, and is our
Expand Down Expand Up @@ -435,14 +432,14 @@ around 15s to 1s.
While we think the commands we've already built are useful, we do have some ideas to go
further, including:

- Better formatting of provider chains
- Outputting DOT format files to visualise with Graphviz
- Editor integrations (e.g. showing the provider chains when hovering a `requires`
statement)
- Better formatting of provider chains
- Outputting DOT format files to visualise with Graphviz
- Editor integrations (e.g. showing the provider chains when hovering a `requires`
statement)

# License & Contributing

* Coach is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
* Bug reports and pull requests are welcome on GitHub at https://github.com/gocardless/coach.
- Coach is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
- Bug reports and pull requests are welcome on GitHub at https://github.com/gocardless/coach.

GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/about/jobs).
11 changes: 3 additions & 8 deletions coach.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,15 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/gocardless/coach"
spec.email = %w[developers@gocardless.com]
spec.license = "MIT"
spec.required_ruby_version = ">= 2.6"
spec.required_ruby_version = ">= 3.1"

spec.files = `git ls-files -z`.split("\x0")
spec.require_paths = ["lib"]
spec.executables = ["coach"]

spec.add_dependency "actionpack", ">= 4.2"
spec.add_dependency "activesupport", ">= 4.2"
spec.add_dependency "actionpack", ">= 7.0"
spec.add_dependency "activesupport", ">= 7.0"
spec.add_dependency "commander", "~> 4.5"

spec.add_development_dependency "gc_ruboconfig", "~> 3.6"
spec.add_development_dependency "pry", "~> 0.10"
spec.add_development_dependency "rspec", "~> 3.2"
spec.add_development_dependency "rspec-github", "~> 2.4.0"
spec.add_development_dependency "rspec-its", "~> 1.2"
spec.metadata["rubygems_mfa_required"] = "true"
end
4 changes: 2 additions & 2 deletions docs/COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Our goal as Coach maintainers is for the library to be compatible with all supported versions of Ruby and Rails.

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.
Specifically, any CRuby/MRI version that has not reached (End of Life)[https://endoflife.date/ruby] is supported. Similarly, any version of Rails listed as currently supported on [this page](https://endoflife.date/rails) is one we aim to support in Coach.

To that end, [our build matrix](../.circleci/config.yml) includes all these versions.
To that end, [our build matrix](../.github/tests.yml) includes all these versions.

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).

Expand Down
2 changes: 1 addition & 1 deletion lib/coach/cli/provider_finder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def find_chain
raise err
end

chains.map { |chain| chain.map(&:to_s).reverse }.to_set
chains.to_set { |chain| chain.map(&:to_s).reverse }
end

private
Expand Down
4 changes: 1 addition & 3 deletions lib/coach/notifications.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ def subscribe!
def unsubscribe!
return unless active?

while @subscriptions.any?
ActiveSupport::Notifications.unsubscribe(@subscriptions.pop)
end
ActiveSupport::Notifications.unsubscribe(@subscriptions.pop) while @subscriptions.any?
true
end

Expand Down
4 changes: 2 additions & 2 deletions lib/coach/request_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ def request_path
end

def filtered_headers
header_value_pairs = @request.filtered_env.map do |key, value|
header_value_pairs = @request.filtered_env.filter_map do |key, value|
key = if RACK_UNPREFIXED_HEADERS.include?(key)
"http_#{key.downcase}"
elsif key.start_with?("HTTP_")
key.downcase
end

[key, self.class.apply_header_rule(key, value)] if key
end.compact
end

header_value_pairs.to_h
end
Expand Down
4 changes: 3 additions & 1 deletion lib/coach/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ def call
config[:callback].call if config.include?(:callback)
log_metadata(**{ name.to_sym => true })

response = [name + config.except(:callback).inspect.to_s]
# Emulate newer hash syntax for older Ruby versions
hash_response = config.except(:callback).map { |k, v| "#{k}: #{v}" }.join(", ")
response = [name + "{#{hash_response}}"]

# Build up a list of middleware called, in the order they were called
if next_middleware
Expand Down
2 changes: 1 addition & 1 deletion lib/coach/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Coach
VERSION = "3.0.1"
VERSION = "4.0.0"
end
2 changes: 1 addition & 1 deletion spec/lib/coach/cli/provider_finder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@
expect(provider_finder.find_chain).
to eq([
%w[FirstProvidingMiddleware FirstIntermediateMiddleware RequiringMiddleware],
%w[SecondProvidingMiddleware SecondIntermediateMiddleware RequiringMiddleware], # rubocop:disable Layout/LineLength
%w[SecondProvidingMiddleware SecondIntermediateMiddleware RequiringMiddleware],
].to_set)
end
end
Expand Down
21 changes: 9 additions & 12 deletions spec/lib/coach/handler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
expect(a_double).to receive(:call)
expect(b_double).to receive(:call)
result = handler.call({})
expect(result).to eq(%w[A{} B{} Terminal{:handler=>true}])
expect(result).to eq(["A{}", "B{}", "Terminal{handler: true}"])
end

context "with an invalid chain" do
Expand Down Expand Up @@ -66,7 +66,7 @@

result = handler.call({})

expect(result).to eq(%w[A{} B{} Terminal{:handler=>true}])
expect(result).to eq(["A{}", "B{}", "Terminal{handler: true}"])
end

context "with an invalid chain" do
Expand Down Expand Up @@ -158,7 +158,7 @@
before { terminal_middleware.uses(middleware_a) }

it "assembles a sequence including all middleware" do
expect(sequence).to match_array([middleware_a, terminal_middleware])
expect(sequence).to contain_exactly(middleware_a, terminal_middleware)
end
end

Expand All @@ -170,8 +170,7 @@
end

it "assembles a sequence including all middleware" do
expect(sequence).to match_array([middleware_c, middleware_b,
middleware_a, terminal_middleware])
expect(sequence).to contain_exactly(middleware_c, middleware_b, middleware_a, terminal_middleware)
end
end

Expand All @@ -184,17 +183,15 @@
end

it "only appears once" do
expect(sequence).to match_array([middleware_c, middleware_a,
middleware_b, terminal_middleware])
expect(sequence).to contain_exactly(middleware_c, middleware_a, middleware_b, terminal_middleware)
end

context "with a different config" do
before { middleware_b.uses(middleware_c, foo: "bar") }

it "appears more than once" do
expect(sequence).to match_array([middleware_c, middleware_a,
middleware_c, middleware_b,
terminal_middleware])
expect(sequence).to contain_exactly(middleware_c, middleware_a, middleware_c, middleware_b,
terminal_middleware)
end
end
end
Expand All @@ -218,7 +215,7 @@

it "sets up the chain correctly, calling each item in the correct order" do
expect(handler.build_request_chain(sequence, {}).call).
to eq(%w[A{} B{:b=>true} Terminal{}])
to eq(["A{}", "B{b: true}", "Terminal{}"])
end

context "with inheriting config" do
Expand All @@ -229,7 +226,7 @@

it "calls lambda with parent middlewares config" do
expect(handler.build_request_chain(sequence, {}).call).
to eq(%w[A{} C{:b=>true} D{} B{:b=>true} Terminal{}])
to eq(["A{}", "C{b: true}", "D{}", "B{b: true}", "Terminal{}"])
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/lib/coach/request_benchmark_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

let(:base_time) { Time.now }

let(:start) { base_time + 0 }
let(:start) { base_time }
let(:a_start) { base_time + 1 }
let(:b_start) { base_time + 2 }
let(:b_finish) { base_time + 3 }
Expand Down
4 changes: 2 additions & 2 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
require "coach"
require "coach/rspec"

Dir[Pathname(__FILE__).dirname.join("support", "**", "*.rb")].
sort.
Dir[Pathname(__FILE__).dirname.join("support", "**", "*.rb")]
.
each { |path| require path }

RSpec.configure do |config|
Expand Down
Loading