tilia-xml 1.2.0.2 → 1.3.0

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.
@@ -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