roxml 2.4.3 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +54 -0
- data/Manifest.txt +9 -6
- data/README.rdoc +24 -17
- data/Rakefile +2 -1
- data/TODO +30 -31
- data/examples/active_record.rb +69 -0
- data/examples/amazon.rb +1 -1
- data/examples/current_weather.rb +1 -1
- data/examples/posts.rb +8 -8
- data/examples/twitter.rb +2 -2
- data/examples/xml/active_record.xml +70 -0
- data/lib/roxml.rb +174 -174
- data/lib/roxml/definition.rb +165 -89
- data/lib/roxml/extensions/deprecation.rb +5 -0
- data/lib/roxml/extensions/string/conversions.rb +2 -3
- data/lib/roxml/hash_definition.rb +26 -25
- data/lib/roxml/xml.rb +15 -6
- data/lib/roxml/xml/parsers/libxml.rb +9 -6
- data/lib/roxml/xml/parsers/rexml.rb +1 -1
- data/lib/roxml/xml/references.rb +14 -17
- data/roxml.gemspec +8 -5
- data/spec/definition_spec.rb +563 -0
- data/spec/examples/active_record_spec.rb +43 -0
- data/spec/roxml_spec.rb +372 -0
- data/spec/shared_specs.rb +15 -0
- data/spec/spec_helper.rb +21 -4
- data/spec/string_spec.rb +15 -0
- data/spec/xml/parser_spec.rb +22 -0
- data/test/fixtures/book_valid.xml +1 -1
- data/test/fixtures/person_with_guarded_mothers.xml +3 -3
- data/test/mocks/mocks.rb +57 -45
- data/test/unit/definition_test.rb +161 -12
- data/test/unit/deprecations_test.rb +97 -0
- data/test/unit/to_xml_test.rb +30 -1
- data/test/unit/xml_bool_test.rb +15 -3
- data/test/unit/xml_construct_test.rb +6 -6
- data/test/unit/xml_hash_test.rb +18 -0
- data/test/unit/xml_initialize_test.rb +6 -3
- data/test/unit/xml_object_test.rb +66 -5
- data/test/unit/xml_text_test.rb +3 -0
- metadata +23 -15
- data/test/unit/array_test.rb +0 -16
- data/test/unit/freeze_test.rb +0 -71
- data/test/unit/inheritance_test.rb +0 -63
- data/test/unit/overriden_output_test.rb +0 -33
- data/test/unit/roxml_test.rb +0 -60
- data/test/unit/string_test.rb +0 -11
data/lib/roxml/xml.rb
CHANGED
@@ -4,6 +4,10 @@ module ROXML
|
|
4
4
|
require 'libxml'
|
5
5
|
XML_PARSER = 'libxml' # :nodoc:
|
6
6
|
rescue LoadError
|
7
|
+
warn <<WARNING
|
8
|
+
ROXML is unable to locate libxml on your system, and so is falling back to
|
9
|
+
the much slower REXML. It's best to check this out and get libxml working if possible.
|
10
|
+
WARNING
|
7
11
|
XML_PARSER = 'rexml' # :nodoc:
|
8
12
|
end
|
9
13
|
end
|
@@ -13,15 +17,20 @@ module ROXML
|
|
13
17
|
module XML
|
14
18
|
class Node
|
15
19
|
def self.from(data)
|
16
|
-
|
20
|
+
case data
|
21
|
+
when XML::Node
|
17
22
|
data
|
18
|
-
|
23
|
+
when XML::Document
|
24
|
+
data.root
|
25
|
+
when File, IO
|
19
26
|
Parser.parse_io(data).root
|
20
|
-
elsif (defined?(URI) && data.is_a?(URI::Generic)) ||
|
21
|
-
(defined?(Pathname) && data.is_a?(Pathname))
|
22
|
-
Parser.parse_file(data.to_s).root
|
23
27
|
else
|
24
|
-
|
28
|
+
if (defined?(URI) && data.is_a?(URI::Generic)) ||
|
29
|
+
(defined?(Pathname) && data.is_a?(Pathname))
|
30
|
+
Parser.parse_file(data.to_s).root
|
31
|
+
else
|
32
|
+
Parser.parse(data).root
|
33
|
+
end
|
25
34
|
end
|
26
35
|
end
|
27
36
|
end
|
@@ -5,13 +5,14 @@ module ROXML
|
|
5
5
|
Document = LibXML::XML::Document
|
6
6
|
Node = LibXML::XML::Node
|
7
7
|
Parser = LibXML::XML::Parser
|
8
|
+
Error = LibXML::XML::Error
|
8
9
|
|
9
10
|
module NamespacedSearch
|
10
11
|
def search(xpath)
|
11
12
|
begin
|
12
|
-
if
|
13
|
+
if namespaces.default && !xpath.include?(':')
|
13
14
|
find(namespaced(xpath),
|
14
|
-
in_default_namespace(
|
15
|
+
in_default_namespace(namespaces.default.href))
|
15
16
|
else
|
16
17
|
find(xpath)
|
17
18
|
end
|
@@ -40,15 +41,17 @@ module ROXML
|
|
40
41
|
include NamespacedSearch
|
41
42
|
|
42
43
|
private
|
43
|
-
delegate :
|
44
|
+
delegate :namespaces, :to => :root
|
44
45
|
end
|
45
46
|
|
46
47
|
class Node
|
47
48
|
include NamespacedSearch
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
class << self
|
51
|
+
def new_with_entity_escaping(name, content = nil, namespace = nil)
|
52
|
+
new_without_entity_escaping(name, content && CGI.escapeHTML(content), namespace)
|
53
|
+
end
|
54
|
+
alias_method_chain :new, :entity_escaping
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
data/lib/roxml/xml/references.rb
CHANGED
@@ -36,13 +36,11 @@ module ROXML
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def default
|
40
|
-
@default ||= @opts.default || (@opts.array? ? Array.new : nil)
|
41
|
-
@default.duplicable? ? @default.dup : @default
|
42
|
-
end
|
43
|
-
|
44
39
|
def value_in(xml)
|
40
|
+
xml = XML::Node.from(xml)
|
45
41
|
value = fetch_value(xml)
|
42
|
+
value = default if value.nil?
|
43
|
+
|
46
44
|
freeze(apply_blocks(value))
|
47
45
|
end
|
48
46
|
|
@@ -51,7 +49,6 @@ module ROXML
|
|
51
49
|
|
52
50
|
def conventionize(what)
|
53
51
|
if !what.blank? && @instance.try(:class).try(:roxml_naming_convention).respond_to?(:call)
|
54
|
-
require 'uri'
|
55
52
|
URI.unescape(@instance.class.roxml_naming_convention.call(URI.escape(what, /\/|::/)))
|
56
53
|
else
|
57
54
|
what
|
@@ -71,7 +68,7 @@ module ROXML
|
|
71
68
|
end
|
72
69
|
|
73
70
|
def freeze(val)
|
74
|
-
if opts.
|
71
|
+
if opts.frozen?
|
75
72
|
val.each(&:freeze) if val.is_a?(Enumerable)
|
76
73
|
val.freeze
|
77
74
|
else
|
@@ -92,7 +89,7 @@ module ROXML
|
|
92
89
|
if child = xml.children.find {|c| c.name == wrapper }
|
93
90
|
return child
|
94
91
|
end
|
95
|
-
xml.child_add(XML::Node.
|
92
|
+
xml.child_add(XML::Node.new(wrapper))
|
96
93
|
end
|
97
94
|
|
98
95
|
def nodes_in(xml)
|
@@ -123,7 +120,7 @@ module ROXML
|
|
123
120
|
# Updates the attribute in the given XML block to
|
124
121
|
# the value provided.
|
125
122
|
def write_xml(xml, value)
|
126
|
-
xml.attributes[name] = value.to_s.
|
123
|
+
xml.attributes[name] = value.to_s.to_utf_without_deprecation
|
127
124
|
end
|
128
125
|
|
129
126
|
def fetch_value(xml)
|
@@ -156,10 +153,10 @@ module ROXML
|
|
156
153
|
xml.name = value
|
157
154
|
elsif array?
|
158
155
|
value.each do |v|
|
159
|
-
add(xml.child_add(XML::Node.
|
156
|
+
add(xml.child_add(XML::Node.new(name)), v)
|
160
157
|
end
|
161
158
|
else
|
162
|
-
add(xml.child_add(XML::Node.
|
159
|
+
add(xml.child_add(XML::Node.new(name)), value)
|
163
160
|
end
|
164
161
|
end
|
165
162
|
|
@@ -182,7 +179,7 @@ module ROXML
|
|
182
179
|
nodes_in(xml) do |nodes|
|
183
180
|
if array?
|
184
181
|
nodes.collect do |e|
|
185
|
-
e.content.strip.
|
182
|
+
e.content.strip.to_latin_without_deprecation
|
186
183
|
end
|
187
184
|
else
|
188
185
|
nodes.first.content
|
@@ -193,9 +190,9 @@ module ROXML
|
|
193
190
|
|
194
191
|
def add(dest, value)
|
195
192
|
if cdata?
|
196
|
-
dest.child_add(XML::Node.new_cdata(value.to_s.
|
193
|
+
dest.child_add(XML::Node.new_cdata(value.to_s.to_utf_without_deprecation))
|
197
194
|
else
|
198
|
-
dest.content = value.to_s.
|
195
|
+
dest.content = CGI.escapeHTML(value.to_s.to_utf_without_deprecation)
|
199
196
|
end
|
200
197
|
end
|
201
198
|
end
|
@@ -214,7 +211,7 @@ module ROXML
|
|
214
211
|
# the value provided.
|
215
212
|
def write_xml(xml, value)
|
216
213
|
value.each_pair do |k, v|
|
217
|
-
node = xml.child_add(XML::Node.
|
214
|
+
node = xml.child_add(XML::Node.new(hash.wrapper))
|
218
215
|
@key.update_xml(node, k)
|
219
216
|
@value.update_xml(node, v)
|
220
217
|
end
|
@@ -238,7 +235,7 @@ module ROXML
|
|
238
235
|
end
|
239
236
|
|
240
237
|
def freeze(vals)
|
241
|
-
if opts.
|
238
|
+
if opts.frozen?
|
242
239
|
vals.each_pair{|k, v| k.freeze; v.freeze }
|
243
240
|
vals.freeze
|
244
241
|
else
|
@@ -261,7 +258,7 @@ module ROXML
|
|
261
258
|
elsif value.is_a?(ROXML)
|
262
259
|
xml.child_add(value.to_xml(name))
|
263
260
|
else
|
264
|
-
node = XML::Node.
|
261
|
+
node = XML::Node.new(name)
|
265
262
|
node.content = value.to_xml
|
266
263
|
xml.child_add(node)
|
267
264
|
end
|
data/roxml.gemspec
CHANGED
@@ -2,23 +2,23 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{roxml}
|
5
|
-
s.version = "2.
|
5
|
+
s.version = "2.5.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Ben Woosley", "Zak Mandhro", "Anders Engstrom", "Russ Olsen"]
|
9
|
-
s.date = %q{2009-02-
|
9
|
+
s.date = %q{2009-02-24}
|
10
10
|
s.description = %q{ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes. As a result, ROXML simplifies the development of RESTful applications, Web Services, and XML-RPC.}
|
11
11
|
s.email = %q{ben.woosley@gmail.com}
|
12
12
|
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
|
13
|
-
s.files = ["History.txt", "MIT-LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "TODO", "config/website.yml", "examples/amazon.rb", "examples/current_weather.rb", "examples/dashed_elements.rb", "examples/posts.rb", "examples/twitter.rb", "examples/xml/amazon.xml", "examples/xml/current_weather.xml", "examples/xml/dashed_elements.xml", "examples/xml/posts.xml", "examples/xml/twitter.xml", "lib/roxml.rb", "lib/roxml/definition.rb", "lib/roxml/extensions.rb", "lib/roxml/extensions/active_support.rb", "lib/roxml/extensions/array.rb", "lib/roxml/extensions/array/conversions.rb", "lib/roxml/extensions/deprecation.rb", "lib/roxml/extensions/string.rb", "lib/roxml/extensions/string/conversions.rb", "lib/roxml/extensions/string/iterators.rb", "lib/roxml/hash_definition.rb", "lib/roxml/xml.rb", "lib/roxml/xml/parsers/libxml.rb", "lib/roxml/xml/parsers/rexml.rb", "lib/roxml/xml/references.rb", "roxml.gemspec", "spec/examples/amazon_spec.rb", "spec/examples/current_weather_spec.rb", "spec/examples/dashed_elements_spec.rb", "spec/examples/post_spec.rb", "spec/examples/twitter_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/rspec.rake", "tasks/test.rake", "test/bugs/rexml_bugs.rb", "test/fixtures/book_malformed.xml", "test/fixtures/book_pair.xml", "test/fixtures/book_text_with_attribute.xml", "test/fixtures/book_valid.xml", "test/fixtures/book_with_authors.xml", "test/fixtures/book_with_contributions.xml", "test/fixtures/book_with_contributors.xml", "test/fixtures/book_with_contributors_attrs.xml", "test/fixtures/book_with_default_namespace.xml", "test/fixtures/book_with_depth.xml", "test/fixtures/book_with_octal_pages.xml", "test/fixtures/book_with_publisher.xml", "test/fixtures/book_with_wrapped_attr.xml", "test/fixtures/dictionary_of_attr_name_clashes.xml", "test/fixtures/dictionary_of_attrs.xml", "test/fixtures/dictionary_of_guarded_names.xml", "test/fixtures/dictionary_of_mixeds.xml", "test/fixtures/dictionary_of_name_clashes.xml", "test/fixtures/dictionary_of_names.xml", "test/fixtures/dictionary_of_texts.xml", "test/fixtures/library.xml", "test/fixtures/library_uppercase.xml", "test/fixtures/muffins.xml", "test/fixtures/nameless_ageless_youth.xml", "test/fixtures/node_with_attr_name_conflicts.xml", "test/fixtures/node_with_name_conflicts.xml", "test/fixtures/numerology.xml", "test/fixtures/person.xml", "test/fixtures/person_with_guarded_mothers.xml", "test/fixtures/person_with_mothers.xml", "test/mocks/dictionaries.rb", "test/mocks/mocks.rb", "test/release/dependencies_test.rb", "test/test_helper.rb", "test/unit/
|
13
|
+
s.files = ["History.txt", "MIT-LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "TODO", "config/website.yml", "examples/active_record.rb", "examples/amazon.rb", "examples/current_weather.rb", "examples/dashed_elements.rb", "examples/posts.rb", "examples/twitter.rb", "examples/xml/active_record.xml", "examples/xml/amazon.xml", "examples/xml/current_weather.xml", "examples/xml/dashed_elements.xml", "examples/xml/posts.xml", "examples/xml/twitter.xml", "lib/roxml.rb", "lib/roxml/definition.rb", "lib/roxml/extensions.rb", "lib/roxml/extensions/active_support.rb", "lib/roxml/extensions/array.rb", "lib/roxml/extensions/array/conversions.rb", "lib/roxml/extensions/deprecation.rb", "lib/roxml/extensions/string.rb", "lib/roxml/extensions/string/conversions.rb", "lib/roxml/extensions/string/iterators.rb", "lib/roxml/hash_definition.rb", "lib/roxml/xml.rb", "lib/roxml/xml/parsers/libxml.rb", "lib/roxml/xml/parsers/rexml.rb", "lib/roxml/xml/references.rb", "roxml.gemspec", "spec/definition_spec.rb", "spec/examples/active_record_spec.rb", "spec/examples/amazon_spec.rb", "spec/examples/current_weather_spec.rb", "spec/examples/dashed_elements_spec.rb", "spec/examples/post_spec.rb", "spec/examples/twitter_spec.rb", "spec/roxml_spec.rb", "spec/shared_specs.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/string_spec.rb", "spec/xml/parser_spec.rb", "tasks/rspec.rake", "tasks/test.rake", "test/bugs/rexml_bugs.rb", "test/fixtures/book_malformed.xml", "test/fixtures/book_pair.xml", "test/fixtures/book_text_with_attribute.xml", "test/fixtures/book_valid.xml", "test/fixtures/book_with_authors.xml", "test/fixtures/book_with_contributions.xml", "test/fixtures/book_with_contributors.xml", "test/fixtures/book_with_contributors_attrs.xml", "test/fixtures/book_with_default_namespace.xml", "test/fixtures/book_with_depth.xml", "test/fixtures/book_with_octal_pages.xml", "test/fixtures/book_with_publisher.xml", "test/fixtures/book_with_wrapped_attr.xml", "test/fixtures/dictionary_of_attr_name_clashes.xml", "test/fixtures/dictionary_of_attrs.xml", "test/fixtures/dictionary_of_guarded_names.xml", "test/fixtures/dictionary_of_mixeds.xml", "test/fixtures/dictionary_of_name_clashes.xml", "test/fixtures/dictionary_of_names.xml", "test/fixtures/dictionary_of_texts.xml", "test/fixtures/library.xml", "test/fixtures/library_uppercase.xml", "test/fixtures/muffins.xml", "test/fixtures/nameless_ageless_youth.xml", "test/fixtures/node_with_attr_name_conflicts.xml", "test/fixtures/node_with_name_conflicts.xml", "test/fixtures/numerology.xml", "test/fixtures/person.xml", "test/fixtures/person_with_guarded_mothers.xml", "test/fixtures/person_with_mothers.xml", "test/mocks/dictionaries.rb", "test/mocks/mocks.rb", "test/release/dependencies_test.rb", "test/test_helper.rb", "test/unit/definition_test.rb", "test/unit/deprecations_test.rb", "test/unit/to_xml_test.rb", "test/unit/xml_attribute_test.rb", "test/unit/xml_block_test.rb", "test/unit/xml_bool_test.rb", "test/unit/xml_construct_test.rb", "test/unit/xml_convention_test.rb", "test/unit/xml_hash_test.rb", "test/unit/xml_initialize_test.rb", "test/unit/xml_name_test.rb", "test/unit/xml_namespace_test.rb", "test/unit/xml_object_test.rb", "test/unit/xml_required_test.rb", "test/unit/xml_text_test.rb", "vendor/override_rake_task/README", "vendor/override_rake_task/init.rb", "vendor/override_rake_task/install.rb", "vendor/override_rake_task/lib/override_rake_task.rb", "website/index.html"]
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.homepage = %q{http://roxml.rubyforge.org}
|
16
16
|
s.rdoc_options = ["--main", "README.rdoc"]
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
s.rubyforge_project = %q{roxml}
|
19
|
-
s.rubygems_version = %q{1.3.1
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
20
|
s.summary = %q{Ruby Object to XML mapping library}
|
21
|
-
s.test_files = ["test/unit/
|
21
|
+
s.test_files = ["test/unit/xml_convention_test.rb", "test/unit/xml_object_test.rb", "test/unit/xml_required_test.rb", "test/unit/xml_bool_test.rb", "test/unit/xml_name_test.rb", "test/unit/definition_test.rb", "test/unit/xml_construct_test.rb", "test/unit/xml_namespace_test.rb", "test/unit/deprecations_test.rb", "test/unit/xml_text_test.rb", "test/unit/xml_block_test.rb", "test/unit/xml_attribute_test.rb", "test/unit/xml_initialize_test.rb", "test/unit/xml_hash_test.rb", "test/unit/to_xml_test.rb"]
|
22
22
|
|
23
23
|
if s.respond_to? :specification_version then
|
24
24
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -26,15 +26,18 @@ Gem::Specification.new do |s|
|
|
26
26
|
|
27
27
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
28
|
s.add_runtime_dependency(%q<activesupport>, [">= 2.1.0"])
|
29
|
+
s.add_runtime_dependency(%q<libxml-ruby>, [">= 0.8.6"])
|
29
30
|
s.add_development_dependency(%q<newgem>, [">= 1.2.3"])
|
30
31
|
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
31
32
|
else
|
32
33
|
s.add_dependency(%q<activesupport>, [">= 2.1.0"])
|
34
|
+
s.add_dependency(%q<libxml-ruby>, [">= 0.8.6"])
|
33
35
|
s.add_dependency(%q<newgem>, [">= 1.2.3"])
|
34
36
|
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
35
37
|
end
|
36
38
|
else
|
37
39
|
s.add_dependency(%q<activesupport>, [">= 2.1.0"])
|
40
|
+
s.add_dependency(%q<libxml-ruby>, [">= 0.8.6"])
|
38
41
|
s.add_dependency(%q<newgem>, [">= 1.2.3"])
|
39
42
|
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
40
43
|
end
|
@@ -0,0 +1,563 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
class RoxmlObject
|
4
|
+
include ROXML
|
5
|
+
end
|
6
|
+
|
7
|
+
describe ROXML::Definition do
|
8
|
+
describe "#name_explicit?" do
|
9
|
+
it "should indicate whether from option is present" do
|
10
|
+
ROXML::Definition.new(:element, :from => 'somewhere').name_explicit?.should be_true
|
11
|
+
ROXML::Definition.new(:element).name_explicit?.should be_false
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not consider name proxies as explicit" do
|
15
|
+
ROXML::Definition.new(:element, :from => :attr).name_explicit?.should be_false
|
16
|
+
ROXML::Definition.new(:element, :from => :content).name_explicit?.should be_false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "hash options declaration", :shared => true do
|
21
|
+
it "should represent a hash" do
|
22
|
+
@opts.hash?.should be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have hash definition" do
|
26
|
+
{@opts.hash.key.type => @opts.hash.key.name}.should == @hash_args[:key]
|
27
|
+
{@opts.hash.value.type => @opts.hash.value.name}.should == @hash_args[:value]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not represent an array" do
|
31
|
+
@opts.array?.should be_false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "types" do
|
36
|
+
describe ":content" do
|
37
|
+
it "should be recognized" do
|
38
|
+
ROXML::Definition.new(:author).content?.should be_false
|
39
|
+
ROXML::Definition.new(:author, :content).content?.should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should be deprecated"
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "array reference" do
|
46
|
+
it "[] means array of texts" do
|
47
|
+
opts = ROXML::Definition.new(:authors, [])
|
48
|
+
opts.array?.should be_true
|
49
|
+
opts.type.should == :text
|
50
|
+
end
|
51
|
+
|
52
|
+
it "[:text] means array of texts" do
|
53
|
+
opts = ROXML::Definition.new(:authors, [:text])
|
54
|
+
opts.array?.should be_true
|
55
|
+
opts.type.should == :text
|
56
|
+
end
|
57
|
+
|
58
|
+
it "[:attr] means array of attrs" do
|
59
|
+
opts = ROXML::Definition.new(:authors, [:attr])
|
60
|
+
opts.array?.should be_true
|
61
|
+
opts.type.should == :attr
|
62
|
+
end
|
63
|
+
|
64
|
+
it "[Object] means array of objects" do
|
65
|
+
opts = ROXML::Definition.new(:authors, [Hash])
|
66
|
+
opts.array?.should be_true
|
67
|
+
opts.type.should == Hash
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "{}" do
|
72
|
+
describe "hash with attr key and text val" do
|
73
|
+
before do
|
74
|
+
@opts = ROXML::Definition.new(:attributes, {:key => {:attr => :name},
|
75
|
+
:value => :value})
|
76
|
+
@hash_args = {:key => {:attr => 'name'},
|
77
|
+
:value => {:text => 'value'}}
|
78
|
+
end
|
79
|
+
|
80
|
+
it_should_behave_like "hash options declaration"
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "hash with String class for type" do
|
84
|
+
before do
|
85
|
+
@opts = ROXML::Definition.new(:attributes, {:key => {String => 'name'},
|
86
|
+
:value => {String => 'value'}})
|
87
|
+
@hash_args = {:key => {:text => 'name'}, :value => {:text => 'value'}}
|
88
|
+
end
|
89
|
+
|
90
|
+
it_should_behave_like "hash options declaration"
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "hash with attr key and content val" do
|
94
|
+
before do
|
95
|
+
@opts = ROXML::Definition.new(:attributes, {:key => {:attr => :name},
|
96
|
+
:value => :content})
|
97
|
+
@hash_args = {:key => {:attr => 'name'}, :value => {:text => '.'}}
|
98
|
+
end
|
99
|
+
|
100
|
+
it_should_behave_like "hash options declaration"
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "hash of attrs" do
|
104
|
+
before do
|
105
|
+
@hash_args = {:key => {:attr => 'name'}, :value => {:attr => 'value'}}
|
106
|
+
@opts = ROXML::Definition.new(:attributes, {:attrs => [:name, :value]})
|
107
|
+
end
|
108
|
+
|
109
|
+
it_should_behave_like "hash options declaration"
|
110
|
+
|
111
|
+
describe "with options" do
|
112
|
+
before do
|
113
|
+
@hash_args = {:key => {:attr => 'dt'}, :value => {:attr => 'dd'}}
|
114
|
+
@opts = ROXML::Definition.new(:definitions, {:attrs => [:dt, :dd]},
|
115
|
+
:in => 'definitions')
|
116
|
+
end
|
117
|
+
|
118
|
+
it_should_behave_like "hash options declaration"
|
119
|
+
|
120
|
+
it "should not interfere with options" do
|
121
|
+
@opts.wrapper.should == 'definitions'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe ":as" do
|
129
|
+
describe "=> :array" do
|
130
|
+
it "should be deprecated"
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "=> []" do
|
134
|
+
it "should means array of texts" do
|
135
|
+
opts = ROXML::Definition.new(:authors, :as => [])
|
136
|
+
opts.array?.should be_true
|
137
|
+
opts.type.should == :text
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should unescape xml entities" do
|
141
|
+
ROXML::Definition.new(:questions, :as => []).to_ref(RoxmlObject.new).value_in(%{
|
142
|
+
<xml>
|
143
|
+
<question>"Wickard & Filburn" ></question>
|
144
|
+
<question> < McCulloch & Maryland?</question>
|
145
|
+
</xml>
|
146
|
+
}).should == ["\"Wickard & Filburn\" >", "< McCulloch & Maryland?"]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "=> {}" do
|
151
|
+
describe "hash with attr key and text val" do
|
152
|
+
before do
|
153
|
+
@opts = ROXML::Definition.new(:attributes, :as => {:key => {:attr => :name},
|
154
|
+
:value => :value})
|
155
|
+
@hash_args = {:key => {:attr => 'name'},
|
156
|
+
:value => {:text => 'value'}}
|
157
|
+
end
|
158
|
+
|
159
|
+
it_should_behave_like "hash options declaration"
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "hash with String class for type" do
|
163
|
+
before do
|
164
|
+
@opts = ROXML::Definition.new(:attributes, :as => {:key => {String => 'name'},
|
165
|
+
:value => {String => 'value'}})
|
166
|
+
@hash_args = {:key => {:text => 'name'}, :value => {:text => 'value'}}
|
167
|
+
end
|
168
|
+
|
169
|
+
it_should_behave_like "hash options declaration"
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "hash with attr key and content val" do
|
173
|
+
before do
|
174
|
+
@opts = ROXML::Definition.new(:attributes, :as => {:key => {:attr => :name},
|
175
|
+
:value => :content})
|
176
|
+
@hash_args = {:key => {:attr => 'name'}, :value => {:text => '.'}}
|
177
|
+
end
|
178
|
+
|
179
|
+
it_should_behave_like "hash options declaration"
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "hash of attrs" do
|
183
|
+
before do
|
184
|
+
@hash_args = {:key => {:attr => 'name'}, :value => {:attr => 'value'}}
|
185
|
+
@opts = ROXML::Definition.new(:attributes, :as => {:attrs => [:name, :value]})
|
186
|
+
end
|
187
|
+
|
188
|
+
it_should_behave_like "hash options declaration"
|
189
|
+
|
190
|
+
describe "with options" do
|
191
|
+
before do
|
192
|
+
@hash_args = {:key => {:attr => 'dt'}, :value => {:attr => 'dd'}}
|
193
|
+
@opts = ROXML::Definition.new(:definitions, :as => {:attrs => [:dt, :dd]},
|
194
|
+
:in => 'definitions')
|
195
|
+
end
|
196
|
+
|
197
|
+
it_should_behave_like "hash options declaration"
|
198
|
+
|
199
|
+
it "should not interfere with options" do
|
200
|
+
@opts.wrapper.should == 'definitions'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "for block shorthand" do
|
207
|
+
describe "in literal array" do
|
208
|
+
before do
|
209
|
+
@opts = ROXML::Definition.new(:intarray, :as => [Integer])
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should be detected as array reference" do
|
213
|
+
@opts.array?.should be_true
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should be normal otherwise" do
|
217
|
+
@opts.type.should == :text
|
218
|
+
@opts.blocks.size.should == 1
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should have no blocks without a shorthand" do
|
223
|
+
ROXML::Definition.new(:count).blocks.should be_empty
|
224
|
+
ROXML::Definition.new(:count, :as => :bogus).blocks.should be_empty
|
225
|
+
ROXML::Definition.new(:count, :as => :foat).blocks.should be_empty # misspelled
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "block shorthand type declaration", :shared => true do
|
229
|
+
it "should translate nil to nil" do
|
230
|
+
@definition.blocks.first.call(nil).should be_nil
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should translate empty strings to nil" do
|
234
|
+
@definition.blocks.first.call("").should be_nil
|
235
|
+
@definition.blocks.first.call(" ").should be_nil
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
describe ":as => Integer", :shared => true do
|
240
|
+
it_should_behave_like "block shorthand type declaration"
|
241
|
+
|
242
|
+
it "should translate text to integers" do
|
243
|
+
@definition.blocks.first['3'].should == 3
|
244
|
+
@definition.blocks.first['792'].should == 792
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should raise on non-integer values" do
|
248
|
+
proc { @definition.blocks.first['08'] }.should raise_error(ArgumentError)
|
249
|
+
proc { @definition.blocks.first['793.12'] }.should raise_error(ArgumentError)
|
250
|
+
proc { @definition.blocks.first['junk 11'] }.should raise_error(ArgumentError)
|
251
|
+
proc { @definition.blocks.first['11sttf'] }.should raise_error(ArgumentError)
|
252
|
+
end
|
253
|
+
|
254
|
+
context "when passed an array" do
|
255
|
+
it "should translate the array elements to integer" do
|
256
|
+
@definition.blocks.first.call(["792", "12", "328"]).should == [792, 12, 328]
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe "Integer" do
|
262
|
+
before do
|
263
|
+
@definition = ROXML::Definition.new(:intvalue, :as => Integer)
|
264
|
+
end
|
265
|
+
|
266
|
+
it_should_behave_like ":as => Integer"
|
267
|
+
end
|
268
|
+
|
269
|
+
describe ":integer" do
|
270
|
+
before do
|
271
|
+
@definition = ROXML::Definition.new(:intvalue, :as => :integer)
|
272
|
+
end
|
273
|
+
|
274
|
+
it_should_behave_like ":as => Integer"
|
275
|
+
|
276
|
+
it "should be deprecated"
|
277
|
+
end
|
278
|
+
|
279
|
+
describe ":as => Float", :shared => true do
|
280
|
+
it_should_behave_like "block shorthand type declaration"
|
281
|
+
|
282
|
+
it "should translate text to float" do
|
283
|
+
@definition.blocks.first['3'].should == 3.0
|
284
|
+
@definition.blocks.first['12.7'].should == 12.7
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should raise on non-float values" do
|
288
|
+
proc { @definition.blocks.first['junk 11.3'] }.should raise_error(ArgumentError)
|
289
|
+
proc { @definition.blocks.first['11.1sttf'] }.should raise_error(ArgumentError)
|
290
|
+
end
|
291
|
+
|
292
|
+
context "when passed an array" do
|
293
|
+
it "should translate the array elements to integer" do
|
294
|
+
@definition.blocks.first.call(["792.13", "240", "3.14"]).should == [792.13, 240.0, 3.14]
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe ":float" do
|
300
|
+
before do
|
301
|
+
@definition = ROXML::Definition.new(:floatvalue, :as => :float)
|
302
|
+
end
|
303
|
+
|
304
|
+
it_should_behave_like ":as => Float"
|
305
|
+
|
306
|
+
it "should be deprecated"
|
307
|
+
end
|
308
|
+
|
309
|
+
describe "Float" do
|
310
|
+
before do
|
311
|
+
@definition = ROXML::Definition.new(:floatvalue, :as => Float)
|
312
|
+
end
|
313
|
+
|
314
|
+
it_should_behave_like ":as => Float"
|
315
|
+
end
|
316
|
+
|
317
|
+
describe "BigDecimal" do
|
318
|
+
before do
|
319
|
+
@definition = ROXML::Definition.new(:decimalvalue, :as => BigDecimal)
|
320
|
+
end
|
321
|
+
|
322
|
+
it_should_behave_like "block shorthand type declaration"
|
323
|
+
|
324
|
+
it "should translate text to decimal numbers" do
|
325
|
+
@definition.blocks.first['3'].should == BigDecimal.new("3.0")
|
326
|
+
@definition.blocks.first['0.3'].should == BigDecimal.new("0.3")
|
327
|
+
end
|
328
|
+
|
329
|
+
it "should extract what it can, and fall back to 0" do
|
330
|
+
@definition.blocks.first['junk 11'].should eql(BigDecimal.new("0"))
|
331
|
+
@definition.blocks.first['11sttf'].should eql(BigDecimal.new("11.0"))
|
332
|
+
end
|
333
|
+
|
334
|
+
context "when passed an array" do
|
335
|
+
it "should translate the array elements to integer" do
|
336
|
+
@definition.blocks.first.call(["12.1", "328.2"]).should == [BigDecimal.new("12.1"), BigDecimal.new("328.2")]
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
describe "Fixnum" do
|
342
|
+
before do
|
343
|
+
@definition = ROXML::Definition.new(:fixnumvalue, :as => Fixnum)
|
344
|
+
end
|
345
|
+
|
346
|
+
it_should_behave_like "block shorthand type declaration"
|
347
|
+
|
348
|
+
it "should translate text to integers" do
|
349
|
+
@definition.blocks.first['3'].should == 3
|
350
|
+
@definition.blocks.first['792'].should == 792
|
351
|
+
@definition.blocks.first['08'].should == 8
|
352
|
+
@definition.blocks.first['279.23'].should == 279
|
353
|
+
end
|
354
|
+
|
355
|
+
it "should extract whatever is possible and fall back to 0" do
|
356
|
+
@definition.blocks.first['junk 11'].should eql(0)
|
357
|
+
@definition.blocks.first['.?sttf'].should eql(0)
|
358
|
+
@definition.blocks.first['11sttf'].should eql(11)
|
359
|
+
end
|
360
|
+
|
361
|
+
context "when passed an array" do
|
362
|
+
it "should translate the array elements to integer" do
|
363
|
+
@definition.blocks.first.call(["792", "12", "328"]).should == [792, 12, 328]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe ":bool" do
|
369
|
+
it "should boolify individual values" do
|
370
|
+
ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("1").should be_true
|
371
|
+
ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("True").should be_true
|
372
|
+
ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("Yes").should be_true
|
373
|
+
end
|
374
|
+
|
375
|
+
context "when an array is passed in" do
|
376
|
+
it "should boolify arrays of values" do
|
377
|
+
ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("0").should be_false
|
378
|
+
ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("false").should be_false
|
379
|
+
ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("nO").should be_false
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
context "when no value is detected" do
|
384
|
+
it "should return nil" do
|
385
|
+
ROXML::Definition.new(:floatvalue, :as => :bool).blocks.first.call("junk").should be_nil
|
386
|
+
end
|
387
|
+
|
388
|
+
context "when a literal block is available" do
|
389
|
+
it "should pass the value itself to the block"
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
describe "Time" do
|
395
|
+
it "should return nil on empty string" do
|
396
|
+
ROXML::Definition.new(:floatvalue, :as => Time).blocks.first.call(" ").should be_nil
|
397
|
+
end
|
398
|
+
|
399
|
+
it "should return a time version of the string" do
|
400
|
+
ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call("12:31am").min.should == 31
|
401
|
+
end
|
402
|
+
|
403
|
+
context "when passed an array of values" do
|
404
|
+
it "should timify all of them" do
|
405
|
+
ROXML::Definition.new(:datevalue, :as => Time).blocks.first.call(["12:31am", "3:00pm", "11:59pm"]).map(&:min).should == [31, 0, 59]
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
describe "Date" do
|
411
|
+
it "should return nil on empty string" do
|
412
|
+
ROXML::Definition.new(:floatvalue, :as => Date).blocks.first.call(" ").should be_nil
|
413
|
+
end
|
414
|
+
|
415
|
+
it "should return a time version of the string" do
|
416
|
+
ROXML::Definition.new(:datevalue, :as => Date).blocks.first.call("September 3rd, 1970").to_s == "1970-09-03"
|
417
|
+
end
|
418
|
+
|
419
|
+
context "when passed an array of values" do
|
420
|
+
it "should timify all of them" do
|
421
|
+
ROXML::Definition.new(:datevalue, :as => Date).blocks.first.call(["September 3rd, 1970", "1776-07-04"]).map(&:to_s).should == ["1970-09-03", "1776-07-04"]
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
describe "DateTime" do
|
427
|
+
it "should return nil on empty string" do
|
428
|
+
ROXML::Definition.new(:floatvalue, :as => DateTime).blocks.first.call(" ").should be_nil
|
429
|
+
end
|
430
|
+
|
431
|
+
it "should return a time version of the string" do
|
432
|
+
ROXML::Definition.new(:datevalue, :as => DateTime).blocks.first.call("12:05pm, September 3rd, 1970").to_s == "1970-09-03T12:05:00+00:00"
|
433
|
+
end
|
434
|
+
|
435
|
+
context "when passed an array of values" do
|
436
|
+
it "should timify all of them" do
|
437
|
+
ROXML::Definition.new(:datevalue, :as => DateTime).blocks.first.call(["12:05pm, September 3rd, 1970", "3:00pm, May 22, 1700"]).map(&:to_s).should == ["1970-09-03T12:05:00+00:00", "1700-05-22T15:00:00+00:00"]
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should prohibit multiple shorthands" do
|
443
|
+
proc { ROXML::Definition.new(:count, :as => [Float, Integer]) }.should raise_error(ArgumentError)
|
444
|
+
end
|
445
|
+
|
446
|
+
it "should stack block shorthands with explicit blocks" do
|
447
|
+
ROXML::Definition.new(:count, :as => Integer) {|val| val.to_i }.blocks.size.should == 2
|
448
|
+
ROXML::Definition.new(:count, :as => Float) {|val| val.object_id }.blocks.size.should == 2
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
describe ":from" do
|
454
|
+
describe "attribute reference", :shared => true do
|
455
|
+
it "should be interpreted as :attr" do
|
456
|
+
@opts.type.should == :attr
|
457
|
+
end
|
458
|
+
|
459
|
+
it "should strip '@' from name" do
|
460
|
+
@opts.name.should == 'attr_name'
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should unescape xml entities" do
|
464
|
+
@opts.to_ref(RoxmlObject.new).value_in(%{
|
465
|
+
<question attr_name=""Wickard & Filburn" > / < McCulloch & Marryland?" />
|
466
|
+
}).should == "\"Wickard & Filburn\" > / < McCulloch & Marryland?"
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
context ":attr" do
|
471
|
+
before do
|
472
|
+
@opts = ROXML::Definition.new(:attr_name, :from => :attr)
|
473
|
+
end
|
474
|
+
|
475
|
+
it_should_behave_like "attribute reference"
|
476
|
+
end
|
477
|
+
|
478
|
+
context "@attribute_name" do
|
479
|
+
before do
|
480
|
+
@opts = ROXML::Definition.new(:attr_name, :from => '@attr_name')
|
481
|
+
end
|
482
|
+
|
483
|
+
it_should_behave_like "attribute reference"
|
484
|
+
|
485
|
+
describe "and with :attr" do
|
486
|
+
before do
|
487
|
+
@opts = ROXML::Definition.new(:attr_name, :attr, :from => '@attr_name')
|
488
|
+
end
|
489
|
+
|
490
|
+
it_should_behave_like "attribute reference"
|
491
|
+
it "should be deprecated"
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
describe ":content" do
|
496
|
+
it "should be recognized" do
|
497
|
+
ROXML::Definition.new(:author, :from => :content).content?.should == true
|
498
|
+
end
|
499
|
+
|
500
|
+
it "should be equivalent to :from => '.'" do
|
501
|
+
ROXML::Definition.new(:author, :from => '.').content?.should == true
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
describe ":in" do
|
507
|
+
context "as xpath" do
|
508
|
+
it "should pass through as wrapper" do
|
509
|
+
ROXML::Definition.new(:manufacturer, :in => './').wrapper.should == './'
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
context "as xpath" do
|
514
|
+
it "should pass through as wrapper" do
|
515
|
+
ROXML::Definition.new(:manufacturer, :in => 'wrapper').wrapper.should == 'wrapper'
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
describe "options" do
|
521
|
+
|
522
|
+
describe "boolean option", :shared => true do
|
523
|
+
it "should be recognized" do
|
524
|
+
ROXML::Definition.new(:author, :content, @option => true).respond_to?(:"#{@option}?")
|
525
|
+
ROXML::Definition.new(:author, :content, @option => true).send(:"#{@option}?").should be_true
|
526
|
+
ROXML::Definition.new(:author, :content, @option => false).send(:"#{@option}?").should be_false
|
527
|
+
end
|
528
|
+
|
529
|
+
it "should default to false" do
|
530
|
+
ROXML::Definition.new(:author, :content).send(:"#{@option}?").should be_false
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
describe ":required" do
|
535
|
+
before do
|
536
|
+
@option = :required
|
537
|
+
end
|
538
|
+
|
539
|
+
it_should_behave_like "boolean option"
|
540
|
+
|
541
|
+
it "should not be allowed together with :else" do
|
542
|
+
proc { ROXML::Definition.new(:author, :content, :required => true, :else => 'Johnny') }.should raise_error(ArgumentError)
|
543
|
+
proc { ROXML::Definition.new(:author, :content, :required => false, :else => 'Johnny') }.should_not raise_error
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
describe ":frozen" do
|
548
|
+
before do
|
549
|
+
@option = :frozen
|
550
|
+
end
|
551
|
+
|
552
|
+
it_should_behave_like "boolean option"
|
553
|
+
end
|
554
|
+
|
555
|
+
describe ":cdata" do
|
556
|
+
before do
|
557
|
+
@option = :cdata
|
558
|
+
end
|
559
|
+
|
560
|
+
it_should_behave_like "boolean option"
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|