graphql 0.9.5 → 0.10.0

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/base_type.rb +24 -0
  3. data/lib/graphql/definition_helpers/defined_by_config.rb +5 -4
  4. data/lib/graphql/definition_helpers/non_null_with_bang.rb +1 -1
  5. data/lib/graphql/definition_helpers/type_definer.rb +1 -1
  6. data/lib/graphql/enum_type.rb +16 -3
  7. data/lib/graphql/input_object_type.rb +10 -0
  8. data/lib/graphql/language.rb +0 -5
  9. data/lib/graphql/language/nodes.rb +79 -75
  10. data/lib/graphql/language/parser.rb +109 -106
  11. data/lib/graphql/language/transform.rb +100 -91
  12. data/lib/graphql/language/visitor.rb +78 -74
  13. data/lib/graphql/list_type.rb +5 -0
  14. data/lib/graphql/non_null_type.rb +6 -2
  15. data/lib/graphql/query.rb +58 -9
  16. data/lib/graphql/query/arguments.rb +29 -26
  17. data/lib/graphql/query/base_execution/value_resolution.rb +3 -3
  18. data/lib/graphql/query/directive_chain.rb +1 -1
  19. data/lib/graphql/query/executor.rb +6 -27
  20. data/lib/graphql/query/literal_input.rb +89 -0
  21. data/lib/graphql/query/ruby_input.rb +20 -0
  22. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  23. data/lib/graphql/query/variables.rb +39 -0
  24. data/lib/graphql/scalar_type.rb +27 -5
  25. data/lib/graphql/schema.rb +5 -0
  26. data/lib/graphql/schema/type_expression.rb +28 -0
  27. data/lib/graphql/static_validation/literal_validator.rb +5 -2
  28. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +0 -2
  29. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
  30. data/lib/graphql/version.rb +1 -1
  31. data/readme.md +3 -2
  32. data/spec/graphql/enum_type_spec.rb +7 -2
  33. data/spec/graphql/input_object_type_spec.rb +45 -0
  34. data/spec/graphql/language/parser_spec.rb +2 -1
  35. data/spec/graphql/language/transform_spec.rb +5 -0
  36. data/spec/graphql/query/base_execution/value_resolution_spec.rb +46 -0
  37. data/spec/graphql/query/context_spec.rb +37 -0
  38. data/spec/graphql/query/executor_spec.rb +33 -0
  39. data/spec/graphql/query_spec.rb +110 -26
  40. data/spec/graphql/schema/type_expression_spec.rb +38 -0
  41. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +2 -2
  42. data/spec/support/dairy_app.rb +17 -17
  43. data/spec/support/dairy_data.rb +2 -2
  44. metadata +12 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e860d8ee6cbcf24b38c43ea7182153e9e1ea6c17
4
- data.tar.gz: 6ffcb982ea45a2e3c16fb68726a1c583849f5184
3
+ metadata.gz: 9cb8700392b11bc4b4e577e38b424c13b3d33dd9
4
+ data.tar.gz: 36f2b6d48b2d11084aeb4d0ea50c194e1f2a4b27
5
5
  SHA512:
6
- metadata.gz: 6990e5ed872ebf7efed61846915a57ed7e21b76ab82ea9c33233bb4747cdb49c435c2e2d2f0a7b8942dbded68800ca54fe517643a9b1bb4a1fb3cfc0f1cd98c4
7
- data.tar.gz: a4740639e811cd70e43b01fa22e8a9d35005b5825778bfa1b5ce31940cf1fc9dc8bb2fc2c262579cd2548645bfc982054fa055eae4ea3d9e4c941015f789def5
6
+ metadata.gz: c8498188be3457f626d74653e48bee19558fc3030f383d8fe65cdf3cfa7f0cf9c8eeabafb1de634a48f9f991de77a0e2630056356de5854af78adbc03881cc14
7
+ data.tar.gz: de3a1fcfdecefe84e9ed578c9840e861670df763dfb7bd96b11e97e7971c6cbd10c669674cc574904ae9fd0b0db29d70f3dac1bf2aa1f3e430320067dd88859a
@@ -20,6 +20,16 @@ module GraphQL
20
20
  self
21
21
  end
22
22
 
23
+ # @return [GraphQL::NonNullType] a non-null version of this type
24
+ def to_non_null_type
25
+ GraphQL::NonNullType.new(of_type: self)
26
+ end
27
+
28
+ # @return [GraphQL::ListType] a list version of this type
29
+ def to_list_type
30
+ GraphQL::ListType.new(of_type: self)
31
+ end
32
+
23
33
  module ModifiesAnotherType
24
34
  def unwrap
25
35
  self.of_type.unwrap
@@ -65,5 +75,19 @@ module GraphQL
65
75
  end
66
76
 
67
77
  alias :inspect :to_s
78
+
79
+ # Coerce `input_value` according to this type's `coerce` method.
80
+ # Raise an error if the value becomes nil.
81
+ # @param [Object] Incoming query value
82
+ # @return [Object] Coerced value for query execution
83
+ def coerce_input!(input_value)
84
+ coerced_value = coerce_input(input_value)
85
+
86
+ if coerced_value.nil?
87
+ raise GraphQL::ExecutionError.new("Couldn't coerce #{input_value.inspect} to #{self.unwrap.name}")
88
+ end
89
+
90
+ coerced_value
91
+ end
68
92
  end
69
93
  end
@@ -31,7 +31,9 @@ module GraphQL::DefinitionHelpers::DefinedByConfig
31
31
  :possible_types, # interface / union
32
32
  :default_value, # argument
33
33
  :on, # directive
34
- :coerce #scalar
34
+ :coerce, #scalar
35
+ :coerce_input, #scalar
36
+ :coerce_result #scalar
35
37
 
36
38
  attr_reader :fields, :input_fields, :arguments, :values
37
39
 
@@ -41,7 +43,7 @@ module GraphQL::DefinitionHelpers::DefinedByConfig
41
43
  @on = []
42
44
  @fields = {}
43
45
  @arguments = {}
44
- @values = {}
46
+ @values = []
45
47
  @input_fields = {}
46
48
  end
47
49
 
@@ -64,8 +66,7 @@ module GraphQL::DefinitionHelpers::DefinedByConfig
64
66
 
65
67
  # For EnumType
66
68
  def value(name, desc = nil, deprecation_reason: nil, value: name)
67
- value = GraphQL::EnumType::EnumValue.new(name: name, description: description, deprecation_reason: deprecation_reason, value: value)
68
- values[name] = value
69
+ values << GraphQL::EnumType::EnumValue.new(name: name, description: description, deprecation_reason: deprecation_reason, value: value)
69
70
  end
70
71
 
71
72
  # For InputObjectType
@@ -6,6 +6,6 @@ module GraphQL::DefinitionHelpers::NonNullWithBang
6
6
  # Make the type non-null
7
7
  # @return [GraphQL::NonNullType] a non-null type which wraps the original type
8
8
  def !
9
- GraphQL::NonNullType.new(of_type: self)
9
+ to_non_null_type
10
10
  end
11
11
  end
@@ -20,6 +20,6 @@ class GraphQL::DefinitionHelpers::TypeDefiner
20
20
  # @param type [Type] A type to be wrapped in a ListType
21
21
  # @return [GraphQL::ListType] A ListType wrapping `type`
22
22
  def [](type)
23
- GraphQL::ListType.new(of_type: type)
23
+ type.to_list_type
24
24
  end
25
25
  end
@@ -14,8 +14,17 @@ class GraphQL::EnumType < GraphQL::BaseType
14
14
  attr_accessor :name, :description, :values
15
15
  defined_by_config :name, :description, :values
16
16
 
17
+ def values=(values)
18
+ @values_by_name = {}
19
+ @values_by_value = {}
20
+ values.each do |enum_value|
21
+ @values_by_name[enum_value.name] = enum_value
22
+ @values_by_value[enum_value.value] = enum_value
23
+ end
24
+ end
25
+
17
26
  def values
18
- @values ||= {}
27
+ @values_by_name
19
28
  end
20
29
 
21
30
  # Define a value within this enum
@@ -40,8 +49,12 @@ class GraphQL::EnumType < GraphQL::BaseType
40
49
  #
41
50
  # @param value_name [String] the string representation of this enum value
42
51
  # @return [Object] the underlying value for this enum value
43
- def coerce(value_name)
44
- values[value_name].value
52
+ def coerce_input(value_name)
53
+ @values_by_name.fetch(value_name).value
54
+ end
55
+
56
+ def coerce_result(value)
57
+ @values_by_value.fetch(value).name
45
58
  end
46
59
 
47
60
  def to_s
@@ -18,4 +18,14 @@ class GraphQL::InputObjectType < GraphQL::BaseType
18
18
  def kind
19
19
  GraphQL::TypeKinds::INPUT_OBJECT
20
20
  end
21
+
22
+ def coerce_input(value)
23
+ input_values = {}
24
+ input_fields.each do |input_key, input_field_defn|
25
+ raw_value = value.fetch(input_key, input_field_defn.default_value)
26
+ field_type = input_field_defn.type
27
+ input_values[input_key] = field_type.coerce_input!(raw_value)
28
+ end
29
+ GraphQL::Query::Arguments.new(input_values)
30
+ end
21
31
  end
@@ -1,8 +1,3 @@
1
- module GraphQL
2
- module Language
3
- end
4
- end
5
-
6
1
  require 'graphql/language/parser'
7
2
  require 'graphql/language/transform'
8
3
  require 'graphql/language/nodes'
@@ -1,89 +1,93 @@
1
- module GraphQL::Language::Nodes
2
- # AbstractNode creates classes who:
3
- # - require their keyword arguments, throw ArgumentError if they don't match
4
- # - expose accessors for keyword arguments
5
- class AbstractNode
6
- attr_accessor :line, :col
1
+ module GraphQL
2
+ module Language
3
+ module Nodes
4
+ # AbstractNode creates classes who:
5
+ # - require their keyword arguments, throw ArgumentError if they don't match
6
+ # - expose accessors for keyword arguments
7
+ class AbstractNode
8
+ attr_accessor :line, :col
7
9
 
8
- # @param options [Hash] Must contain all attributes defined by {required_attrs}, may also include `position_source`
9
- def initialize(options)
10
- required_keys = self.class.required_attrs
11
- allowed_keys = required_keys + [:line, :col]
12
- position_source = options.delete(:position_source)
13
- if !position_source.nil?
14
- options[:line], options[:col] = position_source.line_and_column
15
- end
10
+ # @param options [Hash] Must contain all attributes defined by {required_attrs}, may also include `position_source`
11
+ def initialize(options)
12
+ required_keys = self.class.required_attrs
13
+ allowed_keys = required_keys + [:line, :col]
14
+ position_source = options.delete(:position_source)
15
+ if !position_source.nil?
16
+ options[:line], options[:col] = position_source.line_and_column
17
+ end
16
18
 
17
- present_keys = options.keys
18
- extra_keys = present_keys - allowed_keys
19
- if extra_keys.any?
20
- raise ArgumentError, "#{self.class.name} Extra arguments: #{extra_keys}"
21
- end
19
+ present_keys = options.keys
20
+ extra_keys = present_keys - allowed_keys
21
+ if extra_keys.any?
22
+ raise ArgumentError, "#{self.class.name} Extra arguments: #{extra_keys}"
23
+ end
22
24
 
23
- missing_keys = required_keys - present_keys
24
- if missing_keys.any?
25
- raise ArgumentError, "#{self.class.name} Missing arguments: #{missing_keys}"
26
- end
25
+ missing_keys = required_keys - present_keys
26
+ if missing_keys.any?
27
+ raise ArgumentError, "#{self.class.name} Missing arguments: #{missing_keys}"
28
+ end
27
29
 
28
- allowed_keys.each do |key|
29
- if options.has_key?(key)
30
- value = options[key]
31
- self.send("#{key}=", value)
30
+ allowed_keys.each do |key|
31
+ if options.has_key?(key)
32
+ value = options[key]
33
+ self.send("#{key}=", value)
34
+ end
35
+ end
32
36
  end
33
- end
34
- end
35
37
 
36
- # Test all attributes, checking for any other nodes below this one
37
- def children
38
- self.class.required_attrs
39
- .map { |attr| send(attr) }
40
- .flatten
41
- .select { |val| val.is_a?(GraphQL::Language::Nodes::AbstractNode) }
42
- end
38
+ # Test all attributes, checking for any other nodes below this one
39
+ def children
40
+ self.class.required_attrs
41
+ .map { |attr| send(attr) }
42
+ .flatten
43
+ .select { |val| val.is_a?(GraphQL::Language::Nodes::AbstractNode) }
44
+ end
43
45
 
44
- class << self
45
- attr_reader :required_attrs
46
- # Defines attributes which are required at initialization.
47
- def attr_required(*attr_names)
48
- @required_attrs ||= []
49
- @required_attrs += attr_names
50
- attr_accessor(*attr_names)
51
- end
46
+ class << self
47
+ attr_reader :required_attrs
48
+ # Defines attributes which are required at initialization.
49
+ def attr_required(*attr_names)
50
+ @required_attrs ||= []
51
+ @required_attrs += attr_names
52
+ attr_accessor(*attr_names)
53
+ end
52
54
 
53
- # Create a new AbstractNode child which
54
- # requires and exposes {attr_names}.
55
- # @param attr_names [Array<Symbol>] Attributes this node class will have
56
- # @param block [Block] Block passed to `Class.new`
57
- # @return [Class] A new node class
58
- def create(*attr_names, &block)
59
- cls = Class.new(self, &block)
60
- cls.attr_required(*attr_names)
61
- cls
55
+ # Create a new AbstractNode child which
56
+ # requires and exposes {attr_names}.
57
+ # @param attr_names [Array<Symbol>] Attributes this node class will have
58
+ # @param block [Block] Block passed to `Class.new`
59
+ # @return [Class] A new node class
60
+ def create(*attr_names, &block)
61
+ cls = Class.new(self, &block)
62
+ cls.attr_required(*attr_names)
63
+ cls
64
+ end
65
+ end
62
66
  end
63
- end
64
- end
65
67
 
66
- Argument = AbstractNode.create(:name, :value)
67
- Directive = AbstractNode.create(:name, :arguments)
68
- Document = AbstractNode.create(:parts)
69
- Enum = AbstractNode.create(:name)
70
- Field = AbstractNode.create(:name, :alias, :arguments, :directives, :selections)
71
- FragmentDefinition = AbstractNode.create(:name, :type, :directives, :selections)
72
- FragmentSpread = AbstractNode.create(:name, :directives)
73
- InlineFragment = AbstractNode.create(:type, :directives, :selections)
74
- InputObject = AbstractNode.create(:pairs) do
75
- def to_h(options={})
76
- pairs.inject({}) do |memo, pair|
77
- v = pair.value
78
- memo[pair.name] = v.is_a?(InputObject) ? v.to_h : v
79
- memo
68
+ Argument = AbstractNode.create(:name, :value)
69
+ Directive = AbstractNode.create(:name, :arguments)
70
+ Document = AbstractNode.create(:parts)
71
+ Enum = AbstractNode.create(:name)
72
+ Field = AbstractNode.create(:name, :alias, :arguments, :directives, :selections)
73
+ FragmentDefinition = AbstractNode.create(:name, :type, :directives, :selections)
74
+ FragmentSpread = AbstractNode.create(:name, :directives)
75
+ InlineFragment = AbstractNode.create(:type, :directives, :selections)
76
+ InputObject = AbstractNode.create(:pairs) do
77
+ def to_h(options={})
78
+ pairs.inject({}) do |memo, pair|
79
+ v = pair.value
80
+ memo[pair.name] = v.is_a?(InputObject) ? v.to_h : v
81
+ memo
82
+ end
83
+ end
80
84
  end
85
+ ListType = AbstractNode.create(:of_type)
86
+ NonNullType = AbstractNode.create(:of_type)
87
+ OperationDefinition = AbstractNode.create(:operation_type, :name, :variables, :directives, :selections)
88
+ TypeName = AbstractNode.create(:name)
89
+ Variable = AbstractNode.create(:name, :type, :default_value)
90
+ VariableIdentifier = AbstractNode.create(:name)
81
91
  end
82
92
  end
83
- ListType = AbstractNode.create(:of_type)
84
- NonNullType = AbstractNode.create(:of_type)
85
- OperationDefinition = AbstractNode.create(:operation_type, :name, :variables, :directives, :selections)
86
- TypeName = AbstractNode.create(:name)
87
- Variable = AbstractNode.create(:name, :type, :default_value)
88
- VariableIdentifier = AbstractNode.create(:name)
89
93
  end
@@ -1,118 +1,121 @@
1
- module GraphQL::Language
2
- # Parser is a [parslet](http://kschiess.github.io/parslet/) parser for parsing queries.
3
- #
4
- class Parser < Parslet::Parser
5
- root(:document)
6
- rule(:document) { (
7
- space |
8
- operation_definition |
9
- fragment_definition
10
- ).repeat.as(:document_parts)
11
- }
1
+ module GraphQL
2
+ module Language
3
+ # Parser is a [parslet](http://kschiess.github.io/parslet/) parser for parsing queries.
4
+ #
5
+ class Parser < Parslet::Parser
6
+ root(:document)
7
+ rule(:document) { (
8
+ space |
9
+ operation_definition |
10
+ fragment_definition
11
+ ).repeat.as(:document_parts)
12
+ }
12
13
 
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
- }
14
+ # TODO: whitespace sensitive regarding `on`, eg `onFood`, see lookahead note in spec
15
+ rule(:fragment_definition) {
16
+ str("fragment").as(:fragment_keyword) >>
17
+ space? >> name.as(:fragment_name) >>
18
+ space? >> str("on") >> space? >> name.as(:type_condition) >>
19
+ space? >> directives.maybe.as(:optional_directives).as(:directives) >>
20
+ space? >> selections.as(:selections)
21
+ }
21
22
 
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
- }
23
+ rule(:fragment_spread) {
24
+ spread.as(:fragment_spread_keyword) >> space? >>
25
+ name.as(:fragment_spread_name) >> space? >>
26
+ directives.maybe.as(:optional_directives).as(:directives)
27
+ }
28
+ rule(:spread) { str("...") }
29
+ # TODO: `on` bug, see spec
30
+ rule(:inline_fragment) {
31
+ spread.as(:fragment_spread_keyword) >> space? >>
32
+ str("on ") >> name.as(:inline_fragment_type) >> space? >>
33
+ directives.maybe.as(:optional_directives).as(:directives) >> space? >>
34
+ selections.as(:selections)
35
+ }
35
36
 
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)}
37
+ rule(:operation_definition) { (unnamed_selections | typed_operation_definition) }
38
+ rule(:unnamed_selections) { selections.as(:unnamed_selections)}
39
+ rule(:typed_operation_definition) {
40
+ operation_type.as(:operation_type) >> space? >>
41
+ name.maybe.as(:name) >> space? >>
42
+ operation_variable_definitions.maybe.as(:optional_variables).as(:variables) >> space? >>
43
+ directives.maybe.as(:optional_directives).as(:directives) >> space? >>
44
+ selections.as(:selections)
45
+ }
46
+ rule(:operation_type) { (str("query") | str("mutation")) }
47
+ rule(:operation_variable_definitions) { str("(") >> space? >> (operation_variable_definition >> separator?).repeat(1) >> space? >> str(")") }
48
+ rule(:operation_variable_definition) {
49
+ value_variable.as(:variable_name) >> space? >>
50
+ str(":") >> space? >>
51
+ type.as(:variable_type) >> space? >>
52
+ (str("=") >> space? >> value.as(:variable_default_value)).maybe.as(:variable_optional_default_value)
53
+ }
52
54
 
53
- rule(:selection) { (inline_fragment | fragment_spread | field) >> space? >> separator? }
54
- rule(:selections) { str("{") >> space? >> selection.repeat(1) >> space? >> str("}")}
55
+ rule(:selection) { (inline_fragment | fragment_spread | field) >> space? >> separator? }
56
+ rule(:selections) { str("{") >> space? >> selection.repeat(1) >> space? >> str("}")}
55
57
 
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
- }
58
+ rule(:field) {
59
+ field_alias.maybe.as(:alias) >>
60
+ name.as(:field_name) >>
61
+ field_arguments.maybe.as(:optional_field_arguments).as(:field_arguments) >> space? >>
62
+ directives.maybe.as(:optional_directives).as(:directives) >> space? >>
63
+ selections.maybe.as(:optional_selections).as(:selections)
64
+ }
63
65
 
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? }
66
+ rule(:field_alias) { name.as(:alias_name) >> space? >> str(":") >> space? }
67
+ rule(:field_arguments) { str("(") >> field_argument.repeat(1) >> str(")") }
68
+ rule(:field_argument) { name.as(:field_argument_name) >> str(":") >> space? >> value.as(:field_argument_value) >> separator? }
67
69
 
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? }
70
+ rule(:directives) { (directive >> separator?).repeat(1) }
71
+ rule(:directive) {
72
+ str("@") >> name.as(:directive_name) >>
73
+ directive_arguments.maybe.as(:optional_directive_arguments).as(:directive_arguments)
74
+ }
75
+ rule(:directive_arguments) { str("(") >> directive_argument.repeat(1) >> str(")") }
76
+ rule(:directive_argument) { name.as(:directive_argument_name) >> str(":") >> space? >> value.as(:directive_argument_value) >> separator? }
75
77
 
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) }
78
+ rule(:type) { (non_null_type | list_type | type_name)}
79
+ rule(:list_type) { str("[") >> type.as(:list_type) >> str("]")}
80
+ rule(:non_null_type) { (list_type | type_name).as(:non_null_type) >> str("!") }
81
+ rule(:type_name) { name.as(:type_name) }
80
82
 
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("{") >> space? >> value_input_object_pair.repeat(1).as(:input_object) >> space? >> 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
- rule(:value_string) { str('"') >> value_string_char.repeat.as(:string) >> str('"')}
99
- rule(:value_string_char) { value_string_escaped_char | value_string_escaped_unicode | value_string_source_char}
100
- rule(:value_string_escaped_char) { str("\\") >> match('["\/bfnrt]') }
101
- rule(:value_string_escaped_unicode) { str("\\") >> match('u[\dA-Fa-f]{4}')}
102
- rule(:value_string_source_char) { (str('"') | str("\\") | value_string_line_terminator).absent? >> any }
103
- rule(:value_string_line_terminator) {
104
- str('\u000A') | # new line
105
- str('\u000D') | # carriage return
106
- str('\u2028') | # line separator
107
- str('\u2029') # paragraph separator
108
- }
109
- rule(:value_enum) { name.as(:enum) }
110
- rule(:value_variable) { str("$") >> name.as(:variable) }
83
+ rule(:value) {(
84
+ value_input_object |
85
+ value_float |
86
+ value_int |
87
+ value_string |
88
+ value_boolean |
89
+ value_array |
90
+ value_variable |
91
+ value_enum
92
+ )}
93
+ rule(:value_sign?) { match('[\-\+]').maybe }
94
+ rule(:value_array) { (str("[") >> (value >> separator?).repeat(0) >> str("]")).as(:array) }
95
+ rule(:value_boolean) { (str("true") | str("false")).as(:boolean) }
96
+ 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) }
97
+ rule(:value_input_object) { str("{") >> space? >> value_input_object_pair.repeat(1).as(:input_object) >> space? >> str("}") }
98
+ rule(:value_input_object_pair) { space? >> name.as(:input_object_name) >> space? >> str(":") >> space? >> value.as(:input_object_value) >> separator? }
99
+ rule(:value_int) { (value_sign? >> match('\d').repeat(1)).as(:int) }
100
+ rule(:value_string) { str('"') >> value_string_char.repeat.as(:string) >> str('"')}
101
+ rule(:value_string_char) { value_string_escaped_char | value_string_escaped_unicode | value_string_source_char}
102
+ rule(:value_string_escaped_char) { str("\\") >> match('["\/bfnrt]') }
103
+ rule(:value_string_escaped_unicode) { str("\\") >> match('u[\dA-Fa-f]{4}')}
104
+ rule(:value_string_source_char) { (str('"') | str("\\") | value_string_line_terminator).absent? >> any }
105
+ rule(:value_string_line_terminator) {
106
+ str('\u000A') | # new line
107
+ str('\u000D') | # carriage return
108
+ str('\u2028') | # line separator
109
+ str('\u2029') # paragraph separator
110
+ }
111
+ rule(:value_enum) { name.as(:enum) }
112
+ rule(:value_variable) { str("$") >> name.as(:variable) }
111
113
 
112
- rule(:separator?) { (space? >> str(",") >> space?).maybe }
113
- rule(:name) { match('[_A-Za-z]') >> match('[_0-9A-Za-z]').repeat(0) }
114
- rule(:comment) { str("#") >> match('[^\r\n]').repeat(0) }
115
- rule(:space) { (match('[\s\n]+') | comment).repeat(1) }
116
- rule(:space?) { space.maybe }
114
+ rule(:separator?) { space? >> str(",").maybe >> space? }
115
+ rule(:name) { match('[_A-Za-z]') >> match('[_0-9A-Za-z]').repeat(0) }
116
+ rule(:comment) { str("#") >> match('[^\r\n]').repeat(0) }
117
+ rule(:space) { (match('[\s\n]+') | comment).repeat(1) }
118
+ rule(:space?) { space.maybe }
119
+ end
117
120
  end
118
121
  end