power_api 0.1.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 (138) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +9 -0
  4. data/.hound.yml +4 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +479 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +15 -0
  9. data/CHANGELOG.md +7 -0
  10. data/Gemfile +18 -0
  11. data/Gemfile.lock +310 -0
  12. data/Guardfile +15 -0
  13. data/LICENSE.txt +21 -0
  14. data/README.md +904 -0
  15. data/Rakefile +10 -0
  16. data/app/assets/config/power_api_manifest.js +2 -0
  17. data/app/assets/images/power_api/.keep +0 -0
  18. data/app/assets/javascripts/power_api/application.js +13 -0
  19. data/app/assets/stylesheets/power_api/application.css +15 -0
  20. data/app/controllers/concerns/api/deprecated.rb +23 -0
  21. data/app/controllers/concerns/api/error.rb +37 -0
  22. data/app/controllers/concerns/api/filtered.rb +15 -0
  23. data/app/controllers/concerns/api/versioned.rb +36 -0
  24. data/app/controllers/power_api/base_controller.rb +14 -0
  25. data/app/helpers/power_api/application_helper.rb +4 -0
  26. data/app/jobs/power_api/application_job.rb +4 -0
  27. data/app/mailers/power_api/application_mailer.rb +6 -0
  28. data/app/models/power_api/application_record.rb +5 -0
  29. data/app/responders/api_responder.rb +13 -0
  30. data/app/views/layouts/power_api/application.html.erb +14 -0
  31. data/bin/rails +14 -0
  32. data/config/routes.rb +2 -0
  33. data/lib/generators/power_api/controller/USAGE +5 -0
  34. data/lib/generators/power_api/controller/controller_generator.rb +152 -0
  35. data/lib/generators/power_api/install/USAGE +5 -0
  36. data/lib/generators/power_api/install/install_generator.rb +67 -0
  37. data/lib/generators/power_api/version/USAGE +5 -0
  38. data/lib/generators/power_api/version/version_generator.rb +54 -0
  39. data/lib/power_api.rb +35 -0
  40. data/lib/power_api/engine.rb +28 -0
  41. data/lib/power_api/errors.rb +4 -0
  42. data/lib/power_api/generator_helper/active_record_resource.rb +192 -0
  43. data/lib/power_api/generator_helper/ams_helper.rb +43 -0
  44. data/lib/power_api/generator_helper/controller_helper.rb +184 -0
  45. data/lib/power_api/generator_helper/pagination_helper.rb +48 -0
  46. data/lib/power_api/generator_helper/resource_helper.rb +33 -0
  47. data/lib/power_api/generator_helper/routes_helper.rb +91 -0
  48. data/lib/power_api/generator_helper/rubocop_helper.rb +11 -0
  49. data/lib/power_api/generator_helper/simple_token_auth_helper.rb +124 -0
  50. data/lib/power_api/generator_helper/swagger_helper.rb +463 -0
  51. data/lib/power_api/generator_helper/template_builder_helper.rb +23 -0
  52. data/lib/power_api/generator_helper/version_helper.rb +16 -0
  53. data/lib/power_api/generator_helpers.rb +25 -0
  54. data/lib/power_api/version.rb +3 -0
  55. data/lib/tasks/power_api_tasks.rake +4 -0
  56. data/power_api.gemspec +44 -0
  57. data/spec/dummy/Rakefile +6 -0
  58. data/spec/dummy/app/assets/config/manifest.js +5 -0
  59. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  60. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  61. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  62. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  63. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  64. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  65. data/spec/dummy/app/controllers/concerns/api/deprecated_spec.rb +37 -0
  66. data/spec/dummy/app/controllers/concerns/api/error_spec.rb +97 -0
  67. data/spec/dummy/app/controllers/concerns/api/filtered_spec.rb +42 -0
  68. data/spec/dummy/app/controllers/concerns/api/versioned_spec.rb +64 -0
  69. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  70. data/spec/dummy/app/jobs/application_job.rb +2 -0
  71. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  72. data/spec/dummy/app/models/application_record.rb +3 -0
  73. data/spec/dummy/app/models/blog.rb +5 -0
  74. data/spec/dummy/app/models/portfolio.rb +5 -0
  75. data/spec/dummy/app/models/user.rb +3 -0
  76. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  77. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  78. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  79. data/spec/dummy/bin/bundle +3 -0
  80. data/spec/dummy/bin/rails +4 -0
  81. data/spec/dummy/bin/rake +4 -0
  82. data/spec/dummy/bin/setup +38 -0
  83. data/spec/dummy/bin/update +29 -0
  84. data/spec/dummy/bin/yarn +11 -0
  85. data/spec/dummy/config.ru +5 -0
  86. data/spec/dummy/config/application.rb +26 -0
  87. data/spec/dummy/config/boot.rb +5 -0
  88. data/spec/dummy/config/cable.yml +10 -0
  89. data/spec/dummy/config/database.yml +25 -0
  90. data/spec/dummy/config/environment.rb +5 -0
  91. data/spec/dummy/config/environments/development.rb +54 -0
  92. data/spec/dummy/config/environments/production.rb +91 -0
  93. data/spec/dummy/config/environments/test.rb +42 -0
  94. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  95. data/spec/dummy/config/initializers/assets.rb +14 -0
  96. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  97. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  98. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  99. data/spec/dummy/config/initializers/inflections.rb +16 -0
  100. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  101. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  102. data/spec/dummy/config/locales/en.yml +33 -0
  103. data/spec/dummy/config/puma.rb +56 -0
  104. data/spec/dummy/config/routes.rb +12 -0
  105. data/spec/dummy/config/secrets.yml +32 -0
  106. data/spec/dummy/config/spring.rb +6 -0
  107. data/spec/dummy/db/migrate/20190322205209_create_blogs.rb +10 -0
  108. data/spec/dummy/db/migrate/20200215225917_create_users.rb +9 -0
  109. data/spec/dummy/db/migrate/20200227150449_create_portfolios.rb +10 -0
  110. data/spec/dummy/db/migrate/20200227150548_add_portfolio_id_blogs.rb +5 -0
  111. data/spec/dummy/db/schema.rb +38 -0
  112. data/spec/dummy/package.json +5 -0
  113. data/spec/dummy/public/404.html +67 -0
  114. data/spec/dummy/public/422.html +67 -0
  115. data/spec/dummy/public/500.html +66 -0
  116. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  117. data/spec/dummy/public/apple-touch-icon.png +0 -0
  118. data/spec/dummy/public/favicon.ico +0 -0
  119. data/spec/dummy/spec/assets/image.png +0 -0
  120. data/spec/dummy/spec/assets/video.mp4 +0 -0
  121. data/spec/dummy/spec/factories/blogs.rb +7 -0
  122. data/spec/dummy/spec/factories/portfolios.rb +6 -0
  123. data/spec/dummy/spec/factories/users.rb +5 -0
  124. data/spec/dummy/spec/lib/power_api/generator_helper/ams_helper_spec.rb +87 -0
  125. data/spec/dummy/spec/lib/power_api/generator_helper/controller_helper_spec.rb +361 -0
  126. data/spec/dummy/spec/lib/power_api/generator_helper/pagination_helper_spec.rb +56 -0
  127. data/spec/dummy/spec/lib/power_api/generator_helper/resource_helper_spec.rb +31 -0
  128. data/spec/dummy/spec/lib/power_api/generator_helper/routes_helper_spec.rb +179 -0
  129. data/spec/dummy/spec/lib/power_api/generator_helper/simple_token_auth_helper_spec.rb +164 -0
  130. data/spec/dummy/spec/lib/power_api/generator_helper/swagger_helper_spec.rb +451 -0
  131. data/spec/dummy/spec/lib/power_api/generator_helper/version_helper_spec.rb +55 -0
  132. data/spec/dummy/spec/support/shared_examples/active_record_resource.rb +101 -0
  133. data/spec/dummy/spec/support/shared_examples/active_record_resource_atrributes.rb +164 -0
  134. data/spec/dummy/spec/support/test_generator_helpers.rb +29 -0
  135. data/spec/dummy/spec/support/test_helpers.rb +11 -0
  136. data/spec/rails_helper.rb +49 -0
  137. data/spec/spec_helper.rb +9 -0
  138. metadata +602 -0
@@ -0,0 +1,23 @@
1
+ module PowerApi::GeneratorHelper::TemplateBuilderHelper
2
+ extend ActiveSupport::Concern
3
+
4
+ def concat_tpl_statements(*methods)
5
+ methods.reject(&:blank?).join("\n")
6
+ end
7
+
8
+ def concat_tpl_method(method_name, *method_lines)
9
+ concat_tpl_statements(
10
+ "def #{method_name}",
11
+ *method_lines,
12
+ "end"
13
+ )
14
+ end
15
+
16
+ def tpl_class(class_def, *statements)
17
+ concat_tpl_statements(
18
+ "class #{class_def}",
19
+ *statements,
20
+ "end\n"
21
+ )
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module PowerApi::GeneratorHelper::VersionHelper
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ attr_reader :version_number
6
+ end
7
+
8
+ def version_number=(value)
9
+ @version_number = value.to_s.to_i
10
+ raise PowerApi::GeneratorError.new("invalid version number") if version_number < 1
11
+ end
12
+
13
+ def first_version?
14
+ version_number.to_i == 1
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ module PowerApi
2
+ class GeneratorHelpers
3
+ include GeneratorHelper::ResourceHelper
4
+ include GeneratorHelper::VersionHelper
5
+ include GeneratorHelper::SwaggerHelper
6
+ include GeneratorHelper::AmsHelper
7
+ include GeneratorHelper::ControllerHelper
8
+ include GeneratorHelper::RoutesHelper
9
+ include GeneratorHelper::PaginationHelper
10
+ include GeneratorHelper::SimpleTokenAuthHelper
11
+ include GeneratorHelper::RubocopHelper
12
+
13
+ def initialize(config = {})
14
+ config.each do |attribute, value|
15
+ load_attribute(attribute, value)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def load_attribute(attribute, value)
22
+ send("#{attribute}=", value)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module PowerApi
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :power_api do
3
+ # # Task goes here
4
+ # end
data/power_api.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem"s version:
4
+ require "power_api/version"
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.name = "power_api"
9
+ s.version = PowerApi::VERSION
10
+ s.authors = ["Platanus", "Leandro Segovia"]
11
+ s.email = ["rubygems@platan.us", "ldlsegovia@gmail.com"]
12
+ s.homepage = "https://github.com/platanus/power_api"
13
+ s.summary = "Set of other gems and configurations designed to build incredible APIs"
14
+ s.description = "It is a Rails engine that gathers a set of other gems and configurations designed to build incredible APIs"
15
+ s.license = "MIT"
16
+
17
+ s.files = `git ls-files`.split($/).reject { |fn| fn.start_with? "spec" }
18
+ s.bindir = "exe"
19
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ s.test_files = Dir["spec/**/*"]
21
+
22
+ s.add_dependency "rails", ">= 4.2.0"
23
+
24
+ s.add_dependency "active_model_serializers", "~> 0.10.0"
25
+ s.add_dependency "api-pagination"
26
+ s.add_dependency "kaminari"
27
+ s.add_dependency "ransack"
28
+ s.add_dependency "responders"
29
+ s.add_dependency "rswag-api"
30
+ s.add_dependency "rswag-ui"
31
+ s.add_dependency "simple_token_authentication", "~> 1.0"
32
+ s.add_dependency "versionist", "~> 1.0"
33
+
34
+ s.add_development_dependency "coveralls"
35
+ s.add_development_dependency "factory_bot_rails"
36
+ s.add_development_dependency "guard-rspec"
37
+ s.add_development_dependency "pry"
38
+ s.add_development_dependency "pry-rails"
39
+ s.add_development_dependency "rspec-rails"
40
+ s.add_development_dependency "rswag-specs"
41
+ s.add_development_dependency "rubocop", "0.65.0"
42
+ s.add_development_dependency "rubocop-rspec"
43
+ s.add_development_dependency "sqlite3", "~> 1.3.0"
44
+ end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,5 @@
1
+
2
+ //= link_tree ../images
3
+ //= link_directory ../javascripts .js
4
+ //= link_directory ../stylesheets .css
5
+ //= link power_api_manifest.js
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ // Action Cable provides the framework to deal with WebSockets in Rails.
2
+ // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3
+ //
4
+ //= require action_cable
5
+ //= require_self
6
+ //= require_tree ./channels
7
+
8
+ (function() {
9
+ this.App || (this.App = {});
10
+
11
+ App.cable = ActionCable.createConsumer();
12
+
13
+ }).call(this);
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery with: :exception
3
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Api::Deprecated', type: :controller do
4
+ before do
5
+ routes.draw { get :action1, to: "anonymous#action" }
6
+
7
+ get :action
8
+ end
9
+
10
+ context "with deprecated action" do
11
+ controller do
12
+ include ::Api::Deprecated
13
+
14
+ deprecate :action
15
+
16
+ def action
17
+ head :ok
18
+ end
19
+ end
20
+
21
+ it { expect(response.status).to eq(200) }
22
+ it { expect(response.headers["Deprecated"]).to eq(true) }
23
+ end
24
+
25
+ context "with deprecated action" do
26
+ controller do
27
+ include ::Api::Deprecated
28
+
29
+ def action
30
+ head :ok
31
+ end
32
+ end
33
+
34
+ it { expect(response.status).to eq(200) }
35
+ it { expect(response.headers["Deprecated"]).to be_nil }
36
+ end
37
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Api::Error', type: :controller do
4
+ before do
5
+ routes.draw { get :action, to: "anonymous#action" }
6
+
7
+ get :action
8
+ end
9
+
10
+ def response_body
11
+ JSON.parse(response.body).deep_symbolize_keys
12
+ end
13
+
14
+ context "with Exception error" do
15
+ let(:expected_response) do
16
+ {
17
+ detail: ":-(",
18
+ message: "server_error",
19
+ type: "RuntimeError"
20
+ }
21
+ end
22
+
23
+ controller do
24
+ include ::Api::Error
25
+
26
+ def action
27
+ raise ':-('
28
+ end
29
+ end
30
+
31
+ it { expect(response_body).to eq(expected_response) }
32
+ it { expect(response.status).to eq(500) }
33
+ end
34
+
35
+ context "with ActiveRecord::RecordNotFound error" do
36
+ let(:expected_response) do
37
+ {
38
+ detail: ":-(",
39
+ message: "record_not_found"
40
+ }
41
+ end
42
+
43
+ controller do
44
+ include ::Api::Error
45
+
46
+ def action
47
+ raise ActiveRecord::RecordNotFound.new(":-(")
48
+ end
49
+ end
50
+
51
+ it { expect(response_body).to eq(expected_response) }
52
+ it { expect(response.status).to eq(404) }
53
+ end
54
+
55
+ context "with ActiveModel::ForbiddenAttributesError error" do
56
+ let(:expected_response) do
57
+ {
58
+ detail: ":-(",
59
+ message: "protected_attributes"
60
+ }
61
+ end
62
+
63
+ controller do
64
+ include ::Api::Error
65
+
66
+ def action
67
+ raise ActiveModel::ForbiddenAttributesError.new(":-(")
68
+ end
69
+ end
70
+
71
+ it { expect(response_body).to eq(expected_response) }
72
+ it { expect(response.status).to eq(400) }
73
+ end
74
+
75
+ context "with ActiveRecord::RecordInvalid error" do
76
+ let(:expected_response) do
77
+ {
78
+ message: "invalid_attributes",
79
+ errors: {
80
+ body: ["can't be blank"],
81
+ title: ["can't be blank"]
82
+ }
83
+ }
84
+ end
85
+
86
+ controller do
87
+ include ::Api::Error
88
+
89
+ def action
90
+ raise Blog.create!
91
+ end
92
+ end
93
+
94
+ it { expect(response_body).to eq(expected_response) }
95
+ it { expect(response.status).to eq(400) }
96
+ end
97
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Api::Filtered', type: :controller do
4
+ let(:filters) do
5
+ nil
6
+ end
7
+
8
+ controller do
9
+ include ::Api::Filtered
10
+
11
+ def action
12
+ render json: filtered_collection(Blog.all)
13
+ end
14
+ end
15
+
16
+ before do
17
+ routes.draw { get :action, to: "anonymous#action" }
18
+
19
+ create(:blog, title: "Lean's blog")
20
+ create(:blog, title: "Santiago's blog")
21
+
22
+ get :action, params: { q: filters }
23
+ end
24
+
25
+ def resources_count
26
+ JSON.parse(response.body).count
27
+ end
28
+
29
+ it { expect(resources_count).to eq(2) }
30
+ it { expect(response.status).to eq(200) }
31
+
32
+ context "with filters" do
33
+ let(:filters) do
34
+ {
35
+ title_cont: "Lean"
36
+ }
37
+ end
38
+
39
+ it { expect(resources_count).to eq(1) }
40
+ it { expect(response.status).to eq(200) }
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Api::Versioned', type: :controller do
4
+ let(:available_versions) { 1 }
5
+ let(:headers) do
6
+ {}
7
+ end
8
+
9
+ before do
10
+ allow(ENV).to receive(:fetch).with(
11
+ "AVAILABLE_API_VERSIONS", 1
12
+ ).and_return(available_versions)
13
+
14
+ routes.draw { get :action, to: "anonymous#action" }
15
+ request.headers.merge!(headers) unless headers.blank?
16
+ get :action
17
+ end
18
+
19
+ controller do
20
+ include ::Api::Versioned
21
+ include ::Api::Error
22
+
23
+ def action
24
+ head :ok
25
+ end
26
+ end
27
+
28
+ context "with default version" do
29
+ it { expect(response.status).to eq(200) }
30
+ it { expect(response.headers["Content-Type"]).to eq("text/html; version=1") }
31
+
32
+ context "with invalid version header" do
33
+ let(:headers) do
34
+ {
35
+ "Accept" => "version=2"
36
+ }
37
+ end
38
+
39
+ it { expect(response.status).to eq(400) }
40
+ end
41
+ end
42
+
43
+ context "with multiple versions" do
44
+ let(:available_versions) { 2 }
45
+ let(:headers) do
46
+ {
47
+ "Accept" => "version=2"
48
+ }
49
+ end
50
+
51
+ it { expect(response.status).to eq(200) }
52
+ it { expect(response.headers["Content-Type"]).to eq("text/html; version=2") }
53
+
54
+ context "with invalid version header" do
55
+ let(:headers) do
56
+ {
57
+ "Accept" => "version=3"
58
+ }
59
+ end
60
+
61
+ it { expect(response.status).to eq(400) }
62
+ end
63
+ end
64
+ end