sdl4r 0.9.2 → 0.9.3

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