gris 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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