Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse_source: allow direct targetting of a node #119

Merged
merged 1 commit into from
Sep 24, 2020
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
95 changes: 29 additions & 66 deletions spec/rubocop/ast/send_node_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

RSpec.describe RuboCop::AST::SendNode do
let(:send_node) { parse_source(source).ast }
let(:send_node) { parse_source(source).node }

describe '.new' do
context 'with a regular method send' do
Expand Down Expand Up @@ -94,13 +94,11 @@
end

describe '#access_modifier?' do
let(:send_node) { parse_source(source).ast.children[1] }

context 'when node is a bare `module_function`' do
let(:source) do
<<~RUBY
module Foo
module_function
>> module_function <<
end
RUBY
end
Expand All @@ -112,7 +110,7 @@ module Foo
let(:source) do
<<~RUBY
module Foo
module_function :foo
>> module_function :foo <<
end
RUBY
end
Expand All @@ -124,7 +122,7 @@ module Foo
let(:source) do
<<~RUBY
module Foo
some_command
>> some_command <<
end
RUBY
end
Expand All @@ -134,13 +132,11 @@ module Foo
end

describe '#bare_access_modifier?' do
let(:send_node) { parse_source(source).ast.children[1] }

context 'when node is a bare `module_function`' do
let(:source) do
<<~RUBY
module Foo
module_function
>> module_function <<
end
RUBY
end
Expand All @@ -152,7 +148,7 @@ module Foo
let(:source) do
<<~RUBY
module Foo
private :foo
>> private :foo <<
end
RUBY
end
Expand All @@ -164,7 +160,7 @@ module Foo
let(:source) do
<<~RUBY
module Foo
some_command
>> some_command <<
end
RUBY
end
Expand All @@ -174,13 +170,11 @@ module Foo
end

describe '#non_bare_access_modifier?' do
let(:send_node) { parse_source(source).ast.children[1] }

context 'when node is a non-bare `module_function`' do
let(:source) do
<<~RUBY
module Foo
module_function :foo
>> module_function :foo <<
end
RUBY
end
Expand All @@ -192,7 +186,7 @@ module Foo
let(:source) do
<<~RUBY
module Foo
private
>> private <<
end
RUBY
end
Expand All @@ -204,7 +198,7 @@ module Foo
let(:source) do
<<~RUBY
module Foo
some_command
>> some_command <<
end
RUBY
end
Expand All @@ -216,11 +210,9 @@ module Foo
describe '#macro?' do
context 'without a receiver' do
context 'when parent is a class' do
let(:send_node) { parse_source(source).ast.children[2].children[0] }

let(:source) do
['class Foo',
' bar :baz',
'>>bar :baz<<',
' bar :qux',
'end'].join("\n")
end
Expand All @@ -229,11 +221,9 @@ module Foo
end

context 'when parent is a module' do
let(:send_node) { parse_source(source).ast.children[1].children[0] }

let(:source) do
['module Foo',
' bar :baz',
'>>bar :baz<<',
' bar :qux',
'end'].join("\n")
end
Expand All @@ -242,11 +232,9 @@ module Foo
end

context 'when parent is a class constructor' do
let(:send_node) { parse_source(source).ast.children[2].children[0] }

let(:source) do
['Module.new do',
' bar :baz',
'>>bar :baz<<',
' bar :qux',
'end'].join("\n")
end
Expand All @@ -255,11 +243,9 @@ module Foo
end

context 'when parent is a singleton class' do
let(:send_node) { parse_source(source).ast.children[1].children[0] }

let(:source) do
['class << self',
' bar :baz',
'>>bar :baz<<',
' bar :qux',
'end'].join("\n")
end
Expand All @@ -268,11 +254,9 @@ module Foo
end

context 'when parent is a block' do
let(:send_node) { parse_source(source).ast.children[2].children[0] }

let(:source) do
['concern :Auth do',
' bar :baz',
'>>bar :baz<<',
' bar :qux',
'end'].join("\n")
end
Expand All @@ -281,12 +265,10 @@ module Foo
end

context 'when parent is a keyword begin inside of an class' do
let(:send_node) { parse_source(source).ast.children[2].children[0] }

let(:source) do
['class Foo',
' begin',
' bar :qux',
'>> bar :qux <<',
' end',
'end'].join("\n")
end
Expand All @@ -301,23 +283,19 @@ module Foo
end

context 'when parent is a begin without a parent' do
let(:send_node) { parse_source(source).ast.children[0] }

let(:source) do
['begin',
' bar :qux',
'>>bar :qux<<',
'end'].join("\n")
end

it { expect(send_node.macro?).to be_truthy }
end

context 'when parent is a method definition' do
let(:send_node) { parse_source(source).ast.children[2] }

let(:source) do
['def foo',
' bar :baz',
'>>bar :baz<<',
'end'].join("\n")
end

Expand All @@ -327,23 +305,19 @@ module Foo

context 'with a receiver' do
context 'when parent is a class' do
let(:send_node) { parse_source(source).ast.children[2] }

let(:source) do
['class Foo',
' qux.bar :baz',
' >> qux.bar :baz <<',
'end'].join("\n")
end

it { expect(send_node.macro?).to be_falsey }
end

context 'when parent is a module' do
let(:send_node) { parse_source(source).ast.children[1] }

let(:source) do
['module Foo',
' qux.bar :baz',
' >> qux.bar :baz << ',
'end'].join("\n")
end

Expand Down Expand Up @@ -760,8 +734,7 @@ module Foo

describe '#enumerable_method?' do
context 'with an enumerable method' do
let(:send_node) { parse_source(source).ast.send_node }
let(:source) { 'foo.all? { |e| bar?(e) }' }
let(:source) { '>> foo.all? << { |e| bar?(e) }' }

it { expect(send_node.enumerable_method?).to be_truthy }
end
Expand Down Expand Up @@ -992,9 +965,7 @@ module Foo

describe '#block_literal?' do
context 'with a block literal' do
let(:send_node) { parse_source(source).ast.children[0] }

let(:source) { 'foo.bar { |q| baz(q) }' }
let(:source) { '>> foo.bar << { |q| baz(q) }' }

it { expect(send_node.block_literal?).to be_truthy }
end
Expand Down Expand Up @@ -1034,9 +1005,7 @@ module Foo

describe '#block_node' do
context 'with a block literal' do
let(:send_node) { parse_source(source).ast.children[0] }

let(:source) { 'foo.bar { |q| baz(q) }' }
let(:source) { '>>foo.bar<< { |q| baz(q) }' }

it { expect(send_node.block_node.block_type?).to be(true) }
end
Expand Down Expand Up @@ -1162,22 +1131,19 @@ module Foo

describe '#lambda?' do
context 'with a lambda method' do
let(:source) { 'lambda { |foo| bar(foo) }' }
let(:send_node) { parse_source(source).ast.send_node }
let(:source) { '>> lambda << { |foo| bar(foo) }' }

it { expect(send_node.lambda?).to be_truthy }
end

context 'with a method named lambda in a class' do
let(:source) { 'foo.lambda { |bar| baz }' }
let(:send_node) { parse_source(source).ast.send_node }
let(:source) { '>> foo.lambda << { |bar| baz }' }

it { expect(send_node.lambda?).to be_falsey }
end

context 'with a stabby lambda method' do
let(:source) { '-> (foo) { do_something(foo) }' }
let(:send_node) { parse_source(source).ast.send_node }
let(:source) { '>> -> << (foo) { do_something(foo) }' }

it { expect(send_node.lambda?).to be_truthy }
end
Expand All @@ -1191,15 +1157,13 @@ module Foo

describe '#lambda_literal?' do
context 'with a stabby lambda' do
let(:send_node) { parse_source(source).ast.send_node }
let(:source) { '-> (foo) { do_something(foo) }' }
let(:source) { '>> -> << (foo) { do_something(foo) }' }

it { expect(send_node.lambda_literal?).to be(true) }
end

context 'with a lambda method' do
let(:send_node) { parse_source(source).ast.send_node }
let(:source) { 'lambda { |foo| bar(foo) }' }
let(:source) { '>> lambda << { |foo| bar(foo) }' }

it { expect(send_node.lambda_literal?).to be(false) }
end
Expand All @@ -1212,8 +1176,7 @@ module Foo

# Regression test https://github.com/rubocop-hq/rubocop/pull/5194
context 'with `a.() {}` style method' do
let(:send_node) { parse_source(source).ast.send_node }
let(:source) { 'a.() {}' }
let(:source) { '>>a.()<< {}' }

it { expect(send_node.lambda?).to be_falsey }
end
Expand Down
21 changes: 20 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,29 @@ module DefaultRubyVersion
let(:ruby_version) { 2.4 }
end

module RuboCop
module AST
# patch class
class ProcessedSource
attr_accessor :node
end
end
end

# ...
module ParseSourceHelper
def parse_source(source)
RuboCop::AST::ProcessedSource.new(source, ruby_version, nil)
lookup = nil
ruby = source.gsub(/>>(.*)<</) { lookup = Regexp.last_match(1).strip }
source = RuboCop::AST::ProcessedSource.new(ruby, ruby_version, nil)
source.node = if lookup
source.ast.each_node.find(
-> { raise "No node corresponds to source '#{lookup}'" }
) { |node| node.source == lookup }
else
source.ast
end
source
end
end

Expand Down