sdl4r 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,4 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
@@ -12,6 +13,7 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
  module SDL4R
17
19
 
@@ -20,7 +22,7 @@ module SDL4R
20
22
  # Gives access to the characters read to the Parser.
21
23
  # This class was designed to gather the handling of the UTF-8 issues in one place and shield the
22
24
  # Parser class from these problems.
23
- class Reader
25
+ class Reader # :nodoc: all
24
26
 
25
27
  RUBY_1_8_OR_LESS = require 'jcode'
26
28
 
@@ -1,3 +1,4 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
@@ -12,6 +13,7 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
  module SDL4R
17
19
 
@@ -22,7 +24,7 @@ module SDL4R
22
24
  #
23
25
  # +seconds+ can have a fraction
24
26
  # +time_zone_offset+ is a fraction of a day (equal to nil if not specified)
25
- class TimeSpanWithZone
27
+ class TimeSpanWithZone # :nodoc: all
26
28
 
27
29
  private
28
30
 
@@ -1,3 +1,4 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
@@ -12,6 +13,7 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
  module SDL4R
17
19
 
@@ -23,7 +25,7 @@ module SDL4R
23
25
  #
24
26
  # @author Daniel Leuck, Philippe Vosges
25
27
  #
26
- class Token
28
+ class Token # :nodoc: all
27
29
 
28
30
  def initialize(text, line = -1, position = -1)
29
31
  @text = text
@@ -1,3 +1,4 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
@@ -12,6 +13,7 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
 
17
19
  module SDL4R
@@ -22,7 +24,7 @@ module SDL4R
22
24
  class Parser
23
25
 
24
26
  # Tokenizer of the SDL parser
25
- class Tokenizer
27
+ class Tokenizer # :nodoc: all
26
28
 
27
29
  TOKEN_TYPES = [
28
30
  :IDENTIFIER,
data/lib/sdl4r/sdl.rb CHANGED
@@ -1,3 +1,4 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
@@ -12,24 +13,16 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15
-
16
+ #++
16
17
 
17
18
  require 'jcode'
18
19
  require 'base64'
19
20
  require 'rational'
20
21
  require 'date'
21
22
 
22
- # Various SDL related utility methods
23
+ # Gathers utility methods.
23
24
  #
24
25
  module SDL4R
25
-
26
- # Creates and returns a tag named "root" and add all the tags specified in the given +input+.
27
- #
28
- # +input+:: String, IO, Pathname or URI.
29
- #
30
- def self.read(input)
31
- Tag.new("root").read(input)
32
- end
33
26
 
34
27
  MAX_INTEGER_32 = 2**31 - 1
35
28
  MIN_INTEGER_32 = -(2**31)
@@ -42,8 +35,7 @@ module SDL4R
42
35
  # Creates an SDL string representation for a given object and returns it.
43
36
  #
44
37
  # +o+:: the object to format
45
- # +add_quotes+:: indicates whether quotes will be added to Strings and characters
46
- # (true by default)
38
+ # +add_quotes+:: indicates whether quotes will be added to Strings and characters (true by default)
47
39
  # +line_prefix+:: the line prefix to use ("" by default)
48
40
  # +indent+:: the indent string to use ("\t" by default)
49
41
  #
@@ -130,7 +122,10 @@ module SDL4R
130
122
  end
131
123
  end
132
124
 
133
- # This method was kept from the Java code but it is not sure if it should have a usefulness yet.
125
+ # Coerce the type to a standard SDL type or raises an ArgumentError.
126
+ #
127
+ # For the time being, just returns +o+ thus allowing to add anything to the SDL tags. This might
128
+ # not be allowed in the future.
134
129
  #
135
130
  def self.coerce_or_fail(o)
136
131
  return o
@@ -138,10 +133,10 @@ module SDL4R
138
133
 
139
134
  # Validates an SDL identifier String. SDL Identifiers must start with a
140
135
  # Unicode letter or underscore (_) and contain only unicode letters,
141
- # digits, underscores (_), and dashes(-).
136
+ # digits, underscores (_), dashes(-) and periods (.).
142
137
  #
143
- # @param identifier The identifier to validate
144
- # @throws IllegalArgumentException if the identifier is not legal
138
+ # == Raises
139
+ # ArgumentError if the identifier is not legal
145
140
  #
146
141
  # TODO: support UTF-8 identifiers
147
142
  #
@@ -173,8 +168,36 @@ module SDL4R
173
168
  end
174
169
  end
175
170
 
171
+ # Creates and returns a tag named "root" and add all the tags specified in the given +input+.
172
+ #
173
+ # +input+:: String, IO, Pathname or URI.
174
+ #
175
+ # root = SDL4R::read(<<EOF
176
+ # planets {
177
+ # earth area_km2=510900000
178
+ # mars
179
+ # }
180
+ # EOF
181
+ # )
182
+ #
183
+ # root = SDL4R::read(Pathname.new("my_dir/my_file.sdl"))
184
+ #
185
+ # IO.open("my_dir/my_file.sdl", "r") { |io|
186
+ # root = SDL4R::read(io)
187
+ # }
188
+ #
189
+ # root = SDL4R::read(URI.new("http://my_site/my_file.sdl"))
190
+ #
191
+ def self.read(input)
192
+ Tag.new("root").read(input)
193
+ end
194
+
176
195
  # Parses and returns the value corresponding with the specified SDL literal.
177
196
  #
197
+ # SDL4R.to_value("\"abcd\"") # => "abcd"
198
+ # SDL4R.to_value("1") # => 1
199
+ # SDL4R.to_value("null") # => nil
200
+ #
178
201
  def self.to_value(s)
179
202
  raise ArgumentError, "'s' cannot be null" if s.nil?
180
203
  return read(s).child.value
@@ -185,7 +208,7 @@ module SDL4R
185
208
  #
186
209
  # Example
187
210
  #
188
- # array = SDL4R.to_values("1 true 12:24:01")
211
+ # array = SDL4R.to_value_array("1 true 12:24:01")
189
212
  #
190
213
  # Will return an int, a boolean, and a time span.
191
214
  #
@@ -201,7 +224,7 @@ module SDL4R
201
224
  #
202
225
  # hash = SDL4R.to_attribute_hash("value=1 debugging=on time=12:24:01");
203
226
  #
204
- # Will return a map containing value=1, debugging=true, and time=12:24:01
227
+ # # { "value" => 1, "debugging" => true, "time" => SdlTimeSpan.new(12, 24, 01) }
205
228
  #
206
229
  def self.to_attribute_map(s)
207
230
  raise ArgumentError, "'s' cannot be null" if s.nil?
@@ -1,3 +1,4 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
@@ -12,12 +13,13 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
 
17
19
  module SDL4R
18
20
 
19
- #
20
21
  # Represents a binary value.
22
+ #
21
23
  # This class was introduced to avoid the confusion between a Ruby String and a binary literal.
22
24
  #
23
25
  class SdlBinary
@@ -35,9 +37,7 @@ module SDL4R
35
37
  return self.bytes == o.bytes
36
38
  end
37
39
 
38
- def eql?(o)
39
- self == o
40
- end
40
+ alias_method :eql?, :==
41
41
 
42
42
  def hash
43
43
  return bytes.hash
@@ -1,8 +1,9 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
4
- # This program is free software. You can distribute or modify it under the
5
- # terms of the GNU Lesser General Public License version 2.1 as published by
5
+ # This program is free software. You can distribute or modify it under the
6
+ # terms of the GNU Lesser General Public License version 2.1 as published by
6
7
  # the Free Software Foundation.
7
8
  #
8
9
  # This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
@@ -12,6 +13,7 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
 
17
19
  module SDL4R
@@ -1,8 +1,9 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
4
- # This program is free software. You can distribute or modify it under the
5
- # terms of the GNU Lesser General Public License version 2.1 as published by
5
+ # This program is free software. You can distribute or modify it under the
6
+ # terms of the GNU Lesser General Public License version 2.1 as published by
6
7
  # the Free Software Foundation.
7
8
  #
8
9
  # This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
@@ -12,6 +13,7 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
 
17
19
  module SDL4R
@@ -123,120 +125,91 @@ module SDL4R
123
125
 
124
126
  # Get the total number of hours in this time span. For example, if
125
127
  # this time span represents two days, this method will return 48.
126
- #
127
- # @return This timespan in hours
128
128
  #
129
129
  def total_hours
130
130
  return sign * (@totalMilliseconds.abs / MILLISECONDS_IN_HOUR)
131
131
  end
132
132
 
133
- #
134
133
  # Get the total number of minutes in this time span. For example, if
135
134
  # this time span represents two hours, this method will return 120.
136
- #
137
- # @return This timespan in minutes
138
135
  #
139
136
  def total_minutes
140
137
  return sign * (@totalMilliseconds.abs / MILLISECONDS_IN_MINUTE)
141
138
  end
142
139
 
143
- #
144
140
  # Get the total number of seconds in this time span. For example, if
145
141
  # this time span represents three minutes, this method will return 180.
146
- #
147
- # @return This timespan in seconds
148
142
  #
149
143
  def total_seconds
150
144
  return sign * (@totalMilliseconds.abs / MILLISECONDS_IN_SECOND)
151
145
  end
152
146
 
153
- #
154
147
  # Get the total number of milliseconds in this time span. For example, if
155
148
  # this time span represents 4 seconds, this method will return 4000.
156
- #
157
- # @return This timespan in milliseconds
158
149
  #
159
150
  def total_milliseconds
160
151
  return @totalMilliseconds
161
152
  end
162
153
 
163
- #
164
154
  # Returns an new SdlTimeSpan instance that is the opposite of this
165
155
  # instance
166
- #
167
- # @return An instance representing the inverse of this instance
168
156
  #
169
157
  def negate
170
158
  SdlTimeSpan.new(-@totalMilliseconds)
171
159
  end
172
160
 
173
- #
174
161
  # Return a new instance with the days adjusted by the given amount.
175
- # Positive numbers add days. Negative numbers remove days.
162
+ # Positive numbers add days. Negative numbers remove days.
176
163
  #
177
- # @param days The adjustment (days to add or subtract)
178
- # @return A new instance with the given adjustment.
164
+ # +days+:: The adjustment (days to add or subtract)
179
165
  #
180
166
  def roll_days(days)
181
167
  SdlTimeSpan.new(@totalMilliseconds + (days * MILLISECONDS_IN_DAY))
182
168
  end
183
169
 
184
- #
185
170
  # Return a new instance with the hours adjusted by the given amount.
186
171
  # Positive numbers add hours. Negative numbers remove hours.
187
172
  #
188
- # @param hours The adjustment (hours to add or subtract)
189
- # @return A new instance with the given adjustment.
173
+ # +hours+:: The adjustment (hours to add or subtract)
190
174
  #
191
175
  def roll_hours(hours)
192
176
  SdlTimeSpan.new(@totalMilliseconds + (hours * MILLISECONDS_IN_HOUR))
193
177
  end
194
178
 
195
- #
196
179
  # Return a new instance with the minutes adjusted by the given amount.
197
180
  # Positive numbers add minutes. Negative numbers remove minutes.
198
181
  #
199
- # @param minutes The adjustment (minutes to add or subtract)
200
- # @return A new instance with the given adjustment.
182
+ # +minutes+:: The adjustment (minutes to add or subtract)
201
183
  #
202
184
  def roll_minutes(minutes)
203
185
  SdlTimeSpan.new(@totalMilliseconds + (minutes * MILLISECONDS_IN_MINUTE))
204
186
  end
205
187
 
206
- #
207
188
  # Return a new instance with the seconds adjusted by the given amount.
208
189
  # Positive numbers add seconds. Negative numbers remove seconds.
209
190
  #
210
- # @param seconds The adjustment (seconds to add or subtract)
211
- # @return A new instance with the given adjustment.
191
+ # +seconds+:: The adjustment (seconds to add or subtract)
212
192
  #
213
193
  def roll_seconds(seconds)
214
194
  SdlTimeSpan.new(@totalMilliseconds + (seconds * MILLISECONDS_IN_SECOND))
215
195
  end
216
196
 
217
- #
218
197
  # Return a new instance with the milliseconds adjusted by the given amount.
219
198
  # Positive numbers add milliseconds. Negative numbers remove milliseconds.
220
199
  #
221
- # @param milliseconds The adjustment (milliseconds to add or subtract)
222
- # @return A new instance with the given adjustment.
200
+ # +milliseconds+:: The adjustment (milliseconds to add or subtract)
223
201
  #
224
202
  def roll_milliseconds(milliseconds)
225
203
  SdlTimeSpan.new(@totalMilliseconds + milliseconds)
226
204
  end
227
205
 
228
- #
229
206
  # A hashcode based on the canonical string representation.
230
- #
231
- # @return A hashcode for this time span
232
207
  #
233
208
  def hash
234
209
  to_s.hash
235
210
  end
236
211
 
237
212
  # Tests for equivalence.
238
- #
239
- # @return true If the given object is equivalent
240
213
  #
241
214
  def eql?(other)
242
215
  other.is_a?(SdlTimeSpan) and @totalMilliseconds == other.total_milliseconds
@@ -249,27 +222,22 @@ module SDL4R
249
222
  @totalMilliseconds <=> other.total_milliseconds
250
223
  end
251
224
 
252
- # <p>Returns an SDL representation of this time span using the format:<p>
225
+ # Returns an SDL representation of this time span using the format:
253
226
  #
254
- # <pre>
255
- # (days:)hours:minutes:seconds(.milliseconds)
256
- # </pre>
227
+ # (days:)hours:minutes:seconds(.milliseconds)
257
228
  #
258
- # <p>(parenthesis indicate optional components)
229
+ # (parenthesis indicate optional components)
259
230
  #
260
- # <p>The days and milliseconds components will not be included if they
261
- # are set to 0. Days must be suffixed with "d" for clarity.</p>
231
+ # The days and milliseconds components will not be included if they
232
+ # are set to 0. Days must be suffixed with "d" for clarity.
262
233
  #
263
- # <p>Hours, minutes, and seconds will be zero paded to two characters.</p>
234
+ # Hours, minutes, and seconds will be zero paded to two characters.
235
+ #
236
+ # Examples:
264
237
  #
265
- # <p>Examples:</p>
266
- # <pre>
267
238
  # 23:13:00 (12 hours and 13 minutes)
268
239
  # 24d:12:13:09.234 (24 days, 12 hours, 13 minutes, 9 seconds,
269
240
  # 234 milliseconds)
270
- # </pre>
271
- #
272
- # @return an SDL representation of this time span
273
241
  #
274
242
  def to_s
275
243
  _days = days
data/lib/sdl4r/tag.rb CHANGED
@@ -1,3 +1,4 @@
1
+ #--
1
2
  # Simple Declarative Language (SDL) for Ruby
2
3
  # Copyright 2005 Ikayzo, inc.
3
4
  #
@@ -12,6 +13,7 @@
12
13
  # You should have received a copy of the GNU Lesser General Public License
13
14
  # along with this program; if not, contact the Free Software Foundation, Inc.,
14
15
  # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+ #++
15
17
 
16
18
 
17
19
  module SDL4R
@@ -23,306 +25,81 @@ module SDL4R
23
25
  require File.dirname(__FILE__) + '/sdl'
24
26
  require File.dirname(__FILE__) + '/parser'
25
27
 
26
- # SDL (Simple Declarative Language) documents are made up of Tags. A Tag
27
- # contains
28
- #
29
- # * a name (if not present, the name "content" is used)
30
- # * a namespace (optional)
31
- # * 0 or more values (optional)
32
- # * 0 or more attributes (optional)
33
- # * 0 or more children (optional)
34
- #
35
- # For the SDL code:
36
- #
37
- # size 4
38
- # smoker false
39
- #
40
- #
41
- # Assuming this code is in a file called values.sdl, the values can be read
42
- # using the following code (ignoring exceptions):
43
- #
44
- # root = Tag.new("root").read(new File("values.sdl"));
45
- # int size = root.getChild("size").intValue();
46
- # boolean smoker = root.getChild("smoker").booleanValue();
47
- #
48
- # A tag is basically a data structure with a list of values, a map of
49
- # attributes, and (if it has a body) child tags. In the example above, the
50
- # "values.sdl" file is read into a tag called "root". It has two children
51
- # (tags) called "size" and "smoker". Both these children have one value, no
52
- # attributes, and no bodies.
53
- #
54
- # SDL is often used for simple key-value mappings. To simplify things Tag
55
- # has the methods getValue and setValue which operate on the first element in
56
- # the values list. Also notice SDL understands types which are determined
57
- # using type inference.
58
- #
59
- # The example above used the simple format common in property files:
60
- #
61
- # name value
62
- #
63
- # The full SDL tag format is:
64
- #
65
- # namespace:name value_list attribute_list {
66
- # children_tags
67
- # }
68
- #
69
- # where value_list is zero or more space separated SDL literals and
70
- # attribute_list is zero or more space separated (namespace:)key=value pairs.
71
- # The name, namespace, and keys are SDL identifiers. Values are SDL literals.
72
- # Namespace is optional for both tag names and attributes. Tag bodies are also
73
- # optional. SDL identifiers begin with a unicode letter or an underscore (_)
74
- # followed by zero or more unicode letters, numbers, underscores (_) and
75
- # dashes (-).
76
- #
77
- # SDL also supports anonymous tags which are assigned the name "content".
78
- # An annoymous tag starts with a literal and is followed by zero or more
79
- # additional literals and zero or more attributes. The examples section below
80
- # demonstrates the use of anonymous tags.
81
- #
82
- # Tags without bodies are terminated by a new line character (\n) and may be
83
- # continue onto the next line by placing a backslash (\) at the end of the
84
- # line. Tags may be nested to an arbitrary depth. SDL ignores all other white
85
- # space characters between tokens. Although nested blocks are indented by
86
- # convention, tabs have no significance in the language.
87
- #
88
- # There are two ways to write String literals.
89
- #
90
- # 1. Starting and ending with double quotes ("). Double quotes, backslash
91
- # characters (\), and new lines (\n) within this type of String literal
92
- # must be escaped like so:
93
- #
94
- # file "C:\\folder\\file.txt"
95
- # say "I said \"something\""
96
- #
97
- # This type of String literal can be continued on the next line by placing a
98
- # backslash (\) at the end of the line like so:
99
- #
100
- # line "this is a \
101
- # long string of text"
102
- #
103
- # White space before the first character in the second line will be ignored.
104
- #
105
- # 2. Starting and ending with a backquote (`). This type of string literal
106
- # can only be ended with a second backquote (`). It is not necessary (or
107
- # possible) to escape any type of character within a backquote string
108
- # literal. This type of literal can also span lines. All white spaces are
109
- # preserved including new lines.
110
- #
111
- # Examples:
112
- #
113
- # file `C:\folder\file.txt`
114
- # say `I said "something"`
115
- # regex `\w+\.suite\(\)`
116
- # long_line `This is
117
- # a long line
118
- # fee fi fo fum`
119
- #
120
- # Note: SDL interprets new lines in `` String literals as a single new line
121
- # character (\n) regarless of the platform.
122
- #
123
- # Binary literals use base64 characters enclosed in square brackets ([]).
124
- # The binary literal type can also span lines. White space is ignored.
125
- #
126
- #
127
- # Examples:
128
- # key [sdf789GSfsb2+3324sf2] name="my key"
129
- # image [
130
- # R3df789GSfsb2edfSFSDF
131
- # uikuikk2349GSfsb2edfS
132
- # vFSDFR3df789GSfsb2edf
133
- # ]
134
- # upload from="ikayzo.com" data=[
135
- # R3df789GSfsb2edfSFSDF
136
- # uikuikk2349GSfsb2edfS
137
- # vFSDFR3df789GSfsb2edf
138
- # ]
139
- #
140
- # SDL supports date, time span, and date/time literals. Date and Date/Time
141
- # literals use a 24 hour clock (0-23). If a timezone is not specified, the
142
- # default locale's timezone will be used.
28
+ # SDL documents are made of Tags.
143
29
  #
144
- # Examples:
145
- #
146
- # # create a tag called "date" with a date value of Dec 5, 2005
147
- # date 2005/12/05
148
- #
149
- # # various time span literals
150
- # hours 03:00:00
151
- # minutes 00:12:00
152
- # seconds 00:00:42
153
- # short_time 00:12:32.423 # 12 minutes, 32 seconds, 423 milliseconds
154
- # long_time 30d:15:23:04.023 # 30 days, 15 hours, 23 mins, 4 secs, 23 millis
155
- # before -00:02:30 # 2 hours and 30 minutes ago
156
- #
157
- # # a date time literal
158
- # in_japan 2005/12/05 14:12:23.345-JST
159
- #
160
- #
161
- # SDL 1.0 has thirteen literal types (parenthesis indicate optional components)
162
- #
163
- # 1. string (unicode) - examples: "hello" or `aloha`
164
- # 2. character (unicode) - example: '/'
165
- # Note: &#92;uXXXX style unicode escapes are not supported (or
166
- # needed because sdl files are UTF8)
167
- # 3. integer (32 bits signed) - example: 123
168
- # 4. long integer (64 bits signed) - examples: 123L or 123l
169
- # 5. float (32 bits signed) - examples 123.43F 123.43f
170
- # 6. double float (64 bits signed) - example: 123.43 or 123.43d or 123.43D
171
- # 7. decimal (128+ bits signed) - example: 123.44BD or 123.44bd
172
- # 8. boolean - examples: true or false or on or off
173
- # 9. date yyyy/mm/dd - example 2005/12/05
174
- # 10. date time yyyy/mm/dd hh:mm(:ss)(.xxx)(-ZONE)
175
- # example - 2005/12/05 05:21:23.532-JST
176
- # notes: uses a 24 hour clock (0-23), only hours and minutes are
177
- # mandatory
178
- # 11. time span using the format (d:)hh:mm:ss(.xxx)
179
- # notes: if the day component is included it must be suffixed with
180
- # a lower case 'd'
181
- # examples 12:14:42 (12 hours, 14 minutes, 42 seconds)
182
- # 00:09:12 (9 minutes, 12 seconds)
183
- # 00:00:01.023 (1 second, 23 milliseconds)
184
- # 23d:05:21:23.532 (23 days, 5 hours, 21 minutes,
185
- # 23 seconds, 532 milliseconds)
186
- # 12. binary [base64] exmaple - [sdf789GSfsb2+3324sf2]
187
- # 13. null
188
- #
189
- #
190
- # Timezones must be specified using a valid time zone ID (ex. America/Los_Angeles), three letter
191
- # abbreviation (ex. HST), or GMT(+/-)hh(:mm) formatted custom timezone (ex. GMT+02 or GMT+02:30)
192
- #
193
- # Note: SDL 1.1 will likely add a reference literal type.
194
- #
195
- # These types are designed to be portable across Java, .NET, and other
196
- # popular platforms.
197
- #
198
- #
199
- # SDL supports four comment types.
200
- #
201
- # 1. // single line comments identicle to those used in Java, C, etc. // style
202
- # comments can occur anywhere in a line. All text after // up to the new line
203
- # will be ignored.
204
- # 2. # property style comments. They work the same way as //
205
- # 3. -- separator comments useful for visually dividing content. They work the same way as //
206
- # 4. Slash star (/*) style multiline comments. These begin with a slash
207
- # star and end with a star slash. Everything in between is ignored.
208
- #
209
- #
210
- #
211
- # An example SDL file:
212
- #
213
- # # a tag having only a name
214
- # my_tag
215
- #
216
- # # three tags acting as name value pairs
217
- # first_name "Akiko"
218
- # last_name "Johnson"
219
- # height 68
220
- #
221
- # # a tag with a value list
222
- # person "Akiko" "Johnson" 68
223
- #
224
- # # a tag with attributes
225
- # person first_name="Akiko" last_name="Johnson" height=68
226
- #
227
- # # a tag with values and attributes
228
- # person "Akiko" "Johnson" height=60
229
- #
230
- # # a tag with attributes using namespaces
231
- # person name:first-name="Akiko" name:last-name="Johnson"
232
- #
233
- # # a tag with values, attributes, namespaces, and children
234
- # my_namespace:person "Akiko" "Johnson" dimensions:height=68 {
235
- # son "Nouhiro" "Johnson"
236
- # daughter "Sabrina" "Johnson" location="Italy" {
237
- # hobbies "swimming" "surfing"
238
- # languages "English" "Italian"
239
- # smoker false
240
- # }
241
- # }
242
- #
243
- # ------------------------------------------------------------------
244
- # // (notice the separator style comment above...)
245
- #
246
- # # a log entry
247
- # # note - this tag has two values (date_time and string) and an
248
- # # attribute (error)
249
- # entry 2005/11/23 10:14:23.253-GMT "Something bad happened" error=true
250
- #
251
- # # a long line
252
- # mylist "something" "another" true "shoe" 2002/12/13 "rock" \
253
- # "morestuff" "sink" "penny" 12:15:23.425
254
- #
255
- # # a long string
256
- # text "this is a long rambling line of text with a continuation \
257
- # and it keeps going and going..."
258
- #
259
- # # anonymous tag examples
260
- #
261
- # files {
262
- # "/folder1/file.txt"
263
- # "/file2.txt"
264
- # }
265
- #
266
- # # To retrieve the files as a list of strings
267
- # #
268
- # # List files = tag.getChild("files").getChildrenValues("content");
269
- # #
270
- # # We us the name "content" because the files tag has two children, each of
271
- # # which are anonymous tags (values with no name.) These tags are assigned
272
- # # the name "content"
273
- #
274
- # matrix {
275
- # 1 2 3
276
- # 4 5 6
277
- # }
278
- #
279
- # # To retrieve the values from the matrix (as a list of lists)
280
- # #
281
- # # List rows = tag.getChild("matrix").getChildrenValues("content");
282
- #
283
- #
284
- # Example of getting the "location" attribute from the "daughter" tag
285
- # above (ignoring exceptions)
286
- #
287
- # Tag root = new Tag("root").read("myfile.sdl");
288
- # Tag daughter = root.getChild("daughter", true); // recursive search
289
- # String location = daughter.getAttribute("location").toString();
290
- #
291
- # SDL is normally stored in a file with the .sdl extension. These files
292
- # should always be encoded using UTF8. SDL fully supports unicode in
293
- # identifiers and literals.
294
- #
295
- # @author Daniel Leuck
30
+ # Do not assume that methods returning sets (Hash, Array, etc) of children/values/attributes/etc
31
+ # in this class returns copies or implementations. It can be one or the other depending on the
32
+ # method. The implementations are designed to be fast and correct, not too protect the Tag
33
+ # instances from ill-use of the returned values.
34
+ #
35
+ # See the README[link:files/README.html] for a longer explanation on SDL documents.
36
+ #
37
+ # == Authors
38
+ # Daniel Leuck, Philippe Vosges
296
39
  #
297
40
  class Tag
298
41
 
299
- #
300
42
  # the name of this Tag
301
43
  #
302
44
  attr_reader :name
303
45
 
304
- #
305
- # the namespace of this Tag or an empty string when there is no namespace.
46
+ # the namespace of this Tag or an empty string when there is no namespace (i.e. default
47
+ # namespace).
306
48
  #
307
49
  attr_reader :namespace
50
+
51
+ # Convenient method to check and handle a pair of parameters namespace/name where, in some
52
+ # cases, only one is specified (i.e. the name only).
53
+ #
54
+ # Use at the beginning of a method in order to have correctly defined parameters:
55
+ # def foo(namespace, name = nil)
56
+ # namespace, name = to_nns namespace, name
57
+ # end
58
+ #
59
+ def to_nns(namespace, name)
60
+ if name.nil? and not namespace.nil?
61
+ name = namespace
62
+ namespace = ""
63
+ end
64
+ return namespace, name
65
+ end
66
+ private :to_nns
308
67
 
309
- # Creates an empty tag in the given namespace. If the +namespace+ is null
68
+ # Creates an empty tag in the given namespace. If the +namespace+ is nil
310
69
  # it will be coerced to an empty String.
311
70
  #
312
- # +namespace+:: the namespace for this tag
313
- # +name+:: the name of this tag
314
- #
315
- # Throws ArgumentError if the name is not a legal SDL identifier
316
- # (see SDL#validate_identifier) or the namespace is non-blank
71
+ # tag = Tag.new("name")
72
+ # tag = Tag.new("namespace", "name")
73
+ #
74
+ # tag = Tag.new("fruit") do
75
+ # add_value 2
76
+ # new_child("orange") do
77
+ # set_attribute("quantity", 2)
78
+ # end
79
+ # end
80
+ #
81
+ # which builds the following SDL structure
82
+ #
83
+ # fruit 2 {
84
+ # orange quantity=2
85
+ # }
86
+ #
87
+ # ==Raises
88
+ # ArgumentError if the name is not a legal SDL identifier
89
+ # (see SDL4R#validate_identifier) or the namespace is non-blank
317
90
  # and is not a legal SDL identifier.
318
91
  #
319
- def initialize(name, namespace = "", &block)
320
- namespace = namespace.to_s
92
+ def initialize(namespace, name = nil, &block)
93
+ namespace, name = to_nns namespace, name
94
+
95
+ raise ArgumentError, "tag namespace must be a String" unless namespace.is_a? String
96
+ raise ArgumentError, "tag name must be a String" unless name.is_a? String
97
+
321
98
  SDL4R.validate_identifier(namespace) unless namespace.empty?
322
99
  @namespace = namespace
323
100
 
324
101
  name = name.to_s.strip
325
- raise ArgumentError, "Tag name cannot be null or empty" if name.empty?
102
+ raise ArgumentError, "Tag name cannot be nil or empty" if name.empty?
326
103
  SDL4R.validate_identifier(name)
327
104
  @name = name
328
105
 
@@ -366,9 +143,26 @@ module SDL4R
366
143
 
367
144
  # Adds the given object as a child if it is a +Tag+, as an attribute if it is a Hash
368
145
  # {key => value} (supports namespaces), or as a value otherwise.
146
+ # If it is an array, each of its elements is added to this Tag via this operator. If any of its
147
+ # elements is itself an array, then an anonymous tag is created and the array is passed to it
148
+ # via this operator (see the examples below)
149
+ #
150
+ # tag << Tag.new("child")
151
+ # tag << 123 # new integer value
152
+ # tag << "islamabad" # new string value
153
+ # tag << { "metric:length" => 1027 } # new attribute (with namespace)
154
+ # tag << [nil, 456, "abc"] # several values added
155
+ #
156
+ # tag = Tag.new("tag")
157
+ # tag << [[1, 2, 3], [4, 5, 6]] # tag {
158
+ # # 1 2 3
159
+ # # 4 5 6
160
+ # # }
369
161
  #
370
162
  # Returns +self+.
371
163
  #
164
+ # Use other accessors for a stricter and less "magical" behavior.
165
+ #
372
166
  def <<(o)
373
167
  if o.is_a?(Tag)
374
168
  add_child(o)
@@ -376,7 +170,16 @@ module SDL4R
376
170
  o.each_pair { |key, value|
377
171
  namespace, key = key.split(/:/) if key.match(/:/)
378
172
  namespace ||= ""
379
- set_attribute(key, value, namespace)
173
+ set_attribute(namespace, key, value)
174
+ }
175
+ elsif o.is_a? Array
176
+ o.each { |item|
177
+ if item.is_a? Array
178
+ anonymous = new_child("content")
179
+ anonymous << item
180
+ else
181
+ self << item
182
+ end
380
183
  }
381
184
  else
382
185
  add_value(o)
@@ -424,16 +227,34 @@ module SDL4R
424
227
  @children.size
425
228
  end
426
229
 
427
- # Returns an Array of the children Tags of this Tag.
230
+ # children(recursive)
231
+ # children(recursive, name)
232
+ # children(recursive, namespace, name)
233
+ #
234
+ # children(recursive) { |child| ... }
235
+ # children(recursive, name) { |child| ... }
236
+ # children(recursive, namespace, name) { |child| ... }
237
+ #
238
+ # Returns an Array of the children Tags of this Tag or enumerates them.
428
239
  #
429
240
  # +recursive+:: if true children and all descendants will be returned. False by default.
430
241
  # +name+:: if not nil, only children having this name will be returned. Nil by default.
431
- # +namespace+:: if not nil, only children having this namespace will be returned.
432
- # Nil by default.
242
+ # +namespace+:: use nil for all namespaces and "" for the default one. Nil by default.
433
243
  #
434
- def children(recursive = false, name = nil, namespace = nil, &block)
244
+ # tag.children # => array of the children
245
+ # tag.children(true) { |descendant| ... }
246
+ #
247
+ # tag.children(false, "name") # => children of name "name"
248
+ # tag.children(false, "ns", nil) # => children of namespace "ns"
249
+ #
250
+ def children(recursive = false, namespace = nil, name = :DEFAULT, &block) # :yields: child
251
+ if name == :DEFAULT
252
+ name = namespace
253
+ namespace = nil
254
+ end
255
+
435
256
  if block_given?
436
- each_child(recursive, name, namespace, &block)
257
+ each_child(recursive, namespace, name, &block)
437
258
 
438
259
  else
439
260
  unless recursive or name or namespace
@@ -441,7 +262,7 @@ module SDL4R
441
262
 
442
263
  else
443
264
  result = []
444
- each_child(recursive, name, namespace) { |child|
265
+ each_child(recursive, namespace, name) { |child|
445
266
  result << child
446
267
  }
447
268
  return result
@@ -450,7 +271,7 @@ module SDL4R
450
271
  end
451
272
 
452
273
  # Returns the values of all the children with the given +name+. If the child has
453
- # more than one value, all the values will be added as a list. If the child
274
+ # more than one value, all the values will be added as an array. If the child
454
275
  # has no value, +nil+ will be added. The search is not recursive.
455
276
  #
456
277
  # +name+:: if nil, all children are considered (nil by default).
@@ -469,6 +290,10 @@ module SDL4R
469
290
  return children_values
470
291
  end
471
292
 
293
+ # child
294
+ # child(name)
295
+ # child(recursive, name)
296
+ #
472
297
  # Get the first child with the given name, optionally using a recursive search.
473
298
  #
474
299
  # +name+:: the name of the child Tag. If +nil+, the first child is returned (+nil+ if there are
@@ -476,7 +301,12 @@ module SDL4R
476
301
  #
477
302
  # Returns the first child tag having the given name or +nil+ if no such child exists
478
303
  #
479
- def child(name = nil, recursive = false)
304
+ def child(recursive = false, name = nil)
305
+ if name.nil?
306
+ name = recursive
307
+ recursive = false
308
+ end
309
+
480
310
  unless name
481
311
  return @children.first
482
312
  else
@@ -502,17 +332,22 @@ module SDL4R
502
332
  # providing it the child as parameter.
503
333
  #
504
334
  # +recursive+:: if true, enumerate grand-children, etc, recursively
505
- # +name+:: if not nil, indicates the name of the children to enumerate
506
335
  # +namespace+:: if not nil, indicates the namespace of the children to enumerate
336
+ # +name+:: if not nil, indicates the name of the children to enumerate
507
337
  #
508
- def each_child(recursive = false, name = nil, namespace = nil, &block)
338
+ def each_child(recursive = false, namespace = nil, name = :DEFAULT, &block)
339
+ if name == :DEFAULT
340
+ name = namespace
341
+ namespace = nil
342
+ end
343
+
509
344
  @children.each do |child|
510
345
  if (name.nil? or child.name == name) and
511
346
  (namespace.nil? or child.namespace == namespace)
512
347
  yield child
513
348
  end
514
349
 
515
- child.children(recursive, name, namespace, &block) if recursive
350
+ child.children(recursive, namespace, name, &block) if recursive
516
351
  end
517
352
  return nil
518
353
  end
@@ -556,14 +391,11 @@ module SDL4R
556
391
  return hash
557
392
  end
558
393
 
559
- # Adds a value to this Tag. The allowable types are String, Number,
560
- # Boolean, Character, byte[], Byte[] (coerced to byte[]), Calendar,
561
- # Date (coerced to Calendar), and null. Passing any other type will
562
- # result in an IllegalArgumentException.
563
- #
394
+ # Adds a value to this Tag. See SDL4R#coerce_or_fail to know about the allowable types.
395
+ #
564
396
  # +v+:: The value to add
565
397
  #
566
- # Raises a +ArgumentError+ if the value is not a legal SDL type
398
+ # Raises an +ArgumentError+ if the value is not a legal SDL type
567
399
  #
568
400
  def add_value(v)
569
401
  @values.push(SDL4R::coerce_or_fail(v))
@@ -575,14 +407,19 @@ module SDL4R
575
407
  @values.include?(v)
576
408
  end
577
409
 
578
- # Remove a value from this Tag.
410
+ # Removes the first occurence of the specified value from this Tag.
579
411
  #
580
412
  # +v+:: The value to remove
581
413
  #
582
414
  # Returns true If the value exists and is removed
583
415
  #
584
416
  def remove_value(v)
585
- return !@values.delete(v).nil?
417
+ index = @values.index(v)
418
+ if index
419
+ return !@values.delete_at(index).nil?
420
+ else
421
+ return false
422
+ end
586
423
  end
587
424
 
588
425
  # Removes all values.
@@ -591,8 +428,12 @@ module SDL4R
591
428
  @values = []
592
429
  end
593
430
 
594
- # Returns an Array of the values of this Tag
595
- def values
431
+ # Returns an Array of the values of this Tag or enumerates them.
432
+ #
433
+ # tag.values # => [123, "spices"]
434
+ # tag.values { |value| puts value }
435
+ #
436
+ def values # :yields: value
596
437
  if block_given?
597
438
  @values.each { |v| yield v }
598
439
  else
@@ -616,23 +457,36 @@ module SDL4R
616
457
  }
617
458
  end
618
459
 
460
+ # set_attribute(key, value)
461
+ # set_attribute(namespace, key, value)
619
462
  #
620
- # Set an attribute in the given namespace for this tag. The allowable
463
+ # Set an attribute in the given namespace for this tag. The allowable
621
464
  # attribute value types are the same as those allowed for
622
465
  # {@link #addValue(Object)}
623
466
  #
624
467
  # +namespace+:: The namespace for this attribute
625
468
  # +key+:: The attribute key
626
469
  # +value+:: The attribute value
470
+ #
627
471
  # @throws IllegalArgumentException if the key is not a legal SDL
628
- # identifier (see {@link SDL#validateIdentifier(String)}), or the
472
+ # identifier (see {@link SDL4R#validateIdentifier(String)}), or the
629
473
  # namespace is non-blank and is not a legal SDL identifier, or the
630
474
  # value is not a legal SDL type
631
475
  #
632
- def set_attribute(key, value, namespace = "")
476
+ def set_attribute(namespace, key, value = nil)
477
+ if value.nil?
478
+ value = key
479
+ key = namespace
480
+ namespace = ""
481
+ end
482
+
483
+ raise ArgumentError, "attribute namespace must be a String" unless namespace.is_a? String
484
+ raise ArgumentError, "attribute key must be a String" unless key.is_a? String
485
+ raise ArgumentError, "attribute key cannot be empty" if key.empty?
486
+
633
487
  SDL4R.validate_identifier(namespace) unless namespace.empty?
634
488
  SDL4R.validate_identifier(key)
635
-
489
+
636
490
  attributes = @attributesByNamespace[namespace]
637
491
 
638
492
  if attributes.nil?
@@ -643,31 +497,51 @@ module SDL4R
643
497
  attributes[key] = SDL4R.coerce_or_fail(value)
644
498
  end
645
499
 
500
+ # attribute(key)
501
+ # attribute(namespace, key)
502
+ #
646
503
  # Returns the attribute of the specified +namespace+ of specified +key+ or +nil+ if not found.
647
504
  #
648
- # +namespace+:: the default namespace ("") by default
649
505
  #
650
- def attribute(key, namespace = "")
506
+ def attribute(namespace, key = nil)
507
+ namespace, key = to_nns namespace, key
651
508
  attributes = @attributesByNamespace[namespace]
652
509
  return attributes.nil? ? nil : attributes[key]
653
510
  end
654
511
 
655
- # Indicates whether the specified attribute exists in this Tag.
512
+ # Indicates whether there is at least an attribute in this Tag.
513
+ # has_attribute?
656
514
  #
657
- # +key+:: key of the attribute
658
- # +namespace+:: namespace of the attribute ("", the default namespace, by default)
515
+ # Indicates whether there is the specified attribute exists in this Tag.
516
+ # has_attribute?(key)
517
+ # has_attribute?(namespace, key)
659
518
  #
660
- def has_attribute?(key, namespace = "")
661
- attributes = @attributesByNamespace[namespace]
662
- return attributes.nil? ? false : attributes.has_key?(key)
519
+ def has_attribute?(namespace = nil, key = nil)
520
+ namespace, key = to_nns namespace, key
521
+
522
+ if namespace or key
523
+ attributes = @attributesByNamespace[namespace]
524
+ return attributes.nil? ? false : attributes.has_key?(key)
525
+
526
+ else
527
+ attributes { return true }
528
+ return false
529
+ end
663
530
  end
664
531
 
665
- # Returns a copy of the Hash of the attributes of the specified +namespace+ (default is all).
532
+ # Returns a Hash of the attributes of the specified +namespace+ (default is all) or enumerates
533
+ # them.
666
534
  #
667
- # +namespace+:: namespace of the returned attributes. If nil, all attributes are returned with
668
- # qualified names (e.g. "meat:color"). If "" attributes of the default namespace are returned.
535
+ # tag.attributes # => { "length" => 123, "width" = 25.4, "orig:color" => "gray" }
536
+ # tag.attributes("orig") do |namespace, key, value|
537
+ # p "#{namespace}:#{key} = #{value}"
538
+ # end
669
539
  #
670
- def attributes(namespace = nil, &block)
540
+ # +namespace+::
541
+ # namespace of the returned attributes. If nil, all attributes are returned with
542
+ # qualified names (e.g. "meat:color"). If "", attributes of the default namespace are returned.
543
+ #
544
+ def attributes(namespace = nil, &block) # :yields: namespace, key, value
671
545
  if block_given?
672
546
  each_attribute(namespace, &block)
673
547
 
@@ -675,7 +549,7 @@ module SDL4R
675
549
  if namespace.nil?
676
550
  hash = {}
677
551
 
678
- each_attribute(nil) do | key, value, namespace |
552
+ each_attribute do | namespace, key, value |
679
553
  qualified_name = namespace.empty? ? key : namespace + ':' + key
680
554
  hash[qualified_name] = value
681
555
  end
@@ -689,6 +563,9 @@ module SDL4R
689
563
  end
690
564
  end
691
565
 
566
+ # remove_attribute(key)
567
+ # remove_attribute(namespace, key)
568
+ #
692
569
  # Removes the attribute, whose name and namespace are specified.
693
570
  #
694
571
  # +key+:: name of the removed atribute
@@ -696,7 +573,8 @@ module SDL4R
696
573
  #
697
574
  # Returns the value of the removed attribute or +nil+ if it didn't exist.
698
575
  #
699
- def remove_attribute(key, namespace = "")
576
+ def remove_attribute(namespace, key = nil)
577
+ namespace, key = to_nns namespace, key
700
578
  attributes = @attributesByNamespace[namespace]
701
579
  return attributes.nil? ? nil : attributes.delete(key)
702
580
  end
@@ -713,11 +591,9 @@ module SDL4R
713
591
  end
714
592
 
715
593
  # Enumerates the attributes for the specified +namespace+.
716
- # If no +namespace+ is specified, enumerates the attribute of the default
717
- # namespace. If +namespace+ is nil, enumerates the attributes of all
718
- # namespaces.
594
+ # Enumerates all the attributes by default.
719
595
  #
720
- def each_attribute(namespace = "", &block)
596
+ def each_attribute(namespace = nil, &block) # :yields: namespace, key, value
721
597
  if namespace.nil?
722
598
  @attributesByNamespace.each_key { |a_namespace| each_attribute(a_namespace, &block) }
723
599
 
@@ -725,37 +601,43 @@ module SDL4R
725
601
  attributes = @attributesByNamespace[namespace]
726
602
  unless attributes.nil?
727
603
  attributes.each_pair do |key, value|
728
- yield key, value, namespace
604
+ yield namespace, key, value
729
605
  end
730
606
  end
731
607
  end
732
608
  end
733
609
  private :each_attribute
734
610
 
735
- # Sets all the attributes of a +namespace+ for this Tag in one operation.
736
- # See # #add_value for allowable attribute value types.
611
+
612
+ # set_attributes(attribute_hash)
613
+ # set_attributes(namespace, attribute_hash)
614
+ #
615
+ # Sets the attributes specified by a Hash in the given +namespace+ in one operation. The
616
+ # previous attributes of the specified +namespace+ are removed.
617
+ # See #set_attribute for allowable attribute value types.
737
618
  #
738
619
  # +attributes+:: a Hash where keys are attribute keys
739
620
  # +namespace+:: "" (default namespace) by default
740
621
  #
741
622
  # Raises an +ArgumentError+ if any key in the map is not a legal SDL
742
- # identifier (see SDL#validate_identifier), or any value
623
+ # identifier (see SDL4R#validate_identifier), or any value
743
624
  # is not a legal SDL type.
744
625
  #
745
- def set_attributes(attribute_hash, namespace = "")
746
- return if attribute_hash.nil? or attribute_hash.empty?
747
-
748
- attributes = @attributesByNamespace[namespace]
749
- if attributes.nil?
750
- attributes = {}
751
- @attributesByNamespace[namespace] = attributes
752
- else
753
- attributes.clear()
626
+ def set_attributes(namespace, attribute_hash = nil)
627
+ if attribute_hash.nil?
628
+ attribute_hash = namespace
629
+ namespace = ""
754
630
  end
755
631
 
632
+ raise ArgumentError, "namespace can't be nil" if namespace.nil?
633
+ raise ArgumentError, "attribute_hash should be a Hash" unless attribute_hash.is_a? Hash
634
+
635
+ namespace_attributes = @attributesByNamespace[namespace]
636
+ namespace_attributes.clear if namespace_attributes
637
+
756
638
  attribute_hash.each_pair do |key, value|
757
639
  # Calling set_attribute() is required to ensure validations
758
- set_attribute(key, value)
640
+ set_attribute(namespace, key, value)
759
641
  end
760
642
  end
761
643
 
@@ -765,13 +647,13 @@ module SDL4R
765
647
  # See #set_attributes
766
648
  #
767
649
  def attributes=(attribute_hash)
768
- set_attributes(attribute_hash, "")
650
+ set_attributes(attribute_hash)
769
651
  end
770
652
 
771
653
  # Sets the name of this Tag.
772
654
  #
773
655
  # Raises +ArgumentError+ if the name is not a legal SDL
774
- # identifier (see SDL#validate_identifier)
656
+ # identifier (see SDL4R#validate_identifier)
775
657
 
776
658
  def name=(a_name)
777
659
  a_name = a_name.to_s
@@ -779,10 +661,10 @@ module SDL4R
779
661
  @name = a_name
780
662
  end
781
663
 
782
- # The namespace to set. null will be coerced to the empty string.
664
+ # The namespace to set. +nil+ will be coerced to the empty string.
783
665
  #
784
666
  # Raises +ArgumentError+ if the namespace is non-blank and is not
785
- # a legal SDL identifier (see {@link SDL#validate_identifier(String)})
667
+ # a legal SDL identifier (see {@link SDL4R#validate_identifier(String)})
786
668
 
787
669
  def namespace=(a_namespace)
788
670
  a_namespace = a_namespace.to_s
@@ -892,7 +774,7 @@ module SDL4R
892
774
 
893
775
  # output attributes
894
776
  unless @attributesByNamespace.empty?
895
- all_attributes_hash = attributes(nil)
777
+ all_attributes_hash = attributes
896
778
  all_attributes_array = all_attributes_hash.sort { |a, b|
897
779
  namespace1, name1 = a[0].split(':')
898
780
  namespace1, name1 = "", namespace1 if name1.nil?
@@ -952,18 +834,27 @@ module SDL4R
952
834
  # Returns a string containing an XML representation of this tag. Values
953
835
  # will be represented using _val0, _val1, etc.
954
836
  #
955
- # Returns An XML String describing this Tag
956
- # +linePrefix+:: A prefix to insert before every line.
957
- # Returns A String containing an XML representation of this tag. Values
958
- # will be represented using _val0, _val1, etc.
837
+ # +line_prefix+:: A prefix to insert before every line.
838
+ # +uri_by_namespace+:: a Hash giving the URIs for the namespaces. Nil to ignore this.
959
839
  #
960
- def to_xml_string(linePrefix = "")
961
- linePrefix = "" if linePrefix.nil?
840
+ def to_xml_string(line_prefix = "", uri_by_namespace = nil)
841
+ line_prefix ||= ""
962
842
 
963
843
  s = ""
964
- s << linePrefix << ?<
844
+ s << line_prefix << ?<
965
845
  s << "#{namespace}:" unless namespace.empty?
966
846
  s << name
847
+
848
+ # output namespace declarations
849
+ if uri_by_namespace
850
+ uri_by_namespace.each_pair do |namespace, uri|
851
+ if namespace
852
+ s << " xmlns:#{namespace}=\"#{uri}\""
853
+ else
854
+ s << " xmlns=\"#{uri}\""
855
+ end
856
+ end
857
+ end
967
858
 
968
859
  # output values
969
860
  unless @values.empty?
@@ -975,10 +866,9 @@ module SDL4R
975
866
  end
976
867
 
977
868
  # output attributes
978
- unless @attributes.empty?
979
- @attributes.each do |attribute_name, attribute_value|
869
+ if has_attribute?
870
+ attributes do |attribute_namespace, attribute_name, attribute_value|
980
871
  s << " "
981
- attribute_namespace = @attributeToNamespace[attribute_name]
982
872
  s << "#{attribute_namespace}:" unless attribute_namespace.empty?
983
873
  s << attribute_name << "=\"" << SDL4R.format(attribute_value, false) << ?"
984
874
  end
@@ -989,10 +879,10 @@ module SDL4R
989
879
  else
990
880
  s << ">\n"
991
881
  @children.each do |child|
992
- s << child.to_xml_string(linePrefix + " ") << ?\n
882
+ s << child.to_xml_string(line_prefix + " ") << ?\n
993
883
  end
994
884
 
995
- s << linePrefix << "</"
885
+ s << line_prefix << "</"
996
886
  s << "#{namespace}:" unless namespace.empty?
997
887
  s << name << ?>
998
888
  end