Narnach-libxml_rails 0.0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +3 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +40 -0
- data/Rakefile +28 -0
- data/init.rb +1 -0
- data/lib/bitbckt/core_ext/hash/conversions.rb +91 -0
- data/lib/libxml_rails.rb +6 -0
- data/lib/libxml_rails/active_resource.rb +2 -0
- data/lib/narnach/core_ext/array/conversions.rb +64 -0
- data/lib/narnach/core_ext/hash/conversions.rb +91 -0
- data/lib/narnach/rails_ext/active_resource.rb +64 -0
- data/libxml_rails.gemspec +34 -0
- data/spec/from_xml_spec.rb +328 -0
- data/spec/narnach/core_ext/array/conversions_spec.rb +73 -0
- data/spec/narnach/core_ext/hash/conversions_spec.rb +154 -0
- data/spec/narnach/rails_ext/active_resource_spec.rb +16 -0
- data/spec/spec_helper.rb +4 -0
- metadata +94 -0
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Brandon Mitchell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
= libxml_rails
|
2
|
+
|
3
|
+
libxml_rails is a gem/rails plugin by Brandon Mitchell. It is designed to replace the default XML processor in Rails (XmlSimple) with the C-based libxml. It requires the libxml-ruby gem.
|
4
|
+
|
5
|
+
This fork is maintained by Wes 'Narnach' Oldenbeuving.
|
6
|
+
|
7
|
+
Changes from the Brandon's version are:
|
8
|
+
* Don't rely on echoe to build the gem.
|
9
|
+
* Added Hash#to_xml_with_libxml and Array#to_xml_with_libxml
|
10
|
+
* ActiveResource::Base#to_xml uses libxml.
|
11
|
+
* ActiveResource::Formats::XmlFormat#encode uses libxml
|
12
|
+
|
13
|
+
=== Installation
|
14
|
+
|
15
|
+
libxml_rails can be installed as a rails plugin or as a stand-alone gem.
|
16
|
+
|
17
|
+
=== Gem Installation
|
18
|
+
|
19
|
+
From PROJECT_ROOT:
|
20
|
+
|
21
|
+
gem install libxml-ruby
|
22
|
+
rake install
|
23
|
+
|
24
|
+
=== Plugin Installation
|
25
|
+
|
26
|
+
From RAILS_ROOT:
|
27
|
+
|
28
|
+
script/plugin install git://github.com/Narnach/libxml_rails.git
|
29
|
+
|
30
|
+
Add the following to the configuration block in config/environment.rb:
|
31
|
+
|
32
|
+
config.gem 'libxml-ruby'
|
33
|
+
|
34
|
+
=== Gem Installation
|
35
|
+
|
36
|
+
Add the following to the configuration block in config/environment.rb:
|
37
|
+
|
38
|
+
config.gem 'Narnach-libxml_rails', :source => 'http://gems.github.com'
|
39
|
+
|
40
|
+
Copyright (c) 2008 Brandon Mitchell, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
require "rake/gempackagetask"
|
4
|
+
require 'rubygems'
|
5
|
+
|
6
|
+
################################################################################
|
7
|
+
### Gem
|
8
|
+
################################################################################
|
9
|
+
|
10
|
+
begin
|
11
|
+
# Parse gemspec using the github safety level.
|
12
|
+
file = Dir['*.gemspec'].first
|
13
|
+
data = File.read(file)
|
14
|
+
spec = nil
|
15
|
+
Thread.new { spec = eval("$SAFE = 3\n%s" % data)}.join
|
16
|
+
|
17
|
+
# Create the gem tasks
|
18
|
+
Rake::GemPackageTask.new(spec) do |package|
|
19
|
+
package.gem_spec = spec
|
20
|
+
end
|
21
|
+
rescue Exception => e
|
22
|
+
printf "WARNING: Error caught (%s): %s\n%s", e.class.name, e.message, e.backtrace[0...5].map {|l| ' %s' % l}.join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Package and install the gem for the current version'
|
26
|
+
task :install => :gem do
|
27
|
+
system "sudo gem install -l pkg/%s-%s.gem" % [spec.name, spec.version]
|
28
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'libxml_rails'))
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Bitbckt #:nodoc:
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Hash #:nodoc:
|
4
|
+
module Conversions
|
5
|
+
|
6
|
+
def self.included(klass)
|
7
|
+
klass.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def from_xml(xml)
|
12
|
+
result = LibXML::XML::Parser.string(xml).parse
|
13
|
+
if result.root.attributes['type'] == 'array'
|
14
|
+
{ result.root.name.to_s.gsub(/-/,'_') => array_from_node(result.root) }
|
15
|
+
else
|
16
|
+
{ result.root.name.to_s.gsub(/-/,'_') => xml_node_to_hash(result.root) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def xml_node_to_hash(node)
|
22
|
+
# If we are at an XML::Node, build the Hash
|
23
|
+
if node.element?
|
24
|
+
result_hash = {}
|
25
|
+
if node.children?
|
26
|
+
|
27
|
+
node.each_child do |child|
|
28
|
+
next if child.empty?
|
29
|
+
|
30
|
+
if child.attributes['type'] == 'array'
|
31
|
+
result = array_from_node(child)
|
32
|
+
elsif child.attributes['type'] == 'string' and child.children.empty?
|
33
|
+
# NOTE: Odd issue with libxml - XML::Node#empty? returns false and
|
34
|
+
# XML::Node#children? returns true when the Node contains just
|
35
|
+
# an empty string (#children == []), but has attributes.
|
36
|
+
result = ''
|
37
|
+
elsif child.attributes['type'] == 'file'
|
38
|
+
result = Object::Hash::XML_PARSING['file'].call(child.content.to_s, child.attributes)
|
39
|
+
elsif Object::Hash::XML_PARSING.include? child.attributes['type'] and not child.content.to_s.chomp.blank?
|
40
|
+
result = Object::Hash::XML_PARSING[child.attributes['type']].call(child.content.to_s)
|
41
|
+
else
|
42
|
+
result = xml_node_to_hash(child)
|
43
|
+
result['type'] = child.attributes['type'] if child.attributes['type'] and result
|
44
|
+
end
|
45
|
+
|
46
|
+
return result if child.name == 'text'
|
47
|
+
|
48
|
+
key = child.name.gsub(/-/, '_')
|
49
|
+
if result_hash[key]
|
50
|
+
if result_hash[key].is_a?(Object::Array)
|
51
|
+
result_hash[key] << result
|
52
|
+
else
|
53
|
+
result_hash[key] = [result_hash[key]] << result
|
54
|
+
end
|
55
|
+
else
|
56
|
+
result_hash[key] = result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
else
|
61
|
+
if node.attributes['type'] || node.attributes.length == 0 || node.attributes['nil'] == 'true'
|
62
|
+
result_hash = nil
|
63
|
+
else
|
64
|
+
node.each_attr do |attribute|
|
65
|
+
result_hash[attribute.name] = attribute.value.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
return result_hash
|
71
|
+
else
|
72
|
+
return node.content.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def array_from_node(node)
|
77
|
+
returning([]) do |collection|
|
78
|
+
node.each_child do |child|
|
79
|
+
next if child.empty?
|
80
|
+
collection << xml_node_to_hash(child)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Hash.class_eval { include Bitbckt::CoreExtensions::Hash::Conversions }
|
data/lib/libxml_rails.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Narnach #:nodoc:
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Array #:nodoc:
|
4
|
+
module Conversions
|
5
|
+
# Version of #to_xml copy-adjusted from ActiveSupport to work with libxml.
|
6
|
+
#
|
7
|
+
# Options not supported:
|
8
|
+
# - :indent
|
9
|
+
def to_xml_with_libxml(options = {})
|
10
|
+
raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml_with_libxml }
|
11
|
+
options.reverse_merge!({:to_string => true, :skip_instruct => false })
|
12
|
+
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
|
13
|
+
options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? first.class.to_s.underscore.pluralize : "records"
|
14
|
+
options[:root] = options[:root].to_s.dasherize if dasherize
|
15
|
+
options[:children] ||= options[:root].singularize
|
16
|
+
to_string = options.delete(:to_string)
|
17
|
+
skip_instruct = options.delete(:skip_instruct)
|
18
|
+
root = options.delete(:root).to_s
|
19
|
+
doc = nil
|
20
|
+
if skip_instruct
|
21
|
+
node = LibXML::XML::Node.new(root)
|
22
|
+
doc = node
|
23
|
+
case options[:builder]
|
24
|
+
when LibXML::XML::Document
|
25
|
+
options[:builder].root << node
|
26
|
+
when nil
|
27
|
+
options[:builder] = node
|
28
|
+
else
|
29
|
+
options[:builder] << node
|
30
|
+
end
|
31
|
+
else
|
32
|
+
options[:builder] = LibXML::XML::Document.new
|
33
|
+
options[:builder].encoding = 'UTF-8'
|
34
|
+
options[:builder].root = LibXML::XML::Node.new(root)
|
35
|
+
doc = options[:builder].root
|
36
|
+
end
|
37
|
+
doc['type'] = 'array' unless options[:skip_types]
|
38
|
+
|
39
|
+
|
40
|
+
children = options.delete(:children)
|
41
|
+
opts = options.merge({ :root => children })
|
42
|
+
|
43
|
+
unless empty?
|
44
|
+
yield doc if block_given?
|
45
|
+
each do |e|
|
46
|
+
e.to_xml_with_libxml(opts.merge!({ :skip_instruct => true, :to_string => false, :builder => doc }))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
if to_string
|
50
|
+
string = options[:builder].to_s
|
51
|
+
string << "\n" if skip_instruct # Emulate Builder behaviour
|
52
|
+
return string
|
53
|
+
else
|
54
|
+
return options[:builder]
|
55
|
+
end
|
56
|
+
end # to_xml_with_libxml
|
57
|
+
end # module Conversions
|
58
|
+
end # module Hash
|
59
|
+
end # module CoreExtensions
|
60
|
+
end # module Narnach
|
61
|
+
|
62
|
+
class Array
|
63
|
+
include Narnach::CoreExtensions::Array::Conversions
|
64
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Narnach #:nodoc:
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Hash #:nodoc:
|
4
|
+
module Conversions
|
5
|
+
XML_TYPE_NAMES = ActiveSupport::CoreExtensions::Hash::Conversions::XML_TYPE_NAMES unless defined?(XML_TYPE_NAMES)
|
6
|
+
XML_FORMATTING = ActiveSupport::CoreExtensions::Hash::Conversions::XML_FORMATTING unless defined?(XML_FORMATTING)
|
7
|
+
|
8
|
+
# Version of #to_xml copy-adjusted from ActiveSupport to work with libxml.
|
9
|
+
#
|
10
|
+
# Options supported in XMLBuilder that are/will be supported here:
|
11
|
+
# - :root, name of root node. Default to hash
|
12
|
+
# - :children, name of child nodes. Default to singular of root.
|
13
|
+
# - :skip_types
|
14
|
+
#
|
15
|
+
# Options supported in a different way:
|
16
|
+
# - :builder. Holds the active LibXML::XML::Document or LibXML::XML::Node.
|
17
|
+
# - :skip_instruct. Determine if the document encoding needs to be set. When false, a new Document is created and used as :builder. When true a new Node is created when no :builder is specified.
|
18
|
+
# - :dasherize, dasherize the node names or keep them as-is.
|
19
|
+
#
|
20
|
+
# Options known but not (yet) supported:
|
21
|
+
# - :indent, default to level 2
|
22
|
+
#
|
23
|
+
# Uses Builder's String#to_xs for escaping
|
24
|
+
def to_xml_with_libxml(options = {})
|
25
|
+
options.reverse_merge!({:root => "hash", :to_string => true })
|
26
|
+
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
|
27
|
+
root = dasherize ? options[:root].to_s.dasherize : options[:root].to_s
|
28
|
+
to_string = options.delete(:to_string)
|
29
|
+
skip_instruct = options.delete(:skip_instruct)
|
30
|
+
doc = nil
|
31
|
+
if skip_instruct
|
32
|
+
node = LibXML::XML::Node.new(root)
|
33
|
+
doc = node
|
34
|
+
case options[:builder]
|
35
|
+
when LibXML::XML::Document
|
36
|
+
options[:builder].root << node
|
37
|
+
when nil
|
38
|
+
options[:builder] = node
|
39
|
+
else
|
40
|
+
options[:builder] << node
|
41
|
+
end
|
42
|
+
else
|
43
|
+
options[:builder] = LibXML::XML::Document.new
|
44
|
+
options[:builder].encoding = 'UTF-8'
|
45
|
+
options[:builder].root = LibXML::XML::Node.new(root)
|
46
|
+
doc = options[:builder].root
|
47
|
+
end
|
48
|
+
self.each do |key, value|
|
49
|
+
case value
|
50
|
+
when ::Hash
|
51
|
+
value.to_xml_with_libxml(options.merge({ :root => key, :skip_instruct => true, :to_string => false, :builder => doc }))
|
52
|
+
when ::Array
|
53
|
+
value.to_xml_with_libxml(options.merge({ :root => key, :children => key.to_s.singularize, :skip_instruct => true, :to_string => false, :builder => doc}))
|
54
|
+
# when ::Method, ::Proc
|
55
|
+
else
|
56
|
+
if value.respond_to?(:to_xml_with_libxml)
|
57
|
+
value.to_xml_with_libxml(options.merge({ :root => key, :skip_instruct => true, :to_string => false, :builder => doc }))
|
58
|
+
else
|
59
|
+
type_name = XML_TYPE_NAMES[value.class.name]
|
60
|
+
key = dasherize ? key.to_s.dasherize : key.to_s
|
61
|
+
attributes = options[:skip_types] || value.nil? || type_name.nil? ? { } : { :type => type_name }
|
62
|
+
if value.nil?
|
63
|
+
attributes[:nil] = true
|
64
|
+
end
|
65
|
+
|
66
|
+
content = XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value
|
67
|
+
child = LibXML::XML::Node.new(key, content.to_s.to_xs)
|
68
|
+
attributes.stringify_keys.each do |akey, avalue|
|
69
|
+
child[akey] = String(avalue).to_s.to_xs
|
70
|
+
end
|
71
|
+
doc << child
|
72
|
+
end # if
|
73
|
+
end # case
|
74
|
+
end # each
|
75
|
+
yield options[:builder] if block_given?
|
76
|
+
if to_string
|
77
|
+
string = options[:builder].to_s
|
78
|
+
string << "\n" if skip_instruct # Emulate Builder behaviour
|
79
|
+
return string
|
80
|
+
else
|
81
|
+
return options[:builder]
|
82
|
+
end
|
83
|
+
end # to_xml_with_libxml
|
84
|
+
end # module Conversions
|
85
|
+
end # module Hash
|
86
|
+
end # module CoreExtensions
|
87
|
+
end # module Narnach
|
88
|
+
|
89
|
+
class Hash
|
90
|
+
include Narnach::CoreExtensions::Hash::Conversions
|
91
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
gem 'activeresource'
|
2
|
+
require 'active_resource'
|
3
|
+
require 'active_resource/formats/xml_format'
|
4
|
+
|
5
|
+
module Narnach
|
6
|
+
module RailsExt
|
7
|
+
module ActiveResource
|
8
|
+
module Base
|
9
|
+
# A method to convert the the resource to an XML string.
|
10
|
+
#
|
11
|
+
# This is a copy-adjusted version of ActiveResource's #to_xml, but
|
12
|
+
# it uses libxml for serialization instead of builder.
|
13
|
+
#
|
14
|
+
# ==== Options
|
15
|
+
# The +options+ parameter is handed off to the +to_xml_with_libxml+ method on each
|
16
|
+
# attribute, so it has the same options as the +to_xml_with_libxml+ methods in
|
17
|
+
# Active Support.
|
18
|
+
#
|
19
|
+
# * <tt>:dasherize</tt> - Boolean option to determine whether or not element names should
|
20
|
+
# replace underscores with dashes (default is <tt>false</tt>).
|
21
|
+
# * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
|
22
|
+
# that generates the XML declaration (default is <tt>false</tt>).
|
23
|
+
#
|
24
|
+
# ==== Examples
|
25
|
+
# my_group = SubsidiaryGroup.find(:first)
|
26
|
+
# my_group.to_xml
|
27
|
+
# # => <?xml version="1.0" encoding="UTF-8"?>
|
28
|
+
# # <subsidiary_group> [...] </subsidiary_group>
|
29
|
+
#
|
30
|
+
# my_group.to_xml(:dasherize => true)
|
31
|
+
# # => <?xml version="1.0" encoding="UTF-8"?>
|
32
|
+
# # <subsidiary-group> [...] </subsidiary-group>
|
33
|
+
#
|
34
|
+
# my_group.to_xml(:skip_instruct => true)
|
35
|
+
# # => <subsidiary_group> [...] </subsidiary_group>
|
36
|
+
def to_xml(options={})
|
37
|
+
attributes.to_xml_with_libxml({:root => self.class.element_name}.merge(options))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Formats
|
42
|
+
module XmlFormat
|
43
|
+
def encode(hash, options={})
|
44
|
+
hash.to_xml_with_libxml(options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module ActiveResource
|
53
|
+
module Formats
|
54
|
+
XmlFormat.class_eval do
|
55
|
+
remove_method :encode
|
56
|
+
include Narnach::RailsExt::ActiveResource::Formats::XmlFormat
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Base.class_eval do
|
61
|
+
remove_method :to_xml
|
62
|
+
include Narnach::RailsExt::ActiveResource::Base
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
# Project
|
3
|
+
s.name = 'libxml_rails'
|
4
|
+
s.description = "Libxml_rails replaces ActiveSupport's XmlSimple XML parsing with libxml-ruby. Original gem by Brandon Mitchell, this fork is by Wes 'Narnach' Oldenbeuving."
|
5
|
+
s.summary = s.description
|
6
|
+
s.version = '0.0.2.5'
|
7
|
+
s.date = '2009-01-06'
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Brandon Mitchell", "Wes Oldenbeuving"]
|
10
|
+
s.email = "narnach@gmail.com"
|
11
|
+
s.homepage = "http://www.github.com/Narnach/libxml_rails"
|
12
|
+
|
13
|
+
# Files
|
14
|
+
root_files = %w[CHANGELOG init.rb libxml_rails.gemspec MIT-LICENSE Rakefile README.rdoc]
|
15
|
+
lib_files = %w[bitbckt/core_ext/hash/conversions narnach/core_ext/hash/conversions narnach/core_ext/array/conversions narnach/rails_ext/active_resource libxml_rails libxml_rails/active_resource]
|
16
|
+
spec_files = %w[from_xml] + lib_files.select{|f| f[0...7] == 'narnach'}
|
17
|
+
other_files = %w[spec/spec_helper.rb]
|
18
|
+
s.require_path = "lib"
|
19
|
+
s.executables = []
|
20
|
+
s.test_files = spec_files.map {|f| 'spec/%s_spec.rb' % f}
|
21
|
+
s.files = root_files + s.test_files + other_files + lib_files.map {|f| 'lib/%s.rb' % f}
|
22
|
+
|
23
|
+
# rdoc
|
24
|
+
s.has_rdoc = true
|
25
|
+
s.extra_rdoc_files = %w[ README.rdoc MIT-LICENSE]
|
26
|
+
s.rdoc_options << '--inline-source' << '--line-numbers' << '--main' << 'README.rdoc'
|
27
|
+
|
28
|
+
# Dependencies
|
29
|
+
s.add_dependency 'activesupport', '>= 2.1.0'
|
30
|
+
s.add_dependency 'libxml-ruby', '>= 0.8.3'
|
31
|
+
|
32
|
+
# Requirements
|
33
|
+
s.required_ruby_version = ">= 1.8.0"
|
34
|
+
end
|
@@ -0,0 +1,328 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Hash, '.from_xml' do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@xml_options = { :root => :person, :skip_instruct => true, :indent => 0 }
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'parses a single record' do
|
10
|
+
topic_xml = <<-EOT
|
11
|
+
<topic>
|
12
|
+
<title>The First Topic</title>
|
13
|
+
<author-name>David</author-name>
|
14
|
+
<id type="integer">1</id>
|
15
|
+
<approved type="boolean"> true </approved>
|
16
|
+
<replies-count type="integer">0</replies-count>
|
17
|
+
<replies-close-in type="integer">2592000000</replies-close-in>
|
18
|
+
<written-on type="date">2003-07-16</written-on>
|
19
|
+
<viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
|
20
|
+
<content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
|
21
|
+
<author-email-address>david@loudthinking.com</author-email-address>
|
22
|
+
<parent-id></parent-id>
|
23
|
+
<ad-revenue type="decimal">1.5</ad-revenue>
|
24
|
+
<optimum-viewing-angle type="float">135</optimum-viewing-angle>
|
25
|
+
<resident type="symbol">yes</resident>
|
26
|
+
</topic>
|
27
|
+
EOT
|
28
|
+
|
29
|
+
expected_topic_hash = {
|
30
|
+
:title => "The First Topic",
|
31
|
+
:author_name => "David",
|
32
|
+
:id => 1,
|
33
|
+
:approved => true,
|
34
|
+
:replies_count => 0,
|
35
|
+
:replies_close_in => 2592000000,
|
36
|
+
:written_on => Date.new(2003, 7, 16),
|
37
|
+
:viewed_at => Time.utc(2003, 7, 16, 9, 28),
|
38
|
+
:content => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
|
39
|
+
:author_email_address => "david@loudthinking.com",
|
40
|
+
:parent_id => nil,
|
41
|
+
:ad_revenue => BigDecimal("1.50"),
|
42
|
+
:optimum_viewing_angle => 135.0,
|
43
|
+
:resident => :yes
|
44
|
+
}.stringify_keys
|
45
|
+
|
46
|
+
Hash.from_xml(topic_xml)["topic"].should == expected_topic_hash
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'parses a single record with nil values' do
|
50
|
+
topic_xml = <<-EOT
|
51
|
+
<topic>
|
52
|
+
<title></title>
|
53
|
+
<id type="integer"></id>
|
54
|
+
<approved type="boolean"></approved>
|
55
|
+
<written-on type="date"></written-on>
|
56
|
+
<viewed-at type="datetime"></viewed-at>
|
57
|
+
<content type="yaml"></content>
|
58
|
+
<parent-id></parent-id>
|
59
|
+
</topic>
|
60
|
+
EOT
|
61
|
+
|
62
|
+
expected_topic_hash = {
|
63
|
+
:title => nil,
|
64
|
+
:id => nil,
|
65
|
+
:approved => nil,
|
66
|
+
:written_on => nil,
|
67
|
+
:viewed_at => nil,
|
68
|
+
:content => nil,
|
69
|
+
:parent_id => nil
|
70
|
+
}.stringify_keys
|
71
|
+
|
72
|
+
Hash.from_xml(topic_xml)["topic"].should == expected_topic_hash
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'parses multiple records' do
|
76
|
+
topics_xml = <<-EOT
|
77
|
+
<topics type="array">
|
78
|
+
<topic>
|
79
|
+
<title>The First Topic</title>
|
80
|
+
<author-name>David</author-name>
|
81
|
+
<id type="integer">1</id>
|
82
|
+
<approved type="boolean">false</approved>
|
83
|
+
<replies-count type="integer">0</replies-count>
|
84
|
+
<replies-close-in type="integer">2592000000</replies-close-in>
|
85
|
+
<written-on type="date">2003-07-16</written-on>
|
86
|
+
<viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
|
87
|
+
<content>Have a nice day</content>
|
88
|
+
<author-email-address>david@loudthinking.com</author-email-address>
|
89
|
+
<parent-id nil="true"></parent-id>
|
90
|
+
</topic>
|
91
|
+
<topic>
|
92
|
+
<title>The Second Topic</title>
|
93
|
+
<author-name>Jason</author-name>
|
94
|
+
<id type="integer">1</id>
|
95
|
+
<approved type="boolean">false</approved>
|
96
|
+
<replies-count type="integer">0</replies-count>
|
97
|
+
<replies-close-in type="integer">2592000000</replies-close-in>
|
98
|
+
<written-on type="date">2003-07-16</written-on>
|
99
|
+
<viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
|
100
|
+
<content>Have a nice day</content>
|
101
|
+
<author-email-address>david@loudthinking.com</author-email-address>
|
102
|
+
<parent-id></parent-id>
|
103
|
+
</topic>
|
104
|
+
</topics>
|
105
|
+
EOT
|
106
|
+
|
107
|
+
expected_topic_hash = {
|
108
|
+
:title => "The First Topic",
|
109
|
+
:author_name => "David",
|
110
|
+
:id => 1,
|
111
|
+
:approved => false,
|
112
|
+
:replies_count => 0,
|
113
|
+
:replies_close_in => 2592000000,
|
114
|
+
:written_on => Date.new(2003, 7, 16),
|
115
|
+
:viewed_at => Time.utc(2003, 7, 16, 9, 28),
|
116
|
+
:content => "Have a nice day",
|
117
|
+
:author_email_address => "david@loudthinking.com",
|
118
|
+
:parent_id => nil
|
119
|
+
}.stringify_keys
|
120
|
+
|
121
|
+
Hash.from_xml(topics_xml)["topics"].first.should == expected_topic_hash
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'parses a single record with attributes *other* than "type"' do
|
125
|
+
topic_xml = <<-EOT
|
126
|
+
<rsp stat="ok">
|
127
|
+
<photos page="1" pages="1" perpage="100" total="16">
|
128
|
+
<photo id="175756086" owner="55569174@N00" secret="0279bf37a1" server="76" title="Colored Pencil PhotoBooth Fun" ispublic="1" isfriend="0" isfamily="0"/>
|
129
|
+
</photos>
|
130
|
+
</rsp>
|
131
|
+
EOT
|
132
|
+
|
133
|
+
expected_topic_hash = {
|
134
|
+
:id => "175756086",
|
135
|
+
:owner => "55569174@N00",
|
136
|
+
:secret => "0279bf37a1",
|
137
|
+
:server => "76",
|
138
|
+
:title => "Colored Pencil PhotoBooth Fun",
|
139
|
+
:ispublic => "1",
|
140
|
+
:isfriend => "0",
|
141
|
+
:isfamily => "0",
|
142
|
+
}.stringify_keys
|
143
|
+
|
144
|
+
Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"].should == expected_topic_hash
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'parses an empty array' do
|
148
|
+
blog_xml = <<-XML
|
149
|
+
<blog>
|
150
|
+
<posts type="array"></posts>
|
151
|
+
</blog>
|
152
|
+
XML
|
153
|
+
expected_blog_hash = {"blog" => {"posts" => []}}
|
154
|
+
Hash.from_xml(blog_xml).should == expected_blog_hash
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'parses an empty array with whitespace' do
|
158
|
+
blog_xml = <<-XML
|
159
|
+
<blog>
|
160
|
+
<posts type="array">
|
161
|
+
</posts>
|
162
|
+
</blog>
|
163
|
+
XML
|
164
|
+
expected_blog_hash = {"blog" => {"posts" => []}}
|
165
|
+
Hash.from_xml(blog_xml).should == expected_blog_hash
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'parses an array with one entry' do
|
169
|
+
blog_xml = <<-XML
|
170
|
+
<blog>
|
171
|
+
<posts type="array">
|
172
|
+
<post>a post</post>
|
173
|
+
</posts>
|
174
|
+
</blog>
|
175
|
+
XML
|
176
|
+
expected_blog_hash = {"blog" => {"posts" => ["a post"]}}
|
177
|
+
Hash.from_xml(blog_xml).should == expected_blog_hash
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'parses an array with multiple entries' do
|
181
|
+
blog_xml = <<-XML
|
182
|
+
<blog>
|
183
|
+
<posts type="array">
|
184
|
+
<post>a post</post>
|
185
|
+
<post>another post</post>
|
186
|
+
</posts>
|
187
|
+
</blog>
|
188
|
+
XML
|
189
|
+
expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}}
|
190
|
+
Hash.from_xml(blog_xml).should == expected_blog_hash
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'parses a file' do
|
194
|
+
blog_xml = <<-XML
|
195
|
+
<blog>
|
196
|
+
<logo type="file" name="logo.png" content_type="image/png">
|
197
|
+
</logo>
|
198
|
+
</blog>
|
199
|
+
XML
|
200
|
+
hash = Hash.from_xml(blog_xml)
|
201
|
+
hash.has_key?('blog').should be_true
|
202
|
+
hash['blog'].has_key?('logo').should be_true
|
203
|
+
|
204
|
+
file = hash['blog']['logo']
|
205
|
+
file.original_filename.should == 'logo.png'
|
206
|
+
file.content_type.should == 'image/png'
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'parses a file with defaults' do
|
210
|
+
blog_xml = <<-XML
|
211
|
+
<blog>
|
212
|
+
<logo type="file">
|
213
|
+
</logo>
|
214
|
+
</blog>
|
215
|
+
XML
|
216
|
+
file = Hash.from_xml(blog_xml)['blog']['logo']
|
217
|
+
file.original_filename.should == 'untitled'
|
218
|
+
file.content_type.should == 'application/octet-stream'
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'parses XSD-like types' do
|
222
|
+
bacon_xml = <<-EOT
|
223
|
+
<bacon>
|
224
|
+
<weight type="double">0.5</weight>
|
225
|
+
<price type="decimal">12.50</price>
|
226
|
+
<chunky type="boolean"> 1 </chunky>
|
227
|
+
<expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at>
|
228
|
+
<notes type="string"></notes>
|
229
|
+
<illustration type="base64Binary">YmFiZS5wbmc=</illustration>
|
230
|
+
</bacon>
|
231
|
+
EOT
|
232
|
+
|
233
|
+
expected_bacon_hash = {
|
234
|
+
:weight => 0.5,
|
235
|
+
:chunky => true,
|
236
|
+
:price => BigDecimal("12.50"),
|
237
|
+
:expires_at => Time.utc(2007,12,25,12,34,56),
|
238
|
+
:notes => "",
|
239
|
+
:illustration => "babe.png"
|
240
|
+
}.stringify_keys
|
241
|
+
|
242
|
+
Hash.from_xml(bacon_xml)["bacon"].should == expected_bacon_hash
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'trickles the "type" attribute through, when unknown' do
|
246
|
+
product_xml = <<-EOT
|
247
|
+
<product>
|
248
|
+
<weight type="double">0.5</weight>
|
249
|
+
<image type="ProductImage"><filename>image.gif</filename></image>
|
250
|
+
|
251
|
+
</product>
|
252
|
+
EOT
|
253
|
+
|
254
|
+
expected_product_hash = {
|
255
|
+
:weight => 0.5,
|
256
|
+
:image => {'type' => 'ProductImage', 'filename' => 'image.gif' },
|
257
|
+
}.stringify_keys
|
258
|
+
|
259
|
+
Hash.from_xml(product_xml)["product"].should == expected_product_hash
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'unescapes text nodes' do
|
263
|
+
xml_string = '<person><bare-string>First & Last Name</bare-string><pre-escaped-string>First &amp; Last Name</pre-escaped-string></person>'
|
264
|
+
expected_hash = {
|
265
|
+
:bare_string => 'First & Last Name',
|
266
|
+
:pre_escaped_string => 'First & Last Name'
|
267
|
+
}.stringify_keys
|
268
|
+
Hash.from_xml(xml_string)['person'].should == expected_hash
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'parses Hash.to_xml output' do
|
272
|
+
hash = {
|
273
|
+
:bare_string => 'First & Last Name',
|
274
|
+
:pre_escaped_string => 'First & Last Name'
|
275
|
+
}.stringify_keys
|
276
|
+
|
277
|
+
Hash.from_xml(hash.to_xml(@xml_options))['person'].should == hash
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'parses a datetime with UTC time' do
|
281
|
+
alert_xml = <<-XML
|
282
|
+
<alert>
|
283
|
+
<alert_at type="datetime">2008-02-10T15:30:45Z</alert_at>
|
284
|
+
</alert>
|
285
|
+
XML
|
286
|
+
alert_at = Hash.from_xml(alert_xml)['alert']['alert_at']
|
287
|
+
alert_at.utc?.should be_true
|
288
|
+
alert_at.should == Time.utc(2008, 2, 10, 15, 30, 45)
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'parses a datetime with non-UTC time' do
|
292
|
+
alert_xml = <<-XML
|
293
|
+
<alert>
|
294
|
+
<alert_at type="datetime">2008-02-10T10:30:45-05:00</alert_at>
|
295
|
+
</alert>
|
296
|
+
XML
|
297
|
+
alert_at = Hash.from_xml(alert_xml)['alert']['alert_at']
|
298
|
+
alert_at.utc?.should be_true
|
299
|
+
alert_at.should == Time.utc(2008, 2, 10, 15, 30, 45)
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'parses a datetime with a far-future date' do
|
303
|
+
alert_xml = <<-XML
|
304
|
+
<alert>
|
305
|
+
<alert_at type="datetime">2050-02-10T15:30:45Z</alert_at>
|
306
|
+
</alert>
|
307
|
+
XML
|
308
|
+
alert_at = Hash.from_xml(alert_xml)['alert']['alert_at']
|
309
|
+
alert_at.utc?.should be_true
|
310
|
+
alert_at.year.should == 2050
|
311
|
+
alert_at.month.should == 2
|
312
|
+
alert_at.day.should == 10
|
313
|
+
alert_at.hour.should == 15
|
314
|
+
alert_at.min.should == 30
|
315
|
+
alert_at.sec.should == 45
|
316
|
+
end
|
317
|
+
|
318
|
+
it 'undasherizes the root node name' do
|
319
|
+
xml = <<-EOT
|
320
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
321
|
+
<with-dash>
|
322
|
+
<another-dash>text</another-dash>
|
323
|
+
</with-dash>
|
324
|
+
EOT
|
325
|
+
expected_hash = { "with_dash" => {"another_dash"=>"text"} }
|
326
|
+
Hash.from_xml(xml).should == expected_hash
|
327
|
+
end
|
328
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
require 'narnach/core_ext/array/conversions'
|
3
|
+
|
4
|
+
describe Array, '#to_xml' do
|
5
|
+
describe 'ActiveSupport tests' do
|
6
|
+
before(:each) do
|
7
|
+
@builder_xml_options = {:skip_instruct => true }
|
8
|
+
@libxml_options = {:skip_instruct => true }
|
9
|
+
end
|
10
|
+
|
11
|
+
def compare_with_rails_for(hash, options = {})
|
12
|
+
builder_xml = hash.to_xml(@builder_xml_options.merge(options))
|
13
|
+
libxml_xml = hash.to_xml_with_libxml(@libxml_options.merge(options))
|
14
|
+
libxml_xml.should == builder_xml
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should pass test_to_xml' do
|
18
|
+
compare_with_rails_for([
|
19
|
+
{ :name => "David", :age => 26, :age_in_millis => 820497600000 },
|
20
|
+
{ :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') }
|
21
|
+
])
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should pass test_to_xml_with_dedicated_name' do
|
25
|
+
compare_with_rails_for([
|
26
|
+
{ :name => "David", :age => 26, :age_in_millis => 820497600000 }, { :name => "Jason", :age => 31 }
|
27
|
+
],{:root => "people"})
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should pass test_to_xml_with_options' do
|
31
|
+
compare_with_rails_for([
|
32
|
+
{ :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" }
|
33
|
+
], {:skip_types => true})
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should pass test_to_xml_with_dasherize_false' do
|
37
|
+
compare_with_rails_for([
|
38
|
+
{ :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" }
|
39
|
+
], {:skip_types => true, :dasherize => false})
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should pass test_to_xml_with_dasherize_true' do
|
43
|
+
compare_with_rails_for([
|
44
|
+
{ :name => "David", :street_address => "Paulina" }, { :name => "Jason", :street_address => "Evergreen" }
|
45
|
+
], {:skip_types => true, :dasherize => true})
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should pass test_to_with_instruct' do
|
49
|
+
compare_with_rails_for([
|
50
|
+
{ :name => "David", :age => 26, :age_in_millis => 820497600000 },
|
51
|
+
{ :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') }
|
52
|
+
], {:skip_instruct => false})
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should pass test_to_xml_with_block' do
|
56
|
+
ary = [
|
57
|
+
{ :name => "David", :age => 26, :age_in_millis => 820497600000 },
|
58
|
+
{ :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') }
|
59
|
+
]
|
60
|
+
builder_xml = ary.to_xml(@builder_xml_options) do |builder|
|
61
|
+
builder.count 2
|
62
|
+
end
|
63
|
+
libxml_xml = ary.to_xml_with_libxml(@libxml_options) do |libxml|
|
64
|
+
libxml << LibXML::XML::Node.new('count', 2)
|
65
|
+
end
|
66
|
+
libxml_xml.should == builder_xml
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should pass test_to_xml_with_empty' do
|
70
|
+
compare_with_rails_for([])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Hash, '#from_xml' do
|
4
|
+
it "should undasherize the Hash keys" do
|
5
|
+
xml = <<-XML
|
6
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
7
|
+
<post>
|
8
|
+
<post-id type="integer">1</post-id>
|
9
|
+
</post>
|
10
|
+
XML
|
11
|
+
Hash.from_xml(xml).should == {'post' => {'post_id' => 1}}
|
12
|
+
end
|
13
|
+
|
14
|
+
# # libxml will not break, but it takes about 140MB and 60 seconds on a 2.4GHz Core2 Duo Macbook to succeed.
|
15
|
+
# # It would be nice if entity expansion could be disabled if you don't plan to use it.
|
16
|
+
# it 'should pass test_expansion_count_is_limited' do
|
17
|
+
# attack_xml = <<-EOT
|
18
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
19
|
+
# <!DOCTYPE member [
|
20
|
+
# <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
|
21
|
+
# <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
|
22
|
+
# <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;">
|
23
|
+
# <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;">
|
24
|
+
# <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;">
|
25
|
+
# <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;">
|
26
|
+
# <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
|
27
|
+
# ]>
|
28
|
+
# <member>
|
29
|
+
# &a;
|
30
|
+
# </member>
|
31
|
+
# EOT
|
32
|
+
# lambda {
|
33
|
+
# Hash.from_xml(attack_xml)
|
34
|
+
# }.should_not raise_error
|
35
|
+
# end
|
36
|
+
end
|
37
|
+
|
38
|
+
class IWriteMyOwnXML
|
39
|
+
def to_xml(options = {})
|
40
|
+
options[:indent] ||= 2
|
41
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
42
|
+
xml.instruct! unless options[:skip_instruct]
|
43
|
+
xml.level_one do
|
44
|
+
xml.tag!(:second_level, 'content')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_xml_with_libxml(options = {})
|
49
|
+
{:second_level => 'content'}.to_xml_with_libxml(options.merge(:root => 'level_one', :dasherize => false))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe Hash, "#to_xml_with_libxml" do
|
54
|
+
it "should convert a Hash with one element" do
|
55
|
+
hsh = {:one => 1}
|
56
|
+
libxml_xml = hsh.to_xml_with_libxml.to_s
|
57
|
+
builder_xml = hsh.to_xml
|
58
|
+
libxml_xml.should == builder_xml
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should convert a Hash with nested Hash" do
|
62
|
+
hsh = {:one => 1, 'two' => { :three => 3}}
|
63
|
+
libxml_xml = hsh.to_xml_with_libxml.to_s
|
64
|
+
builder_xml = hsh.to_xml
|
65
|
+
libxml_xml.should == builder_xml
|
66
|
+
end
|
67
|
+
|
68
|
+
# These tests are adapted from the Rails ActiveSupport tests, so test to_xml_with_libxml in the same situations as to_xml
|
69
|
+
describe 'ActiveSupport tests' do
|
70
|
+
before(:each) do
|
71
|
+
@builder_xml_options = { :root => :person, :skip_instruct => true }
|
72
|
+
@libxml_options = { :root => :person, :skip_instruct => true }
|
73
|
+
end
|
74
|
+
|
75
|
+
def compare_with_rails_for(hash, custom_builder_options={}, custom_libxml_options={})
|
76
|
+
builder_xml = hash.to_xml(@builder_xml_options.merge(custom_builder_options))
|
77
|
+
libxml_xml = hash.to_xml_with_libxml(@libxml_options.merge(custom_libxml_options))
|
78
|
+
libxml_xml.should == builder_xml
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should pass test_one_level' do
|
82
|
+
compare_with_rails_for({ :name => "David", :street => "Paulina" })
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should pass test_one_level_dasherize_false' do
|
86
|
+
compare_with_rails_for({ :name => "David", :street_name => "Paulina" }, {:dasherize => false}, {:dasherize => false})
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should pass test_one_level_dasherize_true' do
|
90
|
+
compare_with_rails_for({ :name => "David", :street_name => "Paulina" }, {:dasherize => true}, {:dasherize => true})
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should pass test_one_level_with_types' do
|
94
|
+
compare_with_rails_for({ :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes })
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should pass test_one_level_with_nils' do
|
98
|
+
compare_with_rails_for({ :name => "David", :street => "Paulina", :age => nil })
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should pass test_one_level_with_skipping_types' do
|
102
|
+
compare_with_rails_for({ :name => "David", :street => "Paulina", :age => nil }, {:skip_types => true}, {:skip_types => true})
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should pass test_one_level_with_yielding' do
|
106
|
+
hash = { :name => "David", :street => "Paulina" }
|
107
|
+
builder_xml = hash.to_xml(@builder_xml_options) do |x|
|
108
|
+
x.creator("Rails")
|
109
|
+
end
|
110
|
+
libxml_xml = hash.to_xml_with_libxml(@libxml_options) do |x|
|
111
|
+
x << LibXML::XML::Node.new('creator', 'Rails')
|
112
|
+
end
|
113
|
+
libxml_xml.should == builder_xml
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should pass test_two_levels' do
|
117
|
+
compare_with_rails_for({ :name => "David", :address => { :street => "Paulina" } })
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should pass test_two_levels_with_second_level_overriding_to_xml' do
|
121
|
+
compare_with_rails_for({ :name => "David", :address => { :street => "Paulina" }, :child => IWriteMyOwnXML.new })
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should pass test_two_levels_with_array' do
|
125
|
+
compare_with_rails_for({ :name => "David", :addresses => [{ :street => "Paulina" }, { :street => "Evergreen" }] })
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should test_three_levels_with_array' do
|
129
|
+
compare_with_rails_for({ :name => "David", :addresses => [{ :streets => [ { :name => "Paulina" }, { :name => "Paulina" } ] } ] })
|
130
|
+
end
|
131
|
+
|
132
|
+
# The XML builder seems to fail miserably when trying to tag something
|
133
|
+
# with the same name as a Kernel method (throw, test, loop, select ...)
|
134
|
+
it 'should pass test_kernel_method_names_to_xml' do
|
135
|
+
compare_with_rails_for({ :throw => { :ball => 'red' } })
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should pass test_escaping_to_xml' do
|
139
|
+
compare_with_rails_for({
|
140
|
+
:bare_string => 'First & Last Name',
|
141
|
+
:pre_escaped_string => 'First & Last Name'
|
142
|
+
}.stringify_keys)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should pass test_roundtrip_to_xml_from_xml' do
|
146
|
+
hash = {
|
147
|
+
:bare_string => 'First & Last Name',
|
148
|
+
:pre_escaped_string => 'First & Last Name'
|
149
|
+
}.stringify_keys
|
150
|
+
|
151
|
+
Hash.from_xml(hash.to_xml_with_libxml(@libxml_options))['person'].should == hash
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
require 'libxml_rails/active_resource'
|
3
|
+
|
4
|
+
class SomePerson < ActiveResource::Base
|
5
|
+
self.site = 'http://example.org'
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ActiveResource, '#to_xml' do
|
9
|
+
before(:each) do
|
10
|
+
@sp = SomePerson.new(:name => 'Wes', :last_name => 'Oldenbeuving', :age => 22)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return the resource as XML" do
|
14
|
+
@sp.to_xml(:libxml=>false).should == @sp.to_xml(:libxml=>true)
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Narnach-libxml_rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brandon Mitchell
|
8
|
+
- Wes Oldenbeuving
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-01-06 00:00:00 -08:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.1.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: libxml-ruby
|
27
|
+
version_requirement:
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.8.3
|
33
|
+
version:
|
34
|
+
description: Libxml_rails replaces ActiveSupport's XmlSimple XML parsing with libxml-ruby. Original gem by Brandon Mitchell, this fork is by Wes 'Narnach' Oldenbeuving.
|
35
|
+
email: narnach@gmail.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README.rdoc
|
42
|
+
- MIT-LICENSE
|
43
|
+
files:
|
44
|
+
- CHANGELOG
|
45
|
+
- init.rb
|
46
|
+
- libxml_rails.gemspec
|
47
|
+
- MIT-LICENSE
|
48
|
+
- Rakefile
|
49
|
+
- README.rdoc
|
50
|
+
- spec/from_xml_spec.rb
|
51
|
+
- spec/narnach/core_ext/hash/conversions_spec.rb
|
52
|
+
- spec/narnach/core_ext/array/conversions_spec.rb
|
53
|
+
- spec/narnach/rails_ext/active_resource_spec.rb
|
54
|
+
- spec/spec_helper.rb
|
55
|
+
- lib/bitbckt/core_ext/hash/conversions.rb
|
56
|
+
- lib/narnach/core_ext/hash/conversions.rb
|
57
|
+
- lib/narnach/core_ext/array/conversions.rb
|
58
|
+
- lib/narnach/rails_ext/active_resource.rb
|
59
|
+
- lib/libxml_rails.rb
|
60
|
+
- lib/libxml_rails/active_resource.rb
|
61
|
+
has_rdoc: true
|
62
|
+
homepage: http://www.github.com/Narnach/libxml_rails
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options:
|
65
|
+
- --inline-source
|
66
|
+
- --line-numbers
|
67
|
+
- --main
|
68
|
+
- README.rdoc
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.8.0
|
76
|
+
version:
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: "0"
|
82
|
+
version:
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.2.0
|
87
|
+
signing_key:
|
88
|
+
specification_version: 2
|
89
|
+
summary: Libxml_rails replaces ActiveSupport's XmlSimple XML parsing with libxml-ruby. Original gem by Brandon Mitchell, this fork is by Wes 'Narnach' Oldenbeuving.
|
90
|
+
test_files:
|
91
|
+
- spec/from_xml_spec.rb
|
92
|
+
- spec/narnach/core_ext/hash/conversions_spec.rb
|
93
|
+
- spec/narnach/core_ext/array/conversions_spec.rb
|
94
|
+
- spec/narnach/rails_ext/active_resource_spec.rb
|