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 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