Skip to content
This repository has been archived by the owner on Apr 22, 2022. It is now read-only.

Commit

Permalink
Merge pull request #25 from mdsol/feature/hale_deserializer
Browse files Browse the repository at this point in the history
Feature/hale deserializer
  • Loading branch information
fosdev committed Jul 3, 2014
2 parents a86c760 + 7e67085 commit 3d4c8c3
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 211 deletions.
15 changes: 8 additions & 7 deletions lib/representors/serialization/hal_deserializer.rb
Expand Up @@ -8,14 +8,15 @@ module Representors
# For examples of how this format looks like check the files under spec/fixtures/hal
# TODO: support Curies http://www.w3.org/TR/2010/NOTE-curie-20101216/
class HalDeserializer < DeserializerBase
LINKS_KEY = '_links'
EMBEDDED_KEY = '_embedded'
CURIE_KEY = 'curies'
HREF = 'href'
LINKS_KEY = '_links'.freeze
EMBEDDED_KEY = '_embedded'.freeze
CURIE_KEY = 'curies'.freeze
HREF = 'href'.freeze
RESERVED_KEYS = [LINKS_KEY, EMBEDDED_KEY]

media_symbol :hal
media_type 'application/hal+json', 'application/json'

private

def setup_serialization(media)
Expand All @@ -33,9 +34,9 @@ def builder_add_from_deserialized!(builder, media)

# Properties are normal JSON keys in the HAL document. Create properties in the resulting object
def deserialize_properties!(builder, media)
# links and embedded are not properties but keywords of HAL, skipping them.
media.keys.each do |property_name|
if (property_name != LINKS_KEY) && (property_name != EMBEDDED_KEY)
# links and embedded are not properties but keywords of HAL, skipping them.
unless (RESERVED_KEYS.include?(property_name))
builder.add_attribute(property_name, media[property_name])
end
end
Expand Down
15 changes: 15 additions & 0 deletions lib/representors/serialization/hale_deserializer.rb
Expand Up @@ -4,5 +4,20 @@ module Representors
class HaleDeserializer < HalDeserializer
media_symbol :hale
media_type 'application/vnd.hale+json'

META_KEY = '_meta'.freeze
RESERVED_KEYS = HalDeserializer::RESERVED_KEYS + [META_KEY]

private

# Very complex but this will be called by the setup_serialization(media) in HalDeserializer
# TODO: refactor
def builder_add_from_deserialized!(builder, data_as_a_hash)
deserialize_properties!(builder, data_as_a_hash)

deserialize_links!(builder, data_as_a_hash)
deserialize_embedded!(builder, data_as_a_hash)
end

end
end
204 changes: 2 additions & 202 deletions spec/lib/representors/serialization/hal_deserializer_spec.rb
@@ -1,10 +1,6 @@
require 'spec_helper'

describe Representors::HalDeserializer do
subject(:deserializer) {Representors::HalDeserializer.new(document)}
let(:semantics_field) {deserializer.to_representor.properties}
let(:transitions_field) {deserializer.to_representor.transitions}
let(:embedded_field) {deserializer.to_representor.embedded }

it "initializes with a JSON document" do
expect(Representors::HalDeserializer.new({}.to_json)).to be_instance_of(Representors::HalDeserializer)
Expand All @@ -20,204 +16,8 @@
end

describe "#to_representor" do

context "empty document" do
let(:document) { {}.to_json }

it "returns a hash with no attributes, links or embedded resources" do
expect(deserializer.to_representor.properties).to be_empty
expect(deserializer.to_representor.transitions).to be_empty
expect(deserializer.to_representor.embedded).to be_empty
end
end

context 'Document with only properties' do
let(:original_hash) do
{
'title' => 'The Neverending Story',
'author' => 'Michael Ende',
'pages' => '396'
}
end
let(:document) { original_hash.to_json}

it 'return a representor with all the attributes of the document' do
expect(semantics_field).to eq(original_hash)
end

end

context 'Document with properties and links' do
let(:semantics) { { 'title' => 'The Neverending Story'}}
let(:transition_rel) { 'author'}
let(:transition_href) { '/mike'}
let(:document) do
{
'title' => 'The Neverending Story',
'_links' => {
'author' => {'href' => '/mike'}
}
}
end

it 'return a hash with all the attributes of the document' do
expect(semantics_field).to eq(semantics)
end
it 'Create a transition with the link' do
expect(transitions_field.first.rel).to eq(transition_rel)
expect(transitions_field.first.uri).to eq(transition_href)
end
it 'does not return any embedded resource' do
expect(embedded_field).to be_empty
end

it_behaves_like 'can create a representor from a hal document' do
subject(:deserializer) {Representors::HalDeserializer.new(document)}
end

context 'Document with properties, links and embedded' do
let(:semantics) { { 'title' => 'The Neverending Story'}}
let(:transition_rel) { 'author'}
let(:transition_href) { '/mike'}
let(:embedded_book) { {'content' => 'A...'} }
let(:document) do
{
'title' => 'The Neverending Story',
'_links' => {
transition_rel => {'href' => transition_href}
},
'_embedded' => {
'embedded_book' => embedded_book
}
}
end
it 'Returns a hash with all the attributes of the document' do
expect(semantics_field).to eq(semantics)
end
it 'Creates a transition with the link' do
expect(transitions_field.first.rel).to eq(transition_rel)
expect(transitions_field.first.uri).to eq(transition_href)
end

it 'Creates an embedded resource with its data' do
expect(embedded_field['embedded_book'].properties).to eq(embedded_book)
end
end


context 'Document with an embedded collection' do
let(:embedded_book1) { {'content' => 'A...'} }
let(:embedded_book2) { {'content' => 'When...'} }
let(:embedded_book3) { {'content' => 'Once upon...'} }
let(:embedded_books) { [ embedded_book1, embedded_book2, embedded_book3 ] }
let(:document) do
{
'_embedded' => {
'embedded_books' => [ embedded_book1, embedded_book2, embedded_book3 ]
}
}
end

it 'Creates three embedded resources' do
expect(embedded_field['embedded_books']).to have(embedded_books.size).items
end

it 'Creates embedded resources with its data' do
embedded_books.each_with_index do |item, index|
expect(embedded_field['embedded_books'][index].properties).to eq(item)
end
end
end

context 'Document with only a self link and a title' do
let(:href) { '/example_resource'}
let(:title) { 'super!'}
let(:document) do
{ '_links' => {
'self' => { 'href' => href, 'title' => title}
}
}
end

it 'the transition has a "self" rel' do
expect(transitions_field.first.rel).to eq('self')
end

it 'The transition has its href set properly' do
expect(transitions_field.first.uri).to eq(href)
end

it 'The transition has a title' do
expect(transitions_field.first['title']).to eq(title)
end

end

context 'Document with an array of two links under items' do
let(:first_href) {'/example_resource'}
let(:second_href) {'/lotr_resource2'}
let(:rel) { 'items'}
let(:document) do
{ '_links' => {
rel => [{ 'href' => first_href, 'title' => 'resource1'},
{ 'href' => second_href, 'title' => 'resource2'}]
}
}
end

it 'The representor has two links' do
expect(transitions_field).to have(2).items
end

it 'The transitions have a rel properly set' do
expect(transitions_field.all?{|link| link.rel == 'items'}).to be_true
end

it 'The transitions have a href properly set ' do
expect(transitions_field[0].uri).to eq(first_href)
expect(transitions_field[1].uri).to eq(second_href)
end
end

context 'Document with a link without a href' do
let(:document) do
{ '_links' => {
'self' => { 'title' => 'things'}
}
}
end

it 'raises a DeserializationError' do
expect{transitions_field}.to raise_error(Representors::DeserializationError, "All links must contain the href attribute")
end
end

context 'Document where not all links have href' do
let(:link_properties) { { 'href' => '/example_resource'} }
let(:document) do
{ '_links' => {
'items' => [{ 'title' => 'resource1'},
{ 'href' => '/example_resource2', 'title' => 'resource2'}]
}
}
end

it 'raises a DeserializationError' do
expect{transitions_field}.to raise_error(Representors::DeserializationError, "All links must contain the href attribute")
end
end

context 'Document with CURIEs' do
let(:link_properties) { { 'href' => '/example_resource'} }
let(:document) do
{ '_links' => {
'curies' => { 'href' => '/example_resource'}
}
}
end

it 'raises a DeserializationError' do
expect{transitions_field}.to raise_error(Representors::DeserializationError, "CURIE support not implemented for HAL")
end
end

end
end
44 changes: 42 additions & 2 deletions spec/lib/representors/serialization/hale_deserializer_spec.rb
Expand Up @@ -5,13 +5,53 @@ module Representors
it 'inherits from HalDeserializer' do
expect(HaleDeserializer.class.ancestors.include? HalDeserializer)
end

it 'provides the media type application/vnd.hale+json' do
expect(HaleDeserializer.media_types).to include('application/vnd.hale+json')
end

it 'provides the media symbol :hale' do
expect(HaleDeserializer.media_symbols).to include(:hale)
end

describe "#to_representor" do
it_behaves_like 'can create a representor from a hal document' do
subject(:deserializer) {Representors::HaleDeserializer.new(document)}
end

context '_meta with properties and links' do
subject(:deserializer) {Representors::HaleDeserializer.new(document)}
let(:semantics) { { 'title' => 'The Neverending Story'}}
let(:transition_rel) { 'author'}
let(:transition_href) { '/mike'}
let(:document) do
{
'title' => 'The Neverending Story',
'_links' => {
'author' => {'href' => '/mike'}
},
'_meta' => {
'any' => { 'json' => 'thing'}
}
}

it 'return a hash with all the attributes of the document' do
expect(semantics_field).to eq(semantics)
end
it 'Create a transition with the link' do
expect(transitions_field.size).to eq(1)
expect(transitions_field.first.rel).to eq(transition_rel)
expect(transitions_field.first.uri).to eq(transition_href)
end
it 'does not return any embedded resource' do
expect(embedded_field).to be_empty
end

end

end

end

end
end

0 comments on commit 3d4c8c3

Please sign in to comment.