graphiti-rb 1.0.alpha.1

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 (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +20 -0
  6. data/.yardopts +2 -0
  7. data/Appraisals +11 -0
  8. data/CODE_OF_CONDUCT.md +49 -0
  9. data/Gemfile +12 -0
  10. data/Guardfile +32 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +75 -0
  13. data/Rakefile +15 -0
  14. data/bin/appraisal +17 -0
  15. data/bin/console +14 -0
  16. data/bin/rspec +17 -0
  17. data/bin/setup +8 -0
  18. data/gemfiles/rails_4.gemfile +17 -0
  19. data/gemfiles/rails_5.gemfile +17 -0
  20. data/graphiti.gemspec +34 -0
  21. data/lib/generators/jsonapi/resource_generator.rb +169 -0
  22. data/lib/generators/jsonapi/templates/application_resource.rb.erb +15 -0
  23. data/lib/generators/jsonapi/templates/controller.rb.erb +61 -0
  24. data/lib/generators/jsonapi/templates/create_request_spec.rb.erb +30 -0
  25. data/lib/generators/jsonapi/templates/destroy_request_spec.rb.erb +20 -0
  26. data/lib/generators/jsonapi/templates/index_request_spec.rb.erb +22 -0
  27. data/lib/generators/jsonapi/templates/resource.rb.erb +11 -0
  28. data/lib/generators/jsonapi/templates/resource_reads_spec.rb.erb +62 -0
  29. data/lib/generators/jsonapi/templates/resource_writes_spec.rb.erb +63 -0
  30. data/lib/generators/jsonapi/templates/show_request_spec.rb.erb +21 -0
  31. data/lib/generators/jsonapi/templates/update_request_spec.rb.erb +34 -0
  32. data/lib/graphiti-rb.rb +1 -0
  33. data/lib/graphiti.rb +121 -0
  34. data/lib/graphiti/adapters/abstract.rb +516 -0
  35. data/lib/graphiti/adapters/active_record.rb +6 -0
  36. data/lib/graphiti/adapters/active_record/base.rb +249 -0
  37. data/lib/graphiti/adapters/active_record/belongs_to_sideload.rb +17 -0
  38. data/lib/graphiti/adapters/active_record/has_many_sideload.rb +17 -0
  39. data/lib/graphiti/adapters/active_record/has_one_sideload.rb +17 -0
  40. data/lib/graphiti/adapters/active_record/inferrence.rb +12 -0
  41. data/lib/graphiti/adapters/active_record/many_to_many_sideload.rb +30 -0
  42. data/lib/graphiti/adapters/null.rb +236 -0
  43. data/lib/graphiti/base.rb +70 -0
  44. data/lib/graphiti/configuration.rb +21 -0
  45. data/lib/graphiti/context.rb +16 -0
  46. data/lib/graphiti/deserializer.rb +208 -0
  47. data/lib/graphiti/errors.rb +309 -0
  48. data/lib/graphiti/extensions/boolean_attribute.rb +33 -0
  49. data/lib/graphiti/extensions/extra_attribute.rb +70 -0
  50. data/lib/graphiti/extensions/temp_id.rb +26 -0
  51. data/lib/graphiti/filter_operators.rb +25 -0
  52. data/lib/graphiti/hash_renderer.rb +57 -0
  53. data/lib/graphiti/jsonapi_serializable_ext.rb +50 -0
  54. data/lib/graphiti/query.rb +251 -0
  55. data/lib/graphiti/rails.rb +28 -0
  56. data/lib/graphiti/railtie.rb +74 -0
  57. data/lib/graphiti/renderer.rb +60 -0
  58. data/lib/graphiti/resource.rb +110 -0
  59. data/lib/graphiti/resource/configuration.rb +239 -0
  60. data/lib/graphiti/resource/dsl.rb +138 -0
  61. data/lib/graphiti/resource/interface.rb +32 -0
  62. data/lib/graphiti/resource/polymorphism.rb +68 -0
  63. data/lib/graphiti/resource/sideloading.rb +102 -0
  64. data/lib/graphiti/resource_proxy.rb +127 -0
  65. data/lib/graphiti/responders.rb +19 -0
  66. data/lib/graphiti/runner.rb +25 -0
  67. data/lib/graphiti/scope.rb +98 -0
  68. data/lib/graphiti/scoping/base.rb +99 -0
  69. data/lib/graphiti/scoping/default_filter.rb +58 -0
  70. data/lib/graphiti/scoping/extra_attributes.rb +29 -0
  71. data/lib/graphiti/scoping/filter.rb +93 -0
  72. data/lib/graphiti/scoping/filterable.rb +36 -0
  73. data/lib/graphiti/scoping/paginate.rb +87 -0
  74. data/lib/graphiti/scoping/sort.rb +64 -0
  75. data/lib/graphiti/sideload.rb +281 -0
  76. data/lib/graphiti/sideload/belongs_to.rb +34 -0
  77. data/lib/graphiti/sideload/has_many.rb +16 -0
  78. data/lib/graphiti/sideload/has_one.rb +9 -0
  79. data/lib/graphiti/sideload/many_to_many.rb +24 -0
  80. data/lib/graphiti/sideload/polymorphic_belongs_to.rb +108 -0
  81. data/lib/graphiti/stats/dsl.rb +89 -0
  82. data/lib/graphiti/stats/payload.rb +49 -0
  83. data/lib/graphiti/types.rb +172 -0
  84. data/lib/graphiti/util/attribute_check.rb +88 -0
  85. data/lib/graphiti/util/field_params.rb +16 -0
  86. data/lib/graphiti/util/hash.rb +51 -0
  87. data/lib/graphiti/util/hooks.rb +33 -0
  88. data/lib/graphiti/util/include_params.rb +39 -0
  89. data/lib/graphiti/util/persistence.rb +219 -0
  90. data/lib/graphiti/util/relationship_payload.rb +64 -0
  91. data/lib/graphiti/util/serializer_attributes.rb +97 -0
  92. data/lib/graphiti/util/sideload.rb +33 -0
  93. data/lib/graphiti/util/validation_response.rb +78 -0
  94. data/lib/graphiti/version.rb +3 -0
  95. metadata +317 -0
@@ -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
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /pkg/
7
+ /spec/reports/
8
+ /gemfiles/*.lock
9
+ /tmp/
10
+ .byebug_history
11
+ spec/dummy/log/*
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --require spec_helper
@@ -0,0 +1 @@
1
+ 2.3.0
@@ -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
@@ -0,0 +1,2 @@
1
+ --plugin classmethods
2
+ --output-dir docs
@@ -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
@@ -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
@@ -0,0 +1,12 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in graphiti.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'pry'
8
+ gem 'pry-byebug', platform: [:mri]
9
+ gem 'appraisal'
10
+ gem 'guard'
11
+ gem 'guard-rspec'
12
+ end
@@ -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
@@ -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.
@@ -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
+ ```
@@ -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
@@ -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")
@@ -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
@@ -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")
@@ -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,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 => "../"
@@ -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