Class: RuboCop::Cop::Gusto::NoMetaprogramming

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/gusto/no_metaprogramming.rb

Overview

Checks and discourages the use of metaprogramming techniques that make code harder to understand, debug, and maintain.

Examples:


# bad - using define_method
define_method(:my_method) do |arg|
  puts arg
end

# good - using regular method definition
def my_method(arg)
  puts arg
end

# bad - using instance_eval
object.instance_eval do
  def foo
    bar
  end
end

# good - defining methods on the class
class MyClass
  def foo
    bar
  end
end

# bad - using method_missing
def method_missing(method, *args)
  if method.to_s.start_with?('find_by_')
    # ...
  end
end

# bad - using define_singleton_method
object.define_singleton_method(:foo) { bar }

# good - define class methods directly
def self.foo
  bar
end

# bad - using class_eval
MyClass.class_eval do
  def foo
    bar
  end
end

Constant Summary collapse

RESTRICT_ON_SEND =
%i(define_method instance_eval define_singleton_method class_eval).freeze

Instance Method Summary collapse

Instance Method Details

#included_definition?(node) ⇒ Object



61
62
63
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 61

def_node_matcher :included_definition?, <<~PATTERN
  (defs self :included ...)
PATTERN

#inherited_definition?(node) ⇒ Object



66
67
68
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 66

def_node_matcher :inherited_definition?, <<~PATTERN
  (defs self :inherited ...)
PATTERN

#on_def(node) ⇒ Object



105
106
107
108
109
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 105

def on_def(node)
  using_method_missing?(node) do
    add_offense(node, message: "Please do not use method_missing. Instead, explicitly define the methods you expect to receive.")
  end
end

#on_defs(node) ⇒ Object



95
96
97
98
99
100
101
102
103
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 95

def on_defs(node)
  included_definition?(node) do
    add_offense(node, message: "self.included modifies the behavior of classes at runtime. Please avoid using if possible.")
  end

  inherited_definition?(node) do
    add_offense(node, message: "self.inherited modifies the behavior of classes at runtime. Please avoid using if possible.")
  end
end

#on_send(node) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 111

def on_send(node)
  using_define_method?(node) do
    add_offense(node, message: "Please do not define methods dynamically, instead define them using `def` and explicitly. This helps readability for both humans and machines.")
  end

  using_define_singleton_method_on_klass_instance?(node) do
    add_offense(node, message: "Please do not use define_singleton_method. Instead, define the method explicitly using `def self.my_method; end`")
  end

  using_instance_eval?(node) do
    add_offense(node, message: "Please do not use instance_eval to augment behavior onto an instance. Instead, define the method you want to use in the class definition.")
  end

  using_class_eval?(node) do
    add_offense(node, message: "Please do not use class_eval to augment behavior onto a class. Instead, define the method you want to use in the class definition.")
  end
end

#using_class_eval?(node) ⇒ Object



86
87
88
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 86

def_node_matcher :using_class_eval?, <<~PATTERN
  (send _ :class_eval ...)
PATTERN

#using_define_method?(node) ⇒ Object



76
77
78
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 76

def_node_matcher :using_define_method?, <<~PATTERN
  (send _ :define_method ...)
PATTERN

#using_define_singleton_method_on_klass_instance?(node) ⇒ Object



91
92
93
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 91

def_node_matcher :using_define_singleton_method_on_klass_instance?, <<~PATTERN
  (send _ :define_singleton_method ...)
PATTERN

#using_instance_eval?(node) ⇒ Object



81
82
83
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 81

def_node_matcher :using_instance_eval?, <<~PATTERN
  (send _ :instance_eval ...)
PATTERN

#using_method_missing?(node) ⇒ Object



71
72
73
# File 'lib/rubocop/cop/gusto/no_metaprogramming.rb', line 71

def_node_matcher :using_method_missing?, <<~PATTERN
  (def :method_missing ...)
PATTERN