graphql 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graph_ql/{types/input_value.rb → argument.rb} +4 -1
- data/lib/graph_ql/{scalars/boolean_type.rb → boolean_type.rb} +0 -0
- data/lib/graph_ql/definition_helpers.rb +10 -0
- data/lib/graph_ql/definition_helpers/argument_definer.rb +5 -2
- data/lib/graph_ql/definition_helpers/definable.rb +1 -1
- data/lib/graph_ql/definition_helpers/field_definer.rb +4 -1
- data/lib/graph_ql/definition_helpers/non_null_with_bang.rb +3 -1
- data/lib/graph_ql/definition_helpers/string_named_hash.rb +7 -1
- data/lib/graph_ql/definition_helpers/type_definer.rb +13 -1
- data/lib/graph_ql/directive.rb +14 -6
- data/lib/graph_ql/{directives → directive}/include_directive.rb +1 -1
- data/lib/graph_ql/{directives → directive}/skip_directive.rb +1 -1
- data/lib/graph_ql/enum_type.rb +66 -0
- data/lib/graph_ql/field.rb +49 -13
- data/lib/graph_ql/{scalars/float_type.rb → float_type.rb} +0 -0
- data/lib/graph_ql/{scalars/id_type.rb → id_type.rb} +0 -0
- data/lib/graph_ql/input_object_type.rb +33 -0
- data/lib/graph_ql/{scalars/int_type.rb → int_type.rb} +0 -0
- data/lib/graph_ql/interface_type.rb +33 -0
- data/lib/graph_ql/introspection/field_type.rb +1 -0
- data/lib/graph_ql/introspection/fields_field.rb +1 -0
- data/lib/graph_ql/introspection/input_value_type.rb +1 -1
- data/lib/graph_ql/introspection/introspection_query.rb +77 -0
- data/lib/graph_ql/introspection/schema_field.rb +13 -0
- data/lib/graph_ql/introspection/type_by_name_field.rb +14 -0
- data/lib/graph_ql/introspection/type_kind_enum.rb +1 -1
- data/lib/graph_ql/{types/list_type.rb → list_type.rb} +3 -0
- data/lib/graph_ql/{parser/nodes.rb → nodes.rb} +8 -1
- data/lib/graph_ql/{types/non_null_type.rb → non_null_type.rb} +3 -0
- data/lib/graph_ql/object_type.rb +92 -0
- data/lib/graph_ql/parser.rb +107 -6
- data/lib/graph_ql/query.rb +8 -0
- data/lib/graph_ql/query/arguments.rb +13 -4
- data/lib/graph_ql/{directives → query}/directive_chain.rb +2 -2
- data/lib/graph_ql/query/field_resolution_strategy.rb +2 -2
- data/lib/graph_ql/query/operation_resolver.rb +3 -3
- data/lib/graph_ql/query/selection_resolver.rb +1 -1
- data/lib/graph_ql/scalar_type.rb +9 -0
- data/lib/graph_ql/schema.rb +26 -17
- data/lib/graph_ql/schema/type_reducer.rb +7 -0
- data/lib/graph_ql/static_validation/arguments_validator.rb +1 -0
- data/lib/graph_ql/static_validation/message.rb +4 -1
- data/lib/graph_ql/static_validation/rules/fields_are_defined_on_type.rb +1 -0
- data/lib/graph_ql/static_validation/rules/fields_have_appropriate_selections.rb +1 -0
- data/lib/graph_ql/static_validation/type_stack.rb +24 -4
- data/lib/graph_ql/static_validation/validator.rb +27 -0
- data/lib/graph_ql/{scalars/string_type.rb → string_type.rb} +0 -0
- data/lib/graph_ql/transform.rb +87 -0
- data/lib/graph_ql/type_kinds.rb +9 -0
- data/lib/graph_ql/{types/union.rb → union_type.rb} +8 -4
- data/lib/graph_ql/version.rb +1 -1
- data/lib/graph_ql/{parser/visitor.rb → visitor.rb} +29 -4
- data/lib/graphql.rb +28 -11
- data/readme.md +11 -1
- data/spec/graph_ql/{types/enum_spec.rb → enum_type_spec.rb} +1 -1
- data/spec/graph_ql/{fields/field_spec.rb → field_spec.rb} +0 -0
- data/spec/graph_ql/{scalars/id_type_spec.rb → id_type_spec.rb} +0 -0
- data/spec/graph_ql/{types/input_object_type_spec.rb → input_object_type_spec.rb} +0 -0
- data/spec/graph_ql/{types/interface_spec.rb → interface_type_spec.rb} +1 -1
- data/spec/graph_ql/introspection/introspection_query_spec.rb +10 -0
- data/spec/graph_ql/introspection/schema_type_spec.rb +0 -4
- data/spec/graph_ql/introspection/type_type_spec.rb +1 -5
- data/spec/graph_ql/{types/object_type_spec.rb → object_type_spec.rb} +0 -0
- data/spec/graph_ql/{parser/parser_spec.rb → parser_spec.rb} +0 -0
- data/spec/graph_ql/query/operation_resolver_spec.rb +1 -1
- data/spec/graph_ql/query_spec.rb +6 -2
- data/spec/graph_ql/schema/type_validator_spec.rb +1 -1
- data/spec/graph_ql/{parser/transform_spec.rb → transform_spec.rb} +0 -0
- data/spec/graph_ql/{types/union_spec.rb → union_type_spec.rb} +2 -2
- data/spec/graph_ql/{parser/visitor_spec.rb → visitor_spec.rb} +0 -0
- data/spec/support/{dummy_app.rb → dairy_app.rb} +8 -8
- data/spec/support/{dummy_data.rb → dairy_data.rb} +0 -0
- data/spec/support/star_wars_data.rb +71 -0
- data/spec/support/star_wars_schema.rb +87 -0
- metadata +59 -50
- data/lib/graph_ql/definition_helpers/forwardable.rb +0 -10
- data/lib/graph_ql/parser/parser.rb +0 -108
- data/lib/graph_ql/parser/transform.rb +0 -87
- data/lib/graph_ql/scalars/scalar_type.rb +0 -5
- data/lib/graph_ql/types/enum.rb +0 -32
- data/lib/graph_ql/types/input_object_type.rb +0 -14
- data/lib/graph_ql/types/interface.rb +0 -14
- data/lib/graph_ql/types/object_type.rb +0 -66
@@ -1,108 +0,0 @@
|
|
1
|
-
# Parser is a [parslet](http://kschiess.github.io/parslet/) parser for parsing queries.
|
2
|
-
#
|
3
|
-
# If it failes to parse, a {SyntaxError} is raised.
|
4
|
-
class GraphQL::Parser < Parslet::Parser
|
5
|
-
root(:document)
|
6
|
-
rule(:document) { (
|
7
|
-
space |
|
8
|
-
operation_definition |
|
9
|
-
fragment_definition
|
10
|
-
).repeat(1).as(:document_parts)
|
11
|
-
}
|
12
|
-
|
13
|
-
# TODO: whitespace sensitive regarding `on`, eg `onFood`, see lookahead note in spec
|
14
|
-
rule(:fragment_definition) {
|
15
|
-
str("fragment").as(:fragment_keyword) >>
|
16
|
-
space? >> name.as(:fragment_name) >>
|
17
|
-
space? >> str("on") >> space? >> name.as(:type_condition) >>
|
18
|
-
space? >> directives.maybe.as(:optional_directives).as(:directives) >>
|
19
|
-
space? >> selections.as(:selections)
|
20
|
-
}
|
21
|
-
|
22
|
-
rule(:fragment_spread) {
|
23
|
-
spread.as(:fragment_spread_keyword) >> space? >>
|
24
|
-
name.as(:fragment_spread_name) >> space? >>
|
25
|
-
directives.maybe.as(:optional_directives).as(:directives)
|
26
|
-
}
|
27
|
-
rule(:spread) { str("...") }
|
28
|
-
# TODO: `on` bug, see spec
|
29
|
-
rule(:inline_fragment) {
|
30
|
-
spread.as(:fragment_spread_keyword) >> space? >>
|
31
|
-
str("on ") >> name.as(:inline_fragment_type) >> space? >>
|
32
|
-
directives.maybe.as(:optional_directives).as(:directives) >> space? >>
|
33
|
-
selections.as(:selections)
|
34
|
-
}
|
35
|
-
|
36
|
-
rule(:operation_definition) { (unnamed_selections | named_operation_definition) }
|
37
|
-
rule(:unnamed_selections) { selections.as(:unnamed_selections)}
|
38
|
-
rule(:named_operation_definition) {
|
39
|
-
operation_type.as(:operation_type) >> space? >>
|
40
|
-
name.as(:name) >> space? >>
|
41
|
-
operation_variable_definitions.maybe.as(:optional_variables).as(:variables) >> space? >>
|
42
|
-
directives.maybe.as(:optional_directives).as(:directives) >> space? >>
|
43
|
-
selections.as(:selections)
|
44
|
-
}
|
45
|
-
rule(:operation_type) { (str("query") | str("mutation")) }
|
46
|
-
rule(:operation_variable_definitions) { str("(") >> space? >> (operation_variable_definition >> separator?).repeat(1) >> space? >> str(")") }
|
47
|
-
rule(:operation_variable_definition) {
|
48
|
-
value_variable.as(:variable_name) >> space? >>
|
49
|
-
str(":") >> space? >>
|
50
|
-
type.as(:variable_type) >> space? >>
|
51
|
-
(str("=") >> space? >> value.as(:variable_default_value)).maybe.as(:variable_optional_default_value)}
|
52
|
-
|
53
|
-
rule(:selection) { (inline_fragment | fragment_spread | field) >> space? >> separator? }
|
54
|
-
rule(:selections) { str("{") >> space? >> selection.repeat(1) >> space? >> str("}")}
|
55
|
-
|
56
|
-
rule(:field) {
|
57
|
-
field_alias.maybe.as(:alias) >>
|
58
|
-
name.as(:field_name) >>
|
59
|
-
field_arguments.maybe.as(:optional_field_arguments).as(:field_arguments) >> space? >>
|
60
|
-
directives.maybe.as(:optional_directives).as(:directives) >> space? >>
|
61
|
-
selections.maybe.as(:optional_selections).as(:selections)
|
62
|
-
}
|
63
|
-
|
64
|
-
rule(:field_alias) { name.as(:alias_name) >> space? >> str(":") >> space? }
|
65
|
-
rule(:field_arguments) { str("(") >> field_argument.repeat(1) >> str(")") }
|
66
|
-
rule(:field_argument) { name.as(:field_argument_name) >> str(":") >> space? >> value.as(:field_argument_value) >> separator? }
|
67
|
-
|
68
|
-
rule(:directives) { (directive >> separator?).repeat(1) }
|
69
|
-
rule(:directive) {
|
70
|
-
str("@") >> name.as(:directive_name) >>
|
71
|
-
directive_arguments.maybe.as(:optional_directive_arguments).as(:directive_arguments)
|
72
|
-
}
|
73
|
-
rule(:directive_arguments) { str("(") >> directive_argument.repeat(1) >> str(")") }
|
74
|
-
rule(:directive_argument) { name.as(:directive_argument_name) >> str(":") >> space? >> value.as(:directive_argument_value) >> separator? }
|
75
|
-
|
76
|
-
rule(:type) { (non_null_type | list_type | type_name)}
|
77
|
-
rule(:list_type) { str("[") >> type.as(:list_type) >> str("]")}
|
78
|
-
rule(:non_null_type) { (list_type | type_name).as(:non_null_type) >> str("!") }
|
79
|
-
rule(:type_name) { name.as(:type_name) }
|
80
|
-
|
81
|
-
rule(:value) {(
|
82
|
-
value_input_object |
|
83
|
-
value_float |
|
84
|
-
value_int |
|
85
|
-
value_string |
|
86
|
-
value_boolean |
|
87
|
-
value_array |
|
88
|
-
value_variable |
|
89
|
-
value_enum
|
90
|
-
)}
|
91
|
-
rule(:value_sign?) { match('[\-\+]').maybe }
|
92
|
-
rule(:value_array) { (str("[") >> (value >> separator?).repeat(0) >> str("]")).as(:array) }
|
93
|
-
rule(:value_boolean) { (str("true") | str("false")).as(:boolean) }
|
94
|
-
rule(:value_float) { (value_sign? >> match('\d').repeat(1) >> str(".") >> match('\d').repeat(1) >> (match("[eE]") >> value_sign? >> match('\d').repeat(1)).maybe).as(:float) }
|
95
|
-
rule(:value_input_object) { str("{") >> value_input_object_pair.repeat(1).as(:input_object) >> str("}") }
|
96
|
-
rule(:value_input_object_pair) { space? >> name.as(:input_object_name) >> space? >> str(":") >> space? >> value.as(:input_object_value) >> separator? }
|
97
|
-
rule(:value_int) { (value_sign? >> match('\d').repeat(1)).as(:int) }
|
98
|
-
# TODO: support unicode, escaped chars (match the spec)
|
99
|
-
rule(:value_string) { str('"') >> match('[^\"]').repeat(1).as(:string) >> str('"')}
|
100
|
-
rule(:value_enum) { name.as(:enum) }
|
101
|
-
rule(:value_variable) { str("$") >> name.as(:variable) }
|
102
|
-
|
103
|
-
rule(:separator?) { (space? >> str(",") >> space?).maybe }
|
104
|
-
rule(:name) { match('[_A-Za-z]') >> match('[_0-9A-Za-z]').repeat(0) }
|
105
|
-
rule(:comment) { str("#") >> match('[^\r\n]').repeat(0) }
|
106
|
-
rule(:space) { (match('[\s\n]+') | comment).repeat(1) }
|
107
|
-
rule(:space?) { space.maybe }
|
108
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
# {Transform} is a [parslet](http://kschiess.github.io/parslet/) transform for for turning the AST into objects in {GraphQL::Nodes} objects.
|
2
|
-
class GraphQL::Transform < Parslet::Transform
|
3
|
-
# Get syntax classes by shallow name:
|
4
|
-
include GraphQL::Nodes
|
5
|
-
|
6
|
-
def self.optional_sequence(name)
|
7
|
-
rule(name => simple(:val)) { [] }
|
8
|
-
rule(name => sequence(:val)) { val }
|
9
|
-
end
|
10
|
-
|
11
|
-
# Document
|
12
|
-
rule(document_parts: sequence(:p)) { Document.new(parts: p, line: p.first.line, col: p.first.col)}
|
13
|
-
|
14
|
-
# Fragment Definition
|
15
|
-
rule(
|
16
|
-
fragment_keyword: simple(:kw),
|
17
|
-
fragment_name: simple(:name),
|
18
|
-
type_condition: simple(:type),
|
19
|
-
directives: sequence(:directives),
|
20
|
-
selections: sequence(:selections)
|
21
|
-
) {FragmentDefinition.new(name: name.to_s, type: type.to_s, directives: directives, selections: selections, position_source: kw)}
|
22
|
-
|
23
|
-
rule(
|
24
|
-
fragment_spread_keyword: simple(:kw),
|
25
|
-
fragment_spread_name: simple(:n),
|
26
|
-
directives: sequence(:d)
|
27
|
-
) { FragmentSpread.new(name: n.to_s, directives: d, position_source: kw)}
|
28
|
-
|
29
|
-
rule(
|
30
|
-
fragment_spread_keyword: simple(:kw),
|
31
|
-
inline_fragment_type: simple(:n),
|
32
|
-
directives: sequence(:d),
|
33
|
-
selections: sequence(:s),
|
34
|
-
) { InlineFragment.new(type: n.to_s, directives: d, selections: s, position_source: kw)}
|
35
|
-
|
36
|
-
# Operation Definition
|
37
|
-
rule(
|
38
|
-
operation_type: simple(:ot),
|
39
|
-
name: simple(:n),
|
40
|
-
variables: sequence(:v),
|
41
|
-
directives: sequence(:d),
|
42
|
-
selections: sequence(:s),
|
43
|
-
) { OperationDefinition.new(operation_type: ot.to_s, name: n.to_s, variables: v, directives: d, selections: s, position_source: ot) }
|
44
|
-
optional_sequence(:optional_variables)
|
45
|
-
rule(variable_name: simple(:n), variable_type: simple(:t), variable_optional_default_value: simple(:v)) { Variable.new(name: n.name, type: t, default_value: v, line: n.line, col: n.col)}
|
46
|
-
rule(variable_name: simple(:n), variable_type: simple(:t), variable_optional_default_value: sequence(:v)) { Variable.new(name: n.name, type: t, default_value: v, line: n.line, col: n.col)}
|
47
|
-
rule(variable_default_value: simple(:v) ) { v }
|
48
|
-
rule(variable_default_value: sequence(:v) ) { v }
|
49
|
-
# Query short-hand
|
50
|
-
rule(unnamed_selections: sequence(:s)) { OperationDefinition.new(selections: s, operation_type: "query", name: nil, variables: [], directives: [], line: s.first.line, col: s.first.col)}
|
51
|
-
|
52
|
-
# Field
|
53
|
-
rule(
|
54
|
-
alias: simple(:a),
|
55
|
-
field_name: simple(:name),
|
56
|
-
field_arguments: sequence(:args),
|
57
|
-
directives: sequence(:dir),
|
58
|
-
selections: sequence(:sel)
|
59
|
-
) { Field.new(alias: a && a.to_s, name: name.to_s, arguments: args, directives: dir, selections: sel, position_source: [a, name].find { |part| !part.nil? }) }
|
60
|
-
|
61
|
-
rule(alias_name: simple(:a)) { a }
|
62
|
-
optional_sequence(:optional_field_arguments)
|
63
|
-
rule(field_argument_name: simple(:n), field_argument_value: simple(:v)) { Argument.new(name: n.to_s, value: v, position_source: n)}
|
64
|
-
optional_sequence(:optional_selections)
|
65
|
-
optional_sequence(:optional_directives)
|
66
|
-
|
67
|
-
# Directive
|
68
|
-
rule(directive_name: simple(:name), directive_arguments: sequence(:args)) { Directive.new(name: name.to_s, arguments: args, position_source: name ) }
|
69
|
-
rule(directive_argument_name: simple(:n), directive_argument_value: simple(:v)) { Argument.new(name: n.to_s, value: v, position_source: n)}
|
70
|
-
optional_sequence(:optional_directive_arguments)
|
71
|
-
|
72
|
-
# Type Defs
|
73
|
-
rule(type_name: simple(:n)) { TypeName.new(name: n.to_s, position_source: n) }
|
74
|
-
rule(list_type: simple(:t)) { ListType.new(of_type: t, line: t.line, col: t.col)}
|
75
|
-
rule(non_null_type: simple(:t)) { NonNullType.new(of_type: t, line: t.line, col: t.col)}
|
76
|
-
|
77
|
-
# Values
|
78
|
-
rule(array: sequence(:v)) { v }
|
79
|
-
rule(boolean: simple(:v)) { v == "true" ? true : false }
|
80
|
-
rule(input_object: sequence(:v)) { InputObject.new(pairs: v, line: v.first.line, col: v.first.col) }
|
81
|
-
rule(input_object_name: simple(:n), input_object_value: simple(:v)) { Argument.new(name: n.to_s, value: v, position_source: n)}
|
82
|
-
rule(int: simple(:v)) { v.to_i }
|
83
|
-
rule(float: simple(:v)) { v.to_f }
|
84
|
-
rule(string: simple(:v)) { v.to_s }
|
85
|
-
rule(variable: simple(:v)) { VariableIdentifier.new(name: v.to_s, position_source: v) }
|
86
|
-
rule(enum: simple(:v)) { Enum.new(name: v.to_s, position_source: v)}
|
87
|
-
end
|
data/lib/graph_ql/types/enum.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
class GraphQL::Enum
|
2
|
-
include GraphQL::NonNullWithBang
|
3
|
-
extend GraphQL::Definable
|
4
|
-
attr_definable :name, :description
|
5
|
-
attr_reader :values
|
6
|
-
def initialize
|
7
|
-
@values = {}
|
8
|
-
yield(self, GraphQL::TypeDefiner.instance, GraphQL::FieldDefiner.instance, GraphQL::ArgumentDefiner.instance)
|
9
|
-
end
|
10
|
-
|
11
|
-
def value(name, description=nil, deprecation_reason: nil, value: name)
|
12
|
-
@values[name] = EnumValue.new(name: name, description: description, deprecation_reason: deprecation_reason, value: value)
|
13
|
-
end
|
14
|
-
|
15
|
-
def kind
|
16
|
-
GraphQL::TypeKinds::ENUM
|
17
|
-
end
|
18
|
-
|
19
|
-
def coerce(value_name)
|
20
|
-
@values[value_name].value
|
21
|
-
end
|
22
|
-
|
23
|
-
class EnumValue
|
24
|
-
attr_reader :name, :description, :deprecation_reason, :value
|
25
|
-
def initialize(name:, description:, deprecation_reason:, value:)
|
26
|
-
@name = name
|
27
|
-
@description = description
|
28
|
-
@deprecation_reason = deprecation_reason
|
29
|
-
@value = value
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class GraphQL::InputObjectType < GraphQL::ObjectType
|
2
|
-
attr_definable :input_fields
|
3
|
-
|
4
|
-
def input_fields(new_fields=nil)
|
5
|
-
if !new_fields.nil?
|
6
|
-
@new_fields = GraphQL::StringNamedHash.new(new_fields).to_h
|
7
|
-
end
|
8
|
-
@new_fields
|
9
|
-
end
|
10
|
-
|
11
|
-
def kind
|
12
|
-
GraphQL::TypeKinds::INPUT_OBJECT
|
13
|
-
end
|
14
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class GraphQL::Interface < GraphQL::ObjectType
|
2
|
-
def kind
|
3
|
-
GraphQL::TypeKinds::INTERFACE
|
4
|
-
end
|
5
|
-
|
6
|
-
def possible_types
|
7
|
-
@possible_types ||= []
|
8
|
-
end
|
9
|
-
|
10
|
-
# Might have to override this in your own interface
|
11
|
-
def resolve_type(object)
|
12
|
-
@possible_types.find {|t| t.name == object.class.name }
|
13
|
-
end
|
14
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
class GraphQL::ObjectType
|
2
|
-
extend GraphQL::Definable
|
3
|
-
attr_definable :name, :description, :interfaces, :fields
|
4
|
-
include GraphQL::NonNullWithBang
|
5
|
-
|
6
|
-
def initialize(&block)
|
7
|
-
self.fields = []
|
8
|
-
self.interfaces = []
|
9
|
-
yield(self, GraphQL::TypeDefiner.instance, GraphQL::FieldDefiner.instance, GraphQL::ArgumentDefiner.instance)
|
10
|
-
end
|
11
|
-
|
12
|
-
def fields(new_fields=nil)
|
13
|
-
if !new_fields.nil?
|
14
|
-
self.fields = new_fields
|
15
|
-
end
|
16
|
-
@fields
|
17
|
-
end
|
18
|
-
|
19
|
-
def fields=(new_fields)
|
20
|
-
stringified_fields = GraphQL::StringNamedHash.new(new_fields).to_h
|
21
|
-
# TODO: should this field be exposed during introspection? https://github.com/graphql/graphql-js/issues/73
|
22
|
-
stringified_fields["__typename"] = GraphQL::Introspection::TypenameField.create(self)
|
23
|
-
@fields = stringified_fields
|
24
|
-
end
|
25
|
-
|
26
|
-
def interfaces(new_interfaces=nil)
|
27
|
-
if !new_interfaces.nil?
|
28
|
-
# if you define interfaces twice, you're gonna have a bad time :(
|
29
|
-
# (because it gets registered with that interface, then overriden)
|
30
|
-
@interfaces = new_interfaces
|
31
|
-
new_interfaces.each {|i| i.possible_types << self }
|
32
|
-
end
|
33
|
-
@interfaces
|
34
|
-
end
|
35
|
-
|
36
|
-
def kind
|
37
|
-
GraphQL::TypeKinds::OBJECT
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_s
|
41
|
-
Printer.instance.print(self)
|
42
|
-
end
|
43
|
-
|
44
|
-
alias :inspect :to_s
|
45
|
-
|
46
|
-
def ==(other)
|
47
|
-
if other.is_a?(GraphQL::ObjectType)
|
48
|
-
self.to_s == other.to_s
|
49
|
-
else
|
50
|
-
super
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
class Printer
|
55
|
-
include Singleton
|
56
|
-
def print(type)
|
57
|
-
if type.kind.non_null?
|
58
|
-
"#{print(type.of_type)}!"
|
59
|
-
elsif type.kind.list?
|
60
|
-
"[#{print(type.of_type)}]"
|
61
|
-
else
|
62
|
-
type.name
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|