trenni 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2012 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,181 @@
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+
22
+ require 'strscan'
23
+
24
+ module Trenni
25
+ # This scanner processes general markup into a sequence of events which are passed to a delegate.
26
+ class Scanner
27
+ OPENED_TAG = :opened
28
+ CLOSED_TAG = :closed
29
+
30
+ class ScanError < StandardError
31
+ def initialize(message, scanner)
32
+ @message = message
33
+
34
+ @pos = scanner.pos
35
+ @offset = calculate_line_number(scanner)
36
+ end
37
+
38
+ attr :offset
39
+
40
+ def to_s
41
+ if @offset
42
+ "Scan Error: #{@message} @ [#{@offset[0]}:#{@offset[2]}]: #{@offset[4]}"
43
+ else
44
+ "Scan Error [#{@pos}]: #{@message}"
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ def calculate_line_number(scanner)
51
+ at = scanner.pos
52
+
53
+ line_no = 1
54
+ line_offset = offset = 0
55
+
56
+ scanner.string.lines.each do |line|
57
+ line_offset = offset
58
+ offset += line.size
59
+
60
+ if offset >= at
61
+ return [line_no, line_offset, at - line_offset, offset, line]
62
+ end
63
+
64
+ line_no += 1
65
+ end
66
+
67
+ return nil
68
+ end
69
+ end
70
+
71
+ def initialize(delegate)
72
+ @delegate = delegate
73
+ end
74
+
75
+ def parse(string)
76
+ scanner = StringScanner.new(string)
77
+
78
+ until scanner.eos?
79
+ start_pos = scanner.pos
80
+
81
+ scan_text(scanner)
82
+ scan_tag(scanner)
83
+
84
+ if start_pos == scanner.pos
85
+ raise ScanError.new("Scanner didn't move", scanner)
86
+ end
87
+ end
88
+ end
89
+
90
+ protected
91
+
92
+ def scan_text(scanner)
93
+ # Match any character data except the open tag character.
94
+ if scanner.scan(/[^<]+/m)
95
+ @delegate.text(scanner.matched)
96
+ end
97
+ end
98
+
99
+ def scan_tag(scanner)
100
+ if scanner.scan(/</)
101
+ if scanner.scan(/\//)
102
+ scan_tag_normal(scanner, CLOSED_TAG)
103
+ elsif scanner.scan(/!\[CDATA\[/)
104
+ scan_tag_cdata(scanner)
105
+ elsif scanner.scan(/!/)
106
+ scan_tag_comment(scanner)
107
+ elsif scanner.scan(/\?/)
108
+ scan_tag_instruction(scanner)
109
+ else
110
+ scan_tag_normal(scanner)
111
+ end
112
+ end
113
+ end
114
+
115
+ def scan_attributes(scanner)
116
+ # Parse an attribute in the form of key="value" or key.
117
+ while scanner.scan(/\s*([^\s=\/>]+)/um)
118
+ name = scanner[1]
119
+ if scanner.scan(/=((['"])(.*?)\2)/um)
120
+ @delegate.attribute(name, scanner[3])
121
+ else
122
+ @delegate.attribute(name, true)
123
+ end
124
+ end
125
+ end
126
+
127
+ def scan_tag_normal(scanner, begin_tag_type = OPENED_TAG)
128
+ if scanner.scan(/[^\s\/>]+/)
129
+ @delegate.begin_tag(scanner.matched, begin_tag_type)
130
+
131
+ scanner.scan(/\s*/)
132
+ self.scan_attributes(scanner)
133
+ scanner.scan(/\s*/)
134
+
135
+ if scanner.scan(/\/>/)
136
+ if begin_tag_type == CLOSED_TAG
137
+ raise ScanError.new("Tag cannot be closed at both ends!", scanner)
138
+ else
139
+ @delegate.finish_tag(begin_tag_type, CLOSED_TAG)
140
+ end
141
+ elsif scanner.scan(/>/)
142
+ @delegate.finish_tag(begin_tag_type, OPENED_TAG)
143
+ else
144
+ raise ScanError.new("Invalid characters in tag!", scanner)
145
+ end
146
+ else
147
+ raise ScanError.new("Invalid tag!", scanner)
148
+ end
149
+ end
150
+
151
+ def scan_tag_cdata(scanner)
152
+ if scanner.scan_until(/(.*?)\]\]>/m)
153
+ @delegate.cdata(scanner[1])
154
+ else
155
+ raise ScanError.new("CDATA segment is not closed!", scanner)
156
+ end
157
+ end
158
+
159
+ def scan_tag_comment(scanner)
160
+ if scanner.scan(/--/)
161
+ if scanner.scan_until(/(.*?)-->/m)
162
+ @delegate.comment("--" + scanner[1] + "--")
163
+ else
164
+ raise ScanError.new("Comment is not closed!", scanner)
165
+ end
166
+ else
167
+ if scanner.scan_until(/(.*?)>/)
168
+ @delegate.comment(scanner[1])
169
+ else
170
+ raise ScanError.new("Comment is not closed!", scanner)
171
+ end
172
+ end
173
+ end
174
+
175
+ def scan_tag_instruction(scanner)
176
+ if scanner.scan_until(/(.*)\?>/)
177
+ @delegate.instruction(scanner[1])
178
+ end
179
+ end
180
+ end
181
+ end
@@ -1,3 +1,22 @@
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
1
20
 
2
21
  module Trenni
3
22
  module Strings
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,4 +1,4 @@
1
- # Copyright 2012 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Trenni
22
- VERSION = "1.0.4"
22
+ VERSION = "1.1.0"
23
23
  end
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # Copyright (c) 2007, 2012 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'pathname'
24
+ require 'test/unit'
25
+ require 'stringio'
26
+ require 'digest/md5'
27
+
28
+ require 'trenni/scanner'
29
+
30
+ class TestScanner < Test::Unit::TestCase
31
+ class ScannerDelegate
32
+ def initialize
33
+ @events = []
34
+ end
35
+
36
+ attr :events
37
+
38
+ def method_missing(*args)
39
+ @events << args
40
+ end
41
+ end
42
+
43
+ def test_markup
44
+ delegate = ScannerDelegate.new
45
+ scanner = Trenni::Scanner.new(delegate)
46
+
47
+ scanner.parse(%Q{<foo bar="20" baz>Hello World</foo>})
48
+
49
+ expected_events = [
50
+ [:begin_tag, "foo", :opened],
51
+ [:attribute, "bar", "20"],
52
+ [:attribute, "baz", true],
53
+ [:finish_tag, :opened, :opened],
54
+ [:text, "Hello World"],
55
+ [:begin_tag, "foo", :closed],
56
+ [:finish_tag, :closed, :opened],
57
+ ]
58
+
59
+ assert_equal expected_events, delegate.events
60
+ end
61
+
62
+ def test_cdata
63
+ delegate = ScannerDelegate.new
64
+ scanner = Trenni::Scanner.new(delegate)
65
+
66
+ scanner.parse(%Q{<test><![CDATA[Hello World]]></test>})
67
+
68
+ expected_events = [
69
+ [:begin_tag, "test", :opened],
70
+ [:finish_tag, :opened, :opened],
71
+ [:cdata, "Hello World"],
72
+ [:begin_tag, "test", :closed],
73
+ [:finish_tag, :closed, :opened],
74
+ ]
75
+
76
+ assert_equal expected_events, delegate.events
77
+ end
78
+
79
+ def test_errors
80
+ delegate = ScannerDelegate.new
81
+ scanner = Trenni::Scanner.new(delegate)
82
+
83
+ assert_raise Trenni::Scanner::ScanError do
84
+ scanner.parse(%Q{<foo})
85
+ end
86
+
87
+ assert_raise Trenni::Scanner::ScanError do
88
+ scanner.parse(%Q{<foo bar=>})
89
+ end
90
+
91
+ assert_nothing_raised Trenni::Scanner::ScanError do
92
+ scanner.parse(%Q{<foo bar="" baz>})
93
+ end
94
+ end
95
+ end
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # Copyright (c) 2007, 2012 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # Copyright (c) 2007, 2012 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
3
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  # of this software and associated documentation files (the "Software"), to deal
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trenni
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 4
10
- version: 1.0.4
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Samuel Williams
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-10-25 00:00:00 Z
18
+ date: 2012-10-26 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: "\tTrenni is a templating system that evaluates textual strings containing Ruby\n\
@@ -40,10 +40,12 @@ files:
40
40
  - lib/trenni.rb
41
41
  - lib/trenni/builder.rb
42
42
  - lib/trenni/extensions/symbol-1.8.7.rb
43
+ - lib/trenni/scanner.rb
43
44
  - lib/trenni/strings.rb
44
45
  - lib/trenni/template.rb
45
46
  - lib/trenni/version.rb
46
47
  - test/test_builder.rb
48
+ - test/test_scanner.rb
47
49
  - test/test_strings.rb
48
50
  - test/test_template.rb
49
51
  - trenni.gemspec
@@ -82,5 +84,6 @@ specification_version: 3
82
84
  summary: A fast native templating system that compiles directly to Ruby code.
83
85
  test_files:
84
86
  - test/test_builder.rb
87
+ - test/test_scanner.rb
85
88
  - test/test_strings.rb
86
89
  - test/test_template.rb