graphql 0.9.5 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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