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,19 @@
1
+ defaults: &defaults
2
+ encoding: unicode
3
+ adapter: postgresql
4
+ host: <%%= ENV['DATABASE_HOST'] %>
5
+ username: <%%= ENV['DATABASE_USER'] %>
6
+ password: <%%= ENV['DATABASE_PASSWORD'] %>
7
+ database: <%%= ENV['DATABASE_NAME'] %>
8
+
9
+ production:
10
+ <<: *defaults
11
+
12
+ development:
13
+ <<: *defaults
14
+
15
+ test:
16
+ <<: *defaults
17
+
18
+ staging:
19
+ <<: *defaults
@@ -0,0 +1,4 @@
1
+ require 'erb'
2
+ db = YAML.load(ERB.new(File.read('./config/database.yml')).result)[Gris.env]
3
+ ActiveRecord::Base.establish_connection(db)
4
+ ActiveRecord::Base.include_root_in_json = false
@@ -0,0 +1,11 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # Note that this schema.rb definition is the authoritative source for your
6
+ # database schema. If you need to create the application database on another
7
+ # system, you should be using db:schema:load, not running all the migrations
8
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <head>
3
+ <title>Page Not Found</title>
4
+ </head>
5
+ <body>
6
+ <h1>Ooops...</h1>
7
+ <p>
8
+ This page could not be found.
9
+ </p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,11 @@
1
+ <html>
2
+ <head>
3
+ <title>Unexpected Error</title>
4
+ </head>
5
+ <body>
6
+ <h1>Ouch...</h1>
7
+ <p>
8
+ Something went terribly wrong.
9
+ </p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Application::Service do
4
+ include Rack::Test::Methods
5
+
6
+ context 'CORS' do
7
+ include_context 'with a running app'
8
+ it 'supports options' do
9
+ options '/', {},
10
+ 'HTTP_ORIGIN' => 'http://cors.example.com',
11
+ 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'Origin, Accept, Content-Type',
12
+ 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET'
13
+
14
+ expect(response_code).to eq 200
15
+ expect(last_response.headers['Access-Control-Allow-Origin']).to eq 'http://cors.example.com'
16
+ expect(last_response.headers['Access-Control-Expose-Headers']).to eq ''
17
+ end
18
+
19
+ it 'includes Access-Control-Allow-Origin in the response' do
20
+ get '/', {}, 'HTTP_ORIGIN' => 'http://cors.example.com'
21
+ expect(response_code).to eq 200
22
+ expect(last_response.headers['Access-Control-Allow-Origin']).to eq 'http://cors.example.com'
23
+ end
24
+
25
+ it 'includes Access-Control-Allow-Origin in errors' do
26
+ get '/invalid', {}, 'HTTP_ORIGIN' => 'http://cors.example.com'
27
+ expect(response_code).to eq 404
28
+ expect(last_response.headers['Access-Control-Allow-Origin']).to eq 'http://cors.example.com'
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'webmock/rspec'
4
+ require 'rack/test'
5
+ require 'gris/rspec_extensions/response_helpers'
6
+
7
+ require './app'
8
+ # Requires supporting ruby files with custom matchers and macros, etc,
9
+ # in spec/support/ and its subdirectories.
10
+ Dir['./spec/support/**/*.rb'].each { |f| require f }
11
+
12
+ RSpec.configure do |config|
13
+ config.include Gris::RspecExtensions::ResponseHelpers
14
+ config.mock_with :rspec
15
+ config.expect_with :rspec
16
+
17
+ config.before(:suite) do
18
+ ActiveRecord::Migration.maintain_test_schema!
19
+ DatabaseCleaner.strategy = :transaction
20
+ DatabaseCleaner.clean_with(:truncation)
21
+ end
22
+
23
+ config.after(:each) do |_example|
24
+ DatabaseCleaner.clean
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ shared_context 'with a running app' do
2
+ let(:app) { Application::Service.instance }
3
+ end
@@ -0,0 +1,26 @@
1
+ module Gris
2
+ module CrudHelpers
3
+ def create(type, options = {})
4
+ instance = type.create! options[:from]
5
+ present instance, with: options[:with]
6
+ end
7
+
8
+ def update(instance, options = {})
9
+ instance.update_attributes! options[:from]
10
+ present instance, with: options[:with]
11
+ end
12
+
13
+ def delete(instance, options = {})
14
+ instance.destroy
15
+ present instance, with: options[:with]
16
+ end
17
+
18
+ def permitted_params(options = {})
19
+ options = { include_missing: false }.merge(options)
20
+ declared(params, options)
21
+ end
22
+
23
+ # extend all endpoints to include this
24
+ Grape::Endpoint.send :include, self if defined?(Grape)
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ module Gris
2
+ class Identity
3
+ def self.health
4
+ {
5
+ name: name,
6
+ base_url: base_url,
7
+ hostname: hostname,
8
+ revision: revision,
9
+ pid: pid,
10
+ parent_pid: parent_pid,
11
+ platform: platform
12
+ }
13
+ end
14
+
15
+ def self.name
16
+ ENV['SERVICE_NAME'] || 'api-service'
17
+ end
18
+
19
+ def self.base_url
20
+ ENV['BASE_URL'] || 'http://localhost:9292'
21
+ end
22
+
23
+ def self.hostname
24
+ @hostname ||= `hostname`.strip
25
+ end
26
+
27
+ def self.revision
28
+ @revision ||= `git rev-parse HEAD`.strip
29
+ end
30
+
31
+ def self.pid
32
+ @pid ||= Process.pid
33
+ end
34
+
35
+ def self.parent_pid
36
+ @ppid ||= Process.ppid
37
+ end
38
+
39
+ def self.platform
40
+ {
41
+ version: platform_revision,
42
+ name: 'Gris'
43
+ }
44
+ end
45
+
46
+ def self.platform_revision
47
+ Gris::VERSION
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ module Gris
2
+ class Middleware
3
+ class AppMonitor
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ if ['/health', '/health.json'].include? env['PATH_INFO']
10
+ [200, { 'Content-type' => 'application/json' }, [Gris::Identity.health.to_json]]
11
+ else
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ module Gris
2
+ module PaginatedPresenter
3
+ def self.included(base)
4
+ base.class_eval do
5
+ include Gris::Presenter
6
+
7
+ property :total_count
8
+ property :total_pages
9
+ property :current_page
10
+ property :next_page
11
+ property :prev_page
12
+
13
+ link :self do |opts|
14
+ "#{request_url(opts)}?#{query_string_for_page(represented.current_page, opts)}"
15
+ end
16
+
17
+ link :next do |opts|
18
+ "#{request_url(opts)}?#{query_string_for_page(represented.next_page, opts)}" if represented.next_page
19
+ end
20
+
21
+ link :prev do |opts|
22
+ "#{request_url(opts)}?#{query_string_for_page(represented.prev_page, opts)}" if represented.prev_page
23
+ end
24
+
25
+ private
26
+
27
+ def request_url(opts)
28
+ request = Grape::Request.new(opts[:env])
29
+ "#{request.base_url}#{opts[:env]['PATH_INFO']}"
30
+ end
31
+
32
+ # replace the page parameter in the query string
33
+ def query_string_for_page(page, opts)
34
+ qs = Rack::Utils.parse_nested_query(opts[:env]['QUERY_STRING'])
35
+ qs['page'] = page
36
+ qs.to_query
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ require 'roar/representer'
2
+ require 'roar/json'
3
+ require 'roar/json/hal'
4
+
5
+ module Gris
6
+ module Presenter
7
+ def self.included(base)
8
+ base.class_eval do
9
+ include Roar::JSON::HAL
10
+ include Roar::Hypermedia
11
+ include Grape::Roar::Representer
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,57 @@
1
+ module Gris
2
+ module RspecExtensions
3
+ module ResponseHelpers
4
+ def response_code
5
+ last_response.status
6
+ end
7
+
8
+ def response_body
9
+ last_response.body
10
+ end
11
+
12
+ def parsed_response
13
+ Hashie::Mash.new(JSON.parse(last_response.body))
14
+ end
15
+
16
+ def result
17
+ parsed_response
18
+ end
19
+
20
+ def embedded_results(klass)
21
+ parsed_response[:_embedded][klass.name.tableize.to_sym]
22
+ end
23
+
24
+ def embedded_results_count(klass)
25
+ embedded_results(klass).count
26
+ end
27
+
28
+ def expect_embedded_results_count_of(count, klass)
29
+ expect(embedded_results_count(klass)).to eq(count)
30
+ end
31
+
32
+ def first_embedded_result(klass)
33
+ embedded_results(klass).first
34
+ end
35
+
36
+ def embedded_result_with_id(id, klass)
37
+ embedded_results(klass).select { |r| r.id == id }.first
38
+ end
39
+
40
+ def links
41
+ parsed_response['_links']
42
+ end
43
+
44
+ def link_to_self
45
+ links['self']
46
+ end
47
+
48
+ def link_to_next
49
+ links['next']
50
+ end
51
+
52
+ def link_to_previous
53
+ links['prev']
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_support'
2
+
3
+ module Gris
4
+ class << self
5
+ def load_environment
6
+ Dotenv.load(Gris.env.test? ? '.env.test' : '.env')
7
+ end
8
+
9
+ def env
10
+ @_env ||= ActiveSupport::StringInquirer.new(ENV['RACK_ENV'] || 'development')
11
+ end
12
+
13
+ def env=(environment)
14
+ @_env = ActiveSupport::StringInquirer.new(environment)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ module Gris
2
+ VERSION = '0.0.2'
3
+
4
+ class Version
5
+ class << self
6
+ def next_major
7
+ next_level(:major)
8
+ end
9
+
10
+ def next_minor
11
+ next_level(:minor)
12
+ end
13
+
14
+ def next_patch
15
+ next_level(:patch)
16
+ end
17
+
18
+ def next_level(level)
19
+ fail 'Unidentified Level' unless [:major, :minor, :patch].include?(level)
20
+ parts = Gris::VERSION.split('.').map(&:to_i)
21
+ if level == :major
22
+ parts[0] += 1
23
+ significant_index = 1
24
+ end
25
+ if level == :minor
26
+ parts[1] += 1
27
+ significant_index = 2
28
+ end
29
+ if level == :patch
30
+ parts[2] += 1
31
+ significant_index = 3
32
+ end
33
+ parts.map.with_index { |_p, i| parts[i] = 0 if i >= significant_index }
34
+ parts.join('.')
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,81 @@
1
+ unless defined?(Rails)
2
+ task :environment do
3
+ require 'erb'
4
+ require './app'
5
+
6
+ fail 'ActiveRecord Not Found' unless Module.const_defined?(:ActiveRecord)
7
+ end
8
+
9
+ namespace :db do
10
+ desc 'Migrate the database through scripts in db/migrate. Target specific version with VERSION=x'
11
+ task migrate: :environment do
12
+ ActiveRecord::Migrator.migrate('db/migrate', ENV['VERSION'] ? ENV['VERSION'].to_i : nil)
13
+ Rake::Task['db:schema:dump'].invoke unless Gris.env.production?
14
+ end
15
+
16
+ desc 'Rollback to a previous migration. Go back multiple steps with STEP=x'
17
+ task rollback: :environment do
18
+ ActiveRecord::Migration.verbose = true
19
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
20
+ ActiveRecord::Migrator.rollback('db/migrate', step)
21
+ end
22
+
23
+ desc 'Create the database'
24
+ task create: :environment do
25
+ db = YAML.load(ERB.new(File.read('./config/database.yml')).result)[Gris.env]
26
+
27
+ options = {}.tap do |o|
28
+ o[:adapter] = db['adapter']
29
+ o[:database] = 'postgres' if db['adapter'] == 'postgresql'
30
+ end
31
+
32
+ ActiveRecord::Base.establish_connection(options)
33
+ ActiveRecord::Base.connection.create_database(db['database'])
34
+ end
35
+
36
+ desc 'Delete the database'
37
+ task drop: :environment do
38
+ db = YAML.load(ERB.new(File.read('./config/database.yml')).result)[Gris.env]
39
+
40
+ options = {}.tap do |o|
41
+ o[:adapter] = db['adapter']
42
+ o[:database] = 'postgres' if db['adapter'] == 'postgresql'
43
+ end
44
+
45
+ ActiveRecord::Base.establish_connection(options)
46
+ ActiveRecord::Base.connection.drop_database(db['database'])
47
+ end
48
+
49
+ desc 'Create the test database'
50
+ task reset: :environment do
51
+ Rake::Task['db:drop'].invoke
52
+ Rake::Task['db:create'].invoke
53
+ Rake::Task['db:schema:load'].invoke
54
+ end
55
+
56
+ namespace :schema do
57
+ desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
58
+ task dump: :environment do
59
+ require 'active_record/schema_dumper'
60
+ File.open(ENV['SCHEMA'] || 'db/schema.rb', 'w') do |file|
61
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
62
+ end
63
+ end
64
+
65
+ desc 'Load a schema.rb file into the database'
66
+ task load: :environment do
67
+ file = ENV['SCHEMA'] || 'db/schema.rb'
68
+ db = YAML.load(ERB.new(File.read('./config/database.yml')).result)[Gris.env]
69
+ ActiveRecord::Base.establish_connection(db)
70
+ ActiveRecord::Schema.verbose = true
71
+ load(file)
72
+ end
73
+ end
74
+
75
+ desc 'Load the seed data from db/seeds.rb'
76
+ task seed: :environment do
77
+ ActiveRecord::Tasks::DatabaseTasks.seed_loader = Gris::ActiveRecordSeeder.new './db/seeds.rb'
78
+ ActiveRecord::Tasks::DatabaseTasks.load_seed
79
+ end
80
+ end
81
+ end