wikicloth 0.5.0 → 0.6.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.
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