napa 0.4.0 → 0.4.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e880773f7d012f8c314fd0d58baf8b321cc0970d
4
- data.tar.gz: 0610b2934b4e1edc1a72a0f60883b116240a1f3c
3
+ metadata.gz: 99dd7c64867542bf20e480334250d1e47c271df0
4
+ data.tar.gz: 870471e9345f770dea420b9f0edf609dbf16cd25
5
5
  SHA512:
6
- metadata.gz: 15a72bf0f710f598bb027068fe1e9724fd8a21c5e11eae46e1656d4ac051b48dbe82aeae35b2725c1b3d1a4cf1a5692d5f92bc6732d3be3e34457ec563cce99b
7
- data.tar.gz: bafddb18590875dc3439383d62fc2d1974aadef74c4debd94937add6e9786370c69b2c39d0d0ebb2b6df5318a8cf766aba94cb9de532b91c6a89aaf7f5c9ed98
6
+ metadata.gz: ad6d3c13701b0536aaf9269e424b33ab91fb7e0cbd89b0d7e7e9b1cc8a080282fcd9a869e7161a6ebebe1f5839fe052c3087b34a9ca49444e42e832811380cc1
7
+ data.tar.gz: f46a872779294f28648f2f041850d46535146b763def899ac6dfebaaa9332984d654c67fae599b6ab978a0da6ebe279b057943cb900d7ef6815a75a21c1fa2fa
data/.travis.yml CHANGED
@@ -7,3 +7,7 @@ rvm:
7
7
  - ruby-2.0.0
8
8
 
9
9
  script: "bundle exec rspec spec --color"
10
+
11
+ addons:
12
+ code_climate:
13
+ repo_token: 8d11efee
data/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  master
2
2
  ===
3
+ * Added a reasons object to error responses to represent active record validation errors for individual attributes
4
+ * Added ability to filter sensitive data from logs.
3
5
 
4
6
  0.4.0
5
7
  ===
@@ -13,7 +15,7 @@ master
13
15
  * Added initialization hook to run code when a Napa service boots
14
16
  * Added Migration generators from Rails
15
17
  * Added rake db:seed functionality
16
- * Added some convinience methods to spec_helper
18
+ * Added some convenience methods to spec_helper
17
19
 
18
20
  0.3.0
19
21
  ===
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  [![Build Status](https://travis-ci.org/bellycard/napa.png?branch=master)](https://travis-ci.org/bellycard/napa)
2
2
  [![Dependency Status](https://gemnasium.com/bellycard/napa.png)](https://gemnasium.com/bellycard/napa)
3
+ [![Code Climate](https://codeclimate.com/github/bellycard/napa/badges/gpa.svg)](https://codeclimate.com/github/bellycard/napa)
4
+ [![Test Coverage](https://codeclimate.com/github/bellycard/napa/badges/coverage.svg)](https://codeclimate.com/github/bellycard/napa)
3
5
 
4
6
  # Napa
5
7
 
@@ -47,7 +49,7 @@ Commands:
47
49
 
48
50
 
49
51
  ### Console
50
- Similar to the Rails console, load an IRB sesson with your applications environment by running:
52
+ Similar to the Rails console, load an IRB session with your applications environment by running:
51
53
 
52
54
  ```
53
55
  napa console
@@ -127,6 +129,27 @@ ActiveRecord::Base.logger = Napa::Logger.logger
127
129
  ```ruby
128
130
  Napa::Logger.logger.debug 'Some Debug Message'
129
131
  ```
132
+
133
+ ### Scrubbing Logs of Sensitive Data
134
+
135
+ Some requests may contain sensitive information, such as passwords or credit card numbers. In order to protect this information, they should be filtered out from logs.
136
+
137
+ To do so, add the following line to an initializer:
138
+ ```ruby
139
+ Napa::ParamSanitizer.filter_params = [:password, :password_confirmation, :cvv, :card_number]
140
+ ```
141
+ Note that the keys in the array above are just examples. They should be replaced with the parameters that have sensitive data in their value.
142
+
143
+ Example **unfiltered** request ( ... denotes other information):
144
+ ```
145
+ { ... "message":{"request":{"method":"POST","path":"/example","query":"name=Test%20User%200039\u0026password=password", ... "params":{"name":"Test User 0039","password":"password"} ...}}}
146
+ ```
147
+
148
+ Example **filtered** request ( ... denotes other information):
149
+ ```
150
+ { ... "message":{"request":{"method":"POST","path":"/example","query":"name=Test%20User%200039\u0026password=[FILTERED]", ... "params":{"name":"Test User 0039","password":"[FILTERED]"} ...}}}
151
+ ```
152
+
130
153
  ### StatsD
131
154
  There are two middlewares available to enable StatsD reporting, `RequestStats` and `DatabaseStats`. They can be enabled independently in your `config.ru` file:
132
155
 
@@ -168,6 +191,20 @@ By default it will use `:memory_store`, but you can override it to use any other
168
191
  Napa.cache = :dalli_store
169
192
  ```
170
193
 
194
+ ### Sorting
195
+
196
+ Napa has an optional module you can include in any Api called
197
+ `Napa::SortableApi`. To include this, add `include SortableApi` in the
198
+ `helpers` block of the Api.
199
+
200
+ `SortableApi` takes in a parameter for sort in the format of
201
+ `field1,field2,-field3`, where `field1` and `field2` are used to sort
202
+ ascending, and `field3` is sorted descending. For example,
203
+ `-field4,field1` would be equivalent to `ORDER BY field4 DESC, field1'.
204
+
205
+ Call `sorted_from_params(ar_relation, params[:sort])` passing in an
206
+ `ActiveRecord::Relation` for `ar_relation`, and a comma-delimited string of field names for `params[:sort]`.
207
+
171
208
  ## Bugs & Feature Requests
172
209
  Please add an issue in [Github](https://github.com/bellycard/napa/issues) if you discover a bug or have a feature request.
173
210
 
@@ -11,6 +11,15 @@ module Napa
11
11
  rack_response(err.to_json, 404)
12
12
  end
13
13
  modified_class.rescue_from ::ActiveRecord::RecordInvalid do |e|
14
+ err = Napa::JsonError.new(:unprocessable_entity, e.message, e.record.errors.messages)
15
+ Napa::Logger.logger.debug Napa::Logger.response(422, {}, err)
16
+ rack_response(err.to_json, 422)
17
+ end
18
+ end
19
+
20
+ # if AASM is being used, rescue from invalid transitions
21
+ if defined?(::AASM)
22
+ modified_class.rescue_from ::AASM::InvalidTransition do |e|
14
23
  err = Napa::JsonError.new(:unprocessable_entity, e.message)
15
24
  Napa::Logger.logger.debug Napa::Logger.response(422, {}, err)
16
25
  rack_response(err.to_json, 422)
@@ -10,8 +10,8 @@ module Napa
10
10
  end
11
11
  end
12
12
 
13
- def present_error(code, message = '')
14
- Napa::JsonError.new(code, message)
13
+ def present_error(code, message = '', reasons={})
14
+ Napa::JsonError.new(code, message, reasons)
15
15
  end
16
16
 
17
17
  def permitted_params(options = {})
@@ -1,8 +1,9 @@
1
1
  module Napa
2
2
  class JsonError
3
- def initialize(code, message)
3
+ def initialize(code, message, reasons={})
4
4
  @code = code
5
5
  @message = message
6
+ @reasons = reasons
6
7
  end
7
8
 
8
9
  def to_json(options = {})
@@ -10,12 +11,14 @@ module Napa
10
11
  end
11
12
 
12
13
  def to_h
13
- {
14
+ e = {
14
15
  error: {
15
16
  code: @code,
16
17
  message: @message
17
18
  }
18
19
  }
20
+ e[:error][:reasons] = @reasons if @reasons.present?
21
+ e
19
22
  end
20
23
  end
21
24
  end
@@ -1,6 +1,10 @@
1
+ require 'napa/param_sanitizer'
2
+
1
3
  module Napa
2
4
  class Middleware
3
5
  class Logger
6
+ include Napa::ParamSanitizer
7
+
4
8
  def initialize(app)
5
9
  @app = app
6
10
  end
@@ -26,7 +30,8 @@ module Napa
26
30
 
27
31
  def format_request(env)
28
32
  request = Rack::Request.new(env)
29
- params = request.params
33
+ params = request.params
34
+
30
35
  begin
31
36
  params = JSON.parse(request.body.read) if env['CONTENT_TYPE'] == 'application/json'
32
37
  rescue
@@ -36,11 +41,11 @@ module Napa
36
41
  request_data = {
37
42
  method: request.request_method,
38
43
  path: request.path_info,
39
- query: request.query_string,
44
+ query: filtered_query_string(request.query_string),
40
45
  host: Napa::Identity.hostname,
41
46
  pid: Napa::Identity.pid,
42
47
  revision: Napa::Identity.revision,
43
- params: params,
48
+ params: filtered_parameters(params),
44
49
  remote_ip: request.ip
45
50
  }
46
51
  request_data[:user_id] = current_user.try(:id) if defined?(current_user)
@@ -0,0 +1,30 @@
1
+ require 'action_dispatch'
2
+
3
+ module Napa
4
+ module ParamSanitizer
5
+ include ActionDispatch::Http::FilterParameters
6
+
7
+ mattr_accessor :filter_params
8
+
9
+ KV_REGEXP = '[^&;=]+'
10
+ PAIR_REGEXP = %r{(#{KV_REGEXP})=(#{KV_REGEXP})}
11
+
12
+ def filter_params
13
+ @@filter_params || []
14
+ end
15
+
16
+ def parameter_filter
17
+ parameter_filter_for(filter_params)
18
+ end
19
+
20
+ def filtered_parameters(params)
21
+ parameter_filter.filter(params)
22
+ end
23
+
24
+ def filtered_query_string(query_string)
25
+ query_string.gsub(PAIR_REGEXP) do |_|
26
+ parameter_filter.filter([[$1, $2]]).first.join("=")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ if defined?(ActiveRecord)
2
+ module Napa
3
+ module SortableApi
4
+ def sort_from_params(objects, sort_params)
5
+ return objects if sort_params.nil?
6
+
7
+ sort_fields = sort_params.split(",")
8
+ sort_fields.each do |sort_field|
9
+ sort_field = (sort_field[1..-1] + " DESC") if sort_field.start_with?("-")
10
+ objects = objects.order(sort_field)
11
+ end
12
+
13
+ return objects
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,15 +1,19 @@
1
1
  module Napa
2
2
  module StatsDTimer
3
- def report_time(timer_name)
4
- start_time = Time.now
5
- yield
6
- response_time = (Time.now - start_time) * 1000 # statsd reports timers in milliseconds
7
- Napa::Stats.emitter.timing(timer_name, response_time)
3
+ def report_time(timer_name, sample_rate: 1)
4
+ if (Time.now.to_f * 1000).to_i % sample_rate == 0
5
+ start_time = Time.now
6
+ yield
7
+ response_time = (Time.now - start_time) * 1000 # statsd reports timers in milliseconds
8
+ Napa::Stats.emitter.timing(timer_name, response_time)
9
+ else
10
+ yield
11
+ end
8
12
  end
9
13
 
10
14
  module ClassMethods
11
- def report_time(timer_name)
12
- new.report_time(timer_name) do
15
+ def report_time(timer_name, sample_rate: 1)
16
+ new.report_time(timer_name, sample_rate: sample_rate) do
13
17
  yield
14
18
  end
15
19
  end
data/lib/napa/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Napa
2
- VERSION = '0.4.0'
2
+ VERSION = '0.4.1'
3
3
 
4
4
  class Version
5
5
  class << self
data/lib/napa.rb CHANGED
@@ -32,6 +32,7 @@ require 'napa/middleware/authentication'
32
32
  require 'napa/middleware/request_stats'
33
33
  require 'napa/middleware/database_stats'
34
34
  require 'napa/authentication'
35
+ require 'napa/sortable_api'
35
36
 
36
37
  require 'napa/deprecations'
37
38
  require 'napa/deploy'
data/napa.gemspec CHANGED
@@ -5,8 +5,9 @@ Gem::Specification.new do |gem|
5
5
  gem.authors = ["Darby Frey"]
6
6
  gem.email = ["darby@bellycard.com"]
7
7
  gem.description = %q{A simple framework for building APIs with Grape}
8
- gem.summary = %q{A simple framework for building APIs with Grape}
9
- gem.homepage = ""
8
+ gem.summary = %q{A rack-based framework wrapping around the Grape REST-like framework for Ruby.}
9
+ gem.homepage = "https://tech.bellycard.com"
10
+ gem.licenses = ['MIT']
10
11
 
11
12
  gem.files = `git ls-files`.split($\)
12
13
  gem.executables << 'napa'
@@ -17,22 +18,25 @@ Gem::Specification.new do |gem|
17
18
  gem.required_ruby_version = '>= 2.0'
18
19
 
19
20
 
20
- gem.add_dependency 'rake'
21
- gem.add_dependency 'logging'
22
- gem.add_dependency 'dotenv'
23
- gem.add_dependency 'octokit'
24
- gem.add_dependency 'thor'
25
- gem.add_dependency 'virtus'
26
- gem.add_dependency 'grape'
27
- gem.add_dependency 'grape-swagger'
28
- gem.add_dependency 'roar'
29
- gem.add_dependency 'statsd-ruby'
30
- gem.add_dependency 'racksh'
31
- gem.add_dependency 'git'
21
+ gem.add_dependency 'rake', '~> 10.3'
22
+ gem.add_dependency 'logging', '~> 1.8'
23
+ gem.add_dependency 'dotenv', '~> 1.0'
24
+ gem.add_dependency 'octokit', '~> 3.5'
25
+ gem.add_dependency 'thor', '~> 0.19'
26
+ gem.add_dependency 'virtus', '~> 1.0'
27
+ gem.add_dependency 'grape', '~> 0.9'
28
+ gem.add_dependency 'grape-swagger', '~> 0.8'
29
+ gem.add_dependency 'roar', '~> 0.12'
30
+ gem.add_dependency 'statsd-ruby', '~> 1.2'
31
+ gem.add_dependency 'racksh', '~> 1.0'
32
+ gem.add_dependency 'git', '~> 1.2'
33
+ gem.add_dependency 'actionpack', '>= 3.2'
32
34
 
33
- gem.add_development_dependency 'rspec'
34
- gem.add_development_dependency 'pry'
35
- gem.add_development_dependency 'rubocop'
36
- gem.add_development_dependency 'activerecord', '~>3.2.2'
37
- gem.add_development_dependency 'sqlite3'
35
+ gem.add_development_dependency 'rspec', '~> 3.1'
36
+ gem.add_development_dependency 'pry', '~> 0.10'
37
+ gem.add_development_dependency 'rubocop', '~> 0.25'
38
+ gem.add_development_dependency 'activerecord', '~> 3.2'
39
+ gem.add_development_dependency 'sqlite3', '~> 1.3'
40
+ gem.add_development_dependency 'acts_as_fu', '~> 0'
41
+ gem.add_development_dependency 'codeclimate-test-reporter'
38
42
  end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'rack/test'
3
+
4
+ describe Napa::GrapeExtenders do
5
+ include Rack::Test::Methods
6
+
7
+ before do
8
+ allow(Napa::Logger.logger).to receive(:debug)
9
+ end
10
+
11
+ subject do
12
+ Class.new(Grape::API) do
13
+ format :json
14
+ extend Napa::GrapeExtenders
15
+ end
16
+ end
17
+
18
+ def app
19
+ subject
20
+ end
21
+
22
+ describe 'ActiveRecord extensions' do
23
+ it 'rescues ActiveRecord::RecordNotFound and returns a 404' do
24
+ subject.get do
25
+ raise ActiveRecord::RecordNotFound
26
+ end
27
+
28
+ get '/'
29
+ expect(response_code).to be 404
30
+ expect(parsed_response.error.code).to eq 'record_not_found'
31
+ end
32
+ end
33
+
34
+ describe 'AASM extensions' do
35
+ it 'rescues AASM::InvalidTransition and returns a 422' do
36
+ module AASM
37
+ class InvalidTransition < StandardError
38
+ end
39
+ end
40
+
41
+ subject.get do
42
+ raise AASM::InvalidTransition
43
+ end
44
+
45
+ get '/'
46
+ expect(response_code).to be 422
47
+ expect(parsed_response.error.code).to eq 'unprocessable_entity'
48
+ end
49
+ end
50
+ end
@@ -10,5 +10,24 @@ describe Napa::JsonError do
10
10
  expect(parsed['error']['code']).to eq('code')
11
11
  expect(parsed['error']['message']).to eq('message')
12
12
  end
13
+
14
+ it 'returns a json hash with additional reasons' do
15
+ error = Napa::JsonError.new(:code, 'message', {foo: 'bar'}).to_json
16
+ parsed = JSON.parse(error)
17
+
18
+ expect(parsed['error']['code']).to eq('code')
19
+ expect(parsed['error']['message']).to eq('message')
20
+ expect(parsed['error']['reasons']['foo']).to eq('bar')
21
+ end
22
+
23
+ it 'excludes `reasons` from hash if no reasons given' do
24
+ error = Napa::JsonError.new(:code, 'message').to_json
25
+ parsed = JSON.parse(error)
26
+
27
+ expect(parsed['error']['code']).to eq('code')
28
+ expect(parsed['error']['message']).to eq('message')
29
+ expect(parsed['error']['reasons']).to be nil
30
+ end
31
+
13
32
  end
14
33
  end
@@ -0,0 +1,56 @@
1
+ require 'active_record'
2
+ require 'spec_helper'
3
+ require 'napa/sortable_api'
4
+
5
+ describe "SortableApi" do
6
+ describe "#sort_from_params" do
7
+ before do
8
+ build_model :foos do
9
+ integer :param1
10
+ integer :param2
11
+ end
12
+
13
+ @object1 = Foo.create(param1: 2, param2: 1)
14
+ @object2 = Foo.create(param1: 2, param2: 3)
15
+ @object3 = Foo.create(param1: 3, param2: 5)
16
+ @object4 = Foo.create(param1: 1, param2: 3)
17
+ @object5 = Foo.create(param1: 1, param2: 1)
18
+
19
+ @api = Object.new
20
+ @api.extend(Napa::SortableApi)
21
+ @foos = Foo.scoped
22
+ end
23
+
24
+ it "returns the sortable objects if sort_param is nil" do
25
+ expect(@api.sort_from_params(@foos, nil)).to eq(@foos)
26
+ end
27
+
28
+ it "sorts by a given parameter" do
29
+ sorted = @api.sort_from_params(@foos, "param1")
30
+ expect(sorted.last).to eq(@object3)
31
+ expect(sorted.to_sql).to end_with("ORDER BY param1")
32
+ end
33
+
34
+ it "sorts by a given parameter descending if preceded by -" do
35
+ sorted = @api.sort_from_params(@foos, "-param1")
36
+ expect(sorted.first).to eq(@object3)
37
+ expect(sorted.to_sql).to end_with("ORDER BY param1 DESC")
38
+ end
39
+
40
+ it "sorts by multiple parameters in order" do
41
+ sorted = @api.sort_from_params(@foos, "param2,param1")
42
+ expect(sorted.to_a).to eq([@object5, @object1, @object4, @object2, @object3])
43
+ expect(sorted.to_sql).to end_with("ORDER BY param2, param1")
44
+
45
+ alt_sorted = @api.sort_from_params(@foos, "param1,param2")
46
+ expect(alt_sorted.to_a).to eq([@object5, @object4, @object1, @object2, @object3])
47
+ expect(alt_sorted.to_sql).to end_with("ORDER BY param1, param2")
48
+ end
49
+
50
+ it "sorts by multiple parameters, even if descending" do
51
+ sorted = @api.sort_from_params(@foos, "-param2,param1")
52
+ expect(sorted.to_a).to eq([@object3, @object4, @object2, @object5, @object1])
53
+ expect(sorted.to_sql).to end_with("ORDER BY param2 DESC, param1")
54
+ end
55
+ end
56
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,16 +1,25 @@
1
1
  ENV['RACK_ENV'] = 'test'
2
2
 
3
3
  require 'napa/setup'
4
+ require 'acts_as_fu'
5
+
6
+ require "codeclimate-test-reporter"
7
+ CodeClimate::TestReporter.start
4
8
 
5
9
  Napa.skip_initialization = true
6
10
 
7
11
  require 'napa'
12
+ require 'napa/rspec_extensions/response_helpers'
8
13
 
9
14
  # from https://gist.github.com/adamstegman/926858
10
15
  RSpec.configure do |config|
16
+ config.include Napa::RspecExtensions::ResponseHelpers
17
+
11
18
  config.before(:all) { silence_output }
12
19
  config.after(:all) { enable_output }
13
20
 
21
+ config.include ActsAsFu
22
+
14
23
  config.before(:each) do
15
24
  allow(Napa).to receive(:initialize)
16
25
  allow(Napa::Logger).to receive_message_chain('logger.info').with(:napa_deprecation_warning)
metadata CHANGED
@@ -1,241 +1,283 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: napa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darby Frey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-23 00:00:00.000000000 Z
11
+ date: 2015-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '10.3'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '10.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: logging
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1.8'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '1.8'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: dotenv
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: octokit
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '3.5'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '3.5'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: thor
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '0.19'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '0.19'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: virtus
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ~>
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '1.0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ~>
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '1.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: grape
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ~>
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '0.9'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ~>
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '0.9'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: grape-swagger
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '>='
115
+ - - ~>
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: '0.8'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '>='
122
+ - - ~>
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: '0.8'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: roar
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '>='
129
+ - - ~>
130
130
  - !ruby/object:Gem::Version
131
- version: '0'
131
+ version: '0.12'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '>='
136
+ - - ~>
137
137
  - !ruby/object:Gem::Version
138
- version: '0'
138
+ version: '0.12'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: statsd-ruby
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '>='
143
+ - - ~>
144
144
  - !ruby/object:Gem::Version
145
- version: '0'
145
+ version: '1.2'
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - '>='
150
+ - - ~>
151
151
  - !ruby/object:Gem::Version
152
- version: '0'
152
+ version: '1.2'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: racksh
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - '>='
157
+ - - ~>
158
158
  - !ruby/object:Gem::Version
159
- version: '0'
159
+ version: '1.0'
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - '>='
164
+ - - ~>
165
165
  - !ruby/object:Gem::Version
166
- version: '0'
166
+ version: '1.0'
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: git
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: '1.2'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ~>
179
+ - !ruby/object:Gem::Version
180
+ version: '1.2'
181
+ - !ruby/object:Gem::Dependency
182
+ name: actionpack
169
183
  requirement: !ruby/object:Gem::Requirement
170
184
  requirements:
171
185
  - - '>='
172
186
  - !ruby/object:Gem::Version
173
- version: '0'
187
+ version: '3.2'
174
188
  type: :runtime
175
189
  prerelease: false
176
190
  version_requirements: !ruby/object:Gem::Requirement
177
191
  requirements:
178
192
  - - '>='
179
193
  - !ruby/object:Gem::Version
180
- version: '0'
194
+ version: '3.2'
181
195
  - !ruby/object:Gem::Dependency
182
196
  name: rspec
183
197
  requirement: !ruby/object:Gem::Requirement
184
198
  requirements:
185
- - - '>='
199
+ - - ~>
186
200
  - !ruby/object:Gem::Version
187
- version: '0'
201
+ version: '3.1'
188
202
  type: :development
189
203
  prerelease: false
190
204
  version_requirements: !ruby/object:Gem::Requirement
191
205
  requirements:
192
- - - '>='
206
+ - - ~>
193
207
  - !ruby/object:Gem::Version
194
- version: '0'
208
+ version: '3.1'
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: pry
197
211
  requirement: !ruby/object:Gem::Requirement
198
212
  requirements:
199
- - - '>='
213
+ - - ~>
200
214
  - !ruby/object:Gem::Version
201
- version: '0'
215
+ version: '0.10'
202
216
  type: :development
203
217
  prerelease: false
204
218
  version_requirements: !ruby/object:Gem::Requirement
205
219
  requirements:
206
- - - '>='
220
+ - - ~>
207
221
  - !ruby/object:Gem::Version
208
- version: '0'
222
+ version: '0.10'
209
223
  - !ruby/object:Gem::Dependency
210
224
  name: rubocop
211
225
  requirement: !ruby/object:Gem::Requirement
212
226
  requirements:
213
- - - '>='
227
+ - - ~>
214
228
  - !ruby/object:Gem::Version
215
- version: '0'
229
+ version: '0.25'
216
230
  type: :development
217
231
  prerelease: false
218
232
  version_requirements: !ruby/object:Gem::Requirement
219
233
  requirements:
220
- - - '>='
234
+ - - ~>
221
235
  - !ruby/object:Gem::Version
222
- version: '0'
236
+ version: '0.25'
223
237
  - !ruby/object:Gem::Dependency
224
238
  name: activerecord
225
239
  requirement: !ruby/object:Gem::Requirement
226
240
  requirements:
227
241
  - - ~>
228
242
  - !ruby/object:Gem::Version
229
- version: 3.2.2
243
+ version: '3.2'
230
244
  type: :development
231
245
  prerelease: false
232
246
  version_requirements: !ruby/object:Gem::Requirement
233
247
  requirements:
234
248
  - - ~>
235
249
  - !ruby/object:Gem::Version
236
- version: 3.2.2
250
+ version: '3.2'
237
251
  - !ruby/object:Gem::Dependency
238
252
  name: sqlite3
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ~>
256
+ - !ruby/object:Gem::Version
257
+ version: '1.3'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ~>
263
+ - !ruby/object:Gem::Version
264
+ version: '1.3'
265
+ - !ruby/object:Gem::Dependency
266
+ name: acts_as_fu
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ~>
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ~>
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: codeclimate-test-reporter
239
281
  requirement: !ruby/object:Gem::Requirement
240
282
  requirements:
241
283
  - - '>='
@@ -333,8 +375,10 @@ files:
333
375
  - lib/napa/output_formatters/entity.rb
334
376
  - lib/napa/output_formatters/include_nil.rb
335
377
  - lib/napa/output_formatters/representer.rb
378
+ - lib/napa/param_sanitizer.rb
336
379
  - lib/napa/rspec_extensions/response_helpers.rb
337
380
  - lib/napa/setup.rb
381
+ - lib/napa/sortable_api.rb
338
382
  - lib/napa/stats.rb
339
383
  - lib/napa/stats_d_timer.rb
340
384
  - lib/napa/version.rb
@@ -353,6 +397,7 @@ files:
353
397
  - spec/generators/migration_generator_spec.rb
354
398
  - spec/generators/readme_generator_spec.rb
355
399
  - spec/generators/scaffold_generator_spec.rb
400
+ - spec/grape_extenders_spec.rb
356
401
  - spec/grape_extensions/error_formatter_spec.rb
357
402
  - spec/grape_extensions/include_nil_spec.rb
358
403
  - spec/identity_spec.rb
@@ -363,13 +408,15 @@ files:
363
408
  - spec/middleware/authentication_spec.rb
364
409
  - spec/middleware/database_stats_spec.rb
365
410
  - spec/middleware/request_stats_spec.rb
411
+ - spec/sortable_api_spec.rb
366
412
  - spec/spec_helper.rb
367
413
  - spec/stats_d_timer_spec.rb
368
414
  - spec/stats_spec.rb
369
415
  - spec/version_spec.rb
370
416
  - tasks/version.rake
371
- homepage: ''
372
- licenses: []
417
+ homepage: https://tech.bellycard.com
418
+ licenses:
419
+ - MIT
373
420
  metadata: {}
374
421
  post_install_message:
375
422
  rdoc_options: []
@@ -387,10 +434,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
387
434
  version: '0'
388
435
  requirements: []
389
436
  rubyforge_project:
390
- rubygems_version: 2.2.2
437
+ rubygems_version: 2.0.14
391
438
  signing_key:
392
439
  specification_version: 4
393
- summary: A simple framework for building APIs with Grape
440
+ summary: A rack-based framework wrapping around the Grape REST-like framework for
441
+ Ruby.
394
442
  test_files:
395
443
  - spec/active_record_extensions/filter_by_hash_spec.rb
396
444
  - spec/active_record_extensions/seeder_spec.rb
@@ -403,6 +451,7 @@ test_files:
403
451
  - spec/generators/migration_generator_spec.rb
404
452
  - spec/generators/readme_generator_spec.rb
405
453
  - spec/generators/scaffold_generator_spec.rb
454
+ - spec/grape_extenders_spec.rb
406
455
  - spec/grape_extensions/error_formatter_spec.rb
407
456
  - spec/grape_extensions/include_nil_spec.rb
408
457
  - spec/identity_spec.rb
@@ -413,7 +462,9 @@ test_files:
413
462
  - spec/middleware/authentication_spec.rb
414
463
  - spec/middleware/database_stats_spec.rb
415
464
  - spec/middleware/request_stats_spec.rb
465
+ - spec/sortable_api_spec.rb
416
466
  - spec/spec_helper.rb
417
467
  - spec/stats_d_timer_spec.rb
418
468
  - spec/stats_spec.rb
419
469
  - spec/version_spec.rb
470
+ has_rdoc: