sdl4r 0.9.9 → 0.9.11
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +70 -1
- data/LICENSE +499 -497
- data/Rakefile +38 -28
- data/TODO +194 -45
- data/doc/classes/SDL4R/AbbreviationTimezoneProxy.html +151 -0
- data/doc/classes/SDL4R/ConstantTimezone.html +129 -0
- data/doc/classes/SDL4R/Element.html +148 -0
- data/doc/classes/SDL4R/Reader.html +683 -0
- data/doc/classes/SDL4R/RelativeTimezone.html +187 -0
- data/doc/classes/SDL4R/SdlBinary.html +188 -0
- data/doc/classes/SDL4R/SdlParseError.html +110 -0
- data/doc/classes/SDL4R/SdlTimeSpan.html +651 -0
- data/doc/classes/SDL4R/Serializer.html +557 -0
- data/doc/classes/SDL4R/Serializer/Ref.html +138 -0
- data/doc/classes/SDL4R/TZAbbreviationDB/Record.html +117 -0
- data/doc/classes/SDL4R/Tag.html +1274 -0
- data/doc/classes/SDL4R/Token.html +131 -0
- data/doc/created.rid +1 -0
- data/doc/files/CHANGELOG.html +290 -0
- data/doc/files/LICENSE.html +53 -0
- data/doc/files/README.html +405 -0
- data/doc/files/lib/sdl4r/abbreviation_timezone_proxy_rb.html +63 -0
- data/doc/files/lib/sdl4r/constant_timezone_rb.html +54 -0
- data/doc/files/lib/sdl4r/element_rb.html +54 -0
- data/doc/files/lib/sdl4r/reader_rb.html +68 -0
- data/doc/files/lib/sdl4r/relative_timezone_rb.html +62 -0
- data/doc/files/lib/sdl4r/sdl4r_rb.html +66 -0
- data/doc/files/lib/sdl4r/sdl4r_tzinfo_rb.html +64 -0
- data/doc/files/lib/sdl4r/sdl4r_version_rb.html +54 -0
- data/doc/files/lib/sdl4r/sdl_binary_rb.html +54 -0
- data/doc/files/lib/sdl4r/sdl_parse_error_rb.html +54 -0
- data/doc/files/lib/sdl4r/sdl_time_span_rb.html +54 -0
- data/doc/files/lib/sdl4r/serializer_rb.html +62 -0
- data/doc/files/lib/sdl4r/tag_rb.html +66 -0
- data/doc/files/lib/sdl4r/token_rb.html +54 -0
- data/doc/files/lib/sdl4r/tokenizer_rb.html +64 -0
- data/doc/files/lib/sdl4r/tz_abbreviation_db_rb.html +67 -0
- data/doc/files/lib/sdl4r_rb.html +54 -0
- data/doc/files/lib/sdl4r_tzinfo_rb.html +54 -0
- data/doc/fr_class_index.html +23 -0
- data/doc/fr_file_index.html +40 -0
- data/doc/fr_method_index.html +4711 -0
- data/doc/index.html +15 -0
- data/doc/rdoc-style.css +328 -0
- data/lib/sdl4r.rb +3 -1
- data/lib/sdl4r/abbreviation_timezone_proxy.rb +38 -0
- data/lib/sdl4r/constant_timezone.rb +58 -0
- data/{test/sdl4r/sdl_test.rb → lib/sdl4r/element.rb} +19 -14
- data/lib/sdl4r/reader.rb +772 -0
- data/lib/sdl4r/relative_timezone.rb +156 -0
- data/lib/sdl4r/sdl4r.rb +187 -45
- data/lib/sdl4r/sdl4r_tzinfo.rb +75 -0
- data/lib/sdl4r/sdl4r_version.rb +24 -0
- data/lib/sdl4r/sdl_parse_error.rb +1 -1
- data/lib/sdl4r/sdl_time_span.rb +5 -1
- data/lib/sdl4r/serializer.rb +473 -60
- data/lib/sdl4r/tag.rb +126 -51
- data/lib/sdl4r/token.rb +49 -0
- data/lib/sdl4r/tokenizer.rb +431 -0
- data/lib/sdl4r/tz_abbreviation_db.rb +266 -0
- data/read_jprof.html +16934 -0
- data/read_jprof_pull.html +14451 -0
- data/read_prof.html +4983 -0
- data/read_prof_pull.html +4896 -0
- data/test/sdl4r/parser_test.rb +577 -503
- data/test/sdl4r/read_jprof.rb +58 -0
- data/test/sdl4r/read_prof.rb +70 -0
- data/test/sdl4r/reader_test.rb +173 -0
- data/test/sdl4r/relative_timezone_test.rb +102 -0
- data/test/sdl4r/sdl4r_test.rb +611 -528
- data/test/sdl4r/sdl4r_tzinfo_test.rb +108 -0
- data/test/sdl4r/sdl_test_case.rb +60 -0
- data/test/sdl4r/serializer_test.rb +448 -11
- data/test/sdl4r/tag_test.rb +84 -5
- data/test/sdl4r/tokenizer_test.rb +128 -0
- metadata +69 -11
- data/lib/sdl4r/parser.rb +0 -648
- data/lib/sdl4r/parser/reader.rb +0 -184
- data/lib/sdl4r/parser/time_span_with_zone.rb +0 -57
- data/lib/sdl4r/parser/token.rb +0 -138
- data/lib/sdl4r/parser/tokenizer.rb +0 -507
data/test/sdl4r/tag_test.rb
CHANGED
@@ -18,15 +18,23 @@
|
|
18
18
|
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19
19
|
#++
|
20
20
|
|
21
|
+
# Work-around a bug in NetBeans (http://netbeans.org/bugzilla/show_bug.cgi?id=188653)
|
22
|
+
if ENV["NB_EXEC_EXTEXECUTION_PROCESS_UUID"]
|
23
|
+
$:[0] = File.join(File.dirname(__FILE__),'../../lib')
|
24
|
+
$:.unshift(File.join(File.dirname(__FILE__),'../../test'))
|
25
|
+
end
|
26
|
+
|
21
27
|
module SDL4R
|
22
28
|
|
23
29
|
require 'test/unit'
|
24
30
|
require "rexml/document"
|
25
31
|
|
26
32
|
require 'sdl4r/tag'
|
27
|
-
|
33
|
+
|
34
|
+
require "sdl4r/sdl_test_case"
|
28
35
|
|
29
36
|
class TagTest < Test::Unit::TestCase
|
37
|
+
include SdlTestCase
|
30
38
|
|
31
39
|
public
|
32
40
|
|
@@ -357,6 +365,9 @@ module SDL4R
|
|
357
365
|
|
358
366
|
tag.set_attributes("", {}) # removes all attributes in the default namespace
|
359
367
|
assert_equal({"ns1:a2" => 12, "ns1:a3" => 13}, tag.attributes)
|
368
|
+
|
369
|
+
tag.set_attributes("ns1", {})
|
370
|
+
assert_equal({}, tag.attributes)
|
360
371
|
end
|
361
372
|
|
362
373
|
def test_to_child_hash
|
@@ -452,7 +463,7 @@ module SDL4R
|
|
452
463
|
assert !(tag1 == tag2)
|
453
464
|
assert !(tag1.equal?(tag2))
|
454
465
|
assert_not_equal tag1.hash, tag2.hash
|
455
|
-
|
466
|
+
end
|
456
467
|
|
457
468
|
def test_children_values
|
458
469
|
root = Tag.new "root"
|
@@ -504,7 +515,7 @@ EOF
|
|
504
515
|
assert_equal "ns1", xml_doc[0].namespace
|
505
516
|
|
506
517
|
tag = Tag.new "tag1" do
|
507
|
-
self << 123
|
518
|
+
self << "123"
|
508
519
|
end
|
509
520
|
xml_doc = REXML::Document.new(tag.to_xml_string(options))
|
510
521
|
assert_equal "tag1", xml_doc[0].name
|
@@ -618,9 +629,9 @@ EOF
|
|
618
629
|
root.write(output, true)
|
619
630
|
assert_equal(
|
620
631
|
"root 1876/07/01 1592/09/13 09:05:00 1592/09/13 09:05:07" +
|
621
|
-
" -98/06/15 13:47:12.340 3112/01/10 00:00:00+01:00",
|
632
|
+
" -98/06/15 13:47:12.340 3112/01/10 00:00:00-GMT+01:00",
|
622
633
|
output)
|
623
|
-
|
634
|
+
end
|
624
635
|
|
625
636
|
# Check that having a timespan after a date in a tag values doesn't fail when loaded.
|
626
637
|
#
|
@@ -642,5 +653,73 @@ EOF
|
|
642
653
|
assert_equal "square", tag1.attribute("type")
|
643
654
|
end
|
644
655
|
|
656
|
+
def test_symbol_as_identifier
|
657
|
+
# Tag identifiers
|
658
|
+
tag = Tag.new(:my_tag)
|
659
|
+
assert_equal "my_tag", tag.name
|
660
|
+
|
661
|
+
tag = Tag.new(:ns, :my_tag)
|
662
|
+
assert_equal "ns", tag.namespace
|
663
|
+
assert_equal "my_tag", tag.name
|
664
|
+
|
665
|
+
tag.namespace = :ns2
|
666
|
+
tag.name = :your_tag
|
667
|
+
assert_equal "ns2", tag.namespace
|
668
|
+
assert_equal "your_tag", tag.name
|
669
|
+
|
670
|
+
child = tag.new_child(:ns, :my_child)
|
671
|
+
assert_equal "ns", child.namespace
|
672
|
+
assert_equal "my_child", child.name
|
673
|
+
|
674
|
+
assert_equal child, tag.child(:ns, :my_child)
|
675
|
+
assert_equal [child], tag.children(false, :ns, :my_child)
|
676
|
+
assert tag.has_child?(:ns, :my_child)
|
677
|
+
assert !tag.has_child?(:ns2, :my_child)
|
678
|
+
|
679
|
+
child << 123
|
680
|
+
assert_equal [123], tag.children_values(:my_child)
|
681
|
+
|
682
|
+
# Attribute identifiers
|
683
|
+
tag.set_attribute(:ns1, :attr1, 2)
|
684
|
+
tag.set_attribute(:attr1, 1)
|
685
|
+
tag.set_attribute(:ns2, :attr1, 3)
|
686
|
+
assert_equal 1, tag.attribute(:attr1)
|
687
|
+
assert_equal 2, tag.attribute(:ns1, :attr1)
|
688
|
+
assert_equal 3, tag.attribute(:ns2, :attr1)
|
689
|
+
assert_equal({"attr1" => 1, "ns1:attr1" => 2, "ns2:attr1" => 3}, tag.attributes)
|
690
|
+
assert_equal({"attr1" => 2}, tag.attributes(:ns1))
|
691
|
+
|
692
|
+
tag.set_attributes(:attr2 => 20, :attr4 => 40)
|
693
|
+
tag.set_attributes(:ns1, :attr3 => 30)
|
694
|
+
assert_equal(
|
695
|
+
{"attr2" => 20, "ns1:attr3" => 30, "attr4" => 40, "ns2:attr1" => 3}, tag.attributes)
|
696
|
+
assert_equal({"attr3" => 30}, tag.attributes(:ns1))
|
697
|
+
assert tag.has_attribute?(:attr2)
|
698
|
+
assert tag.has_attribute?(:ns1, :attr3)
|
699
|
+
assert !tag.has_attribute?(:attr3)
|
700
|
+
|
701
|
+
tag.remove_attribute(:attr2)
|
702
|
+
assert_equal nil, tag.attribute(:attr2)
|
703
|
+
assert tag.has_attribute?(:ns1, :attr3)
|
704
|
+
tag.remove_attribute(:ns1, :attr3)
|
705
|
+
assert !tag.has_attribute?(:ns1, :attr3)
|
706
|
+
|
707
|
+
tag.clear_attributes()
|
708
|
+
|
709
|
+
tag.set_attributes(:ns2, :attr2 => 50, :attr3 => 60, :attr4 => 70)
|
710
|
+
assert_equal({"ns2:attr2" => 50, "ns2:attr3" => 60, "ns2:attr4" => 70}, tag.attributes)
|
711
|
+
|
712
|
+
tag.clear_attributes(:ns1)
|
713
|
+
assert_equal({"ns2:attr2" => 50, "ns2:attr3" => 60, "ns2:attr4" => 70}, tag.attributes)
|
714
|
+
tag.clear_attributes(:ns2)
|
715
|
+
assert !tag.has_attribute?
|
716
|
+
assert !tag.has_attributes?
|
717
|
+
|
718
|
+
tag.clear_attributes
|
719
|
+
|
720
|
+
tag << {:attr10 => 100, :"ns20:attr20" => 200}
|
721
|
+
assert_equal({"attr10" => 100, "ns20:attr20" => 200}, tag.attributes)
|
722
|
+
end
|
723
|
+
|
645
724
|
end
|
646
725
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
#--
|
5
|
+
# Simple Declarative Language (SDL) for Ruby
|
6
|
+
# Copyright 2005 Ikayzo, inc.
|
7
|
+
#
|
8
|
+
# This program is free software. You can distribute or modify it under the
|
9
|
+
# terms of the GNU Lesser General Public License version 2.1 as published by
|
10
|
+
# the Free Software Foundation.
|
11
|
+
#
|
12
|
+
# This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
|
13
|
+
# INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
14
|
+
# See the GNU Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
17
|
+
# along with this program; if not, contact the Free Software Foundation, Inc.,
|
18
|
+
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19
|
+
#++
|
20
|
+
|
21
|
+
# Work-around a bug in NetBeans (http://netbeans.org/bugzilla/show_bug.cgi?id=188653)
|
22
|
+
if ENV["NB_EXEC_EXTEXECUTION_PROCESS_UUID"]
|
23
|
+
$:[0] = File.join(File.dirname(__FILE__),'../../../lib')
|
24
|
+
$:.unshift(File.join(File.dirname(__FILE__),'../../../test'))
|
25
|
+
end
|
26
|
+
|
27
|
+
if RUBY_VERSION < '1.9.0'
|
28
|
+
$KCODE = 'u'
|
29
|
+
require 'jcode'
|
30
|
+
end
|
31
|
+
|
32
|
+
module SDL4R
|
33
|
+
module Parser
|
34
|
+
|
35
|
+
require 'stringio'
|
36
|
+
require 'test/unit'
|
37
|
+
|
38
|
+
require 'sdl4r/tag'
|
39
|
+
require 'sdl4r/tokenizer'
|
40
|
+
|
41
|
+
require 'sdl4r/sdl_test_case'
|
42
|
+
|
43
|
+
|
44
|
+
class TokenizerTest < Test::Unit::TestCase
|
45
|
+
include SdlTestCase
|
46
|
+
|
47
|
+
# Fully tokenizes 's' and returns an array of the found token types plus an array of the found
|
48
|
+
# tokens
|
49
|
+
#
|
50
|
+
def tokenize(s)
|
51
|
+
tokenizer = Tokenizer.new(StringIO.new(s))
|
52
|
+
token_types = []
|
53
|
+
tokens = []
|
54
|
+
|
55
|
+
while tokenizer.read
|
56
|
+
token_types << tokenizer.token_type
|
57
|
+
tokens << tokenizer.token
|
58
|
+
end
|
59
|
+
|
60
|
+
assert_equal :EOF, token_types.last
|
61
|
+
assert_equal nil, tokens.last
|
62
|
+
|
63
|
+
token_types.pop
|
64
|
+
tokens.pop
|
65
|
+
|
66
|
+
return token_types, tokens
|
67
|
+
end
|
68
|
+
private :tokenize
|
69
|
+
|
70
|
+
def test_backquote_strings
|
71
|
+
types, tokens = tokenize("``")
|
72
|
+
assert_equal [:INLINE_BACKQUOTE_STRING], types
|
73
|
+
assert_equal [""], tokens
|
74
|
+
|
75
|
+
types, tokens = tokenize("` `")
|
76
|
+
assert_equal [:INLINE_BACKQUOTE_STRING], types
|
77
|
+
assert_equal [" "], tokens
|
78
|
+
|
79
|
+
types, tokens = tokenize("`abc\\\ndef`")
|
80
|
+
assert_equal(
|
81
|
+
[:MULTILINE_BACKQUOTE_STRING_START, :MULTILINE_BACKQUOTE_STRING_END], types)
|
82
|
+
assert_equal ["abc\\\n", "def"], tokens
|
83
|
+
|
84
|
+
types, tokens = tokenize("`abc\\\n def`")
|
85
|
+
assert_equal(
|
86
|
+
[:MULTILINE_BACKQUOTE_STRING_START, :MULTILINE_BACKQUOTE_STRING_END], types)
|
87
|
+
assert_equal ["abc\\\n", " def"], tokens
|
88
|
+
|
89
|
+
types, tokens = tokenize("`\ndef`")
|
90
|
+
assert_equal(
|
91
|
+
[:MULTILINE_BACKQUOTE_STRING_START, :MULTILINE_BACKQUOTE_STRING_END], types)
|
92
|
+
assert_equal ["\n", "def"], tokens
|
93
|
+
|
94
|
+
types, tokens = tokenize("`abc\n def \n ghi`")
|
95
|
+
assert_equal [
|
96
|
+
:MULTILINE_BACKQUOTE_STRING_START,
|
97
|
+
:MULTILINE_BACKQUOTE_STRING_PART,
|
98
|
+
:MULTILINE_BACKQUOTE_STRING_END],
|
99
|
+
types
|
100
|
+
assert_equal ["abc\n", " def \n", " ghi"], tokens
|
101
|
+
|
102
|
+
|
103
|
+
types, tokens = tokenize("`abc\n def \n ghi\n`")
|
104
|
+
assert_equal [
|
105
|
+
:MULTILINE_BACKQUOTE_STRING_START,
|
106
|
+
:MULTILINE_BACKQUOTE_STRING_PART,
|
107
|
+
:MULTILINE_BACKQUOTE_STRING_PART,
|
108
|
+
:MULTILINE_BACKQUOTE_STRING_END],
|
109
|
+
types
|
110
|
+
assert_equal ["abc\n", " def \n", " ghi\n", ""], tokens
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_double_quote_string
|
114
|
+
types, tokens = tokenize('""')
|
115
|
+
assert_equal [:INLINE_DOUBLE_QUOTE_STRING], types
|
116
|
+
assert_equal [""], tokens
|
117
|
+
|
118
|
+
types, tokens = tokenize('"tutu"')
|
119
|
+
assert_equal [:INLINE_DOUBLE_QUOTE_STRING], types
|
120
|
+
assert_equal ["tutu"], tokens
|
121
|
+
|
122
|
+
types, tokens = tokenize('"\\t"')
|
123
|
+
assert_equal [:INLINE_DOUBLE_QUOTE_STRING], types
|
124
|
+
assert_equal ["\\t"], tokens
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 9
|
8
|
-
-
|
9
|
-
version: 0.9.
|
8
|
+
- 11
|
9
|
+
version: 0.9.11
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Philippe Vosges
|
@@ -15,11 +15,11 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-12-26 00:00:00 +09:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
22
|
-
description: "
|
22
|
+
description: " The Simple Declarative Language provides an easy way to describe lists, maps,\n and trees of typed data in a compact, easy to read representation.\n For property files, configuration files, logs, and simple serialization\n requirements, SDL provides a compelling alternative to XML and Properties\n files.\n"
|
23
23
|
email: sdl-users@ikayzo.org
|
24
24
|
executables: []
|
25
25
|
|
@@ -29,29 +29,84 @@ extra_rdoc_files: []
|
|
29
29
|
|
30
30
|
files:
|
31
31
|
- lib/sdl4r.rb
|
32
|
-
- lib/sdl4r/
|
33
|
-
- lib/sdl4r/
|
34
|
-
- lib/sdl4r/
|
35
|
-
- lib/sdl4r/
|
36
|
-
- lib/sdl4r/
|
32
|
+
- lib/sdl4r/abbreviation_timezone_proxy.rb
|
33
|
+
- lib/sdl4r/constant_timezone.rb
|
34
|
+
- lib/sdl4r/element.rb
|
35
|
+
- lib/sdl4r/reader.rb
|
36
|
+
- lib/sdl4r/relative_timezone.rb
|
37
37
|
- lib/sdl4r/sdl4r.rb
|
38
|
+
- lib/sdl4r/sdl4r_tzinfo.rb
|
39
|
+
- lib/sdl4r/sdl4r_version.rb
|
38
40
|
- lib/sdl4r/sdl_binary.rb
|
39
41
|
- lib/sdl4r/sdl_parse_error.rb
|
40
42
|
- lib/sdl4r/sdl_time_span.rb
|
41
43
|
- lib/sdl4r/serializer.rb
|
42
44
|
- lib/sdl4r/tag.rb
|
45
|
+
- lib/sdl4r/token.rb
|
46
|
+
- lib/sdl4r/tokenizer.rb
|
47
|
+
- lib/sdl4r/tz_abbreviation_db.rb
|
43
48
|
- CHANGELOG
|
44
49
|
- LICENSE
|
45
50
|
- Rakefile
|
46
51
|
- README
|
52
|
+
- read_jprof.html
|
53
|
+
- read_jprof_pull.html
|
54
|
+
- read_prof.html
|
55
|
+
- read_prof_pull.html
|
47
56
|
- TODO
|
48
57
|
- test/sdl4r/parser_test.rb
|
58
|
+
- test/sdl4r/reader_test.rb
|
59
|
+
- test/sdl4r/read_jprof.rb
|
60
|
+
- test/sdl4r/read_prof.rb
|
61
|
+
- test/sdl4r/relative_timezone_test.rb
|
49
62
|
- test/sdl4r/sdl4r_test.rb
|
50
|
-
- test/sdl4r/
|
63
|
+
- test/sdl4r/sdl4r_tzinfo_test.rb
|
64
|
+
- test/sdl4r/sdl_test_case.rb
|
51
65
|
- test/sdl4r/serializer_test.rb
|
52
66
|
- test/sdl4r/tag_test.rb
|
53
67
|
- test/sdl4r/test_basic_types.sdl
|
54
68
|
- test/sdl4r/test_structures.sdl
|
69
|
+
- test/sdl4r/tokenizer_test.rb
|
70
|
+
- doc/classes/SDL4R/AbbreviationTimezoneProxy.html
|
71
|
+
- doc/classes/SDL4R/ConstantTimezone.html
|
72
|
+
- doc/classes/SDL4R/Element.html
|
73
|
+
- doc/classes/SDL4R/Reader.html
|
74
|
+
- doc/classes/SDL4R/RelativeTimezone.html
|
75
|
+
- doc/classes/SDL4R/SdlBinary.html
|
76
|
+
- doc/classes/SDL4R/SdlParseError.html
|
77
|
+
- doc/classes/SDL4R/SdlTimeSpan.html
|
78
|
+
- doc/classes/SDL4R/Serializer/Ref.html
|
79
|
+
- doc/classes/SDL4R/Serializer.html
|
80
|
+
- doc/classes/SDL4R/Tag.html
|
81
|
+
- doc/classes/SDL4R/Token.html
|
82
|
+
- doc/classes/SDL4R/TZAbbreviationDB/Record.html
|
83
|
+
- doc/created.rid
|
84
|
+
- doc/files/CHANGELOG.html
|
85
|
+
- doc/files/lib/sdl4r/abbreviation_timezone_proxy_rb.html
|
86
|
+
- doc/files/lib/sdl4r/constant_timezone_rb.html
|
87
|
+
- doc/files/lib/sdl4r/element_rb.html
|
88
|
+
- doc/files/lib/sdl4r/reader_rb.html
|
89
|
+
- doc/files/lib/sdl4r/relative_timezone_rb.html
|
90
|
+
- doc/files/lib/sdl4r/sdl4r_rb.html
|
91
|
+
- doc/files/lib/sdl4r/sdl4r_tzinfo_rb.html
|
92
|
+
- doc/files/lib/sdl4r/sdl4r_version_rb.html
|
93
|
+
- doc/files/lib/sdl4r/sdl_binary_rb.html
|
94
|
+
- doc/files/lib/sdl4r/sdl_parse_error_rb.html
|
95
|
+
- doc/files/lib/sdl4r/sdl_time_span_rb.html
|
96
|
+
- doc/files/lib/sdl4r/serializer_rb.html
|
97
|
+
- doc/files/lib/sdl4r/tag_rb.html
|
98
|
+
- doc/files/lib/sdl4r/tokenizer_rb.html
|
99
|
+
- doc/files/lib/sdl4r/token_rb.html
|
100
|
+
- doc/files/lib/sdl4r/tz_abbreviation_db_rb.html
|
101
|
+
- doc/files/lib/sdl4r_rb.html
|
102
|
+
- doc/files/lib/sdl4r_tzinfo_rb.html
|
103
|
+
- doc/files/LICENSE.html
|
104
|
+
- doc/files/README.html
|
105
|
+
- doc/fr_class_index.html
|
106
|
+
- doc/fr_file_index.html
|
107
|
+
- doc/fr_method_index.html
|
108
|
+
- doc/index.html
|
109
|
+
- doc/rdoc-style.css
|
55
110
|
has_rdoc: true
|
56
111
|
homepage: http://sdl4r.rubyforge.org/
|
57
112
|
licenses: []
|
@@ -86,7 +141,10 @@ specification_version: 3
|
|
86
141
|
summary: Simple Declarative Language for Ruby library
|
87
142
|
test_files:
|
88
143
|
- test/sdl4r/parser_test.rb
|
144
|
+
- test/sdl4r/reader_test.rb
|
145
|
+
- test/sdl4r/relative_timezone_test.rb
|
89
146
|
- test/sdl4r/sdl4r_test.rb
|
90
|
-
- test/sdl4r/
|
147
|
+
- test/sdl4r/sdl4r_tzinfo_test.rb
|
91
148
|
- test/sdl4r/serializer_test.rb
|
92
149
|
- test/sdl4r/tag_test.rb
|
150
|
+
- test/sdl4r/tokenizer_test.rb
|
data/lib/sdl4r/parser.rb
DELETED
@@ -1,648 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -w
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
#--
|
5
|
-
# Simple Declarative Language (SDL) for Ruby
|
6
|
-
# Copyright 2005 Ikayzo, inc.
|
7
|
-
#
|
8
|
-
# This program is free software. You can distribute or modify it under the
|
9
|
-
# terms of the GNU Lesser General Public License version 2.1 as published by
|
10
|
-
# the Free Software Foundation.
|
11
|
-
#
|
12
|
-
# This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
|
13
|
-
# INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
14
|
-
# See the GNU Lesser General Public License for more details.
|
15
|
-
#
|
16
|
-
# You should have received a copy of the GNU Lesser General Public License
|
17
|
-
# along with this program; if not, contact the Free Software Foundation, Inc.,
|
18
|
-
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19
|
-
#++
|
20
|
-
|
21
|
-
|
22
|
-
module SDL4R
|
23
|
-
|
24
|
-
require 'base64'
|
25
|
-
|
26
|
-
require File.dirname(__FILE__) + '/sdl_binary'
|
27
|
-
require File.dirname(__FILE__) + '/sdl_time_span'
|
28
|
-
require File.dirname(__FILE__) + '/sdl_parse_error'
|
29
|
-
require File.dirname(__FILE__) + '/parser/tokenizer'
|
30
|
-
|
31
|
-
# The SDL parser.
|
32
|
-
#
|
33
|
-
# In Ruby 1.8, in order to enable UTF-8 support, you may have to declare the following lines:
|
34
|
-
#
|
35
|
-
# $KCODE = 'u'
|
36
|
-
# require 'jcode'
|
37
|
-
#
|
38
|
-
# This will give you correct input and output and correct UTF-8 "general" sorting.
|
39
|
-
# Alternatively you can use the following options when launching the Ruby interpreter:
|
40
|
-
#
|
41
|
-
# /path/to/ruby -Ku -rjcode
|
42
|
-
#
|
43
|
-
# == Authors
|
44
|
-
# Daniel Leuck, Philippe Vosges
|
45
|
-
#
|
46
|
-
class Parser
|
47
|
-
|
48
|
-
# Passed to parse_error() in order to specify an error that occured on no specific position
|
49
|
-
# (column).
|
50
|
-
UNKNOWN_POSITION = -2
|
51
|
-
|
52
|
-
# Creates an SDL parser on the specified +IO+.
|
53
|
-
#
|
54
|
-
# IO.open("path/to/sdl_file") { |io|
|
55
|
-
# parser = SDL4R::Parser.new(io)
|
56
|
-
# tags = parser.parse()
|
57
|
-
# }
|
58
|
-
#
|
59
|
-
def initialize(io)
|
60
|
-
raise ArgumentError, "io == nil" if io.nil?
|
61
|
-
|
62
|
-
@tokenizer = Tokenizer.new(io)
|
63
|
-
end
|
64
|
-
|
65
|
-
# Parses the underlying +IO+ and returns an +Array+ of +Tag+.
|
66
|
-
#
|
67
|
-
# ==Errors
|
68
|
-
# [IOError] If a problem is encountered with the IO
|
69
|
-
# [SdlParseError] If the document is malformed
|
70
|
-
def parse
|
71
|
-
tags = []
|
72
|
-
|
73
|
-
while tokens = @tokenizer.read_line_tokens()
|
74
|
-
if tokens.last.type == :START_BLOCK
|
75
|
-
# tag with a block
|
76
|
-
tag = construct_tag(tokens[0...-1])
|
77
|
-
add_children(tag)
|
78
|
-
tags << tag
|
79
|
-
|
80
|
-
elsif tokens.first.type == :END_BLOCK
|
81
|
-
# we found an block end token that should have been consumed by
|
82
|
-
# add_children() normally
|
83
|
-
parse_error(
|
84
|
-
"No opening block ({) for close block (}).",
|
85
|
-
tokens.first.line,
|
86
|
-
tokens.first.position)
|
87
|
-
else
|
88
|
-
# tag without block
|
89
|
-
tags << construct_tag(tokens)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
@tokenizer.close()
|
94
|
-
|
95
|
-
return tags
|
96
|
-
end
|
97
|
-
|
98
|
-
# Creates and returns the object representing a datetime (DateTime in the default
|
99
|
-
# implementation). Can be overriden.
|
100
|
-
#
|
101
|
-
# def new_date_time(year, month, day, hour, min, sec, time_zone_offset)
|
102
|
-
# Time.utc(year, month, day, hour, min, sec)
|
103
|
-
# end
|
104
|
-
#
|
105
|
-
def new_date_time(year, month, day, hour, min, sec, time_zone_offset)
|
106
|
-
SDL4R::new_date_time(year, month, day, hour, min, sec, time_zone_offset)
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
# Parses the children tags of +parent+ until an end of block is found.
|
112
|
-
def add_children(parent)
|
113
|
-
while tokens = @tokenizer.read_line_tokens()
|
114
|
-
if tokens.first.type == :END_BLOCK
|
115
|
-
return
|
116
|
-
|
117
|
-
elsif tokens.last.type == :START_BLOCK
|
118
|
-
# found a child with a block
|
119
|
-
tag = construct_tag(tokens[0...-1]);
|
120
|
-
add_children(tag)
|
121
|
-
parent.add_child(tag)
|
122
|
-
|
123
|
-
else
|
124
|
-
parent.add_child(construct_tag(tokens))
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
parse_error("No close block (}).", @tokenizer.line_no, UNKNOWN_POSITION)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Construct a Tag (but not its children) from a string of tokens
|
132
|
-
#
|
133
|
-
# Throws SdlParseError if some bad syntax is found.
|
134
|
-
def construct_tag(tokens)
|
135
|
-
raise ArgumentError, "tokens == nil" if tokens.nil?
|
136
|
-
if tokens.empty?
|
137
|
-
parse_error("Internal Error: empty token list", @tokenizer.line_no, UNKNOWN_POSITION)
|
138
|
-
end
|
139
|
-
|
140
|
-
first_token = tokens.first
|
141
|
-
if first_token.literal?
|
142
|
-
first_token = Token.new(ANONYMOUS_TAG_NAME)
|
143
|
-
tokens.insert(0, first_token)
|
144
|
-
|
145
|
-
elsif first_token.type != :IDENTIFIER
|
146
|
-
expecting_but_got(
|
147
|
-
"IDENTIFIER",
|
148
|
-
"#{first_token.type} (#{first_token.text})",
|
149
|
-
first_token.line,
|
150
|
-
first_token.position)
|
151
|
-
end
|
152
|
-
|
153
|
-
tag = nil
|
154
|
-
if tokens.size == 1
|
155
|
-
tag = Tag.new(first_token.text)
|
156
|
-
|
157
|
-
else
|
158
|
-
values_start_index = 1
|
159
|
-
second_token = tokens[1]
|
160
|
-
|
161
|
-
if second_token.type == :COLON
|
162
|
-
if tokens.size == 2 or tokens[2].type != :IDENTIFIER
|
163
|
-
parse_error(
|
164
|
-
"Colon (:) encountered in unexpected location.",
|
165
|
-
second_token.line,
|
166
|
-
second_token.position)
|
167
|
-
end
|
168
|
-
|
169
|
-
third_token = tokens[2];
|
170
|
-
tag = Tag.new(first_token.text, third_token.text)
|
171
|
-
values_start_index = 3
|
172
|
-
|
173
|
-
else
|
174
|
-
tag = Tag.new(first_token.text)
|
175
|
-
end
|
176
|
-
|
177
|
-
# read values
|
178
|
-
attribute_start_index = add_tag_values(tag, tokens, values_start_index)
|
179
|
-
|
180
|
-
# read attributes
|
181
|
-
if attribute_start_index < tokens.size
|
182
|
-
add_tag_attributes(tag, tokens, attribute_start_index)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
return tag
|
187
|
-
end
|
188
|
-
|
189
|
-
# Return the position at the end of the value list
|
190
|
-
#
|
191
|
-
def add_tag_values(tag, tokens, start)
|
192
|
-
size = tokens.size()
|
193
|
-
i = start;
|
194
|
-
|
195
|
-
while i < size
|
196
|
-
token = tokens[i]
|
197
|
-
|
198
|
-
if token.literal?
|
199
|
-
# if a DATE token is followed by a TIME token combine them
|
200
|
-
next_token = ((i + 1) < size)? tokens[i + 1] : nil
|
201
|
-
if token.type == :DATE && next_token && next_token.type == :TIME
|
202
|
-
date = token.object_for_literal()
|
203
|
-
time_span_with_zone = next_token.object_for_literal()
|
204
|
-
|
205
|
-
if time_span_with_zone.day
|
206
|
-
# as there are days specified, it can't be a full precision date
|
207
|
-
tag.add_value(date);
|
208
|
-
tag.add_value(
|
209
|
-
SdlTimeSpan.new(
|
210
|
-
time_span_with_zone.day || 0,
|
211
|
-
time_span_with_zone.hour,
|
212
|
-
time_span_with_zone.min,
|
213
|
-
time_span_with_zone.sec))
|
214
|
-
|
215
|
-
|
216
|
-
if time_span_with_zone.time_zone_offset
|
217
|
-
parse_error("TimeSpan cannot have a timeZone", t.line, t.position)
|
218
|
-
end
|
219
|
-
|
220
|
-
else
|
221
|
-
tag.add_value(combine(date, time_span_with_zone))
|
222
|
-
end
|
223
|
-
|
224
|
-
i += 1
|
225
|
-
|
226
|
-
else
|
227
|
-
value = token.object_for_literal()
|
228
|
-
if value.is_a?(TimeSpanWithZone)
|
229
|
-
# the literal looks like a time zone
|
230
|
-
if value.time_zone_offset
|
231
|
-
expecting_but_got(
|
232
|
-
"TIME SPAN",
|
233
|
-
"TIME (component of date/time)",
|
234
|
-
token.line,
|
235
|
-
token.position)
|
236
|
-
end
|
237
|
-
|
238
|
-
tag.add_value(SdlTimeSpan.new(value.day || 0, value.hour, value.min, value.sec))
|
239
|
-
else
|
240
|
-
tag.add_value(value)
|
241
|
-
end
|
242
|
-
end
|
243
|
-
elsif token.type == :IDENTIFIER
|
244
|
-
break
|
245
|
-
else
|
246
|
-
expecting_but_got(
|
247
|
-
"LITERAL or IDENTIFIER", token.type, token.line, token.position)
|
248
|
-
end
|
249
|
-
|
250
|
-
i += 1
|
251
|
-
end
|
252
|
-
|
253
|
-
return i
|
254
|
-
end
|
255
|
-
|
256
|
-
#
|
257
|
-
# Add attributes to the given tag
|
258
|
-
#
|
259
|
-
def add_tag_attributes(tag, tokens, start)
|
260
|
-
i = start
|
261
|
-
size = tokens.size
|
262
|
-
|
263
|
-
while i < size
|
264
|
-
token = tokens[i]
|
265
|
-
if token.type != :IDENTIFIER
|
266
|
-
expecting_but_got("IDENTIFIER", token.type, token.line, token.position)
|
267
|
-
end
|
268
|
-
name_or_namespace = token.text;
|
269
|
-
|
270
|
-
if i == (size - 1)
|
271
|
-
expecting_but_got(
|
272
|
-
"\":\" or \"=\" \"LITERAL\"",
|
273
|
-
"END OF LINE.",
|
274
|
-
token.line,
|
275
|
-
token.position)
|
276
|
-
end
|
277
|
-
|
278
|
-
i += 1
|
279
|
-
token = tokens[i]
|
280
|
-
if token.type == :COLON
|
281
|
-
if i == (size - 1)
|
282
|
-
expecting_but_got(
|
283
|
-
"IDENTIFIER", "END OF LINE", token.line, token.position)
|
284
|
-
end
|
285
|
-
|
286
|
-
i += 1
|
287
|
-
token = tokens[i]
|
288
|
-
if token.type != :IDENTIFIER
|
289
|
-
expecting_but_got(
|
290
|
-
"IDENTIFIER", token.type, token.line, token.position)
|
291
|
-
end
|
292
|
-
name = token.text
|
293
|
-
|
294
|
-
if i == (size - 1)
|
295
|
-
expecting_but_got("\"=\"", "END OF LINE", token.line, token.position)
|
296
|
-
end
|
297
|
-
|
298
|
-
i += 1
|
299
|
-
token = tokens[i]
|
300
|
-
if token.type != :EQUALS
|
301
|
-
expecting_but_got("\"=\"", token.type, token.line, token.position)
|
302
|
-
end
|
303
|
-
|
304
|
-
if i == (size - 1)
|
305
|
-
expecting_but_got("LITERAL", "END OF LINE", token.line, token.position)
|
306
|
-
end
|
307
|
-
|
308
|
-
i += 1
|
309
|
-
token = tokens[i]
|
310
|
-
if !token.literal?
|
311
|
-
expecting_but_got("LITERAL", token.type, token.line, token.position)
|
312
|
-
end
|
313
|
-
|
314
|
-
if token.type == :DATE and (i + 1) < size and tokens[i + 1].type == :TIME
|
315
|
-
date = token.get_object_for_literal()
|
316
|
-
time_span_with_zone = tokens[i + 1].get_object_for_literal()
|
317
|
-
|
318
|
-
if time_span_with_zone.days != 0
|
319
|
-
expecting_but_got(
|
320
|
-
"TIME (component of date/time) in attribute value",
|
321
|
-
"TIME SPAN",
|
322
|
-
token.line,
|
323
|
-
token.position)
|
324
|
-
else
|
325
|
-
tag.set_attribute(name_or_namespace, name, combine(date, time_span_with_zone))
|
326
|
-
end
|
327
|
-
|
328
|
-
i += 1
|
329
|
-
else
|
330
|
-
value = token.object_for_literal();
|
331
|
-
if value.is_a?(TimeSpanWithZone)
|
332
|
-
time_span_with_zone = value
|
333
|
-
|
334
|
-
if time_span_with_zone.time_zone_offset
|
335
|
-
expecting_but_got(
|
336
|
-
"TIME SPAN",
|
337
|
-
"TIME (component of date/time)",
|
338
|
-
token.line,
|
339
|
-
token.position)
|
340
|
-
end
|
341
|
-
|
342
|
-
time_span = SdlTimeSpan.new(
|
343
|
-
time_span_with_zone.day,
|
344
|
-
time_span_with_zone.hour,
|
345
|
-
time_span_with_zone.min,
|
346
|
-
time_span_with_zone.sec)
|
347
|
-
|
348
|
-
tag.set_attribute(name_or_namespace, name, time_span)
|
349
|
-
else
|
350
|
-
tag.set_attribute(name_or_namespace, name, value);
|
351
|
-
end
|
352
|
-
end
|
353
|
-
elsif token.type == :EQUALS
|
354
|
-
if i == (size - 1)
|
355
|
-
expecting_but_got("LITERAL", "END OF LINE", token.line, token.position)
|
356
|
-
end
|
357
|
-
|
358
|
-
i += 1
|
359
|
-
token = tokens[i]
|
360
|
-
if !token.literal?
|
361
|
-
expecting_but_got("LITERAL", token.type, token.line, token.position)
|
362
|
-
end
|
363
|
-
|
364
|
-
if token.type == :DATE and (i + 1) < size and tokens[i + 1].type == :TIME
|
365
|
-
date = token.object_for_literal()
|
366
|
-
time_span_with_zone = tokens[i + 1].object_for_literal()
|
367
|
-
|
368
|
-
if time_span_with_zone.day
|
369
|
-
expecting_but_got(
|
370
|
-
"TIME (component of date/time) in attribute value",
|
371
|
-
"TIME SPAN",
|
372
|
-
token.line,
|
373
|
-
token.position)
|
374
|
-
end
|
375
|
-
tag.set_attribute(name_or_namespace, combine(date, time_span_with_zone))
|
376
|
-
|
377
|
-
i += 1
|
378
|
-
else
|
379
|
-
value = token.object_for_literal()
|
380
|
-
if value.is_a?(TimeSpanWithZone)
|
381
|
-
time_span_with_zone = value
|
382
|
-
if time_span_with_zone.time_zone_offset
|
383
|
-
expecting_but_got(
|
384
|
-
"TIME SPAN",
|
385
|
-
"TIME (component of date/time)",
|
386
|
-
token.line,
|
387
|
-
token.position)
|
388
|
-
end
|
389
|
-
|
390
|
-
time_span = SdlTimeSpan.new(
|
391
|
-
time_span_with_zone.day || 0,
|
392
|
-
time_span_with_zone.hour,
|
393
|
-
time_span_with_zone.min,
|
394
|
-
time_span_with_zone.sec)
|
395
|
-
tag.set_attribute(name_or_namespace, time_span)
|
396
|
-
else
|
397
|
-
tag.set_attribute(name_or_namespace, value);
|
398
|
-
end
|
399
|
-
end
|
400
|
-
else
|
401
|
-
expecting_but_got(
|
402
|
-
"\":\" or \"=\"", token.type, token.line, token.position)
|
403
|
-
end
|
404
|
-
|
405
|
-
i += 1
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
# Combines a simple Date with a TimeSpanWithZone to create a DateTime
|
410
|
-
#
|
411
|
-
def combine(date, time_span_with_zone)
|
412
|
-
time_zone_offset = time_span_with_zone.time_zone_offset
|
413
|
-
time_zone_offset = TimeSpanWithZone.default_time_zone_offset if time_zone_offset.nil?
|
414
|
-
|
415
|
-
new_date_time(
|
416
|
-
date.year,
|
417
|
-
date.month,
|
418
|
-
date.day,
|
419
|
-
time_span_with_zone.hour,
|
420
|
-
time_span_with_zone.min,
|
421
|
-
time_span_with_zone.sec,
|
422
|
-
time_zone_offset)
|
423
|
-
end
|
424
|
-
|
425
|
-
private
|
426
|
-
############################################################################
|
427
|
-
## Parsers for types
|
428
|
-
############################################################################
|
429
|
-
|
430
|
-
def Parser.parse_string(literal)
|
431
|
-
unless literal =~ /(^`.*`$)|(^\".*\"$)/m
|
432
|
-
raise ArgumentError,
|
433
|
-
"Malformed string <#{literal}>." +
|
434
|
-
" Strings must start and end with \" or `"
|
435
|
-
end
|
436
|
-
|
437
|
-
return literal[1..-2]
|
438
|
-
end
|
439
|
-
|
440
|
-
def Parser.parse_character(literal)
|
441
|
-
unless literal =~ /(^'.*'$)/
|
442
|
-
raise ArgumentError,
|
443
|
-
"Malformed character <#{literal}>." +
|
444
|
-
" Character must start and end with single quotes"
|
445
|
-
end
|
446
|
-
|
447
|
-
return literal[1]
|
448
|
-
end
|
449
|
-
|
450
|
-
def Parser.parse_number(literal)
|
451
|
-
# we use the fact that Kernel.Integer() and Kernel.Float() raise ArgumentErrors
|
452
|
-
if literal =~ /(.*)(L)$/i
|
453
|
-
return Integer($1)
|
454
|
-
elsif literal =~ /([^BDF]*)(BD)$/i
|
455
|
-
return BigDecimal($1)
|
456
|
-
elsif literal =~ /([^BDF]*)(F|D)$/i
|
457
|
-
return Float($1)
|
458
|
-
elsif literal.count(".e") == 0
|
459
|
-
return Integer(literal)
|
460
|
-
else
|
461
|
-
return Float(literal)
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
# Parses the given literal into a returned array
|
466
|
-
# [days, hours, minutes, seconds, time_zone_offset].
|
467
|
-
# 'days', 'hours' and 'minutes' are integers.
|
468
|
-
# 'seconds' and 'time_zone_offset' are rational numbers.
|
469
|
-
# 'days' and 'seconds' are equal to 0 if they're not specified in +literal+.
|
470
|
-
# 'time_zone_offset' is equal to nil if not specified.
|
471
|
-
#
|
472
|
-
# +allowDays+ indicates whether the specification of days is allowed
|
473
|
-
# in +literal+
|
474
|
-
# +allowTimeZone+ indicates whether the specification of the timeZone is
|
475
|
-
# allowed in +literal+
|
476
|
-
#
|
477
|
-
# All components are returned disregarding the values of +allowDays+ and
|
478
|
-
# +allowTimeZone+.
|
479
|
-
#
|
480
|
-
# Raises an ArgumentError if +literal+ has a bad format.
|
481
|
-
def Parser.parse_time_span_and_time_zone(literal, allowDays, allowTimeZone)
|
482
|
-
overall_sign = (literal =~ /^-/)? -1 : +1
|
483
|
-
|
484
|
-
if literal =~ /^(([+\-]?\d+)d:)/
|
485
|
-
if allowDays
|
486
|
-
days = Integer($2)
|
487
|
-
time_part = literal[($1.length)..-1]
|
488
|
-
else
|
489
|
-
# detected a day specification in a pure time literal
|
490
|
-
raise ArgumentError, "unexpected day specification in #{literal}"
|
491
|
-
end
|
492
|
-
else
|
493
|
-
days = nil
|
494
|
-
time_part = literal
|
495
|
-
end
|
496
|
-
|
497
|
-
# We have to parse the string ourselves because AFAIK :
|
498
|
-
# - strptime() can't parse milliseconds
|
499
|
-
# - strptime() can't parse the time zone custom offset (CET+02:30)
|
500
|
-
# - strptime() accepts trailing chars
|
501
|
-
# (e.g. "12:24-xyz@" ==> "xyz@" is obviously wrong but strptime()
|
502
|
-
# won't mind)
|
503
|
-
if time_part =~ /^([+-]?\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?(?:(?:-([a-zA-Z]+))?(?:([\+\-]\d+)(?::(\d+))?)?)?$/i
|
504
|
-
hours = $1.to_i
|
505
|
-
minutes = $2.to_i
|
506
|
-
# seconds and milliseconds are implemented as one rational number
|
507
|
-
# unless there are no milliseconds
|
508
|
-
millisecond_part = ($4)? $4.ljust(3, "0") : nil
|
509
|
-
if millisecond_part
|
510
|
-
seconds = Rational(($3 + millisecond_part).to_i, 10 ** millisecond_part.length)
|
511
|
-
else
|
512
|
-
seconds = ($3)? Integer($3) : 0
|
513
|
-
end
|
514
|
-
|
515
|
-
if ($5 or $6) and not allowTimeZone
|
516
|
-
raise ArgumentError, "unexpected time zone specification in #{literal}"
|
517
|
-
end
|
518
|
-
|
519
|
-
time_zone_code = $5 # might be nil
|
520
|
-
|
521
|
-
if $6
|
522
|
-
zone_custom_minute_offset = $6.to_i * 60
|
523
|
-
if $7
|
524
|
-
if zone_custom_minute_offset > 0
|
525
|
-
zone_custom_minute_offset = zone_custom_minute_offset + $7.to_i
|
526
|
-
else
|
527
|
-
zone_custom_minute_offset = zone_custom_minute_offset - $7.to_i
|
528
|
-
end
|
529
|
-
end
|
530
|
-
end
|
531
|
-
|
532
|
-
time_zone_offset = get_time_zone_offset(time_zone_code, zone_custom_minute_offset)
|
533
|
-
|
534
|
-
if not allowDays and $1 =~ /^[+-]/
|
535
|
-
# unexpected timeSpan syntax
|
536
|
-
raise ArgumentError, "unexpected sign on hours : #{literal}"
|
537
|
-
end
|
538
|
-
|
539
|
-
# take the sign into account
|
540
|
-
hours *= overall_sign if days # otherwise the sign is already applied to the hours
|
541
|
-
minutes *= overall_sign
|
542
|
-
seconds *= overall_sign
|
543
|
-
|
544
|
-
return [ days, hours, minutes, seconds, time_zone_offset ]
|
545
|
-
|
546
|
-
else
|
547
|
-
raise ArgumentError, "bad time component : #{literal}"
|
548
|
-
end
|
549
|
-
end
|
550
|
-
|
551
|
-
# Parses the given literal (String) into a returned DateTime object.
|
552
|
-
#
|
553
|
-
# Raises an ArgumentError if +literal+ has a bad format.
|
554
|
-
def Parser.parse_date_time(literal)
|
555
|
-
raise ArgumentError("date literal is nil") if literal.nil?
|
556
|
-
|
557
|
-
begin
|
558
|
-
parts = literal.split(" ")
|
559
|
-
if parts.length == 1
|
560
|
-
return parse_date(literal)
|
561
|
-
else
|
562
|
-
date = parse_date(parts[0]);
|
563
|
-
time_part = parts[1]
|
564
|
-
|
565
|
-
days, hours, minutes, seconds, time_zone_offset =
|
566
|
-
parse_time_span_and_time_zone(time_part, false, true)
|
567
|
-
|
568
|
-
return new_date_time(
|
569
|
-
date.year, date.month, date.day, hours, minutes, seconds, time_zone_offset)
|
570
|
-
end
|
571
|
-
|
572
|
-
rescue ArgumentError
|
573
|
-
raise ArgumentError, "Bad date/time #{literal} : #{$!.message}"
|
574
|
-
end
|
575
|
-
end
|
576
|
-
|
577
|
-
##
|
578
|
-
# Returns the time zone offset (Rational) corresponding to the provided parameters as a fraction
|
579
|
-
# of a day. This method adds the two offsets if they are both provided.
|
580
|
-
#
|
581
|
-
# +time_zone_code+: can be nil
|
582
|
-
# +custom_minute_offset+: can be nil
|
583
|
-
#
|
584
|
-
def Parser.get_time_zone_offset(time_zone_code, custom_minute_offset)
|
585
|
-
return nil unless time_zone_code or custom_minute_offset
|
586
|
-
|
587
|
-
time_zone_offset = custom_minute_offset ? Rational(custom_minute_offset, 60 * 24) : 0
|
588
|
-
|
589
|
-
return time_zone_offset unless time_zone_code
|
590
|
-
|
591
|
-
# we have to provide some bogus year/month/day in order to parse our time zone code
|
592
|
-
d = DateTime.strptime("1999/01/01 #{time_zone_code}", "%Y/%m/%d %Z")
|
593
|
-
# the offset is a fraction of a day
|
594
|
-
return d.offset() + time_zone_offset
|
595
|
-
end
|
596
|
-
|
597
|
-
# Parses the +literal+ into a returned Date object.
|
598
|
-
#
|
599
|
-
# Raises an ArgumentError if +literal+ has a bad format.
|
600
|
-
|
601
|
-
def Parser.parse_date(literal)
|
602
|
-
# here, we're being stricter than strptime() alone as we forbid trailing chars
|
603
|
-
if literal =~ /^(-?\d+)\/(\d+)\/(\d+)$/
|
604
|
-
begin
|
605
|
-
return Date.strptime(literal, "%Y/%m/%d")
|
606
|
-
rescue ArgumentError
|
607
|
-
raise ArgumentError, "Malformed Date <#{literal}> : #{$!.message}"
|
608
|
-
end
|
609
|
-
end
|
610
|
-
|
611
|
-
raise ArgumentError, "Malformed Date <#{literal}>"
|
612
|
-
end
|
613
|
-
|
614
|
-
# Returns a String that contains the binary content corresponding to +literal+.
|
615
|
-
#
|
616
|
-
# +literal+ : a base-64 encoded literal (e.g. "[V2hvIHdhbnRzIHRvIGxpdmUgZm9yZXZlcj8=]")
|
617
|
-
def Parser.parse_binary(literal)
|
618
|
-
clean_literal = literal[1..-2] # remove square brackets
|
619
|
-
return SdlBinary.decode64(clean_literal)
|
620
|
-
end
|
621
|
-
|
622
|
-
# Parses +literal+ (String) into the corresponding SDLTimeSpan, which is then
|
623
|
-
# returned.
|
624
|
-
#
|
625
|
-
# Raises an ArgumentError if the literal is not a correct timeSpan literal.
|
626
|
-
def Parser.parse_time_span(literal)
|
627
|
-
days, hours, minutes, seconds, time_zone_offset =
|
628
|
-
parse_time_span_and_time_zone(literal, true, false)
|
629
|
-
|
630
|
-
milliseconds = ((seconds - seconds.to_i) * 1000).to_i
|
631
|
-
seconds = seconds.to_i
|
632
|
-
|
633
|
-
return SDLTimeSpan.new(days, hours, minutes, seconds, milliseconds)
|
634
|
-
end
|
635
|
-
|
636
|
-
# Close the reader and throw a SdlParseError using the format
|
637
|
-
# Was expecting X but got Y.
|
638
|
-
#
|
639
|
-
def expecting_but_got(expecting, got, line, position)
|
640
|
-
@tokenizer.expecting_but_got(expecting, got, line, position)
|
641
|
-
end
|
642
|
-
|
643
|
-
# Raises a SdlParseError.
|
644
|
-
def parse_error(description, line_no, position)
|
645
|
-
@tokenizer.parse_error(description, line_no, position)
|
646
|
-
end
|
647
|
-
end
|
648
|
-
end
|