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 CHANGED
@@ -26,7 +26,7 @@ Install
26
26
  git clone git://github.com/nricciar/wikicloth.git
27
27
  cd wikicloth/
28
28
  rake gem
29
- sudo gem install pkg/wikicloth-0.2.0.gem
29
+ sudo gem install pkg/wikicloth-0.5.0.gem
30
30
 
31
31
  Usage
32
32
  ---------------------------------------------------
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
- desc 'Default: run unit tests.'
8
- task :default => :test
7
+ require 'bundler'
8
+ Bundler::GemHelper.install_tasks
9
9
 
10
- desc 'Test the wikicloth plugin.'
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
- spec = Gem::Specification.new do |s|
28
- s.name = "wikicloth"
29
- s.version = WikiCloth::VERSION
30
- s.author = "David Ricciardi"
31
- s.email = "nricciar@gmail.com"
32
- s.homepage = "http://github.com/nricciar/wikicloth"
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
- Rake::GemPackageTask.new(spec) do |pkg|
48
- pkg.need_tar = true
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
@@ -1,22 +1,27 @@
1
- class Object
2
- module InstanceExecHelper; end
3
- include InstanceExecHelper
4
- def instance_exec(*args, &block)
5
- begin
6
- old_critical, Thread.critical = Thread.critical, true
7
- n = 0
8
- n += 1 while respond_to?(mname="__instance_exec#{n}")
9
- InstanceExecHelper.module_eval{ define_method(mname, &block) }
10
- ensure
11
- Thread.critical = old_critical
12
- end
13
- begin
14
- ret = send(mname, *args)
15
- ensure
16
- InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
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
@@ -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.first.wikitext({ :replace => { id => data.last(1) == "\n" ? data : "#{data}\n" } })
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.first.get_section(id)
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.first.wikitext()
105
+ @wikicloth.sections.collect { |s| s.wikitext() }.join
106
106
  end
107
107
 
108
108
  end
@@ -6,6 +6,8 @@ module WikiCloth
6
6
  self.title = title
7
7
  @children = []
8
8
  @id = id
9
+ @template = nil
10
+ @auto_toc = nil
9
11
  end
10
12
 
11
13
  def children
@@ -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 unless check.nil?
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
- true
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
- self.data = ret
32
- ""
33
- end
34
- end
35
-
36
- def get_param(name,default=nil)
37
- ret = nil
38
- # numbered params
39
- if name =~ /^[0-9]+$/
40
- ret = self.params[name.to_i].instance_of?(Hash) ? self.params[name.to_i][:value] : self.params[name.to_i]
41
- end
42
- # named params
43
- self.params.each do |param|
44
- ret = param[:value] if param[:name] == name
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: &#123;&#123;#{debug_tree}&#125;&#125;</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.length.times do |i|
55
- temp = params[i].split("=")
56
- return temp[1].strip if temp[0].strip == params[0] && i != 0
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
- return ""
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
- self.data.chop!
133
- self.current_param = self.data
134
- self.data = ""
135
- return false
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].data.chop!
72
- @buffers << WikiBuffer::Var.new("",@options)
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 { |c| self.add_char(c) }
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.5.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? || opt[:data].blank?
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.first.render(self.options)
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
@@ -1,3 +1,7 @@
1
+
1
2
  require 'rubygems'
3
+ gem "test-unit", ">= 2.0.5"
2
4
  require 'active_support'
3
5
  require 'active_support/test_case'
6
+ require 'test/unit'
7
+ require File.join(File.dirname(__FILE__),'../init')
@@ -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
- # Replace this with your real tests.
5
- test "the truth" do
6
- assert true
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\">&#91;<a href=\"?section=Hallo\" target=\"_blank\" class=\"exlink\">edit</a>&#93;</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: 11
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 5
8
+ - 6
9
9
  - 0
10
- version: 0.5.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-09-20 00:00:00 +00:00
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: []
@@ -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
@@ -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