lib/rubocop/ast_node.rb in rubocop-0.37.0 vs lib/rubocop/ast_node.rb in rubocop-0.37.1
- old
+ new
@@ -41,12 +41,10 @@
:or, :postexe, :redo, :rescue, :retry, :return, :self, :super,
:zsuper, :then, :undef, :until, :when, :while, :yield].freeze
OPERATOR_KEYWORDS = [:and, :or].freeze
SPECIAL_KEYWORDS = %w(__FILE__ __LINE__ __ENCODING__).freeze
- RSPEC_METHODS = [:describe, :it].freeze
-
# def_matcher can be used to define a pattern-matching method on Node
class << self
def def_matcher(method_name, pattern_str)
compiler = RuboCop::NodePattern::Compiler.new(pattern_str, 'self')
src = "def #{method_name}(" \
@@ -329,27 +327,51 @@
when :class, :module, :casgn
# TODO: if constant name has cbase (leading ::), then we don't need
# to keep traversing up through nested classes/modules
ancestor.defined_module_name
when :sclass
- obj = ancestor.children[0]
- # TODO: look for constant definition and see if it is nested
- # inside a class or module
- return "#<Class:#{obj.const_name}>" if obj.const_type?
- return "#<Class:#{ancestor.parent_module_name}>" if obj.self_type?
- return nil
+ return parent_module_name_for_sclass(ancestor)
else # block
- return nil if ancestor.known_dsl?
- if ancestor.method_name == :class_eval && ancestor.receiver
- return nil unless ancestor.receiver.const_type?
- ancestor.receiver.const_name
+ if ancestor.method_name == :class_eval
+ # `class_eval` with no receiver applies to whatever module or class
+ # we are currently in
+ next unless (receiver = ancestor.receiver)
+ return nil unless receiver.const_type?
+ receiver.const_name
+ elsif new_class_or_module_block?(ancestor)
+ # we will catch this in the `casgn` branch above
+ next
+ else
+ return nil
end
end
end.compact.reverse.join('::')
result.empty? ? 'Object' : result
end
+ def parent_module_name_for_sclass(sclass_node)
+ # TODO: look for constant definition and see if it is nested
+ # inside a class or module
+ subject = sclass_node.children[0]
+
+ if subject.const_type?
+ "#<Class:#{subject.const_name}>"
+ elsif subject.self_type?
+ "#<Class:#{sclass_node.parent_module_name}>"
+ end
+ end
+
+ def new_class_or_module_block?(block_node)
+ receiver = block_node.receiver
+
+ block_node.method_name == :new &&
+ receiver && receiver.const_type? &&
+ (receiver.const_name == 'Class' || receiver.const_name == 'Module') &&
+ block_node.parent &&
+ block_node.parent.casgn_type?
+ end
+
## Predicates
def multiline?
expr = loc.expression
expr && (expr.first_line != expr.last_line)
@@ -520,14 +542,9 @@
:pair, :regexp, :until, :until_post, :when, :while, :while_post
child_nodes.all?(&:pure?)
else
false
end
- end
-
- # Known DSL methods which eval body inside an anonymous class/module
- def known_dsl?
- RSPEC_METHODS.include?(method_name) && receiver.nil?
end
protected
def visit_descendants(&block)