graphiti-rb 1.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +20 -0
- data/.yardopts +2 -0
- data/Appraisals +11 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +12 -0
- data/Guardfile +32 -0
- data/LICENSE.txt +21 -0
- data/README.md +75 -0
- data/Rakefile +15 -0
- data/bin/appraisal +17 -0
- data/bin/console +14 -0
- data/bin/rspec +17 -0
- data/bin/setup +8 -0
- data/gemfiles/rails_4.gemfile +17 -0
- data/gemfiles/rails_5.gemfile +17 -0
- data/graphiti.gemspec +34 -0
- data/lib/generators/jsonapi/resource_generator.rb +169 -0
- data/lib/generators/jsonapi/templates/application_resource.rb.erb +15 -0
- data/lib/generators/jsonapi/templates/controller.rb.erb +61 -0
- data/lib/generators/jsonapi/templates/create_request_spec.rb.erb +30 -0
- data/lib/generators/jsonapi/templates/destroy_request_spec.rb.erb +20 -0
- data/lib/generators/jsonapi/templates/index_request_spec.rb.erb +22 -0
- data/lib/generators/jsonapi/templates/resource.rb.erb +11 -0
- data/lib/generators/jsonapi/templates/resource_reads_spec.rb.erb +62 -0
- data/lib/generators/jsonapi/templates/resource_writes_spec.rb.erb +63 -0
- data/lib/generators/jsonapi/templates/show_request_spec.rb.erb +21 -0
- data/lib/generators/jsonapi/templates/update_request_spec.rb.erb +34 -0
- data/lib/graphiti-rb.rb +1 -0
- data/lib/graphiti.rb +121 -0
- data/lib/graphiti/adapters/abstract.rb +516 -0
- data/lib/graphiti/adapters/active_record.rb +6 -0
- data/lib/graphiti/adapters/active_record/base.rb +249 -0
- data/lib/graphiti/adapters/active_record/belongs_to_sideload.rb +17 -0
- data/lib/graphiti/adapters/active_record/has_many_sideload.rb +17 -0
- data/lib/graphiti/adapters/active_record/has_one_sideload.rb +17 -0
- data/lib/graphiti/adapters/active_record/inferrence.rb +12 -0
- data/lib/graphiti/adapters/active_record/many_to_many_sideload.rb +30 -0
- data/lib/graphiti/adapters/null.rb +236 -0
- data/lib/graphiti/base.rb +70 -0
- data/lib/graphiti/configuration.rb +21 -0
- data/lib/graphiti/context.rb +16 -0
- data/lib/graphiti/deserializer.rb +208 -0
- data/lib/graphiti/errors.rb +309 -0
- data/lib/graphiti/extensions/boolean_attribute.rb +33 -0
- data/lib/graphiti/extensions/extra_attribute.rb +70 -0
- data/lib/graphiti/extensions/temp_id.rb +26 -0
- data/lib/graphiti/filter_operators.rb +25 -0
- data/lib/graphiti/hash_renderer.rb +57 -0
- data/lib/graphiti/jsonapi_serializable_ext.rb +50 -0
- data/lib/graphiti/query.rb +251 -0
- data/lib/graphiti/rails.rb +28 -0
- data/lib/graphiti/railtie.rb +74 -0
- data/lib/graphiti/renderer.rb +60 -0
- data/lib/graphiti/resource.rb +110 -0
- data/lib/graphiti/resource/configuration.rb +239 -0
- data/lib/graphiti/resource/dsl.rb +138 -0
- data/lib/graphiti/resource/interface.rb +32 -0
- data/lib/graphiti/resource/polymorphism.rb +68 -0
- data/lib/graphiti/resource/sideloading.rb +102 -0
- data/lib/graphiti/resource_proxy.rb +127 -0
- data/lib/graphiti/responders.rb +19 -0
- data/lib/graphiti/runner.rb +25 -0
- data/lib/graphiti/scope.rb +98 -0
- data/lib/graphiti/scoping/base.rb +99 -0
- data/lib/graphiti/scoping/default_filter.rb +58 -0
- data/lib/graphiti/scoping/extra_attributes.rb +29 -0
- data/lib/graphiti/scoping/filter.rb +93 -0
- data/lib/graphiti/scoping/filterable.rb +36 -0
- data/lib/graphiti/scoping/paginate.rb +87 -0
- data/lib/graphiti/scoping/sort.rb +64 -0
- data/lib/graphiti/sideload.rb +281 -0
- data/lib/graphiti/sideload/belongs_to.rb +34 -0
- data/lib/graphiti/sideload/has_many.rb +16 -0
- data/lib/graphiti/sideload/has_one.rb +9 -0
- data/lib/graphiti/sideload/many_to_many.rb +24 -0
- data/lib/graphiti/sideload/polymorphic_belongs_to.rb +108 -0
- data/lib/graphiti/stats/dsl.rb +89 -0
- data/lib/graphiti/stats/payload.rb +49 -0
- data/lib/graphiti/types.rb +172 -0
- data/lib/graphiti/util/attribute_check.rb +88 -0
- data/lib/graphiti/util/field_params.rb +16 -0
- data/lib/graphiti/util/hash.rb +51 -0
- data/lib/graphiti/util/hooks.rb +33 -0
- data/lib/graphiti/util/include_params.rb +39 -0
- data/lib/graphiti/util/persistence.rb +219 -0
- data/lib/graphiti/util/relationship_payload.rb +64 -0
- data/lib/graphiti/util/serializer_attributes.rb +97 -0
- data/lib/graphiti/util/sideload.rb +33 -0
- data/lib/graphiti/util/validation_response.rb +78 -0
- data/lib/graphiti/version.rb +3 -0
- metadata +317 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 44d6ed1a70a645555aa14f12ec2da127e17ba5cd
|
4
|
+
data.tar.gz: 02681454df9a553eda4285623493c55dcecca72c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1bdec95482b5cd25c1ea41175d14b77be860f6b7c2a758bddf9f2eeb65939205834f096ebd313c932026172e40cf8110c5c2d0ae4467b08e4197b2c1060b1c04
|
7
|
+
data.tar.gz: 5b406ea40631a1a2e1890868a0826ef90b18543e8d7a47ab8ebcd9fc49e346f456950fdc6e2ab423f2658c79ca3508f87ec0c3056fe0dcc5075afa946fcfb5b9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.0
|
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
sudo: false
|
2
|
+
language: ruby
|
3
|
+
rvm:
|
4
|
+
- 2.3.3
|
5
|
+
|
6
|
+
script: "bundle exec rake"
|
7
|
+
|
8
|
+
install: bundle install --retry=3 --jobs=3
|
9
|
+
|
10
|
+
gemfile:
|
11
|
+
- gemfiles/rails_4.gemfile
|
12
|
+
- gemfiles/rails_5.gemfile
|
13
|
+
|
14
|
+
deploy:
|
15
|
+
provider: rubygems
|
16
|
+
api_key: $RUBYGEMS_API_KEY
|
17
|
+
gem: graphiti-rb
|
18
|
+
on:
|
19
|
+
tags: true
|
20
|
+
repo: jsonapi-suite/jsonapi_compliable
|
data/.yardopts
ADDED
data/Appraisals
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
appraise "rails-4" do
|
2
|
+
gem "rails", "~> 4.1"
|
3
|
+
gem 'jsonapi-rails', '~> 0.3.1', require: 'jsonapi/rails'
|
4
|
+
gem 'rspec-rails'
|
5
|
+
end
|
6
|
+
|
7
|
+
appraise "rails-5" do
|
8
|
+
gem "rails", "~> 5.2"
|
9
|
+
gem 'jsonapi-rails', '~> 0.3.1', require: 'jsonapi/rails'
|
10
|
+
gem 'rspec-rails'
|
11
|
+
end
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at spasupuleti4@bloomberg.net. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
guard :rspec, cmd: "bundle exec rspec --color --format documentation" do
|
2
|
+
require "guard/rspec/dsl"
|
3
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
4
|
+
watch(%r{^spec/(.*)\/?(.*)_spec\.rb$})
|
5
|
+
|
6
|
+
# Feel free to open issues for suggestions and improvements
|
7
|
+
|
8
|
+
# RSpec files
|
9
|
+
rspec = dsl.rspec
|
10
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
11
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
12
|
+
watch(rspec.spec_files)
|
13
|
+
|
14
|
+
# Ruby files
|
15
|
+
ruby = dsl.ruby
|
16
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
17
|
+
|
18
|
+
# Rails files
|
19
|
+
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
20
|
+
|
21
|
+
watch(rails.controllers) do |m|
|
22
|
+
[
|
23
|
+
rspec.spec.call("controllers/#{m[1]}_controller"),
|
24
|
+
rspec.spec.call("api/#{m[1]}")
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Rails config changes
|
29
|
+
watch(rails.spec_helper) { rspec.spec_dir }
|
30
|
+
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
31
|
+
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
32
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Venkata Pasupuleti
|
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,75 @@
|
|
1
|
+
### Graphiti
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/jsonapi-suite/jsonapi_compliable.svg?branch=master)](https://travis-ci.org/jsonapi-suite/jsonapi_compliable)
|
4
|
+
|
5
|
+
[JSONAPI Suite Website](https://jsonapi-suite.github.io/jsonapi_suite)
|
6
|
+
|
7
|
+
[Documentation](https://jsonapi-suite.github.io/jsonapi_compliable)
|
8
|
+
|
9
|
+
Supported Rails versions: >= 4.1
|
10
|
+
|
11
|
+
### Upgrading to 0.11.x
|
12
|
+
|
13
|
+
Due to a backwards-incompatibility introduced in the underlying
|
14
|
+
[jsonapi-rb](http://jsonapi-rb.org) gem, specifying custom serializers
|
15
|
+
now works slightly differently.
|
16
|
+
|
17
|
+
Before:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# app/serializers/serializable_post.rb
|
21
|
+
|
22
|
+
has_many :comments, class: SerializableSpecialComment
|
23
|
+
```
|
24
|
+
|
25
|
+
and/or
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
render_jsonapi(post, class: SerializableSpecialPost)
|
29
|
+
```
|
30
|
+
|
31
|
+
This is now all handled at the controller level:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
render_jsonapi(post, class: {
|
35
|
+
Post: SerializableSpecialPost,
|
36
|
+
Comment: SerializableSpecialComment
|
37
|
+
})
|
38
|
+
```
|
39
|
+
|
40
|
+
### Upgrading to 0.10
|
41
|
+
|
42
|
+
`sideload_whitelist` has been moved from the resource to the controller:
|
43
|
+
|
44
|
+
```diff
|
45
|
+
class PostsController < ApplicationController
|
46
|
+
jsonapi resource: PostResource do
|
47
|
+
- sideload_whitelist({ index: [:foo] })
|
48
|
+
- end
|
49
|
+
+ sideload_whitelist({ index: [:foo] })
|
50
|
+
end
|
51
|
+
|
52
|
+
# NEW
|
53
|
+
```
|
54
|
+
|
55
|
+
### Running tests
|
56
|
+
|
57
|
+
We support Rails >= 4.1. To do so, we use the [appraisal](https://github.com/thoughtbot/appraisal) gem. So, run:
|
58
|
+
|
59
|
+
```bash
|
60
|
+
$ bin/appraisal rails-4 bin/rspec
|
61
|
+
$ bin/appraisal rails-5 bin/rspec
|
62
|
+
```
|
63
|
+
|
64
|
+
Or run tests for all versions:
|
65
|
+
|
66
|
+
```bash
|
67
|
+
$ bin/appraisal bin/rspec
|
68
|
+
```
|
69
|
+
|
70
|
+
### Generating the Documentation
|
71
|
+
|
72
|
+
```bash
|
73
|
+
$ yard doc
|
74
|
+
$ yard server
|
75
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "appraisal"
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
6
|
+
if ENV["APPRAISAL_INITIALIZED"]
|
7
|
+
t.pattern = 'spec/integration/rails'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
12
|
+
task :default => [:spec, :appraisal]
|
13
|
+
else
|
14
|
+
task :default => [:spec]
|
15
|
+
end
|
data/bin/appraisal
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'appraisal' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("appraisal", "appraisal")
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "graphiti-rb"
|
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
|
data/bin/rspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# This file was generated by Bundler.
|
5
|
+
#
|
6
|
+
# The application 'rspec' is installed as part of a gem, and
|
7
|
+
# this file is here to facilitate running it.
|
8
|
+
#
|
9
|
+
|
10
|
+
require "pathname"
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
12
|
+
Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "bundler/setup"
|
16
|
+
|
17
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/setup
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "rails", "~> 4.1"
|
6
|
+
gem "jsonapi-rails", "~> 0.3.1", :require => "jsonapi/rails"
|
7
|
+
gem "rspec-rails"
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem "pry"
|
11
|
+
gem "pry-byebug", :platform => [:mri]
|
12
|
+
gem "appraisal"
|
13
|
+
gem "guard"
|
14
|
+
gem "guard-rspec"
|
15
|
+
end
|
16
|
+
|
17
|
+
gemspec :path => "../"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "rails", "~> 5.2"
|
6
|
+
gem "jsonapi-rails", "~> 0.3.1", :require => "jsonapi/rails"
|
7
|
+
gem "rspec-rails"
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem "pry"
|
11
|
+
gem "pry-byebug", :platform => [:mri]
|
12
|
+
gem "appraisal"
|
13
|
+
gem "guard"
|
14
|
+
gem "guard-rspec"
|
15
|
+
end
|
16
|
+
|
17
|
+
gemspec :path => "../"
|
data/graphiti.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'graphiti/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "graphiti-rb"
|
8
|
+
spec.version = Graphiti::VERSION
|
9
|
+
spec.authors = ["Lee Richmond"]
|
10
|
+
spec.email = ["richmolj@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Easily build jsonapi.org-compatible APIs}
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
# Pinning this version until backwards-incompatibility is addressed
|
21
|
+
spec.add_dependency 'jsonapi-serializable', '~> 0.3.0'
|
22
|
+
spec.add_dependency 'dry-types', '~> 0.13'
|
23
|
+
spec.add_dependency 'jsonapi_errorable', '~> 0.9'
|
24
|
+
spec.add_dependency 'concurrent-ruby', '~> 1.0'
|
25
|
+
|
26
|
+
spec.add_development_dependency "activerecord", ['>= 4.1', '< 6']
|
27
|
+
spec.add_development_dependency "kaminari", '~> 0.17'
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
spec.add_development_dependency "sqlite3"
|
31
|
+
spec.add_development_dependency "database_cleaner"
|
32
|
+
spec.add_development_dependency "activemodel", ['>= 4.1', '< 6']
|
33
|
+
spec.add_development_dependency "jsonapi_spec_helpers", '>= 1.0.alpha.1'
|
34
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Graphiti
|
2
|
+
class ResourceGenerator < ::Rails::Generators::NamedBase
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
|
5
|
+
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
|
6
|
+
|
7
|
+
class_option :'omit-comments',
|
8
|
+
type: :boolean,
|
9
|
+
default: false,
|
10
|
+
aliases: ['--omit-comments', '-c'],
|
11
|
+
desc: 'Generate without documentation comments'
|
12
|
+
class_option :'actions',
|
13
|
+
type: :array,
|
14
|
+
default: nil,
|
15
|
+
aliases: ['--actions', '-a'],
|
16
|
+
desc: 'Array of controller actions to support, e.g. "index show destroy"'
|
17
|
+
|
18
|
+
desc "This generator creates a resource file at app/resources, as well as corresponding controller/specs/route/etc"
|
19
|
+
def copy_resource_file
|
20
|
+
unless model_klass
|
21
|
+
raise "You must define a #{class_name} model before generating the corresponding resource."
|
22
|
+
end
|
23
|
+
|
24
|
+
generate_controller
|
25
|
+
generate_application_resource unless application_resource_defined?
|
26
|
+
generate_route
|
27
|
+
generate_resource_specs
|
28
|
+
generate_api_specs
|
29
|
+
generate_resource
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def actions
|
35
|
+
@options['actions'] || %w(index show create update destroy)
|
36
|
+
end
|
37
|
+
|
38
|
+
def actions?(*methods)
|
39
|
+
methods.any? { |m| actions.include?(m) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def omit_comments?
|
43
|
+
@options['omit-comments']
|
44
|
+
end
|
45
|
+
|
46
|
+
def responders?
|
47
|
+
defined?(Responders)
|
48
|
+
end
|
49
|
+
|
50
|
+
def generate_controller
|
51
|
+
to = File.join('app/controllers', class_path, "#{file_name.pluralize}_controller.rb")
|
52
|
+
template('controller.rb.erb', to)
|
53
|
+
end
|
54
|
+
|
55
|
+
def generate_application_resource
|
56
|
+
to = File.join('app/resources', class_path, "application_resource.rb")
|
57
|
+
template('application_resource.rb.erb', to)
|
58
|
+
end
|
59
|
+
|
60
|
+
def application_resource_defined?
|
61
|
+
'ApplicationResource'.safe_constantize.present?
|
62
|
+
end
|
63
|
+
|
64
|
+
def generate_route
|
65
|
+
code = " resources :#{type}"
|
66
|
+
code << ", only: [#{actions.map { |a| ":#{a}" }.join(', ')}]" if actions.length < 5
|
67
|
+
code << "\n"
|
68
|
+
inject_into_file 'config/routes.rb', after: "scope path: '/v1' do\n" do
|
69
|
+
code
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def generate_resource_specs
|
74
|
+
to = File.join("spec/resources/#{file_name}", class_path, "reads_spec.rb")
|
75
|
+
template('resource_reads_spec.rb.erb', to)
|
76
|
+
|
77
|
+
to = File.join("spec/resources/#{file_name}", class_path, "writes_spec.rb")
|
78
|
+
template('resource_writes_spec.rb.erb', to)
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_api_specs
|
82
|
+
if actions?('index')
|
83
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
84
|
+
class_path,
|
85
|
+
"index_spec.rb"
|
86
|
+
template('index_request_spec.rb.erb', to)
|
87
|
+
end
|
88
|
+
|
89
|
+
if actions?('show')
|
90
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
91
|
+
class_path,
|
92
|
+
"show_spec.rb"
|
93
|
+
template('show_request_spec.rb.erb', to)
|
94
|
+
end
|
95
|
+
|
96
|
+
if actions?('create')
|
97
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
98
|
+
class_path,
|
99
|
+
"create_spec.rb"
|
100
|
+
template('create_request_spec.rb.erb', to)
|
101
|
+
end
|
102
|
+
|
103
|
+
if actions?('update')
|
104
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
105
|
+
class_path,
|
106
|
+
"update_spec.rb"
|
107
|
+
template('update_request_spec.rb.erb', to)
|
108
|
+
end
|
109
|
+
|
110
|
+
if actions?('destroy')
|
111
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
112
|
+
class_path,
|
113
|
+
"destroy_spec.rb"
|
114
|
+
template('destroy_request_spec.rb.erb', to)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def generate_resource
|
119
|
+
to = File.join('app/resources', class_path, "#{file_name}_resource.rb")
|
120
|
+
template('resource.rb.erb', to)
|
121
|
+
end
|
122
|
+
|
123
|
+
def jsonapi_config
|
124
|
+
File.exists?('.jsonapicfg.yml') ? YAML.load_file('.jsonapicfg.yml') : {}
|
125
|
+
end
|
126
|
+
|
127
|
+
def update_config!(attrs)
|
128
|
+
config = jsonapi_config.merge(attrs)
|
129
|
+
File.open('.jsonapicfg.yml', 'w') { |f| f.write(config.to_yaml) }
|
130
|
+
end
|
131
|
+
|
132
|
+
def prompt(header: nil, description: nil, default: nil)
|
133
|
+
say(set_color("\n#{header}", :magenta, :bold)) if header
|
134
|
+
say("\n#{description}") if description
|
135
|
+
answer = ask(set_color("\n(default: #{default}):", :magenta, :bold))
|
136
|
+
answer = default if answer.blank? && default != 'nil'
|
137
|
+
say(set_color("\nGot it!\n", :white, :bold))
|
138
|
+
answer
|
139
|
+
end
|
140
|
+
|
141
|
+
def api_namespace
|
142
|
+
@api_namespace ||= begin
|
143
|
+
ns = jsonapi_config['namespace']
|
144
|
+
|
145
|
+
if ns.blank?
|
146
|
+
ns = prompt \
|
147
|
+
header: "What is your API namespace?",
|
148
|
+
description: "This will be used as a route prefix, e.g. if you want the route '/books_api/v1/authors' your namespace would be 'books_api'",
|
149
|
+
default: 'api'
|
150
|
+
update_config!('namespace' => ns)
|
151
|
+
end
|
152
|
+
|
153
|
+
ns
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def model_klass
|
158
|
+
class_name.safe_constantize
|
159
|
+
end
|
160
|
+
|
161
|
+
def resource_klass
|
162
|
+
"#{model_klass}Resource"
|
163
|
+
end
|
164
|
+
|
165
|
+
def type
|
166
|
+
model_klass.name.underscore.pluralize
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|