gql 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/gql.rb +16 -2
- data/lib/gql/call.rb +4 -3
- data/lib/gql/config.rb +4 -0
- data/lib/gql/errors.rb +11 -11
- data/lib/gql/executor.rb +2 -0
- data/lib/gql/field.rb +3 -2
- data/lib/gql/fields/array.rb +4 -1
- data/lib/gql/fields/connection.rb +2 -1
- data/lib/gql/fields/integer.rb +1 -3
- data/lib/gql/fields/object.rb +2 -1
- data/lib/gql/fields/string.rb +3 -11
- data/lib/gql/node.rb +34 -36
- data/lib/gql/parser.rb +3 -3
- data/lib/gql/parser.y +3 -3
- data/lib/gql/schema/call.rb +20 -0
- data/lib/gql/schema/connection.rb +7 -0
- data/lib/gql/schema/field.rb +20 -0
- data/lib/gql/schema/node.rb +17 -0
- data/lib/gql/schema/parameter.rb +32 -0
- data/lib/gql/schema/placeholder.rb +6 -0
- data/lib/gql/version.rb +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96bce7d738e7b21e2253ec10315f64b4fb33408e
|
4
|
+
data.tar.gz: c28e4961a061063f51703cd714eb646efb8465ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8069bf344b4c87f43b718f4b0b0a8ad2c30be35f186bf4d1f1e2f1119f356feef3c8a126982a177c860817d32dfa5b1c63d4268c96486f2272691e7f1593f59c
|
7
|
+
data.tar.gz: 18e1efe2c211f3579b12b808fdd842eb938c8f45f2b0b50049582e819adb6fe4f99eb33a2c0e6bb6a642b69acd20a04deb72f7054edc96001821f940cb2e237d
|
data/README.md
CHANGED
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 :
|
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
|
-
|
84
|
+
result << token
|
85
|
+
yield token if block_given?
|
74
86
|
end
|
87
|
+
|
88
|
+
result
|
75
89
|
end
|
76
90
|
})
|
77
91
|
|
data/lib/gql/call.rb
CHANGED
@@ -12,10 +12,10 @@ module GQL
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
class_attribute :
|
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
|
data/lib/gql/config.rb
CHANGED
data/lib/gql/errors.rb
CHANGED
@@ -25,35 +25,35 @@ module GQL
|
|
25
25
|
end
|
26
26
|
|
27
27
|
class UndefinedFieldType < Error
|
28
|
-
def initialize(
|
29
|
-
types = GQL.field_types.keys.sort.map { |
|
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 `#{
|
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(
|
38
|
-
calls = node_class.
|
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 `#{
|
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(
|
47
|
-
fields = node_class.
|
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 `#{
|
50
|
+
super("#{node_class} has no field named `#{id}`.#{fields}")
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
class
|
54
|
+
class SyntaxError < Error
|
55
55
|
def initialize(value, token)
|
56
|
-
token = '
|
56
|
+
token = 'character' if token == 'error' || token == %Q{"#{value}"}
|
57
57
|
|
58
58
|
super("Unexpected #{token}: `#{value}`.")
|
59
59
|
end
|
data/lib/gql/executor.rb
CHANGED
data/lib/gql/field.rb
CHANGED
@@ -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
|
data/lib/gql/fields/array.rb
CHANGED
@@ -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
|
data/lib/gql/fields/integer.rb
CHANGED
data/lib/gql/fields/object.rb
CHANGED
@@ -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
|
data/lib/gql/fields/string.rb
CHANGED
@@ -1,17 +1,9 @@
|
|
1
1
|
module GQL
|
2
2
|
module Fields
|
3
3
|
class String < Field
|
4
|
-
call :upcase
|
5
|
-
|
6
|
-
|
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
|
data/lib/gql/node.rb
CHANGED
@@ -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 :
|
7
|
+
class_attribute :calls, :fields, instance_accessor: false, instance_predicate: false
|
8
8
|
|
9
|
-
self.
|
10
|
-
self.
|
9
|
+
self.calls = {}
|
10
|
+
self.fields = {}
|
11
11
|
|
12
12
|
class << self
|
13
|
-
def call(
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
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(*
|
30
|
-
options =
|
27
|
+
def field(*ids, &block)
|
28
|
+
options = ids.extract_options!
|
31
29
|
|
32
|
-
|
33
|
-
method = block || lambda { target.public_send(
|
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 "#{
|
43
|
-
self.
|
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(
|
48
|
-
if
|
49
|
-
field :cursor, &-> { target.public_send(
|
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, *
|
53
|
+
def method_missing(method, *ids, &block)
|
56
54
|
if field_type_class = GQL.field_types[method]
|
57
|
-
options =
|
55
|
+
options = ids.extract_options!
|
58
56
|
|
59
|
-
field(*
|
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.
|
84
|
+
call_class = self.class.calls[ast_call.id]
|
87
85
|
|
88
86
|
if call_class.nil?
|
89
|
-
raise Errors::UndefinedCall.new(ast_call.
|
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.
|
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.
|
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
|
-
|
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.
|
111
|
+
raise Errors::UndefinedField.new(ast_field.id, self.class)
|
115
112
|
end
|
116
113
|
|
117
|
-
|
114
|
+
method = Field::Method.new(target, context)
|
115
|
+
target = method.execute(field_class.method)
|
118
116
|
|
119
|
-
field = field_class.new(ast_field,
|
117
|
+
field = field_class.new(ast_field, target, variables, context)
|
120
118
|
field.value
|
121
119
|
end
|
122
120
|
end
|
data/lib/gql/parser.rb
CHANGED
@@ -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(:
|
24
|
+
class Field < Struct.new(:id, :alias_id, :call, :fields)
|
25
25
|
end
|
26
26
|
|
27
|
-
class Call < Struct.new(:
|
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::
|
65
|
+
raise Errors::SyntaxError.new(value, token_to_str(token))
|
66
66
|
end
|
67
67
|
|
68
68
|
private
|
data/lib/gql/parser.y
CHANGED
@@ -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(:
|
140
|
+
class Field < Struct.new(:id, :alias_id, :call, :fields)
|
141
141
|
end
|
142
142
|
|
143
|
-
class Call < Struct.new(:
|
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::
|
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,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
|
data/lib/gql/version.rb
CHANGED
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
|
+
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
|