graphql-client 0.0.18 → 0.0.19

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: ca22da5b31b85d955d2a209f48e5767c2b953848
4
- data.tar.gz: 0150a203bb5fe856b6ea6c15bd941056f86002ff
3
+ metadata.gz: c087161bf28d989bf274ba68bf76223ff4cc7b84
4
+ data.tar.gz: 3054f8552e6e6a532ebd09a15e7f5914b8dfa994
5
5
  SHA512:
6
- metadata.gz: c41fc037d158823686bf372addbc0b6592a87f2e9b470f0fb7302393cc89ad42f452bcb87bfdb142887437c42438e95d20bd236045088e11077cb48dba99ee38
7
- data.tar.gz: 99f425fee8b8e70e876cc8d262befa594f2a2b182cad5b4b6b27a392139e1ecf84a5c6726f0719c96292afe17053ad16060be7ea73e8d414c931315cbddd0fab
6
+ metadata.gz: 4044f2bf520a94bcaf5f6a918baf4daa8eb72479f7fd9de12bacfe58f40a362f57d675207ef0a25d9508113ccc3a0985c2095fa4534385ab4d33b08db2592815
7
+ data.tar.gz: 8d19a14603c36df798b2280432d54e5dceb98d31a1d949c10bd2ac349b82dcf559359253e10b51a3d655f3e3cf22505f1b4ea97ff4a9acdf8e1992e91c462f9b
@@ -1,39 +1,17 @@
1
1
  require "active_support/inflector"
2
2
  require "active_support/notifications"
3
3
  require "graphql"
4
+ require "graphql/client/error"
4
5
  require "graphql/client/query_result"
6
+ require "graphql/client/query"
7
+ require "graphql/client/response"
5
8
  require "graphql/language/nodes/deep_freeze_ext"
6
9
  require "graphql/language/operation_slice"
7
10
 
8
11
  module GraphQL
9
12
  class Client
10
- class Error < StandardError; end
11
13
  class ValidationError < Error; end
12
14
 
13
- class ResponseError < Error
14
- def initialize(definition, error)
15
- @request_definition = definition
16
- @locations = error["locations"]
17
- super error["message"]
18
- end
19
- end
20
-
21
- class ResponseErrors < Error
22
- include Enumerable
23
-
24
- attr_reader :errors
25
-
26
- def initialize(definition, errors)
27
- @request_definition = definition
28
- @errors = errors.map { |error| ResponseError.new(definition, error) }
29
- super @errors.map(&:message).join(", ")
30
- end
31
-
32
- def each(&block)
33
- errors.each(&block)
34
- end
35
- end
36
-
37
15
  attr_reader :schema, :fetch
38
16
 
39
17
  attr_accessor :document_tracking_enabled
@@ -50,8 +28,6 @@ module GraphQL
50
28
  else
51
29
  load_schema(JSON.parse(schema))
52
30
  end
53
- else
54
- nil
55
31
  end
56
32
  end
57
33
 
@@ -114,34 +90,49 @@ module GraphQL
114
90
  end
115
91
 
116
92
  private
117
- def query_result_class
118
- @query_result_class ||= GraphQL::Client::QueryResult.wrap(definition_node, name: name)
119
- end
93
+
94
+ def query_result_class
95
+ @query_result_class ||= GraphQL::Client::QueryResult.wrap(definition_node, name: name)
96
+ end
120
97
  end
121
98
 
122
99
  class OperationDefinition < Definition
123
100
  # Public: Alias for definition name.
124
- alias_method :operation_name, :definition_name
101
+ alias operation_name definition_name
125
102
  end
126
103
 
127
104
  class FragmentDefinition < Definition
128
105
  end
129
106
 
130
- def parse(str)
107
+ def parse(str, filename = nil, lineno = nil)
108
+ if filename.nil? || lineno.nil?
109
+ filename, lineno, = caller(1, 1).first.split(":", 3)
110
+ lineno = lineno.to_i
111
+ end
112
+
131
113
  definition_dependencies = Set.new
132
114
 
133
- str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)+)/) { |m|
134
- const_name = $1
115
+ str = str.gsub(/\.\.\.([a-zA-Z0-9_]+(::[a-zA-Z0-9_]+)+)/) do
116
+ match = Regexp.last_match
117
+ const_name = match[1]
135
118
  case fragment = ActiveSupport::Inflector.safe_constantize(const_name)
136
119
  when FragmentDefinition
137
120
  definition_dependencies.merge(fragment.document.definitions)
138
121
  "...#{fragment.definition_name}"
139
- when nil
140
- raise NameError, "uninitialized constant #{const_name}\n#{str}"
141
122
  else
142
- raise TypeError, "expected #{const_name} to be a #{FragmentDefinition}, but was a #{fragment.class}"
123
+ if fragment
124
+ error = TypeError.new("expected #{const_name} to be a #{FragmentDefinition}, but was a #{fragment.class}")
125
+ else
126
+ error = NameError.new("uninitialized constant #{const_name}")
127
+ end
128
+
129
+ if filename && lineno
130
+ error.set_backtrace(["#{filename}:#{lineno + match.pre_match.count("\n") + 1}"] + caller)
131
+ end
132
+
133
+ raise error
143
134
  end
144
- }
135
+ end
145
136
 
146
137
  doc = GraphQL.parse(str)
147
138
 
@@ -149,8 +140,7 @@ module GraphQL
149
140
  node.name ||= "__anonymous__"
150
141
  end
151
142
 
152
- definition_dependencies.merge(doc.definitions)
153
- document_dependencies = Language::Nodes::Document.new(definitions: definition_dependencies.to_a)
143
+ document_dependencies = Language::Nodes::Document.new(definitions: doc.definitions + definition_dependencies.to_a)
154
144
 
155
145
  if @schema
156
146
  rules = GraphQL::StaticValidation::ALL_RULES - [GraphQL::StaticValidation::FragmentsAreUsed]
@@ -159,7 +149,10 @@ module GraphQL
159
149
 
160
150
  errors = validator.validate(query)
161
151
  errors.fetch(:errors).each do |error|
162
- raise ValidationError, error["message"] + "\n\n" + str
152
+ validation_line = error["locations"][0]["line"]
153
+ error = ValidationError.new(error["message"])
154
+ error.set_backtrace(["#{filename}:#{lineno + validation_line}"] + caller) if filename && lineno
155
+ raise error
163
156
  end
164
157
  end
165
158
 
@@ -171,12 +164,13 @@ module GraphQL
171
164
  definitions[node.name] = definition
172
165
  end
173
166
 
174
- rename_node = -> (node, parent) {
175
- if definition = definitions[node.name]
167
+ rename_node = ->(node, _parent) do
168
+ definition = definitions[node.name]
169
+ if definition
176
170
  node.extend(LazyName)
177
171
  node.name = -> { definition.definition_name }
178
172
  end
179
- }
173
+ end
180
174
  visitor = Language::Visitor.new(doc)
181
175
  visitor[Language::Nodes::FragmentDefinition].leave << rename_node
182
176
  visitor[Language::Nodes::OperationDefinition].leave << rename_node
@@ -185,9 +179,7 @@ module GraphQL
185
179
 
186
180
  doc.deep_freeze
187
181
 
188
- if document_tracking_enabled
189
- self.document.definitions.concat(doc.definitions)
190
- end
182
+ document.definitions.concat(doc.definitions) if document_tracking_enabled
191
183
 
192
184
  if definitions[nil]
193
185
  definitions[nil]
@@ -200,87 +192,15 @@ module GraphQL
200
192
  end
201
193
  end
202
194
 
203
- def document
204
- @document
205
- end
206
-
207
- class Response
208
- attr_reader :extensions
209
-
210
- def initialize(extensions: nil)
211
- @extensions = extensions || {}
212
- end
213
- end
214
-
215
- class SuccessfulResponse < Response
216
- attr_reader :data
217
-
218
- def initialize(data:, **kargs)
219
- @data = data
220
- super(**kargs)
221
- end
222
- end
223
-
224
- class PartialResponse < SuccessfulResponse
225
- attr_reader :errors
226
-
227
- def initialize(errors:, **kargs)
228
- @errors = errors
229
- super(**kargs)
230
- end
231
- end
232
-
233
- class FailedResponse < Response
234
- attr_reader :errors
235
-
236
- def initialize(errors:, **kargs)
237
- @errors = errors
238
- super(**kargs)
239
- end
240
- end
241
-
242
- class Query
243
- attr_reader :document, :operation_name, :variables, :context
244
-
245
- def initialize(document, operation_name: nil, variables: {}, context: {})
246
- @document = document
247
- @operation_name = operation_name
248
- @variables = variables
249
- @context = context
250
- end
251
-
252
- def to_s
253
- document.to_query_string
254
- end
255
-
256
- def operation
257
- document.definitions.find { |node| node.name == operation_name }
258
- end
259
-
260
- def operation_type
261
- operation.operation_type
262
- end
263
-
264
- def payload
265
- {
266
- document: document,
267
- operation_name: operation_name,
268
- operation_type: operation_type,
269
- variables: variables
270
- }
271
- end
272
- end
195
+ attr_reader :document
273
196
 
274
197
  def query(definition, variables: {}, context: {})
275
- unless fetch
276
- raise Error, "client network fetching not configured"
277
- end
198
+ raise Error, "client network fetching not configured" unless fetch
278
199
 
279
200
  query = Query.new(definition.document,
280
- operation_name: definition.operation_name,
281
- variables: variables,
282
- context: context
283
- )
201
+ operation_name: definition.operation_name,
202
+ variables: variables,
203
+ context: context)
284
204
 
285
205
  result = ActiveSupport::Notifications.instrument("query.graphql", query.payload) do
286
206
  fetch.call(query)
@@ -316,11 +236,10 @@ module GraphQL
316
236
  fetch.call(IntrospectionQuery)
317
237
  end
318
238
 
319
- private
320
- module LazyName
321
- def name
322
- @name.call
323
- end
239
+ module LazyName
240
+ def name
241
+ @name.call
324
242
  end
243
+ end
325
244
  end
326
245
  end
@@ -0,0 +1,5 @@
1
+ module GraphQL
2
+ class Client
3
+ class Error < StandardError; end
4
+ end
5
+ end
@@ -2,12 +2,36 @@ require "action_view"
2
2
 
3
3
  module GraphQL
4
4
  class Client
5
+ # Public: Extended Erubis implementation that supports GraphQL static
6
+ # query sections.
7
+ #
8
+ # <%graphql
9
+ # query GetVerison {
10
+ # version
11
+ # }
12
+ # %>
13
+ # <%= data.version %>
14
+ #
15
+ # Configure ActionView's default ERB implementation to use this class.
16
+ #
17
+ # ActionView::Template::Handlers::ERB.erb_implementation = GraphQL::Client::Erubis
18
+ #
5
19
  class Erubis < ActionView::Template::Handlers::Erubis
6
- def self.extract_graphql_sections(src)
7
- src.scan(/<%graphql([^%]+)%>/).flatten.first
20
+ # Public: Extract GraphQL section from ERB template.
21
+ #
22
+ # src - String ERB text
23
+ #
24
+ # Returns String GraphQL query and line number or nil or no section was
25
+ # defined.
26
+ def self.extract_graphql_section(src)
27
+ query_string = src.scan(/<%graphql([^%]+)%>/).flatten.first
28
+ if query_string
29
+ return query_string, Regexp.last_match.pre_match.count("\n") + 1
30
+ end
8
31
  end
9
32
 
10
- # Ignore static <%graphql sections
33
+ # Internal: Extend Rails' Erubis handler to simply ignore <%graphql
34
+ # sections.
11
35
  def convert_input(src, input)
12
36
  input = input.gsub(/<%graphql/, "<%#")
13
37
  super(src, input)
@@ -4,19 +4,55 @@ require "uri"
4
4
 
5
5
  module GraphQL
6
6
  class Client
7
+ # Public: Basic HTTP network adapter.
8
+ #
9
+ # GraphQL::Client::Client.new(
10
+ # fetch: GraphQL::Client::HTTP.new("http://graphql-swapi.parseapp.com/")
11
+ # )
12
+ #
13
+ # Assumes GraphQL endpoint follows the express-graphql endpoint conventions.
14
+ # https://github.com/graphql/express-graphql#http-usage
15
+ #
16
+ # Production applications should consider implementing there own network
17
+ # adapter. This class exists for trivial stock usage and allows for minimal
18
+ # request header configuration.
7
19
  class HTTP
8
- attr_reader :uri
9
-
10
- # GraphQL::Client::HTTP.new("http://graphql-swapi.parseapp.com/")
20
+ # Public: Create HTTP adapter instance for a single GraphQL endpoint.
21
+ #
22
+ # GraphQL::Client::HTTP.new("http://graphql-swapi.parseapp.com/") do
23
+ # def headers(query)
24
+ # { "User-Agent": "My Client" }
25
+ # end
26
+ # end
27
+ #
28
+ # uri - String endpoint URI
29
+ # block - Optional block to configure class
11
30
  def initialize(uri, &block)
12
- @uri = ::URI.parse(uri)
31
+ @uri = URI.parse(uri)
13
32
  class_eval(&block) if block_given?
14
33
  end
15
34
 
16
- def headers(query)
35
+ # Public: Parsed endpoint URI
36
+ #
37
+ # Returns URI.
38
+ attr_reader :uri
39
+
40
+ # Public: Extension point for subclasses to set custom request headers.
41
+ #
42
+ # query - The GraphQL::Client::Query being sent
43
+ #
44
+ # Returns Hash of String header names and values.
45
+ def headers(_)
17
46
  {}
18
47
  end
19
48
 
49
+ # Public: Make an HTTP request for GraphQL query.
50
+ #
51
+ # Implements Client's "fetch" adapter interface.
52
+ #
53
+ # query - The GraphQL::Client::Query being sent
54
+ #
55
+ # Returns { "data" => ... , "errors" => ... } Hash.
20
56
  def call(query)
21
57
  http = Net::HTTP.new(uri.host, uri.port)
22
58
  http.use_ssl = uri.scheme == "https"
@@ -2,13 +2,33 @@ require "active_support/log_subscriber"
2
2
 
3
3
  module GraphQL
4
4
  class Client
5
+ # Public: Logger for "*.graphql" notification events.
6
+ #
7
+ # Logs GraphQL queries to Rails logger.
8
+ #
9
+ # QUERY (123ms) UsersController::ShowQuery
10
+ # MUTATION (456ms) UsersController::UpdateMutation
11
+ #
12
+ # Enable GraphQL Client query logging.
13
+ #
14
+ # require "graphql/client/log_subscriber"
15
+ # GraphQL::Client::LogSubscriber.attach_to :graphql
16
+ #
5
17
  class LogSubscriber < ActiveSupport::LogSubscriber
6
18
  def query(event)
7
- info { "#{event.payload[:name]} (#{event.duration.round(1)}ms) #{event.payload[:operation_name].gsub("__", "::")}" }
8
- debug { event.payload[:document].to_query_string }
19
+ # TODO: Colorize output
20
+ info do
21
+ [
22
+ event.payload[:operation_type].upcase,
23
+ "(#{event.duration.round(1)}ms)",
24
+ event.payload[:operation_name].gsub("__", "::")
25
+ ].join(" ")
26
+ end
27
+
28
+ debug do
29
+ event.payload[:document].to_query_string
30
+ end
9
31
  end
10
32
  end
11
33
  end
12
34
  end
13
-
14
- GraphQL::Client::LogSubscriber.attach_to :graphql
@@ -0,0 +1,65 @@
1
+ module GraphQL
2
+ class Client
3
+ class Query
4
+ # Internal: Construct Query.
5
+ #
6
+ # Avoid creating queries with this constructor, perfer using Client#query.
7
+ #
8
+ # document - A parsed GraphQL::Language::Nodes::Document of the query
9
+ # operation_name - String operation to execute
10
+ # variables - Hash of variables to execute with the operation
11
+ # context - Hash of metadata to pass to network adapter
12
+ def initialize(document, operation_name: nil, variables: {}, context: {})
13
+ @document = document
14
+ @operation_name = operation_name
15
+ @variables = variables
16
+ @context = context
17
+ end
18
+
19
+ # Public: A parsed GraphQL::Language::Nodes::Document of the query.
20
+ attr_reader :document
21
+
22
+ # Public: String name of operation to execute.
23
+ attr_reader :operation_name
24
+
25
+ # Public: Hash of variables to execute with the operation.
26
+ attr_reader :variables
27
+
28
+ # Public: Hash of contextual metadata.
29
+ attr_reader :context
30
+
31
+ # Public: Serialized query string
32
+ #
33
+ # Returns String.
34
+ def to_s
35
+ document.to_query_string
36
+ end
37
+
38
+ # Public: Get operation definition node.
39
+ #
40
+ # Returns GraphQL::Language::Nodes::OperationDefinition.
41
+ def operation
42
+ document.definitions.find { |node| node.name == operation_name }
43
+ end
44
+
45
+ # Public: Query operation type
46
+ #
47
+ # Returns "query", "mutation" or "subscription".
48
+ def operation_type
49
+ operation.operation_type
50
+ end
51
+
52
+ # Internal: Payload object to pass to ActiveSupport::Notifications.
53
+ #
54
+ # Returns Hash.
55
+ def payload
56
+ {
57
+ document: document,
58
+ operation_name: operation_name,
59
+ operation_type: operation_type,
60
+ variables: variables
61
+ }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -42,9 +42,7 @@ module GraphQL
42
42
 
43
43
  # Convert GraphQL camelcase to snake case: commitComments -> commit_comments
44
44
  field_alias = ActiveSupport::Inflector.underscore(field)
45
- if field != field_alias
46
- send :alias_method, field_alias, field
47
- end
45
+ send :alias_method, field_alias, field if field != field_alias
48
46
 
49
47
  class_eval <<-RUBY, __FILE__, __LINE__
50
48
  def #{field_alias}?
@@ -52,15 +50,14 @@ module GraphQL
52
50
  end
53
51
  RUBY
54
52
 
55
- if field == "edges"
56
- class_eval <<-RUBY, __FILE__, __LINE__
53
+ next unless field == "edges"
54
+ class_eval <<-RUBY, __FILE__, __LINE__
57
55
  def each_node
58
56
  return enum_for(:each_node) unless block_given?
59
57
  edges.each { |edge| yield edge.node }
60
58
  self
61
59
  end
62
- RUBY
63
- end
60
+ RUBY
64
61
  end
65
62
 
66
63
  assigns = fields.map do |field, type|
@@ -85,12 +82,12 @@ module GraphQL
85
82
  end
86
83
  end
87
84
 
88
- def self.source_node
89
- @source_node
85
+ class << self
86
+ attr_reader :source_node
90
87
  end
91
88
 
92
- def self.fields
93
- @fields
89
+ class << self
90
+ attr_reader :fields
94
91
  end
95
92
 
96
93
  def self.name
@@ -98,7 +95,7 @@ module GraphQL
98
95
  end
99
96
 
100
97
  def self.inspect
101
- "#<#{self.name} fields=#{@fields.keys.inspect}>"
98
+ "#<#{name} fields=#{@fields.keys.inspect}>"
102
99
  end
103
100
 
104
101
  def self.cast(obj)
@@ -110,9 +107,9 @@ module GraphQL
110
107
  when QueryResult
111
108
  spreads = Set.new(self.spreads(obj.class.source_node).map(&:name))
112
109
 
113
- if !spreads.include?(self.source_node.name)
114
- message = "couldn't cast #{obj.inspect} to #{self.inspect}\n\n"
115
- suggestion = "\n ...#{name || "YourFragment"} # SUGGESTION"
110
+ unless spreads.include?(source_node.name)
111
+ message = "couldn't cast #{obj.inspect} to #{inspect}\n\n"
112
+ suggestion = "\n ...#{name || 'YourFragment'} # SUGGESTION"
116
113
  message << GraphQL::Language::Generation.generate(obj.class.source_node).sub(/\n}$/, "#{suggestion}\n}")
117
114
  raise TypeError, message
118
115
  end
@@ -122,7 +119,7 @@ module GraphQL
122
119
  when NilClass
123
120
  nil
124
121
  else
125
- raise TypeError, "#{obj.class}"
122
+ raise TypeError, obj.class.to_s
126
123
  end
127
124
  end
128
125
 
@@ -150,7 +147,7 @@ module GraphQL
150
147
  end
151
148
 
152
149
  def self.|(other)
153
- new_fields = self.fields.dup
150
+ new_fields = fields.dup
154
151
  other.fields.each do |name, value|
155
152
  if new_fields[name]
156
153
  new_fields[name] |= value
@@ -159,14 +156,14 @@ module GraphQL
159
156
  end
160
157
  end
161
158
  # TODO: Picking first source node seems error prone
162
- define(name: self.name, source_node: self.source_node, fields: new_fields)
159
+ define(name: self.name, source_node: source_node, fields: new_fields)
163
160
  end
164
161
 
165
162
  attr_reader :data
166
- alias_method :to_h, :data
163
+ alias to_h data
167
164
 
168
165
  def inspect
169
- ivars = (self.class.fields.keys).map { |sym| "#{sym}=#{instance_variable_get("@#{sym}").inspect}" }
166
+ ivars = self.class.fields.keys.map { |sym| "#{sym}=#{instance_variable_get("@#{sym}").inspect}" }
170
167
  buf = "#<#{self.class.name}"
171
168
  buf << " " << ivars.join(" ") if ivars.any?
172
169
  buf << ">"
@@ -178,6 +175,10 @@ module GraphQL
178
175
  rescue NoMethodError => e
179
176
  raise NoMethodError, "undefined method `#{e.name}' for #{inspect}"
180
177
  end
178
+
179
+ def respond_to_missing?(*args)
180
+ super
181
+ end
181
182
  end
182
183
  end
183
184
  end
@@ -1,6 +1,5 @@
1
1
  require "graphql"
2
2
  require "graphql/client"
3
- require "graphql/client/log_subscriber"
4
3
  require "rails/railtie"
5
4
 
6
5
  module GraphQL
@@ -11,12 +10,17 @@ module GraphQL
11
10
 
12
11
  # Eager load leaky dependency to workaround AS::Dependencies unloading issues
13
12
  # https://github.com/rmosolgo/graphql-ruby/pull/240
14
- initializer "graphql.eager_load_hack" do |app|
13
+ initializer "graphql.eager_load_hack" do |_app|
15
14
  require "graphql"
16
15
  GraphQL::BOOLEAN_TYPE.name
17
16
  end
18
17
 
19
- initializer "graphql.configure_erb_implementation" do |app|
18
+ initializer "graphql.configure_log_subscriber" do |_app|
19
+ require "graphql/client/log_subscriber"
20
+ GraphQL::Client::LogSubscriber.attach_to :graphql
21
+ end
22
+
23
+ initializer "graphql.configure_erb_implementation" do |_app|
20
24
  require "graphql/client/erubis"
21
25
  ActionView::Template::Handlers::ERB.erb_implementation = GraphQL::Client::Erubis
22
26
  end
@@ -27,11 +31,13 @@ module GraphQL
27
31
  path = app.paths["app/views"].first
28
32
  client = config.graphql.client
29
33
 
30
- Object.const_set(:Views, Module.new {
34
+ config.watchable_dirs[path] = [:erb]
35
+
36
+ Object.const_set(:Views, Module.new do
31
37
  extend GraphQL::Client::ViewModule
32
38
  self.path = path
33
39
  self.client = client
34
- })
40
+ end)
35
41
  end
36
42
  end
37
43
  end
@@ -0,0 +1,87 @@
1
+ require "graphql/client/error"
2
+
3
+ module GraphQL
4
+ class Client
5
+ # Public: Abstract base class for GraphQL responses.
6
+ #
7
+ # https://facebook.github.io/graphql/#sec-Response-Format
8
+ class Response
9
+ # Public: Hash of server specific extension metadata.
10
+ attr_reader :extensions
11
+
12
+ # Internal: Initialize base class.
13
+ def initialize(extensions: nil)
14
+ @extensions = extensions || {}
15
+ end
16
+ end
17
+
18
+ class SuccessfulResponse < Response
19
+ # Public: Wrapped QueryResult of data returned from the server.
20
+ #
21
+ # https://facebook.github.io/graphql/#sec-Data
22
+ #
23
+ # Returns instance of QueryResult subclass.
24
+ attr_reader :data
25
+
26
+ # Internal: Initialize SuccessfulResponse.
27
+ def initialize(data:, **kargs)
28
+ @data = data
29
+ super(**kargs)
30
+ end
31
+ end
32
+
33
+ class PartialResponse < SuccessfulResponse
34
+ # Public: Get partial failures from response.
35
+ #
36
+ # https://facebook.github.io/graphql/#sec-Errors
37
+ #
38
+ # Returns ResponseErrors collection object.
39
+ attr_reader :errors
40
+
41
+ # Internal: Initialize PartialResponse.
42
+ def initialize(errors:, **kargs)
43
+ @errors = errors
44
+ super(**kargs)
45
+ end
46
+ end
47
+
48
+ class FailedResponse < Response
49
+ # Public: Get errors from response.
50
+ #
51
+ # https://facebook.github.io/graphql/#sec-Errors
52
+ #
53
+ # Returns ResponseErrors collection object.
54
+ attr_reader :errors
55
+
56
+ # Internal: Initialize FailedResponse.
57
+ def initialize(errors:, **kargs)
58
+ @errors = errors
59
+ super(**kargs)
60
+ end
61
+ end
62
+
63
+ class ResponseError < Error
64
+ def initialize(definition, error)
65
+ @request_definition = definition
66
+ @locations = error["locations"]
67
+ super error["message"]
68
+ end
69
+ end
70
+
71
+ class ResponseErrors < Error
72
+ include Enumerable
73
+
74
+ attr_reader :errors
75
+
76
+ def initialize(definition, errors)
77
+ @request_definition = definition
78
+ @errors = errors.map { |error| ResponseError.new(definition, error) }
79
+ super @errors.map(&:message).join(", ")
80
+ end
81
+
82
+ def each(&block)
83
+ errors.each(&block)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -20,17 +20,14 @@ module GraphQL
20
20
  #
21
21
  # Returns nothing.
22
22
  def eager_load!
23
- return unless File.directory?(self.path)
23
+ return unless File.directory?(path)
24
24
 
25
- Dir.entries(self.path).each do |entry|
25
+ Dir.entries(path).each do |entry|
26
26
  next if entry == "." || entry == ".."
27
27
  name = entry.sub(/(\.\w+)+$/, "").camelize.to_sym
28
28
  if ViewModule.valid_constant_name?(name) && loadable_const_defined?(name)
29
29
  mod = const_get(name, false)
30
30
  mod.eager_load!
31
- else
32
- # Ignore template names that don't camelize to safe constants:
33
- # 404, foo-dash
34
31
  end
35
32
  end
36
33
 
@@ -97,7 +94,7 @@ module GraphQL
97
94
  # Returns String absolute path to file, otherwise nil.
98
95
  def const_path(name)
99
96
  pathname = ActiveSupport::Inflector.underscore(name.to_s)
100
- Dir[File.join(self.path, "{#{pathname},_#{pathname}}{/,.*}")].map { |fn| File.expand_path(fn) }.first
97
+ Dir[File.join(path, "{#{pathname},_#{pathname}}{/,.*}")].map { |fn| File.expand_path(fn) }.first
101
98
  end
102
99
 
103
100
  # Internal: Initialize new module for constant name and load ERB statics.
@@ -115,13 +112,12 @@ module GraphQL
115
112
 
116
113
  if File.extname(path) == ".erb"
117
114
  contents = File.read(path)
118
- query = GraphQL::Client::Erubis.extract_graphql_sections(contents)
119
- # TODO: Use generic client parser
120
- mod = client.parse(query) if query
115
+ query, lineno = GraphQL::Client::Erubis.extract_graphql_section(contents)
116
+ mod = client.parse(query, path, lineno) if query
121
117
  end
122
118
 
123
119
  mod.extend(ViewModule)
124
- mod.client = self.client
120
+ mod.client = client
125
121
  mod.path = path
126
122
  mod
127
123
  end
@@ -132,7 +128,9 @@ module GraphQL
132
128
  #
133
129
  # Returns module or raises NameError if missing.
134
130
  def const_missing(name)
135
- if path = const_path(name)
131
+ path = const_path(name)
132
+
133
+ if path
136
134
  mod = load_module(path)
137
135
  const_set(name, mod)
138
136
  mod.unloadable
@@ -9,9 +9,7 @@ module GraphQL
9
9
  # Returns self Node.
10
10
  def deep_freeze
11
11
  self.class.child_attributes.each do |attr_name|
12
- public_send(attr_name).freeze.each do |node|
13
- node.deep_freeze
14
- end
12
+ public_send(attr_name).freeze.each(&:deep_freeze)
15
13
  end
16
14
  freeze
17
15
  end
@@ -16,7 +16,7 @@ module GraphQL
16
16
  seen = Set.new([operation_name])
17
17
  stack = [operation_name]
18
18
 
19
- while stack.length > 0
19
+ until stack.empty?
20
20
  name = stack.pop
21
21
  names = find_definition_fragment_spreads(document, name)
22
22
  seen.merge(names)
@@ -28,12 +28,12 @@ module GraphQL
28
28
 
29
29
  def self.find_definition_fragment_spreads(document, definition_name)
30
30
  definition = document.definitions.find { |node| node.name == definition_name }
31
- raise "missing definition: #{definition_name}" if !definition
31
+ raise "missing definition: #{definition_name}" unless definition
32
32
  spreads = Set.new
33
33
  visitor = Visitor.new(definition)
34
- visitor[Nodes::FragmentSpread].enter << -> (node, parent) {
34
+ visitor[Nodes::FragmentSpread].enter << -> (node, _parent) do
35
35
  spreads << node.name
36
- }
36
+ end
37
37
  visitor.visit
38
38
  spreads
39
39
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-10 00:00:00.000000000 Z
11
+ date: 2016-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: actionpack
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -31,7 +31,21 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: '6.0'
33
33
  - !ruby/object:Gem::Dependency
34
- name: activesupport
34
+ name: graphql
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.18'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.18'
47
+ - !ruby/object:Gem::Dependency
48
+ name: actionpack
35
49
  requirement: !ruby/object:Gem::Requirement
36
50
  requirements:
37
51
  - - ">="
@@ -40,7 +54,7 @@ dependencies:
40
54
  - - "<"
41
55
  - !ruby/object:Gem::Version
42
56
  version: '6.0'
43
- type: :runtime
57
+ type: :development
44
58
  prerelease: false
45
59
  version_requirements: !ruby/object:Gem::Requirement
46
60
  requirements:
@@ -51,47 +65,47 @@ dependencies:
51
65
  - !ruby/object:Gem::Version
52
66
  version: '6.0'
53
67
  - !ruby/object:Gem::Dependency
54
- name: graphql
68
+ name: minitest
55
69
  requirement: !ruby/object:Gem::Requirement
56
70
  requirements:
57
71
  - - "~>"
58
72
  - !ruby/object:Gem::Version
59
- version: '0.18'
60
- type: :runtime
73
+ version: '5.9'
74
+ type: :development
61
75
  prerelease: false
62
76
  version_requirements: !ruby/object:Gem::Requirement
63
77
  requirements:
64
78
  - - "~>"
65
79
  - !ruby/object:Gem::Version
66
- version: '0.18'
80
+ version: '5.9'
67
81
  - !ruby/object:Gem::Dependency
68
- name: minitest
82
+ name: rake
69
83
  requirement: !ruby/object:Gem::Requirement
70
84
  requirements:
71
85
  - - "~>"
72
86
  - !ruby/object:Gem::Version
73
- version: '5.9'
87
+ version: '11.2'
74
88
  type: :development
75
89
  prerelease: false
76
90
  version_requirements: !ruby/object:Gem::Requirement
77
91
  requirements:
78
92
  - - "~>"
79
93
  - !ruby/object:Gem::Version
80
- version: '5.9'
94
+ version: '11.2'
81
95
  - !ruby/object:Gem::Dependency
82
- name: rake
96
+ name: rubocop
83
97
  requirement: !ruby/object:Gem::Requirement
84
98
  requirements:
85
99
  - - "~>"
86
100
  - !ruby/object:Gem::Version
87
- version: '11.2'
101
+ version: '0.42'
88
102
  type: :development
89
103
  prerelease: false
90
104
  version_requirements: !ruby/object:Gem::Requirement
91
105
  requirements:
92
106
  - - "~>"
93
107
  - !ruby/object:Gem::Version
94
- version: '11.2'
108
+ version: '0.42'
95
109
  description: "???"
96
110
  email: engineering@github.com
97
111
  executables: []
@@ -100,11 +114,14 @@ extra_rdoc_files: []
100
114
  files:
101
115
  - LICENSE
102
116
  - lib/graphql/client.rb
117
+ - lib/graphql/client/error.rb
103
118
  - lib/graphql/client/erubis.rb
104
119
  - lib/graphql/client/http.rb
105
120
  - lib/graphql/client/log_subscriber.rb
121
+ - lib/graphql/client/query.rb
106
122
  - lib/graphql/client/query_result.rb
107
123
  - lib/graphql/client/railtie.rb
124
+ - lib/graphql/client/response.rb
108
125
  - lib/graphql/client/view_module.rb
109
126
  - lib/graphql/language/nodes/deep_freeze_ext.rb
110
127
  - lib/graphql/language/operation_slice.rb