gql 0.0.4 → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe2deb60572972e21f7f7371dd4437cd87532043
4
- data.tar.gz: 502022ff7d90578776e50bcb84b9d19deddbbd8f
3
+ metadata.gz: 96bce7d738e7b21e2253ec10315f64b4fb33408e
4
+ data.tar.gz: c28e4961a061063f51703cd714eb646efb8465ff
5
5
  SHA512:
6
- metadata.gz: b865d13e6b65926e4dad2e418d8cc49882a168e809eeaa372987123714aa6ad761e84f73abef746835fc9964e3683ef6de8f1ea4a91ed8c6b3ce0a0484eeac73
7
- data.tar.gz: d1e7b56cd2d314de5a175c19a7f4bde686d0a907c144a6650d2a271876bde255a1e8b1b9ee6b5d8a8ebd7962d9eb81321fed1b9f4b38edbc16800ed87b5f7e10
6
+ metadata.gz: 8069bf344b4c87f43b718f4b0b0a8ad2c30be35f186bf4d1f1e2f1119f356feef3c8a126982a177c860817d32dfa5b1c63d4268c96486f2272691e7f1593f59c
7
+ data.tar.gz: 18e1efe2c211f3579b12b808fdd842eb938c8f45f2b0b50049582e819adb6fe4f99eb33a2c0e6bb6a642b69acd20a04deb72f7054edc96001821f940cb2e237d
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # GQL
1
+ # gql
2
2
 
3
3
  An attempted implementation of Facebook's yet-to-be-released GraphQL specification, heavily inspired by [graphql-ruby](https://github.com/rmosolgo/graphql-ruby), but with other/more/less features/bugs.
4
4
 
data/lib/gql.rb CHANGED
@@ -11,7 +11,7 @@ module GQL
11
11
 
12
12
  module Errors
13
13
  autoload :InvalidNodeClass, 'gql/errors'
14
- autoload :ParseError, 'gql/errors'
14
+ autoload :SyntaxError, 'gql/errors'
15
15
  autoload :UndefinedCall, 'gql/errors'
16
16
  autoload :UndefinedField, 'gql/errors'
17
17
  autoload :UndefinedNodeClass, 'gql/errors'
@@ -29,6 +29,15 @@ module GQL
29
29
  autoload :String, 'gql/fields/string'
30
30
  end
31
31
 
32
+ module Schema
33
+ autoload :Call, 'gql/schema/call'
34
+ autoload :Connection, 'gql/schema/connection'
35
+ autoload :Field, 'gql/schema/field'
36
+ autoload :Node, 'gql/schema/node'
37
+ autoload :Parameter, 'gql/schema/parameter'
38
+ autoload :Placeholder, 'gql/schema/placeholder'
39
+ end
40
+
32
41
  extend(Module.new {
33
42
  def config
34
43
  Thread.current[:gql_config] ||= Config.new
@@ -69,9 +78,14 @@ module GQL
69
78
  tokenizer = Tokenizer.new
70
79
  tokenizer.scan_setup input
71
80
 
81
+ result = []
82
+
72
83
  while token = tokenizer.next_token
73
- yield token
84
+ result << token
85
+ yield token if block_given?
74
86
  end
87
+
88
+ result
75
89
  end
76
90
  })
77
91
 
@@ -12,10 +12,10 @@ module GQL
12
12
  end
13
13
  end
14
14
 
15
- class_attribute :method, :result_class, instance_accessor: false, instance_predicate: false
15
+ class_attribute :id, :result_class, :method, instance_accessor: false, instance_predicate: false
16
16
 
17
17
  class << self
18
- def build_class(result_class, method)
18
+ def build_class(id, result_class, method)
19
19
  if result_class.is_a? Array
20
20
  result_class.unshift Connection if result_class.size == 1
21
21
  result_class.unshift Fields::Connection if result_class.size == 2
@@ -27,12 +27,13 @@ module GQL
27
27
  end
28
28
 
29
29
  options = { connection_class: connection_class, node_class: node_class }
30
- result_class = field_type_class.build_class(nil, options)
30
+ result_class = field_type_class.build_class(:result, nil, options)
31
31
  elsif result_class && !(result_class <= Node)
32
32
  raise Errors::InvalidNodeClass.new(result_class, Node)
33
33
  end
34
34
 
35
35
  Class.new(self).tap do |call_class|
36
+ call_class.id = id.to_s
36
37
  call_class.method = method
37
38
  call_class.result_class = result_class
38
39
  end
@@ -9,6 +9,10 @@ module GQL
9
9
  raise Errors::InvalidNodeClass.new(value, Node)
10
10
  end
11
11
 
12
+ if ENV['DEBUG']
13
+ value.call :_schema, Schema::Node, -> { context[:_schema_root] }
14
+ end
15
+
12
16
  @@root_node_class = value
13
17
  end
14
18
 
@@ -25,35 +25,35 @@ module GQL
25
25
  end
26
26
 
27
27
  class UndefinedFieldType < Error
28
- def initialize(name)
29
- types = GQL.field_types.keys.sort.map { |name| "`#{name}`" }
28
+ def initialize(id)
29
+ types = GQL.field_types.keys.sort.map { |id| "`#{id}`" }
30
30
  types = types.size > 0 ? " Available types: #{types.to_sentence}." : ''
31
31
 
32
- super("The field type `#{name}` is undefined. Define it with `GQL.field_types[:#{name}] = My#{name.to_s.camelize}`.#{types}")
32
+ super("The field type `#{id}` is undefined. Define it with `GQL.field_types[:#{id}] = My#{id.to_s.camelize}`.#{types}")
33
33
  end
34
34
  end
35
35
 
36
36
  class UndefinedCall < Error
37
- def initialize(name, node_class)
38
- calls = node_class.call_classes.keys.sort.map { |name| "`#{name}`" }
37
+ def initialize(id, node_class)
38
+ calls = node_class.calls.keys.sort.map { |id| "`#{id}`" }
39
39
  calls = calls.size > 0 ? " Available calls: #{calls.to_sentence}." : ''
40
40
 
41
- super("#{node_class} has no call named `#{name}`.#{calls}")
41
+ super("#{node_class} has no call named `#{id}`.#{calls}")
42
42
  end
43
43
  end
44
44
 
45
45
  class UndefinedField < Error
46
- def initialize(name, node_class)
47
- fields = node_class.field_classes.keys.sort.map { |name| "`#{name}`" }
46
+ def initialize(id, node_class)
47
+ fields = node_class.fields.keys.sort.map { |id| "`#{id}`" }
48
48
  fields = fields.size > 0 ? " Available fields: #{fields.to_sentence}." : ''
49
49
 
50
- super("#{node_class} has no field named `#{name}`.#{fields}")
50
+ super("#{node_class} has no field named `#{id}`.#{fields}")
51
51
  end
52
52
  end
53
53
 
54
- class ParseError < Error
54
+ class SyntaxError < Error
55
55
  def initialize(value, token)
56
- token = 'value' if token == 'error'
56
+ token = 'character' if token == 'error' || token == %Q{"#{value}"}
57
57
 
58
58
  super("Unexpected #{token}: `#{value}`.")
59
59
  end
@@ -12,6 +12,8 @@ module GQL
12
12
 
13
13
  raise Errors::UndefinedRoot if node_class.nil?
14
14
 
15
+ context[:_schema_root] = node_class if ENV['DEBUG']
16
+
15
17
  node = node_class.new(ast_node, nil, variables, context)
16
18
  node.value
17
19
  end
@@ -14,11 +14,12 @@ module GQL
14
14
  end
15
15
  end
16
16
 
17
- class_attribute :method, instance_accessor: false, instance_predicate: false
17
+ class_attribute :id, :method, instance_accessor: false, instance_predicate: false
18
18
 
19
19
  class << self
20
- def build_class(method, options = {})
20
+ def build_class(id, method, options = {})
21
21
  Class.new(self).tap do |field_class|
22
+ field_class.id = id.to_s
22
23
  field_class.method = method
23
24
  end
24
25
  end
@@ -6,7 +6,7 @@ module GQL
6
6
  class_attribute :node_class, instance_accessor: false, instance_predicate: false
7
7
 
8
8
  class << self
9
- def build_class(method, options = {})
9
+ def build_class(id, method, options = {})
10
10
  node_class = options[:node_class] || self.node_class
11
11
 
12
12
  if node_class.nil?
@@ -18,12 +18,15 @@ module GQL
18
18
  end
19
19
 
20
20
  Class.new(self).tap do |field_class|
21
+ field_class.id = id.to_s
21
22
  field_class.method = method
22
23
  field_class.node_class = node_class
23
24
  end
24
25
  end
25
26
  end
26
27
 
28
+ call :size, Integer, -> { target.size }
29
+
27
30
  def value
28
31
  target.map do |item|
29
32
  node = self.class.node_class.new(ast_node, item, variables, context)
@@ -7,7 +7,7 @@ module GQL
7
7
  self.connection_class = GQL::Connection
8
8
 
9
9
  class << self
10
- def build_class(method, options = {})
10
+ def build_class(id, method, options = {})
11
11
  connection_class = options[:connection_class] || self.connection_class
12
12
 
13
13
  if connection_class.nil?
@@ -19,6 +19,7 @@ module GQL
19
19
  end
20
20
 
21
21
  Class.new(self).tap do |field_class|
22
+ field_class.id = id.to_s
22
23
  field_class.method = method
23
24
  field_class.connection_class = connection_class.build_class(options[:node_class])
24
25
  end
@@ -2,9 +2,7 @@ module GQL
2
2
  module Fields
3
3
  class Integer < Field
4
4
  # This is just an example call, monkeypatch to add your own.
5
- call :is_zero, returns: Boolean do
6
- target.zero?
7
- end
5
+ call :is_zero, Boolean, -> { target.zero? }
8
6
  end
9
7
  end
10
8
  end
@@ -6,7 +6,7 @@ module GQL
6
6
  class_attribute :node_class, instance_accessor: false, instance_predicate: false
7
7
 
8
8
  class << self
9
- def build_class(method, options = {})
9
+ def build_class(id, method, options = {})
10
10
  node_class = options[:node_class] || self.node_class
11
11
 
12
12
  if node_class.nil?
@@ -18,6 +18,7 @@ module GQL
18
18
  end
19
19
 
20
20
  Class.new(self).tap do |field_class|
21
+ field_class.id = id.to_s
21
22
  field_class.method = method
22
23
  field_class.node_class = node_class
23
24
  end
@@ -1,17 +1,9 @@
1
1
  module GQL
2
2
  module Fields
3
3
  class String < Field
4
- call :upcase do
5
- target.upcase
6
- end
7
-
8
- call :downcase do
9
- target.downcase
10
- end
11
-
12
- call :length, returns: Integer do
13
- target.size
14
- end
4
+ call :upcase, -> { target.upcase }
5
+ call :downcase, -> { target.downcase }
6
+ call :length, Integer, -> { target.size }
15
7
 
16
8
  # These are just example calls, monkeypatch to add your own.
17
9
  end
@@ -4,59 +4,57 @@ require 'active_support/core_ext/array/extract_options'
4
4
 
5
5
  module GQL
6
6
  class Node
7
- class_attribute :call_classes, :field_classes, instance_accessor: false, instance_predicate: false
7
+ class_attribute :calls, :fields, instance_accessor: false, instance_predicate: false
8
8
 
9
- self.call_classes = {}
10
- self.field_classes = {}
9
+ self.calls = {}
10
+ self.fields = {}
11
11
 
12
12
  class << self
13
- def call(*names, &block)
14
- names_with_result_class = names.extract_options!
15
-
16
- names.each do |name|
17
- names_with_result_class[name] = nil
13
+ def call(id, result_class = nil, body = nil)
14
+ if body.nil? && result_class.is_a?(Proc)
15
+ body = result_class
16
+ result_class = nil
18
17
  end
19
18
 
20
- names_with_result_class.each do |name, result_class|
21
- method = block || lambda { |*args| target.public_send(name, *args) }
22
- call_class = Call.build_class(result_class, method)
19
+ body ||= lambda { |*args| target.public_send(id, *args) }
23
20
 
24
- self.const_set "#{name.to_s.camelize}Call", call_class
25
- self.call_classes = call_classes.merge(name => call_class)
26
- end
21
+ call_class = Call.build_class(id, result_class, body)
22
+
23
+ self.const_set "#{id.to_s.camelize}Call", call_class
24
+ self.calls = calls.merge(id.to_sym => call_class)
27
25
  end
28
26
 
29
- def field(*names, &block)
30
- options = names.extract_options!
27
+ def field(*ids, &block)
28
+ options = ids.extract_options!
31
29
 
32
- names.each do |name|
33
- method = block || lambda { target.public_send(name) }
30
+ ids.each do |id|
31
+ method = block || lambda { target.public_send(id) }
34
32
  field_type_class = options.delete(:field_type_class) || Field
35
33
 
36
34
  unless field_type_class <= Field
37
35
  raise Errors::InvalidNodeClass.new(field_type_class, Field)
38
36
  end
39
37
 
40
- field_class = field_type_class.build_class(method, options)
38
+ field_class = field_type_class.build_class(id, method, options)
41
39
 
42
- self.const_set "#{name.to_s.camelize}Field", field_class
43
- self.field_classes = field_classes.merge(name => field_class)
40
+ self.const_set "#{id.to_s.camelize}Field", field_class
41
+ self.fields = fields.merge(id.to_sym => field_class)
44
42
  end
45
43
  end
46
44
 
47
- def cursor(name = nil, &block)
48
- if name
49
- field :cursor, &-> { target.public_send(name) }
45
+ def cursor(id = nil, &block)
46
+ if id
47
+ field :cursor, &-> { target.public_send(id) }
50
48
  elsif block_given?
51
49
  field :cursor, &block
52
50
  end
53
51
  end
54
52
 
55
- def method_missing(method, *names, &block)
53
+ def method_missing(method, *ids, &block)
56
54
  if field_type_class = GQL.field_types[method]
57
- options = names.extract_options!
55
+ options = ids.extract_options!
58
56
 
59
- field(*names, options.merge(field_type_class: field_type_class), &block)
57
+ field(*ids, options.merge(field_type_class: field_type_class), &block)
60
58
  else
61
59
  super
62
60
  end
@@ -83,10 +81,10 @@ module GQL
83
81
  end
84
82
 
85
83
  def value_of_call(ast_call)
86
- call_class = self.class.call_classes[ast_call.name]
84
+ call_class = self.class.calls[ast_call.id]
87
85
 
88
86
  if call_class.nil?
89
- raise Errors::UndefinedCall.new(ast_call.name, self.class.superclass)
87
+ raise Errors::UndefinedCall.new(ast_call.id, self.class)
90
88
  end
91
89
 
92
90
  call = call_class.new(self, ast_call, target, variables, context)
@@ -95,28 +93,28 @@ module GQL
95
93
 
96
94
  def value_of_fields(ast_fields)
97
95
  ast_fields.reduce({}) do |memo, ast_field|
98
- key = ast_field.alias_name || ast_field.name
96
+ key = ast_field.alias_id || ast_field.id
99
97
 
100
98
  memo.merge key => value_of_field(ast_field)
101
99
  end
102
100
  end
103
101
 
104
102
  def value_of_field(ast_field)
105
- case ast_field.name
103
+ case ast_field.id
106
104
  when :node
107
105
  field = self.class.new(ast_field, target, variables, context)
108
106
  field.value
109
107
  else
110
- method = Field::Method.new(target, context)
111
- field_class = self.class.field_classes[ast_field.name]
108
+ field_class = self.class.fields[ast_field.id]
112
109
 
113
110
  if field_class.nil?
114
- raise Errors::UndefinedField.new(ast_field.name, self.class.superclass)
111
+ raise Errors::UndefinedField.new(ast_field.id, self.class)
115
112
  end
116
113
 
117
- next_target = method.execute(field_class.method)
114
+ method = Field::Method.new(target, context)
115
+ target = method.execute(field_class.method)
118
116
 
119
- field = field_class.new(ast_field, next_target, variables, context)
117
+ field = field_class.new(ast_field, target, variables, context)
120
118
  field.value
121
119
  end
122
120
  end
@@ -21,10 +21,10 @@ module_eval(<<'...end parser.y/module_eval...', 'parser.y', 133)
21
21
  class Node < Struct.new(:call, :fields)
22
22
  end
23
23
 
24
- class Field < Struct.new(:name, :alias_name, :call, :fields)
24
+ class Field < Struct.new(:id, :alias_id, :call, :fields)
25
25
  end
26
26
 
27
- class Call < Struct.new(:name, :arguments, :call, :fields)
27
+ class Call < Struct.new(:id, :arguments, :call, :fields)
28
28
  end
29
29
 
30
30
  UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
@@ -62,7 +62,7 @@ module_eval(<<'...end parser.y/module_eval...', 'parser.y', 133)
62
62
  end
63
63
 
64
64
  def on_error(token, value, vstack)
65
- raise Errors::ParseError.new(value, token_to_str(token))
65
+ raise Errors::SyntaxError.new(value, token_to_str(token))
66
66
  end
67
67
 
68
68
  private
@@ -137,10 +137,10 @@ require 'active_support/core_ext/object/blank'
137
137
  class Node < Struct.new(:call, :fields)
138
138
  end
139
139
 
140
- class Field < Struct.new(:name, :alias_name, :call, :fields)
140
+ class Field < Struct.new(:id, :alias_id, :call, :fields)
141
141
  end
142
142
 
143
- class Call < Struct.new(:name, :arguments, :call, :fields)
143
+ class Call < Struct.new(:id, :arguments, :call, :fields)
144
144
  end
145
145
 
146
146
  UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
@@ -178,7 +178,7 @@ require 'active_support/core_ext/object/blank'
178
178
  end
179
179
 
180
180
  def on_error(token, value, vstack)
181
- raise Errors::ParseError.new(value, token_to_str(token))
181
+ raise Errors::SyntaxError.new(value, token_to_str(token))
182
182
  end
183
183
 
184
184
  private
@@ -0,0 +1,20 @@
1
+ module GQL
2
+ module Schema
3
+ class Call < GQL::Node
4
+ cursor :id
5
+ string :id
6
+
7
+ array :parameters, :node_class => Parameter do
8
+ target.method.parameters
9
+ end
10
+
11
+ string :type do
12
+ target.name
13
+ end
14
+
15
+ object :result_class, :node_class => Node do
16
+ target.result_class || Placeholder
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,7 @@
1
+ module GQL
2
+ module Schema
3
+ class Connection < GQL::Connection
4
+ integer :count
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ module GQL
2
+ module Schema
3
+ class Field < GQL::Node
4
+ cursor :id
5
+ string :id
6
+
7
+ string :type do
8
+ target.name
9
+ end
10
+
11
+ connection :calls, :connection_class => Connection, :node_class => Call do
12
+ target.calls.values
13
+ end
14
+
15
+ connection :fields, :connection_class => Connection, :node_class => Field do
16
+ target.fields.values
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module GQL
2
+ module Schema
3
+ class Node < GQL::Node
4
+ string :type do
5
+ target.name
6
+ end
7
+
8
+ connection :calls, :connection_class => Connection, :node_class => Call do
9
+ target.calls.values
10
+ end
11
+
12
+ connection :fields, :connection_class => Connection, :node_class => Field do
13
+ target.fields.values
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ module GQL
2
+ module Schema
3
+ class Parameter < GQL::Node
4
+ cursor { target[1].to_s }
5
+
6
+ string :id do
7
+ target[1].to_s
8
+ end
9
+
10
+ string :mode do
11
+ case target[0]
12
+ when :req
13
+ 'required'
14
+ when :opt
15
+ 'optional'
16
+ when :rest
17
+ 'rest'
18
+ when :keyreq
19
+ 'required keyword'
20
+ when :key
21
+ 'optional keyword'
22
+ when :keyrest
23
+ 'keyword rest'
24
+ when :block
25
+ 'block'
26
+ else
27
+ target[0].to_s
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ module GQL
2
+ module Schema
3
+ class Placeholder < GQL::Node
4
+ end
5
+ end
6
+ end
@@ -1,3 +1,3 @@
1
1
  module GQL
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.5'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Andert
@@ -126,6 +126,12 @@ files:
126
126
  - lib/gql/node.rb
127
127
  - lib/gql/parser.rb
128
128
  - lib/gql/parser.y
129
+ - lib/gql/schema/call.rb
130
+ - lib/gql/schema/connection.rb
131
+ - lib/gql/schema/field.rb
132
+ - lib/gql/schema/node.rb
133
+ - lib/gql/schema/parameter.rb
134
+ - lib/gql/schema/placeholder.rb
129
135
  - lib/gql/tokenizer.rb
130
136
  - lib/gql/tokenizer.rex
131
137
  - lib/gql/version.rb