graphql_model_mapper 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c4b6b09863ce496e54d98306ed8edc1a31e720d1
4
+ data.tar.gz: c00f8470a348752631c91c280715f4f8cb59fe0e
5
+ SHA512:
6
+ metadata.gz: a7a0e7b631352b9314c28ef35ae3bddf89cffa2ab9c82c76e219a033396945c97f59ab42091185007ab23b152d2f8a312b383d09b783b3838757637f4a4749f0
7
+ data.tar.gz: d3b1c83e2b307b86e47707c140efba01e461b13c8e25d4497b64b89c39875a3875f21c04f0d456390cca2fa3b6f14f7ef9d09da7ae4012c3cbbb8737913bc3f2
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.8
5
+ before_install: gem install bundler -v 1.16.0
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake'
4
+ gem 'activerecord', '~>3.2.22.5', :require => 'active_record'
5
+ gem 'activemodel', '~>3.2.22.5', :require => 'active_record'
6
+ gem 'activesupport', '~>3.2.22.5', :require => 'active_support'
7
+ gem 'graphql', '~>1.7.5'
8
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
9
+
10
+ # Specify your gem's dependencies in graphql_model_mapper.gemspec
11
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ graphql_model_mapper (0.0.2)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (3.2.22.5)
10
+ activesupport (= 3.2.22.5)
11
+ builder (~> 3.0.0)
12
+ activerecord (3.2.22.5)
13
+ activemodel (= 3.2.22.5)
14
+ activesupport (= 3.2.22.5)
15
+ arel (~> 3.0.2)
16
+ tzinfo (~> 0.3.29)
17
+ activesupport (3.2.22.5)
18
+ i18n (~> 0.6, >= 0.6.4)
19
+ multi_json (~> 1.0)
20
+ arel (3.0.3)
21
+ builder (3.0.4)
22
+ concurrent-ruby (1.0.5)
23
+ graphql (1.7.5)
24
+ i18n (0.9.1)
25
+ concurrent-ruby (~> 1.0)
26
+ minitest (5.10.3)
27
+ multi_json (1.12.2)
28
+ rake (12.2.1)
29
+ tzinfo (0.3.53)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ activemodel (~> 3.2.22.5)
36
+ activerecord (~> 3.2.22.5)
37
+ activesupport (~> 3.2.22.5)
38
+ bundler (~> 1.16)
39
+ graphql (~> 1.7.5)
40
+ graphql_model_mapper!
41
+ minitest (~> 5.0)
42
+ rake
43
+
44
+ BUNDLED WITH
45
+ 1.16.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Gene Black
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,416 @@
1
+ # graphql_model_mapper
2
+ This project is a work in progress and is in a pre-alpha state. Many thanks to @AndyKriger https://github.com/AndyKriger who initiated and shared the original idea on the GraphQL issue thread https://github.com/rmosolgo/graphql-ruby/issues/945.
3
+
4
+ The graphql_model_mapper gem facilitates the generation of GraphQL objects based on the definition of your existing ActiveRecord models.
5
+
6
+ It has been tested on Rails 3.2, 4.1 and 5.0 using Ruby 2.2.8
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'graphql_model_mapper', :git => "git://github.com/geneeblack/graphql_model_mapper.git"
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install graphql_model_mapper
23
+
24
+ ## Usage
25
+
26
+ Initially, you will not have any models exposed as GraphQL types. To expose a model you can add any/all of the following macro attributes to your model definition:
27
+
28
+ graphql_query # to generate a GraphQL query object (and associated GraphQL input/output types) for the model
29
+ graphql_create # to generate a GraphQL create mutation object (and its associated GraphQL input/output types) for the model
30
+ graphql_delete # to generate a GraphQL delete mutation object (and its associated GraphQL input/output types) for the model
31
+ graphql_update # to generate a GraphQL update mutation object (and its associated GraphQL input/output types) for the model
32
+
33
+ The default input/output types generated for the model are based on the default settings (which may be overriden by initializing GraphqlModelMapper::GRAPHQL_DEFAULT_TYPES in your own initializer
34
+
35
+ Note that the query and delete mutations do not have an input type defined since their arguments are currently generated internally:
36
+
37
+ GraphqlModelMapper::GRAPHQL_DEFAULT_TYPES =
38
+ query: {
39
+ output_type: {
40
+ required_attributes: [], # attributes required in the type - empty list defaults to no required attributes
41
+ excluded_attributes: [], # exclude these attributes from the type - empty list defaults to no excluded attributes
42
+ allowed_attributes: [], # only allow these attributes in the type - empty list defaults to all attributes allowed
43
+ foreign_keys: true, # generate the foreign keys on the type
44
+ primary_keys: true, # generate the primary keys for the type
45
+ validation_keys: false, # generate non-nullable validation keys for the type
46
+ association_macro: nil, # generate the associations fo the type - nil defaults to all associations (other than those that are polymorphic), you may also specify :has_many or :belongs_to or :has_one
47
+ source_nulls: false, # use the null definitions that are defined by the database for the exposed attributes
48
+ type_key: :query, # internal identifier for the query/mutation type for which this type definition applies
49
+ type_sub_key: :output_type # internal sub-identifier for the input/output type for which this definition applies
50
+ }
51
+ },
52
+ update: {
53
+ input_type: {
54
+ required_attributes: [],
55
+ excluded_attributes: [],
56
+ allowed_attributes: [],
57
+ foreign_keys: true,
58
+ primary_keys: true,
59
+ validation_keys: false,
60
+ association_macro: nil,
61
+ source_nulls: false,
62
+ type_key: :update,
63
+ type_sub_key: :input_type
64
+ },
65
+ output_type: {
66
+ required_attributes: [],
67
+ excluded_attributes: [],
68
+ allowed_attributes: [],
69
+ foreign_keys: true,
70
+ primary_keys: true,
71
+ validation_keys: false,
72
+ association_macro: nil,
73
+ source_nulls: true,
74
+ type_key: :update,
75
+ type_sub_key: :output_type
76
+ }
77
+ },
78
+ delete: {
79
+ output_type: {
80
+ required_attributes: [],
81
+ excluded_attributes: [],
82
+ allowed_attributes: [],
83
+ foreign_keys: false,
84
+ primary_keys: true,
85
+ validation_keys: false,
86
+ association_macro: nil,
87
+ source_nulls: true,
88
+ type_key: :delete,
89
+ type_sub_key: :output_type
90
+ }
91
+ },
92
+ create: {
93
+ input_type: {
94
+ required_attributes: [],
95
+ excluded_attributes: [],
96
+ allowed_attributes: [],
97
+ foreign_keys: true,
98
+ primary_keys: false,
99
+ validation_keys: false,
100
+ association_macro: :has_many,
101
+ source_nulls: false,
102
+ type_key: :create,
103
+ type_sub_key: :input_type
104
+ },
105
+ output_type: {
106
+ required_attributes: [],
107
+ excluded_attributes: [],
108
+ allowed_attributes: [],
109
+ foreign_keys: true,
110
+ primary_keys: true,
111
+ validation_keys: false,
112
+ association_macro: nil,
113
+ source_nulls: true,
114
+ type_key: :create,
115
+ type_sub_key: :output_type
116
+ }
117
+ }
118
+
119
+ or individually by using the
120
+
121
+ graphql_type
122
+
123
+ macro attribute on the model, passing the individual settings that differ from the defaults. i.e.
124
+
125
+
126
+ graphql_types query: {
127
+ output_type: {
128
+ excluded_attributes: [:crypted_password]
129
+ }
130
+ },
131
+ update: {
132
+ input_type: {
133
+ excluded_attributes: [:crypted_password]
134
+ },
135
+ output_type: {
136
+ excluded_attributes: [:crypted_password]
137
+ }
138
+ },
139
+ create: {
140
+ input_type: {
141
+ excluded_attributes: [:crypted_password]
142
+ },
143
+ output_type: {
144
+ excluded_attributes: [:crypted_password]
145
+ }
146
+ },
147
+ delete: {
148
+ input_type: {
149
+ excluded_attributes: [:crypted_password]
150
+ },
151
+ output_type: {
152
+ excluded_attributes: [:crypted_password]
153
+ }
154
+ }
155
+
156
+ ## Other Options
157
+
158
+ The query and mutation objects have a default resolver defined that may be sufficient for your needs (with the exception of the create mutation which most likely will not be adequate for your implementation, currently it simply validates the input and does not attempt to add the record).
159
+
160
+ def self.create_resolver(obj, inputs, ctx, model_name)
161
+ if !GraphqlModelMapper.authorized?(ctx, model_name, :create)
162
+ raise GraphQL::ExecutionError.new("error: unauthorized access: create '#{model_name.classify}'")
163
+ end
164
+ model = model_name.classify.constantize
165
+ item = model.new(inputs[model_name.downcase].to_h)
166
+ begin
167
+ if !item.valid?
168
+ raise GraphQL::ExecutionError.new(item.errors.full_messages.join("; "))
169
+ else
170
+ raise GraphQL::ExecutionError.new("error: WIP, item not saved but is a valid '#{model_name.classify}'")
171
+ #item.save!
172
+ end
173
+ end
174
+ item
175
+ end
176
+
177
+
178
+ If you want to assign your own resolvers for your type you can override the default resolver for the type on the macro attribute in the following way:
179
+
180
+ graphql_query resolver: -> (obj, inputs, ctx){ raise GraphQL::ExecutionError.new(inputs.to_h.to_a) }
181
+
182
+ The method that you assign to the resolver should either be self contained or call a class method that accepts and orchestrates the parameters passed from GraphQL in the resolve. In this example it is simply calling a GraphQL::ExecutionError to output the contents of the input parameters. These methods could be anywhere in your application, they are not limited to the model on which they are defined.
183
+
184
+ When returning items to populate the appropriate output type, return them as a hash value shaped to fit the output types definition. GraphQL will take care of the final mapping and shapping of the models item(s)
185
+
186
+ resolver: -> (obj, inputs, ctx){
187
+ items = YourClass.method_that_returns_items(obj, inputs, ctx, name)
188
+ {
189
+ total: items.length,
190
+ items: items
191
+ }
192
+ }
193
+ or
194
+
195
+ resolver: -> (obj, inputs, ctx){
196
+ items = YourClass.method_that_returns_an_item(obj, inputs, ctx, name)
197
+ {
198
+ item: item
199
+ }
200
+ }
201
+
202
+
203
+ Some other attributes that you can set on the graphql_query in addition to the resolver are
204
+
205
+ ## graphql_query
206
+
207
+ description: # a short description of the query
208
+ scope_methods: # scope methods available to be used in the query, these should not be parameterized and must be written so that they do not collide with other tables which may be included in the associations
209
+ arguments: # a list of argument definitions to override the default arguments, if using your own arguments you will need to override the query resolver to act on those arguments, the default arguments exposed on the query are:
210
+
211
+ default_arguments =
212
+ [{:name=>:explain, :type=>GraphQL::BOOLEAN_TYPE, :default=>nil}, # handled by the default resolver, outputs the top level sql for the operation
213
+ {:name=>:id, :type=>GraphQL::INT_TYPE, :default=>nil}, # allows input of an id for top level record selection for the model
214
+ {:name=>:ids, :type=>GraphQL::INT_TYPE.to_list_type, :default=>nil}, # allows input of an array of ids for top level records selection for the model
215
+ {:name=>:limit, :type=>GraphQL::INT_TYPE, :default=>50}, # limits the number of records retuurned (defaults to 50 records)
216
+ {:name=>:offset, :type=>GraphQL::INT_TYPE, :default=>nil}, # specifies an offset for the start of the records returned
217
+ {:name=>:order, :type=>GraphQL::STRING_TYPE, :default=>nil}, # a string value that is passed to ActiveRecord query specifying the output order
218
+ {:name=>:where, :type=>GraphQL::STRING_TYPE.to_list_type, :default=>nil}] # a string array for use in ActiveRecord query, can be a string or a query/value array to be used by the query ["model.id =? and model.date is not nul]", "1"]
219
+
220
+ ## graphql_delete
221
+ description:
222
+ scope_methods:
223
+ arguments:
224
+ resolver:
225
+
226
+ ## graphql_update
227
+
228
+ description:
229
+ resolver:
230
+
231
+ ## graphql_create
232
+
233
+ description:
234
+ resolver:
235
+
236
+
237
+ ## Optional Authorization
238
+
239
+ The schema has the capability to use the cancancan gem to enable authorized access to the query and mutation fields based on the models, if implemented it also will control the availability of the associations assigned to the model based on their underlying model authorization. This is an optional setup and is not required.
240
+
241
+ gem "cancancan", "~> 1.10"
242
+
243
+ Follow the setup for cancancan and create an app/model/ability.rb file to setup your access rights
244
+
245
+ class Ability
246
+ include CanCan::Ability
247
+
248
+ def initialize(user)
249
+ # Define abilities for the passed in user here. For example:
250
+ #
251
+ # user ||= User.new # guest user (not logged in)
252
+ # if user.admin?
253
+ # can :manage, :all
254
+ # else
255
+ # can :read, :all
256
+ # end
257
+ #
258
+ # The first argument to `can` is the action you are giving the user
259
+ # permission to do.
260
+ # If you pass :manage it will apply to every action. Other common actions
261
+ # here are :read, :create, :update and :destroy.
262
+ #
263
+ # The second argument is the resource the user can perform the action on.
264
+ # If you pass :all it will apply to every resource. Otherwise pass a Ruby
265
+ # class of the resource.
266
+ #
267
+ # The third argument is an optional hash of conditions to further filter the
268
+ # objects.
269
+ # For example, here the user can only update published articles.
270
+ #
271
+ # can :update, Article, :published => true
272
+ #
273
+ # See the wiki for details:
274
+ # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
275
+
276
+
277
+ user ||= User.new # guest user (not logged in)
278
+ if user.is_admin?
279
+ can :manage, :all
280
+ else
281
+ can :manage, [YourModelA] # this will allow access to :query, :create, :update, :delete GraphQL methods for defined models
282
+ can :read, [YourModelB] # this will allow access to :query GraphQL methods for defined models as well as allow read access to associations of that type
283
+ can :create, [YourModelC] # this will allow access to :create GraphQL methods for defined models
284
+ can :update, [YourModelD] # this will allow access to :update GraphQL methods for defined models
285
+ can :delete, [YourModelE] # this will allow access to :delete GraphQL methods for defined models
286
+
287
+ end
288
+
289
+ end
290
+ end
291
+
292
+
293
+ GraphqlModelMapper requires an optional ability method on your current_user in order to check the context current_users authorization to access a GraphQL objects model implementation.
294
+
295
+ class User < ActiveRecord::Base
296
+ def ability
297
+ @ability ||= Ability.new(self)
298
+ end
299
+
300
+ ...
301
+ end
302
+
303
+ ## Schema implementation
304
+
305
+ Once you have your models decorated with the graphql_query/graphql_update/graphql_create/graphql_delete attributes the next step is implementing your schema and adding it to your controller. For this example I am using a schema definition located at app/graphql/graphql_model_mapper_schema.rb. I have used https://github.com/exAspArk/graphql-errors to handle errors generated from the resolve methods. It is not required but it provides an easy way to setup error handling.
306
+
307
+ #app/graphql/graphql_model_mapper_schema.rb
308
+ require 'graphql_model_mapper'
309
+
310
+ # these are options that can be passed to the schema initiation to enable query logging or for authorization setup
311
+ # nesting_strategy can be :flat, :shallow or :deep
312
+ # type_case can be :camelize, :underscore or :classify
313
+ # the default values are shown below
314
+ options = {:log_query_depth=>false, :log_query_complexity=>false, :use_backtrace=>false, :use_authorize=>false, :nesting_strategy=>:shallow, :type_case=>:camelize}
315
+ GraphqlModelMapperSchema = GraphqlModelMapper.Schema(use_authorize: true)
316
+ GraphQL::Errors.configure(GraphqlModelMapperSchema) do
317
+
318
+ rescue_from ActiveRecord::StatementInvalid do |exception|
319
+ GraphQL::ExecutionError.new(exception.message)
320
+ end
321
+
322
+ rescue_from ActiveRecord::RecordNotFound do |exception|
323
+ GraphQL::ExecutionError.new(exception.message)
324
+ end
325
+
326
+
327
+ rescue_from ActiveRecord::RecordInvalid do |exception|
328
+ GraphQL::ExecutionError.new(exception.message)
329
+ end
330
+
331
+ rescue_from StandardError do |exception|
332
+ GraphQL::ExecutionError.new(exception.message)
333
+ end
334
+ end
335
+
336
+ ## Graphiql controller setup
337
+
338
+ I recommend that you install
339
+
340
+ gem "graphiql-rails"
341
+
342
+ so you may access and test your GraphQL queries. It is located at https://github.com/rmosolgo/graphiql-rails. Once you have graphiql-rails you can setup the route
343
+
344
+ #config/routes.rb
345
+ [YourApp]::Application.routes.draw do
346
+ if Rails.env.development? || Rails.env.staging? # you can restrict access to graphiql to specific environments here
347
+ mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
348
+ end
349
+
350
+ post "/graphql", to: "graphql#execute"
351
+
352
+ ....
353
+ end
354
+
355
+ you can then reference your previously assigned schema in app/controllers/graphql_contoller.rb
356
+
357
+ #app/controllers/graphql_controller
358
+ class GraphqlController < ApplicationController
359
+ def execute
360
+ variables = ensure_hash(params[:variables])
361
+ query = params[:query]
362
+ operation_name = params[:operationName]
363
+ context = {
364
+ # Query context goes here, for example:
365
+ current_user: current_user
366
+ }
367
+
368
+ begin
369
+ if (logged_in?)# && current_user.is_admin?)
370
+ Ability.new(current_user) if GraphqlModelMapper.use_authorize # set on GraphqlModelMapper.Schema initialization
371
+ elsif Rails.env != "development"
372
+ query = nil
373
+ end
374
+ result = GraphqlModelMapperSchema.execute(query, variables: variables, context: context, operation_name: operation_name, except: ExceptFilter)
375
+
376
+ end
377
+ render json: result
378
+ end
379
+
380
+ private
381
+ # this class is exercised when use_authorize is true
382
+ class ExceptFilter
383
+ def self.call(schema_member, context)
384
+ return false unless GraphqlModelMapper.use_authorize
385
+ # true if field should be excluded, false if it should be included
386
+ return false unless authorized_proc = schema_member.metadata[:authorized_proc]
387
+ model_name = schema_member.metadata[:model_name]
388
+ access_type = schema_member.metadata[:access_type]
389
+ !authorized_proc.call(context, model_name, access_type)
390
+ end
391
+ end
392
+
393
+ def ensure_hash(query_variables)
394
+ if query_variables.blank?
395
+ {}
396
+ elsif query_variables.is_a?(String)
397
+ JSON.parse(query_variables)
398
+ else
399
+ query_variables
400
+ end
401
+ end
402
+ end
403
+
404
+ ## Development
405
+
406
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
407
+
408
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
409
+
410
+ ## Contributing
411
+
412
+ Bug reports and pull requests are welcome on GitHub at https://github.com/geneeblack/graphql_model_mapper.
413
+
414
+ ## License
415
+
416
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "graphql_model_mapper"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,37 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "graphql_model_mapper/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "graphql_model_mapper"
8
+ spec.version = GraphqlModelMapper::VERSION
9
+ spec.authors = ["Gene Black"]
10
+ spec.email = ["geblack@hotmail.com"]
11
+
12
+ spec.summary = %q{Adds GraphQL object generation based on your ActiveRecord models.}
13
+ spec.description = %q{This gem extends ActiveRecord::Base to add automatic generation of GraphQL objects based on your models.}
14
+ spec.homepage = "https://github.com/geneblack/graphql_model_mapper"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "graphql", "~> 1.7.5"
34
+ spec.add_development_dependency "bundler", "~> 1.16"
35
+ spec.add_development_dependency "rake", "~> 10.0"
36
+ spec.add_development_dependency "minitest", "~> 5.0"
37
+ end