From ce70c06397afe88d239a1fa973b0ba2fa5d498de Mon Sep 17 00:00:00 2001 From: John Wilkinson Date: Thu, 9 Jun 2016 16:01:22 +0800 Subject: [PATCH 1/4] Delegate to Roar's represent w/o options argument Small change that seems to grant us all of the niceties of Roar's represent for free --- lib/grape/roar/decorator.rb | 2 +- lib/grape/roar/representer.rb | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/grape/roar/decorator.rb b/lib/grape/roar/decorator.rb index 923f103..84eda70 100644 --- a/lib/grape/roar/decorator.rb +++ b/lib/grape/roar/decorator.rb @@ -4,7 +4,7 @@ module Grape module Roar class Decorator < ::Roar::Decorator def self.represent(object, _options = {}) - new(object) + super(object) end end end diff --git a/lib/grape/roar/representer.rb b/lib/grape/roar/representer.rb index e24678a..44c905e 100644 --- a/lib/grape/roar/representer.rb +++ b/lib/grape/roar/representer.rb @@ -2,13 +2,14 @@ module Grape module Roar module Representer def self.included(base) + super + base.send(:include, ::Roar::Representer) base.extend(ClassMethods) end module ClassMethods def represent(object, _options = {}) - object.extend self - object + super(object) end end end From c4d0f6c0e01bd26124628db44cbf86b326312b21 Mon Sep 17 00:00:00 2001 From: John Wilkinson Date: Fri, 10 Jun 2016 01:23:28 +0800 Subject: [PATCH 2/4] Allow rbx failures and add array usage specs As per feedback in PR I had to move things around a little bit in the example representers because using the request url as the self rel only works if the resource will always be presented by itself It's still a useful example to have to demonstrate how using `env` works though, so I made sure to move it into a resource that fits that criteria. --- .travis.yml | 4 ++++ spec/decorator_spec.rb | 27 +++++++++++++++++++++------ spec/nested_representer_spec.rb | 3 ++- spec/present_with_spec.rb | 27 +++++++++++++++++++++------ spec/support/order_representer.rb | 5 +++-- spec/support/product_representer.rb | 5 ++--- 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80e020f..e4881a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,3 +11,7 @@ rvm: - 1.9.3 - jruby-19mode - rbx-2.2.10 + +matrix: + allow_failures: + - rvm: rbx-2.2.10 diff --git a/spec/decorator_spec.rb b/spec/decorator_spec.rb index 24f9290..1b88bed 100644 --- a/spec/decorator_spec.rb +++ b/spec/decorator_spec.rb @@ -15,15 +15,30 @@ def app end context 'decorator' do - before do - subject.get('/user/:id') do - present User.new(name: 'Lonestar', id: params[:id]), with: UserRepresenter + context 'with a single resource' do + before do + subject.get('/user/:id') do + present User.new(name: 'Lonestar', id: params[:id]), with: UserRepresenter + end + end + + it 'returns a single hypermedia representation' do + get '/user/666' + expect(last_response.body).to eq '{"name":"Lonestar","id":"666","links":[{"rel":"self","href":"/user/666"}]}' end end - it 'returns a hypermedia representation' do - get '/user/666' - expect(last_response.body).to eq '{"name":"Lonestar","id":"666","links":[{"rel":"self","href":"/user/666"}]}' + context 'with an array of resources' do + before do + subject.get('/users') do + present [User.new(name: 'Texassee', id: 1), User.new(name: 'Lonestar', id: 2)], with: UserRepresenter + end + end + + it 'returns an array of hypermedia representations' do + get 'users' + expect(last_response.body).to eq '[{"name":"Texassee","id":1,"links":[{"rel":"self","href":"/user/1"}]},{"name":"Lonestar","id":2,"links":[{"rel":"self","href":"/user/2"}]}]' + end end end end diff --git a/spec/nested_representer_spec.rb b/spec/nested_representer_spec.rb index f256596..90ed4fe 100644 --- a/spec/nested_representer_spec.rb +++ b/spec/nested_representer_spec.rb @@ -26,7 +26,8 @@ def app it 'returns a hypermedia representation' do get '/order/666' - expect(last_response.body).to eq '{"id":"666","client_id":42,"articles":[{"title":"One","id":1,"links":[{"rel":"self","href":"/article/1"}]},{"title":"Two","id":2,"links":[{"rel":"self","href":"/article/2"}]}],"links":[{"rel":"self","href":"/order/666"},{"rel":"items","href":"/order/666/items"}]}' + expect(last_response.body).to eq '{"id":"666","client_id":42,"articles":[{"title":"One","id":1,"links":[{"rel":"self","href":"/article/1"}]},{"title":"Two","id":2,"links":[{"rel":"self","href":"/article/2"}]}],' \ + '"links":[{"rel":"self","href":"http://example.org/order/666"},{"rel":"items","href":"/order/666/items"}]}' end end end diff --git a/spec/present_with_spec.rb b/spec/present_with_spec.rb index 2143190..2ce246a 100644 --- a/spec/present_with_spec.rb +++ b/spec/present_with_spec.rb @@ -15,15 +15,30 @@ def app end context 'using present' do - before do - subject.get('/product/:id') do - present Product.new(title: 'Lonestar', id: params[:id]), with: ProductRepresenter + context 'with a single resource' do + before do + subject.get('/product/:id') do + present Product.new(title: 'Lonestar', id: params[:id]), with: ProductRepresenter + end + end + + it 'returns a hypermedia representation' do + get '/product/666' + expect(last_response.body).to eq '{"title":"Lonestar","id":"666","links":[{"rel":"self","href":"/product/666"}]}' end end - it 'returns a hypermedia representation' do - get '/product/666' - expect(last_response.body).to eq '{"title":"Lonestar","id":"666","links":[{"rel":"self","href":"http://example.org/product/666"}]}' + context 'with an array of resources' do + before do + subject.get('/products') do + present [Product.new(title: 'Texassee', id: 1), Product.new(title: 'Lonestar', id: 2)], with: ProductRepresenter + end + end + + it 'returns an array of hypermedia representations' do + get 'products' + expect(last_response.body).to eq '[{"title":"Texassee","id":1,"links":[{"rel":"self","href":"/product/1"}]},{"title":"Lonestar","id":2,"links":[{"rel":"self","href":"/product/2"}]}]' + end end end end diff --git a/spec/support/order_representer.rb b/spec/support/order_representer.rb index 28b2496..ed24f31 100644 --- a/spec/support/order_representer.rb +++ b/spec/support/order_representer.rb @@ -9,8 +9,9 @@ module OrderRepresenter collection :articles, class: Article - link :self do - "/order/#{id}" + link :self do |opts| + request = Grape::Request.new(opts[:env]) + "#{request.url}" end link :items do diff --git a/spec/support/product_representer.rb b/spec/support/product_representer.rb index 3b558e4..c341737 100644 --- a/spec/support/product_representer.rb +++ b/spec/support/product_representer.rb @@ -8,8 +8,7 @@ module ProductRepresenter property :title property :id - link :self do |opts| - request = Grape::Request.new(opts[:env]) - "#{request.url}" + link :self do + "/product/#{id}" end end From 8cd7ca01f1b7901e35359cb65b792b4906714f0e Mon Sep 17 00:00:00 2001 From: John Wilkinson Date: Fri, 10 Jun 2016 02:34:38 +0800 Subject: [PATCH 3/4] Add a failing spec for a previous use case --- spec/present_with_spec.rb | 13 +++++++++++++ spec/support/products_representer.rb | 10 ++++++++++ 2 files changed, 23 insertions(+) create mode 100644 spec/support/products_representer.rb diff --git a/spec/present_with_spec.rb b/spec/present_with_spec.rb index 2ce246a..36b8402 100644 --- a/spec/present_with_spec.rb +++ b/spec/present_with_spec.rb @@ -40,5 +40,18 @@ def app expect(last_response.body).to eq '[{"title":"Texassee","id":1,"links":[{"rel":"self","href":"/product/1"}]},{"title":"Lonestar","id":2,"links":[{"rel":"self","href":"/product/2"}]}]' end end + + context 'with an array of resources as a resource' do + before do + subject.get('/products') do + present [Product.new(title: 'Texassee', id: 1), Product.new(title: 'Lonestar', id: 2)], with: ProductsRepresenter + end + end + + it 'returns an array of hypermedia representations' do + get 'products' + expect(last_response.body).to eq '[{"title":"Texassee","id":1,"links":[{"rel":"self","href":"/product/1"}]},{"title":"Lonestar","id":2,"links":[{"rel":"self","href":"/product/2"}]}]' + end + end end end diff --git a/spec/support/products_representer.rb b/spec/support/products_representer.rb new file mode 100644 index 0000000..8907321 --- /dev/null +++ b/spec/support/products_representer.rb @@ -0,0 +1,10 @@ +require 'roar/json/hal' +require 'support/product_representer' + +module ProductsRepresenter + include Roar::JSON::HAL + include Roar::Hypermedia + include Grape::Roar::Representer + + collection :entries, extend: ProductRepresenter, as: :products, embedded: true +end From b4e0273f8697830fa455f98a99d9bad2311bf0d4 Mon Sep 17 00:00:00 2001 From: John Wilkinson Date: Fri, 10 Jun 2016 02:45:39 +0800 Subject: [PATCH 4/4] Travis and formatting fixes --- .travis.yml | 4 ++-- spec/decorator_spec.rb | 5 ++++- spec/present_with_spec.rb | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e4881a3..38a06cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ rvm: - 2.0.0 - 1.9.3 - jruby-19mode - - rbx-2.2.10 + - rbx-2 matrix: allow_failures: - - rvm: rbx-2.2.10 + - rvm: rbx-2 diff --git a/spec/decorator_spec.rb b/spec/decorator_spec.rb index 1b88bed..78edd11 100644 --- a/spec/decorator_spec.rb +++ b/spec/decorator_spec.rb @@ -37,7 +37,10 @@ def app it 'returns an array of hypermedia representations' do get 'users' - expect(last_response.body).to eq '[{"name":"Texassee","id":1,"links":[{"rel":"self","href":"/user/1"}]},{"name":"Lonestar","id":2,"links":[{"rel":"self","href":"/user/2"}]}]' + expect(last_response.body).to eq [ + { 'name' => 'Texassee', 'id' => 1, 'links' => [{ 'rel' => 'self', 'href' => '/user/1' }] }, + { 'name' => 'Lonestar', 'id' => 2, 'links' => [{ 'rel' => 'self', 'href' => '/user/2' }] } + ].to_json end end end diff --git a/spec/present_with_spec.rb b/spec/present_with_spec.rb index 36b8402..40104d4 100644 --- a/spec/present_with_spec.rb +++ b/spec/present_with_spec.rb @@ -50,7 +50,10 @@ def app it 'returns an array of hypermedia representations' do get 'products' - expect(last_response.body).to eq '[{"title":"Texassee","id":1,"links":[{"rel":"self","href":"/product/1"}]},{"title":"Lonestar","id":2,"links":[{"rel":"self","href":"/product/2"}]}]' + expect(last_response.body).to eq [ + { 'title' => 'Texassee', 'id' => 1, 'links' => [{ 'rel' => 'self', 'href' => '/product/1' }] }, + { 'title' => 'Lonestar', 'id' => 2, 'links' => [{ 'rel' => 'self', 'href' => '/product/2' }] } + ] end end end