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.
- data/README +79 -6
- data/Rakefile +15 -2
- data/TODO.txt +37 -6
- data/doc/created.rid +1 -1
- data/doc/fr_class_index.html +0 -4
- data/doc/fr_method_index.html +78 -111
- data/lib/sdl4r/parser.rb +32 -20
- data/lib/sdl4r/parser/reader.rb +3 -1
- data/lib/sdl4r/parser/time_span_with_zone.rb +3 -1
- data/lib/sdl4r/parser/token.rb +3 -1
- data/lib/sdl4r/parser/tokenizer.rb +3 -1
- data/lib/sdl4r/sdl.rb +41 -18
- data/lib/sdl4r/sdl_binary.rb +4 -4
- data/lib/sdl4r/sdl_parse_error.rb +4 -2
- data/lib/sdl4r/sdl_time_span.rb +18 -50
- data/lib/sdl4r/tag.rb +246 -356
- data/test/sdl4r/parser_test.rb +2 -0
- data/test/sdl4r/{test.rb → sdl4r_test.rb} +9 -7
- data/test/sdl4r/tag_test.rb +487 -0
- metadata +48 -49
data/lib/sdl4r/parser/reader.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
|
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
|
|
data/lib/sdl4r/parser/token.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
|
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
|
-
#
|
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
|
-
#
|
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 (_),
|
136
|
+
# digits, underscores (_), dashes(-) and periods (.).
|
142
137
|
#
|
143
|
-
#
|
144
|
-
#
|
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.
|
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
|
-
#
|
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?
|
data/lib/sdl4r/sdl_binary.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/sdl4r/sdl_time_span.rb
CHANGED
@@ -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.
|
162
|
+
# Positive numbers add days. Negative numbers remove days.
|
176
163
|
#
|
177
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
225
|
+
# Returns an SDL representation of this time span using the format:
|
253
226
|
#
|
254
|
-
#
|
255
|
-
# (days:)hours:minutes:seconds(.milliseconds)
|
256
|
-
# </pre>
|
227
|
+
# (days:)hours:minutes:seconds(.milliseconds)
|
257
228
|
#
|
258
|
-
#
|
229
|
+
# (parenthesis indicate optional components)
|
259
230
|
#
|
260
|
-
#
|
261
|
-
# are set to 0. Days must be suffixed with "d" for clarity
|
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
|
-
#
|
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
|
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
|
-
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
#
|
151
|
-
#
|
152
|
-
#
|
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: \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
|
-
#
|
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
|
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
|
-
#
|
313
|
-
#
|
314
|
-
#
|
315
|
-
#
|
316
|
-
#
|
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(
|
320
|
-
namespace = namespace
|
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
|
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
|
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
|
-
#
|
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+::
|
432
|
-
# Nil by default.
|
242
|
+
# +namespace+:: use nil for all namespaces and "" for the default one. Nil by default.
|
433
243
|
#
|
434
|
-
|
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,
|
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,
|
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
|
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(
|
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,
|
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,
|
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.
|
560
|
-
#
|
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
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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
|
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
|
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(
|
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
|
512
|
+
# Indicates whether there is at least an attribute in this Tag.
|
513
|
+
# has_attribute?
|
656
514
|
#
|
657
|
-
#
|
658
|
-
#
|
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?(
|
661
|
-
|
662
|
-
|
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
|
532
|
+
# Returns a Hash of the attributes of the specified +namespace+ (default is all) or enumerates
|
533
|
+
# them.
|
666
534
|
#
|
667
|
-
#
|
668
|
-
#
|
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
|
-
|
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
|
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(
|
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
|
-
#
|
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 =
|
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
|
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
|
-
|
736
|
-
#
|
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
|
623
|
+
# identifier (see SDL4R#validate_identifier), or any value
|
743
624
|
# is not a legal SDL type.
|
744
625
|
#
|
745
|
-
def set_attributes(
|
746
|
-
|
747
|
-
|
748
|
-
|
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
|
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.
|
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
|
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
|
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
|
-
#
|
956
|
-
# +
|
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(
|
961
|
-
|
840
|
+
def to_xml_string(line_prefix = "", uri_by_namespace = nil)
|
841
|
+
line_prefix ||= ""
|
962
842
|
|
963
843
|
s = ""
|
964
|
-
s <<
|
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
|
-
|
979
|
-
|
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(
|
882
|
+
s << child.to_xml_string(line_prefix + " ") << ?\n
|
993
883
|
end
|
994
884
|
|
995
|
-
s <<
|
885
|
+
s << line_prefix << "</"
|
996
886
|
s << "#{namespace}:" unless namespace.empty?
|
997
887
|
s << name << ?>
|
998
888
|
end
|