lokar 0.1.0 → 0.2.0

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.
Files changed (2) hide show
  1. data/lokar.rb +90 -74
  2. metadata +16 -5
data/lokar.rb CHANGED
@@ -2,133 +2,149 @@ require 'strscan'
2
2
 
3
3
  module Lokar
4
4
  def self.render(string, filename = '<Lokar>', binding = nil)
5
- output = ["__output__ = []", *parse(string, filename), "\n__output__"]
6
-
7
- eval(output.join, binding, filename).join
5
+ eval("__output__ = []#{parse(string, filename).join}; __output__", binding, filename).join
8
6
  end
9
7
 
10
8
  def self.compile(string, filename = '<Lokar>', binding = nil)
11
- output = ["Proc.new do __output__ = []", *parse(string, filename), "\n__output__ end"]
12
-
13
- eval output.join, binding, filename
9
+ eval "Proc.new do __output__ = []#{parse(string, filename).join}; __output__ end", binding, filename
14
10
  end
15
11
 
16
12
  def self.parse(string, filename)
17
13
  scanner = StringScanner.new(string)
18
- output = []
19
14
  prev_text = false
20
15
  prev_output = true
16
+ output = []
17
+ line = 1
18
+ flushed = 1
21
19
 
22
20
  while true
23
- match = scanner.scan_until(/(?=<\?r[ \t]|\#{|^[ \t]*%)/m)
21
+ match = scanner.scan_until(/(?=<\?r(?:[ \t]|$)|\#?\#{|^[ \t]*%|(?:\r\n?|\n))/m)
24
22
  if match
25
23
  # Add the text before the match
26
- if prev_text
27
- output.insert(-1, match.inspect)
28
- else
24
+ unless prev_text
29
25
  if prev_output
30
- output << " << "
26
+ output << "<<"
31
27
  else
32
- output << "\n__output__ << "
28
+ output << ";__output__<<"
33
29
  prev_output = true
34
30
  end
35
- output << match.inspect
36
31
  prev_text = true
37
32
  end
33
+ output << match.inspect
38
34
 
39
35
  case # Find out what of the regular expression matched
40
- when scanner.match?(/</) # Parse <?r ?> tags
36
+ when match = scanner.scan(/\r\n?|\n/) # Parse newlines
37
+ unless prev_text
38
+ if prev_output
39
+ output << "<<"
40
+ else
41
+ output << ";__output__<<"
42
+ prev_output = true
43
+ end
44
+ prev_text = true
45
+ end
46
+ output << match.inspect
47
+ line += 1
48
+
49
+ when scanner.match?(/</) # Parse <?r?> tags
41
50
  scanner.pos += 3
42
51
  result = scanner.scan_until(/(?=\?>)/m)
43
- raise "#{filename}: Unterminated <?r ?> tag" unless result
44
-
45
- output << "\n"
46
- output << result
52
+ raise "#{filename}:#{line}: Unterminated <\?r ?> tag" unless result
47
53
 
54
+ output << ("\n" * (line - flushed)) << ";" << result
55
+ flushed = line
48
56
  prev_text = false
49
57
  prev_output = false
50
58
 
51
59
  scanner.pos += 2
52
60
 
53
- when scanner.match?(/\#/) # Parse #{ } tags
54
- index = 1
55
- scanner.pos += 2
56
-
57
- if prev_output
58
- output << " << ("
61
+ when scanner.skip(/\#/) # Parse #{ } tags
62
+ if scanner.skip(/\#/)
63
+ unless prev_text
64
+ if prev_output
65
+ output << "<<"
66
+ else
67
+ output << ";__output__<<"
68
+ prev_output = true
69
+ end
70
+ prev_text = true
71
+ end
72
+ output << '#'.inspect
59
73
  else
60
- output << "\n__output__ << ("
61
- prev_output = true
62
- end
63
-
64
- while true
65
- result = scanner.scan_until(/(?=}|{)/m)
66
- raise "#{filename}: Unterminated \#{ } tag" unless result
67
- output << result
68
- case
69
- when scanner.scan(/{/)
70
- index += 1
71
- output << '{'
72
-
73
- when scanner.scan(/}/)
74
- index -= 1
75
- break if index == 0
76
- output << '}'
74
+ index = 1
75
+ scanner.pos += 1
76
+
77
+ if prev_output
78
+ output << "<<" << ("\n" * (line - flushed)) << "("
79
+ else
80
+ output << ("\n" * (line - flushed)) << ";__output__<<("
81
+ prev_output = true
82
+ end
83
+ flushed = line
84
+ prev_text = false
85
+
86
+ while true
87
+ result = scanner.scan_until(/(?=}|{)/m)
88
+ raise "#{filename}:#{line}: Unterminated \#\{ } tag" unless result
89
+ output << result
90
+ case
91
+ when scanner.skip(/{/)
92
+ index += 1
93
+ output << '{'
94
+
95
+ when scanner.skip(/}/)
96
+ index -= 1
97
+ break if index == 0
98
+ output << '}'
99
+ end
77
100
  end
101
+
102
+ output << ")"
78
103
  end
79
-
80
- output << ")"
81
-
82
- prev_output = true
83
- prev_text = false
84
104
 
85
105
  else # Parse %, %% and %= lines
86
106
  result = scanner.scan(/[ \t]*%/)
87
- if scanner.scan(/%/)
88
- result = result.inspect
89
- if prev_text
90
- output << result
91
- else
107
+ if scanner.skip(/%/)
108
+ unless prev_text
92
109
  if prev_output
93
- output << " << "
110
+ output << "<<"
94
111
  else
95
- output << "\n__output__ << "
112
+ output << ";__output__<<"
96
113
  prev_output = true
97
114
  end
98
- output << result
99
115
  prev_text = true
100
116
  end
101
- else
102
- if scanner.scan(/=/)
103
- if prev_output
104
- output << " << ("
105
- else
106
- output << "\n__output__ << ("
107
- prev_output = true
108
- end
109
- output << scanner.scan_until(/(\r\n|\n|\Z)/)
110
- output << ")"
117
+ output << result.inspect
118
+ elsif scanner.skip(/=/)
119
+ if prev_output
120
+ output << "<<" << ("\n" * (line - flushed)) << "("
111
121
  else
112
- output << "\n"
113
- output << scanner.scan_until(/(\r\n|\n|\Z)/)
114
- prev_output = false
122
+ output << ("\n" * (line - flushed)) << ";__output__<<("
123
+ prev_output = true
115
124
  end
125
+ flushed = line
126
+ prev_text = false
127
+ output << scanner.scan_until(/(?=\r\n|\n|\Z)/) << ")"
128
+ else
129
+ output << ("\n" * (line - flushed)) << ";" << scanner.scan_until(/\r\n|\n|\Z/)
130
+ flushed = line
116
131
  prev_text = false
132
+ prev_output = false
117
133
  end
118
134
  end
119
135
  else # End of file
120
136
  unless scanner.eos?
121
137
  # Add the pending text
122
- if prev_text
123
- output << scanner.rest.inspect
124
- else
138
+ unless prev_text
125
139
  if prev_output
126
- output << " << "
140
+ output << "<<"
127
141
  else
128
- output << "\n__output__ << "
142
+ output << ";__output__<<"
143
+ prev_output = true
129
144
  end
130
- output << scanner.rest.inspect
145
+ prev_text = true
131
146
  end
147
+ output << scanner.rest.inspect
132
148
  end
133
149
  break
134
150
  end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lokar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Zoxc
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-01-05 00:00:00 +01:00
17
+ date: 2010-09-20 00:00:00 +02:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -34,21 +39,27 @@ rdoc_options: []
34
39
  require_paths:
35
40
  - .
36
41
  required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
37
43
  requirements:
38
44
  - - ">="
39
45
  - !ruby/object:Gem::Version
46
+ segments:
47
+ - 1
48
+ - 9
49
+ - 0
40
50
  version: 1.9.0
41
- version:
42
51
  required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
43
53
  requirements:
44
54
  - - ">="
45
55
  - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
46
58
  version: "0"
47
- version:
48
59
  requirements: []
49
60
 
50
61
  rubyforge_project:
51
- rubygems_version: 1.3.5
62
+ rubygems_version: 1.3.7
52
63
  signing_key:
53
64
  specification_version: 3
54
65
  summary: Lokar is a simple fast template engine.