gql 0.0.10 → 0.0.11
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 +4 -4
- data/README.md +1 -1
- data/lib/gql.rb +11 -5
- data/lib/gql/call.rb +10 -11
- data/lib/gql/config.rb +29 -1
- data/lib/gql/errors.rb +52 -26
- data/lib/gql/executor.rb +4 -2
- data/lib/gql/has_calls.rb +83 -0
- data/lib/gql/has_fields.rb +103 -0
- data/lib/gql/node.rb +6 -148
- data/lib/gql/parser.rb +11 -2
- data/lib/gql/schema/call.rb +1 -9
- data/lib/gql/schema/list.rb +1 -1
- data/lib/gql/schema/parameter.rb +12 -22
- data/lib/gql/tokenizer.rb +4 -1
- data/lib/gql/version.rb +1 -1
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: defb9d23450cd1caa407d256c9cc8606ced22880
|
4
|
+
data.tar.gz: 069be6463c76f8add762ce9dff462e3d36a15a0c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5d31f91c8bb62a86e08a1fe77ba99a860766b67b91099aa8ada33e75cd13f8a57934795b2d14722dd435407a40c775c378deab6922790e6d41252a5faaa7d5a
|
7
|
+
data.tar.gz: d7edece3f9ff42860d183bdbd41584ae69bc0d96b82936c8e7b7c625857746edda3f0c27826a72c6ff7f0b989a5a3796a0dae2a241c47274d32d581864c44b81
|
data/README.md
CHANGED
@@ -36,7 +36,7 @@ TODO: Write usage instructions here
|
|
36
36
|
Run `bin/console` for an interactive prompt (loaded with example models/data) and enter the following:
|
37
37
|
|
38
38
|
```ruby
|
39
|
-
puts
|
39
|
+
puts query(<<-QUERY_STRING).to_json
|
40
40
|
user(<token>) {
|
41
41
|
id,
|
42
42
|
is_admin,
|
data/lib/gql.rb
CHANGED
@@ -23,14 +23,14 @@ module GQL
|
|
23
23
|
extend ActiveSupport::Autoload
|
24
24
|
|
25
25
|
autoload_at 'gql/errors' do
|
26
|
+
autoload :CallNotFound
|
27
|
+
autoload :FieldNotFound
|
26
28
|
autoload :InvalidNodeClass
|
29
|
+
autoload :NoMethodError
|
30
|
+
autoload :RootClassNotSet
|
27
31
|
autoload :ScanError
|
28
32
|
autoload :SyntaxError
|
29
|
-
autoload :UndefinedCall
|
30
|
-
autoload :UndefinedField
|
31
33
|
autoload :UndefinedNodeClass
|
32
|
-
autoload :UndefinedRoot
|
33
|
-
autoload :UndefinedFieldType
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -50,7 +50,13 @@ module GQL
|
|
50
50
|
Thread.current[:gql_config] ||= Config.new
|
51
51
|
end
|
52
52
|
|
53
|
-
|
53
|
+
def config=(value)
|
54
|
+
Thread.current[:gql_config] = value
|
55
|
+
end
|
56
|
+
|
57
|
+
%w(root_node_class root_target_proc field_types
|
58
|
+
default_list_class default_field_proc
|
59
|
+
default_call_proc).each do |method|
|
54
60
|
module_eval <<-DELEGATORS, __FILE__, __LINE__ + 1
|
55
61
|
def #{method}
|
56
62
|
config.#{method}
|
data/lib/gql/call.rb
CHANGED
@@ -6,20 +6,11 @@ module GQL
|
|
6
6
|
|
7
7
|
class << self
|
8
8
|
def returns(result_class = nil, &block)
|
9
|
-
|
10
|
-
self.result_class = result_class
|
11
|
-
elsif block_given?
|
12
|
-
Class.new(Node).tap do |result_class|
|
13
|
-
result_class.default_proc = -> id { -> { target[id] } }
|
14
|
-
result_class.class_eval(&block)
|
15
|
-
|
16
|
-
returns result_class
|
17
|
-
end
|
18
|
-
end
|
9
|
+
self.result_class = result_class || result_class_from_block(block)
|
19
10
|
end
|
20
11
|
|
21
12
|
def execute(caller_class, ast_node, target, variables, context)
|
22
|
-
args = substitute_variables(ast_node.arguments, variables)
|
13
|
+
args = substitute_variables(ast_node.arguments, variables.dup)
|
23
14
|
target = new(target, context).execute(*args)
|
24
15
|
|
25
16
|
next_class = result_class || caller_class
|
@@ -30,8 +21,16 @@ module GQL
|
|
30
21
|
|
31
22
|
private
|
32
23
|
def substitute_variables(args, variables)
|
24
|
+
return args unless variables.any?
|
33
25
|
args.map { |arg| arg.is_a?(::Symbol) ? variables[arg] : arg }
|
34
26
|
end
|
27
|
+
|
28
|
+
def result_class_from_block(block)
|
29
|
+
Class.new(Node).tap do |result_class|
|
30
|
+
result_class.field_proc = -> id { -> { target[id] } }
|
31
|
+
result_class.class_eval(&block)
|
32
|
+
end
|
33
|
+
end
|
35
34
|
end
|
36
35
|
|
37
36
|
attr_reader :target, :context
|
data/lib/gql/config.rb
CHANGED
@@ -9,13 +9,21 @@ module GQL
|
|
9
9
|
raise Errors::InvalidNodeClass.new(value, Node)
|
10
10
|
end
|
11
11
|
|
12
|
-
if ENV['DEBUG']
|
12
|
+
if value && ENV['DEBUG']
|
13
13
|
value.call :_schema, -> { context[:_schema_root] }, returns: Schema::Root
|
14
14
|
end
|
15
15
|
|
16
16
|
@@root_node_class = value
|
17
17
|
end
|
18
18
|
|
19
|
+
def root_target_proc
|
20
|
+
@@root_target_proc ||= -> context { nil }
|
21
|
+
end
|
22
|
+
|
23
|
+
def root_target_proc=(value)
|
24
|
+
@@root_target_proc = value
|
25
|
+
end
|
26
|
+
|
19
27
|
def field_types
|
20
28
|
@@field_types ||= {
|
21
29
|
array: Array,
|
@@ -36,7 +44,27 @@ module GQL
|
|
36
44
|
end
|
37
45
|
|
38
46
|
def default_list_class=(value)
|
47
|
+
unless value.nil? || value <= Node
|
48
|
+
raise Errors::InvalidNodeClass.new(value, Node)
|
49
|
+
end
|
50
|
+
|
39
51
|
@@default_list_class = value
|
40
52
|
end
|
53
|
+
|
54
|
+
def default_field_proc
|
55
|
+
@@default_field_proc ||= -> id { -> { target.public_send(id) } }
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_field_proc=(value)
|
59
|
+
@@default_field_proc = value
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_call_proc
|
63
|
+
@@default_call_proc ||= -> id { -> (*args) { target.public_send(id, *args) } }
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_call_proc=(value)
|
67
|
+
@@default_call_proc = value
|
68
|
+
end
|
41
69
|
end
|
42
70
|
end
|
data/lib/gql/errors.rb
CHANGED
@@ -6,60 +6,86 @@ module GQL
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module Errors
|
9
|
-
class
|
10
|
-
|
11
|
-
|
9
|
+
class NotFoundError < Error
|
10
|
+
private
|
11
|
+
def construct_message(node_class, id, name, method)
|
12
|
+
items = node_class.send(method).keys.sort.map { |key| "`#{key}'" }
|
13
|
+
|
14
|
+
msg = "#{node_class} has no #{name} named `#{id}'."
|
15
|
+
msg << " Available #{name.pluralize}: #{items.to_sentence}." if items.any?
|
16
|
+
msg
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class CallNotFound < NotFoundError
|
21
|
+
def initialize(id, node_class)
|
22
|
+
msg = construct_message(node_class, id, 'call', :calls)
|
23
|
+
|
24
|
+
super(msg)
|
12
25
|
end
|
13
26
|
end
|
14
27
|
|
15
|
-
class
|
16
|
-
def initialize(
|
17
|
-
|
28
|
+
class FieldNotFound < NotFoundError
|
29
|
+
def initialize(id, node_class)
|
30
|
+
msg = construct_message(node_class, id, 'field', :fields)
|
31
|
+
|
32
|
+
super(msg)
|
18
33
|
end
|
19
34
|
end
|
20
35
|
|
21
36
|
class InvalidNodeClass < Error
|
22
37
|
def initialize(node_class, super_class)
|
23
|
-
|
38
|
+
msg = "#{node_class} must be a (subclass of) #{super_class}."
|
39
|
+
|
40
|
+
super(msg)
|
24
41
|
end
|
25
42
|
end
|
26
43
|
|
27
|
-
class
|
28
|
-
|
29
|
-
types = GQL.field_types.keys.sort.map { |id| "`#{id}`" }
|
30
|
-
types = types.size > 0 ? " Available types: #{types.to_sentence}." : ''
|
44
|
+
class NoMethodError < Error
|
45
|
+
attr_reader :cause
|
31
46
|
|
32
|
-
|
33
|
-
|
34
|
-
end
|
47
|
+
def initialize(node_class, id, cause)
|
48
|
+
@cause = cause
|
35
49
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
50
|
+
msg = "Undefined method `#{id}' for #{node_class}. "
|
51
|
+
msg << "Did you try to add a field of type `#{id}'? "
|
52
|
+
msg << "If so, you have to register your field type first "
|
53
|
+
msg << "like this: `GQL.field_types[:#{id}] = My#{id.to_s.camelize}'. "
|
54
|
+
msg << "The following field types are currently registered: "
|
55
|
+
msg << GQL.field_types.keys.sort.map { |id| "`#{id}'" }.to_sentence
|
40
56
|
|
41
|
-
super(
|
57
|
+
super(msg)
|
42
58
|
end
|
43
59
|
end
|
44
60
|
|
45
|
-
class
|
46
|
-
def initialize
|
47
|
-
|
48
|
-
|
61
|
+
class RootClassNotSet < Error
|
62
|
+
def initialize
|
63
|
+
msg = "GQL root node class is not set. "
|
64
|
+
msg << "Set it with `GQL.root_node_class = MyRootNode'."
|
49
65
|
|
50
|
-
super(
|
66
|
+
super(msg)
|
51
67
|
end
|
52
68
|
end
|
53
69
|
|
70
|
+
class ScanError < Error
|
71
|
+
end
|
72
|
+
|
54
73
|
class SyntaxError < Error
|
55
74
|
def initialize(lineno, value, token)
|
56
75
|
token = 'character' if token == 'error' || token == %Q{"#{value}"}
|
76
|
+
msg = "Unexpected #{token}: `#{value}' (line #{lineno})."
|
57
77
|
|
58
|
-
super(
|
78
|
+
super(msg)
|
59
79
|
end
|
60
80
|
end
|
61
81
|
|
62
|
-
class
|
82
|
+
class UndefinedNodeClass < Error
|
83
|
+
def initialize(node_class, name)
|
84
|
+
msg = "#{node_class} must have a #{name} class set. "
|
85
|
+
msg << "Set it with `self.#{name}_class = My#{name.camelize}Class'."
|
86
|
+
|
87
|
+
super(msg)
|
88
|
+
end
|
63
89
|
end
|
64
90
|
end
|
65
91
|
end
|
data/lib/gql/executor.rb
CHANGED
@@ -10,11 +10,13 @@ module GQL
|
|
10
10
|
def execute(context = {})
|
11
11
|
node_class = GQL.root_node_class
|
12
12
|
|
13
|
-
raise Errors::
|
13
|
+
raise Errors::RootClassNotSet if node_class.nil?
|
14
14
|
|
15
15
|
context[:_schema_root] = node_class if ENV['DEBUG']
|
16
16
|
|
17
|
-
|
17
|
+
target = GQL.root_target_proc.call(context)
|
18
|
+
|
19
|
+
node = node_class.new(ast_root, target, variables, context)
|
18
20
|
node.value
|
19
21
|
end
|
20
22
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
3
|
+
require 'active_support/core_ext/class/attribute'
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
5
|
+
require 'active_support/core_ext/object/try'
|
6
|
+
|
7
|
+
module GQL
|
8
|
+
module HasCalls
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
class_attribute :calls, :call_proc, instance_accessor: false, instance_predicate: false
|
13
|
+
self.calls = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def call(id, *args)
|
18
|
+
options = args.extract_options!
|
19
|
+
|
20
|
+
call_spec = args.shift || proc_for_call(id)
|
21
|
+
result_spec = options[:returns] || call_spec.try(:result_class)
|
22
|
+
result_class = result_class_from_spec(result_spec)
|
23
|
+
|
24
|
+
Node.validate_is_subclass! result_class, 'result' if result_class
|
25
|
+
|
26
|
+
call_class = call_class_from_spec(call_spec)
|
27
|
+
call_class.id = id.to_s
|
28
|
+
call_class.result_class = result_class
|
29
|
+
|
30
|
+
self.const_set "#{id.to_s.camelize}Call", call_class
|
31
|
+
self.calls = calls.merge(id.to_sym => call_class)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def proc_for_call(id)
|
36
|
+
instance_exec id, &(call_proc || GQL.default_call_proc)
|
37
|
+
end
|
38
|
+
|
39
|
+
def result_class_from_spec(spec)
|
40
|
+
return spec unless spec.is_a? ::Array
|
41
|
+
|
42
|
+
result_class_from_connection_spec spec.dup
|
43
|
+
end
|
44
|
+
|
45
|
+
def result_class_from_connection_spec(spec)
|
46
|
+
if spec.size == 1
|
47
|
+
spec.unshift GQL.default_list_class
|
48
|
+
end
|
49
|
+
|
50
|
+
options = {
|
51
|
+
list_class: spec.first,
|
52
|
+
item_class: spec.last
|
53
|
+
}
|
54
|
+
|
55
|
+
Connection.build_class :result, nil, options
|
56
|
+
end
|
57
|
+
|
58
|
+
def call_class_from_spec(spec)
|
59
|
+
return Class.new(spec) unless spec.is_a?(Proc)
|
60
|
+
|
61
|
+
Class.new(Call).tap do |call_class|
|
62
|
+
call_class.class_eval do
|
63
|
+
self.proc = spec
|
64
|
+
|
65
|
+
def execute(*args)
|
66
|
+
instance_exec(*args, &self.class.proc)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def value_of_call(ast_call)
|
75
|
+
call_class = call_class_for_id(ast_call.id)
|
76
|
+
call_class.execute(self.class, ast_call, target, variables, context)
|
77
|
+
end
|
78
|
+
|
79
|
+
def call_class_for_id(id)
|
80
|
+
self.class.calls[id] or raise Errors::CallNotFound.new(id, self.class)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
3
|
+
require 'active_support/core_ext/class/attribute'
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
5
|
+
|
6
|
+
module GQL
|
7
|
+
module HasFields
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
class_attribute :fields, :field_proc, instance_accessor: false, instance_predicate: false
|
12
|
+
self.fields = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def field(id, *args)
|
17
|
+
options = args.extract_options!
|
18
|
+
type = options.delete(:type) || Node
|
19
|
+
proc = args.shift || proc_for_field(id)
|
20
|
+
|
21
|
+
Node.validate_is_subclass! type, 'type'
|
22
|
+
|
23
|
+
type.build_class(id, proc, options).tap do |field_class|
|
24
|
+
self.const_set "#{id.to_s.camelize}Field", field_class
|
25
|
+
self.fields = fields.merge(id.to_sym => field_class)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def cursor(id_or_proc)
|
30
|
+
id = id_or_proc.is_a?(Proc) ? nil : id_or_proc
|
31
|
+
proc = id ? -> { target.public_send(id) } : id_or_proc
|
32
|
+
|
33
|
+
field :cursor, proc, type: Raw
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to?(method, *args)
|
37
|
+
super || GQL.field_types.has_key?(method)
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_missing(method, *args, &block)
|
41
|
+
if type = GQL.field_types[method]
|
42
|
+
define_field_method method, type
|
43
|
+
send method, *args, &block
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
rescue NoMethodError => exc
|
48
|
+
raise Errors::NoMethodError.new(self, method, exc)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def proc_for_field(id)
|
53
|
+
instance_exec id, &(field_proc || GQL.default_field_proc)
|
54
|
+
end
|
55
|
+
|
56
|
+
def define_field_method(name, type)
|
57
|
+
Node.define_singleton_method name do |*args, &block|
|
58
|
+
options = args.extract_options!.merge(type: type)
|
59
|
+
args = args.push(options)
|
60
|
+
|
61
|
+
field(*args, &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def value_of_fields(ast_fields)
|
68
|
+
ast_fields.reduce({}) do |result, ast_field|
|
69
|
+
key = ast_field.alias_id || ast_field.id
|
70
|
+
|
71
|
+
result.merge key => value_of_field(ast_field)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def value_of_field(ast_field)
|
76
|
+
if ast_field.id == :node
|
77
|
+
field = self.class.new(ast_field, target, variables, context)
|
78
|
+
field.value
|
79
|
+
else
|
80
|
+
field_class = field_class_for_id(ast_field.id)
|
81
|
+
next_target = target_for_field(target, field_class.proc)
|
82
|
+
|
83
|
+
field = field_class.new(ast_field, next_target, variables, context)
|
84
|
+
field.value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def field_class_for_id(id)
|
89
|
+
self.class.fields[id] or raise Errors::FieldNotFound.new(id, self.class)
|
90
|
+
end
|
91
|
+
|
92
|
+
def target_for_field(current_target, proc)
|
93
|
+
method = ExecutionContext.new(current_target, context)
|
94
|
+
method.execute proc
|
95
|
+
end
|
96
|
+
|
97
|
+
class ExecutionContext < Struct.new(:target, :context)
|
98
|
+
def execute(method, args = [])
|
99
|
+
instance_exec(*args, &method)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/gql/node.rb
CHANGED
@@ -1,27 +1,14 @@
|
|
1
1
|
require 'active_support/core_ext/class/attribute'
|
2
|
-
|
3
|
-
require '
|
4
|
-
require '
|
2
|
+
|
3
|
+
require 'gql/has_calls'
|
4
|
+
require 'gql/has_fields'
|
5
5
|
|
6
6
|
module GQL
|
7
7
|
class Node
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(target, context)
|
12
|
-
@target, @context = target, context
|
13
|
-
end
|
14
|
-
|
15
|
-
def execute(method, args = [])
|
16
|
-
instance_exec(*args, &method)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class_attribute :id, :proc, :calls, :fields, :default_proc, instance_accessor: false, instance_predicate: false
|
8
|
+
include HasCalls
|
9
|
+
include HasFields
|
21
10
|
|
22
|
-
|
23
|
-
self.fields = {}
|
24
|
-
self.default_proc = -> id { -> { target.public_send(id) } }
|
11
|
+
class_attribute :id, :proc, instance_accessor: false, instance_predicate: false
|
25
12
|
|
26
13
|
class << self
|
27
14
|
def build_class(id, proc, options = {})
|
@@ -31,76 +18,6 @@ module GQL
|
|
31
18
|
end
|
32
19
|
end
|
33
20
|
|
34
|
-
def call(id, *args)
|
35
|
-
if id.is_a? Hash
|
36
|
-
id.each do |name, call_class|
|
37
|
-
call name, call_class
|
38
|
-
end
|
39
|
-
else
|
40
|
-
options = args.extract_options!
|
41
|
-
|
42
|
-
proc_or_class = args.shift || -> (*pargs) { target.public_send(id, *pargs) }
|
43
|
-
result_class = options[:returns] || proc_or_class.try(:result_class)
|
44
|
-
|
45
|
-
if result_class.is_a? ::Array
|
46
|
-
if result_class.size == 1
|
47
|
-
result_class.unshift GQL.default_list_class || Connection
|
48
|
-
end
|
49
|
-
|
50
|
-
options = {
|
51
|
-
list_class: result_class.first,
|
52
|
-
item_class: result_class.last
|
53
|
-
}
|
54
|
-
|
55
|
-
result_class = Connection.build_class(:result, nil, options)
|
56
|
-
elsif result_class
|
57
|
-
Node.validate_is_subclass! result_class, 'result'
|
58
|
-
end
|
59
|
-
|
60
|
-
call_class =
|
61
|
-
if proc_or_class.is_a? Proc
|
62
|
-
Class.new(Call).tap do |klass|
|
63
|
-
klass.class_eval do
|
64
|
-
self.proc = proc_or_class
|
65
|
-
|
66
|
-
def execute(*args)
|
67
|
-
instance_exec(*args, &self.class.proc)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
self.const_set "#{id.to_s.camelize}Call", klass
|
72
|
-
end
|
73
|
-
else
|
74
|
-
proc_or_class
|
75
|
-
end
|
76
|
-
|
77
|
-
call_class.id = id.to_s
|
78
|
-
call_class.result_class = result_class
|
79
|
-
|
80
|
-
self.calls = calls.merge(id.to_sym => call_class)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def field(id, *args)
|
85
|
-
options = args.extract_options!
|
86
|
-
proc = args.shift || instance_exec(id, &default_proc)
|
87
|
-
type = options.delete(:type) || Node
|
88
|
-
|
89
|
-
Node.validate_is_subclass! type, 'type'
|
90
|
-
|
91
|
-
type.build_class(id, proc, options).tap do |field_class|
|
92
|
-
self.const_set "#{id.to_s.camelize}Field", field_class
|
93
|
-
self.fields = fields.merge(id.to_sym => field_class)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def cursor(id_or_proc)
|
98
|
-
id = id_or_proc.is_a?(Proc) ? nil : id_or_proc
|
99
|
-
proc = id ? -> { target.public_send(id) } : id_or_proc
|
100
|
-
|
101
|
-
field :cursor, proc, type: Raw
|
102
|
-
end
|
103
|
-
|
104
21
|
def validate_is_subclass!(subclass, name)
|
105
22
|
if subclass.nil?
|
106
23
|
raise Errors::UndefinedNodeClass.new(self, name)
|
@@ -110,27 +27,6 @@ module GQL
|
|
110
27
|
raise Errors::InvalidNodeClass.new(subclass, self)
|
111
28
|
end
|
112
29
|
end
|
113
|
-
|
114
|
-
def respond_to?(method, *args)
|
115
|
-
super || GQL.field_types.has_key?(method)
|
116
|
-
end
|
117
|
-
|
118
|
-
def method_missing(method, *args, &block)
|
119
|
-
if type = GQL.field_types[method]
|
120
|
-
Node.define_singleton_method method do |*margs, &mblock|
|
121
|
-
options = margs.extract_options!.merge(type: type)
|
122
|
-
margs = margs.push(options)
|
123
|
-
|
124
|
-
field(*margs, &mblock)
|
125
|
-
end
|
126
|
-
|
127
|
-
send method, *args, &block
|
128
|
-
else
|
129
|
-
super
|
130
|
-
end
|
131
|
-
rescue NoMethodError
|
132
|
-
raise Errors::UndefinedFieldType, method
|
133
|
-
end
|
134
30
|
end
|
135
31
|
|
136
32
|
attr_reader :ast_node, :target, :variables, :context
|
@@ -150,44 +46,6 @@ module GQL
|
|
150
46
|
end
|
151
47
|
end
|
152
48
|
|
153
|
-
def value_of_call(ast_call)
|
154
|
-
call_class = self.class.calls[ast_call.id]
|
155
|
-
|
156
|
-
if call_class.nil?
|
157
|
-
raise Errors::UndefinedCall.new(ast_call.id, self.class)
|
158
|
-
end
|
159
|
-
|
160
|
-
call_class.execute(self.class, ast_call, target, variables, context)
|
161
|
-
end
|
162
|
-
|
163
|
-
def value_of_fields(ast_fields)
|
164
|
-
ast_fields.reduce({}) do |result, ast_field|
|
165
|
-
key = ast_field.alias_id || ast_field.id
|
166
|
-
|
167
|
-
result.merge key => value_of_field(ast_field)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def value_of_field(ast_field)
|
172
|
-
case ast_field.id
|
173
|
-
when :node
|
174
|
-
field = self.class.new(ast_field, target, variables, context)
|
175
|
-
field.value
|
176
|
-
else
|
177
|
-
field_class = self.class.fields[ast_field.id]
|
178
|
-
|
179
|
-
if field_class.nil?
|
180
|
-
raise Errors::UndefinedField.new(ast_field.id, self.class)
|
181
|
-
end
|
182
|
-
|
183
|
-
method = ExecutionContext.new(target, context)
|
184
|
-
target = method.execute(field_class.proc)
|
185
|
-
|
186
|
-
field = field_class.new(ast_field, target, variables, context)
|
187
|
-
field.value
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
49
|
def raw_value
|
192
50
|
nil
|
193
51
|
end
|
data/lib/gql/parser.rb
CHANGED
@@ -27,6 +27,15 @@ module_eval(<<'...end parser.racc/module_eval...', 'parser.racc', 135)
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
class Root < Struct.new(:call, :fields)
|
31
|
+
def as_json(*)
|
32
|
+
{
|
33
|
+
call: call.as_json,
|
34
|
+
fields: fields.as_json
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
30
39
|
class Node < Struct.new(:id, :alias_id, :call, :fields)
|
31
40
|
def as_json(*)
|
32
41
|
{
|
@@ -300,14 +309,14 @@ module_eval(<<'.,.,', 'parser.racc', 4)
|
|
300
309
|
|
301
310
|
module_eval(<<'.,.,', 'parser.racc', 8)
|
302
311
|
def _reduce_2(val, _values, result)
|
303
|
-
result =
|
312
|
+
result = Root.new(val[0], nil )
|
304
313
|
result
|
305
314
|
end
|
306
315
|
.,.,
|
307
316
|
|
308
317
|
module_eval(<<'.,.,', 'parser.racc', 9)
|
309
318
|
def _reduce_3(val, _values, result)
|
310
|
-
result =
|
319
|
+
result = Root.new(nil, val[1])
|
311
320
|
result
|
312
321
|
end
|
313
322
|
.,.,
|
data/lib/gql/schema/call.rb
CHANGED
@@ -6,15 +6,7 @@ module GQL
|
|
6
6
|
string :id
|
7
7
|
string :type, -> { target.name }
|
8
8
|
object :result_class, -> { target.result_class || Placeholder }, node_class: Node
|
9
|
-
|
10
|
-
|
11
|
-
array :parameters, -> {
|
12
|
-
if target.proc
|
13
|
-
target.proc.parameters
|
14
|
-
else
|
15
|
-
target.instance_method(:execute).parameters
|
16
|
-
end
|
17
|
-
}, item_class: Parameter
|
9
|
+
array :parameters, -> { (target.proc || target.instance_method(:execute)).parameters }, item_class: Parameter
|
18
10
|
end
|
19
11
|
end
|
20
12
|
end
|
data/lib/gql/schema/list.rb
CHANGED
data/lib/gql/schema/parameter.rb
CHANGED
@@ -1,30 +1,20 @@
|
|
1
1
|
module GQL
|
2
2
|
module Schema
|
3
3
|
class Parameter < GQL::Node
|
4
|
-
|
4
|
+
MODES = {
|
5
|
+
req: 'required',
|
6
|
+
opt: 'optional',
|
7
|
+
rest: 'rest',
|
8
|
+
keyreq: 'required keyword',
|
9
|
+
key: 'optional keyword',
|
10
|
+
keyrest: 'keyword rest',
|
11
|
+
block: 'block'
|
12
|
+
}.freeze
|
5
13
|
|
6
|
-
|
14
|
+
cursor -> { target[1].to_s }
|
7
15
|
|
8
|
-
string :
|
9
|
-
|
10
|
-
when :req
|
11
|
-
'required'
|
12
|
-
when :opt
|
13
|
-
'optional'
|
14
|
-
when :rest
|
15
|
-
'rest'
|
16
|
-
when :keyreq
|
17
|
-
'required keyword'
|
18
|
-
when :key
|
19
|
-
'optional keyword'
|
20
|
-
when :keyrest
|
21
|
-
'keyword rest'
|
22
|
-
when :block
|
23
|
-
'block'
|
24
|
-
else
|
25
|
-
target[0].to_s
|
26
|
-
end
|
27
|
-
}
|
16
|
+
string :id, -> { target[1].to_s }
|
17
|
+
string :mode, -> { MODES[target[0]] || target[0].to_s }
|
28
18
|
end
|
29
19
|
end
|
30
20
|
end
|
data/lib/gql/tokenizer.rb
CHANGED
data/lib/gql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Andert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: codeclimate-test-reporter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.4'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.4'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: activesupport
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,6 +125,8 @@ files:
|
|
111
125
|
- lib/gql/connection.rb
|
112
126
|
- lib/gql/errors.rb
|
113
127
|
- lib/gql/executor.rb
|
128
|
+
- lib/gql/has_calls.rb
|
129
|
+
- lib/gql/has_fields.rb
|
114
130
|
- lib/gql/node.rb
|
115
131
|
- lib/gql/number.rb
|
116
132
|
- lib/gql/object.rb
|
@@ -138,7 +154,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
154
|
requirements:
|
139
155
|
- - ">="
|
140
156
|
- !ruby/object:Gem::Version
|
141
|
-
version: 2.
|
157
|
+
version: '2.1'
|
142
158
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
159
|
requirements:
|
144
160
|
- - ">="
|