diff --git a/.rubocop.yml b/.rubocop.yml index a43dfa720..c85ec1515 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -31,6 +31,9 @@ Style/RaiseArgs: Style/RedundantArrayConstructor: Enabled: false # doesn't work well with params definition +Style/Send: + Enabled: true + Metrics/AbcSize: Max: 45 diff --git a/CHANGELOG.md b/CHANGELOG.md index dd24c4ef6..00b2351d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * [#2581](https://github.com/ruby-grape/grape/pull/2581): Delegate `to_s` in Grape::API::Instance - [@ericproulx](https://github.com/ericproulx). * [#2582](https://github.com/ruby-grape/grape/pull/2582): Fix leaky slash when normalizing - [@ericproulx](https://github.com/ericproulx). * [#2583](https://github.com/ruby-grape/grape/pull/2583): Optimize api parameter documentation and memory usage - [@ericproulx](https://github.com/ericproulx). +* [#2589](https://github.com/ruby-grape/grape/pull/2589): Replace `send` by `__send__` in codebase - [@ericproulx](https://github.com/ericproulx). * Your contribution here. #### Fixes diff --git a/benchmark/issue_mounting.rb b/benchmark/issue_mounting.rb new file mode 100755 index 000000000..0cfa285be --- /dev/null +++ b/benchmark/issue_mounting.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'bundler/inline' + +gemfile(true) do + source 'https://rubygems.org' + gem 'grape' + gem 'rack' + gem 'minitest' + gem 'rack-test' +end + +require 'minitest/autorun' +require 'rack/test' +require 'grape' + +class GrapeAPIBugTest < Minitest::Test + include Rack::Test::Methods + + RootAPI = Class.new(Grape::API) do + format :json + + delete :test do + status 200 + [] + end + end + + def test_v1_users_via_api + env = Rack::MockRequest.env_for('/test', method: Rack::DELETE) + response = Rack::MockResponse[*RootAPI.call(env)] + + assert_equal '[]', response.body + assert_equal 200, response.status + end +end diff --git a/lib/grape/api.rb b/lib/grape/api.rb index 81d101abb..5395be00e 100644 --- a/lib/grape/api.rb +++ b/lib/grape/api.rb @@ -132,7 +132,7 @@ def replay_step_on(instance, method:, args:, block:) return if skip_immediate_run?(instance, args) eval_args = evaluate_arguments(instance.configuration, *args) - response = instance.send(method, *eval_args, &block) + response = instance.__send__(method, *eval_args, &block) if skip_immediate_run?(instance, [response]) response else diff --git a/lib/grape/dsl/settings.rb b/lib/grape/dsl/settings.rb index bbd29d1a7..50f055933 100644 --- a/lib/grape/dsl/settings.rb +++ b/lib/grape/dsl/settings.rb @@ -33,7 +33,7 @@ def inheritable_setting # @param type [Symbol] # @param key [Symbol] def unset(type, key) - setting = inheritable_setting.send(type) + setting = inheritable_setting.__send__(type) setting.delete key end @@ -42,7 +42,7 @@ def unset(type, key) # @param value [Object] will be stored if the value is currently empty # @return either the old value, if it wasn't nil, or the given value def get_or_set(type, key, value) - setting = inheritable_setting.send(type) + setting = inheritable_setting.__send__(type) if value.nil? setting[key] else diff --git a/lib/grape/exceptions/base.rb b/lib/grape/exceptions/base.rb index 27ef78b45..9ad4ecfcf 100644 --- a/lib/grape/exceptions/base.rb +++ b/lib/grape/exceptions/base.rb @@ -17,7 +17,7 @@ def initialize(status: nil, message: nil, headers: nil) end def [](index) - send index + __send__ index end protected diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index e5cc2a51c..dad8aba21 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -195,7 +195,7 @@ %w[group resource resources segment].each do |als| it "`.#{als}` is an alias" do inner_namespace = nil - subject.send(als, :awesome) do + subject.__send__(als, :awesome) do inner_namespace = namespace end expect(inner_namespace).to eq '/awesome' @@ -485,10 +485,10 @@ def to_txt objects.each do |object| it "allows a(n) #{object.class} json object in params" do subject.format :json - subject.send(verb) do + subject.__send__(verb) do env[Grape::Env::API_REQUEST_BODY] end - send verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json' + __send__ verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json' expect(last_response.status).to eq(verb == :post ? 201 : 200) expect(last_response.body).to eql Grape::Json.dump(object) expect(last_request.params).to eql({}) @@ -496,10 +496,10 @@ def to_txt it 'stores input in api.request.input' do subject.format :json - subject.send(verb) do + subject.__send__(verb) do env[Grape::Env::API_REQUEST_INPUT] end - send verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json' + __send__ verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json' expect(last_response.status).to eq(verb == :post ? 201 : 200) expect(last_response.body).to eql Grape::Json.dump(object).to_json end @@ -507,10 +507,10 @@ def to_txt context 'chunked transfer encoding' do it 'stores input in api.request.input' do subject.format :json - subject.send(verb) do + subject.__send__(verb) do env[Grape::Env::API_REQUEST_INPUT] end - send verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json', 'HTTP_TRANSFER_ENCODING' => 'chunked' + __send__ verb, '/', Grape::Json.dump(object), 'CONTENT_TYPE' => 'application/json', 'HTTP_TRANSFER_ENCODING' => 'chunked' expect(last_response.status).to eq(verb == :post ? 201 : 200) expect(last_response.body).to eql Grape::Json.dump(object).to_json end @@ -549,7 +549,7 @@ def to_txt end %w[get post put delete options patch].each do |m| - send(m, '/abc') + __send__(m, '/abc') expect(last_response.body).to eql 'lol' end end @@ -588,14 +588,14 @@ def to_txt verbs = %w[post get head delete put options patch] verbs.each do |verb| it "allows and properly constrain a #{verb.upcase} method" do - subject.send(verb, '/example') do + subject.__send__(verb, '/example') do verb end - send(verb, '/example') + __send__(verb, '/example') expect(last_response.body).to eql verb == 'head' ? '' : verb # Call it with all methods other than the properly constrained one. (verbs - [verb]).each do |other_verb| - send(other_verb, '/example') + __send__(other_verb, '/example') expected_rc = if other_verb == 'options' then 204 elsif other_verb == 'head' && verb == 'get' then 200 else @@ -1050,7 +1050,7 @@ def to_txt end it 'returns compiled!' do - expect(app.send(:compile!)).to eq(:compiled!) + expect(app.__send__(:compile!)).to eq(:compiled!) end end @@ -1059,7 +1059,7 @@ def to_txt describe 'instance_for_rack' do context 'when the app was not mounted' do it 'returns the base_instance' do - expect(app.send(:instance_for_rack)).to eq app.base_instance + expect(app.__send__(:instance_for_rack)).to eq app.base_instance end end @@ -1071,7 +1071,7 @@ def to_txt mount mounted_app end end - expect(app.send(:instance_for_rack)).to eq app.send(:mounted_instances).first + expect(app.__send__(:instance_for_rack)).to eq app.__send__(:mounted_instances).first end end end diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb index eecb9102f..f6da9365c 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -929,26 +929,26 @@ def memoized describe 'all other' do %w[post get head put options patch].each do |verb| it "allows for the anchoring option with a #{verb.upcase} method" do - subject.send(verb, '/example', anchor: true) do + subject.__send__(verb, '/example', anchor: true) do verb end - send(verb, '/example/and/some/more') + __send__(verb, '/example/and/some/more') expect(last_response.status).to be 404 end it "anchors paths by default for the #{verb.upcase} method" do - subject.send(verb, '/example') do + subject.__send__(verb, '/example') do verb end - send(verb, '/example/and/some/more') + __send__(verb, '/example/and/some/more') expect(last_response.status).to be 404 end it "responds to /example/and/some/more for the non-anchored #{verb.upcase} method" do - subject.send(verb, '/example', anchor: false) do + subject.__send__(verb, '/example', anchor: false) do verb end - send(verb, '/example/and/some/more') + __send__(verb, '/example/and/some/more') expect(last_response.status).to eql verb == 'post' ? 201 : 200 expect(last_response.body).to eql verb == 'head' ? '' : verb end diff --git a/spec/grape/exceptions/base_spec.rb b/spec/grape/exceptions/base_spec.rb index 2378fdf6a..3a6a7849d 100644 --- a/spec/grape/exceptions/base_spec.rb +++ b/spec/grape/exceptions/base_spec.rb @@ -18,7 +18,7 @@ end describe '#compose_message' do - subject { described_class.new.send(:compose_message, key, **attributes) } + subject { described_class.new.__send__(:compose_message, key, **attributes) } let(:key) { :invalid_formatter } let(:attributes) { { klass: String, to_format: 'xml' } } diff --git a/spec/grape/validations/params_scope_spec.rb b/spec/grape/validations/params_scope_spec.rb index 3caec4dd7..0e9443631 100644 --- a/spec/grape/validations/params_scope_spec.rb +++ b/spec/grape/validations/params_scope_spec.rb @@ -1249,7 +1249,7 @@ def initialize(value) before do # puts "a_decl: #{a_decl}, a_opts: #{a_opts}, b_opts: #{b_opts}" subject.params do - send a_decl, :a, **a_opts + __send__ a_decl, :a, **a_opts given(a: ->(val) { val == 'x' }) { requires :b, **b_opts } given(a: ->(val) { val == 'y' }) { requires :c, **b_opts } end diff --git a/spec/support/content_type_helpers.rb b/spec/support/content_type_helpers.rb index 9721edacd..7f71417e2 100644 --- a/spec/support/content_type_helpers.rb +++ b/spec/support/content_type_helpers.rb @@ -7,7 +7,7 @@ module Helpers define_method :"#{method}_with_json" do |uri, params = {}, env = {}, &block| params = params.to_json env['CONTENT_TYPE'] ||= 'application/json' - send(method, uri, params, env, &block) + __send__(method, uri, params, env, &block) end end end