gql 0.0.19 → 0.0.20
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/lib/gql.rb +6 -20
- data/lib/gql/array.rb +8 -14
- data/lib/gql/config.rb +19 -53
- data/lib/gql/connection.rb +4 -8
- data/lib/gql/errors.rb +1 -1
- data/lib/gql/executor.rb +2 -2
- data/lib/gql/field.rb +6 -14
- data/lib/gql/lazy.rb +31 -0
- data/lib/gql/mixins/common.rb +31 -0
- data/lib/gql/mixins/has_calls.rb +120 -0
- data/lib/gql/mixins/has_fields.rb +138 -0
- data/lib/gql/object.rb +16 -4
- data/lib/gql/registry.rb +39 -0
- data/lib/gql/schema/call.rb +2 -2
- data/lib/gql/schema/field.rb +2 -2
- data/lib/gql/version.rb +1 -1
- metadata +21 -5
- data/lib/gql/has_calls.rb +0 -104
- data/lib/gql/has_fields.rb +0 -132
- data/lib/gql/test_case.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84b1f6dbe8ad680fd457f4f14dbd0183b4b18d46
|
4
|
+
data.tar.gz: 192058fde95f568491e87c6edd719b9a4c85b1c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dee4291ac7f769adf121c145b8f2a2a93bd0a3417aba29e218120cc2106045f2e4f19cbcd2491b778aff4531f6c04d88acb39500bae1d24763be054131cfe29a
|
7
|
+
data.tar.gz: ae67282c3aa9cf8b48155429c7f6714f16562ba3ff77fdf9f4a9edcfabc8fae59d02b7472490599f3959b36a2af82971ad8ff36754be8f3b8b61cf71d757ff64
|
data/lib/gql.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'active_support/dependencies/autoload'
|
2
|
+
|
2
3
|
require 'gql/version'
|
4
|
+
require 'gql/errors'
|
3
5
|
|
4
6
|
module GQL
|
5
7
|
extend ActiveSupport::Autoload
|
@@ -9,33 +11,17 @@ module GQL
|
|
9
11
|
autoload :Call
|
10
12
|
autoload :Config
|
11
13
|
autoload :Connection
|
12
|
-
autoload :Error, 'gql/errors'
|
13
14
|
autoload :Executor
|
14
15
|
autoload :Field
|
16
|
+
autoload :Lazy
|
15
17
|
autoload :Number
|
16
18
|
autoload :Object
|
17
19
|
autoload :Parser
|
20
|
+
autoload :Registry
|
18
21
|
autoload :Scalar
|
19
22
|
autoload :String
|
20
|
-
autoload :TestCase
|
21
23
|
autoload :Tokenizer
|
22
24
|
|
23
|
-
module Errors
|
24
|
-
extend ActiveSupport::Autoload
|
25
|
-
|
26
|
-
autoload_at 'gql/errors' do
|
27
|
-
autoload :CallNotFound
|
28
|
-
autoload :FieldClassNotSet
|
29
|
-
autoload :FieldNotFound
|
30
|
-
autoload :InvalidFieldClass
|
31
|
-
autoload :NoMethodError
|
32
|
-
autoload :RootClassNotSet
|
33
|
-
autoload :ScanError
|
34
|
-
autoload :SyntaxError
|
35
|
-
autoload :VariableNotFound
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
25
|
module Schema
|
40
26
|
extend ActiveSupport::Autoload
|
41
27
|
|
@@ -55,8 +41,8 @@ module GQL
|
|
55
41
|
Thread.current[:gql_config] = value
|
56
42
|
end
|
57
43
|
|
58
|
-
%w(
|
59
|
-
|
44
|
+
%w(root_class root_target_proc field_types
|
45
|
+
default_list_class default_field_proc
|
60
46
|
default_call_proc debug).each do |method|
|
61
47
|
module_eval <<-DELEGATORS, __FILE__, __LINE__ + 1
|
62
48
|
def #{method}
|
data/lib/gql/array.rb
CHANGED
@@ -2,32 +2,26 @@ require 'active_support/core_ext/class/attribute'
|
|
2
2
|
|
3
3
|
module GQL
|
4
4
|
class Array < Field
|
5
|
-
class_attribute :
|
5
|
+
class_attribute :item_class, instance_accessor: false, instance_predicate: false
|
6
6
|
|
7
7
|
class << self
|
8
8
|
def build_class(id, proc, options = {})
|
9
|
-
|
10
|
-
|
11
|
-
if item_field_class.is_a?(Hash)
|
12
|
-
item_field_class.values.each do |ifc|
|
13
|
-
Field.validate_is_subclass! ifc, 'item_field_class'
|
14
|
-
end
|
15
|
-
else
|
16
|
-
Field.validate_is_subclass! item_field_class, 'item_field_class'
|
17
|
-
item_field_class = Hash.new(item_field_class)
|
18
|
-
end
|
9
|
+
item_class = options.delete(:item_class) || self.item_class
|
10
|
+
item_class = ::Hash.new(item_class) unless item_class.is_a?(::Hash)
|
19
11
|
|
20
12
|
Class.new(self).tap do |field_class|
|
21
|
-
field_class.id = id
|
13
|
+
field_class.id = id
|
22
14
|
field_class.proc = proc
|
23
|
-
field_class.
|
15
|
+
field_class.item_class = item_class
|
24
16
|
end
|
25
17
|
end
|
26
18
|
end
|
27
19
|
|
28
20
|
def value
|
29
21
|
target.map do |item|
|
30
|
-
|
22
|
+
field_class = Registry.fetch(self.class.item_class[item.class])
|
23
|
+
|
24
|
+
field = field_class.new(ast_node, item, variables, context)
|
31
25
|
field.value
|
32
26
|
end
|
33
27
|
end
|
data/lib/gql/config.rb
CHANGED
@@ -1,17 +1,11 @@
|
|
1
|
-
require 'active_support/core_ext/class/subclasses'
|
2
|
-
|
3
1
|
module GQL
|
4
2
|
class Config
|
5
|
-
def
|
6
|
-
@@
|
3
|
+
def root_class
|
4
|
+
@@root_class ||= nil
|
7
5
|
end
|
8
6
|
|
9
|
-
def
|
10
|
-
|
11
|
-
raise Errors::InvalidFieldClass.new(value, Field)
|
12
|
-
end
|
13
|
-
|
14
|
-
@@root_field_class = value
|
7
|
+
def root_class=(value)
|
8
|
+
@@root_class = value
|
15
9
|
end
|
16
10
|
|
17
11
|
def root_target_proc
|
@@ -24,12 +18,12 @@ module GQL
|
|
24
18
|
|
25
19
|
def field_types
|
26
20
|
@@field_types ||= {
|
27
|
-
array: Array,
|
28
|
-
boolean: Boolean,
|
29
|
-
connection: Connection,
|
30
|
-
number: Number,
|
31
|
-
object: Object,
|
32
|
-
string: String
|
21
|
+
array: 'GQL::Array',
|
22
|
+
boolean: 'GQL::Boolean',
|
23
|
+
connection: 'GQL::Connection',
|
24
|
+
number: 'GQL::Number',
|
25
|
+
object: 'GQL::Object',
|
26
|
+
string: 'GQL::String'
|
33
27
|
}
|
34
28
|
end
|
35
29
|
|
@@ -37,16 +31,12 @@ module GQL
|
|
37
31
|
@@field_types = value
|
38
32
|
end
|
39
33
|
|
40
|
-
def
|
41
|
-
@@
|
34
|
+
def default_list_class
|
35
|
+
@@default_list_class ||= 'GQL::Field'
|
42
36
|
end
|
43
37
|
|
44
|
-
def
|
45
|
-
|
46
|
-
raise Errors::InvalidFieldClass.new(value, Field)
|
47
|
-
end
|
48
|
-
|
49
|
-
@@default_list_field_class = value
|
38
|
+
def default_list_class=(value)
|
39
|
+
@@default_list_class = value
|
50
40
|
end
|
51
41
|
|
52
42
|
def default_field_proc
|
@@ -77,6 +67,8 @@ module GQL
|
|
77
67
|
def debug=(value)
|
78
68
|
value = !!value
|
79
69
|
|
70
|
+
@@debug = nil unless defined?(@@debug)
|
71
|
+
|
80
72
|
return if value == @@debug
|
81
73
|
|
82
74
|
value ? switch_debug_on : switch_debug_off
|
@@ -86,39 +78,13 @@ module GQL
|
|
86
78
|
|
87
79
|
private
|
88
80
|
def switch_debug_on
|
89
|
-
|
90
|
-
switch_on_execution_context
|
91
|
-
end
|
92
|
-
|
93
|
-
def switch_debug_off
|
94
|
-
switch_off_type_field
|
95
|
-
switch_off_execution_context
|
96
|
-
end
|
97
|
-
|
98
|
-
def switch_on_type_field
|
99
|
-
return if Field.has_field? :__type__
|
100
|
-
|
101
|
-
type_field_class = Field.object :__type__, -> { field_class }, field_class: Schema::Field
|
102
|
-
|
103
|
-
Field.descendants.each do |field_class|
|
104
|
-
field_class.fields[:__type__] = type_field_class
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def switch_off_type_field
|
109
|
-
return unless Field.has_field? :__type__
|
110
|
-
|
111
|
-
[Field, *Field.descendants].each do |field_class|
|
112
|
-
field_class.remove_field :__type__
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def switch_on_execution_context
|
81
|
+
Field.object :__type__, -> { field_class }, class: Schema::Field
|
117
82
|
Field.send :remove_const, :ExecutionContext if Field.const_defined?(:ExecutionContext)
|
118
83
|
Field.const_set :ExecutionContext, Field::ExecutionContextDebug
|
119
84
|
end
|
120
85
|
|
121
|
-
def
|
86
|
+
def switch_debug_off
|
87
|
+
Field.remove_field :__type__
|
122
88
|
Field.send :remove_const, :ExecutionContext if Field.const_defined?(:ExecutionContext)
|
123
89
|
Field.const_set :ExecutionContext, Field::ExecutionContextNoDebug
|
124
90
|
end
|
data/lib/gql/connection.rb
CHANGED
@@ -1,16 +1,12 @@
|
|
1
|
-
require 'active_support/core_ext/class/attribute'
|
2
|
-
|
3
1
|
module GQL
|
4
2
|
class Connection < Field
|
5
3
|
class << self
|
6
4
|
def build_class(id, proc, options = {})
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
Field.validate_is_subclass! list_field_class, 'list_field_class'
|
5
|
+
list_class = options.delete(:list_class) || GQL.default_list_class
|
6
|
+
item_class = options.delete(:item_class)
|
11
7
|
|
12
|
-
|
13
|
-
field_class.array :edges, -> { target },
|
8
|
+
Registry.fetch(list_class).build_class(id, proc, options).tap do |field_class|
|
9
|
+
field_class.array :edges, -> { target }, item_class: item_class
|
14
10
|
end
|
15
11
|
end
|
16
12
|
end
|
data/lib/gql/errors.rb
CHANGED
data/lib/gql/executor.rb
CHANGED
@@ -8,7 +8,7 @@ module GQL
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def execute(context = {}, vars = {})
|
11
|
-
field_class = GQL.
|
11
|
+
field_class = GQL.root_class
|
12
12
|
|
13
13
|
raise Errors::RootClassNotSet if field_class.nil?
|
14
14
|
|
@@ -16,7 +16,7 @@ module GQL
|
|
16
16
|
|
17
17
|
target = GQL.root_target_proc.call(context)
|
18
18
|
|
19
|
-
field = field_class.new(ast_root, target, variables, context)
|
19
|
+
field = Registry.fetch(field_class).new(ast_root, target, variables, context)
|
20
20
|
field.value
|
21
21
|
end
|
22
22
|
end
|
data/lib/gql/field.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'active_support/core_ext/class/attribute'
|
2
2
|
|
3
|
-
require 'gql/
|
4
|
-
require 'gql/
|
3
|
+
require 'gql/mixins/common'
|
4
|
+
require 'gql/mixins/has_calls'
|
5
|
+
require 'gql/mixins/has_fields'
|
5
6
|
|
6
7
|
module GQL
|
7
8
|
class Field
|
@@ -14,20 +15,11 @@ module GQL
|
|
14
15
|
field_class.proc = proc
|
15
16
|
end
|
16
17
|
end
|
17
|
-
|
18
|
-
def validate_is_subclass!(subclass, name)
|
19
|
-
if subclass.nil?
|
20
|
-
raise Errors::FieldClassNotSet.new(self, name)
|
21
|
-
end
|
22
|
-
|
23
|
-
unless subclass <= self
|
24
|
-
raise Errors::InvalidFieldClass.new(subclass, self)
|
25
|
-
end
|
26
|
-
end
|
27
18
|
end
|
28
19
|
|
29
|
-
|
30
|
-
include
|
20
|
+
extend Mixins::Common
|
21
|
+
include Mixins::HasCalls
|
22
|
+
include Mixins::HasFields
|
31
23
|
|
32
24
|
attr_reader :ast_node, :target, :variables, :context
|
33
25
|
|
data/lib/gql/lazy.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
|
3
|
+
module GQL
|
4
|
+
class Lazy < Field
|
5
|
+
class_attribute :owner, :type, :options, instance_accessor: false, instance_predicate: false
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def build_class(id, proc, options)
|
9
|
+
Class.new(self).tap do |field_class|
|
10
|
+
field_class.owner = options.delete(:owner)
|
11
|
+
field_class.type = options.delete(:type)
|
12
|
+
field_class.id = id
|
13
|
+
field_class.proc = proc
|
14
|
+
field_class.options = options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def resolve
|
19
|
+
owner.remove_field id
|
20
|
+
owner.add_field id, proc, options.merge(type: Registry.fetch(type))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def value
|
25
|
+
field_class = self.class.resolve
|
26
|
+
|
27
|
+
field = field_class.new(ast_node, target, variables, context)
|
28
|
+
field.value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
3
|
+
|
4
|
+
module GQL
|
5
|
+
module Mixins
|
6
|
+
module Common
|
7
|
+
def propagate(type, id, klass)
|
8
|
+
const_name = send("const_name_for_#{type}", id)
|
9
|
+
accessor = type.to_s.pluralize
|
10
|
+
|
11
|
+
const_set const_name, klass
|
12
|
+
|
13
|
+
[self, *descendants].each do |c|
|
14
|
+
c.send "#{accessor}=", c.send(accessor).merge(id => klass)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def shutdown(type, id)
|
19
|
+
const_name = send("const_name_for_#{type}", id)
|
20
|
+
accessor = type.to_s.pluralize
|
21
|
+
|
22
|
+
[self, *descendants].each do |c|
|
23
|
+
next unless c.send("has_#{type}?", id)
|
24
|
+
|
25
|
+
c.send :remove_const, const_name if c.const_defined?(const_name, false)
|
26
|
+
c.send(accessor).delete id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,120 @@
|
|
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/class/subclasses'
|
5
|
+
require 'active_support/core_ext/object/try'
|
6
|
+
require 'active_support/core_ext/string/inflections'
|
7
|
+
|
8
|
+
module GQL
|
9
|
+
module Mixins
|
10
|
+
module HasCalls
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
class_attribute :calls, :call_proc, instance_accessor: false, instance_predicate: false
|
15
|
+
self.calls = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def add_call(id, *args, &block)
|
20
|
+
remove_call id
|
21
|
+
|
22
|
+
id = id.to_sym
|
23
|
+
options = args.extract_options!
|
24
|
+
call_spec = args.shift || block || proc_for_call(id)
|
25
|
+
result_spec = options[:returns] || call_spec.try(:result_class)
|
26
|
+
result_class = result_class_from_spec(result_spec)
|
27
|
+
|
28
|
+
build_call_class(call_spec, id, result_class).tap do |call_class|
|
29
|
+
propagate :call, id, call_class
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alias :call :add_call
|
34
|
+
|
35
|
+
def remove_call(id)
|
36
|
+
shutdown :call, id.to_sym
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_call?(id)
|
40
|
+
calls.has_key? id.to_sym
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def build_call_class(spec, id, result_class)
|
45
|
+
call_class_from_spec(spec).tap do |call_class|
|
46
|
+
call_class.id = id
|
47
|
+
call_class.result_class = result_class
|
48
|
+
|
49
|
+
if result_class && result_class.name.nil?
|
50
|
+
call_class.const_set :Result, result_class
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def call_class_from_spec(spec)
|
56
|
+
return Class.new(spec) unless spec.is_a?(Proc)
|
57
|
+
|
58
|
+
Class.new(Call).tap do |call_class|
|
59
|
+
call_class.class_eval do
|
60
|
+
self.proc = spec
|
61
|
+
|
62
|
+
def execute(*args)
|
63
|
+
instance_exec(*args, &self.class.proc)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def const_name_for_call(id)
|
70
|
+
:"#{id.to_s.camelize}Call"
|
71
|
+
end
|
72
|
+
|
73
|
+
def proc_for_call(id)
|
74
|
+
instance_exec id, &(call_proc || GQL.default_call_proc)
|
75
|
+
end
|
76
|
+
|
77
|
+
def result_class_from_spec(spec)
|
78
|
+
result_class =
|
79
|
+
case spec
|
80
|
+
when ::Array
|
81
|
+
result_class_from_connection_spec spec.dup
|
82
|
+
when ::Hash
|
83
|
+
result_class_from_mapping_spec spec.dup
|
84
|
+
else
|
85
|
+
spec
|
86
|
+
end
|
87
|
+
|
88
|
+
result_class && Registry.fetch(result_class)
|
89
|
+
end
|
90
|
+
|
91
|
+
def result_class_from_connection_spec(spec)
|
92
|
+
if spec.size == 1
|
93
|
+
spec.unshift GQL.default_list_class
|
94
|
+
end
|
95
|
+
|
96
|
+
options = {
|
97
|
+
list_class: spec.first,
|
98
|
+
item_class: spec.last
|
99
|
+
}
|
100
|
+
|
101
|
+
Connection.build_class :result, nil, options
|
102
|
+
end
|
103
|
+
|
104
|
+
def result_class_from_mapping_spec(spec)
|
105
|
+
Object.build_class :result, nil, class: spec
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
def value_of_call(ast_call)
|
111
|
+
call_class = call_class_for_id(ast_call.id)
|
112
|
+
call_class.execute(self.class, ast_call, target, variables, context)
|
113
|
+
end
|
114
|
+
|
115
|
+
def call_class_for_id(id)
|
116
|
+
self.class.calls[id] or raise Errors::CallNotFound.new(id, self.class)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,138 @@
|
|
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/class/subclasses'
|
5
|
+
require 'active_support/core_ext/string/inflections'
|
6
|
+
|
7
|
+
module GQL
|
8
|
+
module Mixins
|
9
|
+
module HasFields
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do
|
13
|
+
class_attribute :fields, :field_proc, instance_accessor: false, instance_predicate: false
|
14
|
+
self.fields = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def add_field(id, *args, &block)
|
19
|
+
remove_field id
|
20
|
+
|
21
|
+
id = id.to_sym
|
22
|
+
options = args.extract_options!
|
23
|
+
type = options.delete(:type) || Field
|
24
|
+
proc = args.shift || block || proc_for_field(id)
|
25
|
+
|
26
|
+
build_field_class(type, id, proc, options).tap do |field_class|
|
27
|
+
propagate :field, id, field_class
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
alias :field :add_field
|
32
|
+
|
33
|
+
def remove_field(id)
|
34
|
+
shutdown :field, id.to_sym
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_field?(id)
|
38
|
+
fields.has_key? id.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
def cursor(id_or_proc)
|
42
|
+
id = id_or_proc.is_a?(Proc) ? nil : id_or_proc
|
43
|
+
proc = id ? -> { target.public_send(id) } : id_or_proc
|
44
|
+
|
45
|
+
add_field :cursor, proc, type: Scalar
|
46
|
+
end
|
47
|
+
|
48
|
+
def respond_to?(method, *args)
|
49
|
+
super || GQL.field_types.has_key?(method)
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(method, *args, &block)
|
53
|
+
if type = GQL.field_types[method]
|
54
|
+
define_field_method method, type
|
55
|
+
send method, *args, &block
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
59
|
+
rescue NoMethodError => exc
|
60
|
+
raise Errors::NoMethodError.new(self, method, exc)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def build_field_class(type, id, proc, options)
|
65
|
+
if type.is_a? ::String
|
66
|
+
Lazy.build_class id, proc, options.merge(owner: self, type: type)
|
67
|
+
else
|
68
|
+
Registry.fetch(type).build_class id, proc, options
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def const_name_for_field(id)
|
73
|
+
prefix = id == :__type__ ? 'Schema_Type' : id.to_s.camelize
|
74
|
+
:"#{prefix}Field"
|
75
|
+
end
|
76
|
+
|
77
|
+
def proc_for_field(id)
|
78
|
+
instance_exec id, &(field_proc || GQL.default_field_proc)
|
79
|
+
end
|
80
|
+
|
81
|
+
def define_field_method(name, type)
|
82
|
+
Field.define_singleton_method name do |*args, &block|
|
83
|
+
options = args.extract_options!.merge(type: type)
|
84
|
+
args = args.push(options)
|
85
|
+
|
86
|
+
add_field(*args, &block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
def value_of_fields(ast_fields)
|
93
|
+
ast_fields.reduce({}) do |result, ast_field|
|
94
|
+
key = ast_field.alias_id || ast_field.id
|
95
|
+
|
96
|
+
result.merge key => value_of_field(ast_field)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def value_of_field(ast_field)
|
101
|
+
if ast_field.id == :node
|
102
|
+
field = self.class.new(ast_field, target, variables, context)
|
103
|
+
field.value
|
104
|
+
else
|
105
|
+
field_class = field_class_for_id(ast_field.id)
|
106
|
+
next_target = target_for_field(target, field_class.proc)
|
107
|
+
|
108
|
+
field = field_class.new(ast_field, next_target, variables, context)
|
109
|
+
field.value
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def field_class_for_id(id)
|
114
|
+
self.class.fields[id] or raise Errors::FieldNotFound.new(id, self.class)
|
115
|
+
end
|
116
|
+
|
117
|
+
def target_for_field(current_target, proc)
|
118
|
+
args = [current_target, context]
|
119
|
+
args.push self.class if GQL.debug
|
120
|
+
|
121
|
+
method = self.class.const_get(:ExecutionContext).new(*args)
|
122
|
+
method.execute proc
|
123
|
+
end
|
124
|
+
|
125
|
+
class ExecutionContextNoDebug < Struct.new(:target, :context)
|
126
|
+
def execute(method, args = [])
|
127
|
+
instance_exec(*args, &method)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class ExecutionContextDebug < Struct.new(:target, :context, :field_class)
|
132
|
+
def execute(method, args = [])
|
133
|
+
instance_exec(*args, &method)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/gql/object.rb
CHANGED
@@ -2,14 +2,26 @@ require 'active_support/core_ext/class/attribute'
|
|
2
2
|
|
3
3
|
module GQL
|
4
4
|
class Object < Field
|
5
|
+
class_attribute :object_class, instance_accessor: false, instance_predicate: false
|
6
|
+
|
5
7
|
class << self
|
6
8
|
def build_class(id, proc, options = {})
|
7
|
-
|
8
|
-
|
9
|
-
Field.validate_is_subclass! field_class, 'field_class'
|
9
|
+
object_class = options.delete(:class) || options.delete(:as)
|
10
|
+
object_class = ::Hash.new(object_class) unless object_class.is_a?(::Hash)
|
10
11
|
|
11
|
-
|
12
|
+
Class.new(self).tap do |klass|
|
13
|
+
klass.id = id
|
14
|
+
klass.proc = proc
|
15
|
+
klass.object_class = object_class
|
16
|
+
end
|
12
17
|
end
|
13
18
|
end
|
19
|
+
|
20
|
+
def value
|
21
|
+
field_class = Registry.fetch(self.class.object_class[target.class])
|
22
|
+
|
23
|
+
field = field_class.new(ast_node, target, variables, context)
|
24
|
+
field.value
|
25
|
+
end
|
14
26
|
end
|
15
27
|
end
|
data/lib/gql/registry.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
require 'active_support/per_thread_registry'
|
3
|
+
|
4
|
+
module GQL
|
5
|
+
class Registry
|
6
|
+
extend ActiveSupport::PerThreadRegistry
|
7
|
+
|
8
|
+
attr_reader :cache
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
reset
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset
|
15
|
+
@cache = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch(key, baseclass = Field)
|
19
|
+
cache[key] || begin
|
20
|
+
raise Errors::FieldClassNotSet.new(baseclass, 'TODO') if key.nil?
|
21
|
+
|
22
|
+
const, name =
|
23
|
+
if key.instance_of? ::Class
|
24
|
+
[key, key.name]
|
25
|
+
else
|
26
|
+
[key.constantize, key]
|
27
|
+
end
|
28
|
+
|
29
|
+
raise Errors::InvalidFieldClass.new(const, baseclass) unless const <= baseclass
|
30
|
+
|
31
|
+
cache.update name => const, const => const
|
32
|
+
|
33
|
+
cache[key]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
alias_method :[], :fetch
|
38
|
+
end
|
39
|
+
end
|
data/lib/gql/schema/call.rb
CHANGED
@@ -5,8 +5,8 @@ module GQL
|
|
5
5
|
|
6
6
|
string :id
|
7
7
|
string :name
|
8
|
-
object :result_class, -> { target.result_class || CallerClass },
|
9
|
-
array :parameters, -> { (target.proc || target.instance_method(:execute)).parameters },
|
8
|
+
object :result_class, -> { target.result_class || CallerClass }, class: Field
|
9
|
+
array :parameters, -> { (target.proc || target.instance_method(:execute)).parameters }, item_class: Parameter
|
10
10
|
|
11
11
|
def scalar_value
|
12
12
|
target.name
|
data/lib/gql/schema/field.rb
CHANGED
@@ -5,8 +5,8 @@ module GQL
|
|
5
5
|
|
6
6
|
string :id
|
7
7
|
string :name
|
8
|
-
connection :calls, -> { target.calls.values },
|
9
|
-
connection :fields, -> { target.fields.values },
|
8
|
+
connection :calls, -> { target.calls.values }, list_class: List, item_class: Call
|
9
|
+
connection :fields, -> { target.fields.values }, list_class: List, item_class: Field
|
10
10
|
|
11
11
|
def scalar_value
|
12
12
|
target.name
|
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.20
|
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-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest-perf
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.1'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: activesupport
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,11 +126,14 @@ files:
|
|
112
126
|
- lib/gql/errors.rb
|
113
127
|
- lib/gql/executor.rb
|
114
128
|
- lib/gql/field.rb
|
115
|
-
- lib/gql/
|
116
|
-
- lib/gql/
|
129
|
+
- lib/gql/lazy.rb
|
130
|
+
- lib/gql/mixins/common.rb
|
131
|
+
- lib/gql/mixins/has_calls.rb
|
132
|
+
- lib/gql/mixins/has_fields.rb
|
117
133
|
- lib/gql/number.rb
|
118
134
|
- lib/gql/object.rb
|
119
135
|
- lib/gql/parser.rb
|
136
|
+
- lib/gql/registry.rb
|
120
137
|
- lib/gql/scalar.rb
|
121
138
|
- lib/gql/schema/call.rb
|
122
139
|
- lib/gql/schema/caller_class.rb
|
@@ -124,7 +141,6 @@ files:
|
|
124
141
|
- lib/gql/schema/list.rb
|
125
142
|
- lib/gql/schema/parameter.rb
|
126
143
|
- lib/gql/string.rb
|
127
|
-
- lib/gql/test_case.rb
|
128
144
|
- lib/gql/tokenizer.rb
|
129
145
|
- lib/gql/version.rb
|
130
146
|
homepage: https://github.com/martinandert/gql
|
data/lib/gql/has_calls.rb
DELETED
@@ -1,104 +0,0 @@
|
|
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 add_call(id, *args, &block)
|
18
|
-
options = args.extract_options!
|
19
|
-
|
20
|
-
call_spec = args.shift || block || 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
|
-
Field.validate_is_subclass! result_class, 'result_class' 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
|
-
if result_class && result_class.name.nil?
|
31
|
-
call_class.const_set :Result, result_class
|
32
|
-
end
|
33
|
-
|
34
|
-
self.const_set const_name_for_call(id), call_class
|
35
|
-
self.calls = calls.merge(id.to_sym => call_class)
|
36
|
-
end
|
37
|
-
|
38
|
-
alias :call :add_call
|
39
|
-
|
40
|
-
def remove_call(id)
|
41
|
-
const_name = const_name_for_call(id)
|
42
|
-
|
43
|
-
send :remove_const, const_name if const_defined?(const_name)
|
44
|
-
calls.delete id
|
45
|
-
end
|
46
|
-
|
47
|
-
def has_call?(id)
|
48
|
-
calls.has_key? id
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
def const_name_for_call(id)
|
53
|
-
:"#{id.to_s.camelize}Call"
|
54
|
-
end
|
55
|
-
|
56
|
-
def proc_for_call(id)
|
57
|
-
instance_exec id, &(call_proc || GQL.default_call_proc)
|
58
|
-
end
|
59
|
-
|
60
|
-
def result_class_from_spec(spec)
|
61
|
-
return spec unless spec.is_a? ::Array
|
62
|
-
|
63
|
-
result_class_from_connection_spec spec.dup
|
64
|
-
end
|
65
|
-
|
66
|
-
def result_class_from_connection_spec(spec)
|
67
|
-
if spec.size == 1
|
68
|
-
spec.unshift GQL.default_list_field_class
|
69
|
-
end
|
70
|
-
|
71
|
-
options = {
|
72
|
-
list_field_class: spec.first,
|
73
|
-
item_field_class: spec.last
|
74
|
-
}
|
75
|
-
|
76
|
-
Connection.build_class :result, nil, options
|
77
|
-
end
|
78
|
-
|
79
|
-
def call_class_from_spec(spec)
|
80
|
-
return Class.new(spec) unless spec.is_a?(Proc)
|
81
|
-
|
82
|
-
Class.new(Call).tap do |call_class|
|
83
|
-
call_class.class_eval do
|
84
|
-
self.proc = spec
|
85
|
-
|
86
|
-
def execute(*args)
|
87
|
-
instance_exec(*args, &self.class.proc)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
def value_of_call(ast_call)
|
96
|
-
call_class = call_class_for_id(ast_call.id)
|
97
|
-
call_class.execute(self.class, ast_call, target, variables, context)
|
98
|
-
end
|
99
|
-
|
100
|
-
def call_class_for_id(id)
|
101
|
-
self.class.calls[id] or raise Errors::CallNotFound.new(id, self.class)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
data/lib/gql/has_fields.rb
DELETED
@@ -1,132 +0,0 @@
|
|
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 add_field(id, *args, &block)
|
17
|
-
options = args.extract_options!
|
18
|
-
type = options.delete(:type) || Field
|
19
|
-
proc = args.shift || block || proc_for_field(id)
|
20
|
-
|
21
|
-
Field.validate_is_subclass! type, 'type'
|
22
|
-
|
23
|
-
type.build_class(id, proc, options).tap do |field_class|
|
24
|
-
const_name = const_name_for_field(id)
|
25
|
-
|
26
|
-
const_set const_name, field_class unless const_defined?(const_name)
|
27
|
-
self.fields = fields.merge(id.to_sym => field_class)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
alias :field :add_field
|
32
|
-
|
33
|
-
def remove_field(id)
|
34
|
-
const_name = const_name_for_field(id)
|
35
|
-
|
36
|
-
send :remove_const, const_name if const_defined?(const_name)
|
37
|
-
fields.delete id
|
38
|
-
end
|
39
|
-
|
40
|
-
def has_field?(id)
|
41
|
-
fields.has_key? id
|
42
|
-
end
|
43
|
-
|
44
|
-
def cursor(id_or_proc)
|
45
|
-
id = id_or_proc.is_a?(Proc) ? nil : id_or_proc
|
46
|
-
proc = id ? -> { target.public_send(id) } : id_or_proc
|
47
|
-
|
48
|
-
add_field :cursor, proc, type: Scalar
|
49
|
-
end
|
50
|
-
|
51
|
-
def respond_to?(method, *args)
|
52
|
-
super || GQL.field_types.has_key?(method)
|
53
|
-
end
|
54
|
-
|
55
|
-
def method_missing(method, *args, &block)
|
56
|
-
if type = GQL.field_types[method]
|
57
|
-
define_field_method method, type
|
58
|
-
send method, *args, &block
|
59
|
-
else
|
60
|
-
super
|
61
|
-
end
|
62
|
-
rescue NoMethodError => exc
|
63
|
-
raise Errors::NoMethodError.new(self, method, exc)
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
def const_name_for_field(id)
|
68
|
-
prefix = id == :__type__ ? 'Schema_Type' : id.to_s.camelize
|
69
|
-
:"#{prefix}Field"
|
70
|
-
end
|
71
|
-
|
72
|
-
def proc_for_field(id)
|
73
|
-
instance_exec id, &(field_proc || GQL.default_field_proc)
|
74
|
-
end
|
75
|
-
|
76
|
-
def define_field_method(name, type)
|
77
|
-
Field.define_singleton_method name do |*args, &block|
|
78
|
-
options = args.extract_options!.merge(type: type)
|
79
|
-
args = args.push(options)
|
80
|
-
|
81
|
-
add_field(*args, &block)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
def value_of_fields(ast_fields)
|
88
|
-
ast_fields.reduce({}) do |result, ast_field|
|
89
|
-
key = ast_field.alias_id || ast_field.id
|
90
|
-
|
91
|
-
result.merge key => value_of_field(ast_field)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def value_of_field(ast_field)
|
96
|
-
if ast_field.id == :node
|
97
|
-
field = self.class.new(ast_field, target, variables, context)
|
98
|
-
field.value
|
99
|
-
else
|
100
|
-
field_class = field_class_for_id(ast_field.id)
|
101
|
-
next_target = target_for_field(target, field_class.proc)
|
102
|
-
|
103
|
-
field = field_class.new(ast_field, next_target, variables, context)
|
104
|
-
field.value
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def field_class_for_id(id)
|
109
|
-
self.class.fields[id] or raise Errors::FieldNotFound.new(id, self.class)
|
110
|
-
end
|
111
|
-
|
112
|
-
def target_for_field(current_target, proc)
|
113
|
-
args = [current_target, context]
|
114
|
-
args.push self.class if GQL.debug
|
115
|
-
|
116
|
-
method = self.class.const_get(:ExecutionContext).new(*args)
|
117
|
-
method.execute proc
|
118
|
-
end
|
119
|
-
|
120
|
-
class ExecutionContextNoDebug < Struct.new(:target, :context)
|
121
|
-
def execute(method, args = [])
|
122
|
-
instance_exec(*args, &method)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
class ExecutionContextDebug < Struct.new(:target, :context, :field_class)
|
127
|
-
def execute(method, args = [])
|
128
|
-
instance_exec(*args, &method)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
data/lib/gql/test_case.rb
DELETED