desponders 0.2.0
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 +7 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +59 -0
- data/Rakefile +1 -0
- data/desponders.gemspec +25 -0
- data/lib/desponders/error_responder.rb +23 -0
- data/lib/desponders/http_cache_responder.rb +22 -0
- data/lib/desponders/locales/en.yml +6 -0
- data/lib/desponders/paginated_responder.rb +69 -0
- data/lib/desponders/rest_responder.rb +18 -0
- data/lib/desponders/version.rb +3 -0
- data/lib/desponders.rb +13 -0
- data/spec/desponders/error_responder_spec.rb +44 -0
- data/spec/desponders/http_cache_responder_spec.rb +58 -0
- data/spec/desponders/paginated_responder_spec.rb +108 -0
- data/spec/desponders/rest_responder_spec.rb +70 -0
- data/spec/spec_helper.rb +19 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e54fe6506dfbcfbd55b07f20c47647da2cc553bf
|
4
|
+
data.tar.gz: b0d9692bcbcceb0798ee20943ef4ed75849fa47d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 53ff2a38c22f6b6a441eda7df9e8870febd397e978afd8736e216a15311036c11ab27d0277746767981bce161b6f636f6932a3c5d7d1eae6056c1449bd29357c
|
7
|
+
data.tar.gz: 4f80b5479461aa336fe2946ae7356413ea68a9c5893c1fd86b8d8c2e10acf1c2e0d231f7d94b0636a3fa588f7f57483b3b869e3bb256e6a3e98e5d361ebefc5b
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Dscout, Inc
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
[](https://travis-ci.org/dscout/desponders)
|
2
|
+
|
3
|
+
# Desponders
|
4
|
+
|
5
|
+
A stack of light-weight responders tailored to JSON APIs.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'desponders', '0.2.0'
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
Use the provided `ApiResponder`, which includes all of the responder modules in
|
18
|
+
a sane order:
|
19
|
+
|
20
|
+
* Desponders::ErrorResponder
|
21
|
+
* Desponders::RESTResponder
|
22
|
+
* Desponders::PaginatedResponder
|
23
|
+
* Desponders::HTTPCacheResponder
|
24
|
+
|
25
|
+
Alternatively, create a `ActionController::Responder` subclass and include the
|
26
|
+
responders that you would like to use:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
class CustomResponder < ActionController::Responder
|
30
|
+
include Desponders::RESTResponder
|
31
|
+
include Desponders::HTTPCacheResponder
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
Include the responder in any controllers serving API requests:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
class ApplicationController < ActionController::Base
|
39
|
+
# Included
|
40
|
+
self.responder = Desponder::Responder
|
41
|
+
|
42
|
+
# Custom
|
43
|
+
self.responder = CustomResponder
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
## Thanks
|
48
|
+
|
49
|
+
The implementation of Desponders is based on the fanstastic work of Jose Valim
|
50
|
+
and his contributions to Responders within Rails, as well as Plataformatec's
|
51
|
+
Responders gem.
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
1. Fork it
|
56
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
57
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
58
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
59
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/desponders.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'desponders/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'desponders'
|
8
|
+
spec.version = Desponders::VERSION
|
9
|
+
spec.authors = ['Parker Selbert']
|
10
|
+
spec.email = ['parker@sorentwo.com']
|
11
|
+
spec.homepage = 'https://github.com/dscout/desponders'
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.description = 'A stack of light-weight responders tailored to JSON APIs'
|
14
|
+
spec.summary = 'A stack of light-weight responders tailored to JSON APIs'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.test_files = spec.files.grep(%r{^(spec)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_dependency 'railties', '>= 3.2', '< 5'
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 2.14.0'
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Desponders
|
2
|
+
module ErrorResponder
|
3
|
+
# If it isn't a get request and the response model has errors it
|
4
|
+
# automatically renders json with errors
|
5
|
+
def to_format
|
6
|
+
if has_errors?
|
7
|
+
controller.render json: {
|
8
|
+
message: lookup_message, errors: resource.errors
|
9
|
+
}, status: :unprocessable_entity
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def lookup_message
|
16
|
+
action = controller.action_name
|
17
|
+
lookup = ['errors', action].join('.').to_sym
|
18
|
+
options = { resource_name: resource.class.model_name.human }
|
19
|
+
|
20
|
+
I18n.t(lookup, options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Desponders
|
2
|
+
module HttpCacheResponder
|
3
|
+
def to_format
|
4
|
+
return if do_http_cache? && do_http_cache!
|
5
|
+
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def do_http_cache?
|
12
|
+
get? && ActionController::Base.perform_caching &&
|
13
|
+
resource.respond_to?(:updated_at)
|
14
|
+
end
|
15
|
+
|
16
|
+
def do_http_cache!
|
17
|
+
controller.fresh_when(etag: resource,
|
18
|
+
last_modified: resource.updated_at,
|
19
|
+
public: false)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
3
|
+
module Desponders
|
4
|
+
module PaginatedResponder
|
5
|
+
def to_format
|
6
|
+
if get? && resource.respond_to?(:paginate)
|
7
|
+
self.resource_size = resource.size
|
8
|
+
self.resource = resource.paginate(page: page, per_page: per_page)
|
9
|
+
|
10
|
+
response.headers['Link'] = link_headers
|
11
|
+
end
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_accessor :resource, :resource_size
|
19
|
+
|
20
|
+
delegate :response, :request, to: :controller
|
21
|
+
|
22
|
+
def default_page
|
23
|
+
1
|
24
|
+
end
|
25
|
+
|
26
|
+
def default_per_page
|
27
|
+
30
|
28
|
+
end
|
29
|
+
|
30
|
+
def page
|
31
|
+
(request.params[:page] || default_page).to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
def per_page
|
35
|
+
(request.params[:per_page] || default_per_page).to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def first_page
|
39
|
+
1
|
40
|
+
end
|
41
|
+
|
42
|
+
def prev_page
|
43
|
+
[first_page, page - 1].max
|
44
|
+
end
|
45
|
+
|
46
|
+
def next_page
|
47
|
+
[last_page, page + 1].min
|
48
|
+
end
|
49
|
+
|
50
|
+
def last_page
|
51
|
+
calculated = (resource_size.to_f / per_page).ceil
|
52
|
+
|
53
|
+
calculated.zero? ? 1 : calculated
|
54
|
+
end
|
55
|
+
|
56
|
+
def link_headers
|
57
|
+
base, rest = request.url.split('?')
|
58
|
+
|
59
|
+
[construct_link_rel(base, first_page, per_page, 'first'),
|
60
|
+
construct_link_rel(base, prev_page, per_page, 'prev'),
|
61
|
+
construct_link_rel(base, next_page, per_page, 'next'),
|
62
|
+
construct_link_rel(base, last_page, per_page, 'last')].join(',')
|
63
|
+
end
|
64
|
+
|
65
|
+
def construct_link_rel(base, page, per_page, rel)
|
66
|
+
%(#{base}?page=#{page}&per_page=#{per_page}; rel="#{rel}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Desponders
|
2
|
+
module RestResponder
|
3
|
+
def to_format
|
4
|
+
case
|
5
|
+
when get?
|
6
|
+
display(resource, status: :ok)
|
7
|
+
when has_errors?
|
8
|
+
super
|
9
|
+
when post?
|
10
|
+
display(resource, status: :created)
|
11
|
+
when put?
|
12
|
+
display(resource, status: :ok)
|
13
|
+
when delete?
|
14
|
+
display({}, status: :no_content)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/desponders.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'action_controller/base'
|
2
|
+
|
3
|
+
module Desponders
|
4
|
+
autoload :ErrorResponder, 'desponders/error_responder'
|
5
|
+
autoload :HttpCacheResponder, 'desponders/http_cache_responder'
|
6
|
+
autoload :PaginatedResponder, 'desponders/paginated_responder'
|
7
|
+
autoload :RestResponder, 'desponders/rest_responder'
|
8
|
+
|
9
|
+
class Railtie < ::Rails::Railtie
|
10
|
+
require 'active_support/i18n'
|
11
|
+
I18n.load_path << File.expand_path('../desponders/locales/en.yml', __FILE__)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
I18n.load_path += [File.expand_path('lib/desponders/locales/en.yml')]
|
4
|
+
|
5
|
+
describe Desponders::ErrorResponder do
|
6
|
+
class MockErrorResponder < Struct.new(:to_format)
|
7
|
+
include Desponders::ErrorResponder
|
8
|
+
|
9
|
+
attr_accessor :controller, :resource
|
10
|
+
|
11
|
+
def initialize(controller, resource)
|
12
|
+
@controller = controller
|
13
|
+
@resource = resource
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:controller) { double(:controller, action_name: 'create') }
|
18
|
+
let(:resource) { double(:resource, errors: []) }
|
19
|
+
|
20
|
+
subject(:responder) { MockErrorResponder.new(controller, resource) }
|
21
|
+
|
22
|
+
before do
|
23
|
+
resource.class.stub_chain(:model_name, :human).and_return('Mock')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'renders error messages when a non-get request has errors ' do
|
27
|
+
responder.stub(has_errors?: true)
|
28
|
+
|
29
|
+
expect(controller).to receive(:render).with(json: {
|
30
|
+
message: 'Mock could not be created',
|
31
|
+
errors: []
|
32
|
+
}, status: :unprocessable_entity)
|
33
|
+
|
34
|
+
responder.to_format
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not render without errors' do
|
38
|
+
responder.stub(has_errors?: false)
|
39
|
+
|
40
|
+
expect(controller).to_not receive(:render)
|
41
|
+
|
42
|
+
responder.to_format
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Desponders::HttpCacheResponder do
|
4
|
+
class MockHttpCacheResponderBase
|
5
|
+
def to_format
|
6
|
+
'{}'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class MockHttpCacheResponder < MockHttpCacheResponderBase
|
11
|
+
include Desponders::HttpCacheResponder
|
12
|
+
|
13
|
+
attr_accessor :controller
|
14
|
+
|
15
|
+
def initialize(controller)
|
16
|
+
@controller = controller
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:controller) { double(:controller, fresh_when: true) }
|
21
|
+
let(:resource) { double(:resource, updated_at: nil) }
|
22
|
+
let(:collection) { double(:collection) }
|
23
|
+
|
24
|
+
subject(:responder) { MockHttpCacheResponder.new(controller) }
|
25
|
+
|
26
|
+
it 'returns nothing with a single resource on get' do
|
27
|
+
responder.stub(get?: true, fresh_when: true, resource: resource)
|
28
|
+
|
29
|
+
expect(responder.to_format).to be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'passes through with multiple resources on get' do
|
33
|
+
responder.stub(get?: true, resource: collection)
|
34
|
+
|
35
|
+
expect(responder.to_format).to be_present
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'passes through without a fresh resource' do
|
39
|
+
controller.stub(fresh_when: false)
|
40
|
+
responder.stub(get?: true, resource: resource)
|
41
|
+
|
42
|
+
expect(responder.to_format).to be_present
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'passes through without a get request' do
|
46
|
+
responder.stub(get?: false, resource: resource)
|
47
|
+
|
48
|
+
expect(responder.to_format).to be_present
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'does not cache if perform_caching is false' do
|
52
|
+
responder.stub(get?: true, resource: resource)
|
53
|
+
|
54
|
+
ActionController::Base.stub(perform_caching: false)
|
55
|
+
|
56
|
+
expect(responder.to_format).to be_present
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Desponders::PaginatedResponder do
|
4
|
+
class MockPaginatedResponderBase
|
5
|
+
def to_format
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class MockPaginatedResponder < MockPaginatedResponderBase
|
10
|
+
include Desponders::PaginatedResponder
|
11
|
+
|
12
|
+
attr_accessor :controller, :resource
|
13
|
+
|
14
|
+
def initialize(controller, resource)
|
15
|
+
@controller = controller
|
16
|
+
@resource = resource
|
17
|
+
end
|
18
|
+
|
19
|
+
def get?; true; end
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:controller) { double(:controller, request: request, response: response) }
|
23
|
+
let(:paginated) { double(:paginated) }
|
24
|
+
let(:request) { double(:request, params: {}, url: 'https://example.com/missions') }
|
25
|
+
let(:response) { double(:response, headers: {}) }
|
26
|
+
let(:resource) { double(:resource, paginate: paginated, size: 100) }
|
27
|
+
|
28
|
+
subject(:responder) { MockPaginatedResponder.new(controller, resource) }
|
29
|
+
|
30
|
+
def link_header
|
31
|
+
controller.response.headers['Link']
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'with a paginatable resource on a get request' do
|
35
|
+
it 'replaces the current resource with a paginated scope' do
|
36
|
+
responder.to_format
|
37
|
+
responder.resource.should eq(paginated)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'defaults pagination to the first page' do
|
41
|
+
resource.should_receive(:paginate).with(hash_including(page: 1))
|
42
|
+
responder.to_format
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'uses provided page and per_page params' do
|
46
|
+
resource.should_receive(:paginate).with(page: 2, per_page: 25)
|
47
|
+
|
48
|
+
request.params[:page] = 2
|
49
|
+
request.params[:per_page] = 25
|
50
|
+
|
51
|
+
responder.to_format
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'injects resource urls into a LINK header' do
|
55
|
+
request.params[:page] = 2
|
56
|
+
|
57
|
+
responder.to_format
|
58
|
+
|
59
|
+
link_header.tap do |header|
|
60
|
+
header.should include('https://example.com/missions?page=1&per_page=30; rel="first"')
|
61
|
+
header.should include('https://example.com/missions?page=1&per_page=30; rel="prev"')
|
62
|
+
header.should include('https://example.com/missions?page=3&per_page=30; rel="next"')
|
63
|
+
header.should include('https://example.com/missions?page=4&per_page=30; rel="last"')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'ignores params in the request url when constructing headers' do
|
68
|
+
request.stub(url: 'https://example.com/missions?thing=1&other=2')
|
69
|
+
|
70
|
+
responder.to_format
|
71
|
+
|
72
|
+
link_header.should_not include('?thing=1&other=2')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'calculates the next page based on resource size and the per_page value' do
|
76
|
+
resource.stub(size: 500)
|
77
|
+
|
78
|
+
request.params[:page] = 3
|
79
|
+
request.params[:per_page] = 50
|
80
|
+
|
81
|
+
responder.to_format
|
82
|
+
|
83
|
+
link_header.tap do |header|
|
84
|
+
header.should include('page=2&per_page=50; rel="prev"')
|
85
|
+
header.should include('page=4&per_page=50; rel="next"')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'prevents the next and last pages from being 0' do
|
90
|
+
resource.stub(size: 0)
|
91
|
+
|
92
|
+
responder.to_format
|
93
|
+
|
94
|
+
link_header.should include('page=1&per_page=30; rel="next"')
|
95
|
+
link_header.should include('page=1&per_page=30; rel="last"')
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'calculates the last page based on resource size and the per_page value' do
|
99
|
+
resource.stub(size: 500)
|
100
|
+
|
101
|
+
request.params[:per_page] = 50
|
102
|
+
|
103
|
+
responder.to_format
|
104
|
+
|
105
|
+
link_header.should include('page=10&per_page=50; rel="last"')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Desponders::RestResponder do
|
4
|
+
class MockRestResponderBase
|
5
|
+
def to_format
|
6
|
+
'{}'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class MockRestResponder < MockRestResponderBase
|
11
|
+
include Desponders::RestResponder
|
12
|
+
|
13
|
+
attr_accessor :resource
|
14
|
+
|
15
|
+
def initialize(resource)
|
16
|
+
@resource = resource
|
17
|
+
end
|
18
|
+
|
19
|
+
def display
|
20
|
+
end
|
21
|
+
|
22
|
+
def get?; false; end
|
23
|
+
def post?; false; end
|
24
|
+
def put?; false; end
|
25
|
+
def delete?; false; end
|
26
|
+
def has_errors?; false; end
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:resource) { double(:resource) }
|
30
|
+
|
31
|
+
subject(:responder) { MockRestResponder.new(resource) }
|
32
|
+
|
33
|
+
it 'renders the resource with 200 status with a get request' do
|
34
|
+
responder.stub(get?: true)
|
35
|
+
|
36
|
+
expect(responder).to receive(:display).with(resource, status: :ok)
|
37
|
+
|
38
|
+
responder.to_format
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'renders the resource with 201 created with a create request' do
|
42
|
+
responder.stub(post?: true)
|
43
|
+
|
44
|
+
expect(responder).to receive(:display).with(resource, status: :created)
|
45
|
+
|
46
|
+
responder.to_format
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'renders the resource with a put request' do
|
50
|
+
responder.stub(put?: true)
|
51
|
+
|
52
|
+
expect(responder).to receive(:display).with(resource, status: :ok)
|
53
|
+
|
54
|
+
responder.to_format
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'renders no content with a delete request' do
|
58
|
+
responder.stub(delete?: true)
|
59
|
+
|
60
|
+
expect(responder).to receive(:display).with({}, status: :no_content)
|
61
|
+
|
62
|
+
responder.to_format
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'falls through to super with errors' do
|
66
|
+
responder.stub(has_errors?: true)
|
67
|
+
|
68
|
+
expect(responder.to_format).to eq('{}')
|
69
|
+
end
|
70
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require 'active_support'
|
5
|
+
require 'action_controller'
|
6
|
+
require 'rails/railtie'
|
7
|
+
require 'i18n'
|
8
|
+
|
9
|
+
ENV['RAILS_ENV'] = 'test'
|
10
|
+
|
11
|
+
require 'desponders'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
15
|
+
config.run_all_when_everything_filtered = true
|
16
|
+
config.filter_run :focus
|
17
|
+
|
18
|
+
config.order = 'random'
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: desponders
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Parker Selbert
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: railties
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
- - <
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.2'
|
30
|
+
- - <
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.3'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.3'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 2.14.0
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ~>
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 2.14.0
|
75
|
+
description: A stack of light-weight responders tailored to JSON APIs
|
76
|
+
email:
|
77
|
+
- parker@sorentwo.com
|
78
|
+
executables: []
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- .gitignore
|
83
|
+
- .rspec
|
84
|
+
- .travis.yml
|
85
|
+
- CHANGELOG.md
|
86
|
+
- Gemfile
|
87
|
+
- LICENSE.txt
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- desponders.gemspec
|
91
|
+
- lib/desponders.rb
|
92
|
+
- lib/desponders/error_responder.rb
|
93
|
+
- lib/desponders/http_cache_responder.rb
|
94
|
+
- lib/desponders/locales/en.yml
|
95
|
+
- lib/desponders/paginated_responder.rb
|
96
|
+
- lib/desponders/rest_responder.rb
|
97
|
+
- lib/desponders/version.rb
|
98
|
+
- spec/desponders/error_responder_spec.rb
|
99
|
+
- spec/desponders/http_cache_responder_spec.rb
|
100
|
+
- spec/desponders/paginated_responder_spec.rb
|
101
|
+
- spec/desponders/rest_responder_spec.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
homepage: https://github.com/dscout/desponders
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.0.0
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: A stack of light-weight responders tailored to JSON APIs
|
127
|
+
test_files:
|
128
|
+
- spec/desponders/error_responder_spec.rb
|
129
|
+
- spec/desponders/http_cache_responder_spec.rb
|
130
|
+
- spec/desponders/paginated_responder_spec.rb
|
131
|
+
- spec/desponders/rest_responder_spec.rb
|
132
|
+
- spec/spec_helper.rb
|