Skip to content

Commit

Permalink
Add struct_constructor?, class_definition? and module_definition? mat…
Browse files Browse the repository at this point in the history
…chers

Closes rubocop#28
  • Loading branch information
tejasbubane committed Jun 19, 2020
1 parent 2817ae4 commit 5824636
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,7 @@
* [#20](https://github.com/rubocop-hq/rubocop-ast/pull/20): Add option predicates for `RegexpNode`. ([@owst][])
* [#11](https://github.com/rubocop-hq/rubocop-ast/issues/11): Add `argument_type?` method to make it easy to recognize argument nodes. ([@tejasbubane][])
* [#31](https://github.com/rubocop-hq/rubocop-ast/pull/31): Use `param === node` to match params, which allows Regexp, Proc, Set, etc. ([@marcandre][])
* [#28](https://github.com/rubocop-hq/rubocop-ast/issues/28): Add `struct_constructor?`, `class_definition?` and `module_definition?` matchers. ([@tejasbubane][])

## 0.0.3 (2020-05-15)

Expand Down
15 changes: 15 additions & 0 deletions lib/rubocop/ast/node.rb
Expand Up @@ -497,6 +497,21 @@ def guard_clause?
(block (send (const nil? {:Class :Module}) :new ...) ...)}
PATTERN

def_node_matcher :struct_constructor?, <<~PATTERN
(block (send (const nil? :Struct) :new ...) ...)
PATTERN

def_node_matcher :class_definition?, <<~PATTERN
{(class (const _ _) ...)
(casgn nil? _ (block (send (const nil? {:Struct :Class}) :new ...) ...))
(sclass {(self) (send nil? _)} ...)}
PATTERN

def_node_matcher :module_definition?, <<~PATTERN
{(module (const _ _) ...)
(casgn nil? _ (block (send (const nil? :Module) :new ...) ...))}
PATTERN

# Some expressions are evaluated for their value, some for their side
# effects, and some for both
# If we know that an expression is useful only for its side effects, that
Expand Down
202 changes: 202 additions & 0 deletions spec/rubocop/ast/node_spec.rb
Expand Up @@ -373,4 +373,206 @@ def used?
end
end
end

describe '#class_constructor?' do
context 'class definition with a block' do
let(:src) { 'Class.new { a = 42 }' }

it 'matches' do
expect(node.class_constructor?).to eq(true)
end
end

context 'module definition with a block' do
let(:src) { 'Module.new { a = 42 }' }

it 'matches' do
expect(node.class_constructor?).to eq(true)
end
end

context 'class definition' do
let(:src) { 'class Foo; a = 42; end' }

it 'does not match' do
expect(node.class_constructor?).to eq(nil)
end
end
end

describe '#struct_constructor?' do
context 'struct definition with a block' do
let(:src) { 'Struct.new { a = 42 }' }

it 'matches' do
expect(node.struct_constructor?).to eq(true)
end
end

context 'struct definition without block' do
let(:src) { 'Struct.new(:foo, :bar)' }

it 'does not matches' do
expect(node.struct_constructor?).to eq(nil)
end
end
end

describe '#class_definition?' do
context 'without inheritance' do
let(:src) { 'class Foo; a = 42; end' }

it 'matches' do
expect(node.class_definition?).to eq(true)
end
end

context 'with inheritance' do
let(:src) { 'class Foo < Bar; a = 42; end' }

it 'matches' do
expect(node.class_definition?).to eq(true)
end
end

context 'with Struct' do
let(:src) do
<<~RUBY
Person = Struct.new(:name, :age) do
a = 2
def details; end
end
RUBY
end

it 'matches' do
expect(node.class_definition?).to eq(true)
end
end

context 'constant defined as Struct without block' do
let(:src) { 'Person = Struct.new(:name, :age)' }

it 'does not match' do
expect(node.class_definition?).to eq(nil)
end
end

context 'with Class.new' do
let(:src) do
<<~RUBY
Person = Class.new do
a = 2
def details; end
end
RUBY
end

it 'matches' do
expect(node.class_definition?).to eq(true)
end
end

context 'namespaced class' do
let(:src) do
<<~RUBY
class Foo::Bar::Baz
BAZ = 2
def variables; end
end
RUBY
end

it 'matches' do
expect(node.class_definition?).to eq(true)
end
end

context 'with self singleton class' do
let(:src) do
<<~RUBY
class << self
BAZ = 2
def variables; end
end
RUBY
end

it 'matches' do
expect(node.class_definition?).to eq(true)
end
end

context 'with object singleton class' do
let(:src) do
<<~RUBY
class << foo
BAZ = 2
def variables; end
end
RUBY
end

it 'matches' do
expect(node.class_definition?).to eq(true)
end
end
end

describe '#module_definition?' do
context 'using module keyword' do
let(:src) { 'module Foo; A = 42; end' }

it 'matches' do
expect(node.module_definition?).to eq(true)
end
end

context 'with Module.new' do
let(:src) do
<<~RUBY
Person = Module.new do
a = 2
def details; end
end
RUBY
end

it 'matches' do
expect(node.module_definition?).to eq(true)
end
end

context 'nested modules' do
let(:src) do
<<~RUBY
module Foo
module Bar
BAZ = 2
def variables; end
end
end
RUBY
end

it 'matches' do
expect(node.module_definition?).to eq(true)
end
end

context 'namespaced modules' do
let(:src) do
<<~RUBY
module Foo::Bar::Baz
BAZ = 2
def variables; end
end
RUBY
end

it 'matches' do
expect(node.module_definition?).to eq(true)
end
end
end
end

0 comments on commit 5824636

Please sign in to comment.