grape-app 0.8.3 → 0.8.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3327dc14503a28d7ea05a7c3f01f4350b4686ea180c3fd7a5daee5d44d5cdff4
4
- data.tar.gz: 5eeb48e23593ea6d26aa37e0ae7b590cc7ccaa2c3a1c5c70302247c1a4f0eb97
3
+ metadata.gz: ba29de5fd70e82430c9bedfe0381fbabf43cd420d16c416e162582926f7bbec1
4
+ data.tar.gz: 71f550566eb3fccf9d66baf45c2e987bef0876a48daf139aac0eedf0746f350e
5
5
  SHA512:
6
- metadata.gz: f13cf9a87bd44430d26f2ac32ca0f2d552d71fd87c20382a009ca19ee0e3c9a2678806096faf016761b03fdb7c5e6ca8259bb2ae07dffd9e5162081026a560d0
7
- data.tar.gz: bd165a05e7d5a6a3603c22e25966d56d4bb4992f92ce4232c6008ec68d3404efd249d55e2dc5c9cae2d5c09dd246e42ba05f510c46056acfcfcf707cbbeae3f7
6
+ metadata.gz: 74835d8b690aacee9164288561974a4954823cb9cac45206e93927c17fbde803f2b13a8bbab437fea84470c36cf518d17c20b00e3459702c965e9c74522ddfd5
7
+ data.tar.gz: 97cbb35a1ade9fb541759efc71789163161c2bf255b36a94febe0ba1698a364d333dbec8a30a8e923d6f2ecbce80edffa164557737d071ae6a8016db2bde94f4
@@ -0,0 +1,21 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version: ["2.6", "2.7", "3.0"]
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby-version }}
20
+ bundler-cache: true
21
+ - run: bundle exec rake
data/.rubocop.yml CHANGED
@@ -1,8 +1,14 @@
1
- inherit_from:
2
- - https://gitlab.com/bsm/misc/raw/master/rubocop/default.yml
1
+ inherit_gem:
2
+ rubocop-bsm:
3
+ - default.yml
4
+ inherit_mode:
5
+ merge:
6
+ - Exclude
3
7
 
4
8
  AllCops:
5
- TargetRubyVersion: "2.5"
9
+ TargetRubyVersion: "2.6"
6
10
  Metrics/ParameterLists:
7
11
  Exclude:
8
12
  - lib/grape/app/helpers/caching.rb
13
+ Rake/Desc:
14
+ Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grape-app (0.8.3)
4
+ grape-app (0.8.8)
5
5
  activesupport
6
6
  grape (>= 1.2)
7
7
  grape-entity
@@ -13,95 +13,122 @@ PATH
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- activemodel (6.0.1)
17
- activesupport (= 6.0.1)
18
- activerecord (6.0.1)
19
- activemodel (= 6.0.1)
20
- activesupport (= 6.0.1)
21
- activesupport (6.0.1)
16
+ activemodel (6.1.3.1)
17
+ activesupport (= 6.1.3.1)
18
+ activerecord (6.1.3.1)
19
+ activemodel (= 6.1.3.1)
20
+ activesupport (= 6.1.3.1)
21
+ activesupport (6.1.3.1)
22
22
  concurrent-ruby (~> 1.0, >= 1.0.2)
23
- i18n (>= 0.7, < 2)
24
- minitest (~> 5.1)
25
- tzinfo (~> 1.1)
26
- zeitwerk (~> 2.2)
27
- ast (2.4.0)
28
- axiom-types (0.1.1)
29
- descendants_tracker (~> 0.0.4)
30
- ice_nine (~> 0.11.0)
31
- thread_safe (~> 0.3, >= 0.3.1)
32
- builder (3.2.3)
33
- coercible (1.0.0)
34
- descendants_tracker (~> 0.0.1)
35
- concurrent-ruby (1.1.5)
36
- descendants_tracker (0.0.4)
37
- thread_safe (~> 0.3, >= 0.3.1)
38
- diff-lcs (1.3)
39
- equalizer (0.0.11)
40
- grape (1.2.5)
23
+ i18n (>= 1.6, < 2)
24
+ minitest (>= 5.1)
25
+ tzinfo (~> 2.0)
26
+ zeitwerk (~> 2.3)
27
+ ast (2.4.2)
28
+ builder (3.2.4)
29
+ concurrent-ruby (1.1.8)
30
+ diff-lcs (1.4.4)
31
+ dry-configurable (0.12.1)
32
+ concurrent-ruby (~> 1.0)
33
+ dry-core (~> 0.5, >= 0.5.0)
34
+ dry-container (0.7.2)
35
+ concurrent-ruby (~> 1.0)
36
+ dry-configurable (~> 0.1, >= 0.1.3)
37
+ dry-core (0.5.0)
38
+ concurrent-ruby (~> 1.0)
39
+ dry-inflector (0.2.0)
40
+ dry-logic (1.1.1)
41
+ concurrent-ruby (~> 1.0)
42
+ dry-core (~> 0.5, >= 0.5)
43
+ dry-types (1.5.1)
44
+ concurrent-ruby (~> 1.0)
45
+ dry-container (~> 0.3)
46
+ dry-core (~> 0.5, >= 0.5)
47
+ dry-inflector (~> 0.1, >= 0.1.2)
48
+ dry-logic (~> 1.0, >= 1.0.2)
49
+ grape (1.5.3)
41
50
  activesupport
42
51
  builder
52
+ dry-types (>= 1.1)
43
53
  mustermann-grape (~> 1.0.0)
44
54
  rack (>= 1.3.0)
45
55
  rack-accept
46
- virtus (>= 1.0.0)
47
- grape-entity (0.7.1)
48
- activesupport (>= 4.0)
56
+ grape-entity (0.9.0)
57
+ activesupport (>= 3.0.0)
49
58
  multi_json (>= 1.3.2)
50
- i18n (1.7.0)
59
+ i18n (1.8.10)
51
60
  concurrent-ruby (~> 1.0)
52
- ice_nine (0.11.2)
53
- jaro_winkler (1.5.4)
54
- minitest (5.13.0)
55
- multi_json (1.14.1)
56
- mustermann (1.0.3)
57
- mustermann-grape (1.0.0)
58
- mustermann (~> 1.0.0)
59
- parallel (1.19.1)
60
- parser (2.6.5.0)
61
- ast (~> 2.4.0)
62
- rack (2.0.7)
61
+ minitest (5.14.4)
62
+ multi_json (1.15.0)
63
+ mustermann (1.1.1)
64
+ ruby2_keywords (~> 0.0.1)
65
+ mustermann-grape (1.0.1)
66
+ mustermann (>= 1.0.0)
67
+ parallel (1.20.1)
68
+ parser (3.0.1.0)
69
+ ast (~> 2.4.1)
70
+ rack (2.2.3)
63
71
  rack-accept (0.4.5)
64
72
  rack (>= 0.4)
65
- rack-cors (1.1.0)
73
+ rack-cors (1.1.1)
66
74
  rack (>= 2.0.0)
67
75
  rack-ssl-enforcer (0.2.9)
68
76
  rack-test (1.1.0)
69
77
  rack (>= 1.0, < 3)
70
78
  rainbow (3.0.0)
71
- rake (13.0.1)
72
- rspec (3.9.0)
73
- rspec-core (~> 3.9.0)
74
- rspec-expectations (~> 3.9.0)
75
- rspec-mocks (~> 3.9.0)
76
- rspec-core (3.9.0)
77
- rspec-support (~> 3.9.0)
78
- rspec-expectations (3.9.0)
79
+ rake (13.0.3)
80
+ regexp_parser (2.1.1)
81
+ rexml (3.2.5)
82
+ rspec (3.10.0)
83
+ rspec-core (~> 3.10.0)
84
+ rspec-expectations (~> 3.10.0)
85
+ rspec-mocks (~> 3.10.0)
86
+ rspec-core (3.10.1)
87
+ rspec-support (~> 3.10.0)
88
+ rspec-expectations (3.10.1)
79
89
  diff-lcs (>= 1.2.0, < 2.0)
80
- rspec-support (~> 3.9.0)
81
- rspec-mocks (3.9.0)
90
+ rspec-support (~> 3.10.0)
91
+ rspec-mocks (3.10.2)
82
92
  diff-lcs (>= 1.2.0, < 2.0)
83
- rspec-support (~> 3.9.0)
84
- rspec-support (3.9.0)
85
- rubocop (0.77.0)
86
- jaro_winkler (~> 1.5.1)
93
+ rspec-support (~> 3.10.0)
94
+ rspec-support (3.10.2)
95
+ rubocop (1.12.1)
87
96
  parallel (~> 1.10)
88
- parser (>= 2.6)
97
+ parser (>= 3.0.0.0)
89
98
  rainbow (>= 2.2.2, < 4.0)
99
+ regexp_parser (>= 1.8, < 3.0)
100
+ rexml
101
+ rubocop-ast (>= 1.2.0, < 2.0)
90
102
  ruby-progressbar (~> 1.7)
91
- unicode-display_width (>= 1.4.0, < 1.7)
92
- ruby-progressbar (1.10.1)
93
- sqlite3 (1.4.1)
94
- thor (0.20.3)
95
- thread_safe (0.3.6)
96
- tzinfo (1.2.5)
97
- thread_safe (~> 0.1)
98
- unicode-display_width (1.6.0)
99
- virtus (1.0.5)
100
- axiom-types (~> 0.1)
101
- coercible (~> 1.0)
102
- descendants_tracker (~> 0.0, >= 0.0.3)
103
- equalizer (~> 0.0, >= 0.0.9)
104
- zeitwerk (2.2.2)
103
+ unicode-display_width (>= 1.4.0, < 3.0)
104
+ rubocop-ast (1.4.1)
105
+ parser (>= 2.7.1.5)
106
+ rubocop-bsm (0.5.6)
107
+ rubocop (~> 1.0)
108
+ rubocop-performance
109
+ rubocop-rails
110
+ rubocop-rake
111
+ rubocop-rspec
112
+ rubocop-performance (1.10.2)
113
+ rubocop (>= 0.90.0, < 2.0)
114
+ rubocop-ast (>= 0.4.0)
115
+ rubocop-rails (2.9.1)
116
+ activesupport (>= 4.2.0)
117
+ rack (>= 1.1)
118
+ rubocop (>= 0.90.0, < 2.0)
119
+ rubocop-rake (0.5.1)
120
+ rubocop
121
+ rubocop-rspec (2.2.0)
122
+ rubocop (~> 1.0)
123
+ rubocop-ast (>= 1.1.0)
124
+ ruby-progressbar (1.11.0)
125
+ ruby2_keywords (0.0.4)
126
+ sqlite3 (1.4.2)
127
+ thor (1.1.0)
128
+ tzinfo (2.0.4)
129
+ concurrent-ruby (~> 1.0)
130
+ unicode-display_width (2.0.0)
131
+ zeitwerk (2.4.2)
105
132
 
106
133
  PLATFORMS
107
134
  ruby
@@ -113,8 +140,8 @@ DEPENDENCIES
113
140
  rack-test
114
141
  rake
115
142
  rspec
116
- rubocop
143
+ rubocop-bsm
117
144
  sqlite3
118
145
 
119
146
  BUNDLED WITH
120
- 2.0.2
147
+ 2.2.5
data/grape-app.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'grape-app'
3
- s.version = '0.8.3'
3
+ s.version = '0.8.8'
4
4
  s.authors = ['Black Square Media Ltd']
5
5
  s.email = ['info@blacksquaremedia.com']
6
6
  s.summary = %(Standalone Grape API apps)
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.test_files = `git ls-files -z -- spec/*`.split("\x0")
13
13
  s.executables = ['grape-app']
14
14
  s.require_paths = ['lib']
15
- s.required_ruby_version = '>= 2.5'
15
+ s.required_ruby_version = '>= 2.6'
16
16
 
17
17
  s.add_dependency 'activesupport'
18
18
  s.add_dependency 'grape', '>= 1.2'
@@ -27,6 +27,6 @@ Gem::Specification.new do |s|
27
27
  s.add_development_dependency 'rack-test'
28
28
  s.add_development_dependency 'rake'
29
29
  s.add_development_dependency 'rspec'
30
- s.add_development_dependency 'rubocop'
30
+ s.add_development_dependency 'rubocop-bsm'
31
31
  s.add_development_dependency 'sqlite3'
32
32
  end
data/lib/grape/app.rb CHANGED
@@ -8,11 +8,10 @@ require 'rack/cors'
8
8
  require 'rack/ssl-enforcer'
9
9
  require 'zeitwerk'
10
10
 
11
- class Grape::App < Grape::API::Instance
11
+ class Grape::App < Grape::API
12
12
  class << self
13
-
14
13
  # Run initializers
15
- def init!(root=nil)
14
+ def init!(root = nil)
16
15
  @root = Pathname.new(root) if root
17
16
 
18
17
  # Require bundle
@@ -73,11 +72,19 @@ class Grape::App < Grape::API::Instance
73
72
  config = self.config
74
73
  @middleware ||= Rack::Builder.new do
75
74
  use Rack::Cors, &config.cors if config.cors
76
- use Rack::SslEnforcer if config.force_ssl
75
+
76
+ if config.force_ssl.is_a?(Hash)
77
+ use Rack::SslEnforcer, **config.force_ssl
78
+ elsif config.force_ssl
79
+ use Rack::SslEnforcer
80
+ end
81
+
77
82
  config.middleware.each do |block|
78
83
  instance_eval(&block)
79
84
  end
80
85
 
86
+ use Grape::App::Middleware::ConnectionManagement if defined?(ActiveRecord)
87
+
81
88
  run Grape::App
82
89
  end
83
90
  end
@@ -103,3 +110,4 @@ end
103
110
  require 'grape/app/configuration'
104
111
  require 'grape/app/helpers'
105
112
  require 'grape/app/inflector'
113
+ require 'grape/app/middleware'
data/lib/grape/app/cli.rb CHANGED
@@ -24,14 +24,13 @@ module Grape::App::CLI
24
24
  def init_lib
25
25
  empty_directory File.join(name, 'lib', name)
26
26
  end
27
-
28
27
  end
29
28
 
30
29
  class Runner < Thor
31
30
  register Builder, :new, 'new NAME', 'create a new application'
32
31
 
33
32
  desc 'console ENV', 'Launch console'
34
- def console(env='development')
33
+ def console(env = 'development')
35
34
  ENV['GRAPE_ENV'] = env
36
35
  require File.expand_path('config/environment', Dir.pwd)
37
36
 
@@ -1,5 +1,4 @@
1
1
  class Grape::App::Configuration < ActiveSupport::InheritableOptions
2
-
3
2
  def middleware(&block)
4
3
  self[:middleware] ||= []
5
4
  self[:middleware].push(block) if block
@@ -22,5 +21,4 @@ class Grape::App::Configuration < ActiveSupport::InheritableOptions
22
21
  end
23
22
  end
24
23
  end
25
-
26
24
  end
@@ -17,14 +17,13 @@ module Grape::App::Helpers::Caching
17
17
  # article
18
18
  # end
19
19
  #
20
- def fresh_when(object=nil, etag: nil, last_modified: nil, **cache_control)
20
+ def fresh_when(object = nil, etag: nil, last_modified: nil, last_modified_field: :updated_at, **cache_control)
21
21
  etag ||= object
22
- last_modified ||= object.try(:updated_at) || object.try(:maximum, :updated_at)
23
-
22
+ last_modified = object.try(last_modified_field) || object.try(:maximum, last_modified_field) if last_modified.nil?
24
23
  etag = ActiveSupport::Digest.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))
25
24
  header 'ETag', etag
26
25
  header 'Last-Modified', last_modified.httpdate if last_modified
27
- cache_control(cache_control) unless cache_control.empty?
26
+ cache_control(**cache_control) unless cache_control.empty?
28
27
 
29
28
  if_modified_since = headers['If-Modified-Since']
30
29
  if_modified_since = Time.rfc2822(if_modified_since) rescue nil if if_modified_since # rubocop:disable Style/RescueModifier
@@ -49,7 +48,7 @@ module Grape::App::Helpers::Caching
49
48
  # stats = article.really_expensive_call if stale?(article)
50
49
  # end
51
50
  #
52
- def stale?(object=nil, **freshness_opts)
51
+ def stale?(object = nil, **freshness_opts)
53
52
  fresh_when(object, **freshness_opts)
54
53
  true
55
54
  end
@@ -6,7 +6,7 @@ module Grape::App::Helpers::RespondWith
6
6
  end
7
7
 
8
8
  # @param [ActiveRecord::Base] record validated record
9
- def respond_with(record, opts={})
9
+ def respond_with(record, opts = {})
10
10
  unless record.errors.empty?
11
11
  opts[:with] = Errors
12
12
  status 400
@@ -0,0 +1,5 @@
1
+ module Grape::App::Middleware
2
+ extend ActiveSupport::Autoload
3
+
4
+ autoload :ConnectionManagement
5
+ end
@@ -0,0 +1,12 @@
1
+ class Grape::App::Middleware::ConnectionManagement
2
+ def initialize(app)
3
+ @app = app
4
+ end
5
+
6
+ def call(env)
7
+ @app.call(env)
8
+ rescue ::ActiveRecord::StatementInvalid
9
+ ::ActiveRecord::Base.clear_active_connections!
10
+ raise
11
+ end
12
+ end
@@ -11,7 +11,6 @@ ActiveRecord::Tasks::DatabaseTasks.tap do |config|
11
11
  end
12
12
 
13
13
  namespace :db do
14
-
15
14
  Rake::Task['load_config'].clear
16
15
 
17
16
  task load_config: :environment do
@@ -34,12 +33,12 @@ namespace :db do
34
33
  ar_version = [ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR].join('.')
35
34
 
36
35
  FileUtils.mkdir_p(migrations_path)
37
- File.write path, <<-MIGRATION.strip_heredoc
36
+ File.write path, <<~RUBY
38
37
  class #{name.camelize} < ActiveRecord::Migration[#{ar_version}]
39
38
  def change
40
39
  end
41
40
  end
42
- MIGRATION
41
+ RUBY
43
42
  puts path
44
43
  end
45
44
 
@@ -47,5 +46,4 @@ namespace :db do
47
46
  desc 'Prepare test DB'
48
47
  task :prepare
49
48
  end
50
-
51
49
  end
@@ -1,4 +1,4 @@
1
- class API::V1 < Grape::API::Instance
1
+ class API::V1 < Grape::API
2
2
  version 'v1'
3
3
  prefix 'api'
4
4
  format :json
@@ -9,7 +9,7 @@ class API::V1 < Grape::API::Instance
9
9
  # error_response message: e.message, status: 404
10
10
  # end
11
11
 
12
- # Mount components
12
+ # Mount components:
13
+ #
13
14
  # mount API::Posts
14
-
15
15
  end
@@ -1,6 +1,8 @@
1
1
  Grape::App.configure do |config|
2
- # Force SSL
3
- # config.force_ssl = true
2
+ # Force SSL, please see https://github.com/tobmatth/rack-ssl-enforcer
3
+ # for configuration options.
4
+ #
5
+ # config.force_ssl = { strict: true }
4
6
 
5
7
  # CORS is disabled by default, please see https://github.com/cyu/rack-cors
6
8
  # for configuration options.
@@ -12,7 +12,7 @@ RSpec.configure do |config|
12
12
  DatabaseCleaner.strategy = :transaction
13
13
  DatabaseCleaner.clean_with :truncation
14
14
  end
15
- config.around :each do |example|
15
+ config.around do |example|
16
16
  DatabaseCleaner.cleaning { example.run }
17
17
  end
18
18
 
@@ -3,14 +3,46 @@ require 'spec_helper'
3
3
  RSpec.describe Grape::App::Helpers::Caching do
4
4
  include Rack::Test::Methods
5
5
 
6
- let(:app) { TestAPI }
6
+ let :app do
7
+ helper = described_class
8
+ Class.new(Grape::API) do
9
+ format :json
7
10
 
8
- it 'should handle fresh-when' do
11
+ helpers helper
12
+
13
+ get '/articles' do
14
+ scope = Article.order(:id)
15
+ opts = params[:public] ? { public: params[:public] } : {}
16
+ fresh_when(scope, **opts)
17
+ scope.to_a
18
+ end
19
+
20
+ get '/articles/never_updated' do
21
+ article = Article.first
22
+ article.updated_at = nil
23
+
24
+ fresh_when(article, last_modified_field: :created_at)
25
+ end
26
+
27
+ get '/articles/:id' do
28
+ article = Article.first
29
+ article if stale?(article, stale_if_error: 5, extras: { a: 1, b: 2 })
30
+ end
31
+ end
32
+ end
33
+ let(:created_at) { Time.at(1515151500).utc }
34
+
35
+ before do
36
+ Article.create! title: 'Welcome', created_at: created_at, updated_at: created_at + 10
37
+ Article.create! title: 'Bye', created_at: created_at, updated_at: created_at + 20
38
+ end
39
+
40
+ it 'handles fresh-when' do
9
41
  get '/articles'
10
42
  expect(last_response.status).to eq(200)
11
43
  expect(last_response.headers).to include(
12
44
  'Content-Type' => 'application/json',
13
- 'ETag' => '975ca8804565c1a569450d61090b2743',
45
+ 'ETag' => 'a5f6c4b024510c9835d8d70cbd3ed00c',
14
46
  'Last-Modified' => 'Fri, 05 Jan 2018 11:25:20 GMT',
15
47
  )
16
48
  expect(JSON.parse(last_response.body).size).to eq(2)
@@ -30,7 +62,15 @@ RSpec.describe Grape::App::Helpers::Caching do
30
62
  expect(last_response.status).to eq(200)
31
63
  end
32
64
 
33
- it 'should support cache-control' do
65
+ it 'handles fresh_when for records that were never updated' do
66
+ get '/articles/never_updated'
67
+ expect(last_response.status).to eq(200)
68
+ expect(last_response.headers).to include(
69
+ 'Last-Modified' => 'Fri, 05 Jan 2018 11:25:00 GMT',
70
+ )
71
+ end
72
+
73
+ it 'supports cache-control' do
34
74
  get '/articles?public=true'
35
75
  expect(last_response.status).to eq(200)
36
76
  expect(last_response.headers).to include(
@@ -38,26 +78,27 @@ RSpec.describe Grape::App::Helpers::Caching do
38
78
  )
39
79
  end
40
80
 
41
- it 'should handle stale? (with cache-control)' do
81
+ it 'handles stale? (with cache-control)' do
42
82
  get '/articles/1'
43
83
  expect(last_response.status).to eq(200)
44
84
  expect(last_response.headers).to include(
45
85
  'Cache-Control' => 'private, stale-if-error=5, a=1, b=2',
46
86
  'Content-Type' => 'application/json',
47
- 'ETag' => 'c4ca4238a0b923820dcc509a6f75849b',
87
+ 'ETag' => '0154407bafc97186a494a05e0652ff61',
48
88
  'Last-Modified' => 'Fri, 05 Jan 2018 11:25:10 GMT',
49
89
  )
50
90
  expect(JSON.parse(last_response.body)).to eq(
51
91
  'id' => 1,
52
92
  'title' => 'Welcome',
53
- 'updated_at' => '2018-01-05 11:25:10 UTC',
93
+ 'updated_at' => '2018-01-05T11:25:10.000Z',
94
+ 'created_at' => '2018-01-05T11:25:00.000Z',
54
95
  )
55
96
 
56
97
  get '/articles/1', {}, 'HTTP_IF_NONE_MATCH' => last_response.headers['ETag']
57
98
  expect(last_response.status).to eq(304)
58
99
  expect(last_response.headers).to include(
59
100
  'Cache-Control' => 'private, stale-if-error=5, a=1, b=2',
60
- 'ETag' => 'c4ca4238a0b923820dcc509a6f75849b',
101
+ 'ETag' => '0154407bafc97186a494a05e0652ff61',
61
102
  'Last-Modified' => 'Fri, 05 Jan 2018 11:25:10 GMT',
62
103
  )
63
104
  end
@@ -3,15 +3,32 @@ require 'spec_helper'
3
3
  RSpec.describe Grape::App::Helpers::Params do
4
4
  include Rack::Test::Methods
5
5
 
6
- let(:app) { TestAPI }
6
+ let :app do
7
+ helper = described_class
8
+ Class.new(Grape::API) do
9
+ format :json
7
10
 
8
- it 'should limit params' do
9
- post '/articles', title: 'Today', fresh: true, id: 1234, updated_at: Time.now
11
+ helpers helper
12
+
13
+ params do
14
+ optional :title
15
+ end
16
+ post '/articles' do
17
+ attrs = { id: 9, updated_at: Time.at(1515151515).utc }
18
+ attrs.update(declared_params)
19
+ Article.new(attrs)
20
+ end
21
+ end
22
+ end
23
+
24
+ it 'limits params' do
25
+ post '/articles', title: 'Today', id: 1234, updated_at: Time.now
10
26
  expect(last_response.status).to eq(201)
11
27
  expect(JSON.parse(last_response.body)).to eq(
28
+ 'created_at' => nil,
12
29
  'id' => 9,
13
30
  'title' => 'Today',
14
- 'updated_at' => '2018-01-05 11:25:15 UTC',
31
+ 'updated_at' => '2018-01-05T11:25:15.000Z',
15
32
  )
16
33
  end
17
34
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Grape::App::Middleware::ConnectionManagement do
4
+ include Rack::Test::Methods
5
+
6
+ let :app do
7
+ failing = ->(_) { raise(ActiveRecord::StatementInvalid) }
8
+ middleware = described_class
9
+ Rack::Builder.new do
10
+ use middleware
11
+ run failing
12
+ end
13
+ end
14
+
15
+ it 'clears active connections' do
16
+ ActiveRecord::Base.connection
17
+ expect(ActiveRecord::Base.connection_handler).to be_active_connections
18
+
19
+ expect { get '/' }.to raise_error(ActiveRecord::StatementInvalid)
20
+ expect(ActiveRecord::Base.connection_handler).not_to be_active_connections
21
+ end
22
+ end
@@ -4,37 +4,38 @@ RSpec.describe Grape::App do
4
4
  include Rack::Test::Methods
5
5
 
6
6
  subject { described_class }
7
+
7
8
  before { subject.init! File.expand_path('../scenario', __dir__) }
8
9
 
9
10
  def app
10
11
  subject.middleware
11
12
  end
12
13
 
13
- it 'should have an env' do
14
+ it 'has an env' do
14
15
  expect(subject.env).to be_instance_of(ActiveSupport::StringInquirer)
15
16
  expect(subject.env).to eq('test')
16
17
  end
17
18
 
18
- it 'should have an root' do
19
+ it 'has an root' do
19
20
  expect(subject.root).to be_instance_of(Pathname)
20
21
  end
21
22
 
22
- it 'should be an API instance' do
23
- expect(subject).to be < Grape::API::Instance
23
+ it 'is an API instance' do
24
+ expect(subject).to be < Grape::API
24
25
  end
25
26
 
26
- it 'should init with default time zone' do
27
+ it 'inits with default time zone' do
27
28
  expect(Time.zone.name).to eq('UTC')
28
29
  expect(Thread.new { Time.zone }.value.name).to eq('UTC')
29
30
  end
30
31
 
31
- it 'should configure i18n' do
32
+ it 'configures i18n' do
32
33
  expect(I18n.load_path).to include(subject.root.join('config', 'locales', 'en.yml').to_s)
33
34
  expect(I18n.default_locale).to eq(:en)
34
35
  expect(I18n.exception_handler).to be_instance_of(Proc)
35
36
  end
36
37
 
37
- it 'should read env specific initializers' do
38
+ it 'reads env specific initializers' do
38
39
  expect(subject.config).to include(
39
40
  :test_specific,
40
41
  :raise_on_missing_translations,
@@ -43,13 +44,13 @@ RSpec.describe Grape::App do
43
44
  )
44
45
  end
45
46
 
46
- it 'should prepare middleware' do
47
+ it 'prepares middleware' do
47
48
  expect(subject.middleware).to be_instance_of(Rack::Builder)
48
- expect(subject.middleware.send(:instance_variable_get, :@use).size).to eq(2)
49
+ expect(subject.middleware.send(:instance_variable_get, :@use).size).to eq(3)
49
50
  expect(subject.middleware.send(:instance_variable_get, :@run)).to be(subject)
50
51
  end
51
52
 
52
- it 'should apply middleware' do
53
+ it 'applies middleware' do
53
54
  header 'Origin', 'test.host'
54
55
  get '/v1/ok'
55
56
  expect(last_response).to be_ok
@@ -1,4 +1,4 @@
1
- class API::Posts < Grape::API::Instance
1
+ class API::Posts < Grape::API
2
2
  get '/posts' do
3
3
  []
4
4
  end
@@ -1,4 +1,4 @@
1
- class API::V1 < Grape::API::Instance
1
+ class API::V1 < Grape::API
2
2
  version 'v1'
3
3
  format :json
4
4
 
data/spec/spec_helper.rb CHANGED
@@ -1,61 +1,16 @@
1
1
  ENV['RACK_ENV'] ||= 'test'
2
2
  require 'grape-app'
3
3
  require 'rack/test'
4
-
5
- class Article
6
- include Virtus.model
7
-
8
- class Scope
9
- include Enumerable
10
-
11
- def maximum(*)
12
- map(&:updated_at).max
13
- end
14
-
15
- def each
16
- yield Article.new(id: 1, title: 'Welcome', updated_at: Time.at(1515151510).utc)
17
- yield Article.new(id: 2, title: 'Bye', updated_at: Time.at(1515151520).utc)
18
- end
19
- end
20
-
21
- def self.all
22
- Scope.new
23
- end
24
-
25
- attribute :id
26
- attribute :title
27
- attribute :updated_at
28
-
29
- def to_param
30
- id.to_s
4
+ require 'active_record'
5
+
6
+ ActiveRecord::Base.configurations = { 'test' => { 'adapter' => 'sqlite3', 'database' => ':memory:' } }
7
+ ActiveRecord::Base.establish_connection :test
8
+ ActiveRecord::Base.connection.instance_eval do
9
+ create_table :articles do |t|
10
+ t.string :title
11
+ t.timestamps
31
12
  end
32
13
  end
33
14
 
34
- class TestAPI < Grape::API::Instance
35
- format :json
36
-
37
- helpers Grape::App::Helpers::Caching
38
- helpers Grape::App::Helpers::Params
39
-
40
- get '/articles' do
41
- scope = Article.all
42
- opts = params[:public] ? { public: params[:public] } : {}
43
- fresh_when(scope, **opts)
44
- scope.map(&:to_hash)
45
- end
46
-
47
- get '/articles/:id' do
48
- article = Article.all.first
49
- article.to_hash if stale?(article, stale_if_error: 5, extras: { a: 1, b: 2 })
50
- end
51
-
52
- params do
53
- requires :title
54
- optional :fresh
55
- end
56
- post '/articles' do
57
- attrs = { id: 9, updated_at: Time.at(1515151515).utc }
58
- attrs.update(declared_params)
59
- Article.new(attrs).to_hash
60
- end
15
+ class Article < ActiveRecord::Base
61
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-app
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.8.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Black Square Media Ltd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-09 00:00:00.000000000 Z
11
+ date: 2021-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -179,7 +179,7 @@ dependencies:
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
181
  - !ruby/object:Gem::Dependency
182
- name: rubocop
182
+ name: rubocop-bsm
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
@@ -215,9 +215,9 @@ extensions: []
215
215
  extra_rdoc_files: []
216
216
  files:
217
217
  - ".editorconfig"
218
+ - ".github/workflows/test.yml"
218
219
  - ".gitignore"
219
220
  - ".rubocop.yml"
220
- - ".travis.yml"
221
221
  - Gemfile
222
222
  - Gemfile.lock
223
223
  - LICENSE
@@ -236,6 +236,8 @@ files:
236
236
  - lib/grape/app/inflector.rb
237
237
  - lib/grape/app/initializers/post.rb
238
238
  - lib/grape/app/initializers/pre.rb
239
+ - lib/grape/app/middleware.rb
240
+ - lib/grape/app/middleware/connection_management.rb
239
241
  - lib/grape/app/tasks.rb
240
242
  - lib/grape/app/tasks/core.rake
241
243
  - lib/grape/app/tasks/databases.rake
@@ -255,6 +257,7 @@ files:
255
257
  - lib/grape_app.rb
256
258
  - spec/grape/app/helpers/caching_spec.rb
257
259
  - spec/grape/app/helpers/params_spec.rb
260
+ - spec/grape/app/middleware/connection_management_spec.rb
258
261
  - spec/grape/app_spec.rb
259
262
  - spec/scenario/Gemfile
260
263
  - spec/scenario/app/api.rb
@@ -277,20 +280,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
277
280
  requirements:
278
281
  - - ">="
279
282
  - !ruby/object:Gem::Version
280
- version: '2.5'
283
+ version: '2.6'
281
284
  required_rubygems_version: !ruby/object:Gem::Requirement
282
285
  requirements:
283
286
  - - ">="
284
287
  - !ruby/object:Gem::Version
285
288
  version: '0'
286
289
  requirements: []
287
- rubygems_version: 3.0.6
290
+ rubygems_version: 3.1.4
288
291
  signing_key:
289
292
  specification_version: 4
290
293
  summary: Standalone Grape API apps
291
294
  test_files:
292
295
  - spec/grape/app/helpers/caching_spec.rb
293
296
  - spec/grape/app/helpers/params_spec.rb
297
+ - spec/grape/app/middleware/connection_management_spec.rb
294
298
  - spec/grape/app_spec.rb
295
299
  - spec/scenario/Gemfile
296
300
  - spec/scenario/app/api.rb
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.5
4
- - 2.6
5
- before_install:
6
- - gem install bundler