gris 0.0.2

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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +1 -0
  5. data/.rubocop_todo.yml +67 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/Gemfile +12 -0
  9. data/Gemfile.lock +203 -0
  10. data/Guardfile +82 -0
  11. data/MIT-LICENSE +20 -0
  12. data/README.md +7 -0
  13. data/Rakefile +11 -0
  14. data/bin/gris +5 -0
  15. data/gris.gemspec +40 -0
  16. data/lib/gris.rb +37 -0
  17. data/lib/gris/cli.rb +71 -0
  18. data/lib/gris/deprecations.rb +9 -0
  19. data/lib/gris/deprecations/gris_setup.rb +14 -0
  20. data/lib/gris/generators.rb +3 -0
  21. data/lib/gris/generators/api_generator.rb +31 -0
  22. data/lib/gris/generators/migration_generator.rb +228 -0
  23. data/lib/gris/generators/scaffold_generator.rb +21 -0
  24. data/lib/gris/generators/templates/api/app/apis/%name_tableize%_endpoint.rb.tt +65 -0
  25. data/lib/gris/generators/templates/api/app/models/%name_underscore%.rb.tt +2 -0
  26. data/lib/gris/generators/templates/api/app/presenters/%name_tableize%_presenter.rb.tt +5 -0
  27. data/lib/gris/generators/templates/api/app/presenters/%name_underscore%_presenter.rb.tt +10 -0
  28. data/lib/gris/generators/templates/api/spec/apis/%name_tableize%_endpoint_spec.rb.tt +70 -0
  29. data/lib/gris/generators/templates/api/spec/fabricators/%name_tableize%_fabricator.rb.tt +2 -0
  30. data/lib/gris/generators/templates/api/spec/models/%name_underscore%_spec.rb.tt +7 -0
  31. data/lib/gris/generators/templates/create_table_migration/%migration_filename%.rb.tt +19 -0
  32. data/lib/gris/generators/templates/migration/%migration_filename%.rb.tt +39 -0
  33. data/lib/gris/generators/templates/scaffold/.Procfile.tt +1 -0
  34. data/lib/gris/generators/templates/scaffold/.env.test.tt +11 -0
  35. data/lib/gris/generators/templates/scaffold/.env.tt +10 -0
  36. data/lib/gris/generators/templates/scaffold/.gitignore.tt +11 -0
  37. data/lib/gris/generators/templates/scaffold/.rspec.tt +3 -0
  38. data/lib/gris/generators/templates/scaffold/.rubocop.yml +18 -0
  39. data/lib/gris/generators/templates/scaffold/.ruby-gemset.tt +1 -0
  40. data/lib/gris/generators/templates/scaffold/.ruby-version.tt +1 -0
  41. data/lib/gris/generators/templates/scaffold/Gemfile.tt +33 -0
  42. data/lib/gris/generators/templates/scaffold/README.md.tt +3 -0
  43. data/lib/gris/generators/templates/scaffold/Rakefile +9 -0
  44. data/lib/gris/generators/templates/scaffold/app.rb +57 -0
  45. data/lib/gris/generators/templates/scaffold/app/apis/application_endpoint.rb +9 -0
  46. data/lib/gris/generators/templates/scaffold/app/presenters/root_presenter.rb +20 -0
  47. data/lib/gris/generators/templates/scaffold/config.ru.tt +6 -0
  48. data/lib/gris/generators/templates/scaffold/config/database.yml.tt +19 -0
  49. data/lib/gris/generators/templates/scaffold/config/initializers/active_record.rb +4 -0
  50. data/lib/gris/generators/templates/scaffold/db/schema.rb +11 -0
  51. data/lib/gris/generators/templates/scaffold/public/errors/404.html +11 -0
  52. data/lib/gris/generators/templates/scaffold/public/errors/500.html +11 -0
  53. data/lib/gris/generators/templates/scaffold/spec/apis/cors_spec.rb +31 -0
  54. data/lib/gris/generators/templates/scaffold/spec/spec_helper.rb +26 -0
  55. data/lib/gris/generators/templates/scaffold/spec/support/app_helper.rb +3 -0
  56. data/lib/gris/grape_extensions/crud_helpers.rb +26 -0
  57. data/lib/gris/identity.rb +50 -0
  58. data/lib/gris/middleware/app_monitor.rb +17 -0
  59. data/lib/gris/output_formatters/paginated_presenter.rb +41 -0
  60. data/lib/gris/output_formatters/presenter.rb +15 -0
  61. data/lib/gris/rspec_extensions/response_helpers.rb +57 -0
  62. data/lib/gris/setup.rb +17 -0
  63. data/lib/gris/version.rb +38 -0
  64. data/lib/tasks/db.rake +81 -0
  65. data/lib/tasks/routes.rake +11 -0
  66. data/spec/generators/api_generator_spec.rb +76 -0
  67. data/spec/generators/migration_generator_spec.rb +96 -0
  68. data/spec/generators/scaffold_generator_spec.rb +119 -0
  69. data/spec/grape_extensions/crud_helpers_spec.rb +5 -0
  70. data/spec/identity_spec.rb +86 -0
  71. data/spec/spec_helper.rb +10 -0
  72. data/spec/support/spec_generators_helper.rb +11 -0
  73. data/spec/version_spec.rb +40 -0
  74. metadata +426 -0
@@ -0,0 +1,65 @@
1
+ class <%= name.classify.pluralize %>Endpoint < Grape::API
2
+ namespace :<%= name.underscore.tableize %> do
3
+ desc 'Get a list of <%= name.underscore.tableize %>'
4
+ params do
5
+ optional :ids, type: Array, desc: 'Array of <%= name.underscore %> ids'
6
+ optional :page, type: Integer, default: 1, desc: 'Current page.'
7
+ optional :size, type: Integer, default: 10, desc: 'Number of <%= name.underscore.tableize %> to return per page.'
8
+ end
9
+ get do
10
+ <%= name.underscore.tableize %> = params[:ids] ? <%= name.classify %>.where(id: params[:ids]) : <%= name.classify %>.all
11
+ present Kaminari.paginate_array(<%= name.underscore.tableize %>).page(params[:page]).per(params[:size]), with: <%= name.classify.pluralize %>Presenter
12
+ end
13
+
14
+ desc 'Create a new <%= name.underscore %>.'
15
+ params do
16
+ requires :<%= name.underscore %>, type: Hash do
17
+ # Use this requires block to whitelist params which
18
+ # may be updated via mass assignment at this endpoint.
19
+ #
20
+ # requires :name, type: String, default: false
21
+ # optional :category, type: String, default: false
22
+ end
23
+ end
24
+ post do
25
+ create <%= name.classify %>, with: <%= name.classify %>Presenter, from: permitted_params[:<%= name.underscore %>]
26
+ end
27
+
28
+ desc 'Get an existing <%= name.underscore %>.'
29
+ params do
30
+ requires :id, desc: 'ID of the <%= name.underscore %>'
31
+ end
32
+ route_param :id do
33
+ desc 'Get an <%= name.underscore %>'
34
+ get do
35
+ <%= name.underscore %> = <%= name.classify %>.find params[:id]
36
+ present <%= name.underscore %>, with: <%= name.classify %>Presenter
37
+ end
38
+ end
39
+
40
+ desc 'Update an existing <%= name.underscore %>.'
41
+ params do
42
+ requires :id, type: String, desc: '<%= name.classify %> id.'
43
+ requires :<%= name.underscore %>, type: Hash do
44
+ # Use this requires block to whitelist params which
45
+ # may be updated via mass assignment at this endpoint.
46
+ #
47
+ # requires :name, type: String, default: false
48
+ # optional :category, type: String, default: false
49
+ end
50
+ end
51
+ patch ':id' do
52
+ <%= name.underscore %> = <%= name.classify %>.find params[:id]
53
+ update <%= name.underscore %>, with: <%= name.classify %>Presenter, from: permitted_params[:<%= name.underscore %>]
54
+ end
55
+
56
+ desc 'Delete an existing <%= name.underscore %>.'
57
+ params do
58
+ requires :id, type: String, desc: '<%= name.classify %> id.'
59
+ end
60
+ delete ':id' do
61
+ <%= name.underscore %> = <%= name.classify %>.find params[:id]
62
+ delete <%= name.underscore %>, with: <%= name.classify %>Presenter
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,2 @@
1
+ class <%= name.classify %> < ActiveRecord::Base
2
+ end
@@ -0,0 +1,5 @@
1
+ module <%= name.classify.pluralize %>Presenter
2
+ include Gris::PaginatedPresenter
3
+
4
+ collection :to_a, extend: <%= name.classify %>Presenter, as: :<%= name.tableize %>, embedded: true
5
+ end
@@ -0,0 +1,10 @@
1
+ module <%= name.classify %>Presenter
2
+ include Gris::Presenter
3
+
4
+ property :id, writeable: false, type: String, desc: '<%= name.classify %> unique ID.'
5
+
6
+ link :self do |opts|
7
+ request = Grape::Request.new(opts[:env])
8
+ "#{request.base_url}/<%= name.tableize %>/#{id}"
9
+ end
10
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= name.classify.pluralize %>Endpoint do
4
+ include Rack::Test::Methods
5
+ include_context 'with a running app'
6
+
7
+ context '<%= name.tableize %>' do
8
+ before(:each) do
9
+ 20.times do
10
+ Fabricate(:<%= name.underscore %>)
11
+ end
12
+ end
13
+
14
+ it 'returns 10 <%= name.tableize %> by default' do
15
+ get '/<%= name.tableize %>'
16
+ expect(response_code).to eq 200
17
+ expect_embedded_results_count_of 10, <%= name.classify %>
18
+ end
19
+
20
+ it 'returns 2 <%= name.tableize %>' do
21
+ get '/<%= name.tableize %>?size=2'
22
+ expect(response_code).to eq 200
23
+ expect_embedded_results_count_of 2, <%= name.classify %>
24
+ end
25
+
26
+ it 'returns pagination' do
27
+ get '/<%= name.tableize %>?size=2&page=2'
28
+ expect(response_code).to eq 200
29
+ expect(link_to_next[:href]).to eq 'http://example.org/<%= name.tableize %>?page=3&size=2'
30
+ expect(link_to_previous[:href]).to eq 'http://example.org/<%= name.tableize %>?page=1&size=2'
31
+ expect(link_to_self[:href]).to eq 'http://example.org/<%= name.tableize %>?page=2&size=2'
32
+ end
33
+
34
+ it 'returns all unique ids' do
35
+ get '/<%= name.tableize %>'
36
+ expect(response_code).to eq 200
37
+ expect(embedded_results(<%= name.classify %>).map { |s| s[:id] }.uniq.count).to eq 10
38
+ end
39
+ end
40
+
41
+ context '<%= name.underscore %>' do
42
+ let(:<%= name.underscore %>1) { Fabricate(:<%= name.underscore %>) }
43
+
44
+ it 'creates a <%= name.underscore %>' do
45
+ post '/<%= name.tableize %>', <%= name.underscore %>: { replace: 'REPLACE ME' }
46
+ expect(response_code).to eq 201
47
+ expect(result[:id]).to_not be_blank
48
+ end
49
+
50
+ it 'returns a <%= name.underscore %>' do
51
+ get "/<%= name.tableize %>/#{<%= name.underscore %>1.id}"
52
+ expect(response_code).to eq 200
53
+ expect(result[:id]).to eq <%= name.underscore %>1.id
54
+ expect(link_to_self[:href]).to eq "http://example.org/<%= name.tableize %>/#{<%= name.underscore %>1.id}"
55
+ end
56
+
57
+ it 'updates a <%= name.underscore %>' do
58
+ patch "/<%= name.tableize %>/#{<%= name.underscore %>1.id}", <%= name.underscore %>: { replace: 'REPLACE ME' }
59
+ expect(response_code).to eq 200
60
+ expect(result[:id]).to eq <%= name.underscore %>1.id
61
+ end
62
+
63
+ it 'deletes a <%= name.underscore %>' do
64
+ expect_any_instance_of(<%= name.classify %>).to receive(:destroy)
65
+ delete "/<%= name.tableize %>/#{<%= name.underscore %>1.id}"
66
+ expect(response_code).to eq 200
67
+ expect(result[:id]).to eq <%= name.underscore %>1.id
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,2 @@
1
+ Fabricator(:<%= name.underscore %>) do
2
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= name.classify %> do
4
+ it 'needs tests to be written!' do
5
+ # pending('write tests for <%= name.classify %>!')
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ class <%= migration_name.camelize %> < ActiveRecord::Migration
2
+ def change
3
+ create_table :<%= table_name %> do |t|
4
+ <% attributes.each do |attribute| -%>
5
+ <% if attribute.password_digest? -%>
6
+ t.string :password_digest<%= attribute.inject_options %>
7
+ <% else -%>
8
+ t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
9
+ <% end -%>
10
+ <% end -%>
11
+ <% if options[:timestamps] %>
12
+ t.timestamps
13
+ <% end -%>
14
+ end
15
+ <% attributes_with_index.each do |attribute| -%>
16
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
17
+ <% end -%>
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ class <%= migration_name.camelize %> < ActiveRecord::Migration
2
+ <%- if migration_action == 'add' -%>
3
+ def change
4
+ <% attributes.each do |attribute| -%>
5
+ <%- if attribute.reference? -%>
6
+ add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
7
+ <%- else -%>
8
+ add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
9
+ <%- if attribute.has_index? -%>
10
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
11
+ <%- end -%>
12
+ <%- end -%>
13
+ <%- end -%>
14
+ end
15
+ <%- elsif migration_action == 'join' -%>
16
+ def change
17
+ create_join_table :<%= join_tables.first %>, :<%= join_tables.second %> do |t|
18
+ <%- attributes.each do |attribute| -%>
19
+ <%= '# ' unless attribute.has_index? -%>t.index <%= attribute.index_name %><%= attribute.inject_index_options %>
20
+ <%- end -%>
21
+ end
22
+ end
23
+ <%- else -%>
24
+ def change
25
+ <% attributes.each do |attribute| -%>
26
+ <%- if migration_action -%>
27
+ <%- if attribute.reference? -%>
28
+ remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
29
+ <%- else -%>
30
+ <%- if attribute.has_index? -%>
31
+ remove_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
32
+ <%- end -%>
33
+ remove_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
34
+ <%- end -%>
35
+ <%- end -%>
36
+ <%- end -%>
37
+ end
38
+ <%- end -%>
39
+ end
@@ -0,0 +1 @@
1
+ web: bundle exec puma -p $PORT -e $RACK_ENV -t 0:5
@@ -0,0 +1,11 @@
1
+ # Uncomment when using Gris::Middleware::Authentication
2
+ # HEADER_PASSWORD=''
3
+
4
+ SERVICE_NAME=<%= app_name %>
5
+ RACK_ENV=test
6
+
7
+ DATABASE_USER=''
8
+ DATABASE_PASSWORD=''
9
+ DATABASE_HOST=localhost
10
+ DATABASE_NAME=<%= app_name.underscore %>_test
11
+ BASE_URL=http://127.0.0.1:9393
@@ -0,0 +1,10 @@
1
+ # Uncomment when using Gris::Middleware::Authentication
2
+ # HEADER_PASSWORD=''
3
+
4
+ SERVICE_NAME=<%= app_name %>
5
+
6
+ DATABASE_USER='<%= @database_user %>'
7
+ DATABASE_PASSWORD=''
8
+ DATABASE_HOST=localhost
9
+ DATABASE_NAME=<%= app_name.underscore %>_development
10
+ BASE_URL=http://127.0.0.1:9292
@@ -0,0 +1,11 @@
1
+ .DS_Store
2
+ .env
3
+ .rspec
4
+ .env
5
+ !.env.test
6
+ !log/.keep
7
+ log/*
8
+ tmp/*
9
+ !.keep
10
+ .ruby-gemset
11
+ .ruby-version
@@ -0,0 +1,3 @@
1
+ --color
2
+ --profile
3
+ --format documentation
@@ -0,0 +1,18 @@
1
+ AllCops:
2
+ Exclude:
3
+ - db/schema.rb
4
+
5
+ Documentation:
6
+ Enabled: false
7
+
8
+ Encoding:
9
+ Enabled: false
10
+
11
+ HandleExceptions:
12
+ Enabled: false
13
+
14
+ LineLength:
15
+ Max: 120
16
+
17
+ NumericLiterals:
18
+ Enabled: false
@@ -0,0 +1,33 @@
1
+ source 'https://rubygems.org'
2
+ ruby '2.1.5'
3
+
4
+ gem 'rack-cors'
5
+ gem 'pg'
6
+ gem 'activerecord', '~> 4.2.0', require: 'active_record'
7
+ gem 'json'
8
+
9
+ gem 'gris'
10
+
11
+ gem 'roar'
12
+ gem 'grape-roar', '~> 0.3.0'
13
+ gem 'grape-swagger'
14
+ gem 'kaminari', '~> 0.16.2', require: 'kaminari/grape'
15
+ gem 'puma'
16
+
17
+ group :development, :test do
18
+ gem 'pry'
19
+ end
20
+
21
+ group :development do
22
+ gem 'rubocop', require: false
23
+ gem 'shotgun', require: false
24
+ end
25
+
26
+ group :test do
27
+ gem 'fabrication'
28
+ gem 'rspec'
29
+ gem 'rack-test'
30
+ gem 'simplecov'
31
+ gem 'webmock'
32
+ gem 'database_cleaner'
33
+ end
@@ -0,0 +1,3 @@
1
+ # Welcome to <%= app_name %>
2
+
3
+ TODO: Add an awesome README that explains how all this stuff works!
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env rake
2
+ require 'gris/setup'
3
+ require 'dotenv'
4
+ Gris.load_environment
5
+
6
+ require './app'
7
+ require 'json'
8
+
9
+ Dir.glob('./lib/tasks/*.rake').each { |r| import r }
@@ -0,0 +1,57 @@
1
+ # load bundler
2
+ require 'bundler/setup'
3
+ Bundler.setup(:default)
4
+
5
+ require 'gris/setup'
6
+ Bundler.require(:default, Gris.env.to_sym)
7
+ require 'gris'
8
+
9
+ # load environment
10
+ Gris.load_environment
11
+
12
+ # autoload initalizers
13
+ Dir['./config/initializers/**/*.rb'].map { |file| require file }
14
+
15
+ # load middleware configs
16
+ Dir['./config/middleware/**/*.rb'].map { |file| require file }
17
+
18
+ # autoload app
19
+ relative_load_paths = %w(app/apis app/presenters app/models app/workers lib)
20
+ ActiveSupport::Dependencies.autoload_paths += relative_load_paths
21
+
22
+ module Application
23
+ class Service
24
+ def initialize
25
+ @filenames = ['', '.html', 'index.html', '/index.html']
26
+ @rack_static = ::Rack::Static.new(
27
+ -> { [404, {}, []] },
28
+ root: File.expand_path('../public', __FILE__),
29
+ urls: ['/']
30
+ )
31
+ end
32
+
33
+ def self.instance
34
+ @instance ||= Rack::Builder.new do
35
+ use Rack::Cors do
36
+ allow do
37
+ origins '*'
38
+ resource '*', headers: :any, methods: :get
39
+ end
40
+ end
41
+ run Application::Service.new
42
+ end.to_app
43
+ end
44
+
45
+ def call(env)
46
+ response = ApplicationEndpoint.call(env)
47
+ # Render error pages or return API response
48
+ case response[0]
49
+ when 404, 500
50
+ content = @rack_static.call(env.merge('PATH_INFO' => "/errors/#{response[0]}.html"))
51
+ [response[0], content[1], content[2]]
52
+ else
53
+ response
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ class ApplicationEndpoint < Grape::API
2
+ format :json
3
+ formatter :json, Grape::Formatter::Roar
4
+
5
+ desc 'Get the Root API Endpoint'
6
+ get do
7
+ present self, with: RootPresenter
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module RootPresenter
2
+ include Roar::JSON::HAL
3
+ include Roar::Hypermedia
4
+ include Grape::Roar::Representer
5
+
6
+ link :self do |opts|
7
+ "#{base_url(opts)}"
8
+ end
9
+
10
+ link :health do |opts|
11
+ { href: "#{base_url(opts)}/health" }
12
+ end
13
+
14
+ private
15
+
16
+ def base_url(opts)
17
+ request = Grape::Request.new(opts[:env])
18
+ request.base_url
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ require './app'
2
+
3
+ use ActiveRecord::ConnectionAdapters::ConnectionManagement
4
+ use Gris::Middleware::AppMonitor
5
+
6
+ run Application::Service.instance