Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start adding support for object conversion / serialization in RP 2.0
- Loading branch information
Showing
15 changed files
with
519 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
module RocketPants | ||
module Converters | ||
|
||
require 'rocket_pants/converters/base' | ||
require 'rocket_pants/converters/serializable_object' | ||
require 'rocket_pants/converters/collection' | ||
require 'rocket_pants/converters/paginated' | ||
require 'rocket_pants/converters/kaminari' | ||
require 'rocket_pants/converters/will_paginate' | ||
|
||
PAGINATED = [WillPaginate, Kaminari] | ||
COLLECTION = [*PAGINATED, Collection] | ||
INDIVIDUAL = [SerializableObject, Base] | ||
|
||
ALL = [*COLLECTION, *INDIVIDUAL] | ||
|
||
def self.fetch(object, options) | ||
converter = ALL.detect { |k| k.converts? object, options } | ||
raise "No Converter found for #{object.inspect}" unless converter | ||
converter.new object, options | ||
end | ||
|
||
def self.serialize_single(object, options) | ||
converter = INDIVIDUAL.detect { |k| k.converts? object, options } | ||
raise "No Converter found for #{object.inspect}" unless converter | ||
converter.new(object, options).convert | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module RocketPants | ||
module Converters | ||
class AMS < Base | ||
|
||
def self.support?(object, options) | ||
options[:serializer].present? || object.respond_to?(:active_model_serializer) | ||
end | ||
|
||
def convert(object, options) | ||
serializer = serializer_for object, options | ||
serializer.new(object, options.merge(root: false)).serializable_hash | ||
end | ||
|
||
private | ||
|
||
def serializer_for(object, options) | ||
options[:serializer] || object.active_model_serializer | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
module RocketPants | ||
module Converters | ||
class Base | ||
|
||
def self.converts?(object, options) | ||
true | ||
end | ||
|
||
attr_reader :object, :options | ||
|
||
def initialize(object, options) | ||
@object = object | ||
@options = options | ||
end | ||
|
||
def convert | ||
object | ||
end | ||
|
||
def metadata | ||
{} | ||
end | ||
|
||
# We default the nested key to be just response for the moment. | ||
# This will be changed to something else to make it compatible with Ember | ||
# and the like before the release of 2.0 | ||
# TODO: Finish this off. | ||
def response_key | ||
options.fetch :root, 'response' | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
module RocketPants | ||
module Converters | ||
class Collection < Base | ||
|
||
alias collection object | ||
|
||
def self.converts?(object, options) | ||
object.is_a?(Array) || object.respond_to?(:to_ary) | ||
end | ||
|
||
def convert | ||
collection.map { |object| serialize_associated(object, options) } | ||
end | ||
|
||
def metadata | ||
super.merge! count: collection.size | ||
end | ||
|
||
private | ||
|
||
def serialize_associated(associated, options) | ||
Converters.serialize_single associated, options | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module RocketPants | ||
module Converters | ||
class Kaminari < Paginated | ||
|
||
def self.converts?(object, options) | ||
object.respond_to?(:num_pages) && object.respond_to?(:current_page) | ||
end | ||
|
||
def pagination | ||
current, total, per_page = collection.current_page, collection.num_pages, collection.limit_value | ||
{ | ||
current: current, | ||
previous: (current > 1 ? (current - 1) : nil), | ||
next: (current == total ? nil : (current + 1)), | ||
per_page: per_page, | ||
pages: total, | ||
count: collection.total_count | ||
} | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
module RocketPants | ||
module Converters | ||
class Paginated < Collection | ||
|
||
def self.converts?(object, options) | ||
raise NotImplementedError.new("This must be implemented in your specified paginated converter") | ||
end | ||
|
||
def metadata | ||
super.tap do |metadata| | ||
metadata[:pagination] = pagination | ||
end | ||
end | ||
|
||
def pagination | ||
raise NotImplementedError.new("This must be implemented in your specified paginated converter.") | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module RocketPants | ||
module Converters | ||
class SerializableObject < Base | ||
|
||
METHODS = [:serializable_hash, :serializable_object] | ||
|
||
def self.converts?(object, options) | ||
METHODS.any? { |m| object.respond_to?(m) } | ||
end | ||
|
||
attr_reader :object, :options | ||
|
||
def convert | ||
method = METHODS.detect { |m| object.respond_to?(m) } | ||
object.send method, options | ||
end | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
module RocketPants | ||
module Converters | ||
class WillPaginate < Paginated | ||
|
||
def self.converts?(object, options) | ||
object.respond_to?(:total_entries) | ||
end | ||
|
||
def pagination | ||
{ | ||
previous: collection.previous_page.try(:to_i), | ||
next: collection.next_page.try(:to_i), | ||
current: collection.current_page.try(:to_i), | ||
per_page: collection.per_page.try(:to_i), | ||
count: collection.total_entries.try(:to_i), | ||
pages: collection.total_pages.try(:to_i) | ||
} | ||
end | ||
|
||
end | ||
end | ||
end |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'spec_helper' | ||
|
||
describe RocketPants::Converters::Base do | ||
|
||
it 'should always support items' do | ||
described_class.should be_converts Object.new, {} | ||
described_class.should be_converts 1, {} | ||
described_class.should be_converts "Hello World", {} | ||
end | ||
|
||
it 'should pass through the item' do | ||
object = Object.new | ||
described_class.new(object, {}).convert.should == object | ||
end | ||
|
||
it 'should have no metadata' do | ||
object = Object.new | ||
described_class.new(object, {x: 1}).metadata.should == {} | ||
end | ||
|
||
it 'should have the default response key' do | ||
object = Object.new | ||
described_class.new(object, {x: 1}).response_key.should == 'response' | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
require 'spec_helper' | ||
|
||
describe RocketPants::Converters::Collection do | ||
|
||
use_reversible_tables :users, scope: :all | ||
|
||
let!(:user) { User.create! age: 23 } | ||
|
||
it 'should have the correct hierarchy' do | ||
described_class.should be < RocketPants::Converters::Base | ||
end | ||
|
||
context 'detection' do | ||
|
||
subject { described_class } | ||
let(:options) { {} } | ||
|
||
it 'should detect arrays' do | ||
subject.should be_converts User.all.to_a, options | ||
end | ||
|
||
it 'should detect activerecord relations' do | ||
subject.should be_converts User.where('id IS NOT NULL'), options | ||
end | ||
|
||
it 'should detect items implementing .to_ary' do | ||
item = Object.new | ||
def item.to_ary; []; end | ||
subject.should be_converts item, options | ||
end | ||
|
||
it 'should not detect hashes' do | ||
subject.should_not be_converts({x: 1, y: 2}, options) | ||
end | ||
|
||
it 'should not detect individual records' do | ||
subject.should_not be_converts User.first!, options | ||
end | ||
|
||
it 'should not detect other objects' do | ||
subject.should_not be_converts 1, options | ||
subject.should_not be_converts Object.new, options | ||
subject.should_not be_converts true, options | ||
subject.should_not be_converts false, options | ||
end | ||
|
||
end | ||
|
||
it 'should serialize the individual options' do | ||
result = Object.new | ||
mock(RocketPants::Converters).serialize_single(user, anything) { result } | ||
converted = described_class.new([user], {}).convert | ||
converted.should be_a Array | ||
converted.should == [result] | ||
end | ||
|
||
it 'should work with an empty array' do | ||
described_class.new([], {}).convert.should == [] | ||
end | ||
|
||
it 'should pass the options to the children' do | ||
result = Object.new | ||
mock(RocketPants::Converters).serialize_single(user, {compact: true}) { result } | ||
converted = described_class.new([user], {compact: true}).convert | ||
converted.should be_a Array | ||
converted.should == [result] | ||
end | ||
|
||
it 'should include count in metadata' do | ||
described_class.new([], {}).metadata.should include count: 0 | ||
described_class.new([1], {}).metadata.should include count: 1 | ||
described_class.new([10, 11, 12], {}).metadata.should include count: 3 | ||
end | ||
|
||
end |
Oops, something went wrong.