sdl4r 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sdl4r/sdl.rb CHANGED
@@ -22,6 +22,14 @@ require 'date'
22
22
  # Various SDL related utility methods
23
23
  #
24
24
  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
25
33
 
26
34
  MAX_INTEGER_32 = 2**31 - 1
27
35
  MIN_INTEGER_32 = -(2**31)
@@ -29,15 +37,6 @@ module SDL4R
29
37
  MAX_INTEGER_64 = 2**63 - 1
30
38
  MIN_INTEGER_64 = -(2**63)
31
39
 
32
-
33
- # Returns the milliseonds part of a DateTime (by translating the +sec_fraction+ part) as an
34
- # integer.
35
- def self.get_date_milliseconds(date)
36
- sec_fraction = date.sec_fraction() # in days
37
- # 86400000 is the number of milliseconds in a day
38
- return (sec_fraction * 86400000).round()
39
- end
40
-
41
40
  BASE64_WRAP_LINE_LENGTH = 72
42
41
 
43
42
  # Creates an SDL string representation for a given object and returns it.
@@ -130,72 +129,6 @@ module SDL4R
130
129
  return o.to_s
131
130
  end
132
131
  end
133
-
134
- # Wraps lines in "s" (by modifying it). This method only supports 1-byte character strings.
135
- #
136
- def self.wrap_lines_in_ascii(s, line_length, line_prefix = nil)
137
- # We could use such code if it supported any value for "line_prefix": unfortunately it is capped
138
- # at 64 in the regular expressions.
139
- #
140
- # return "#{line_prefix}" + encoded_o.scan(/.{1,#{line_prefix}}/).join("#{$/}#{line_prefix}")
141
-
142
- eol_size = "#{$/}".size
143
-
144
- i = 0
145
- while i < s.size
146
- if i > 0
147
- s.insert(i, $/)
148
- i += eol_size
149
- end
150
-
151
- if line_prefix
152
- s.insert(i, line_prefix)
153
- i += line_prefix.size
154
- end
155
-
156
- i += line_length
157
- end
158
- end
159
-
160
- ESCAPED_QUOTES = {
161
- "\"" => "\\\"",
162
- "'" => "\\'",
163
- "`" => "\\`",
164
- }
165
-
166
- ESCAPED_CHARS = {
167
- "\\" => "\\\\",
168
- "\t" => "\\t",
169
- "\r" => "\\r",
170
- "\n" => "\\n",
171
- }
172
- ESCAPED_CHARS.merge!(ESCAPED_QUOTES)
173
-
174
- # Returns an escaped version of +s+ (i.e. where characters which need to be
175
- # escaped, are escaped).
176
- #
177
- def self.escape(s, quote_char = nil)
178
- escaped_s = ""
179
-
180
- s.each_char { |c|
181
- escaped_char = ESCAPED_CHARS[c]
182
- if escaped_char
183
- if ESCAPED_QUOTES.has_key?(c)
184
- if quote_char && c == quote_char
185
- escaped_s << escaped_char
186
- else
187
- escaped_s << c
188
- end
189
- else
190
- escaped_s << escaped_char
191
- end
192
- else
193
- escaped_s << c
194
- end
195
- }
196
-
197
- return escaped_s
198
- end
199
132
 
200
133
  # This method was kept from the Java code but it is not sure if it should have a usefulness yet.
201
134
  #
@@ -226,7 +159,7 @@ module SDL4R
226
159
  "an underscore (_)."
227
160
  end
228
161
 
229
- unless identifier.length == 1 or identifier =~ /^[a-zA-Z_][a-zA-Z_0-9\-]*$/
162
+ unless identifier.length == 1 or identifier =~ /^[a-zA-Z_][a-zA-Z_0-9\-\.]*$/
230
163
  for i in 1..identifier.length
231
164
  unless identifier[i..i] =~ /^[a-zA-Z_0-9\-]$/
232
165
  raise ArgumentError,
@@ -239,4 +172,121 @@ module SDL4R
239
172
  end
240
173
  end
241
174
  end
175
+
176
+ # Parses and returns the value corresponding with the specified SDL literal.
177
+ #
178
+ def self.to_value(s)
179
+ raise ArgumentError, "'s' cannot be null" if s.nil?
180
+ return read(s).child.value
181
+ end
182
+
183
+ # Parse the string of values and return a list. The string is handled
184
+ # as if it is the values portion of an SDL tag.
185
+ #
186
+ # Example
187
+ #
188
+ # array = SDL4R.to_values("1 true 12:24:01")
189
+ #
190
+ # Will return an int, a boolean, and a time span.
191
+ #
192
+ def self.to_value_array(s)
193
+ raise ArgumentError, "'s' cannot be null" if s.nil?
194
+ return read(s).child.values
195
+ end
196
+
197
+ # Parse a string representing the attributes portion of an SDL tag
198
+ # and return the results as a map.
199
+ #
200
+ # Example
201
+ #
202
+ # hash = SDL4R.to_attribute_hash("value=1 debugging=on time=12:24:01");
203
+ #
204
+ # Will return a map containing value=1, debugging=true, and time=12:24:01
205
+ #
206
+ def self.to_attribute_map(s)
207
+ raise ArgumentError, "'s' cannot be null" if s.nil?
208
+ return read("atts " + s).child.attributes
209
+ end
210
+
211
+ # The following is a not so readable way to implement module private methods in Ruby: we add
212
+ # private methods to the singleton class of +self+ i.e. the SDL4R module.
213
+ class << self
214
+ private
215
+
216
+ # Wraps lines in "s" (by modifying it). This method only supports 1-byte character strings.
217
+ #
218
+ def wrap_lines_in_ascii(s, line_length, line_prefix = nil)
219
+ # We could use such code if it supported any value for "line_prefix": unfortunately it is capped
220
+ # at 64 in the regular expressions.
221
+ #
222
+ # return "#{line_prefix}" + encoded_o.scan(/.{1,#{line_prefix}}/).join("#{$/}#{line_prefix}")
223
+
224
+ eol_size = "#{$/}".size
225
+
226
+ i = 0
227
+ while i < s.size
228
+ if i > 0
229
+ s.insert(i, $/)
230
+ i += eol_size
231
+ end
232
+
233
+ if line_prefix
234
+ s.insert(i, line_prefix)
235
+ i += line_prefix.size
236
+ end
237
+
238
+ i += line_length
239
+ end
240
+ end
241
+
242
+ ESCAPED_QUOTES = {
243
+ "\"" => "\\\"",
244
+ "'" => "\\'",
245
+ "`" => "\\`",
246
+ }
247
+
248
+ ESCAPED_CHARS = {
249
+ "\\" => "\\\\",
250
+ "\t" => "\\t",
251
+ "\r" => "\\r",
252
+ "\n" => "\\n",
253
+ }
254
+ ESCAPED_CHARS.merge!(ESCAPED_QUOTES)
255
+
256
+ # Returns an escaped version of +s+ (i.e. where characters which need to be
257
+ # escaped, are escaped).
258
+ #
259
+ def escape(s, quote_char = nil)
260
+ escaped_s = ""
261
+
262
+ s.each_char { |c|
263
+ escaped_char = ESCAPED_CHARS[c]
264
+ if escaped_char
265
+ if ESCAPED_QUOTES.has_key?(c)
266
+ if quote_char && c == quote_char
267
+ escaped_s << escaped_char
268
+ else
269
+ escaped_s << c
270
+ end
271
+ else
272
+ escaped_s << escaped_char
273
+ end
274
+ else
275
+ escaped_s << c
276
+ end
277
+ }
278
+
279
+ return escaped_s
280
+ end
281
+
282
+ # Returns the milliseonds part of a DateTime (by translating the +sec_fraction+ part) as an
283
+ # integer.
284
+ def get_date_milliseconds(date)
285
+ sec_fraction = date.sec_fraction() # in days
286
+ # 86400000 is the number of milliseconds in a day
287
+ return (sec_fraction * 86400000).round()
288
+ end
289
+
290
+ end
291
+
242
292
  end
data/lib/sdl4r/tag.rb CHANGED
@@ -16,6 +16,8 @@
16
16
 
17
17
  module SDL4R
18
18
 
19
+ require 'pathname'
20
+ require 'open-uri'
19
21
  require 'stringio'
20
22
 
21
23
  require File.dirname(__FILE__) + '/sdl'
@@ -314,7 +316,7 @@ module SDL4R
314
316
  # (see SDL#validate_identifier) or the namespace is non-blank
315
317
  # and is not a legal SDL identifier.
316
318
  #
317
- def initialize(name, namespace = "")
319
+ def initialize(name, namespace = "", &block)
318
320
  namespace = namespace.to_s
319
321
  SDL4R.validate_identifier(namespace) unless namespace.empty?
320
322
  @namespace = namespace
@@ -330,6 +332,25 @@ module SDL4R
330
332
  # a Hash of Hash : {namespace => {name => value}}
331
333
  # The default namespace is represented by an empty string.
332
334
  @attributesByNamespace = {}
335
+
336
+ instance_eval(&block) if block_given?
337
+ end
338
+
339
+ # Creates a new child tag.
340
+ # Can take a block so that you can write something like:
341
+ #
342
+ # car = Tag.new("car") do
343
+ # new_child("wheels") do
344
+ # self << 4
345
+ # end
346
+ # end
347
+ #
348
+ # The context of execution of the given block is the child instance
349
+ #
350
+ # Returns the created child Tag.
351
+ #
352
+ def new_child(*args, &block)
353
+ return add_child Tag.new(*args, &block)
333
354
  end
334
355
 
335
356
  # Add a child to this Tag.
@@ -453,7 +474,7 @@ module SDL4R
453
474
  # +name+:: the name of the child Tag. If +nil+, the first child is returned (+nil+ if there are
454
475
  # no children at all).
455
476
  #
456
- # Returns The first child tag having the given name or +nil+ if no such child exists
477
+ # Returns the first child tag having the given name or +nil+ if no such child exists
457
478
  #
458
479
  def child(name = nil, recursive = false)
459
480
  unless name
@@ -463,6 +484,20 @@ module SDL4R
463
484
  end
464
485
  end
465
486
 
487
+ # Indicates whether the child Tag of given name exists.
488
+ #
489
+ # +name+:: name of the searched child Tag
490
+ #
491
+ def has_child?(name)
492
+ !child(name).nil?
493
+ end
494
+
495
+ # Indicates whether there are children Tag.
496
+ #
497
+ def has_children?
498
+ !@children.empty?
499
+ end
500
+
466
501
  # Enumerates the children +Tag+s of this Tag and calls the given block
467
502
  # providing it the child as parameter.
468
503
  #
@@ -482,6 +517,44 @@ module SDL4R
482
517
  return nil
483
518
  end
484
519
  private :each_child
520
+
521
+ # Returns a new Hash where the children's names as keys and their values as the key's value.
522
+ # Example:
523
+ #
524
+ # child1 "toto"
525
+ # child2 2
526
+ #
527
+ # would give
528
+ #
529
+ # { "child1" => "toto", "child2" => 2 }
530
+ #
531
+ def to_child_hash
532
+ hash = {}
533
+ children { |child| hash[child.name] = child.value }
534
+ return hash
535
+ end
536
+
537
+ # Returns a new Hash where the children's names as keys and their values as the key's value.
538
+ # Values are converted to Strings. +nil+ values become empty Strings.
539
+ # Example:
540
+ #
541
+ # child1 "toto"
542
+ # child2 2
543
+ # child3 null
544
+ #
545
+ # would give
546
+ #
547
+ # { "child1" => "toto", "child2" => "2", "child3" => "" }
548
+ #
549
+ def to_child_string_hash
550
+ hash = {}
551
+ children do |child|
552
+ # FIXME: it is quite hard to be sure whether we should mimic the Java version
553
+ # as there might be a lot of values that don't translate nicely to Strings.
554
+ hash[child.name] = child.value.to_s
555
+ end
556
+ return hash
557
+ end
485
558
 
486
559
  # Adds a value to this Tag. The allowable types are String, Number,
487
560
  # Boolean, Character, byte[], Byte[] (coerced to byte[]), Calendar,
@@ -498,7 +571,7 @@ module SDL4R
498
571
 
499
572
  # Returns true if +v+ is a value of this Tag's.
500
573
  #
501
- def has_value(v)
574
+ def has_value?(v)
502
575
  @values.include?(v)
503
576
  end
504
577
 
@@ -584,7 +657,7 @@ module SDL4R
584
657
  # +key+:: key of the attribute
585
658
  # +namespace+:: namespace of the attribute ("", the default namespace, by default)
586
659
  #
587
- def has_attribute(key, namespace = "")
660
+ def has_attribute?(key, namespace = "")
588
661
  attributes = @attributesByNamespace[namespace]
589
662
  return attributes.nil? ? false : attributes.has_key?(key)
590
663
  end
@@ -716,64 +789,45 @@ module SDL4R
716
789
  SDL4R.validate_identifier(a_namespace) unless a_namespace.empty?
717
790
  @namespace = a_namespace
718
791
  end
719
-
720
- #
721
- # Add all the tags specified in the file at the given URL to this Tag.
722
- #
723
- # +url+:: A UTF8 encoded .sdl file
724
- # @throws IOException If there is an IO problem reading the source
725
- # @throws ParseException If the SDL input is malformed
726
- # Returns This tag after adding all the children read from the reader
727
- #
728
- # public Tag read(URL url) throws IOException, SDLParseException {
729
- # return read(new InputStreamReader(url.openStream(), "UTF8"));
730
- # }
731
-
732
- #
733
- # Add all the tags specified in the given file to this Tag.
734
- #
735
- # +file+:: A UTF8 encoded .sdl file
736
- # @throws IOException If there is an IO problem reading the source
737
- # @throws ParseException If the SDL input is malformed
738
- # Returns This tag after adding all the children read from the reader
739
- #
740
- # public Tag read(File file) throws IOException, SDLParseException {
741
- # return read(new InputStreamReader(new FileInputStream(file), "UTF8"));
742
- # }
743
-
744
- #
745
- # Add all the tags specified in the given String to this Tag.
746
- #
747
- # +text+:: An SDL string
748
- # @throws ParseException If the SDL input is malformed
749
- # Returns This tag after adding all the children read from the reader
750
- #
751
- # public Tag read(String text) throws SDLParseException {
752
- # try {
753
- # return read(new StringReader(text));
754
- # } catch(IOException ioe) {
755
- # // Cannot happen
756
- # throw new InternalError("IOExceptio reading a String");
757
- # }
758
- # }
759
-
760
- # Adds all the tags specified in the given +IO+ or String to this Tag.
792
+
793
+ # Adds all the tags specified in the given IO, String, Pathname or URI to this Tag.
761
794
  #
762
- # Returns this Tag after adding all the children read from _input_.
795
+ # Returns this Tag after adding all the children read from +input+.
763
796
  #
764
797
  def read(input)
765
- if input.is_a?(String)
766
- io = StringIO.new(input)
798
+ if input.is_a? String
799
+ read_from_io(true) { StringIO.new(input) }
800
+
801
+ elsif input.is_a? Pathname
802
+ read_from_io(true) { input.open("r") }
803
+
804
+ elsif input.is_a? URI
805
+ read_from_io(true) { input.open }
806
+
767
807
  else
768
- io = input
808
+ read_from_io(false) { input }
769
809
  end
770
810
 
771
- Parser.new(io).parse.each do |tag|
772
- add_child(tag)
773
- end
774
-
775
811
  return self
776
812
  end
813
+
814
+ # Reads and parses the +io+ returned by the specified block and closes this +io+ if +close_io+
815
+ # is true.
816
+ def read_from_io(close_io)
817
+ io = yield
818
+
819
+ begin
820
+ Parser.new(io).parse.each do |tag|
821
+ add_child(tag)
822
+ end
823
+
824
+ ensure
825
+ if close_io
826
+ io.close rescue IOError
827
+ end
828
+ end
829
+ end
830
+ private_methods :read_io
777
831
 
778
832
  # Write this tag out to the given IO or string (optionally clipping the root.)
779
833
  #