From 3e9c2c8bf38816e7fa6e8017a3fd2b2ae007b2e0 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Tue, 26 Mar 2024 02:08:28 +0200 Subject: [PATCH 1/2] Add more cop settings tweaks, exclusions and disablings --- .rubocop.yml | 17 ++- .rubocop_todo.yml | 183 +-------------------------------- spec/support/endpoint_faker.rb | 3 +- 3 files changed, 17 insertions(+), 186 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 413d0d4b48..a58cedd15c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -15,6 +15,10 @@ inherit_from: .rubocop_todo.yml Layout/LineLength: Max: 215 +Lint/EmptyBlock: + Exclude: + - spec/**/*_spec.rb + Style/Documentation: Enabled: false @@ -60,7 +64,7 @@ RSpec/ExampleLength: Max: 60 RSpec/NestedGroups: - Max: 4 + Max: 6 RSpec/FilePath: SpecSuffixOnly: true @@ -69,4 +73,13 @@ RSpec/SpecFilePathFormat: Enabled: false RSpec/MultipleExpectations: - Max: 4 + Enabled: false + +RSpec/NamedSubject: + Enabled: false + +RSpec/MultipleMemoizedHelpers: + Max: 11 + +RSpec/ContextWording: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e296e585a0..afdefec250 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 5000` -# on 2024-03-25 01:40:39 UTC using RuboCop version 1.59.0. +# on 2024-03-26 00:06:40 UTC using RuboCop version 1.59.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -52,29 +52,6 @@ Lint/DuplicateBranch: Exclude: - 'spec/support/versioned_helpers.rb' -# Offense count: 75 -# Configuration parameters: AllowComments, AllowEmptyLambdas. -Lint/EmptyBlock: - Exclude: - - 'spec/grape/api/recognize_path_spec.rb' - - 'spec/grape/api/required_parameters_with_invalid_method_spec.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/dsl/routing_spec.rb' - - 'spec/grape/dsl/settings_spec.rb' - - 'spec/grape/endpoint/declared_spec.rb' - - 'spec/grape/endpoint_spec.rb' - - 'spec/grape/loading_spec.rb' - - 'spec/grape/validations/params_scope_spec.rb' - - 'spec/grape/validations/validators/all_or_none_spec.rb' - - 'spec/grape/validations/validators/at_least_one_of_spec.rb' - - 'spec/grape/validations/validators/coerce_spec.rb' - - 'spec/grape/validations/validators/exactly_one_of_spec.rb' - - 'spec/grape/validations/validators/mutual_exclusion_spec.rb' - - 'spec/grape/validations/validators/regexp_spec.rb' - - 'spec/grape/validations/validators/same_as_spec.rb' - - 'spec/grape/validations_spec.rb' - - 'spec/support/endpoint_faker.rb' - # Offense count: 5 # Configuration parameters: AllowComments. Lint/EmptyClass: @@ -136,63 +113,6 @@ RSpec/AnyInstance: - 'spec/grape/api_spec.rb' - 'spec/grape/middleware/base_spec.rb' -# Offense count: 345 -# Configuration parameters: Prefixes, AllowedPatterns. -# Prefixes: when, with, without -RSpec/ContextWording: - Exclude: - - 'spec/grape/api/defines_boolean_in_params_spec.rb' - - 'spec/grape/api/documentation_spec.rb' - - 'spec/grape/api/inherited_helpers_spec.rb' - - 'spec/grape/api/instance_spec.rb' - - 'spec/grape/api/invalid_format_spec.rb' - - 'spec/grape/api/namespace_parameters_in_route_spec.rb' - - 'spec/grape/api/optional_parameters_in_route_spec.rb' - - 'spec/grape/api/patch_method_helpers_spec.rb' - - 'spec/grape/api/required_parameters_in_route_spec.rb' - - 'spec/grape/api/required_parameters_with_invalid_method_spec.rb' - - 'spec/grape/api/routes_with_requirements_spec.rb' - - 'spec/grape/api_remount_spec.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/dsl/helpers_spec.rb' - - 'spec/grape/dsl/inside_route_spec.rb' - - 'spec/grape/endpoint_spec.rb' - - 'spec/grape/entity_spec.rb' - - 'spec/grape/exceptions/body_parse_errors_spec.rb' - - 'spec/grape/exceptions/invalid_accept_header_spec.rb' - - 'spec/grape/exceptions/validation_errors_spec.rb' - - 'spec/grape/extensions/param_builders/hashie/mash_spec.rb' - - 'spec/grape/middleware/auth/strategies_spec.rb' - - 'spec/grape/middleware/base_spec.rb' - - 'spec/grape/middleware/exception_spec.rb' - - 'spec/grape/middleware/formatter_spec.rb' - - 'spec/grape/middleware/globals_spec.rb' - - 'spec/grape/middleware/stack_spec.rb' - - 'spec/grape/middleware/versioner/accept_version_header_spec.rb' - - 'spec/grape/middleware/versioner/header_spec.rb' - - 'spec/grape/path_spec.rb' - - 'spec/grape/util/inheritable_values_spec.rb' - - 'spec/grape/util/reverse_stackable_values_spec.rb' - - 'spec/grape/util/stackable_values_spec.rb' - - 'spec/grape/validations/attributes_doc_spec.rb' - - 'spec/grape/validations/params_scope_spec.rb' - - 'spec/grape/validations/single_attribute_iterator_spec.rb' - - 'spec/grape/validations/types/array_coercer_spec.rb' - - 'spec/grape/validations/types/primitive_coercer_spec.rb' - - 'spec/grape/validations/types/set_coercer_spec.rb' - - 'spec/grape/validations/validators/all_or_none_spec.rb' - - 'spec/grape/validations/validators/allow_blank_spec.rb' - - 'spec/grape/validations/validators/at_least_one_of_spec.rb' - - 'spec/grape/validations/validators/coerce_spec.rb' - - 'spec/grape/validations/validators/default_spec.rb' - - 'spec/grape/validations/validators/exactly_one_of_spec.rb' - - 'spec/grape/validations/validators/mutual_exclusion_spec.rb' - - 'spec/grape/validations/validators/regexp_spec.rb' - - 'spec/grape/validations/validators/same_as_spec.rb' - - 'spec/grape/validations/validators/values_spec.rb' - - 'spec/grape/validations_spec.rb' - - 'spec/shared/versioning_examples.rb' - # Offense count: 2 # Configuration parameters: IgnoredMetadata. RSpec/DescribeClass: @@ -288,107 +208,6 @@ RSpec/MissingExampleGroupArgument: Exclude: - 'spec/grape/middleware/exception_spec.rb' -# Offense count: 57 -# Configuration parameters: Max. -RSpec/MultipleExpectations: - Exclude: - - 'spec/grape/api/mount_and_rescue_from_spec.rb' - - 'spec/grape/api/parameters_modification_spec.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/dsl/helpers_spec.rb' - - 'spec/grape/dsl/routing_spec.rb' - - 'spec/grape/dsl/settings_spec.rb' - - 'spec/grape/endpoint/declared_spec.rb' - - 'spec/grape/middleware/versioner/header_spec.rb' - - 'spec/grape/util/inheritable_setting_spec.rb' - - 'spec/grape/validations/params_scope_spec.rb' - - 'spec/grape/validations/validators/coerce_spec.rb' - - 'spec/grape/validations/validators/presence_spec.rb' - - 'spec/grape/validations_spec.rb' - -# Offense count: 38 -# Configuration parameters: AllowSubject, Max. -RSpec/MultipleMemoizedHelpers: - Exclude: - - 'spec/grape/middleware/exception_spec.rb' - - 'spec/grape/request_spec.rb' - - 'spec/grape/validations/attributes_doc_spec.rb' - -# Offense count: 2180 -# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. -# SupportedStyles: always, named_only -RSpec/NamedSubject: - Exclude: - - 'spec/grape/api/defines_boolean_in_params_spec.rb' - - 'spec/grape/api/documentation_spec.rb' - - 'spec/grape/api/invalid_format_spec.rb' - - 'spec/grape/api/namespace_parameters_in_route_spec.rb' - - 'spec/grape/api/optional_parameters_in_route_spec.rb' - - 'spec/grape/api/parameters_modification_spec.rb' - - 'spec/grape/api/recognize_path_spec.rb' - - 'spec/grape/api/required_parameters_in_route_spec.rb' - - 'spec/grape/api/required_parameters_with_invalid_method_spec.rb' - - 'spec/grape/api/routes_with_requirements_spec.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/dsl/callbacks_spec.rb' - - 'spec/grape/dsl/desc_spec.rb' - - 'spec/grape/dsl/headers_spec.rb' - - 'spec/grape/dsl/helpers_spec.rb' - - 'spec/grape/dsl/inside_route_spec.rb' - - 'spec/grape/dsl/logger_spec.rb' - - 'spec/grape/dsl/middleware_spec.rb' - - 'spec/grape/dsl/parameters_spec.rb' - - 'spec/grape/dsl/request_response_spec.rb' - - 'spec/grape/dsl/routing_spec.rb' - - 'spec/grape/dsl/settings_spec.rb' - - 'spec/grape/dsl/validations_spec.rb' - - 'spec/grape/endpoint/declared_spec.rb' - - 'spec/grape/endpoint_spec.rb' - - 'spec/grape/entity_spec.rb' - - 'spec/grape/exceptions/base_spec.rb' - - 'spec/grape/exceptions/body_parse_errors_spec.rb' - - 'spec/grape/exceptions/invalid_accept_header_spec.rb' - - 'spec/grape/exceptions/validation_errors_spec.rb' - - 'spec/grape/extensions/param_builders/hash_spec.rb' - - 'spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb' - - 'spec/grape/extensions/param_builders/hashie/mash_spec.rb' - - 'spec/grape/integration/rack_sendfile_spec.rb' - - 'spec/grape/middleware/auth/dsl_spec.rb' - - 'spec/grape/middleware/base_spec.rb' - - 'spec/grape/middleware/formatter_spec.rb' - - 'spec/grape/middleware/globals_spec.rb' - - 'spec/grape/middleware/stack_spec.rb' - - 'spec/grape/middleware/versioner/accept_version_header_spec.rb' - - 'spec/grape/middleware/versioner/header_spec.rb' - - 'spec/grape/middleware/versioner/param_spec.rb' - - 'spec/grape/middleware/versioner/path_spec.rb' - - 'spec/grape/parser_spec.rb' - - 'spec/grape/presenters/presenter_spec.rb' - - 'spec/grape/util/inheritable_setting_spec.rb' - - 'spec/grape/util/inheritable_values_spec.rb' - - 'spec/grape/util/reverse_stackable_values_spec.rb' - - 'spec/grape/util/stackable_values_spec.rb' - - 'spec/grape/util/strict_hash_configuration_spec.rb' - - 'spec/grape/validations/attributes_doc_spec.rb' - - 'spec/grape/validations/params_scope_spec.rb' - - 'spec/grape/validations/types/array_coercer_spec.rb' - - 'spec/grape/validations/types/primitive_coercer_spec.rb' - - 'spec/grape/validations/types/set_coercer_spec.rb' - - 'spec/grape/validations/validators/coerce_spec.rb' - - 'spec/grape/validations/validators/default_spec.rb' - - 'spec/grape/validations/validators/presence_spec.rb' - - 'spec/grape/validations_spec.rb' - -# Offense count: 28 -# Configuration parameters: Max, AllowedGroups. -RSpec/NestedGroups: - Exclude: - - 'spec/grape/api_remount_spec.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/dsl/inside_route_spec.rb' - - 'spec/grape/validations/validators/coerce_spec.rb' - - 'spec/grape/validations_spec.rb' - # Offense count: 18 # Configuration parameters: AllowedPatterns. # AllowedPatterns: ^expect_, ^assert_ diff --git a/spec/support/endpoint_faker.rb b/spec/support/endpoint_faker.rb index 1cf02ef1dd..773eb85a30 100644 --- a/spec/support/endpoint_faker.rb +++ b/spec/support/endpoint_faker.rb @@ -4,8 +4,7 @@ module Spec module Support class EndpointFaker class FakerAPI < Grape::API - get '/' do - end + get('/') end def initialize(app, endpoint = FakerAPI.endpoints.first) From 90687444421c3ff12d4574caff5aa992af91bb23 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Tue, 26 Mar 2024 05:56:36 +0200 Subject: [PATCH 2/2] Fix most Lint/ConstantDefinitionInBlock and RSpec/LeakyConstantDeclaration offenses --- .rubocop_todo.yml | 53 +--- .../api/defines_boolean_in_params_spec.rb | 12 +- spec/grape/api/inherited_helpers_spec.rb | 30 ++- .../grape/api/mount_and_helpers_order_spec.rb | 165 ++++++++----- spec/grape/api/mount_and_rescue_from_spec.rb | 67 ++--- spec/grape/api/nested_helpers_spec.rb | 24 +- spec/grape/api/patch_method_helpers_spec.rb | 27 +- spec/grape/api_spec.rb | 233 +++++++++--------- spec/grape/entity_spec.rb | 18 +- spec/grape/loading_spec.rb | 11 +- spec/grape/middleware/base_spec.rb | 31 ++- spec/grape/middleware/error_spec.rb | 30 +-- spec/grape/middleware/exception_spec.rb | 10 +- spec/grape/middleware/formatter_spec.rb | 4 +- spec/grape/middleware/stack_spec.rb | 87 ++++--- spec/grape/validations/params_scope_spec.rb | 7 +- spec/grape/validations/types_spec.rb | 15 +- .../validations/validators/coerce_spec.rb | 20 +- .../validations/validators/presence_spec.rb | 4 +- .../validations/validators/values_spec.rb | 31 ++- 20 files changed, 450 insertions(+), 429 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index afdefec250..3a11f910ba 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 5000` -# on 2024-03-26 00:06:40 UTC using RuboCop version 1.59.0. +# on 2024-03-26 03:54:44 UTC using RuboCop version 1.59.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -21,30 +21,12 @@ Lint/AmbiguousBlockAssociation: Exclude: - 'spec/grape/dsl/routing_spec.rb' -# Offense count: 55 +# Offense count: 1 # Configuration parameters: AllowedMethods. # AllowedMethods: enums Lint/ConstantDefinitionInBlock: Exclude: - - 'spec/grape/api/defines_boolean_in_params_spec.rb' - - 'spec/grape/api/inherited_helpers_spec.rb' - - 'spec/grape/api/mount_and_helpers_order_spec.rb' - - 'spec/grape/api/mount_and_rescue_from_spec.rb' - - 'spec/grape/api/nested_helpers_spec.rb' - - 'spec/grape/api/patch_method_helpers_spec.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/entity_spec.rb' - - 'spec/grape/loading_spec.rb' - - 'spec/grape/middleware/base_spec.rb' - - 'spec/grape/middleware/error_spec.rb' - - 'spec/grape/middleware/formatter_spec.rb' - - 'spec/grape/middleware/stack_spec.rb' - - 'spec/grape/validations/params_scope_spec.rb' - - 'spec/grape/validations/types_spec.rb' - - 'spec/grape/validations/validators/coerce_spec.rb' - 'spec/grape/validations/validators/except_values_spec.rb' - - 'spec/grape/validations/validators/presence_spec.rb' - - 'spec/grape/validations/validators/values_spec.rb' # Offense count: 3 # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches. @@ -52,14 +34,11 @@ Lint/DuplicateBranch: Exclude: - 'spec/support/versioned_helpers.rb' -# Offense count: 5 +# Offense count: 1 # Configuration parameters: AllowComments. Lint/EmptyClass: Exclude: - 'lib/grape/dsl/parameters.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/entity_spec.rb' - - 'spec/grape/middleware/stack_spec.rb' # Offense count: 6 # Configuration parameters: AllowedParentClasses. @@ -107,7 +86,7 @@ Naming/VariableNumber: - 'spec/grape/exceptions/validation_errors_spec.rb' - 'spec/grape/validations_spec.rb' -# Offense count: 4 +# Offense count: 2 RSpec/AnyInstance: Exclude: - 'spec/grape/api_spec.rb' @@ -156,11 +135,10 @@ RSpec/IndexedLet: - 'spec/grape/presenters/presenter_spec.rb' - 'spec/shared/versioning_examples.rb' -# Offense count: 44 +# Offense count: 39 # Configuration parameters: AssignmentOnly. RSpec/InstanceVariable: Exclude: - - 'spec/grape/api/mount_and_helpers_order_spec.rb' - 'spec/grape/api_spec.rb' - 'spec/grape/endpoint_spec.rb' - 'spec/grape/middleware/base_spec.rb' @@ -168,29 +146,10 @@ RSpec/InstanceVariable: - 'spec/grape/middleware/versioner/header_spec.rb' - 'spec/grape/validations/validators/except_values_spec.rb' -# Offense count: 97 +# Offense count: 6 RSpec/LeakyConstantDeclaration: Exclude: - - 'spec/grape/api/defines_boolean_in_params_spec.rb' - - 'spec/grape/api/inherited_helpers_spec.rb' - - 'spec/grape/api/mount_and_helpers_order_spec.rb' - - 'spec/grape/api/mount_and_rescue_from_spec.rb' - - 'spec/grape/api/nested_helpers_spec.rb' - - 'spec/grape/api/patch_method_helpers_spec.rb' - - 'spec/grape/api_spec.rb' - - 'spec/grape/entity_spec.rb' - - 'spec/grape/loading_spec.rb' - - 'spec/grape/middleware/base_spec.rb' - - 'spec/grape/middleware/error_spec.rb' - - 'spec/grape/middleware/exception_spec.rb' - - 'spec/grape/middleware/formatter_spec.rb' - - 'spec/grape/middleware/stack_spec.rb' - - 'spec/grape/validations/params_scope_spec.rb' - - 'spec/grape/validations/types_spec.rb' - - 'spec/grape/validations/validators/coerce_spec.rb' - 'spec/grape/validations/validators/except_values_spec.rb' - - 'spec/grape/validations/validators/presence_spec.rb' - - 'spec/grape/validations/validators/values_spec.rb' # Offense count: 2 RSpec/MessageChain: diff --git a/spec/grape/api/defines_boolean_in_params_spec.rb b/spec/grape/api/defines_boolean_in_params_spec.rb index e1f31332d9..6d35049cfb 100644 --- a/spec/grape/api/defines_boolean_in_params_spec.rb +++ b/spec/grape/api/defines_boolean_in_params_spec.rb @@ -2,10 +2,10 @@ describe Grape::API::Instance do describe 'boolean constant' do - module DefinesBooleanInstanceSpec - class API < Grape::API + let(:app) do + Class.new(Grape::API) do params do - requires :message, type: Boolean + requires :message, type: Grape::API::Boolean end post :echo do { class: params[:message].class.name, value: params[:message] } @@ -13,10 +13,6 @@ class API < Grape::API end end - def app - DefinesBooleanInstanceSpec::API - end - let(:expected_body) do { class: 'TrueClass', value: true }.to_s end @@ -28,7 +24,7 @@ def app end context 'Params endpoint type' do - subject { DefinesBooleanInstanceSpec::API.new.router.map['POST'].first.options[:params]['message'][:type] } + subject { app.new.router.map['POST'].first.options[:params]['message'][:type] } it 'params type is a boolean' do expect(subject).to eq 'Grape::API::Boolean' diff --git a/spec/grape/api/inherited_helpers_spec.rb b/spec/grape/api/inherited_helpers_spec.rb index 0b7933cb9e..49597bc5be 100644 --- a/spec/grape/api/inherited_helpers_spec.rb +++ b/spec/grape/api/inherited_helpers_spec.rb @@ -3,9 +3,8 @@ describe Grape::API::Helpers do let(:user) { 'Miguel Caneo' } let(:id) { '42' } - - module InheritedHelpersSpec - class SuperClass < Grape::API + let(:api_super_class) do + Class.new(Grape::API) do helpers do params(:superclass_params) { requires :id, type: String } @@ -14,8 +13,9 @@ def current_user end end end - - class OverriddenSubClass < SuperClass + end + let(:api_overridden_sub_class) do + Class.new(api_super_class) do params { use :superclass_params } helpers do @@ -28,16 +28,18 @@ def current_user "#{current_user}: #{params['id']}" end end - - class SubClass < SuperClass + end + let(:api_sub_class) do + Class.new(api_super_class) do params { use :superclass_params } get 'resource' do "#{current_user}: #{params['id']}" end end - - class Example < SubClass + end + let(:api_example) do + Class.new(api_sub_class) do params { use :superclass_params } get 'resource' do @@ -47,7 +49,7 @@ class Example < SubClass end context 'non overriding subclass' do - subject { InheritedHelpersSpec::SubClass } + subject { api_sub_class } def app subject @@ -69,10 +71,8 @@ def app end context 'overriding subclass' do - subject { InheritedHelpersSpec::OverriddenSubClass } - def app - subject + api_overridden_sub_class end context 'given expected params' do @@ -91,10 +91,8 @@ def app end context 'example subclass' do - subject { InheritedHelpersSpec::Example } - def app - subject + api_example end context 'given expected params' do diff --git a/spec/grape/api/mount_and_helpers_order_spec.rb b/spec/grape/api/mount_and_helpers_order_spec.rb index a00423a14f..3485a820e8 100644 --- a/spec/grape/api/mount_and_helpers_order_spec.rb +++ b/spec/grape/api/mount_and_helpers_order_spec.rb @@ -1,31 +1,35 @@ # frozen_string_literal: true describe Grape::API do - def app - subject - end - describe 'rescue_from' do context 'when the API is mounted AFTER defining the class rescue_from handler' do - class APIRescueFrom < Grape::API - rescue_from :all do - error!({ type: 'all' }, 404) - end - - get do - { count: 1 / 0 } + let(:api_rescue_from) do + Class.new(Grape::API) do + rescue_from :all do + error!({ type: 'all' }, 404) + end + + get do + { count: 1 / 0 } + end end end - class MainRescueFromAfter < Grape::API - rescue_from ZeroDivisionError do - error!({ type: 'zero' }, 500) - end + let(:main_rescue_from_after) do + context = self - mount APIRescueFrom + Class.new(Grape::API) do + rescue_from ZeroDivisionError do + error!({ type: 'zero' }, 500) + end + + mount context.api_rescue_from + end end - subject { MainRescueFromAfter } + def app + main_rescue_from_after + end it 'is rescued by the rescue_from ZeroDivisionError handler from Main class' do get '/' @@ -36,25 +40,32 @@ class MainRescueFromAfter < Grape::API end context 'when the API is mounted BEFORE defining the class rescue_from handler' do - class APIRescueFrom < Grape::API - rescue_from :all do - error!({ type: 'all' }, 404) - end - - get do - { count: 1 / 0 } + let(:api_rescue_from) do + Class.new(Grape::API) do + rescue_from :all do + error!({ type: 'all' }, 404) + end + + get do + { count: 1 / 0 } + end end end + let(:main_rescue_from_before) do + context = self - class MainRescueFromBefore < Grape::API - mount APIRescueFrom + Class.new(Grape::API) do + mount context.api_rescue_from - rescue_from ZeroDivisionError do - error!({ type: 'zero' }, 500) + rescue_from ZeroDivisionError do + error!({ type: 'zero' }, 500) + end end end - subject { MainRescueFromBefore } + def app + main_rescue_from_before + end it 'is rescued by the rescue_from ZeroDivisionError handler from Main class' do get '/' @@ -67,21 +78,28 @@ class MainRescueFromBefore < Grape::API describe 'before' do context 'when the API is mounted AFTER defining the before helper' do - class APIBeforeHandler < Grape::API - get do - { count: @count }.to_json + let(:api_before_handler) do + Class.new(Grape::API) do + get do + { count: @count }.to_json + end end end + let(:main_before_handler_after) do + context = self - class MainBeforeHandlerAfter < Grape::API - before do - @count = 1 - end + Class.new(Grape::API) do + before do + @count = 1 + end - mount APIBeforeHandler + mount context.api_before_handler + end end - subject { MainBeforeHandlerAfter } + def app + main_before_handler_after + end it 'is able to access the variables defined in the before helper' do get '/' @@ -92,21 +110,28 @@ class MainBeforeHandlerAfter < Grape::API end context 'when the API is mounted BEFORE defining the before helper' do - class APIBeforeHandler < Grape::API - get do - { count: @count }.to_json + let(:api_before_handler) do + Class.new(Grape::API) do + get do + { count: @count }.to_json + end end end + let(:main_before_handler_before) do + context = self - class MainBeforeHandlerBefore < Grape::API - mount APIBeforeHandler + Class.new(Grape::API) do + mount context.api_before_handler - before do - @count = 1 + before do + @count = 1 + end end end - subject { MainBeforeHandlerBefore } + def app + main_before_handler_before + end it 'is able to access the variables defined in the before helper' do get '/' @@ -119,21 +144,28 @@ class MainBeforeHandlerBefore < Grape::API describe 'after' do context 'when the API is mounted AFTER defining the after handler' do - class APIAfterHandler < Grape::API - get do - { count: 1 }.to_json + let(:api_after_handler) do + Class.new(Grape::API) do + get do + { count: 1 }.to_json + end end end + let(:main_after_handler_after) do + context = self - class MainAfterHandlerAfter < Grape::API - after do - error!({ type: 'after' }, 500) - end + Class.new(Grape::API) do + after do + error!({ type: 'after' }, 500) + end - mount APIAfterHandler + mount context.api_after_handler + end end - subject { MainAfterHandlerAfter } + def app + main_after_handler_after + end it 'is able to access the variables defined in the after helper' do get '/' @@ -144,21 +176,28 @@ class MainAfterHandlerAfter < Grape::API end context 'when the API is mounted BEFORE defining the after helper' do - class APIAfterHandler < Grape::API - get do - { count: 1 }.to_json + let(:api_after_handler) do + Class.new(Grape::API) do + get do + { count: 1 }.to_json + end end end + let(:main_after_handler_before) do + context = self - class MainAfterHandlerBefore < Grape::API - mount APIAfterHandler + Class.new(Grape::API) do + mount context.api_after_handler - after do - error!({ type: 'after' }, 500) + after do + error!({ type: 'after' }, 500) + end end end - subject { MainAfterHandlerBefore } + def app + main_after_handler_before + end it 'is able to access the variables defined in the after helper' do get '/' diff --git a/spec/grape/api/mount_and_rescue_from_spec.rb b/spec/grape/api/mount_and_rescue_from_spec.rb index 0dfc4a35d7..1289a7134d 100644 --- a/spec/grape/api/mount_and_rescue_from_spec.rb +++ b/spec/grape/api/mount_and_rescue_from_spec.rb @@ -1,38 +1,42 @@ # frozen_string_literal: true describe Grape::API do - def app - subject - end - context 'when multiple classes defines the same rescue_from' do - class AnAPI < Grape::API - rescue_from ZeroDivisionError do - error!({ type: 'an-api-zero' }, 404) - end + let(:an_api) do + Class.new(Grape::API) do + rescue_from ZeroDivisionError do + error!({ type: 'an-api-zero' }, 404) + end - get '/an-api' do - { count: 1 / 0 } + get '/an-api' do + { count: 1 / 0 } + end end end + let(:another_api) do + Class.new(Grape::API) do + rescue_from ZeroDivisionError do + error!({ type: 'another-api-zero' }, 322) + end - class AnotherAPI < Grape::API - rescue_from ZeroDivisionError do - error!({ type: 'another-api-zero' }, 322) + get '/another-api' do + { count: 1 / 0 } + end end + end + let(:other_main) do + context = self - get '/another-api' do - { count: 1 / 0 } + Class.new(Grape::API) do + mount context.an_api + mount context.another_api end end - class OtherMain < Grape::API - mount AnAPI - mount AnotherAPI + def app + other_main end - subject { OtherMain } - it 'is rescued by the rescue_from ZeroDivisionError handler defined inside each of the classes' do get '/an-api' @@ -46,19 +50,26 @@ class OtherMain < Grape::API end context 'when some class does not define a rescue_from but it was defined in a previous mounted endpoint' do - class AnAPIWithoutDefinedRescueFrom < Grape::API - get '/another-api-without-defined-rescue-from' do - { count: 1 / 0 } + let(:an_api_without_defined_rescue_from) do + Class.new(Grape::API) do + get '/another-api-without-defined-rescue-from' do + { count: 1 / 0 } + end end end + let(:other_main_with_not_defined_rescue_from) do + context = self - class OtherMainWithNotDefinedRescueFrom < Grape::API - mount AnAPI - mount AnotherAPI - mount AnAPIWithoutDefinedRescueFrom + Class.new(Grape::API) do + mount context.an_api + mount context.another_api + mount context.an_api_without_defined_rescue_from + end end - subject { OtherMainWithNotDefinedRescueFrom } + def app + other_main_with_not_defined_rescue_from + end it 'is not rescued by any of the previous defined rescue_from ZeroDivisionError handlers' do get '/an-api' diff --git a/spec/grape/api/nested_helpers_spec.rb b/spec/grape/api/nested_helpers_spec.rb index 2acddbcf0d..77975f4342 100644 --- a/spec/grape/api/nested_helpers_spec.rb +++ b/spec/grape/api/nested_helpers_spec.rb @@ -1,17 +1,20 @@ # frozen_string_literal: true describe Grape::API::Helpers do - module NestedHelpersSpec - module HelperMethods + let(:helper_methods) do + Module.new do extend Grape::API::Helpers def current_user @current_user ||= params[:current_user] end end + end + let(:nested) do + context = self - class Nested < Grape::API + Class.new(Grape::API) do resource :level1 do - helpers HelperMethods + helpers context.helper_methods get do current_user @@ -24,18 +27,17 @@ class Nested < Grape::API end end end - - class Main < Grape::API - mount Nested - end end + let(:main) do + context = self - subject do - NestedHelpersSpec::Main + Class.new(Grape::API) do + mount context.nested + end end def app - subject + main end it 'can access helpers from a mounted resource' do diff --git a/spec/grape/api/patch_method_helpers_spec.rb b/spec/grape/api/patch_method_helpers_spec.rb index 23b4338e73..ad0a162bab 100644 --- a/spec/grape/api/patch_method_helpers_spec.rb +++ b/spec/grape/api/patch_method_helpers_spec.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true describe Grape::API::Helpers do - module PatchHelpersSpec - class PatchPublic < Grape::API + let(:patch_public) do + Class.new(Grape::API) do format :json version 'public-v1', using: :header, vendor: 'grape' @@ -10,16 +10,20 @@ class PatchPublic < Grape::API { ok: 'public' } end end - - module AuthMethods + end + let(:auth_methods) do + Module.new do def authenticate!; end end + end + let(:patch_private) do + context = self - class PatchPrivate < Grape::API + Class.new(Grape::API) do format :json version 'private-v1', using: :header, vendor: 'grape' - helpers AuthMethods + helpers context.auth_methods before do authenticate! @@ -29,15 +33,18 @@ class PatchPrivate < Grape::API { ok: 'private' } end end + end + let(:main) do + context = self - class Main < Grape::API - mount PatchPublic - mount PatchPrivate + Class.new(Grape::API) do + mount context.patch_public + mount context.patch_private end end def app - PatchHelpersSpec::Main + main end context 'patch' do diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 95b46079c8..f8bb785ff6 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'shared/versioning_examples' +require 'grape-entity' describe Grape::API do subject do @@ -369,17 +370,19 @@ def subject.enable_root_route! end context 'format' do - module ApiSpec - class DummyFormatClass - end - end - before do - allow_any_instance_of(ApiSpec::DummyFormatClass).to receive(:to_json).and_return('abc') - allow_any_instance_of(ApiSpec::DummyFormatClass).to receive(:to_txt).and_return('def') + dummy_class = Class.new do + def to_json(*_rest) + 'abc' + end + + def to_txt + 'def' + end + end subject.get('/abc') do - ApiSpec::DummyFormatClass.new + dummy_class.new end end @@ -1369,8 +1372,8 @@ class DummyFormatClass end context 'custom middleware' do - module ApiSpec - class PhonyMiddleware + let(:phony_middleware) do + Class.new do def initialize(app, *args) @args = args @app = app @@ -1388,43 +1391,44 @@ def call(env) describe '.middleware' do it 'includes middleware arguments from settings' do - subject.use ApiSpec::PhonyMiddleware, 'abc', 123 - expect(subject.middleware).to eql [[:use, ApiSpec::PhonyMiddleware, 'abc', 123]] + subject.use phony_middleware, 'abc', 123 + expect(subject.middleware).to eql [[:use, phony_middleware, 'abc', 123]] end it 'includes all middleware from stacked settings' do - subject.use ApiSpec::PhonyMiddleware, 123 - subject.use ApiSpec::PhonyMiddleware, 'abc' - subject.use ApiSpec::PhonyMiddleware, 'foo' + subject.use phony_middleware, 123 + subject.use phony_middleware, 'abc' + subject.use phony_middleware, 'foo' expect(subject.middleware).to eql [ - [:use, ApiSpec::PhonyMiddleware, 123], - [:use, ApiSpec::PhonyMiddleware, 'abc'], - [:use, ApiSpec::PhonyMiddleware, 'foo'] + [:use, phony_middleware, 123], + [:use, phony_middleware, 'abc'], + [:use, phony_middleware, 'foo'] ] end end describe '.use' do it 'adds middleware' do - subject.use ApiSpec::PhonyMiddleware, 123 - expect(subject.middleware).to eql [[:use, ApiSpec::PhonyMiddleware, 123]] + subject.use phony_middleware, 123 + expect(subject.middleware).to eql [[:use, phony_middleware, 123]] end it 'does not show up outside the namespace' do + example = self inner_middleware = nil - subject.use ApiSpec::PhonyMiddleware, 123 + subject.use phony_middleware, 123 subject.namespace :awesome do - use ApiSpec::PhonyMiddleware, 'abc' + use example.phony_middleware, 'abc' inner_middleware = middleware end - expect(subject.middleware).to eql [[:use, ApiSpec::PhonyMiddleware, 123]] - expect(inner_middleware).to eql [[:use, ApiSpec::PhonyMiddleware, 123], [:use, ApiSpec::PhonyMiddleware, 'abc']] + expect(subject.middleware).to eql [[:use, phony_middleware, 123]] + expect(inner_middleware).to eql [[:use, phony_middleware, 123], [:use, phony_middleware, 'abc']] end it 'calls the middleware' do - subject.use ApiSpec::PhonyMiddleware, 'hello' + subject.use phony_middleware, 'hello' subject.get '/' do env['phony.args'].first.first end @@ -1435,13 +1439,13 @@ def call(env) it 'adds a block if one is given' do block = -> {} - subject.use ApiSpec::PhonyMiddleware, &block - expect(subject.middleware).to eql [[:use, ApiSpec::PhonyMiddleware, block]] + subject.use phony_middleware, &block + expect(subject.middleware).to eql [[:use, phony_middleware, block]] end it 'uses a block if one is given' do block = -> {} - subject.use ApiSpec::PhonyMiddleware, &block + subject.use phony_middleware, &block subject.get '/' do env['phony.block'].inspect end @@ -1452,7 +1456,7 @@ def call(env) it 'does not destroy the middleware settings on multiple runs' do block = -> {} - subject.use ApiSpec::PhonyMiddleware, &block + subject.use phony_middleware, &block subject.get '/' do env['phony.block'].inspect end @@ -1488,8 +1492,8 @@ def call(env) end end - subject.use ApiSpec::PhonyMiddleware, 'hello' - subject.insert_before ApiSpec::PhonyMiddleware, m, message: 'bye' + subject.use phony_middleware, 'hello' + subject.insert_before phony_middleware, m, message: 'bye' subject.get '/' do env['phony.args'].join(' ') end @@ -1509,8 +1513,8 @@ def call(env) end end - subject.use ApiSpec::PhonyMiddleware, 'hello' - subject.insert_after ApiSpec::PhonyMiddleware, m, message: 'bye' + subject.use phony_middleware, 'hello' + subject.insert_after phony_middleware, m, message: 'bye' subject.get '/' do env['phony.args'].join(' ') end @@ -1519,27 +1523,27 @@ def call(env) expect(last_response.body).to eql 'hello bye' end end - end - describe '.insert' do - it 'inserts middleware in a specific location in the stack' do - m = Class.new(Grape::Middleware::Base) do - def call(env) - env['phony.args'] ||= [] - env['phony.args'] << @options[:message] - @app.call(env) + describe '.insert' do + it 'inserts middleware in a specific location in the stack' do + m = Class.new(Grape::Middleware::Base) do + def call(env) + env['phony.args'] ||= [] + env['phony.args'] << @options[:message] + @app.call(env) + end end - end - subject.use ApiSpec::PhonyMiddleware, 'bye' - subject.insert 0, m, message: 'good' - subject.insert 0, m, message: 'hello' - subject.get '/' do - env['phony.args'].join(' ') - end + subject.use phony_middleware, 'bye' + subject.insert 0, m, message: 'good' + subject.insert 0, m, message: 'hello' + subject.get '/' do + env['phony.args'].join(' ') + end - get '/' - expect(last_response.body).to eql 'hello good bye' + get '/' + expect(last_response.body).to eql 'hello good bye' + end end end @@ -2089,9 +2093,7 @@ def foo context 'CustomError subclass of Grape::Exceptions::Base' do before do - module ApiSpec - class CustomError < Grape::Exceptions::Base; end - end + stub_const('ApiSpec::CustomError', Class.new(Grape::Exceptions::Base)) end it 'does not re-raise exceptions of type Grape::Exceptions::Base' do @@ -2155,11 +2157,9 @@ class CustomError < Grape::Exceptions::Base; end context 'custom errors' do before do - class ConnectionError < RuntimeError; end - - class DatabaseError < RuntimeError; end - - class CommunicationError < StandardError; end + stub_const('ConnectionError', Class.new(RuntimeError)) + stub_const('DatabaseError', Class.new(RuntimeError)) + stub_const('CommunicationError', Class.new(StandardError)) end it 'rescues an error via rescue_from :all' do @@ -2315,13 +2315,9 @@ def rescue_all_errors describe '.rescue_from klass, rescue_subclasses: boolean' do before do - module ApiSpec - module APIErrors - class ParentError < StandardError; end - - class ChildError < ParentError; end - end - end + parent_error = Class.new(StandardError) + stub_const('ApiSpec::APIErrors::ParentError', parent_error) + stub_const('ApiSpec::APIErrors::ChildError', Class.new(parent_error)) end it 'rescues error as well as subclass errors with rescue_subclasses option set' do @@ -2449,47 +2445,30 @@ class ChildError < ParentError; end end context 'class' do - before do - module ApiSpec - class CustomErrorFormatter - def self.call(message, _backtrace, _options, _env, _original_exception) - "message: #{message} @backtrace" - end + let(:custom_error_formatter) do + Class.new do + def self.call(message, _backtrace, _options, _env, _original_exception) + "message: #{message} @backtrace" end end end it 'returns a custom error format' do subject.rescue_from :all, backtrace: true - subject.error_formatter :txt, ApiSpec::CustomErrorFormatter - subject.get '/exception' do - raise 'rain!' - end + subject.error_formatter :txt, custom_error_formatter + subject.get('/exception') { raise 'rain!' } + get '/exception' expect(last_response.body).to eq('message: rain! @backtrace') end - end - - describe 'with' do - context 'class' do - before do - module ApiSpec - class CustomErrorFormatter - def self.call(message, _backtrace, _option, _env, _original_exception) - "message: #{message} @backtrace" - end - end - end - end - it 'returns a custom error format' do - subject.rescue_from :all, backtrace: true - subject.error_formatter :txt, with: ApiSpec::CustomErrorFormatter - subject.get('/exception') { raise 'rain!' } + it 'returns a custom error format (using keyword :with)' do + subject.rescue_from :all, backtrace: true + subject.error_formatter :txt, with: custom_error_formatter + subject.get('/exception') { raise 'rain!' } - get '/exception' - expect(last_response.body).to eq('message: rain! @backtrace') - end + get '/exception' + expect(last_response.body).to eq('message: rain! @backtrace') end end @@ -2619,17 +2598,18 @@ def self.call(message, _backtrace, _option, _env, _original_exception) end context 'custom formatter class' do - module ApiSpec - module CustomFormatter + let(:custom_formatter) do + Module.new do def self.call(object, _env) "{\"custom_formatter\":\"#{object[:some]}\"}" end end end + before do subject.content_type :json, 'application/json' subject.content_type :custom, 'application/custom' - subject.formatter :custom, ApiSpec::CustomFormatter + subject.formatter :custom, custom_formatter subject.get :simple do { some: 'hash' } end @@ -2678,17 +2658,18 @@ def self.call(object, _env) end context 'custom parser class' do - module ApiSpec - module CustomParser + let(:custom_parser) do + Module.new do def self.call(object, _env) { object.to_sym => object.to_s.reverse } end end end + before do subject.content_type :txt, 'text/plain' subject.content_type :custom, 'text/custom' - subject.parser :custom, ApiSpec::CustomParser + subject.parser :custom, custom_parser subject.put :simple do params[:simple] end @@ -3471,15 +3452,15 @@ def static end it 'mounts on a nested path' do - APP1 = Class.new(described_class) - APP2 = Class.new(described_class) - APP2.get '/nice' do + app1 = Class.new(described_class) + app2 = Class.new(described_class) + app2.get '/nice' do 'play' end # NOTE: that the reverse won't work, mount from outside-in - APP3 = subject - APP3.mount APP1 => '/app1' - APP1.mount APP2 => '/app2' + app3 = subject + app3.mount app1 => '/app1' + app1.mount app2 => '/app2' get '/app1/app2/nice' expect(last_response.status).to eq(200) expect(last_response.body).to eq('play') @@ -3667,13 +3648,18 @@ def static def self.included(base) base.extend(ClassMethods) end + end + end - module ClassMethods + before do + stub_const( + 'ClassMethods', + Module.new do def my_method @test = true end end - end + ) end it 'correctlies include module in nested mount' do @@ -3892,13 +3878,16 @@ def before end context ':serializable_hash' do - class SerializableHashExample - def serializable_hash - { abc: 'def' } - end - end - before do + stub_const( + 'SerializableHashExample', + Class.new do + def serializable_hash + { abc: 'def' } + end + end + ) + subject.format :serializable_hash end @@ -4231,17 +4220,21 @@ def self.inherited(child_api) end context 'overriding via composition' do - module Inherited - def inherited(api) - super - api.instance_variable_set(:@foo, @bar.dup) + let(:inherited) do + Module.new do + def inherited(api) + super + api.instance_variable_set(:@foo, @bar.dup) + end end end let(:root_api) do + context = self + Class.new(described_class) do @bar = 'Hello, world' - extend Inherited + extend context.inherited end end diff --git a/spec/grape/entity_spec.rb b/spec/grape/entity_spec.rb index 7eaa0fae87..d5eaf367fe 100644 --- a/spec/grape/entity_spec.rb +++ b/spec/grape/entity_spec.rb @@ -46,24 +46,20 @@ def app entity = Class.new(described_class) allow(entity).to receive(:represent).and_return('Hiya') - module EntitySpec - class TestObject - end - - class FakeCollection - def first - TestObject.new - end + test_object_class = Class.new + fake_collection_class = Class.new do + define_method(:first) do + test_object_class.new end end - subject.represent EntitySpec::TestObject, with: entity + subject.represent test_object_class, with: entity subject.get '/example' do - present [EntitySpec::TestObject.new] + present [test_object_class.new] end subject.get '/example2' do - present EntitySpec::FakeCollection.new + present fake_collection_class.new end get '/example' diff --git a/spec/grape/loading_spec.rb b/spec/grape/loading_spec.rb index 767a0b7934..f091fef856 100644 --- a/spec/grape/loading_spec.rb +++ b/spec/grape/loading_spec.rb @@ -2,10 +2,11 @@ describe Grape::API do subject do - CombinedApi = combined_api + context = self + Class.new(Grape::API) do format :json - mount CombinedApi => '/' + mount context.combined_api => '/' end end @@ -16,6 +17,7 @@ namespace :three do get :one do end + get :two do end end @@ -25,10 +27,11 @@ end let(:combined_api) do - JobsApi = jobs_api + context = self + Class.new(Grape::API) do version :v1, using: :accept_version_header, cascade: true - mount JobsApi + mount context.jobs_api end end diff --git a/spec/grape/middleware/base_spec.rb b/spec/grape/middleware/base_spec.rb index 3be95be1f5..bb3b2d6b8a 100644 --- a/spec/grape/middleware/base_spec.rb +++ b/spec/grape/middleware/base_spec.rb @@ -139,8 +139,8 @@ end context 'defaults' do - module BaseSpec - class ExampleWare < Grape::Middleware::Base + let(:example_ware) do + Class.new(Grape::Middleware::Base) do def default_options { monkey: true } end @@ -148,18 +148,18 @@ def default_options end it 'persists the default options' do - expect(BaseSpec::ExampleWare.new(blank_app).options[:monkey]).to be true + expect(example_ware.new(blank_app).options[:monkey]).to be true end it 'overrides default options when provided' do - expect(BaseSpec::ExampleWare.new(blank_app, monkey: false).options[:monkey]).to be false + expect(example_ware.new(blank_app, monkey: false).options[:monkey]).to be false end end end context 'header' do - module HeaderSpec - class ExampleWare < Grape::Middleware::Base + let(:example_ware) do + Class.new(Grape::Middleware::Base) do def before header 'X-Test-Before', 'Hi' end @@ -172,8 +172,10 @@ def after end def app + context = self + Rack::Builder.app do - use HeaderSpec::ExampleWare + use context.example_ware run ->(_) { [200, {}, ['Yeah']] } end end @@ -186,8 +188,8 @@ def app end context 'header overwrite' do - module HeaderOverwritingSpec - class ExampleWare < Grape::Middleware::Base + let(:example_ware) do + Class.new(Grape::Middleware::Base) do def before header 'X-Test-Overwriting', 'Hi' end @@ -197,8 +199,9 @@ def after nil end end - - class API < Grape::API + end + let(:api) do + Class.new(Grape::API) do get('/') do header 'X-Test-Overwriting', 'Yeah' 'Hello' @@ -207,9 +210,11 @@ class API < Grape::API end def app + context = self + Rack::Builder.app do - use HeaderOverwritingSpec::ExampleWare - run HeaderOverwritingSpec::API.new + use context.example_ware + run context.api.new end end diff --git a/spec/grape/middleware/error_spec.rb b/spec/grape/middleware/error_spec.rb index d056ca7e2a..08ae7d460b 100644 --- a/spec/grape/middleware/error_spec.rb +++ b/spec/grape/middleware/error_spec.rb @@ -3,8 +3,8 @@ require 'grape-entity' describe Grape::Middleware::Error do - module ErrorSpec - class ErrorEntity < Grape::Entity + let(:error_entity) do + Class.new(Grape::Entity) do expose :code expose :static @@ -12,8 +12,9 @@ def static 'static text' end end - - class ErrApp + end + let(:err_app) do + Class.new do class << self attr_accessor :error, :format @@ -23,44 +24,44 @@ def call(_env) end end end + let(:options) { { default_message: 'Aww, hamburgers.' } } def app opts = options + context = self Rack::Builder.app do use Spec::Support::EndpointFaker use Grape::Middleware::Error, **opts - run ErrorSpec::ErrApp + run context.err_app end end - let(:options) { { default_message: 'Aww, hamburgers.' } } - it 'sets the status code appropriately' do - ErrorSpec::ErrApp.error = { status: 410 } + err_app.error = { status: 410 } get '/' expect(last_response.status).to eq(410) end it 'sets the status code based on the rack util status code symbol' do - ErrorSpec::ErrApp.error = { status: :gone } + err_app.error = { status: :gone } get '/' expect(last_response.status).to eq(410) end it 'sets the error message appropriately' do - ErrorSpec::ErrApp.error = { message: 'Awesome stuff.' } + err_app.error = { message: 'Awesome stuff.' } get '/' expect(last_response.body).to eq('Awesome stuff.') end it 'defaults to a 500 status' do - ErrorSpec::ErrApp.error = {} + err_app.error = {} get '/' expect(last_response.status).to eq(500) end it 'has a default message' do - ErrorSpec::ErrApp.error = {} + err_app.error = {} get '/' expect(last_response.body).to eq('Aww, hamburgers.') end @@ -69,14 +70,15 @@ def app let(:options) { { default_message: 'Aww, hamburgers.' } } it 'adds the status code if wanted' do - ErrorSpec::ErrApp.error = { message: { code: 200 } } + err_app.error = { message: { code: 200 } } get '/' expect(last_response.body).to eq({ code: 200 }.to_json) end it 'presents an error message' do - ErrorSpec::ErrApp.error = { message: { code: 200, with: ErrorSpec::ErrorEntity } } + entity = error_entity + err_app.error = { message: { code: 200, with: entity } } get '/' expect(last_response.body).to eq({ code: 200, static: 'static text' }.to_json) diff --git a/spec/grape/middleware/exception_spec.rb b/spec/grape/middleware/exception_spec.rb index 18d8bff8b2..bc28fa5625 100644 --- a/spec/grape/middleware/exception_spec.rb +++ b/spec/grape/middleware/exception_spec.rb @@ -22,13 +22,11 @@ def call(_env) end let(:custom_error_app) do - Class.new do - class << self - class CustomError < Grape::Exceptions::Base; end + custom_error = Class.new(Grape::Exceptions::Base) - def call(_env) - raise CustomError.new(status: 400, message: 'failed validation') - end + Class.new do + define_singleton_method(:call) do |_env| + raise custom_error.new(status: 400, message: 'failed validation') end end end diff --git a/spec/grape/middleware/formatter_spec.rb b/spec/grape/middleware/formatter_spec.rb index 025ab42a5c..20600f9d44 100644 --- a/spec/grape/middleware/formatter_spec.rb +++ b/spec/grape/middleware/formatter_spec.rb @@ -257,13 +257,13 @@ def to_xml context 'no content responses' do let(:no_content_response) { ->(status) { [status, {}, ['']] } } - STATUSES_WITHOUT_BODY = if Gem::Version.new(Rack.release) >= Gem::Version.new('2.1.0') + statuses_without_body = if Gem::Version.new(Rack.release) >= Gem::Version.new('2.1.0') Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.keys else Rack::Utils::STATUS_WITH_NO_ENTITY_BODY end - STATUSES_WITHOUT_BODY.each do |status| + statuses_without_body.each do |status| it "does not modify a #{status} response" do expected_response = no_content_response[status] allow(app).to receive(:call).and_return(expected_response) diff --git a/spec/grape/middleware/stack_spec.rb b/spec/grape/middleware/stack_spec.rb index 3325469fd0..d5d503a178 100644 --- a/spec/grape/middleware/stack_spec.rb +++ b/spec/grape/middleware/stack_spec.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true describe Grape::Middleware::Stack do - module StackSpec - class FooMiddleware; end - - class BarMiddleware; end + subject { described_class.new } - class BlockMiddleware + let(:foo_middleware) { Class.new } + let(:bar_middleware) { Class.new } + let(:block_middleware) do + Class.new do attr_reader :block def initialize(&block) @@ -14,34 +14,31 @@ def initialize(&block) end end end - - subject { described_class.new } - let(:proc) { -> {} } - let(:others) { [[:use, StackSpec::BarMiddleware], [:insert_before, StackSpec::BarMiddleware, StackSpec::BlockMiddleware, proc]] } + let(:others) { [[:use, bar_middleware], [:insert_before, bar_middleware, block_middleware, proc]] } before do - subject.use StackSpec::FooMiddleware + subject.use foo_middleware end describe '#use' do it 'pushes a middleware class onto the stack' do - expect { subject.use StackSpec::BarMiddleware } + expect { subject.use bar_middleware } .to change(subject, :size).by(1) - expect(subject.last).to eq(StackSpec::BarMiddleware) + expect(subject.last).to eq(bar_middleware) end it 'pushes a middleware class with arguments onto the stack' do - expect { subject.use StackSpec::BarMiddleware, false, my_arg: 42 } + expect { subject.use bar_middleware, false, my_arg: 42 } .to change(subject, :size).by(1) - expect(subject.last).to eq(StackSpec::BarMiddleware) + expect(subject.last).to eq(bar_middleware) expect(subject.last.args).to eq([false, { my_arg: 42 }]) end it 'pushes a middleware class with block arguments onto the stack' do - expect { subject.use StackSpec::BlockMiddleware, &proc } + expect { subject.use block_middleware, &proc } .to change(subject, :size).by(1) - expect(subject.last).to eq(StackSpec::BlockMiddleware) + expect(subject.last).to eq(block_middleware) expect(subject.last.args).to eq([]) expect(subject.last.block).to eq(proc) end @@ -49,57 +46,59 @@ def initialize(&block) describe '#insert' do it 'inserts a middleware class at the integer index' do - expect { subject.insert 0, StackSpec::BarMiddleware } + expect { subject.insert 0, bar_middleware } .to change(subject, :size).by(1) - expect(subject[0]).to eq(StackSpec::BarMiddleware) - expect(subject[1]).to eq(StackSpec::FooMiddleware) + expect(subject[0]).to eq(bar_middleware) + expect(subject[1]).to eq(foo_middleware) end end describe '#insert_before' do it 'inserts a middleware before another middleware class' do - expect { subject.insert_before StackSpec::FooMiddleware, StackSpec::BarMiddleware } + expect { subject.insert_before foo_middleware, bar_middleware } .to change(subject, :size).by(1) - expect(subject[0]).to eq(StackSpec::BarMiddleware) - expect(subject[1]).to eq(StackSpec::FooMiddleware) + expect(subject[0]).to eq(bar_middleware) + expect(subject[1]).to eq(foo_middleware) end it 'inserts a middleware before an anonymous class given by its superclass' do - subject.use Class.new(StackSpec::BlockMiddleware) + subject.use Class.new(block_middleware) - expect { subject.insert_before StackSpec::BlockMiddleware, StackSpec::BarMiddleware } + expect { subject.insert_before block_middleware, bar_middleware } .to change(subject, :size).by(1) - expect(subject[1]).to eq(StackSpec::BarMiddleware) - expect(subject[2]).to eq(StackSpec::BlockMiddleware) + expect(subject[1]).to eq(bar_middleware) + expect(subject[2]).to eq(block_middleware) end it 'raises an error on an invalid index' do - expect { subject.insert_before StackSpec::BlockMiddleware, StackSpec::BarMiddleware } + stub_const('StackSpec::BlockMiddleware', block_middleware) + expect { subject.insert_before block_middleware, bar_middleware } .to raise_error(RuntimeError, 'No such middleware to insert before: StackSpec::BlockMiddleware') end end describe '#insert_after' do it 'inserts a middleware after another middleware class' do - expect { subject.insert_after StackSpec::FooMiddleware, StackSpec::BarMiddleware } + expect { subject.insert_after foo_middleware, bar_middleware } .to change(subject, :size).by(1) - expect(subject[1]).to eq(StackSpec::BarMiddleware) - expect(subject[0]).to eq(StackSpec::FooMiddleware) + expect(subject[1]).to eq(bar_middleware) + expect(subject[0]).to eq(foo_middleware) end it 'inserts a middleware after an anonymous class given by its superclass' do - subject.use Class.new(StackSpec::BlockMiddleware) + subject.use Class.new(block_middleware) - expect { subject.insert_after StackSpec::BlockMiddleware, StackSpec::BarMiddleware } + expect { subject.insert_after block_middleware, bar_middleware } .to change(subject, :size).by(1) - expect(subject[1]).to eq(StackSpec::BlockMiddleware) - expect(subject[2]).to eq(StackSpec::BarMiddleware) + expect(subject[1]).to eq(block_middleware) + expect(subject[2]).to eq(bar_middleware) end it 'raises an error on an invalid index' do - expect { subject.insert_after StackSpec::BlockMiddleware, StackSpec::BarMiddleware } + stub_const('StackSpec::BlockMiddleware', block_middleware) + expect { subject.insert_after block_middleware, bar_middleware } .to raise_error(RuntimeError, 'No such middleware to insert after: StackSpec::BlockMiddleware') end end @@ -108,16 +107,16 @@ def initialize(&block) it 'applies a collection of operations and middlewares' do expect { subject.merge_with(others) } .to change(subject, :size).by(2) - expect(subject[0]).to eq(StackSpec::FooMiddleware) - expect(subject[1]).to eq(StackSpec::BlockMiddleware) - expect(subject[2]).to eq(StackSpec::BarMiddleware) + expect(subject[0]).to eq(foo_middleware) + expect(subject[1]).to eq(block_middleware) + expect(subject[2]).to eq(bar_middleware) end context 'middleware spec with proc declaration exists' do - let(:middleware_spec_with_proc) { [:use, StackSpec::FooMiddleware, proc] } + let(:middleware_spec_with_proc) { [:use, foo_middleware, proc] } it 'properly forwards spec arguments' do - expect(subject).to receive(:use).with(StackSpec::FooMiddleware) + expect(subject).to receive(:use).with(foo_middleware) subject.merge_with([middleware_spec_with_proc]) end end @@ -129,15 +128,15 @@ def initialize(&block) end context 'when @others are present' do - let(:others) { [[:insert_after, Grape::Middleware::Formatter, StackSpec::BarMiddleware]] } + let(:others) { [[:insert_after, Grape::Middleware::Formatter, bar_middleware]] } it 'applies the middleware specs stored in @others' do subject.concat others subject.use Grape::Middleware::Formatter subject.build - expect(subject[0]).to eq StackSpec::FooMiddleware + expect(subject[0]).to eq foo_middleware expect(subject[1]).to eq Grape::Middleware::Formatter - expect(subject[2]).to eq StackSpec::BarMiddleware + expect(subject[2]).to eq bar_middleware end end end @@ -148,7 +147,7 @@ def initialize(&block) end it 'calls +merge_with+ with the :use specs' do - expect(subject).to receive(:merge_with).with [[:use, StackSpec::BarMiddleware]] + expect(subject).to receive(:merge_with).with [[:use, bar_middleware]] subject.concat others end end diff --git a/spec/grape/validations/params_scope_spec.rb b/spec/grape/validations/params_scope_spec.rb index 71caa267d0..9ef7ad7db8 100644 --- a/spec/grape/validations/params_scope_spec.rb +++ b/spec/grape/validations/params_scope_spec.rb @@ -10,8 +10,8 @@ def app end context 'when using custom types' do - module ParamsScopeSpec - class CustomType + let(:custom_type) do + Class.new do attr_reader :value def self.parse(value) @@ -27,8 +27,9 @@ def initialize(value) end it 'coerces the parameter via the type\'s parse method' do + context = self subject.params do - requires :foo, type: ParamsScopeSpec::CustomType + requires :foo, type: context.custom_type end subject.get('/types') { params[:foo].value } diff --git a/spec/grape/validations/types_spec.rb b/spec/grape/validations/types_spec.rb index 402c3b6db8..003088a43d 100644 --- a/spec/grape/validations/types_spec.rb +++ b/spec/grape/validations/types_spec.rb @@ -1,12 +1,13 @@ # frozen_string_literal: true describe Grape::Validations::Types do - module TypesSpec - class FooType + let(:foo_type) do + Class.new do def self.parse(_); end end - - class BarType + end + let(:bar_type) do + Class.new do def self.parse; end end end @@ -24,7 +25,7 @@ def self.parse; end it 'identifies unknown types' do expect(described_class).not_to be_primitive(Object) - expect(described_class).not_to be_primitive(TypesSpec::FooType) + expect(described_class).not_to be_primitive(foo_type) end end @@ -82,11 +83,11 @@ def self.parse; end end it 'returns true if the type responds to :parse with one argument' do - expect(described_class).to be_custom(TypesSpec::FooType) + expect(described_class).to be_custom(foo_type) end it 'returns false if the type\'s #parse method takes other than one argument' do - expect(described_class).not_to be_custom(TypesSpec::BarType) + expect(described_class).not_to be_custom(bar_type) end end diff --git a/spec/grape/validations/validators/coerce_spec.rb b/spec/grape/validations/validators/coerce_spec.rb index cd1d9dcbd0..0afe720e55 100644 --- a/spec/grape/validations/validators/coerce_spec.rb +++ b/spec/grape/validations/validators/coerce_spec.rb @@ -10,13 +10,15 @@ def app end describe 'coerce' do - class SecureURIOnly - def self.parse(value) - URI.parse(value) - end + let(:secure_uri_only) do + Class.new do + def self.parse(value) + URI.parse(value) + end - def self.parsed?(value) - value.is_a? URI::HTTPS + def self.parsed?(value) + value.is_a? URI::HTTPS + end end end @@ -228,8 +230,9 @@ def self.parsed?(value) context 'a custom type' do it 'coerces the given value' do + context = self subject.params do - requires :uri, coerce: SecureURIOnly + requires :uri, coerce: context.secure_uri_only end subject.get '/secure_uri' do params[:uri].class @@ -325,8 +328,9 @@ def self.parse(_val) end it 'Array of a custom type' do + context = self subject.params do - requires :uri, type: Array[SecureURIOnly] + requires :uri, type: Array[context.secure_uri_only] end subject.get '/secure_uris' do params[:uri].first.class diff --git a/spec/grape/validations/validators/presence_spec.rb b/spec/grape/validations/validators/presence_spec.rb index bbe9865bd0..349fcf8d0d 100644 --- a/spec/grape/validations/validators/presence_spec.rb +++ b/spec/grape/validations/validators/presence_spec.rb @@ -287,7 +287,7 @@ def app context 'with a custom type' do it 'does not validate their type when it is missing' do - class CustomType + custom_type = Class.new do def self.parse(value) return if value.blank? @@ -296,7 +296,7 @@ def self.parse(value) end subject.params do - requires :custom, type: CustomType + requires :custom, type: custom_type end subject.get '/custom' do 'custom' diff --git a/spec/grape/validations/validators/values_spec.rb b/spec/grape/validations/validators/values_spec.rb index c66bf42e53..f78f633481 100644 --- a/spec/grape/validations/validators/values_spec.rb +++ b/spec/grape/validations/validators/values_spec.rb @@ -1,15 +1,12 @@ # frozen_string_literal: true describe Grape::Validations::Validators::ValuesValidator do - let_it_be(:values_model) do + let(:values_model) do Class.new do - DEFAULT_VALUES = %w[valid-type1 valid-type2 valid-type3].freeze - DEFAULT_EXCEPTS = %w[invalid-type1 invalid-type2 invalid-type3].freeze - class << self def values @values ||= [] - [DEFAULT_VALUES + @values].flatten.uniq + [default_values + @values].flatten.uniq end def add_value(value) @@ -19,7 +16,7 @@ def add_value(value) def excepts @excepts ||= [] - [DEFAULT_EXCEPTS + @excepts].flatten.uniq + [default_excepts + @excepts].flatten.uniq end def add_except(except) @@ -34,16 +31,21 @@ def include?(value) def even?(value) value.to_i.even? end + + private + + def default_values + %w[valid-type1 valid-type2 valid-type3].freeze + end + + def default_excepts + %w[invalid-type1 invalid-type2 invalid-type3].freeze + end end end end - before do - stub_const('ValuesModel', values_model) - end - - let_it_be(:app) do - ValuesModel = values_model + let(:app) do Class.new(Grape::API) do default_format :json @@ -271,6 +273,10 @@ def even?(value) end end + before do + stub_const('ValuesModel', values_model) + end + context 'with a custom validation message' do it 'allows a valid value for a parameter' do get('/custom_message', type: 'valid-type1') @@ -384,6 +390,7 @@ def even?(value) end it 'does not validate updated values without proc' do + app # Instantiate with the existing values. ValuesModel.add_value('valid-type4') get('/', type: 'valid-type4') expect(last_response.status).to eq 400