Skip to content
Browse files

Implement support for multiple concurrent formats by dynamically decl…

…aring the elclasses hash instead of having it in XMLElement. This way multiple formats with clashing element names are now possible.
  • Loading branch information...
1 parent c5ade5e commit 3dc585df97ced155aae97da8c366ec8d49047c78 @pedrocr committed Jul 26, 2006
Showing with 119 additions and 27 deletions.
  1. +14 −8 lib/element.rb
  2. +3 −2 lib/stream_object_parser.rb
  3. +8 −0 test/element_test.rb
  4. +68 −0 test/multi_format_test.rb
  5. +17 −8 test/simple_objects.rb
  6. +9 −9 test/stream_object_parser_test.rb
View
22 lib/element.rb
@@ -58,8 +58,7 @@ def self.xmlsubel(name) #:doc:
attr_reader name
define_method((name.to_s+"=").to_sym) { |value|
if value.is_a? String or value.is_a? Fixnum
- elclass = XMLCodec::XMLElement.get_element_class(name)
- value = elclass.new(value)
+ value = self.class.get_element_class(name).new(value)
end
value.__parent = self if value
instance_variable_set "@#{name}", value
@@ -200,8 +199,15 @@ def self.xmlattr(name) #:doc:
attr_accessor name
end
- # This is the hash that gives classes for the element names that are declared.
- ElClasses = {}
+ # Defines a new xml format (like XHTML or DocBook). This should be used in
+ # a class that's the super class of all the elements of a format
+ def self.xmlformat(name=nil)
+ self.const_set('ElClasses', {})
+ end
+
+ def self.elclasses
+ self.const_get('ElClasses')
+ end
# Sets the element name for the element
def self.elname(name)
@@ -211,10 +217,10 @@ def self.elname(name)
# Sets several element names for the element
def self.elnames(*names)
define_method(:elname){names[0].to_sym}
-
+
eln = get_elnames
names.each {|n| eln << n}
- names.each {|n| ElClasses[n.to_sym] = self}
+ names.each {|n| elclasses[n.to_sym] = self}
end
# Returns the list of element names for the element
@@ -322,7 +328,7 @@ def indentation(extra=0)
# Gets the class for a certain element name.
def self.get_element_class(name)
- cl = ElClasses[name.to_sym]
+ cl = elclasses[name.to_sym]
if not cl
raise "No class defined for element type: '" + name.to_s + "'"
end
@@ -391,7 +397,7 @@ def self.import_xml(xmlel)
# Import the XML directly from the text. This call receives the text and the
# classes that should be used to import the subelements.
def self.import_xml_text(text)
- parser = XMLStreamObjectParser.new(ElClasses)
+ parser = XMLStreamObjectParser.new(self)
parser.parse(text)
parser.top_element
end
View
5 lib/stream_object_parser.rb
@@ -61,7 +61,8 @@ def consume
# XMLSOParserElement#consume.
class XMLStreamObjectParser
# Create a new parser with a listener.
- def initialize(listener=nil)
+ def initialize(base_element, listener=nil)
+ @base_element = base_element
@listener = listener
@children = Hash.new([])
@currel = 0
@@ -76,7 +77,7 @@ def next_id
end
def get_elclass(name)
- XMLCodec::XMLElement.get_element_class(name)
+ @base_element.get_element_class(name)
end
def curr_element
View
8 test/element_test.rb
@@ -227,4 +227,12 @@ def test_elwithvalue_methods
el = ValueElement.new(v)
assert_equal v, el.value
end
+
+ def test_auto_conversion_from_string
+ v = 'Some Value'
+ vparent = ValueParent.new
+ vparent.valueelement = v
+ assert_kind_of ValueElement, vparent.valueelement
+ assert_equal vparent.valueelement.value, v
+ end
end
View
68 test/multi_format_test.rb
@@ -0,0 +1,68 @@
+require File.dirname(__FILE__) + '/test_helper'
+require 'rexml/document'
+
+class FirstFormat < XMLCodec::XMLElement
+ xmlformat 'First Format'
+end
+
+class FirstRoot < FirstFormat
+ elname "root"
+ xmlsubel :child
+end
+
+class FirstChild < FirstFormat
+ elname "child"
+ xmlattr :value
+end
+
+class SecondFormat < XMLCodec::XMLElement
+ xmlformat 'Second Format'
+end
+
+class SecondRoot < SecondFormat
+ elname "root"
+ xmlsubel :child
+ xmlsubel :child2
+end
+
+class SecondChild < SecondFormat
+ elname "child"
+ elwithvalue
+end
+
+class SecondChild2 < SecondChild
+ elname "child2"
+ xmlattr :value2
+end
+
+# Test what happens when we define two different XML formats with xmlcodec that
+# have clashing element names
+class TestMultiFormat < Test::Unit::TestCase
+ def test_import_first
+ value = 'somevalue'
+ text = '<root><child value="'+value+'"></child></root>'
+ root = FirstFormat.import_xml_text(text)
+ assert_kind_of(FirstRoot, root)
+ assert_kind_of(FirstChild, root.child)
+ assert_equal value, root.child.value
+ end
+
+ def test_import_second
+ value = 'somevalue'
+ text = '<root><child>'+value+'</child></root>'
+ root = SecondFormat.import_xml_text(text)
+ assert_kind_of(SecondRoot, root)
+ assert_kind_of(SecondChild, root.child)
+ assert_equal value, root.child.value
+ end
+
+ def test_double_inheritance
+ value = 'somevalue'
+ text = '<root><child2 value2="'+value+'">'+value+'</child2></root>'
+ root = SecondFormat.import_xml_text(text)
+ assert_kind_of(SecondRoot, root)
+ assert_kind_of(SecondChild2, root.child2)
+ assert_equal value, root.child2.value
+ assert_equal value, root.child2.value2
+ end
+end
View
25 test/simple_objects.rb
@@ -1,16 +1,20 @@
include XMLCodec
-class SimpleElement < XMLElement
+class BaseFormat < XMLElement
+ xmlformat 'Base Format'
+end
+
+class SimpleElement < BaseFormat
elwithvalue
elname 'abc'
end
-class SimpleElement2 < XMLElement
+class SimpleElement2 < BaseFormat
elwithvalue
elname 'abc1'
end
-class SimpleElementMultName < XMLElement
+class SimpleElementMultName < BaseFormat
elwithvalue
elnames 'abc2', 'abc3'
@@ -26,32 +30,37 @@ def elname
end
end
-class TestElement < XMLElement
+class TestElement < BaseFormat
elname 'subel'
xmlsubel :abc
xmlsubel :abc2
xmlsubel :subel
xmlattr :someattr
end
-class SubelElement < XMLElement
+class SubelElement < BaseFormat
elname 'subels'
xmlsubelements
end
-class SubelMultElement < XMLElement
+class SubelMultElement < BaseFormat
elname 'mult'
xmlsubel_mult :abc
xmlsubel_mult 'abc2' # Use a string and a symbol so that both are checked
end
-class Recursive < XMLElement
+class Recursive < BaseFormat
elname 'recursive'
xmlsubel :abc
xmlsubel_mult :recursive
end
-class ValueElement < XMLElement
+class ValueParent < BaseFormat
+ elname 'valueparent'
+ xmlsubel 'valueelement'
+end
+
+class ValueElement < BaseFormat
elwithvalue
elname 'valueelement'
end
View
18 test/stream_object_parser_test.rb
@@ -42,7 +42,7 @@ def test_simple
file = '<abc>'+value+'</abc>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.abc.get_object
assert_equal el.value, value
@@ -54,7 +54,7 @@ def test_attr
file = '<subel someattr="'+attrvalue+'"><abc>'+value+'</abc></subel>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.abc.get_object
@@ -70,7 +70,7 @@ def test_mult
file = '<mult><abc>'+value+'</abc></mult>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.abc.get_object
@@ -83,7 +83,7 @@ def test_subelements
file = '<subels><abc>'+value+'</abc></subels>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.abc.get_object
@@ -96,7 +96,7 @@ def test_consume_mult
file = '<subel><abc>'+value+'</abc></subel>'
listener = MyConsumingStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.abc.get_object
@@ -110,7 +110,7 @@ def test_multnames_subelements
file = '<subels><abc2>'+value1+'</abc2><abc3>'+value2+'</abc3></subels>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.subels.get_object
@@ -127,7 +127,7 @@ def test_multnames_subel_mult
file = '<mult><abc2>'+value1+'</abc2><abc3>'+value2+'</abc3></mult>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.mult.get_object
@@ -143,7 +143,7 @@ def test_multnames_subel
file = '<subel><abc3>'+value+'</abc3></subel>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el = listener.subel.get_object
@@ -157,7 +157,7 @@ def test_depth
file = '<subel><abc>'+value+'</abc></subel>'
listener = MyStreamListener.new
- parser = XMLStreamObjectParser.new(listener)
+ parser = XMLStreamObjectParser.new(BaseFormat, listener)
parser.parse(file)
el1 = listener.subel

0 comments on commit 3dc585d

Please sign in to comment.
Something went wrong with that request. Please try again.