graphiti-rails 0.2.0

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.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +10 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +72 -0
  5. data/Rakefile +20 -0
  6. data/lib/generators/graphiti/api_test_generator.rb +70 -0
  7. data/lib/generators/graphiti/generator_mixin.rb +45 -0
  8. data/lib/generators/graphiti/install_generator.rb +80 -0
  9. data/lib/generators/graphiti/resource_generator.rb +180 -0
  10. data/lib/generators/graphiti/resource_test_generator.rb +56 -0
  11. data/lib/generators/graphiti/templates/application_resource.rb.erb +15 -0
  12. data/lib/generators/graphiti/templates/controller.rb.erb +61 -0
  13. data/lib/generators/graphiti/templates/create_request_spec.rb.erb +35 -0
  14. data/lib/generators/graphiti/templates/destroy_request_spec.rb.erb +22 -0
  15. data/lib/generators/graphiti/templates/index_request_spec.rb.erb +22 -0
  16. data/lib/generators/graphiti/templates/resource.rb.erb +11 -0
  17. data/lib/generators/graphiti/templates/resource_reads_spec.rb.erb +78 -0
  18. data/lib/generators/graphiti/templates/resource_writes_spec.rb.erb +67 -0
  19. data/lib/generators/graphiti/templates/show_request_spec.rb.erb +21 -0
  20. data/lib/generators/graphiti/templates/update_request_spec.rb.erb +32 -0
  21. data/lib/graphiti-rails.rb +4 -0
  22. data/lib/graphiti/rails.rb +60 -0
  23. data/lib/graphiti/rails/context.rb +33 -0
  24. data/lib/graphiti/rails/debugging.rb +18 -0
  25. data/lib/graphiti/rails/exception_handlers.rb +83 -0
  26. data/lib/graphiti/rails/graphiti_errors_testing.rb +20 -0
  27. data/lib/graphiti/rails/railtie.rb +143 -0
  28. data/lib/graphiti/rails/responders.rb +21 -0
  29. data/lib/graphiti/rails/test_helpers.rb +7 -0
  30. data/lib/graphiti/rails/version.rb +7 -0
  31. data/lib/tasks/graphiti.rake +53 -0
  32. metadata +245 -0
@@ -0,0 +1,33 @@
1
+ module Graphiti
2
+ module Rails
3
+ # Wraps controller actions in a [Graphiti Context](https://www.graphiti.dev/guides/concepts/resources#context) which points to the
4
+ # controller instance by default.
5
+ module Context
6
+ def self.included(klass)
7
+ klass.class_eval do
8
+ include Graphiti::Context
9
+ around_action :wrap_graphiti_context
10
+ end
11
+ end
12
+
13
+ # Called by [`#around_action`](https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-around_action)
14
+ # to wrap the current action in a Graphiti context defined by {#graphiti_context}.
15
+ def wrap_graphiti_context
16
+ Graphiti.with_context(graphiti_context, action_name.to_sym) do
17
+ yield
18
+ end
19
+ end
20
+
21
+ # The context to use for Graphiti Resources. Defaults to the controller instance.
22
+ # Can be redefined for different behavior.
23
+ def graphiti_context
24
+ if respond_to?(:jsonapi_context)
25
+ DEPRECATOR.deprecation_warning("Overriding jsonapi_context", "Override #graphiti_context instead")
26
+ jsonapi_context
27
+ else
28
+ self
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ module Graphiti
2
+ module Rails
3
+ # Wraps controller actions in a [Graphiti Debugger](https://www.graphiti.dev/guides/concepts/debugging#debugger).
4
+ module Debugging
5
+ def self.included(klass)
6
+ klass.around_action :debug_graphiti
7
+ end
8
+
9
+ # Called by [`#around_action`](https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-around_action)
10
+ # to wrap the current action in a Graphiti Debugger.
11
+ def debug_graphiti
12
+ Debugger.debug do
13
+ yield
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,83 @@
1
+ module Graphiti
2
+ module Rails
3
+ class ExceptionHandler < RescueRegistry::ExceptionHandler
4
+ # We've actually changed the signature here which is somewhat risky...
5
+ def build_payload(show_details: false, traces: nil, style: :rails)
6
+ case style
7
+ when :standard
8
+ super(show_details: show_details, traces: traces)
9
+ when :rails
10
+ # TODO: Find way to not duplicate RailsExceptionHandler
11
+ body = {
12
+ status: status_code,
13
+ error: title
14
+ }
15
+
16
+ if show_details
17
+ body[:exception] = exception.inspect
18
+ if traces
19
+ body[:traces] = traces
20
+ end
21
+ end
22
+
23
+ body
24
+ else
25
+ raise ArgumentError, "unknown style #{style}"
26
+ end
27
+ end
28
+
29
+ def formatted_response(content_type, **options)
30
+ # We're relying on the fact that `formatted_response` passes through unknown options to `build_payload`
31
+ if Graphiti::Rails.handled_exception_formats.include?(content_type.to_sym)
32
+ options[:style] = :standard
33
+ end
34
+ super
35
+ end
36
+ end
37
+
38
+ class FallbackHandler < ExceptionHandler
39
+ def formatted_response(content_type, **options)
40
+ if Graphiti::Rails.handled_exception_formats.include?(content_type.to_sym)
41
+ super
42
+ else
43
+ # The nil response will cause the default Rails handler to be used
44
+ nil
45
+ end
46
+ end
47
+ end
48
+
49
+ class InvalidRequestHandler < ExceptionHandler
50
+ # Mostly copied from GraphitiErrors could use some cleanup
51
+ # NOTE: That `style` is ignored
52
+ def build_payload(show_details: false, traces: nil, style: nil)
53
+ errors = exception.errors
54
+
55
+ errors_payload = []
56
+ errors.details.each_pair do |attribute, att_errors|
57
+ att_errors.each_with_index do |error, idx|
58
+ code = error[:error]
59
+ message = errors.messages[attribute][idx]
60
+
61
+ errors_payload << {
62
+ code: "bad_request",
63
+ status: "400",
64
+ title: "Request Error",
65
+ detail: errors.full_message(attribute, message),
66
+ source: {
67
+ pointer: attribute.to_s.tr(".", "/").gsub(/\[(\d+)\]/, '/\1'),
68
+ },
69
+ meta: {
70
+ attribute: attribute,
71
+ message: message,
72
+ code: code,
73
+ },
74
+ }
75
+ end
76
+ end
77
+
78
+ { errors: errors_payload }
79
+ end
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,20 @@
1
+ module Graphiti
2
+ module Rails
3
+ module GraphitiErrorsTesting
4
+ include RescueRegistry::RailsTestHelpers
5
+
6
+ def enable!
7
+ DEPRECATOR.deprecation_warning("GraphitiError.enable! in tests", "This method may cause leaked behavior between tests! Wrap in Graphiti::Rails::TestHelpers#handle_request_exceptions instead.")
8
+ super
9
+ handle_request_exceptions(true)
10
+ end
11
+
12
+ def disable!
13
+ DEPRECATOR.deprecation_warning("GraphitiError.disable! in tests", "This method may cause leaked behavior between tests! Wrap in Graphiti::Rails::TestHelpers#handle_request_exceptions instead. Note that exceptions are no longer caught by default during testing.")
14
+ handle_request_exceptions(false)
15
+ ensure
16
+ super
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Graphiti
4
+ module Rails
5
+ # This Railtie exposes some configuration options:
6
+ # * `config.graphiti.handled_exception_formats`, defaulting to `[:jsonapi]`.
7
+ # Formats in this list will always have their exceptions handled by Graphiti.
8
+ # * `config.graphiti.respond_to_formats`, defaulting to `[:json, :jsonapi, :xml]`.
9
+ # When {Graphiti::Rails::Responders} is included in a controller it will respond
10
+ # to these mime types by default.
11
+ class Railtie < ::Rails::Railtie
12
+ config.graphiti = ActiveSupport::OrderedOptions.new
13
+
14
+ config.graphiti.handled_exception_formats = [:jsonapi]
15
+
16
+ old_respond_to_formats = Graphiti::DEPRECATOR.silence { Graphiti.config.try(:respond_to) }
17
+ config.graphiti.respond_to_formats = old_respond_to_formats || [:json, :jsonapi, :xml]
18
+
19
+ rake_tasks do
20
+ load File.expand_path("../../tasks/graphiti.rake", __dir__)
21
+ end
22
+
23
+ initializer "graphiti-rails.config" do |app|
24
+ Graphiti::Rails.handled_exception_formats = app.config.graphiti.handled_exception_formats
25
+ Graphiti::Rails.respond_to_formats = app.config.graphiti.respond_to_formats
26
+
27
+ root = ::Rails.root
28
+
29
+ config_file = root.join(".graphiticfg.yml")
30
+ if config_file.exist?
31
+ cfg = YAML.load_file(config_file)
32
+ Graphiti.config.schema_path = root.join("public#{cfg["namespace"]}/schema.json")
33
+ else
34
+ Graphiti.config.schema_path = root.join("public/schema.json")
35
+ end
36
+ end
37
+
38
+ initializer "graphti-rails.logger" do
39
+ config.after_initialize do
40
+ Graphiti.config.debug = ::Rails.logger.level.zero?
41
+ Graphiti.logger = ::Rails.logger
42
+ end
43
+ end
44
+
45
+ initializer "graphiti-rails.init" do
46
+ if ::Rails.application.config.eager_load
47
+ config.after_initialize do |app|
48
+ ::Rails.application.reload_routes!
49
+ Graphiti.setup!
50
+ end
51
+ end
52
+
53
+ register_mime_type
54
+ register_parameter_parser
55
+ register_renderers
56
+ establish_concurrency
57
+ configure_endpoint_lookup
58
+ end
59
+
60
+ # from jsonapi-rails
61
+ MEDIA_TYPE = 'application/vnd.api+json'.freeze
62
+
63
+ PARSER = lambda do |body|
64
+ data = JSON.parse(body)
65
+ data[:format] = :jsonapi
66
+ data.with_indifferent_access
67
+ end
68
+
69
+ def register_mime_type
70
+ Mime::Type.register(MEDIA_TYPE, :jsonapi)
71
+ end
72
+
73
+ def register_parameter_parser
74
+ if ::Rails::VERSION::MAJOR >= 5
75
+ ActionDispatch::Request.parameter_parsers[:jsonapi] = PARSER
76
+ else
77
+ ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime[:jsonapi]] = PARSER
78
+ end
79
+ end
80
+
81
+ def register_renderers
82
+ ActiveSupport.on_load(:action_controller) do
83
+ ::ActionController::Renderers.add(:jsonapi) do |proxy, options|
84
+ self.content_type ||= Mime[:jsonapi]
85
+
86
+ # opts = {}
87
+ # if respond_to?(:default_jsonapi_render_options)
88
+ # opts = default_jsonapi_render_options
89
+ # end
90
+
91
+ if proxy.is_a?(Hash) # for destroy
92
+ render(options.merge(json: proxy))
93
+ else
94
+ proxy.to_jsonapi(options)
95
+ end
96
+ end
97
+ end
98
+
99
+ ActiveSupport.on_load(:action_controller) do
100
+ ActionController::Renderers.add(:jsonapi_errors) do |proxy, options|
101
+ self.content_type ||= Mime[:jsonapi]
102
+
103
+ validation = GraphitiErrors::Validation::Serializer.new \
104
+ proxy.data, proxy.payload.relationships
105
+
106
+ render \
107
+ json: {errors: validation.errors},
108
+ status: :unprocessable_entity
109
+ end
110
+ end
111
+ end
112
+
113
+ # Only run concurrently if our environment supports it
114
+ def establish_concurrency
115
+ Graphiti.config.concurrency = !::Rails.env.test? &&
116
+ ::Rails.application.config.cache_classes
117
+ end
118
+
119
+ def configure_endpoint_lookup
120
+ Graphiti.config.context_for_endpoint = ->(path, action) {
121
+ method = :GET
122
+ case action
123
+ when :show then path = "#{path}/1"
124
+ when :create then method = :POST
125
+ when :update
126
+ path = "#{path}/1"
127
+ method = :PUT
128
+ when :destroy
129
+ path = "#{path}/1"
130
+ method = :DELETE
131
+ end
132
+
133
+ route = begin
134
+ ::Rails.application.routes.recognize_path(path, method: method)
135
+ rescue
136
+ nil
137
+ end
138
+ "#{route[:controller]}_controller".classify.safe_constantize if route
139
+ }
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,21 @@
1
+ # For use with the `responders` gem responders gem to get respond_with
2
+ module Graphiti
3
+ module Rails
4
+ module Responders
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include ActionController::MimeResponds
9
+ respond_to(*Graphiti::Rails.respond_to_formats)
10
+ end
11
+
12
+ # Override to avoid location url generation (for now)
13
+ def respond_with(*args, &blk)
14
+ opts = args.extract_options!
15
+ opts[:location] = nil
16
+ args << opts
17
+ super(*args, &blk)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ module Graphiti
2
+ module Rails
3
+ module TestHelpers
4
+ include RescueRegistry::RailsTestHelpers
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Graphiti
4
+ module Rails
5
+ VERSION = '0.2.0'
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ namespace :graphiti do
2
+ include RescueRegistry::RailsTestHelpers
3
+
4
+ def session
5
+ @session ||= ActionDispatch::Integration::Session.new(Rails.application)
6
+ end
7
+
8
+ def setup_rails!
9
+ Rails.application.eager_load!
10
+ Rails.application.config.cache_classes = true
11
+ Rails.application.config.action_controller.perform_caching = false
12
+ end
13
+
14
+ def make_request(path, debug = false)
15
+ if path.split("/").length == 2
16
+ path = "#{ApplicationResource.endpoint_namespace}#{path}"
17
+ end
18
+ path << if path.include?("?")
19
+ "&cache=bust"
20
+ else
21
+ "?cache=bust"
22
+ end
23
+ path = "#{path}&debug=true" if debug
24
+ handle_request_exceptions do
25
+ session.get(path.to_s)
26
+ end
27
+ JSON.parse(session.response.body)
28
+ end
29
+
30
+ desc "Execute request without web server."
31
+ task :request, [:path, :debug] => [:environment] do |_, args|
32
+ setup_rails!
33
+ Graphiti.logger = Graphiti.stdout_logger
34
+ Graphiti::Debugger.preserve = true
35
+ require "pp"
36
+ path, debug = args[:path], args[:debug]
37
+ puts "Graphiti Request: #{path}"
38
+ json = make_request(path, debug)
39
+ pp json
40
+ Graphiti::Debugger.flush if debug
41
+ end
42
+
43
+ desc "Execute benchmark without web server."
44
+ task :benchmark, [:path, :requests] => [:environment] do |_, args|
45
+ setup_rails!
46
+ took = Benchmark.ms {
47
+ args[:requests].to_i.times do
48
+ make_request(args[:path])
49
+ end
50
+ }
51
+ puts "Took: #{(took / args[:requests].to_f).round(2)}ms"
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,245 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: graphiti-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Wagenet
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-05-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphiti
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rescue_registry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: graphiti_spec_helpers
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: kaminari
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: factory_bot
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: responders
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: kramdown-parser-gfm
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rouge
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ description:
182
+ email:
183
+ - peter.wagenet@gmail.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - CHANGELOG.md
189
+ - MIT-LICENSE
190
+ - README.md
191
+ - Rakefile
192
+ - lib/generators/graphiti/api_test_generator.rb
193
+ - lib/generators/graphiti/generator_mixin.rb
194
+ - lib/generators/graphiti/install_generator.rb
195
+ - lib/generators/graphiti/resource_generator.rb
196
+ - lib/generators/graphiti/resource_test_generator.rb
197
+ - lib/generators/graphiti/templates/application_resource.rb.erb
198
+ - lib/generators/graphiti/templates/controller.rb.erb
199
+ - lib/generators/graphiti/templates/create_request_spec.rb.erb
200
+ - lib/generators/graphiti/templates/destroy_request_spec.rb.erb
201
+ - lib/generators/graphiti/templates/index_request_spec.rb.erb
202
+ - lib/generators/graphiti/templates/resource.rb.erb
203
+ - lib/generators/graphiti/templates/resource_reads_spec.rb.erb
204
+ - lib/generators/graphiti/templates/resource_writes_spec.rb.erb
205
+ - lib/generators/graphiti/templates/show_request_spec.rb.erb
206
+ - lib/generators/graphiti/templates/update_request_spec.rb.erb
207
+ - lib/graphiti-rails.rb
208
+ - lib/graphiti/rails.rb
209
+ - lib/graphiti/rails/context.rb
210
+ - lib/graphiti/rails/debugging.rb
211
+ - lib/graphiti/rails/exception_handlers.rb
212
+ - lib/graphiti/rails/graphiti_errors_testing.rb
213
+ - lib/graphiti/rails/railtie.rb
214
+ - lib/graphiti/rails/responders.rb
215
+ - lib/graphiti/rails/test_helpers.rb
216
+ - lib/graphiti/rails/version.rb
217
+ - lib/tasks/graphiti.rake
218
+ homepage: https://www.graphiti.dev
219
+ licenses:
220
+ - MIT
221
+ metadata:
222
+ bug_tracker_uri: https://github.com/graphiti-api/graphiti-rails/issues
223
+ changelog_uri: https://github.com/graphiti-api/graphiti-rails/CHANGELOG.md
224
+ source_code_uri: https://github.com/graphiti-api/graphiti-rails
225
+ post_install_message:
226
+ rdoc_options: []
227
+ require_paths:
228
+ - lib
229
+ required_ruby_version: !ruby/object:Gem::Requirement
230
+ requirements:
231
+ - - ">="
232
+ - !ruby/object:Gem::Version
233
+ version: '0'
234
+ required_rubygems_version: !ruby/object:Gem::Requirement
235
+ requirements:
236
+ - - ">="
237
+ - !ruby/object:Gem::Version
238
+ version: '0'
239
+ requirements: []
240
+ rubyforge_project:
241
+ rubygems_version: 2.7.6
242
+ signing_key:
243
+ specification_version: 4
244
+ summary: Rails integration for Graphiti
245
+ test_files: []