Skip to content

Commit 4deb98d

Browse files
committed
Disable development NoEvalCop for load-time eval calls
1 parent 44b4978 commit 4deb98d

14 files changed

+152
-94
lines changed

cop/development/no_eval_cop.rb

+1-1
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/language/nodes.rb

+4
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ def merge!(new_options)
138138
end
139139

140140
class << self
141+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
142+
141143
# Add a default `#visit_method` and `#children_method_name` using the class name
142144
def inherited(child_class)
143145
super
@@ -294,6 +296,8 @@ def self.from_a(filename, line, col, #{(scalar_method_names + @children_methods.
294296
self.new(filename: filename, line: line, col: col, #{keywords.join(", ")})
295297
end
296298
RUBY
299+
300+
# rubocop:enable Development/NoEvalCop
297301
end
298302
end
299303
end

lib/graphql/language/static_visitor.rb

+43-40
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

+43-40
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

+8-7
Original file line numberDiff line numberDiff line change
@@ -451,17 +451,18 @@ def build_fields(owner, field_definitions, type_resolver, default_resolve:)
451451

452452
# Don't do this for interfaces
453453
if default_resolve
454-
owner.class_eval <<-RUBY, __FILE__, __LINE__
455-
# frozen_string_literal: true
456-
def #{resolve_method_name}(**args)
457-
field_instance = self.class.get_field("#{field_definition.name}")
458-
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
459-
end
460-
RUBY
454+
define_field_resolve_method(owner, resolve_method_name, field_definition.name)
461455
end
462456
end
463457
end
464458

459+
def define_field_resolve_method(owner, method_name, field_name)
460+
owner.define_method(method_name) { |**args|
461+
field_instance = self.class.get_field(field_name)
462+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
463+
}
464+
end
465+
465466
def build_resolve_type(lookup_hash, directives, missing_type_handler)
466467
resolve_type_proc = nil
467468
resolve_type_proc = ->(ast_node) {

lib/graphql/schema/input_object.rb

+21-6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ def to_hash
4444
to_h
4545
end
4646

47+
<<<<<<< HEAD
48+
=======
49+
def deconstruct_keys(keys = nil)
50+
if keys.nil?
51+
@ruby_style_hash
52+
else
53+
new_h = {}
54+
keys.each { |k| @ruby_style_hash.key?(k) && new_h[k] = @ruby_style_hash[k] }
55+
new_h
56+
end
57+
end
58+
59+
>>>>>>> d85e69690f (Disable development NoEvalCop for load-time eval calls)
4760
def prepare
4861
if @context
4962
object = @context[:current_object]
@@ -131,12 +144,7 @@ def argument(*args, **kwargs, &block)
131144
end
132145
end
133146
# Add a method access
134-
method_name = argument_defn.keyword
135-
class_eval <<-RUBY, __FILE__, __LINE__
136-
def #{method_name}
137-
self[#{method_name.inspect}]
138-
end
139-
RUBY
147+
define_accessor_method(argument_defn.keyword)
140148
argument_defn
141149
end
142150

@@ -242,6 +250,13 @@ def coerce_result(value, ctx)
242250

243251
result
244252
end
253+
254+
private
255+
256+
def define_accessor_method(method_name)
257+
define_method(method_name) { self[method_name] }
258+
alias_method(method_name, method_name)
259+
end
245260
end
246261

247262
private

lib/graphql/tracing/appoptics_trace.rb

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ def self.version
2828
Gem::Version.new('1.0.0')
2929
end
3030

31+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
32+
3133
[
3234
'lex',
3335
'parse',
@@ -55,6 +57,8 @@ def #{trace_method}(**data)
5557
RUBY
5658
end
5759

60+
# rubocop:enable Development/NoEvalCop
61+
5862
def execute_field(query:, field:, ast_node:, arguments:, object:)
5963
return_type = field.type.unwrap
6064
trace_field = if return_type.kind.scalar? || return_type.kind.enum?

lib/graphql/tracing/appsignal_trace.rb

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ def initialize(set_action_name: false, **rest)
1313
super
1414
end
1515

16+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
17+
1618
{
1719
"lex" => "lex.graphql",
1820
"parse" => "parse.graphql",
@@ -43,6 +45,8 @@ def #{trace_method}(**data)
4345
RUBY
4446
end
4547
48+
# rubocop:enable Development/NoEvalCop
49+
4650
def platform_execute_field(platform_key)
4751
Appsignal.instrument(platform_key) do
4852
yield

lib/graphql/tracing/data_dog_trace.rb

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def initialize(tracer: nil, analytics_enabled: false, analytics_sample_rate: 1.0
2020
super
2121
end
2222

23+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
24+
2325
{
2426
'lex' => 'lex.graphql',
2527
'parse' => 'parse.graphql',
@@ -69,6 +71,8 @@ def #{trace_method}(**data)
6971
RUBY
7072
end
7173
74+
# rubocop:enable Development/NoEvalCop
75+
7276
def execute_field_span(span_key, query, field, ast_node, arguments, object)
7377
return_type = field.type.unwrap
7478
trace_field = if return_type.kind.scalar? || return_type.kind.enum?

lib/graphql/tracing/notifications_trace.rb

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ def initialize(engine:, **rest)
1616
super
1717
end
1818

19+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
20+
1921
{
2022
"lex" => "lex.graphql",
2123
"parse" => "parse.graphql",
@@ -39,6 +41,8 @@ def #{trace_method}(**metadata, &blk)
3941
RUBY
4042
end
4143

44+
# rubocop:enable Development/NoEvalCop
45+
4246
include PlatformTrace
4347
end
4448
end

lib/graphql/tracing/platform_trace.rb

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ def self.included(child_class)
3939
include(BaseKeyCache)
4040
}
4141
child_class.const_set(:KeyCache, key_methods_class)
42+
43+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
44+
4245
[:execute_field, :execute_field_lazy].each do |field_trace_method|
4346
if !child_class.method_defined?(field_trace_method)
4447
child_class.module_eval <<-RUBY, __FILE__, __LINE__
@@ -91,6 +94,8 @@ def #{rt_trace_method}(query:, type:, object:)
9194
end
9295
RUBY
9396
end
97+
98+
# rubocop:enable Development/NoEvalCop
9499
end
95100
end
96101

0 commit comments

Comments
 (0)