graphql 1.10.6 → 1.10.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/object_generator.rb +50 -8
- data/lib/graphql.rb +4 -4
- data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
- data/lib/graphql/execution/instrumentation.rb +1 -1
- data/lib/graphql/execution/interpreter.rb +2 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +36 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -7
- data/lib/graphql/execution/interpreter/runtime.rb +47 -38
- data/lib/graphql/execution/lookahead.rb +3 -1
- data/lib/graphql/internal_representation/scope.rb +2 -2
- data/lib/graphql/internal_representation/visit.rb +2 -2
- data/lib/graphql/language/document_from_schema_definition.rb +42 -23
- data/lib/graphql/object_type.rb +1 -1
- data/lib/graphql/relay/base_connection.rb +0 -2
- data/lib/graphql/schema.rb +28 -13
- data/lib/graphql/schema/argument.rb +6 -0
- data/lib/graphql/schema/base_64_encoder.rb +2 -0
- data/lib/graphql/schema/enum.rb +9 -1
- data/lib/graphql/schema/field.rb +30 -21
- data/lib/graphql/schema/input_object.rb +9 -6
- data/lib/graphql/schema/interface.rb +5 -0
- data/lib/graphql/schema/list.rb +7 -1
- data/lib/graphql/schema/loader.rb +110 -103
- data/lib/graphql/schema/member.rb +1 -0
- data/lib/graphql/schema/member/has_arguments.rb +33 -13
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/non_null.rb +5 -0
- data/lib/graphql/schema/object.rb +10 -3
- data/lib/graphql/schema/printer.rb +0 -14
- data/lib/graphql/schema/resolver.rb +1 -1
- data/lib/graphql/schema/union.rb +6 -0
- data/lib/graphql/schema/warden.rb +7 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
- data/lib/graphql/subscriptions/subscription_root.rb +10 -2
- data/lib/graphql/tracing.rb +5 -4
- data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
- data/lib/graphql/tracing/platform_tracing.rb +14 -0
- data/lib/graphql/tracing/scout_tracing.rb +11 -0
- data/lib/graphql/types/iso_8601_date.rb +3 -3
- data/lib/graphql/types/iso_8601_date_time.rb +18 -8
- data/lib/graphql/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 647d1d9e043e1e409e56f3d38f7139f2462f2590d5f32b93627dffbb46b0dcdf
|
4
|
+
data.tar.gz: 1cd86cbb6e6452f5300eadaf51a8e6404a6a5a5cdfcffc883ba76190d4960c75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99484e3df661ee34b882bf8e999cbb134574f24d04eb4ed591ecad8f4098ef44b91ba72ae7e856115297cadce8ac13b605df30de5c9b5fd41ba8fbfd5581ac1f
|
7
|
+
data.tar.gz: dfc446058e5abbc0575bbc5ad9e07ec7b2f626ff8b0da73f8bb358efb31c6e35776a9950f07b01dc79032aa8178cf0b9d082b454dab4ce3ecb1d06c051aaecf5
|
@@ -15,20 +15,62 @@ module Graphql
|
|
15
15
|
desc "Create a GraphQL::ObjectType with the given name and fields"
|
16
16
|
source_root File.expand_path('../templates', __FILE__)
|
17
17
|
|
18
|
-
argument :
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
argument :custom_fields,
|
19
|
+
type: :array,
|
20
|
+
default: [],
|
21
|
+
banner: "name:type name:type ...",
|
22
|
+
desc: "Fields for this object (type may be expressed as Ruby or GraphQL)"
|
23
23
|
|
24
24
|
class_option :node,
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
type: :boolean,
|
26
|
+
default: false,
|
27
|
+
desc: "Include the Relay Node interface"
|
28
28
|
|
29
29
|
def create_type_file
|
30
30
|
template "object.erb", "#{options[:directory]}/types/#{type_file_name}.rb"
|
31
31
|
end
|
32
|
+
|
33
|
+
def fields
|
34
|
+
columns = []
|
35
|
+
columns += klass.columns.map { |c| generate_column_string(c) } if class_exists?
|
36
|
+
columns + custom_fields
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.normalize_type_expression(type_expression, mode:, null: true)
|
40
|
+
case type_expression
|
41
|
+
when "Text"
|
42
|
+
["String", null]
|
43
|
+
when "DateTime", "Datetime"
|
44
|
+
["GraphQL::Types::ISO8601DateTime", null]
|
45
|
+
when "Date"
|
46
|
+
["GraphQL::Types::ISO8601Date", null]
|
47
|
+
else
|
48
|
+
super
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def generate_column_string(column)
|
55
|
+
name = column.name
|
56
|
+
required = column.null ? "" : "!"
|
57
|
+
type = column_type_string(column)
|
58
|
+
"#{name}:#{required}#{type}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def column_type_string(column)
|
62
|
+
column.name == "id" ? "ID" : column.type.to_s.camelize
|
63
|
+
end
|
64
|
+
|
65
|
+
def class_exists?
|
66
|
+
klass.is_a?(Class) && klass.ancestors.include?(ActiveRecord::Base)
|
67
|
+
rescue NameError
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
|
71
|
+
def klass
|
72
|
+
@klass ||= Module.const_get(type_name.camelize)
|
73
|
+
end
|
32
74
|
end
|
33
75
|
end
|
34
76
|
end
|
data/lib/graphql.rb
CHANGED
@@ -89,12 +89,15 @@ require "graphql/name_validator"
|
|
89
89
|
require "graphql/language"
|
90
90
|
require "graphql/analysis"
|
91
91
|
require "graphql/tracing"
|
92
|
-
require "graphql/execution"
|
93
92
|
require "graphql/dig"
|
93
|
+
require "graphql/execution"
|
94
94
|
require "graphql/schema"
|
95
95
|
require "graphql/query"
|
96
96
|
require "graphql/directive"
|
97
97
|
require "graphql/execution"
|
98
|
+
require "graphql/runtime_type_error"
|
99
|
+
require "graphql/unresolved_type_error"
|
100
|
+
require "graphql/invalid_null_error"
|
98
101
|
require "graphql/types"
|
99
102
|
require "graphql/relay"
|
100
103
|
require "graphql/boolean_type"
|
@@ -109,10 +112,7 @@ require "graphql/introspection"
|
|
109
112
|
|
110
113
|
require "graphql/analysis_error"
|
111
114
|
require "graphql/coercion_error"
|
112
|
-
require "graphql/runtime_type_error"
|
113
|
-
require "graphql/invalid_null_error"
|
114
115
|
require "graphql/invalid_name_error"
|
115
|
-
require "graphql/unresolved_type_error"
|
116
116
|
require "graphql/integer_encoding_error"
|
117
117
|
require "graphql/string_encoding_error"
|
118
118
|
require "graphql/internal_representation"
|
@@ -54,7 +54,7 @@ module GraphQL
|
|
54
54
|
case defined_complexity
|
55
55
|
when Proc
|
56
56
|
arguments = @query.arguments_for(@node, @field_definition)
|
57
|
-
defined_complexity.call(@query.context, arguments, child_complexity)
|
57
|
+
defined_complexity.call(@query.context, arguments.keyword_arguments, child_complexity)
|
58
58
|
when Numeric
|
59
59
|
defined_complexity + child_complexity
|
60
60
|
else
|
@@ -77,7 +77,7 @@ module GraphQL
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
80
|
-
instrumenters.
|
80
|
+
instrumenters.reverse_each do |instrumenter|
|
81
81
|
begin
|
82
82
|
instrumenter.public_send(after_hook_name, object)
|
83
83
|
rescue => e
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "graphql/execution/interpreter/argument_value"
|
3
|
+
require "graphql/execution/interpreter/arguments"
|
2
4
|
require "graphql/execution/interpreter/arguments_cache"
|
3
5
|
require "graphql/execution/interpreter/execution_errors"
|
4
6
|
require "graphql/execution/interpreter/hash_response"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Execution
|
5
|
+
class Interpreter
|
6
|
+
# A container for metadata regarding arguments present in a GraphQL query.
|
7
|
+
# @see Interpreter::Arguments#argument_values for a hash of these objects.
|
8
|
+
class ArgumentValue
|
9
|
+
def initialize(definition:, value:, default_used:)
|
10
|
+
@definition = definition
|
11
|
+
@value = value
|
12
|
+
@default_used = default_used
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Object] The Ruby-ready value for this Argument
|
16
|
+
attr_reader :value
|
17
|
+
|
18
|
+
# @return [GraphQL::Schema::Argument] The definition instance for this argument
|
19
|
+
attr_reader :definition
|
20
|
+
|
21
|
+
# @return [Boolean] `true` if the schema-defined `default_value:` was applied in this case. (No client-provided value was present.)
|
22
|
+
def default_used?
|
23
|
+
@default_used
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Execution
|
5
|
+
class Interpreter
|
6
|
+
# A wrapper for argument hashes in GraphQL queries.
|
7
|
+
#
|
8
|
+
# @see GraphQL::Query#arguments_for to get access to these objects.
|
9
|
+
class Arguments
|
10
|
+
extend Forwardable
|
11
|
+
include GraphQL::Dig
|
12
|
+
|
13
|
+
# The Ruby-style arguments hash, ready for a resolver.
|
14
|
+
# This hash is the one used at runtime.
|
15
|
+
#
|
16
|
+
# @return [Hash<Symbol, Object>]
|
17
|
+
attr_reader :keyword_arguments
|
18
|
+
|
19
|
+
def initialize(keyword_arguments:, argument_values:)
|
20
|
+
@keyword_arguments = keyword_arguments
|
21
|
+
@argument_values = argument_values
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Hash{Symbol => ArgumentValue}]
|
25
|
+
attr_reader :argument_values
|
26
|
+
|
27
|
+
def_delegators :@keyword_arguments, :key?, :[], :keys, :each, :values
|
28
|
+
def_delegators :@argument_values, :each_value
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
"#<#{self.class} @keyword_arguments=#{keyword_arguments.inspect}>"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -14,13 +14,9 @@ module GraphQL
|
|
14
14
|
# Then call into the schema to coerce those incoming values
|
15
15
|
args = arg_owner.coerce_arguments(parent_object, args_hash, query.context)
|
16
16
|
|
17
|
-
h3[parent_object] =
|
18
|
-
|
19
|
-
|
20
|
-
h3[parent_object] = resolved_args
|
21
|
-
}
|
22
|
-
else
|
23
|
-
args
|
17
|
+
h3[parent_object] = @query.schema.after_lazy(args) do |resolved_args|
|
18
|
+
# when this promise is resolved, update the cache with the resolved value
|
19
|
+
h3[parent_object] = resolved_args
|
24
20
|
end
|
25
21
|
end
|
26
22
|
end
|
@@ -174,9 +174,14 @@ module GraphQL
|
|
174
174
|
next
|
175
175
|
end
|
176
176
|
|
177
|
-
after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments) do |
|
178
|
-
|
179
|
-
|
177
|
+
after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments) do |resolved_arguments|
|
178
|
+
if resolved_arguments.is_a? GraphQL::ExecutionError
|
179
|
+
continue_value(next_path, resolved_arguments, field_defn, return_type.non_null?, ast_node)
|
180
|
+
next
|
181
|
+
end
|
182
|
+
|
183
|
+
kwarg_arguments = resolved_arguments.keyword_arguments
|
184
|
+
|
180
185
|
field_defn.extras.each do |extra|
|
181
186
|
case extra
|
182
187
|
when :ast_node
|
@@ -194,6 +199,8 @@ module GraphQL
|
|
194
199
|
ast_nodes: field_ast_nodes,
|
195
200
|
field: field_defn,
|
196
201
|
)
|
202
|
+
when :argument_details
|
203
|
+
kwarg_arguments[:argument_details] = resolved_arguments
|
197
204
|
else
|
198
205
|
kwarg_arguments[extra] = field_defn.fetch_extra(extra, context)
|
199
206
|
end
|
@@ -247,7 +254,7 @@ module GraphQL
|
|
247
254
|
def continue_value(path, value, field, is_non_null, ast_node)
|
248
255
|
if value.nil?
|
249
256
|
if is_non_null
|
250
|
-
err =
|
257
|
+
err = field.owner::InvalidNullError.new(field.owner, field, value)
|
251
258
|
write_invalid_null_in_response(path, err)
|
252
259
|
else
|
253
260
|
write_in_response(path, nil)
|
@@ -297,18 +304,21 @@ module GraphQL
|
|
297
304
|
write_in_response(path, r)
|
298
305
|
r
|
299
306
|
when "UNION", "INTERFACE"
|
300
|
-
resolved_type_or_lazy = resolve_type(type, value, path)
|
307
|
+
resolved_type_or_lazy, resolved_value = resolve_type(type, value, path)
|
308
|
+
resolved_value ||= value
|
309
|
+
|
301
310
|
after_lazy(resolved_type_or_lazy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |resolved_type|
|
302
311
|
possible_types = query.possible_types(type)
|
303
312
|
|
304
313
|
if !possible_types.include?(resolved_type)
|
305
314
|
parent_type = field.owner
|
306
|
-
|
315
|
+
err_class = type::UnresolvedTypeError
|
316
|
+
type_error = err_class.new(resolved_value, field, parent_type, resolved_type, possible_types)
|
307
317
|
schema.type_error(type_error, context)
|
308
318
|
write_in_response(path, nil)
|
309
319
|
nil
|
310
320
|
else
|
311
|
-
continue_field(path,
|
321
|
+
continue_field(path, resolved_value, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments)
|
312
322
|
end
|
313
323
|
end
|
314
324
|
when "OBJECT"
|
@@ -347,9 +357,15 @@ module GraphQL
|
|
347
357
|
end
|
348
358
|
end
|
349
359
|
end
|
350
|
-
rescue NoMethodError
|
351
|
-
#
|
352
|
-
|
360
|
+
rescue NoMethodError => err
|
361
|
+
# Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
|
362
|
+
if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
|
363
|
+
# This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
|
364
|
+
raise ListResultFailedError.new(value: value, field: field, path: path)
|
365
|
+
else
|
366
|
+
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
367
|
+
raise
|
368
|
+
end
|
353
369
|
end
|
354
370
|
|
355
371
|
response_list
|
@@ -363,11 +379,12 @@ module GraphQL
|
|
363
379
|
end
|
364
380
|
end
|
365
381
|
|
366
|
-
def resolve_with_directives(object, ast_node)
|
367
|
-
|
382
|
+
def resolve_with_directives(object, ast_node, &block)
|
383
|
+
return yield if ast_node.directives.empty?
|
384
|
+
run_directive(object, ast_node, 0, &block)
|
368
385
|
end
|
369
386
|
|
370
|
-
def run_directive(object, ast_node, idx)
|
387
|
+
def run_directive(object, ast_node, idx, &block)
|
371
388
|
dir_node = ast_node.directives[idx]
|
372
389
|
if !dir_node
|
373
390
|
yield
|
@@ -376,9 +393,9 @@ module GraphQL
|
|
376
393
|
if !dir_defn.is_a?(Class)
|
377
394
|
dir_defn = dir_defn.type_class || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
|
378
395
|
end
|
379
|
-
dir_args = arguments(nil, dir_defn, dir_node)
|
396
|
+
dir_args = arguments(nil, dir_defn, dir_node).keyword_arguments
|
380
397
|
dir_defn.resolve(object, dir_args, context) do
|
381
|
-
run_directive(object, ast_node, idx + 1)
|
398
|
+
run_directive(object, ast_node, idx + 1, &block)
|
382
399
|
end
|
383
400
|
end
|
384
401
|
end
|
@@ -387,7 +404,7 @@ module GraphQL
|
|
387
404
|
def directives_include?(node, graphql_object, parent_type)
|
388
405
|
node.directives.each do |dir_node|
|
389
406
|
dir_defn = schema.directives.fetch(dir_node.name).type_class || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
|
390
|
-
args = arguments(graphql_object, dir_defn, dir_node)
|
407
|
+
args = arguments(graphql_object, dir_defn, dir_node).keyword_arguments
|
391
408
|
if !dir_defn.include?(graphql_object, args, context)
|
392
409
|
return false
|
393
410
|
end
|
@@ -401,7 +418,7 @@ module GraphQL
|
|
401
418
|
# @param eager [Boolean] Set to `true` for mutation root fields only
|
402
419
|
# @param trace [Boolean] If `false`, don't wrap this with field tracing
|
403
420
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
404
|
-
def after_lazy(lazy_obj, owner:, field:, path:, scoped_context:, owner_object:, arguments:, eager: false, trace: true)
|
421
|
+
def after_lazy(lazy_obj, owner:, field:, path:, scoped_context:, owner_object:, arguments:, eager: false, trace: true, &block)
|
405
422
|
@interpreter_context[:current_object] = owner_object
|
406
423
|
@interpreter_context[:current_arguments] = arguments
|
407
424
|
@interpreter_context[:current_path] = path
|
@@ -426,11 +443,9 @@ module GraphQL
|
|
426
443
|
end
|
427
444
|
end
|
428
445
|
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
|
429
|
-
|
430
|
-
end
|
431
|
-
after_lazy(inner_obj, owner: owner, field: field, path: path, scoped_context: context.scoped_context, owner_object: owner_object, arguments: arguments, eager: eager) do |really_inner_obj|
|
432
|
-
yield(really_inner_obj)
|
446
|
+
err
|
433
447
|
end
|
448
|
+
after_lazy(inner_obj, owner: owner, field: field, path: path, scoped_context: context.scoped_context, owner_object: owner_object, arguments: arguments, eager: eager, trace: trace, &block)
|
434
449
|
end
|
435
450
|
|
436
451
|
if eager
|
@@ -445,7 +460,13 @@ module GraphQL
|
|
445
460
|
end
|
446
461
|
|
447
462
|
def arguments(graphql_object, arg_owner, ast_node)
|
448
|
-
|
463
|
+
# Don't cache arguments if field extras are requested since extras mutate the argument data structure
|
464
|
+
if arg_owner.arguments_statically_coercible? && (!arg_owner.is_a?(GraphQL::Schema::Field) || arg_owner.extras.empty?)
|
465
|
+
query.arguments_for(ast_node, arg_owner)
|
466
|
+
else
|
467
|
+
# The arguments must be prepared in the context of the given object
|
468
|
+
query.arguments_for(ast_node, arg_owner, parent_object: graphql_object)
|
469
|
+
end
|
449
470
|
end
|
450
471
|
|
451
472
|
def write_invalid_null_in_response(path, invalid_null_error)
|
@@ -485,23 +506,11 @@ module GraphQL
|
|
485
506
|
# at previous parts of the response.
|
486
507
|
# This hash matches the response
|
487
508
|
def type_at(path)
|
488
|
-
|
489
|
-
path.each do |part|
|
490
|
-
t = t[part] || (raise("Invariant: #{part.inspect} not found in #{t}"))
|
491
|
-
end
|
492
|
-
t = t[:__type]
|
493
|
-
t
|
509
|
+
@types_at_paths.fetch(path)
|
494
510
|
end
|
495
511
|
|
496
512
|
def set_type_at_path(path, type)
|
497
|
-
|
498
|
-
path.each do |part|
|
499
|
-
types = types[part] ||= {}
|
500
|
-
end
|
501
|
-
# Use this magic key so that the hash contains:
|
502
|
-
# - string keys for nested fields
|
503
|
-
# - :__type for the object type of a selection
|
504
|
-
types[:__type] ||= type
|
513
|
+
@types_at_paths[path] = type
|
505
514
|
nil
|
506
515
|
end
|
507
516
|
|
@@ -531,7 +540,7 @@ module GraphQL
|
|
531
540
|
|
532
541
|
def resolve_type(type, value, path)
|
533
542
|
trace_payload = { context: context, type: type, object: value, path: path }
|
534
|
-
resolved_type = query.trace("resolve_type", trace_payload) do
|
543
|
+
resolved_type, resolved_value = query.trace("resolve_type", trace_payload) do
|
535
544
|
query.resolve_type(type, value)
|
536
545
|
end
|
537
546
|
|
@@ -542,7 +551,7 @@ module GraphQL
|
|
542
551
|
end
|
543
552
|
end
|
544
553
|
else
|
545
|
-
resolved_type
|
554
|
+
[resolved_type, resolved_value]
|
546
555
|
end
|
547
556
|
end
|
548
557
|
|
@@ -55,7 +55,9 @@ module GraphQL
|
|
55
55
|
@arguments
|
56
56
|
else
|
57
57
|
@arguments = if @field
|
58
|
-
@query.arguments_for(@ast_nodes.first, @field)
|
58
|
+
@query.schema.after_lazy(@query.arguments_for(@ast_nodes.first, @field)) do |args|
|
59
|
+
args.is_a?(Execution::Interpreter::Arguments) ? args.keyword_arguments : args
|
60
|
+
end
|
59
61
|
else
|
60
62
|
nil
|
61
63
|
end
|
@@ -66,11 +66,11 @@ module GraphQL
|
|
66
66
|
# Call the block for each type in `self`.
|
67
67
|
# This uses the simplest possible expression of `self`,
|
68
68
|
# so if this scope is defined by an abstract type, it gets yielded.
|
69
|
-
def each
|
69
|
+
def each(&block)
|
70
70
|
if @abstract_type
|
71
71
|
yield(@type)
|
72
72
|
else
|
73
|
-
@types.each
|
73
|
+
@types.each(&block)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|