Skip to content

Commit b616015

Browse files
ericproulxdblock
andcommitted
New feature : linting (ruby-grape#2557)
* Add linting feature through Grape.config and `lint_api!` method Add spec All specs are now linted * Remove error message for Lint::Error * Add ruby 3.1 to 3.2 to spec integrations Add `yaml-dev` in Dockerfile * Rename `lint_api!` to `lint!` * Revert test.yml * Add README.md and CHANGELOG.md Fix typo in UPGRADING.md * Fix CHANGELOG * Use `lint!` in rails spec * Fix api_spec lint with ensure --------- Co-authored-by: Daniel (dB.) Doubrovkine <[email protected]>
1 parent a65a838 commit b616015

File tree

10 files changed

+67
-7
lines changed

10 files changed

+67
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* [#2554](https://github.com/ruby-grape/grape/pull/2554): Remove `Grape::Http::Headers` and `Grape::Util::Lazy::Object` - [@ericproulx](https://github.com/ericproulx).
1313
* [#2556](https://github.com/ruby-grape/grape/pull/2556): Remove unused `Grape::Request::DEFAULT_PARAMS_BUILDER` constant - [@eriklovmo](https://github.com/eriklovmo).
1414
* [#2558](https://github.com/ruby-grape/grape/pull/2558): Add Ruby's option `enable_frozen_string_literal` in CI - [@ericproulx](https://github.com/ericproulx).
15+
* [#2557](https://github.com/ruby-grape/grape/pull/2557): Add lint! - [@ericproulx](https://github.com/ericproulx).
1516
* Your contribution here.
1617

1718
#### Fixes

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
- [Header](#header)
2929
- [Accept-Version Header](#accept-version-header)
3030
- [Param](#param)
31+
- [Linting](#linting)
32+
- [Bug in Rack::ETag under Rack 3.X](#bug-in-racketag-under-rack-3x)
3133
- [Describing Methods](#describing-methods)
3234
- [Configuration](#configuration)
3335
- [Parameters](#parameters)
@@ -650,6 +652,27 @@ version 'v1', using: :param, parameter: 'v'
650652
curl http://localhost:9292/statuses/public_timeline?v=v1
651653

652654

655+
## Linting
656+
657+
You can check whether your API is in conformance with the [Rack's specification](https://github.com/rack/rack/blob/main/SPEC.rdoc) by calling `lint!` at the API level or through [configuration](#configuration).
658+
659+
```ruby
660+
class Api < Grape::API
661+
lint!
662+
end
663+
```
664+
```ruby
665+
Grape.configure do |config|
666+
config.lint = true
667+
end
668+
```
669+
```ruby
670+
Grape.config.lint = true
671+
```
672+
673+
### Bug in Rack::ETag under Rack 3.X
674+
If you're using Rack 3.X and the `Rack::Etag` middleware (used by [Rails](https://guides.rubyonrails.org/rails_on_rack.html#inspecting-middleware-stack)), a [bug](https://github.com/rack/rack/pull/2324) related to linting has been fixed in [3.1.13](https://github.com/rack/rack/blob/v3.1.13/CHANGELOG.md#3113---2025-04-13) and [3.0.15](https://github.com/rack/rack/blob/v3.1.13/CHANGELOG.md#3015---2025-04-13) respectively.
675+
653676
## Describing Methods
654677

655678
You can add a description to API methods and namespaces. The description would be used by [grape-swagger][grape-swagger] to generate swagger compliant documentation.

UPGRADING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ When using together with `Grape::Extensions::Hash::ParamBuilder`, `route_param`
130130
This was a regression introduced by [#2326](https://github.com/ruby-grape/grape/pull/2326) in Grape v1.8.0.
131131

132132
```ruby
133-
grape.configure do |config|
133+
Grape.configure do |config|
134134
config.param_builder = Grape::Extensions::Hash::ParamBuilder
135135
end
136136

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ENV RUBYOPT --enable-frozen-string-literal --yjit
77
ENV LD_PRELOAD libjemalloc.so.2
88
ENV MALLOC_CONF dirty_decay_ms:1000,narenas:2,background_thread:true
99

10-
RUN apk add --update --no-cache make gcc git libc-dev gcompat jemalloc && \
10+
RUN apk add --update --no-cache make gcc git libc-dev yaml-dev gcompat jemalloc && \
1111
gem update --system && gem install bundler
1212

1313
WORKDIR $LIB_PATH

lib/grape.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def self.deprecator
7575

7676
configure do |config|
7777
config.param_builder = :hash_with_indifferent_access
78+
config.lint = false
7879
config.compile_methods!
7980
end
8081
end

lib/grape/dsl/routing.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,14 @@ def do_not_route_head!
7272
namespace_inheritable(:do_not_route_head, true)
7373
end
7474

75-
# Do not automatically route OPTIONS.
76-
def do_not_route_options!
77-
namespace_inheritable(:do_not_route_options, true)
78-
end
75+
# Do not automatically route OPTIONS.
76+
def do_not_route_options!
77+
namespace_inheritable(:do_not_route_options, true)
78+
end
79+
80+
def lint!
81+
namespace_inheritable(:lint, true)
82+
end
7983

8084
def do_not_document!
8185
namespace_inheritable(:do_not_document, true)

lib/grape/endpoint.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ def build_stack(helpers)
359359
format = namespace_inheritable(:format)
360360

361361
stack.use Rack::Head
362+
stack.use Rack::Lint if lint?
362363
stack.use Class.new(Grape::Middleware::Error),
363364
helpers: helpers,
364365
format: format,
@@ -409,5 +410,9 @@ def build_response_cookies
409410
Rack::Utils.set_cookie_header! header, name, cookie_value
410411
end
411412
end
413+
414+
def lint?
415+
namespace_inheritable(:lint) || Grape.config.lint
416+
end
412417
end
413418
end

spec/grape/api_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4738,4 +4738,28 @@ def uniqe_id_route
47384738
expect(last_response.body).to eq('unknown params_builder: unknown')
47394739
end
47404740
end
4741+
4742+
describe '.lint!' do
4743+
let(:app) do
4744+
Class.new(described_class) do
4745+
lint!
4746+
get '/' do
4747+
status 42
4748+
end
4749+
end
4750+
end
4751+
4752+
around do |example|
4753+
@lint = Grape.config.lint
4754+
Grape.config.lint = false
4755+
example.run
4756+
ensure
4757+
Grape.config.lint = @lint
4758+
end
4759+
4760+
it 'raises a Rack::Lint error' do
4761+
# Status must be an Integer >= 100
4762+
expect { get '/' }.to raise_error(Rack::Lint::LintError)
4763+
end
4764+
end
47414765
end

spec/integration/rails/mounting_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
context 'rails mounted' do
55
let(:api) do
66
Class.new(Grape::API) do
7+
lint!
78
get('/test_grape') { 'rails mounted' }
89
end
910
end
@@ -28,7 +29,7 @@
2829
mount GrapeApi => '/'
2930

3031
get 'up', to: lambda { |_env|
31-
['200', {}, ['hello world']]
32+
[200, {}, ['hello world']]
3233
}
3334
end
3435
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
end
1414
end
1515

16+
Grape.config.lint = true # lint all apis by default
1617
Grape::Util::Registry.include(Deregister)
1718
# issue with ruby 2.7 with ^. We need to extend it again
1819
Grape::Validations.extend(Grape::Util::Registry) if Gem::Version.new(RUBY_VERSION).release < Gem::Version.new('3.0')

0 commit comments

Comments
 (0)