Skip to content

Commit d85e696

Browse files
committed
Disable development NoEvalCop for load-time eval calls
1 parent 7357cd9 commit d85e696

18 files changed

+147
-98
lines changed

cop/development/no_eval_cop.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
module Cop
55
module Development
66
class NoEvalCop < RuboCop::Cop::Base
7-
MSG_TEMPLATE = "Don't use `%{eval_method_name}` which accept strings and may result in unexpected code being generated. Use `%{exec_method_name}` instead, and pass a block."
7+
MSG_TEMPLATE = "Don't use `%{eval_method_name}` which accepts strings and may result evaluating unexpected code. Use `%{exec_method_name}` instead, and pass a block."
88

99
def on_send(node)
1010
case node.method_name

lib/graphql/analysis/analyzer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def result
4242
raise GraphQL::RequiredImplementationMissingError
4343
end
4444

45+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
4546
class << self
4647
private
4748

@@ -72,7 +73,7 @@ def on_leave_#{member_name}(node, parent, visitor)
7273
build_visitor_hooks :variable_definition
7374
build_visitor_hooks :variable_identifier
7475
build_visitor_hooks :abstract_node
75-
76+
# rubocop:enable Development/NoEvalCop
7677
protected
7778

7879
# @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing

lib/graphql/analysis/visitor.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def response_path
6464
@response_path.dup
6565
end
6666

67+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
6768
# Visitor Hooks
6869
[
6970
:operation_definition, :fragment_definition,
@@ -92,6 +93,7 @@ def call_on_leave_#{node_type}(node, parent)
9293
9394
RUBY
9495
end
96+
# rubocop:enable Development/NoEvalCop
9597

9698
def on_operation_definition(node, parent)
9799
object_type = @schema.root_type_for_operation(node.operation_type)

lib/graphql/language/nodes.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ def merge!(new_options)
141141
end
142142

143143
class << self
144+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
145+
144146
# Add a default `#visit_method` and `#children_method_name` using the class name
145147
def inherited(child_class)
146148
super
@@ -341,6 +343,8 @@ def marshal_load(values)
341343
@line, @col, @filename #{marshalling_method_names.map { |n| ", @#{n}"}.join} = values
342344
end
343345
RUBY
346+
347+
# rubocop:enable Development/NoEvalCop
344348
end
345349
end
346350
end

lib/graphql/language/static_visitor.rb

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def visit
2121
@document
2222
end
2323
end
24+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
2425

2526
# We don't use `alias` here because it breaks `super`
2627
def self.make_visit_methods(ast_node_class)
@@ -55,6 +56,48 @@ def #{node_method}(node, parent)
5556
RUBY
5657
end
5758

59+
[
60+
Language::Nodes::Argument,
61+
Language::Nodes::Directive,
62+
Language::Nodes::DirectiveDefinition,
63+
Language::Nodes::DirectiveLocation,
64+
Language::Nodes::Document,
65+
Language::Nodes::Enum,
66+
Language::Nodes::EnumTypeDefinition,
67+
Language::Nodes::EnumTypeExtension,
68+
Language::Nodes::EnumValueDefinition,
69+
Language::Nodes::Field,
70+
Language::Nodes::FieldDefinition,
71+
Language::Nodes::FragmentDefinition,
72+
Language::Nodes::FragmentSpread,
73+
Language::Nodes::InlineFragment,
74+
Language::Nodes::InputObject,
75+
Language::Nodes::InputObjectTypeDefinition,
76+
Language::Nodes::InputObjectTypeExtension,
77+
Language::Nodes::InputValueDefinition,
78+
Language::Nodes::InterfaceTypeDefinition,
79+
Language::Nodes::InterfaceTypeExtension,
80+
Language::Nodes::ListType,
81+
Language::Nodes::NonNullType,
82+
Language::Nodes::NullValue,
83+
Language::Nodes::ObjectTypeDefinition,
84+
Language::Nodes::ObjectTypeExtension,
85+
Language::Nodes::OperationDefinition,
86+
Language::Nodes::ScalarTypeDefinition,
87+
Language::Nodes::ScalarTypeExtension,
88+
Language::Nodes::SchemaDefinition,
89+
Language::Nodes::SchemaExtension,
90+
Language::Nodes::TypeName,
91+
Language::Nodes::UnionTypeDefinition,
92+
Language::Nodes::UnionTypeExtension,
93+
Language::Nodes::VariableDefinition,
94+
Language::Nodes::VariableIdentifier,
95+
].each do |ast_node_class|
96+
make_visit_methods(ast_node_class)
97+
end
98+
99+
# rubocop:disable Development/NoEvalCop
100+
58101
def on_document_children(document_node)
59102
document_node.children.each do |child_node|
60103
visit_method = child_node.visit_method
@@ -122,46 +165,6 @@ def on_argument_children(new_node)
122165
end
123166
end
124167
end
125-
126-
[
127-
Language::Nodes::Argument,
128-
Language::Nodes::Directive,
129-
Language::Nodes::DirectiveDefinition,
130-
Language::Nodes::DirectiveLocation,
131-
Language::Nodes::Document,
132-
Language::Nodes::Enum,
133-
Language::Nodes::EnumTypeDefinition,
134-
Language::Nodes::EnumTypeExtension,
135-
Language::Nodes::EnumValueDefinition,
136-
Language::Nodes::Field,
137-
Language::Nodes::FieldDefinition,
138-
Language::Nodes::FragmentDefinition,
139-
Language::Nodes::FragmentSpread,
140-
Language::Nodes::InlineFragment,
141-
Language::Nodes::InputObject,
142-
Language::Nodes::InputObjectTypeDefinition,
143-
Language::Nodes::InputObjectTypeExtension,
144-
Language::Nodes::InputValueDefinition,
145-
Language::Nodes::InterfaceTypeDefinition,
146-
Language::Nodes::InterfaceTypeExtension,
147-
Language::Nodes::ListType,
148-
Language::Nodes::NonNullType,
149-
Language::Nodes::NullValue,
150-
Language::Nodes::ObjectTypeDefinition,
151-
Language::Nodes::ObjectTypeExtension,
152-
Language::Nodes::OperationDefinition,
153-
Language::Nodes::ScalarTypeDefinition,
154-
Language::Nodes::ScalarTypeExtension,
155-
Language::Nodes::SchemaDefinition,
156-
Language::Nodes::SchemaExtension,
157-
Language::Nodes::TypeName,
158-
Language::Nodes::UnionTypeDefinition,
159-
Language::Nodes::UnionTypeExtension,
160-
Language::Nodes::VariableDefinition,
161-
Language::Nodes::VariableIdentifier,
162-
].each do |ast_node_class|
163-
make_visit_methods(ast_node_class)
164-
end
165168
end
166169
end
167170
end

lib/graphql/language/visitor.rb

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def visit
6060
@document
6161
end
6262
end
63+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
6364

6465
# We don't use `alias` here because it breaks `super`
6566
def self.make_visit_methods(ast_node_class)
@@ -116,6 +117,48 @@ def #{node_method}_with_modifications(node, parent)
116117
RUBY
117118
end
118119

120+
[
121+
Language::Nodes::Argument,
122+
Language::Nodes::Directive,
123+
Language::Nodes::DirectiveDefinition,
124+
Language::Nodes::DirectiveLocation,
125+
Language::Nodes::Document,
126+
Language::Nodes::Enum,
127+
Language::Nodes::EnumTypeDefinition,
128+
Language::Nodes::EnumTypeExtension,
129+
Language::Nodes::EnumValueDefinition,
130+
Language::Nodes::Field,
131+
Language::Nodes::FieldDefinition,
132+
Language::Nodes::FragmentDefinition,
133+
Language::Nodes::FragmentSpread,
134+
Language::Nodes::InlineFragment,
135+
Language::Nodes::InputObject,
136+
Language::Nodes::InputObjectTypeDefinition,
137+
Language::Nodes::InputObjectTypeExtension,
138+
Language::Nodes::InputValueDefinition,
139+
Language::Nodes::InterfaceTypeDefinition,
140+
Language::Nodes::InterfaceTypeExtension,
141+
Language::Nodes::ListType,
142+
Language::Nodes::NonNullType,
143+
Language::Nodes::NullValue,
144+
Language::Nodes::ObjectTypeDefinition,
145+
Language::Nodes::ObjectTypeExtension,
146+
Language::Nodes::OperationDefinition,
147+
Language::Nodes::ScalarTypeDefinition,
148+
Language::Nodes::ScalarTypeExtension,
149+
Language::Nodes::SchemaDefinition,
150+
Language::Nodes::SchemaExtension,
151+
Language::Nodes::TypeName,
152+
Language::Nodes::UnionTypeDefinition,
153+
Language::Nodes::UnionTypeExtension,
154+
Language::Nodes::VariableDefinition,
155+
Language::Nodes::VariableIdentifier,
156+
].each do |ast_node_class|
157+
make_visit_methods(ast_node_class)
158+
end
159+
160+
# rubocop:enable Development/NoEvalCop
161+
119162
def on_document_children(document_node)
120163
new_node = document_node
121164
document_node.children.each do |child_node|
@@ -216,46 +259,6 @@ def on_argument_children(new_node)
216259
new_node
217260
end
218261

219-
[
220-
Language::Nodes::Argument,
221-
Language::Nodes::Directive,
222-
Language::Nodes::DirectiveDefinition,
223-
Language::Nodes::DirectiveLocation,
224-
Language::Nodes::Document,
225-
Language::Nodes::Enum,
226-
Language::Nodes::EnumTypeDefinition,
227-
Language::Nodes::EnumTypeExtension,
228-
Language::Nodes::EnumValueDefinition,
229-
Language::Nodes::Field,
230-
Language::Nodes::FieldDefinition,
231-
Language::Nodes::FragmentDefinition,
232-
Language::Nodes::FragmentSpread,
233-
Language::Nodes::InlineFragment,
234-
Language::Nodes::InputObject,
235-
Language::Nodes::InputObjectTypeDefinition,
236-
Language::Nodes::InputObjectTypeExtension,
237-
Language::Nodes::InputValueDefinition,
238-
Language::Nodes::InterfaceTypeDefinition,
239-
Language::Nodes::InterfaceTypeExtension,
240-
Language::Nodes::ListType,
241-
Language::Nodes::NonNullType,
242-
Language::Nodes::NullValue,
243-
Language::Nodes::ObjectTypeDefinition,
244-
Language::Nodes::ObjectTypeExtension,
245-
Language::Nodes::OperationDefinition,
246-
Language::Nodes::ScalarTypeDefinition,
247-
Language::Nodes::ScalarTypeExtension,
248-
Language::Nodes::SchemaDefinition,
249-
Language::Nodes::SchemaExtension,
250-
Language::Nodes::TypeName,
251-
Language::Nodes::UnionTypeDefinition,
252-
Language::Nodes::UnionTypeExtension,
253-
Language::Nodes::VariableDefinition,
254-
Language::Nodes::VariableIdentifier,
255-
].each do |ast_node_class|
256-
make_visit_methods(ast_node_class)
257-
end
258-
259262
private
260263

261264
def apply_modifications(node, parent, new_node_and_new_parent)

lib/graphql/schema/build_from_definition.rb

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -467,17 +467,18 @@ def build_fields(owner, field_definitions, type_resolver, default_resolve:)
467467

468468
# Don't do this for interfaces
469469
if default_resolve
470-
owner.class_eval <<-RUBY, __FILE__, __LINE__
471-
# frozen_string_literal: true
472-
def #{resolve_method_name}(**args)
473-
field_instance = self.class.get_field("#{field_definition.name}")
474-
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
475-
end
476-
RUBY
470+
define_field_resolve_method(owner, resolve_method_name, field_definition.name)
477471
end
478472
end
479473
end
480474

475+
def define_field_resolve_method(owner, method_name, field_name)
476+
owner.define_method(method_name) { |**args|
477+
field_instance = self.class.get_field(field_name)
478+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
479+
}
480+
end
481+
481482
def build_resolve_type(lookup_hash, directives, missing_type_handler)
482483
resolve_type_proc = nil
483484
resolve_type_proc = ->(ast_node) {

lib/graphql/schema/enum.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ def generate_value_method(value, configured_value_method)
256256
return
257257
end
258258

259-
instance_eval("def #{value_method_name}; #{value.graphql_name.inspect}; end;", __FILE__, __LINE__)
259+
define_singleton_method(value_method_name) { value.graphql_name }
260260
end
261261
end
262262

lib/graphql/schema/input_object.rb

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def deconstruct_keys(keys = nil)
5959
else
6060
new_h = {}
6161
keys.each { |k| @ruby_style_hash.key?(k) && new_h[k] = @ruby_style_hash[k] }
62-
new_h
62+
new_h
6363
end
6464
end
6565

@@ -150,14 +150,8 @@ def argument(*args, **kwargs, &block)
150150
end
151151
end
152152
# Add a method access
153-
method_name = argument_defn.keyword
154153
suppress_redefinition_warning do
155-
class_eval <<-RUBY, __FILE__, __LINE__
156-
def #{method_name}
157-
self[#{method_name.inspect}]
158-
end
159-
alias_method #{method_name.inspect}, #{method_name.inspect}
160-
RUBY
154+
define_accessor_method(argument_defn.keyword)
161155
end
162156
argument_defn
163157
end
@@ -293,6 +287,11 @@ def suppress_redefinition_warning
293287
ensure
294288
$VERBOSE = verbose
295289
end
290+
291+
def define_accessor_method(method_name)
292+
define_method(method_name) { self[method_name] }
293+
alias_method(method_name, method_name)
294+
end
296295
end
297296

298297
private

lib/graphql/tracing/appoptics_trace.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ def self.version
3232
Gem::Version.new('1.0.0')
3333
end
3434

35+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
36+
3537
[
3638
'lex',
3739
'parse',
@@ -59,6 +61,8 @@ def #{trace_method}(**data)
5961
RUBY
6062
end
6163

64+
# rubocop:enable Development/NoEvalCop
65+
6266
def execute_field(query:, field:, ast_node:, arguments:, object:)
6367
return_type = field.type.unwrap
6468
trace_field = if return_type.kind.scalar? || return_type.kind.enum?

0 commit comments

Comments
 (0)