lib/halibut/adapter/json.rb
require 'json'
require 'halibut/core'
module Halibut::Adapter
# This adapter converts Halibut::Core::Resources to JSON encoded strings and back.
#
# @example
# resource = Halibut::Builder.new('http://example.com') do
# link "posts", '/posts'
# link "author", 'http://locks.io'
#
# property "title", 'Entry point'
# end.resource
#
# dumped = Halibut::Adapter::JSON.dump resource
# # => "{\"title\":\"Entry point\",\"_links\":{\"self\":{\"href\":\"http://example.com\"},\"posts\":{\"href\":\"/posts\"},\"author\":{\"href\":\"http://locks.io\"}}}"
#
# loaded = Halibut::Adapter::JSON.load dumped
# resource == loaded
# # => true
#
module JSON
# Returns an Halibut::Core::Resource from a JSON string
#
# @param [StringIO] json the JSON to parse
def self.parse(json)
ResourceExtractor.new(json).resource
end
# Returns a JSON string representation of an Halibut::Core::Resource
def self.dump(resource)
::JSON.dump resource.to_hash
end
private
# @deprecated Please use Halibut::Adapter::JSON.dump instead.
def self.extended(base)
base.extend InstanceMethods
end
module InstanceMethods
# Returns a JSON representation of the resource.
#
# @example
# resource = Halibut::Core::Resource.new('/post')
# resource.extend(Halibut::Adapter::JSON)
# resource.to_json
# # => "{\"_links\":{\"self\":{\"href\":\"/post\"}}}"
#
# @return [String] a JSON representation of the resource
#
# @deprecated This might go.
def to_json
warn "[Deprecation] Don't depend on this, as it might disappear soon."
::JSON.dump self.to_hash
end
end
# ResourceExtractor is responsible for deserializing an HAL resource
# from the JSON representation.
#
# @example
# extractor = ResourceExtractor.new({})
# # => #<Halibut::Adapter::JSON::ResourceExtractor:0x007f8adb92f2a8
# extractor.resource
# # => #<Halibut::Core::Resource:0x007f8add058fb0
#
class ResourceExtractor
# Straight-forward, just pass in the JSON string you want to extract the
# resource from.
#
# @example
# json = '{"_links":{"self":{"href":"http://example.com"}}}'
# ResourceExtractor.new('{}')
#
# @param [StringIO] json the json from which to extract the resource
def initialize(json)
@halibut = Halibut::Core::Resource.new
@json = ::JSON.load(json)
extract_properties
extract_links
extract_embedded_resources
end
# This method should be called when the the resource extracted is needed
def resource
@halibut
end
private
def extract_properties
properties = @json.reject {|k,v| k == '_links' }
.reject {|k,v| k == '_embedded' }
properties.each_pair do |property, value|
@halibut.set_property(property, value)
end
end
def extract_links
links = @json.fetch('_links', [])
links.each do |relation,values|
link = ([] << values).flatten
link.each do |attrs|
href = attrs.delete 'href'
@halibut.add_link(relation, href, attrs)
end
end
end
def extract_embedded_resources
resources = @json.fetch('_embedded', [])
resources.each do |relation,values|
embeds = ([] << values).flatten
embeds.
map {|embed| ::JSON.dump embed }.
map {|embed| Halibut::Adapter::JSON.parse embed }.
each {|embed| @halibut.embed_resource(relation, embed) }
end
end
end
module ConvenienceMethods
def parse_json(json_str_or_io)
Halibut::Adapter::JSON.parse(json_str_or_io)
end
end
end
end