tilia-xml 1.2.0.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,13 +9,6 @@ module Tilia
9
9
  class Base
10
10
  include Element
11
11
 
12
- protected
13
-
14
- # PHP value to serialize.
15
- attr_accessor :value
16
-
17
- public
18
-
19
12
  # Constructor
20
13
  #
21
14
  # @param value
@@ -23,46 +16,12 @@ module Tilia
23
16
  @value = value
24
17
  end
25
18
 
26
- # The xml_serialize metod is called during xml writing.
27
- #
28
- # Use the writer argument to write its own xml serialization.
29
- #
30
- # An important note: do _not_ create a parent element. Any element
31
- # implementing XmlSerializable should only ever write what's considered
32
- # its 'inner xml'.
33
- #
34
- # The parent of the current element is responsible for writing a
35
- # containing element.
36
- #
37
- # This allows serializers to be re-used for different element names.
38
- #
39
- # If you are opening new elements, you must also close them again.
40
- #
41
- # @param [Writer] writer
42
- # @return [void]
19
+ # (see XmlSerializable#xml_serialize)
43
20
  def xml_serialize(writer)
44
21
  writer.write(@value)
45
22
  end
46
23
 
47
- # The deserialize method is called during xml parsing.
48
- #
49
- # This method is called statictly, this is because in theory this method
50
- # may be used as a type of constructor, or factory method.
51
- #
52
- # Often you want to return an instance of the current class, but you are
53
- # free to return other data as well.
54
- #
55
- # Important note 2: You are responsible for advancing the reader to the
56
- # next element. Not doing anything will result in a never-ending loop.
57
- #
58
- # If you just want to skip parsing for this element altogether, you can
59
- # just call reader->next();
60
- #
61
- # reader->parseInnerTree() will parse the entire sub-tree, and advance to
62
- # the next element.
63
- #
64
- # @param [Reader] reader
65
- # @return mixed
24
+ # (see XmlDeserializable#xml_deserialize)
66
25
  def self.xml_deserialize(reader)
67
26
  sub_tree = reader.parse_inner_tree
68
27
  sub_tree
@@ -11,15 +11,6 @@ module Tilia
11
11
  class Cdata
12
12
  include XmlSerializable
13
13
 
14
- protected
15
-
16
- # CDATA element value.
17
- #
18
- # @return [String]
19
- attr_accessor :value
20
-
21
- public
22
-
23
14
  # Constructor
24
15
  #
25
16
  # @param [String] value
@@ -27,23 +18,7 @@ module Tilia
27
18
  @value = value
28
19
  end
29
20
 
30
- # The xml_serialize metod is called during xml writing.
31
- #
32
- # Use the writer argument to write its own xml serialization.
33
- #
34
- # An important note: do _not_ create a parent element. Any element
35
- # implementing XmlSerializble should only ever write what's considered
36
- # its 'inner xml'.
37
- #
38
- # The parent of the current element is responsible for writing a
39
- # containing element.
40
- #
41
- # This allows serializers to be re-used for different element names.
42
- #
43
- # If you are opening new elements, you must also close them again.
44
- #
45
- # @param [Writer] writer
46
- # @return [void]
21
+ # (see XmlSerializable#xml_serialize)
47
22
  def xml_serialize(writer)
48
23
  writer.write_cdata(@value)
49
24
  end
@@ -25,15 +25,6 @@ module Tilia
25
25
  class Elements
26
26
  include Element
27
27
 
28
- protected
29
-
30
- # Value to serialize
31
- #
32
- # @return [Array]
33
- attr_accessor :value
34
-
35
- public
36
-
37
28
  # Constructor
38
29
  #
39
30
  # @param [Array] value
@@ -41,67 +32,14 @@ module Tilia
41
32
  @value = value
42
33
  end
43
34
 
44
- # The xml_serialize metod is called during xml writing.
45
- #
46
- # Use the writer argument to write its own xml serialization.
47
- #
48
- # An important note: do _not_ create a parent element. Any element
49
- # implementing XmlSerializble should only ever write what's considered
50
- # its 'inner xml'.
51
- #
52
- # The parent of the current element is responsible for writing a
53
- # containing element.
54
- #
55
- # This allows serializers to be re-used for different element names.
56
- #
57
- # If you are opening new elements, you must also close them again.
58
- #
59
- # @param [Writer] writer
60
- # @return [void]
35
+ # (see XmlSerializable#xml_serialize)
61
36
  def xml_serialize(writer)
62
- @value.each do |val|
63
- writer.write_element(val)
64
- end
37
+ Serializer.enum(writer, @value)
65
38
  end
66
39
 
67
- # The deserialize method is called during xml parsing.
68
- #
69
- # This method is called statictly, this is because in theory this method
70
- # may be used as a type of constructor, or factory method.
71
- #
72
- # Often you want to return an instance of the current class, but you are
73
- # free to return other data as well.
74
- #
75
- # Important note 2: You are responsible for advancing the reader to the
76
- # next element. Not doing anything will result in a never-ending loop.
77
- #
78
- # If you just want to skip parsing for this element altogether, you can
79
- # just call reader->next();
80
- #
81
- # reader->parseSubTree() will parse the entire sub-tree, and advance to
82
- # the next element.
83
- #
84
- # @param [Reader] reader
85
- # @return mixed
40
+ # (see XmlDeserializable#xml_deserialize)
86
41
  def self.xml_deserialize(reader)
87
- # If there's no children, we don't do anything.
88
- if reader.empty_element?
89
- reader.next
90
- return []
91
- end
92
- reader.read
93
- current_depth = reader.depth
94
-
95
- values = []
96
- loop do
97
- if reader.node_type == ::LibXML::XML::Reader::TYPE_ELEMENT
98
- values << reader.clark
99
- end
100
- break unless reader.depth >= current_depth && reader.next
101
- end
102
-
103
- reader.next
104
- values
42
+ Deserializer.enum(reader)
105
43
  end
106
44
  end
107
45
  end
@@ -26,15 +26,6 @@ module Tilia
26
26
  class KeyValue
27
27
  include Element
28
28
 
29
- protected
30
-
31
- # Value to serialize
32
- #
33
- # @return [Array]
34
- attr_accessor :value
35
-
36
- public
37
-
38
29
  # Constructor
39
30
  #
40
31
  # @param [Array] value
@@ -42,67 +33,14 @@ module Tilia
42
33
  @value = value
43
34
  end
44
35
 
45
- # The xml_serialize metod is called during xml writing.
46
- #
47
- # Use the writer argument to write its own xml serialization.
48
- #
49
- # An important note: do _not_ create a parent element. Any element
50
- # implementing XmlSerializble should only ever write what's considered
51
- # its 'inner xml'.
52
- #
53
- # The parent of the current element is responsible for writing a
54
- # containing element.
55
- #
56
- # This allows serializers to be re-used for different element names.
57
- #
58
- # If you are opening new elements, you must also close them again.
59
- #
60
- # @param [Writer] writer
61
- # @return [void]
36
+ # (see XmlSerializable#xml_serialize)
62
37
  def xml_serialize(writer)
63
38
  writer.write(@value)
64
39
  end
65
40
 
66
- # The deserialize method is called during xml parsing.
67
- #
68
- # This method is called staticly, this is because in theory this method
69
- # may be used as a type of constructor, or factory method.
70
- #
71
- # Often you want to return an instance of the current class, but you are
72
- # free to return other data as well.
73
- #
74
- # Important note 2: You are responsible for advancing the reader to the
75
- # next element. Not doing anything will result in a never-ending loop.
76
- #
77
- # If you just want to skip parsing for this element altogether, you can
78
- # just call reader->next();
79
- #
80
- # reader->parseInnerTree() will parse the entire sub-tree, and advance to
81
- # the next element.
82
- #
83
- # @param [Reader] reader
84
- # @return mixed
41
+ # (see XmlDeserializable#xml_deserialize)
85
42
  def self.xml_deserialize(reader)
86
- # If there's no children, we don't do anything.
87
- if reader.empty_element?
88
- reader.next
89
- return {}
90
- end
91
-
92
- values = {}
93
-
94
- reader.read
95
- loop do
96
- if reader.node_type == ::LibXML::XML::Reader::TYPE_ELEMENT
97
- clark = reader.clark
98
- values[clark] = reader.parse_current_element['value']
99
- else
100
- reader.read
101
- end
102
- break unless reader.node_type != ::LibXML::XML::Reader::TYPE_END_ELEMENT
103
- end
104
- reader.read
105
- values
43
+ Deserializer.key_value(reader)
106
44
  end
107
45
  end
108
46
  end
@@ -14,15 +14,6 @@ module Tilia
14
14
  class Uri
15
15
  include Element
16
16
 
17
- protected
18
-
19
- # Uri element value.
20
- #
21
- # @return [String]
22
- attr_accessor :value
23
-
24
- public
25
-
26
17
  # Constructor
27
18
  #
28
19
  # @param [String] value
@@ -30,23 +21,7 @@ module Tilia
30
21
  @value = value
31
22
  end
32
23
 
33
- # The xml_serialize metod is called during xml writing.
34
- #
35
- # Use the writer argument to write its own xml serialization.
36
- #
37
- # An important note: do _not_ create a parent element. Any element
38
- # implementing XmlSerializble should only ever write what's considered
39
- # its 'inner xml'.
40
- #
41
- # The parent of the current element is responsible for writing a
42
- # containing element.
43
- #
44
- # This allows serializers to be re-used for different element names.
45
- #
46
- # If you are opening new elements, you must also close them again.
47
- #
48
- # @param [Writer] writer
49
- # @return [void]
24
+ # (see XmlSerializable#xml_serialize)
50
25
  def xml_serialize(writer)
51
26
  writer.write_string(
52
27
  ::Tilia::Uri.resolve(
@@ -56,25 +31,7 @@ module Tilia
56
31
  )
57
32
  end
58
33
 
59
- # This method is called during xml parsing.
60
- #
61
- # This method is called statically, this is because in theory this method
62
- # may be used as a type of constructor, or factory method.
63
- #
64
- # Often you want to return an instance of the current class, but you are
65
- # free to return other data as well.
66
- #
67
- # Important note 2: You are responsible for advancing the reader to the
68
- # next element. Not doing anything will result in a never-ending loop.
69
- #
70
- # If you just want to skip parsing for this element altogether, you can
71
- # just call reader->next();
72
- #
73
- # reader->parseSubTree() will parse the entire sub-tree, and advance to
74
- # the next element.
75
- #
76
- # @param [Reader] reader
77
- # @return mixed
34
+ # (see XmlDeserializable#xml_deserialize)
78
35
  def self.xml_deserialize(reader)
79
36
  new(
80
37
  ::Tilia::Uri.resolve(
@@ -16,35 +16,13 @@ module Tilia
16
16
  class XmlFragment
17
17
  include Element
18
18
 
19
- protected
20
-
21
- attr_writer :xml
22
-
23
- public
24
-
25
19
  def initialize(xml)
26
20
  @xml = xml
27
21
  end
28
22
 
29
23
  attr_reader :xml
30
24
 
31
- # The xml_serialize metod is called during xml writing.
32
- #
33
- # Use the writer argument to write its own xml serialization.
34
- #
35
- # An important note: do _not_ create a parent element. Any element
36
- # implementing XmlSerializble should only ever write what's considered
37
- # its 'inner xml'.
38
- #
39
- # The parent of the current element is responsible for writing a
40
- # containing element.
41
- #
42
- # This allows serializers to be re-used for different element names.
43
- #
44
- # If you are opening new elements, you must also close them again.
45
- #
46
- # @param [Writer] writer
47
- # @return [void]
25
+ # (see XmlSerializable#xml_serialize)
48
26
  def xml_serialize(writer)
49
27
  reader = Reader.new
50
28
 
@@ -89,25 +67,7 @@ XML
89
67
  end
90
68
  end
91
69
 
92
- # The deserialize method is called during xml parsing.
93
- #
94
- # This method is called statictly, this is because in theory this method
95
- # may be used as a type of constructor, or factory method.
96
- #
97
- # Often you want to return an instance of the current class, but you are
98
- # free to return other data as well.
99
- #
100
- # You are responsible for advancing the reader to the next element. Not
101
- # doing anything will result in a never-ending loop.
102
- #
103
- # If you just want to skip parsing for this element altogether, you can
104
- # just call reader->next();
105
- #
106
- # reader->parseInnerTree() will parse the entire sub-tree, and advance to
107
- # the next element.
108
- #
109
- # @param [Reader] reader
110
- # @return mixed
70
+ # (see XmlDeserializable#xml_deserialize)
111
71
  def self.xml_deserialize(reader)
112
72
  result = new(reader.read_inner_xml)
113
73
  reader.next
@@ -88,7 +88,7 @@ module Tilia
88
88
  text = nil
89
89
  elements = []
90
90
 
91
- if node_type == ::LibXML::XML::Reader::TYPE_ELEMENT && self.empty_element?
91
+ if node_type == ::LibXML::XML::Reader::TYPE_ELEMENT && empty_element?
92
92
  # Easy!
93
93
  self.next
94
94
  return nil
@@ -117,7 +117,7 @@ module Tilia
117
117
  read
118
118
  break
119
119
  when ::LibXML::XML::Reader::TYPE_NONE
120
- fail Tilia::Xml::ParseException, 'We hit the end of the document prematurely. This likely means that some parser "eats" too many elements. Do not attempt to continue parsing.'
120
+ raise Tilia::Xml::ParseException, 'We hit the end of the document prematurely. This likely means that some parser "eats" too many elements. Do not attempt to continue parsing.'
121
121
  else
122
122
  # Advance to the next element
123
123
  read
@@ -160,22 +160,10 @@ module Tilia
160
160
 
161
161
  attributes = {}
162
162
 
163
- attributes = parse_attributes if self.has_attributes?
163
+ attributes = parse_attributes if has_attributes?
164
164
 
165
- if @element_map.key? name
166
- deserializer = @element_map[name]
165
+ value = deserializer_for_element_name(name).call(self)
167
166
 
168
- if deserializer.is_a?(Class) && deserializer.include?(XmlDeserializable)
169
- value = deserializer.xml_deserialize(self)
170
- elsif deserializer.is_a? Proc
171
- value = deserializer.call(self)
172
- else
173
- # Omit php stuff for error creation
174
- fail "Could not use this type as a deserializer: #{deserializer.inspect}"
175
- end
176
- else
177
- value = Element::Base.xml_deserialize(self)
178
- end
179
167
  {
180
168
  'name' => name,
181
169
  'value' => value,
@@ -211,27 +199,44 @@ module Tilia
211
199
  attributes
212
200
  end
213
201
 
214
- # TODO: document this
215
- def initialize
216
- initialize_context_stack_attributes
217
- end
218
-
219
- # TODO: documentation
202
+ # Fakes PHP method xml
203
+ #
204
+ # Creates a new XML::Reader instance
205
+ #
206
+ # @return [XML::Reader]
220
207
  def xml(input)
221
- fail 'XML document already loaded' if @reader
208
+ raise 'XML document already loaded' if @reader
222
209
 
223
- if input.is_a? String
210
+ if input.is_a?(String)
224
211
  @reader = ::LibXML::XML::Reader.string(input)
225
- elsif input.is_a? File
212
+ elsif input.is_a?(File)
226
213
  @reader = ::LibXML::XML::Reader.file(input)
227
- elsif input.is_a? StringIO
214
+ elsif input.is_a?(StringIO)
228
215
  @reader = ::LibXML::XML::Reader.io(input)
229
216
  else
230
- fail 'Unable to load XML document'
217
+ raise 'Unable to load XML document'
231
218
  end
232
219
  end
233
220
 
234
- # TODO: documentation
221
+ # Returns the function that should be used to parse the element identified
222
+ # by it's clark-notation name.
223
+ #
224
+ # @param [String] name
225
+ # @return [#call]
226
+ def deserializer_for_element_name(name)
227
+ return Element::Base.method(:xml_deserialize) unless @element_map.key?(name)
228
+
229
+ deserializer = @element_map[name]
230
+ return deserializer if deserializer.respond_to?(:call)
231
+
232
+ return deserializer.method(:xml_deserialize) if deserializer.include?(XmlDeserializable)
233
+
234
+ raise "Could not use this type as a deserializer: #{deserializer.inspect} for element: #{name}"
235
+ end
236
+
237
+ # Delegates missing methods to XML::Reader instance
238
+ #
239
+ # @return [void]
235
240
  def method_missing(name, *args)
236
241
  @reader.send(name, *args)
237
242
  end