Created
December 17, 2008 16:11
-
-
Save snusnu/37111 to your computer and use it in GitHub Desktop.
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
require 'rexml/document' | |
begin | |
gem('fastercsv') | |
require 'faster_csv' | |
rescue LoadError | |
nil | |
end | |
begin | |
gem('json') | |
require 'json/ext' | |
rescue LoadError | |
gem('json_pure') | |
require 'json/pure' | |
end | |
module DataMapper | |
module Serialize | |
# Serialize a Resource to JavaScript Object Notation (JSON; RFC 4627) | |
# | |
# @return <String> a JSON representation of the Resource | |
def to_json(*args) | |
options = args.first || {} | |
result = '{ ' | |
fields = [] | |
propset = properties_to_serialize(options) | |
fields += propset.map do |property| | |
"#{property.name.to_json}: #{send(property.getter).to_json}" | |
end | |
if self.respond_to?(:serialize_properties) | |
self.serialize_properties.each do |k,v| | |
fields << "#{k.to_json}: #{v.to_json}" | |
end | |
end | |
if self.class.respond_to?(:read_only_attributes) && exclude_read_only | |
self.class.read_only_attributes.each do |property| | |
fields << "#{property.to_json}: #{send(property).to_json}" | |
end | |
end | |
# add methods | |
(options[:methods] || []).each do |meth| | |
if self.respond_to?(meth) | |
fields << "#{meth.to_json}: #{send(meth).to_json}" | |
end | |
end | |
# Note: if you want to include a whole other model via relation, use :methods | |
# comments.to_json(:relationships=>{:user=>{:include=>[:first_name],:methods=>[:age]}}) | |
# add relationships | |
(options[:relationships] || {}).each do |rel,opts| | |
if self.respond_to?(rel) | |
fields << "#{rel.to_json}: #{send(rel).to_json(opts)}" | |
end | |
end | |
result << fields.join(', ') | |
result << ' }' | |
result | |
end | |
# Serialize a Resource to comma-separated values (CSV). | |
# | |
# @return <String> a CSV representation of the Resource | |
def to_csv(writer = '') | |
FasterCSV.generate(writer) do |csv| | |
row = [] | |
self.class.properties(repository.name).each do |property| | |
row << send(property.name).to_s | |
end | |
csv << row | |
end | |
end | |
# Serialize a Resource to XML | |
# | |
# @return <REXML::Document> an XML representation of this Resource | |
def to_xml(opts = {}) | |
to_xml_document(opts).to_s | |
end | |
# Serialize a Resource to YAML | |
# | |
# @return <YAML> a YAML representation of this Resource | |
def to_yaml(opts = {}) | |
YAML::quick_emit(object_id,opts) do |out| | |
out.map(nil,to_yaml_style) do |map| | |
propset = properties_to_serialize(opts) | |
propset.each do |property| | |
value = send(property.name.to_sym) | |
map.add(property.name, value.is_a?(Class) ? value.to_s : value) | |
end | |
# add methods | |
(opts[:methods] || []).each do |meth| | |
if self.respond_to?(meth) | |
map.add(meth.to_sym, send(meth)) | |
end | |
end | |
(instance_variable_get("@yaml_addes") || []).each do |k,v| | |
map.add(k.to_s,v) | |
end | |
end | |
end | |
end | |
protected | |
# Returns propreties to serialize based on :only or :exclude arrays, if provided | |
# :only takes precendence over :exclude | |
# | |
# @return <Array> properties that need to be serialized | |
def properties_to_serialize(options) | |
only_properties = Array(options[:only]) | |
excluded_properties = Array(options[:exclude]) | |
exclude_read_only = options[:without_read_only_attributes] || false | |
self.class.properties(repository.name).reject do |p| | |
if only_properties.include? p.name | |
false | |
else | |
excluded_properties.include?(p.name) || !(only_properties.empty? || only_properties.include?(p.name)) | |
end | |
end | |
end | |
# Return the name of this Resource - to be used as the root element name. | |
# This can be overloaded. | |
# | |
# @return <String> name of this Resource | |
def xml_element_name | |
Extlib::Inflection.underscore(self.class.name).tr("/", "-") | |
end | |
# Return a REXML::Document representing this Resource | |
# | |
# @return <REXML::Document> an XML representation of this Resource | |
def to_xml_document(opts={}, doc=nil) | |
doc ||= REXML::Document.new | |
root = doc.add_element(xml_element_name) | |
#TODO old code base was converting single quote to double quote on attribs | |
propset = properties_to_serialize(opts) | |
propset.each do |property| | |
value = send(property.name) | |
node = root.add_element(property.name.to_s) | |
unless property.type == String | |
node.attributes["type"] = property.type.to_s.downcase | |
end | |
node << REXML::Text.new(value.to_s) unless value.nil? | |
end | |
# add methods | |
(opts[:methods] || []).each do |meth| | |
if self.respond_to?(meth) | |
xml_name = meth.to_s.gsub(/[^a-z0-9_]/, '') | |
node = root.add_element(xml_name) | |
value = send(meth) | |
node << REXML::Text.new(value.to_s, :raw => true) unless value.nil? | |
end | |
end | |
doc | |
end | |
end # module Serialize | |
module SerializeCollection | |
def to_yaml(opts = {}) | |
# FIXME: Don't double handle the YAML (remove the YAML.load) | |
to_a.collect {|x| YAML.load(x.to_yaml(opts)) }.to_yaml | |
end | |
def to_json(*args) | |
opts = args.first || {} | |
"[" << map {|e| e.to_json(opts)}.join(",") << "]" | |
end | |
def to_xml(opts = {}) | |
to_xml_document(opts).to_s | |
end | |
def to_csv | |
result = "" | |
each do |item| | |
result << item.to_csv + "\n" | |
end | |
result | |
end | |
protected | |
def xml_element_name | |
Extlib::Inflection.pluralize(Extlib::Inflection.underscore(self.model.to_s)).tr("/", "-") | |
end | |
def to_xml_document(opts={}) | |
doc = REXML::Document.new | |
root = doc.add_element(xml_element_name) | |
root.attributes["type"] = 'array' | |
each do |item| | |
item.send(:to_xml_document, opts, root) | |
end | |
doc | |
end | |
end # module SerializeCollection | |
module Resource | |
include Serialize | |
end # module Resource | |
# the json gem adds Object#to_json, which breaks the DM proxies, since it | |
# happens *after* the proxy has been blank slated. This code removes the added | |
# method, so it is delegated correctly to the Collection | |
[ | |
Associations::OneToMany::Proxy, | |
(Associations::ManyToOne::Proxy if defined?(Associations::ManyToOne::Proxy)), | |
Associations::ManyToMany::Proxy | |
].each do |proxy| | |
[:to_json].each do |method| | |
proxy.send(:undef_method, :to_json) rescue nil | |
end | |
end | |
class Collection | |
include SerializeCollection | |
end | |
module Validate | |
class ValidationErrors | |
include SerializeCollection | |
end | |
end | |
end # module DataMapper |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment