graphql-client 0.7.0 → 0.8.0

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: bd882791666554b4b6999b5e6e1089187eb06e9a
4
- data.tar.gz: 5c1e142aee92b113edef6c34a90484ff32b2fd0e
3
+ metadata.gz: 9c735cc6d34d7372e777934b15cbf86540cf994a
4
+ data.tar.gz: 329f6769cf02065e726dd26e9006cb1143f3f8df
5
5
  SHA512:
6
- metadata.gz: 242cd9508205d68cb2459a78bcd689a986c4317478113923d8fbd23d015bf8c936fd84619410228404699a7c229377f6333f857f216853d9991b32603e34443d
7
- data.tar.gz: 74fb38b0777b0df123df5c5a09a6e1caf5f69ec3f5f765c859d041900c58e6403cebd0a59c882095524ba18cf08ab0e04dcfca7164b39c6d2e291e8f845b15f1
6
+ metadata.gz: fd69bd130b837dff72de557d1b0c51e7a4f0b499af231af00d8b2df65a638116021f45660be83c8695aa27bbf808741db5317d4791e68f6bf0db9f059dbf9273
7
+ data.tar.gz: 20d75c1fa9d08f56a096328cf499e163eea4b7d13bfc9767f8fa743004e87c9a611d32d6533cbc0f28d72770b41635eff526549baf81bd52cc319ed0437ccb4c
@@ -3,9 +3,12 @@ require "active_support/inflector"
3
3
  require "active_support/notifications"
4
4
  require "graphql"
5
5
  require "graphql/client/collocated_enforcement"
6
+ require "graphql/client/definition"
6
7
  require "graphql/client/definition_variables"
7
8
  require "graphql/client/error"
8
9
  require "graphql/client/errors"
10
+ require "graphql/client/fragment_definition"
11
+ require "graphql/client/operation_definition"
9
12
  require "graphql/client/query_result"
10
13
  require "graphql/client/query_typename"
11
14
  require "graphql/client/response"
@@ -88,96 +91,6 @@ module GraphQL
88
91
  @enforce_collocated_callers = enforce_collocated_callers
89
92
  end
90
93
 
91
- # Definitions are constructed by Client.parse and wrap a parsed AST of the
92
- # query string as well as hold references to any external query definition
93
- # dependencies.
94
- #
95
- # Definitions MUST be assigned to a constant.
96
- class Definition < Module
97
- def self.for(node:, **kargs)
98
- case node
99
- when Language::Nodes::OperationDefinition
100
- OperationDefinition.new(node: node, **kargs)
101
- when Language::Nodes::FragmentDefinition
102
- FragmentDefinition.new(node: node, **kargs)
103
- else
104
- raise TypeError, "expected node to be a definition type, but was #{node.class}"
105
- end
106
- end
107
-
108
- def initialize(node:, document:, schema:, document_types:, source_location:, enforce_collocated_callers:)
109
- @definition_node = node
110
- @document = document
111
- @schema = schema
112
- @document_types = document_types
113
- @source_location = source_location
114
- @enforce_collocated_callers = enforce_collocated_callers
115
- end
116
-
117
- # Internal: Get underlying operation or fragment defintion AST node for
118
- # definition.
119
- #
120
- # Returns OperationDefinition or FragmentDefinition object.
121
- attr_reader :definition_node
122
-
123
- # Public: Global name of definition in client document.
124
- #
125
- # Returns a GraphQL safe name of the Ruby constant String.
126
- #
127
- # "Users::UserQuery" #=> "Users__UserQuery"
128
- #
129
- # Returns String.
130
- def definition_name
131
- return @definition_name if defined?(@definition_name)
132
-
133
- if name
134
- @definition_name = name.gsub("::", "__").freeze
135
- else
136
- "#{self.class.name}_#{object_id}".gsub("::", "__").freeze
137
- end
138
- end
139
-
140
- # Public: Get document with only the definitions needed to perform this
141
- # operation.
142
- #
143
- # Returns GraphQL::Language::Nodes::Document with one OperationDefinition
144
- # and any FragmentDefinition dependencies.
145
- attr_reader :document
146
-
147
- # Internal: Mapping of document nodes to schema types.
148
- attr_reader :document_types
149
-
150
- attr_reader :schema
151
-
152
- # Public: Returns the Ruby source filename and line number containing this
153
- # definition was not defined in Ruby.
154
- #
155
- # Returns Array pair of [String, Fixnum].
156
- attr_reader :source_location
157
-
158
- attr_reader :enforce_collocated_callers
159
-
160
- def new(*args)
161
- type.new(*args)
162
- end
163
-
164
- def type
165
- # TODO: Fix type indirection
166
- @type ||= GraphQL::Client::QueryResult.wrap(self, definition_node, name: "#{name}.type")
167
- end
168
- end
169
-
170
- # Specific operation definition subtype for queries, mutations or
171
- # subscriptions.
172
- class OperationDefinition < Definition
173
- # Public: Alias for definition name.
174
- alias operation_name definition_name
175
- end
176
-
177
- # Specific fragment definition subtype.
178
- class FragmentDefinition < Definition
179
- end
180
-
181
94
  def parse(str, filename = nil, lineno = nil)
182
95
  if filename.nil? && lineno.nil?
183
96
  location = caller_locations(1, 1).first
@@ -3,6 +3,10 @@ require "graphql/client/error"
3
3
 
4
4
  module GraphQL
5
5
  class Client
6
+
7
+ # Collcation will not be enforced if a stack trace includes any of these gems.
8
+ WHITELISTED_GEM_NAMES = %w{pry byebug}
9
+
6
10
  # Raised when method is called from outside the expected file scope.
7
11
  class NonCollocatedCallerError < Error; end
8
12
 
@@ -30,7 +34,8 @@ module GraphQL
30
34
  return super(*args, &block) if Thread.current[:query_result_caller_location_ignore]
31
35
 
32
36
  locations = caller_locations(1, 1)
33
- if locations.first.path != path
37
+
38
+ if (locations.first.path != path) && !(caller_locations.any? { |cl| WHITELISTED_GEM_NAMES.any? { |g| cl.path.include?("gems/#{g}") } })
34
39
  error = NonCollocatedCallerError.new("#{method} was called outside of '#{path}' https://git.io/v1syX")
35
40
  error.set_backtrace(caller(1))
36
41
  raise error
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Client
4
+ # Definitions are constructed by Client.parse and wrap a parsed AST of the
5
+ # query string as well as hold references to any external query definition
6
+ # dependencies.
7
+ #
8
+ # Definitions MUST be assigned to a constant.
9
+ class Definition < Module
10
+ def self.for(node:, **kargs)
11
+ case node
12
+ when Language::Nodes::OperationDefinition
13
+ OperationDefinition.new(node: node, **kargs)
14
+ when Language::Nodes::FragmentDefinition
15
+ FragmentDefinition.new(node: node, **kargs)
16
+ else
17
+ raise TypeError, "expected node to be a definition type, but was #{node.class}"
18
+ end
19
+ end
20
+
21
+ def initialize(node:, document:, schema:, document_types:, source_location:, enforce_collocated_callers:)
22
+ @definition_node = node
23
+ @document = document
24
+ @schema = schema
25
+ @document_types = document_types
26
+ @source_location = source_location
27
+ @enforce_collocated_callers = enforce_collocated_callers
28
+ end
29
+
30
+ # Internal: Get underlying operation or fragment defintion AST node for
31
+ # definition.
32
+ #
33
+ # Returns OperationDefinition or FragmentDefinition object.
34
+ attr_reader :definition_node
35
+
36
+ # Public: Global name of definition in client document.
37
+ #
38
+ # Returns a GraphQL safe name of the Ruby constant String.
39
+ #
40
+ # "Users::UserQuery" #=> "Users__UserQuery"
41
+ #
42
+ # Returns String.
43
+ def definition_name
44
+ return @definition_name if defined?(@definition_name)
45
+
46
+ if name
47
+ @definition_name = name.gsub("::", "__").freeze
48
+ else
49
+ "#{self.class.name}_#{object_id}".gsub("::", "__").freeze
50
+ end
51
+ end
52
+
53
+ # Public: Get document with only the definitions needed to perform this
54
+ # operation.
55
+ #
56
+ # Returns GraphQL::Language::Nodes::Document with one OperationDefinition
57
+ # and any FragmentDefinition dependencies.
58
+ attr_reader :document
59
+
60
+ # Internal: Mapping of document nodes to schema types.
61
+ attr_reader :document_types
62
+
63
+ attr_reader :schema
64
+
65
+ # Public: Returns the Ruby source filename and line number containing this
66
+ # definition was not defined in Ruby.
67
+ #
68
+ # Returns Array pair of [String, Fixnum].
69
+ attr_reader :source_location
70
+
71
+ attr_reader :enforce_collocated_callers
72
+
73
+ def new(*args)
74
+ type.new(*args)
75
+ end
76
+
77
+ def type
78
+ # TODO: Fix type indirection
79
+ @type ||= GraphQL::Client::QueryResult.wrap(self, definition_node, name: "#{name}.type")
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "graphql/client/definition"
4
+
5
+ module GraphQL
6
+ class Client
7
+ # Specific fragment definition subtype.
8
+ class FragmentDefinition < Definition
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "graphql/client/definition"
4
+
5
+ module GraphQL
6
+ class Client
7
+ # Specific operation definition subtype for queries, mutations or
8
+ # subscriptions.
9
+ class OperationDefinition < Definition
10
+ # Public: Alias for definition name.
11
+ alias operation_name definition_name
12
+ end
13
+ end
14
+ end
@@ -227,12 +227,16 @@ module GraphQL
227
227
  # Returns Errors collection.
228
228
  attr_reader :errors
229
229
 
230
- attr_reader :data
231
- alias to_h data
232
-
233
230
  attr_reader :__typename
234
231
  alias typename __typename
235
232
 
233
+ # Public: Returns the raw response data
234
+ #
235
+ # Returns Hash
236
+ def to_h
237
+ @data
238
+ end
239
+
236
240
  def type_of?(*types)
237
241
  types.any? do |type|
238
242
  if type = self.class.schema.types.fetch(type.to_s, nil)
@@ -272,7 +276,7 @@ module GraphQL
272
276
  raise UnimplementedFieldError, "undefined field `#{e.name}' on #{type} type. https://git.io/v1y3m"
273
277
  end
274
278
 
275
- if data[field.name]
279
+ if @data[field.name]
276
280
  error_class = ImplicitlyFetchedFieldError
277
281
  message = "implicitly fetched field `#{field.name}' on #{type} type. https://git.io/v1yGL"
278
282
  else
@@ -44,14 +44,14 @@ module GraphQL
44
44
  #
45
45
  # Returns nothing.
46
46
  def eager_load!
47
- return unless File.directory?(path)
47
+ return unless File.directory?(load_path)
48
48
 
49
- Dir.entries(path).each do |entry|
49
+ Dir.entries(load_path).each do |entry|
50
50
  next if entry == "." || entry == ".."
51
51
  name = entry.sub(/(\.\w+)+$/, "").camelize.to_sym
52
- if ViewModule.valid_constant_name?(name) && loadable_const_defined?(name)
53
- mod = const_get(name, false)
54
- mod.eager_load!
52
+ if ViewModule.valid_constant_name?(name)
53
+ mod = const_defined?(name, false) ? const_get(name) : load_and_set_module(name)
54
+ mod.eager_load! if mod
55
55
  end
56
56
  end
57
57
 
@@ -73,76 +73,67 @@ module GraphQL
73
73
  name.to_s =~ /^[A-Z][a-zA-Z0-9_]*$/
74
74
  end
75
75
 
76
- # Public: Override constant defined to check if constant name matches a
77
- # view directory or template namespace.
78
- #
79
- # name - String or Symbol constant name
80
- # inherit - If the lookup will also search the ancestors (default: true)
81
- #
82
- # Returns true if definition is found, otherwise false.
83
- # def const_defined?(name, inherit = true)
84
- # if super(name.to_sym, inherit)
85
- # true
86
- # elsif const_path(name)
87
- # true
88
- # else
89
- # false
90
- # end
91
- # end
92
-
93
- def loadable_const_defined?(name)
94
- if const_defined?(name.to_sym, false)
95
- true
96
- elsif const_path(name)
97
- true
98
- else
99
- false
100
- end
101
- end
102
-
103
- # Public: Source location that defined the Module.
76
+ # Public: Directory to retrieve nested GraphQL definitions from.
104
77
  #
105
78
  # Returns absolute String path under app/views.
106
- attr_accessor :path
79
+ attr_accessor :load_path
80
+ alias_method :path=, :load_path=
81
+ alias_method :path, :load_path
107
82
 
108
- # Internal: Detect source location for constant name.
109
- #
110
- # name - String or Symbol constant name
83
+ # Public: if this module was defined by a view
111
84
  #
112
- # Examples
113
- #
114
- # Views.const_path(:Users) #=> "app/views/users"
115
- # Views::Users.const_path(:Show) #=> "app/views/users/show.html.erb"
116
- # Views::Users.const_path(:Profile) #=> "app/views/users/_profile.html.erb"
117
- #
118
- # Returns String absolute path to file, otherwise nil.
119
- def const_path(name)
120
- pathname = ActiveSupport::Inflector.underscore(name.to_s)
121
- Dir[File.join(path, "{#{pathname},_#{pathname}}{/,.*}")].map { |fn| File.expand_path(fn) }.first
122
- end
85
+ # Returns absolute String path under app/views.
86
+ attr_accessor :source_path
123
87
 
124
88
  # Internal: Initialize new module for constant name and load ERB statics.
125
89
  #
126
- # path - String path of directory or erb file.
90
+ # name - String or Symbol constant name.
127
91
  #
128
92
  # Examples
129
93
  #
130
- # load_module("app/views/users")
131
- # load_module("app/views/users/show.html.erb")
94
+ # Views::Users.load_module(:Profile)
95
+ # Views::Users::Profile.load_module(:Show)
132
96
  #
133
97
  # Returns new Module implementing Loadable concern.
134
- def load_module(path)
135
- mod = Module.new
98
+ def load_module(name)
99
+ pathname = ActiveSupport::Inflector.underscore(name.to_s)
100
+ path = Dir[File.join(load_path, "{#{pathname},_#{pathname}}{.*}")].map { |fn| File.expand_path(fn) }.first
136
101
 
137
- if File.extname(path) == ".erb"
138
- contents = File.read(path)
139
- query, lineno = ViewModule.extract_graphql_section(contents)
140
- mod = client.parse(query, path, lineno) if query
141
- end
102
+ return if !path || File.extname(path) != ".erb"
142
103
 
104
+ contents = File.read(path)
105
+ query, lineno = ViewModule.extract_graphql_section(contents)
106
+ return unless query
107
+
108
+ mod = client.parse(query, path, lineno)
143
109
  mod.extend(ViewModule)
110
+ mod.load_path = File.join(load_path, pathname)
111
+ mod.source_path = path
144
112
  mod.client = client
145
- mod.path = path
113
+ mod
114
+ end
115
+
116
+ def placeholder_module(name)
117
+ dirname = File.join(load_path, ActiveSupport::Inflector.underscore(name.to_s))
118
+ return nil unless Dir.exist?(dirname)
119
+
120
+ Module.new.tap do |mod|
121
+ mod.extend(ViewModule)
122
+ mod.load_path = dirname
123
+ mod.client = client
124
+ end
125
+ end
126
+
127
+ def load_and_set_module(name)
128
+ placeholder = placeholder_module(name)
129
+ const_set(name, placeholder) if placeholder
130
+
131
+ mod = load_module(name)
132
+ return placeholder unless mod
133
+
134
+ remove_const(name) if placeholder
135
+ const_set(name, mod)
136
+ mod.unloadable
146
137
  mod
147
138
  end
148
139
 
@@ -152,16 +143,7 @@ module GraphQL
152
143
  #
153
144
  # Returns module or raises NameError if missing.
154
145
  def const_missing(name)
155
- path = const_path(name)
156
-
157
- if path
158
- mod = load_module(path)
159
- const_set(name, mod)
160
- mod.unloadable
161
- mod
162
- else
163
- super
164
- end
146
+ load_and_set_module(name) || super
165
147
  end
166
148
  end
167
149
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-30 00:00:00.000000000 Z
11
+ date: 2017-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -158,6 +158,7 @@ files:
158
158
  - README.md
159
159
  - lib/graphql/client.rb
160
160
  - lib/graphql/client/collocated_enforcement.rb
161
+ - lib/graphql/client/definition.rb
161
162
  - lib/graphql/client/definition_variables.rb
162
163
  - lib/graphql/client/document_types.rb
163
164
  - lib/graphql/client/error.rb
@@ -165,10 +166,12 @@ files:
165
166
  - lib/graphql/client/erubi_enhancer.rb
166
167
  - lib/graphql/client/erubis.rb
167
168
  - lib/graphql/client/erubis_enhancer.rb
169
+ - lib/graphql/client/fragment_definition.rb
168
170
  - lib/graphql/client/hash_with_indifferent_access.rb
169
171
  - lib/graphql/client/http.rb
170
172
  - lib/graphql/client/list.rb
171
173
  - lib/graphql/client/log_subscriber.rb
174
+ - lib/graphql/client/operation_definition.rb
172
175
  - lib/graphql/client/query_result.rb
173
176
  - lib/graphql/client/query_typename.rb
174
177
  - lib/graphql/client/railtie.rb
@@ -197,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
197
200
  version: '0'
198
201
  requirements: []
199
202
  rubyforge_project:
200
- rubygems_version: 2.6.11
203
+ rubygems_version: 2.5.2
201
204
  signing_key:
202
205
  specification_version: 4
203
206
  summary: GraphQL Client