wikicloth 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/Rakefile +20 -31
- data/lib/wikicloth/core_ext.rb +22 -17
- data/lib/wikicloth/lexer.rb +105 -0
- data/lib/wikicloth/parser.rb +5 -5
- data/lib/wikicloth/section.rb +2 -0
- data/lib/wikicloth/token.rb +41 -0
- data/lib/wikicloth/wiki_buffer/html_element.rb +21 -1
- data/lib/wikicloth/wiki_buffer/var.rb +103 -27
- data/lib/wikicloth/wiki_buffer.rb +33 -3
- data/lib/wikicloth/wiki_link_handler.rb +9 -5
- data/lib/wikicloth.rb +6 -3
- data/run_tests.rb +2 -2
- data/test/test_helper.rb +4 -0
- data/test/wiki_cloth_test.rb +121 -4
- metadata +36 -9
- data/lib/wikicloth/calc.citrus +0 -133
- data/lib/wikicloth/math.rb +0 -155
- data/lib/wikicloth/wiki_buffer/template.rb +0 -32
data/README
CHANGED
data/Rakefile
CHANGED
@@ -2,18 +2,12 @@ require 'rake'
|
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/rdoctask'
|
4
4
|
require 'rake/gempackagetask'
|
5
|
-
require 'init'
|
5
|
+
require File.join(File.dirname(__FILE__),'init')
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
require 'bundler'
|
8
|
+
Bundler::GemHelper.install_tasks
|
9
9
|
|
10
|
-
|
11
|
-
Rake::TestTask.new(:test) do |t|
|
12
|
-
t.libs << 'lib'
|
13
|
-
t.libs << 'test'
|
14
|
-
t.pattern = 'test/**/*_test.rb'
|
15
|
-
t.verbose = true
|
16
|
-
end
|
10
|
+
task :default => :test
|
17
11
|
|
18
12
|
desc 'Generate documentation for the wikicloth plugin.'
|
19
13
|
Rake::RDocTask.new(:rdoc) do |rdoc|
|
@@ -24,26 +18,21 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
24
18
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
19
|
end
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
s.platform = Gem::Platform::RUBY
|
34
|
-
s.summary = "An implementation of the mediawiki markup in ruby"
|
35
|
-
s.files = FileList["{lib,tasks}/**/*"].to_a +
|
36
|
-
FileList["sample_documents/*.wiki"].to_a +
|
37
|
-
["init.rb","uninstall.rb","Rakefile","install.rb"]
|
38
|
-
s.require_path = "lib"
|
39
|
-
s.description = File.read("README")
|
40
|
-
s.test_files = FileList["{test}/*.rb"].to_a + ["run_tests.rb"]
|
41
|
-
s.has_rdoc = false
|
42
|
-
s.extra_rdoc_files = ["README","MIT-LICENSE"]
|
43
|
-
s.description = %q{mediawiki parser}
|
44
|
-
s.add_dependency 'builder'
|
45
|
-
s.add_dependency 'expression_parser'
|
21
|
+
find_file = lambda do |name|
|
22
|
+
file_name = lambda {|path| File.join(path, "#{name}.rb")}
|
23
|
+
root = $:.detect do |path|
|
24
|
+
File.exist?(file_name[path])
|
25
|
+
end
|
26
|
+
file_name[root] if root
|
46
27
|
end
|
47
|
-
|
48
|
-
|
28
|
+
|
29
|
+
TEST_LOADER = find_file['rake/rake_test_loader']
|
30
|
+
multiruby = lambda do |glob|
|
31
|
+
system 'multiruby', TEST_LOADER, *Dir.glob(glob)
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::TestTask.new(:test) do |test|
|
35
|
+
test.ruby_opts << "-W"
|
36
|
+
test.pattern = 'test/**/*_test.rb'
|
37
|
+
test.verbose = true
|
49
38
|
end
|
data/lib/wikicloth/core_ext.rb
CHANGED
@@ -1,22 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
if RUBY_VERSION < '1.9'
|
2
|
+
READ_MODE = "r"
|
3
|
+
class Object
|
4
|
+
module InstanceExecHelper; end
|
5
|
+
include InstanceExecHelper
|
6
|
+
def instance_exec(*args, &block)
|
7
|
+
begin
|
8
|
+
old_critical, Thread.critical = Thread.critical, true
|
9
|
+
n = 0
|
10
|
+
n += 1 while respond_to?(mname="__instance_exec#{n}")
|
11
|
+
InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
12
|
+
ensure
|
13
|
+
Thread.critical = old_critical
|
14
|
+
end
|
15
|
+
begin
|
16
|
+
ret = send(mname, *args)
|
17
|
+
ensure
|
18
|
+
InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
|
19
|
+
end
|
20
|
+
ret
|
17
21
|
end
|
18
|
-
ret
|
19
22
|
end
|
23
|
+
else
|
24
|
+
READ_MODE = "r:UTF-8"
|
20
25
|
end
|
21
26
|
|
22
27
|
module Math
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# not actually used by wikicloth atm
|
2
|
+
module WikiCloth
|
3
|
+
|
4
|
+
class Lexer
|
5
|
+
|
6
|
+
def initialize(input)
|
7
|
+
@input = input
|
8
|
+
@return_previous_token = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_next_token
|
12
|
+
if @return_previous_token
|
13
|
+
@return_previous_token = false
|
14
|
+
return @previous_token
|
15
|
+
end
|
16
|
+
|
17
|
+
token = Token.new
|
18
|
+
prepend_input = nil
|
19
|
+
|
20
|
+
case @input
|
21
|
+
when /\A\s+/
|
22
|
+
token.kind = Token::Space
|
23
|
+
when /\A:/
|
24
|
+
token.kind = Token::Colon
|
25
|
+
when /\A([']{2,5})/
|
26
|
+
token.kind = Token::BoldItalic
|
27
|
+
when /\A\n([*]{1,})/
|
28
|
+
token.kind = Token::ListItem
|
29
|
+
when /\A~~~~/
|
30
|
+
token.kind = Token::Signature
|
31
|
+
when /\A<!--/
|
32
|
+
token.kind = Token::BeginComment
|
33
|
+
when /\A-->/
|
34
|
+
token.kind = Token::EndComment
|
35
|
+
when /\A[\w\(\)\.\%;\#\-\/,'&\*~]+/
|
36
|
+
# swallowed bold/italic
|
37
|
+
if $&[-2,2] == "''"
|
38
|
+
prepend_input = "''"
|
39
|
+
token.value = $&[0..-3]
|
40
|
+
elsif $&[-3,3] == "'''"
|
41
|
+
prepend_input = "'''"
|
42
|
+
token.value = $&[0..-4]
|
43
|
+
elsif $&[-5,5] == "'''''"
|
44
|
+
prepend_input = "'''''"
|
45
|
+
token.value = $&[0..-6]
|
46
|
+
# accidently swallowed closing comment
|
47
|
+
elsif $&[-2,2] == "--" && $'[0,1] == '>'
|
48
|
+
prepend_input = '--'
|
49
|
+
token.value = $&[0..-3]
|
50
|
+
else
|
51
|
+
token.value = $&
|
52
|
+
end
|
53
|
+
token.kind = Token::Word
|
54
|
+
when /\A\{\|/
|
55
|
+
token.kind = Token::BeginTable
|
56
|
+
when /\A\|\}/
|
57
|
+
token.kind = Token::EndTable
|
58
|
+
when /\A\|/
|
59
|
+
token.kind = Token::Pipe
|
60
|
+
when /\A=/
|
61
|
+
token.kind = Token::Equals
|
62
|
+
when /\A"/
|
63
|
+
token.kind = Token::Quote
|
64
|
+
when /\A\n/
|
65
|
+
token.kind = Token::NewLine
|
66
|
+
when /\A\{\{/
|
67
|
+
token.kind = Token::OpenRes
|
68
|
+
when /\A\}\}/
|
69
|
+
token.kind = Token::CloseRes
|
70
|
+
when /\A\[\[/
|
71
|
+
token.kind = Token::OpenLink
|
72
|
+
token.value = $&
|
73
|
+
when /\A\]\]/
|
74
|
+
token.kind = Token::CloseLink
|
75
|
+
token.value = $&
|
76
|
+
when /\A\[/
|
77
|
+
token.kind = Token::OpenLink
|
78
|
+
token.kind = $&
|
79
|
+
when /\A\]/
|
80
|
+
token.kind = Token::CloseLink
|
81
|
+
token.kind = $&
|
82
|
+
when /\A\<\s*\//
|
83
|
+
token.kind = Token::OpenElement
|
84
|
+
when /\A\</
|
85
|
+
token.kind = Token::OpenElement
|
86
|
+
when /\A\>/
|
87
|
+
token.kind = Token::CloseElement
|
88
|
+
when ''
|
89
|
+
token.kind = Token::End
|
90
|
+
end
|
91
|
+
token.value ||= $&
|
92
|
+
|
93
|
+
raise "Unknown token #{@input}" if token.unknown?
|
94
|
+
@input = "#{prepend_input}#{$'}"
|
95
|
+
|
96
|
+
@previous_token = token
|
97
|
+
token
|
98
|
+
end
|
99
|
+
|
100
|
+
def revert
|
101
|
+
@return_previous_token = true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
data/lib/wikicloth/parser.rb
CHANGED
@@ -80,21 +80,21 @@ module WikiCloth
|
|
80
80
|
|
81
81
|
# Replace a section, along with any sub-section in the document
|
82
82
|
def put_section(id,data)
|
83
|
-
data = @wikicloth.sections.
|
83
|
+
data = @wikicloth.sections.collect { |s| s.wikitext({ :replace => { id => data.last(1) == "\n" ? data : "#{data}\n" } }) }.join
|
84
84
|
@wikicloth = WikiCloth.new(:data => data, :link_handler => self, :params => @params)
|
85
85
|
end
|
86
86
|
|
87
87
|
# Get the section, along with any sub-section of the document
|
88
88
|
def get_section(id)
|
89
|
-
@wikicloth.sections.
|
89
|
+
@wikicloth.sections.collect { |s| s.get_section(id) }.join
|
90
90
|
end
|
91
91
|
|
92
92
|
def sections
|
93
93
|
@wikicloth.sections
|
94
94
|
end
|
95
95
|
|
96
|
-
def to_html
|
97
|
-
@wikicloth.to_html
|
96
|
+
def to_html(opts = {})
|
97
|
+
@wikicloth.to_html(opts)
|
98
98
|
end
|
99
99
|
|
100
100
|
def to_wiki
|
@@ -102,7 +102,7 @@ module WikiCloth
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def to_wikitext
|
105
|
-
@wikicloth.sections.
|
105
|
+
@wikicloth.sections.collect { |s| s.wikitext() }.join
|
106
106
|
end
|
107
107
|
|
108
108
|
end
|
data/lib/wikicloth/section.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# not actually used by wikicloth atm
|
2
|
+
module WikiCloth
|
3
|
+
|
4
|
+
class Token
|
5
|
+
OpenRes = 1
|
6
|
+
CloseRes = 2
|
7
|
+
OpenLink = 3
|
8
|
+
CloseLink = 4
|
9
|
+
Heading = 5
|
10
|
+
Word = 6
|
11
|
+
NewLine = 7
|
12
|
+
OpenElement = 8
|
13
|
+
CloseElement = 9
|
14
|
+
Equals = 10
|
15
|
+
Quote = 11
|
16
|
+
BeginComment = 12
|
17
|
+
EndComment = 13
|
18
|
+
BeginTable = 14
|
19
|
+
EndTable = 15
|
20
|
+
Pipe = 16
|
21
|
+
BoldItalic = 17
|
22
|
+
ListItem = 18
|
23
|
+
Signature = 19
|
24
|
+
Space = 20
|
25
|
+
Colon = 21
|
26
|
+
End = 22
|
27
|
+
|
28
|
+
attr_accessor :kind
|
29
|
+
attr_accessor :value
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@kind = nil
|
33
|
+
@value = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def unknown?
|
37
|
+
@kind.nil?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -20,7 +20,19 @@ class WikiBuffer::HTMLElement < WikiBuffer
|
|
20
20
|
@in_quotes = false
|
21
21
|
@in_single_quotes = false
|
22
22
|
@start_tag = 1
|
23
|
-
@tag_check = check
|
23
|
+
@tag_check = check
|
24
|
+
end
|
25
|
+
|
26
|
+
def debug
|
27
|
+
case self.element_name
|
28
|
+
when "template"
|
29
|
+
self.get_param("__name")
|
30
|
+
else
|
31
|
+
ret = self.element_name
|
32
|
+
tmp = self.get_param("id")
|
33
|
+
ret += tmp.nil? ? "" : "##{tmp}"
|
34
|
+
ret
|
35
|
+
end
|
24
36
|
end
|
25
37
|
|
26
38
|
def run_globals?
|
@@ -42,6 +54,12 @@ class WikiBuffer::HTMLElement < WikiBuffer
|
|
42
54
|
|
43
55
|
lhandler = @options[:link_handler]
|
44
56
|
case self.element_name
|
57
|
+
when "template"
|
58
|
+
return self.element_content
|
59
|
+
when "noinclude"
|
60
|
+
return self.in_template? ? "" : self.element_content
|
61
|
+
when "includeonly"
|
62
|
+
return self.in_template? ? self.element_content : ""
|
45
63
|
when "ref"
|
46
64
|
self.element_name = "sup"
|
47
65
|
named_ref = self.name_attribute
|
@@ -69,6 +87,8 @@ class WikiBuffer::HTMLElement < WikiBuffer
|
|
69
87
|
}.to_s
|
70
88
|
when "nowiki"
|
71
89
|
return self.element_content
|
90
|
+
when "a"
|
91
|
+
return @options[:link_handler].external_link(self.element_attributes['href'], self.element_content)
|
72
92
|
end
|
73
93
|
|
74
94
|
tmp = elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content }
|
@@ -8,10 +8,30 @@ class WikiBuffer::Var < WikiBuffer
|
|
8
8
|
super(data,options)
|
9
9
|
self.buffer_type = "var"
|
10
10
|
@in_quotes = false
|
11
|
+
@tag_start = true
|
12
|
+
@tag_size = 2
|
13
|
+
@close_size = 2
|
14
|
+
@fname = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def tag_size
|
18
|
+
@tag_size
|
19
|
+
end
|
20
|
+
|
21
|
+
def tag_size=(val)
|
22
|
+
@tag_size = val
|
11
23
|
end
|
12
24
|
|
13
25
|
def skip_html?
|
14
|
-
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def tag_start
|
30
|
+
@tag_start
|
31
|
+
end
|
32
|
+
|
33
|
+
def tag_start=(val)
|
34
|
+
@tag_start = val
|
15
35
|
end
|
16
36
|
|
17
37
|
def function_name
|
@@ -23,27 +43,35 @@ class WikiBuffer::Var < WikiBuffer
|
|
23
43
|
ret = default_functions(function_name,params.collect { |p| p.strip })
|
24
44
|
ret ||= @options[:link_handler].function(function_name, params.collect { |p| p.strip })
|
25
45
|
ret.to_s
|
46
|
+
elsif self.is_param?
|
47
|
+
ret = nil
|
48
|
+
@options[:buffer].buffers.reverse.each do |b|
|
49
|
+
ret = b.get_param(params[0],params[1]) if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template"
|
50
|
+
end
|
51
|
+
ret.to_s
|
26
52
|
else
|
27
|
-
ret = @options[:link_handler].include_resource("#{params[0]}".strip,params[1..-1])
|
28
|
-
# template params
|
29
|
-
ret = ret.to_s.gsub(/\{\{\{\s*([A-Za-z0-9]+)+(|\|+([^}]+))\s*\}\}\}/) { |match| get_param($1.strip,$3.to_s.strip) }
|
30
53
|
# put template at beginning of buffer
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
54
|
+
template_stack = @options[:buffer].buffers.collect { |b| b.get_param("__name") if b.instance_of?(WikiBuffer::HTMLElement) &&
|
55
|
+
b.element_name == "template" }.compact
|
56
|
+
if template_stack.last == params[0]
|
57
|
+
debug_tree = @options[:buffer].buffers.collect { |b| b.debug }.join("-->")
|
58
|
+
"<span class=\"error\">Template loop detected: {{#{debug_tree}}}</span>"
|
59
|
+
else
|
60
|
+
ret = @options[:link_handler].include_resource("#{params[0]}".strip,params[1..-1]).to_s
|
61
|
+
ret.gsub!(/<!--(.|\s)*?-->/,"")
|
62
|
+
count = 0
|
63
|
+
tag_attr = self.params[1..-1].collect { |p|
|
64
|
+
if p.instance_of?(Hash)
|
65
|
+
"#{p[:name]}=\"#{p[:value]}\""
|
66
|
+
else
|
67
|
+
count += 1
|
68
|
+
"#{count}=\"#{p}\""
|
69
|
+
end
|
70
|
+
}.join(" ")
|
71
|
+
self.data = ret.blank? ? "" : "<template __name=\"#{params[0]}\" #{tag_attr}>#{ret}</template>"
|
72
|
+
""
|
73
|
+
end
|
45
74
|
end
|
46
|
-
ret.nil? ? default : ret
|
47
75
|
end
|
48
76
|
|
49
77
|
def default_functions(name,params)
|
@@ -51,11 +79,19 @@ class WikiBuffer::Var < WikiBuffer
|
|
51
79
|
when "#if"
|
52
80
|
params.first.blank? ? params[2] : params[1]
|
53
81
|
when "#switch"
|
54
|
-
params.
|
55
|
-
|
56
|
-
|
82
|
+
match = params.first
|
83
|
+
default = nil
|
84
|
+
for p in params[1..-1]
|
85
|
+
temp = p.split("=")
|
86
|
+
if temp.length == 1 && p == params.last
|
87
|
+
return p
|
88
|
+
elsif temp.instance_of?(Array) && temp.length > 1
|
89
|
+
test = temp.first.strip
|
90
|
+
default = temp[1].strip if test == "#default"
|
91
|
+
return temp[1].strip if test == match
|
92
|
+
end
|
57
93
|
end
|
58
|
-
|
94
|
+
default.nil? ? "" : default
|
59
95
|
when "#expr"
|
60
96
|
begin
|
61
97
|
ExpressionParser::Parser.new.parse(params.first)
|
@@ -96,9 +132,32 @@ class WikiBuffer::Var < WikiBuffer
|
|
96
132
|
params.first[0,1].downcase + params.first[1,-1]
|
97
133
|
when "plural"
|
98
134
|
params.first.to_i > 1 ? params[1] : params[2]
|
135
|
+
when "debug"
|
136
|
+
ret = nil
|
137
|
+
case params.first
|
138
|
+
when "param"
|
139
|
+
@options[:buffer].buffers.reverse.each do |b|
|
140
|
+
if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template"
|
141
|
+
ret = b.get_param(params[1])
|
142
|
+
end
|
143
|
+
end
|
144
|
+
ret
|
145
|
+
when "buffer"
|
146
|
+
ret = "<pre>"
|
147
|
+
buffer = @options[:buffer].buffers
|
148
|
+
buffer.each do |b|
|
149
|
+
ret += " --- #{b.class}"
|
150
|
+
ret += b.instance_of?(WikiBuffer::HTMLElement) ? " -- #{b.element_name}\n" : " -- #{b.data}\n"
|
151
|
+
end
|
152
|
+
"#{ret}</pre>"
|
153
|
+
end
|
99
154
|
end
|
100
155
|
end
|
101
156
|
|
157
|
+
def is_param?
|
158
|
+
@tag_size == 3 ? true : false
|
159
|
+
end
|
160
|
+
|
102
161
|
def is_function?
|
103
162
|
self.function_name.nil? || self.function_name.blank? ? false : true
|
104
163
|
end
|
@@ -129,13 +188,30 @@ class WikiBuffer::Var < WikiBuffer
|
|
129
188
|
|
130
189
|
# End of a template, variable, or function
|
131
190
|
when current_char == '}' && previous_char == '}'
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
191
|
+
if @close_size == @tag_size
|
192
|
+
self.data.chop!
|
193
|
+
self.current_param = self.data
|
194
|
+
self.data = ""
|
195
|
+
return false
|
196
|
+
else
|
197
|
+
@close_size += 1
|
198
|
+
end
|
136
199
|
|
137
200
|
else
|
138
201
|
self.data += current_char
|
202
|
+
if @tag_start
|
203
|
+
# FIXME: template params and templates colliding
|
204
|
+
if @tag_size > 3
|
205
|
+
if @tag_size == 5
|
206
|
+
@options[:buffer].buffers << WikiBuffer::Var.new(self.data,@options)
|
207
|
+
@options[:buffer].buffers[-1].tag_start = false
|
208
|
+
self.data = ""
|
209
|
+
@tag_size = 3
|
210
|
+
return true
|
211
|
+
end
|
212
|
+
end
|
213
|
+
@tag_start = false
|
214
|
+
end
|
139
215
|
end
|
140
216
|
|
141
217
|
return true
|
@@ -3,18 +3,29 @@ class WikiBuffer
|
|
3
3
|
|
4
4
|
def initialize(data="",options={})
|
5
5
|
@options = options
|
6
|
+
@options[:buffer] ||= self
|
6
7
|
self.data = data
|
7
8
|
self.buffer_type = nil
|
8
9
|
@section_count = 0
|
9
10
|
@buffers ||= [ ]
|
10
11
|
@buffers << self
|
11
12
|
@list_data = []
|
13
|
+
@check_new_tag = false
|
14
|
+
@indent = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def debug
|
18
|
+
self.params[0]
|
12
19
|
end
|
13
20
|
|
14
21
|
def run_globals?
|
15
22
|
true
|
16
23
|
end
|
17
24
|
|
25
|
+
def buffers
|
26
|
+
@buffers
|
27
|
+
end
|
28
|
+
|
18
29
|
def skip_html?
|
19
30
|
false
|
20
31
|
end
|
@@ -27,6 +38,21 @@ class WikiBuffer
|
|
27
38
|
@params ||= [ "" ]
|
28
39
|
end
|
29
40
|
|
41
|
+
def get_param(name,default=nil)
|
42
|
+
ret = nil
|
43
|
+
self.params.each do |param|
|
44
|
+
ret = param[:value] if param.instance_of?(Hash) && param[:name] == name
|
45
|
+
end
|
46
|
+
ret.nil? ? default : ret
|
47
|
+
end
|
48
|
+
|
49
|
+
def in_template?
|
50
|
+
@options[:buffer].buffers.each do |b|
|
51
|
+
return true if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template"
|
52
|
+
end
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
30
56
|
def buffer_type
|
31
57
|
@buffer_type
|
32
58
|
end
|
@@ -68,8 +94,12 @@ class WikiBuffer
|
|
68
94
|
case
|
69
95
|
# start variable
|
70
96
|
when previous_char == '{' && current_char == '{'
|
71
|
-
@buffers[-1].
|
72
|
-
|
97
|
+
if @buffers[-1].instance_of?(WikiBuffer::Var) && @buffers[-1].tag_start == true
|
98
|
+
@buffers[-1].tag_size += 1
|
99
|
+
else
|
100
|
+
@buffers[-1].data.chop!
|
101
|
+
@buffers << WikiBuffer::Var.new("",@options)
|
102
|
+
end
|
73
103
|
return true
|
74
104
|
|
75
105
|
# start link
|
@@ -102,7 +132,7 @@ class WikiBuffer
|
|
102
132
|
@buffers[-1].data += tmp.to_s
|
103
133
|
# any data left in the buffer we feed into the parent
|
104
134
|
unless tmp.data.blank?
|
105
|
-
tmp.data.each_char { |
|
135
|
+
tmp.data.each_char { |x| self.add_char(x) }
|
106
136
|
end
|
107
137
|
end
|
108
138
|
end
|
@@ -45,6 +45,10 @@ class WikiLinkHandler
|
|
45
45
|
@external_links ||= []
|
46
46
|
end
|
47
47
|
|
48
|
+
def internal_links
|
49
|
+
@internal_links ||= []
|
50
|
+
end
|
51
|
+
|
48
52
|
def find_reference_by_name(n)
|
49
53
|
references.each { |r| return r if !r[:name].nil? && r[:name].strip == n }
|
50
54
|
return nil
|
@@ -72,6 +76,10 @@ class WikiLinkHandler
|
|
72
76
|
@external_links = val
|
73
77
|
end
|
74
78
|
|
79
|
+
def internal_links=(val)
|
80
|
+
@internal_links = val
|
81
|
+
end
|
82
|
+
|
75
83
|
def url_for(page)
|
76
84
|
"javascript:void(0)"
|
77
85
|
end
|
@@ -81,6 +89,7 @@ class WikiLinkHandler
|
|
81
89
|
end
|
82
90
|
|
83
91
|
def link_for(page, text)
|
92
|
+
self.internal_links << page
|
84
93
|
ltitle = !text.nil? && text.blank? ? self.pipe_trick(page) : text
|
85
94
|
ltitle = page if text.nil?
|
86
95
|
elem.a(link_attributes_for(page)) { |x| x << ltitle.strip }
|
@@ -90,11 +99,6 @@ class WikiLinkHandler
|
|
90
99
|
if self.params.has_key?(resource)
|
91
100
|
self.params[resource]
|
92
101
|
else
|
93
|
-
# FIXME: hack to keep template loops from raising havoc
|
94
|
-
@include_count ||= 0
|
95
|
-
@include_count += 1
|
96
|
-
raise "Page reached maximum number of includes [1000] (possible template loop?)" if @include_count > 100
|
97
|
-
|
98
102
|
ret = template(resource)
|
99
103
|
unless ret.nil?
|
100
104
|
@included_templates ||= {}
|
data/lib/wikicloth.rb
CHANGED
@@ -4,17 +4,19 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "wiki_b
|
|
4
4
|
require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "wiki_link_handler")
|
5
5
|
require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "parser")
|
6
6
|
require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "section")
|
7
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "token")
|
8
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "lexer")
|
7
9
|
String.send(:include, ExtendedString)
|
8
10
|
|
9
11
|
module WikiCloth
|
10
12
|
|
11
|
-
VERSION = "0.
|
13
|
+
VERSION = "0.6.0"
|
12
14
|
|
13
15
|
class WikiCloth
|
14
16
|
|
15
17
|
def initialize(opt={})
|
16
18
|
self.options[:link_handler] = opt[:link_handler] unless opt[:link_handler].nil?
|
17
|
-
self.load(opt[:data],opt[:params]) unless opt[:data].nil?
|
19
|
+
self.load(opt[:data],opt[:params]) unless opt[:data].nil?
|
18
20
|
end
|
19
21
|
|
20
22
|
def load(data,p={})
|
@@ -55,8 +57,9 @@ module WikiCloth
|
|
55
57
|
self.params.merge!({ 'WIKI_VERSION' => ::WikiCloth::VERSION })
|
56
58
|
self.options = { :output => :html, :link_handler => self.link_handler, :params => self.params, :sections => self.sections }.merge(opt)
|
57
59
|
self.options[:link_handler].params = options[:params]
|
58
|
-
data = self.sections.
|
60
|
+
data = self.sections.collect { |s| s.render(self.options) }.join
|
59
61
|
data.gsub!(/<!--(.|\s)*?-->/,"")
|
62
|
+
data << "\n" if data.last(1) != "\n"
|
60
63
|
buffer = WikiBuffer.new("",options)
|
61
64
|
data.each_char { |c| buffer.add_char(c) }
|
62
65
|
buffer.to_s
|
data/run_tests.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'init'
|
1
|
+
require File.join(File.dirname(__FILE__),'init')
|
2
2
|
include WikiCloth
|
3
3
|
|
4
4
|
class WikiParser < WikiCloth::Parser
|
@@ -37,7 +37,7 @@ Dir.glob("sample_documents/*.wiki").each do |x|
|
|
37
37
|
|
38
38
|
start_time = Time.now
|
39
39
|
out_name = "#{x}.html"
|
40
|
-
data = File.open(x) { |x| x.read }
|
40
|
+
data = File.open(x, READ_MODE) { |x| x.read }
|
41
41
|
|
42
42
|
tmp = WikiCloth::Parser.new({
|
43
43
|
:data => data,
|
data/test/test_helper.rb
CHANGED
data/test/wiki_cloth_test.rb
CHANGED
@@ -1,8 +1,125 @@
|
|
1
|
-
require 'test_helper'
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'test_helper'))
|
2
|
+
|
3
|
+
class WikiParser < WikiCloth::Parser
|
4
|
+
template do |template|
|
5
|
+
case template
|
6
|
+
when "noinclude"
|
7
|
+
"<noinclude>hello world</noinclude><includeonly>testing</includeonly>"
|
8
|
+
when "test"
|
9
|
+
"busted"
|
10
|
+
when "nowiki"
|
11
|
+
"hello world"
|
12
|
+
when "testparams"
|
13
|
+
"{{{def|hello world}}} {{{1}}} {{{test}}} {{{nested|{{{2}}}}}}"
|
14
|
+
when "moreparamtest"
|
15
|
+
"{{{{{test|bla}}|wtf}}}"
|
16
|
+
when "loop"
|
17
|
+
"{{loop}}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
external_link do |url,text|
|
21
|
+
"<a href=\"#{url}\" target=\"_blank\" class=\"exlink\">#{text.blank? ? url : text}</a>"
|
22
|
+
end
|
23
|
+
end
|
2
24
|
|
3
25
|
class WikiClothTest < ActiveSupport::TestCase
|
4
|
-
|
5
|
-
test "
|
6
|
-
|
26
|
+
|
27
|
+
test "links and references" do
|
28
|
+
wiki = WikiCloth::Parser.new(:data => File.open(File.join(File.dirname(__FILE__), '../sample_documents/george_washington.wiki'), READ_MODE) { |f| f.read })
|
29
|
+
data = wiki.to_html
|
30
|
+
assert wiki.external_links.size == 62
|
31
|
+
assert wiki.references.size == 76
|
32
|
+
assert wiki.internal_links.size == 560
|
33
|
+
end
|
34
|
+
|
35
|
+
test "template params" do
|
36
|
+
wiki = WikiParser.new(:data => "{{testparams|test|test=bla|it worked|bla=whoo}}\n")
|
37
|
+
data = wiki.to_html
|
38
|
+
assert data =~ /hello world/
|
39
|
+
assert data =~ /test/
|
40
|
+
assert data =~ /bla/
|
41
|
+
assert data =~ /it worked/ # nested default param
|
42
|
+
|
43
|
+
wiki = WikiParser.new(:data => "{{moreparamtest|p=othervar}}")
|
44
|
+
data = wiki.to_html
|
45
|
+
assert data =~ /wtf/
|
46
|
+
|
47
|
+
wiki = WikiParser.new(:data => "{{moreparamtest|p=othervar|busted=whoo}}")
|
48
|
+
data = wiki.to_html
|
49
|
+
assert data =~ /whoo/
|
50
|
+
end
|
51
|
+
|
52
|
+
test "horizontal rule" do
|
53
|
+
wiki = WikiParser.new(:data => "----\n")
|
54
|
+
data = wiki.to_html
|
55
|
+
assert data =~ /hr/
|
56
|
+
end
|
57
|
+
|
58
|
+
test "template loops" do
|
59
|
+
wiki = WikiParser.new(:data => "{{#iferror:{{loop}}|loop detected|wtf}}")
|
60
|
+
data = wiki.to_html
|
61
|
+
assert data =~ /loop detected/
|
62
|
+
end
|
63
|
+
|
64
|
+
test "input with no newline" do
|
65
|
+
wiki = WikiParser.new(:data => "{{test}}")
|
66
|
+
data = wiki.to_html
|
67
|
+
assert data =~ /busted/
|
7
68
|
end
|
69
|
+
|
70
|
+
test "lists" do
|
71
|
+
wiki = WikiParser.new(:data => "* item 1\n* item 2\n* item 3\n")
|
72
|
+
data = wiki.to_html
|
73
|
+
assert data =~ /ul/
|
74
|
+
count = 0
|
75
|
+
# should == 6.. 3 <li>'s and 3 </li>'s
|
76
|
+
data.gsub(/li/) { |ret|
|
77
|
+
count += 1
|
78
|
+
ret
|
79
|
+
}
|
80
|
+
assert count == 6
|
81
|
+
end
|
82
|
+
|
83
|
+
test "noinclude and includeonly tags" do
|
84
|
+
wiki = WikiParser.new(:data => "<noinclude>main page</noinclude><includeonly>never seen</includeonly>{{noinclude}}\n")
|
85
|
+
data = wiki.to_html
|
86
|
+
assert data =~ /testing/
|
87
|
+
assert data =~ /main page/
|
88
|
+
assert !(data =~ /never seen/)
|
89
|
+
assert !(data =~ /hello world/)
|
90
|
+
end
|
91
|
+
|
92
|
+
test "bold/italics" do
|
93
|
+
wiki = WikiParser.new(:data => "test ''testing'' '''123''' '''''echo'''''\n")
|
94
|
+
data = wiki.to_html
|
95
|
+
assert data =~ /<i>testing<\/i>/
|
96
|
+
assert data =~ /<b>123<\/b>/
|
97
|
+
assert data =~ /<b><i>echo<\/i><\/b>/
|
98
|
+
end
|
99
|
+
|
100
|
+
test "sanitize html" do
|
101
|
+
wiki = WikiParser.new(:data => "<script type=\"text/javascript\" src=\"bla.js\"></script>\n<a href=\"test.html\" onmouseover=\"alert('hello world');\">test</a>\n")
|
102
|
+
data = wiki.to_html
|
103
|
+
assert !(data =~ /<script/)
|
104
|
+
assert !(data =~ /onmouseover/)
|
105
|
+
assert data =~ /exlink/
|
106
|
+
end
|
107
|
+
|
108
|
+
test "nowiki and code tags" do
|
109
|
+
wiki = WikiParser.new(:data => "<nowiki>{{test}}</nowiki><code>{{test}}</code>{{nowiki}}\n")
|
110
|
+
data = wiki.to_html
|
111
|
+
assert !(data =~ /busted/)
|
112
|
+
assert data =~ /hello world/
|
113
|
+
end
|
114
|
+
|
115
|
+
test "disable edit stuff" do
|
116
|
+
wiki = WikiParser.new(:data => "= Hallo =")
|
117
|
+
data = wiki.to_html
|
118
|
+
assert_equal data, "<p>\n<h1><span class=\"editsection\">[<a href=\"?section=Hallo\" target=\"_blank\" class=\"exlink\">edit</a>]</span> <span class=\"mw-headline\" id=\"Hallo\">Hallo</span></h1>\n</p>"
|
119
|
+
|
120
|
+
data = wiki.to_html(:noedit => true)
|
121
|
+
assert_equal data, "<p>\n<h1> <span class=\"mw-headline\" id=\"Hallo\">Hallo</span></h1>\n</p>"
|
122
|
+
|
123
|
+
end
|
124
|
+
|
8
125
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wikicloth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.6.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- David Ricciardi
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-12-23 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -46,6 +46,34 @@ dependencies:
|
|
46
46
|
version: "0"
|
47
47
|
type: :runtime
|
48
48
|
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: test-unit
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: activesupport
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
49
77
|
description: mediawiki parser
|
50
78
|
email: nricciar@gmail.com
|
51
79
|
executables: []
|
@@ -57,14 +85,13 @@ extra_rdoc_files:
|
|
57
85
|
- MIT-LICENSE
|
58
86
|
files:
|
59
87
|
- lib/wikicloth.rb
|
60
|
-
- lib/wikicloth/calc.citrus
|
61
|
-
- lib/wikicloth/math.rb
|
62
88
|
- lib/wikicloth/core_ext.rb
|
63
89
|
- lib/wikicloth/wiki_buffer/html_element.rb
|
64
90
|
- lib/wikicloth/wiki_buffer/var.rb
|
65
91
|
- lib/wikicloth/wiki_buffer/table.rb
|
66
|
-
- lib/wikicloth/wiki_buffer/template.rb
|
67
92
|
- lib/wikicloth/wiki_buffer/link.rb
|
93
|
+
- lib/wikicloth/token.rb
|
94
|
+
- lib/wikicloth/lexer.rb
|
68
95
|
- lib/wikicloth/parser.rb
|
69
96
|
- lib/wikicloth/section.rb
|
70
97
|
- lib/wikicloth/wiki_link_handler.rb
|
@@ -84,11 +111,11 @@ files:
|
|
84
111
|
- uninstall.rb
|
85
112
|
- Rakefile
|
86
113
|
- install.rb
|
114
|
+
- README
|
115
|
+
- MIT-LICENSE
|
87
116
|
- test/wiki_cloth_test.rb
|
88
117
|
- test/test_helper.rb
|
89
118
|
- run_tests.rb
|
90
|
-
- README
|
91
|
-
- MIT-LICENSE
|
92
119
|
has_rdoc: true
|
93
120
|
homepage: http://github.com/nricciar/wikicloth
|
94
121
|
licenses: []
|
data/lib/wikicloth/calc.citrus
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
# A grammar for mathematical formulas that apply basic mathematical operations
|
2
|
-
# to all numbers, respecting operator precedence and grouping of expressions
|
3
|
-
# while ignoring whitespace.
|
4
|
-
#
|
5
|
-
# An identical grammar that is written using pure Ruby can be found in calc.rb.
|
6
|
-
grammar Calc
|
7
|
-
|
8
|
-
## Hierarchy
|
9
|
-
|
10
|
-
rule term
|
11
|
-
additive | factor
|
12
|
-
end
|
13
|
-
|
14
|
-
rule additive
|
15
|
-
(factor additive_operator term) {
|
16
|
-
def value
|
17
|
-
additive_operator.apply(factor.value, term.value)
|
18
|
-
end
|
19
|
-
}
|
20
|
-
end
|
21
|
-
|
22
|
-
rule factor
|
23
|
-
multiplicative | prefix
|
24
|
-
end
|
25
|
-
|
26
|
-
rule multiplicative
|
27
|
-
(prefix multiplicative_operator factor) {
|
28
|
-
def value
|
29
|
-
multiplicative_operator.apply(prefix.value, factor.value)
|
30
|
-
end
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
rule prefix
|
35
|
-
prefixed | exponent
|
36
|
-
end
|
37
|
-
|
38
|
-
rule prefixed
|
39
|
-
(unary_operator prefix) {
|
40
|
-
def value
|
41
|
-
unary_operator.apply(prefix.value)
|
42
|
-
end
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
rule exponent
|
47
|
-
exponential | primary
|
48
|
-
end
|
49
|
-
|
50
|
-
rule exponential
|
51
|
-
(primary exponential_operator exponent) {
|
52
|
-
def value
|
53
|
-
exponential_operator.apply(primary.value, exponent.value)
|
54
|
-
end
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
|
-
rule primary
|
59
|
-
group | number
|
60
|
-
end
|
61
|
-
|
62
|
-
rule group
|
63
|
-
(lparen term rparen) {
|
64
|
-
def value
|
65
|
-
term.value
|
66
|
-
end
|
67
|
-
}
|
68
|
-
end
|
69
|
-
|
70
|
-
## Syntax
|
71
|
-
|
72
|
-
rule number
|
73
|
-
float | integer
|
74
|
-
end
|
75
|
-
|
76
|
-
rule float
|
77
|
-
(digits '.' digits space) {
|
78
|
-
def value
|
79
|
-
text.strip.to_f
|
80
|
-
end
|
81
|
-
}
|
82
|
-
end
|
83
|
-
|
84
|
-
rule integer
|
85
|
-
(digits space) {
|
86
|
-
def value
|
87
|
-
text.strip.to_i
|
88
|
-
end
|
89
|
-
}
|
90
|
-
end
|
91
|
-
|
92
|
-
rule digits
|
93
|
-
[0-9]+ ('_' [0-9]+)*
|
94
|
-
end
|
95
|
-
|
96
|
-
rule additive_operator
|
97
|
-
(('+' | '-') space) {
|
98
|
-
def apply(n1, n2)
|
99
|
-
n1.send(text.strip, n2)
|
100
|
-
end
|
101
|
-
}
|
102
|
-
end
|
103
|
-
|
104
|
-
rule multiplicative_operator
|
105
|
-
(('*' | '/' | '%') space) {
|
106
|
-
def apply(n1, n2)
|
107
|
-
n1.send(text.strip, n2)
|
108
|
-
end
|
109
|
-
}
|
110
|
-
end
|
111
|
-
|
112
|
-
rule exponential_operator
|
113
|
-
('**' space) {
|
114
|
-
def apply(n1, n2)
|
115
|
-
n1 ** n2
|
116
|
-
end
|
117
|
-
}
|
118
|
-
end
|
119
|
-
|
120
|
-
rule unary_operator
|
121
|
-
(('~' | '+' | '-') space) {
|
122
|
-
def apply(n)
|
123
|
-
op = text.strip
|
124
|
-
# Unary + and - require an @.
|
125
|
-
n.send(op == '~' ? op : '%s@' % op)
|
126
|
-
end
|
127
|
-
}
|
128
|
-
end
|
129
|
-
|
130
|
-
rule lparen '(' space end
|
131
|
-
rule rparen ')' space end
|
132
|
-
rule space [ \t\n\r]* end
|
133
|
-
end
|
data/lib/wikicloth/math.rb
DELETED
@@ -1,155 +0,0 @@
|
|
1
|
-
# The following code taken from http://lukaszwrobel.pl/blog/math-parser-part-3-implementation
|
2
|
-
module WikiCloth
|
3
|
-
|
4
|
-
class Token
|
5
|
-
Plus = 0
|
6
|
-
Minus = 1
|
7
|
-
Multiply = 2
|
8
|
-
Divide = 3
|
9
|
-
|
10
|
-
Number = 4
|
11
|
-
|
12
|
-
LParen = 5
|
13
|
-
RParen = 6
|
14
|
-
|
15
|
-
End = 7
|
16
|
-
|
17
|
-
attr_accessor :kind
|
18
|
-
attr_accessor :value
|
19
|
-
|
20
|
-
def initialize
|
21
|
-
@kind = nil
|
22
|
-
@value = nil
|
23
|
-
end
|
24
|
-
|
25
|
-
def unknown?
|
26
|
-
@kind.nil?
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class Lexer
|
31
|
-
def initialize(input)
|
32
|
-
@input = input
|
33
|
-
@return_previous_token = false
|
34
|
-
end
|
35
|
-
|
36
|
-
def get_next_token
|
37
|
-
if @return_previous_token
|
38
|
-
@return_previous_token = false
|
39
|
-
return @previous_token
|
40
|
-
end
|
41
|
-
|
42
|
-
token = Token.new
|
43
|
-
|
44
|
-
@input.lstrip!
|
45
|
-
|
46
|
-
case @input
|
47
|
-
when /\A\+/ then
|
48
|
-
token.kind = Token::Plus
|
49
|
-
when /\A-/ then
|
50
|
-
token.kind = Token::Minus
|
51
|
-
when /\A\*/ then
|
52
|
-
token.kind = Token::Multiply
|
53
|
-
when /\A\// then
|
54
|
-
token.kind = Token::Divide
|
55
|
-
when /\A\d+(\.\d+)?/
|
56
|
-
token.kind = Token::Number
|
57
|
-
token.value = $&.to_f
|
58
|
-
when /\A\(/
|
59
|
-
token.kind = Token::LParen
|
60
|
-
when /\A\)/
|
61
|
-
token.kind = Token::RParen
|
62
|
-
when ''
|
63
|
-
token.kind = Token::End
|
64
|
-
end
|
65
|
-
|
66
|
-
raise 'Unknown token' if token.unknown?
|
67
|
-
@input = $'
|
68
|
-
|
69
|
-
@previous_token = token
|
70
|
-
token
|
71
|
-
end
|
72
|
-
|
73
|
-
def revert
|
74
|
-
@return_previous_token = true
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class MathParser
|
79
|
-
def parse(input)
|
80
|
-
@lexer = Lexer.new(input)
|
81
|
-
|
82
|
-
expression_value = expression
|
83
|
-
|
84
|
-
token = @lexer.get_next_token
|
85
|
-
if token.kind == Token::End
|
86
|
-
expression_value
|
87
|
-
else
|
88
|
-
raise 'End expected'
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
protected
|
93
|
-
def expression
|
94
|
-
component1 = factor
|
95
|
-
|
96
|
-
additive_operators = [Token::Plus, Token::Minus]
|
97
|
-
|
98
|
-
token = @lexer.get_next_token
|
99
|
-
while additive_operators.include?(token.kind)
|
100
|
-
component2 = factor
|
101
|
-
|
102
|
-
if token.kind == Token::Plus
|
103
|
-
component1 += component2
|
104
|
-
else
|
105
|
-
component1 -= component2
|
106
|
-
end
|
107
|
-
|
108
|
-
token = @lexer.get_next_token
|
109
|
-
end
|
110
|
-
@lexer.revert
|
111
|
-
|
112
|
-
component1
|
113
|
-
end
|
114
|
-
|
115
|
-
def factor
|
116
|
-
factor1 = number
|
117
|
-
|
118
|
-
multiplicative_operators = [Token::Multiply, Token::Divide]
|
119
|
-
|
120
|
-
token = @lexer.get_next_token
|
121
|
-
while multiplicative_operators.include?(token.kind)
|
122
|
-
factor2 = number
|
123
|
-
|
124
|
-
if token.kind == Token::Multiply
|
125
|
-
factor1 *= factor2
|
126
|
-
else
|
127
|
-
factor1 /= factor2
|
128
|
-
end
|
129
|
-
|
130
|
-
token = @lexer.get_next_token
|
131
|
-
end
|
132
|
-
@lexer.revert
|
133
|
-
|
134
|
-
factor1
|
135
|
-
end
|
136
|
-
|
137
|
-
def number
|
138
|
-
token = @lexer.get_next_token
|
139
|
-
|
140
|
-
if token.kind == Token::LParen
|
141
|
-
value = expression
|
142
|
-
|
143
|
-
expected_rparen = @lexer.get_next_token
|
144
|
-
raise 'Unbalanced parenthesis' unless expected_rparen.kind == Token::RParen
|
145
|
-
elsif token.kind == Token::Number
|
146
|
-
value = token.value
|
147
|
-
else
|
148
|
-
raise 'Not a number'
|
149
|
-
end
|
150
|
-
|
151
|
-
value
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module WikiCloth
|
2
|
-
|
3
|
-
class WikiBuffer::Template < WikiBuffer
|
4
|
-
|
5
|
-
def initialize(data="",options={})
|
6
|
-
super(data,options)
|
7
|
-
@in_quotes = false
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_s
|
11
|
-
"WICKED COOL"
|
12
|
-
end
|
13
|
-
|
14
|
-
protected
|
15
|
-
def new_char()
|
16
|
-
case
|
17
|
-
# End of a template, variable, or function
|
18
|
-
when current_char == '}' && previous_char == '}'
|
19
|
-
puts "TEMP: #{self.data} ----"
|
20
|
-
self.data = ""
|
21
|
-
return false
|
22
|
-
|
23
|
-
else
|
24
|
-
self.data += current_char
|
25
|
-
end
|
26
|
-
|
27
|
-
return true
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|