facwparser 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in facwparser.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 HARUYAMA Seigo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Facwparser
2
+
3
+ Fuxxing Atlassian Confluence Wiki Parser
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'facwparser'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install facwparser
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc "Run Unit Tests"
4
+ task :test do
5
+ $VERBOSE = true
6
+ exec 'ruby', File.dirname(__FILE__) + '/tests/all_tests.rb'
7
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'facwparser/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "facwparser"
8
+ gem.version = Facwparser::VERSION
9
+ gem.authors = ["HARUYAMA Seigo"]
10
+ gem.email = ["haruyama@unixuser.org"]
11
+ gem.description = %q{Fuxxing Atlassian Confluence Wiki Parser}
12
+ gem.summary = %q{Parser of Atlassian Confluence Wiki Markup.}
13
+ gem.homepage = "https://github.com/haruyama/facwparser"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,317 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'cgi'
4
+
5
+
6
+ module Facwparser
7
+ module Element
8
+ class ElementBase
9
+ attr_reader :source, :children
10
+ def initialize(source)
11
+ @source = source
12
+ @children = nil
13
+ end
14
+ def ==(other)
15
+ self.class == other.class && self.source == other.source
16
+ end
17
+
18
+ def render_html(options)
19
+ raise "TODO: render_html is not implemented: " + self.class.to_s + "\n"
20
+ end
21
+ end
22
+
23
+ class P < ElementBase
24
+ def append(source)
25
+ @source += source
26
+ end
27
+ def render_html(options)
28
+ if source =~ /\A *bq. (.+)/m
29
+ @children ||= Parser.parse_value($1, options)
30
+ "<blockquote>\n" + @children.map { |c| c.render_html(options) }.join("") + "\n</blockquote>\n"
31
+ else
32
+ @children ||= Parser.parse_value(source, options)
33
+ "<p>\n" + @children.map { |c| c.render_html(options) }.join("") + "</p>\n"
34
+ end
35
+ end
36
+ end
37
+ class HorizontalRule < ElementBase
38
+ def render_html(options)
39
+ "<hr>\n"
40
+ end
41
+ end
42
+ class Heading < ElementBase
43
+ attr_reader :level, :value
44
+ def initialize(source, level, value)
45
+ super(source)
46
+ @level = level
47
+ @value = value
48
+ end
49
+ def render_html(options)
50
+ "<h#{level}>#{CGI.escapeHTML value}</h#{level}>\n"
51
+ end
52
+ end
53
+ class List < ElementBase
54
+ attr_reader :type
55
+ def initialize(type)
56
+ super('')
57
+ @type = type
58
+ end
59
+ def push(item)
60
+ @children ||= []
61
+ @children.push(item)
62
+ self
63
+ end
64
+ def render_html(options)
65
+ case @type
66
+ when '#'
67
+ return "<ol>\n" + @children.map{ |c| c.render_html(options) }.join("") + "</ol>\n"
68
+ else
69
+ return "<ul>\n" + @children.map{ |c| c.render_html(options) }.join("") + "</ul>\n"
70
+ end
71
+ end
72
+ end
73
+ class ListItem < ElementBase
74
+ attr_reader :symbols, :level, :value
75
+ def initialize(source, symbols, value)
76
+ super(source)
77
+ @symbols = symbols
78
+ @level = symbols.size
79
+ @value = value
80
+ end
81
+ def render_html(options)
82
+ @children = Parser.parse_value value, options
83
+ "<li>" + @children.map {|c| c.render_html(options) }.join("") + "</li>\n"
84
+ end
85
+ end
86
+ class Table < ElementBase
87
+ def initialize()
88
+ super('')
89
+ end
90
+ def push(item)
91
+ @children ||= []
92
+ @children.push(item)
93
+ self
94
+ end
95
+ def render_html(options)
96
+ "<table><thead>\n" + @children[0].render_html(options) +
97
+ "\n</thead>\n<tbody>\n" +
98
+ @children.drop(1).map{|c| c.render_html(options)}.join("\n") +
99
+ "\n</tbody></table>\n"
100
+ end
101
+ end
102
+ class TableHeaders < ElementBase
103
+ attr_reader :elements
104
+ def initialize(source)
105
+ super(source)
106
+ @elements = source.split('||')[1..-2]
107
+ end
108
+ def render_html(options)
109
+ "<tr>" +
110
+ @elements.map { |e| '<th>' + Parser.parse_value(e, options).map { |c| c.render_html(options) }.join(" ") + '</th>'}.join() +
111
+ "</tr>"
112
+ end
113
+ end
114
+ class TableData < ElementBase
115
+ attr_reader :elements
116
+ def initialize(source)
117
+ super(source)
118
+ @elements = []
119
+ element = ''
120
+ s = StringScanner.new(source[1..-2])
121
+ in_link = false
122
+ while s.rest?
123
+ case
124
+ when s.scan(/[^|\[\]]+/) || s.scan(/\\\[/) || s.scan(/\\\]/) || s.scan(/\\\|/)
125
+ element += s[0]
126
+ when s.scan(/\[/)
127
+ in_link = true
128
+ element += s[0]
129
+ when s.scan(/\]/)
130
+ in_link = false
131
+ element += s[0]
132
+ when s.scan(/\|/)
133
+ if in_link
134
+ element += s[0]
135
+ else
136
+ @elements << element
137
+ element = ''
138
+ end
139
+ else
140
+ element += s.rest
141
+ break
142
+ end
143
+ end
144
+ @elements << element if !element.empty?
145
+ end
146
+ def render_html(options)
147
+ "<tr>" +
148
+ @elements.map { |e| '<td>' + Parser.parse_value(e, options).map { |c| c.render_html(options) }.join(" ") + '</td>'}.join() +
149
+ "</tr>"
150
+ end
151
+ end
152
+
153
+ class MacroBase < ElementBase
154
+ end
155
+ class TocMacro < MacroBase
156
+ def initialize(source, options = nil)
157
+ super(source)
158
+ @options = options
159
+ end
160
+ def render_html(options)
161
+ "TODO: table of contents Macro\n"
162
+ end
163
+ end
164
+ class PagetreeMacro < MacroBase
165
+ def initialize(source, options = nil)
166
+ super(source)
167
+ @options = options
168
+ end
169
+ def render_html(options)
170
+ "TODO: pagetree macro\n"
171
+ end
172
+ end
173
+ class NoformatMacro < MacroBase
174
+ def initialize(source, value)
175
+ super(source)
176
+ @value = value
177
+ end
178
+ def render_html(options)
179
+ "<pre>\n#{CGI.escapeHTML @value}\n</pre>\n"
180
+ end
181
+ end
182
+ class CodeMacro < MacroBase
183
+ def initialize(source, options, value)
184
+ super(source)
185
+ @options = options
186
+ @value = value
187
+ end
188
+ def render_html(options)
189
+ "<code class=\"code_#{CGI.escapeHTML(@options[1..-1])}\"><pre>\n#{CGI.escapeHTML @value}\n</pre></code>\n"
190
+ end
191
+ end
192
+ class QuoteMacro < MacroBase
193
+ def initialize(source, value)
194
+ super(source)
195
+ @value = value
196
+ end
197
+ def render_html(options)
198
+ "<blockquote>\n#{CGI.escapeHTML @value}\n</blockquote>\n"
199
+ end
200
+ end
201
+
202
+ class InlineElementBase < ElementBase
203
+ attr_reader :text
204
+ def initialize(source, text)
205
+ super(source)
206
+ @text = text
207
+ end
208
+ def ==(other)
209
+ super(other) && self.text == other.text
210
+ end
211
+ end
212
+
213
+ class A < InlineElementBase
214
+ def render_html(options)
215
+ if @text =~ /\A(.+)\|((?:https?|ftp|file):.+)\z/
216
+ return '<a href="' + CGI.escapeHTML($2) +'">' + CGI.escapeHTML($1) + '</a>'
217
+ elsif @text =~ /\A(?:https?|ftp|file):.+\z/
218
+ return '<a href="' + CGI.escapeHTML(@text) +'">' + CGI.escapeHTML(@text) + '</a>'
219
+ else
220
+ return '[' + CGI.escapeHTML(@text) + ']'
221
+ end
222
+ end
223
+ end
224
+
225
+ class Bold < InlineElementBase
226
+ def render_html(options)
227
+ "<b>#{CGI.escapeHTML(@text)}</b>"
228
+ end
229
+ end
230
+
231
+ class Italic < InlineElementBase
232
+ def render_html(options)
233
+ "<i>#{CGI.escapeHTML(@text)}</i>"
234
+ end
235
+ end
236
+
237
+ class Strike < InlineElementBase
238
+ def render_html(options)
239
+ "<s>#{CGI.escapeHTML(@text)}</s>"
240
+ end
241
+ end
242
+
243
+ class Under < InlineElementBase
244
+ def render_html(options)
245
+ "<u>#{CGI.escapeHTML(@text)}</u>"
246
+ end
247
+ end
248
+
249
+ class Q < InlineElementBase
250
+ def render_html(options)
251
+ "<q>#{CGI.escapeHTML(@text)}</q>"
252
+ end
253
+ end
254
+
255
+ class SUP < InlineElementBase
256
+ def render_html(options)
257
+ "<sup>#{CGI.escapeHTML(@text)}</sup>"
258
+ end
259
+ end
260
+
261
+ class SUB < InlineElementBase
262
+ def render_html(options)
263
+ "<sub>#{CGI.escapeHTML(@text)}</sub>"
264
+ end
265
+ end
266
+
267
+ class TT < InlineElementBase
268
+ def render_html(options)
269
+ "<tt>#{CGI.escapeHTML(@text)}</tt>"
270
+ end
271
+ end
272
+
273
+ class Image < InlineElementBase
274
+ def render_html(options)
275
+ '<img src="' + CGI.escapeHTML(@text) + '">'
276
+ end
277
+ end
278
+
279
+ class JiraMacro < MacroBase
280
+ attr_reader :options
281
+ def initialize(source, options)
282
+ super(source)
283
+ @options = options
284
+ end
285
+ def render_html(options)
286
+ jira_browse_url = (options && options['jira_browse_url']) || ''
287
+ return '<a href="' + CGI.escapeHTML(jira_browse_url) + CGI.escapeHTML(@options) +'">' + CGI.escapeHTML(@options) + '</a>'
288
+ end
289
+ end
290
+
291
+ class ColorMacroStart < MacroBase
292
+ attr_reader :options
293
+ def initialize(source, options)
294
+ super(source)
295
+ @options = options
296
+ end
297
+ def render_html(options)
298
+ return '<font color="' + CGI.escapeHTML(@options) +'">'
299
+ end
300
+ end
301
+
302
+ class ColorMacroEnd < MacroBase
303
+ def initialize(source)
304
+ super(source)
305
+ end
306
+ def render_html(options)
307
+ return '</font>'
308
+ end
309
+ end
310
+
311
+ class Text < InlineElementBase
312
+ def render_html(options)
313
+ CGI.escapeHTML @source
314
+ end
315
+ end
316
+ end
317
+ end
@@ -0,0 +1,178 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'strscan'
4
+
5
+ require File.dirname(__FILE__) + '/element'
6
+
7
+ module Facwparser
8
+ module Parser
9
+ def self.parse(content, options = {})
10
+ elements = parse1(content, options)
11
+ process_elements(elements, options)
12
+ end
13
+
14
+ def self.process_elements(elements, options)
15
+ # TODO toc
16
+ processed = add_list_elements(elements, options)
17
+ add_table_elements(processed, options)
18
+ end
19
+
20
+ def self.add_list_elements(elements, options)
21
+ processed = []
22
+ list_stack = []
23
+ elements.each { |e|
24
+ case
25
+ when e.class == Element::ListItem
26
+ while list_stack.size > e.level
27
+ list_stack.pop
28
+ end
29
+ while list_stack.size < e.level
30
+ list = Element::List.new(e.symbols[list_stack.size])
31
+ if list_stack.empty?
32
+ processed << list
33
+ else
34
+ list_stack[-1].push list
35
+ end
36
+ list_stack << list
37
+ end
38
+ list_stack[-1].push e
39
+ else
40
+ list_stack.clear if list_stack.size > 0
41
+ processed << e
42
+ end
43
+ }
44
+ processed
45
+ end
46
+
47
+ def self.add_table_elements(elements, options)
48
+ processed = []
49
+ table = nil
50
+ elements.each { |e|
51
+ case
52
+ when e.class == Element::TableHeaders || e.class == Element::TableData
53
+ if !table
54
+ table = Element::Table.new
55
+ processed << table
56
+ end
57
+ table.push e
58
+ else
59
+ table = nil
60
+ processed << e
61
+ end
62
+ }
63
+ processed
64
+ end
65
+
66
+ def self.parse1(content, options)
67
+ s = StringScanner.new(content.gsub("\r", '').gsub(/[\t\f]/, ' ') + "\n")
68
+
69
+ elements = []
70
+
71
+ p = nil
72
+
73
+ while s.rest?
74
+ case
75
+ when s.scan(/h(\d)\. +(.+)\n/)
76
+ p = nil
77
+ elements << Element::Heading.new(s[0], s[1].to_i, s[2])
78
+ when s.scan(/----+\n/)
79
+ p = nil
80
+ elements << Element::HorizontalRule.new(s[0])
81
+ when s.scan(/([*\-#]+) +(.+)\n/)
82
+ p = nil
83
+ elements << Element::ListItem.new(s[0], s[1], s[2])
84
+ when s.scan(/\|\|.+\|\| *\n/)
85
+ p = nil
86
+ elements << Element::TableHeaders.new(s[0])
87
+ when s.scan(/\|.+\| *\n/)
88
+ p = nil
89
+ elements << Element::TableData.new(s[0])
90
+ when s.scan(/\{toc(:.*)?\} *\n/)
91
+ p = nil
92
+ elements << Element::TocMacro.new(s[0], s[1] ? s[1][1,] : nil)
93
+ when s.scan(/\{pagetree(:.*)?\} *\n/)
94
+ p = nil
95
+ elements << Element::PagetreeMacro.new(s[0], s[1] ? s[1][1,] : nil)
96
+ when s.scan(/\{noformat\} *\n(?m)(.+?\n)\{noformat\} *\n/)
97
+ p = nil
98
+ elements << Element::NoformatMacro.new(s[0], s[1])
99
+ when s.scan(/\{code(:.*?)?\} *\n(?m)(.+?\n)\{code\} *\n/)
100
+ p = nil
101
+ elements << Element::CodeMacro.new(s[0], s[1], s[2])
102
+ when s.scan(/\{quote\} *\n(?m)(.+?\n)\{quote\} *\n/)
103
+ p = nil
104
+ elements << Element::QuoteMacro.new(s[0], s[1])
105
+ when s.scan(/ *\n/)
106
+ p = nil
107
+ when s.scan(/(.+)\n/)
108
+ if p
109
+ p.append(s[0])
110
+ else
111
+ p = Element::P.new(s[0])
112
+ elements << p
113
+ end
114
+ else
115
+ raise "Parse Error. line=#{s.rest}"
116
+ end
117
+ end
118
+ elements
119
+ end
120
+
121
+ def self.unescape_text(text)
122
+ text.gsub(/\\([\[\]\*+_?{}!^~-])/) {
123
+ $1
124
+ }
125
+ end
126
+
127
+ def self.parse_value(value, options)
128
+
129
+ #jira
130
+ #img
131
+
132
+ children = []
133
+
134
+ value.split("\n").each { |l|
135
+ s = StringScanner.new(l)
136
+ while s.rest?
137
+ case
138
+ when s.scan(/\[(.+?)(?<!\\)\]/)
139
+ children << Element::A.new(s[0], unescape_text(s[1]))
140
+ when s.scan(/\*(.+?)(?<!\\)\*/)
141
+ children << Element::Bold.new(s[0], unescape_text(s[1]))
142
+ when s.scan(/\_(.+?)(?<!\\)\_/)
143
+ children << Element::Italic.new(s[0], unescape_text(s[1]))
144
+ when s.scan(/\-(.+?)(?<!\\)\-/)
145
+ children << Element::Strike.new(s[0], unescape_text(s[1]))
146
+ when s.scan(/\+(.+?)(?<!\\)\+/)
147
+ children << Element::Under.new(s[0], unescape_text(s[1]))
148
+ when s.scan(/\^(.+?)(?<!\\)\^/)
149
+ children << Element::SUP.new(s[0], unescape_text(s[1]))
150
+ when s.scan(/\~(.+?)(?<!\\)\~/)
151
+ children << Element::SUB.new(s[0], unescape_text(s[1]))
152
+ when s.scan(/\?\?(.+?)(?<!\\)\?\?/)
153
+ children << Element::Q.new(s[0], unescape_text(s[1]))
154
+ when s.scan(/\{\{(.+?)(?<!\\)\}\}/)
155
+ children << Element::TT.new(s[0], unescape_text(s[1]))
156
+ when s.scan(/\!(https?:(?:.+?))(?<!\\)\!/)
157
+ children << Element::Image.new(s[0], unescape_text(s[1]))
158
+ when s.scan(/\{jira:(.+?)(?<!\\)\}/)
159
+ children << Element::JiraMacro.new(s[0], unescape_text(s[1]))
160
+ when s.scan(/\{color:(.+?)(?<!\\)\}/)
161
+ children << Element::ColorMacroStart.new(s[0], unescape_text(s[1]))
162
+ when s.scan(/\{color\}/)
163
+ children << Element::ColorMacroEnd.new(s[0])
164
+ when s.scan(/[^\[^\\*_+{!-]+/)
165
+ children << Element::Text.new(s[0], unescape_text(s[0]))
166
+ when s.scan(/\\[\[\]\*+_?{}!^~-]/)
167
+ children << Element::Text.new(s[0], unescape_text(s[0]))
168
+ else
169
+ children << Element::Text.new(s.rest, unescape_text(s.rest))
170
+ break
171
+ end
172
+ end
173
+ }
174
+
175
+ children
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,15 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.dirname(__FILE__) + '/element'
4
+
5
+ module Facwparser
6
+ module Render
7
+ def self.render_html(elements, options = {})
8
+ output = ''
9
+ elements.each { |e|
10
+ output += e.render_html(options)
11
+ }
12
+ output
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Facwparser
2
+ VERSION = "0.0.1"
3
+ end
data/lib/facwparser.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'facwparser/version'
2
+ require 'facwparser/parser'
3
+ require 'facwparser/render'
4
+
5
+ module Facwparser
6
+ def self.to_html(source, options = nil)
7
+ Render.render_html(Parser.parse(source, options), options) + "\n"
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+ require 'facwparser'
4
+
5
+ print <<EOS
6
+ <!DOCTYPE html>
7
+ <html>
8
+ <head>
9
+ <title>sample</title>
10
+ </head>
11
+ <body>
12
+ EOS
13
+ print Facwparser.to_html(ARGF.read)
14
+ print <<EOS
15
+ </body>
16
+ </html>
17
+ EOS
@@ -0,0 +1,3 @@
1
+ Dir.chdir(File.dirname(__FILE__)) do
2
+ Dir.glob('**/test_*.rb') { |test_case| require './' + test_case }
3
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../../../lib/facwparser/parser'
4
+
5
+
6
+ class TestAddListElements < Test::Unit::TestCase
7
+
8
+ def test_add_list_elements_1
9
+ pre = [
10
+ Facwparser::Element::ListItem.new("* 4\n", '*', '4'),
11
+ Facwparser::Element::ListItem.new("** 5\n", '**', '5'),
12
+ Facwparser::Element::ListItem.new("**# 6\n", '**#', '6'),
13
+ ]
14
+
15
+ assert_equal([
16
+ Facwparser::Element::List.new('*').push(
17
+ Facwparser::Element::ListItem.new("* 4\n", '*', '4')).push(
18
+ Facwparser::Element::List.new('*').push(
19
+ Facwparser::Element::ListItem.new("** 5\n", '**', '5')).push(
20
+ Facwparser::Element::List.new('#').push(
21
+ Facwparser::Element::ListItem.new("**# 6\n", '**#', '6'))
22
+ ))
23
+ ], Facwparser::Parser.add_list_elements(pre, {}))
24
+
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,214 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../../../lib/facwparser/parser'
4
+
5
+
6
+ class TestParse1 < Test::Unit::TestCase
7
+
8
+ def test_parse1_p
9
+ source =<<EOS
10
+ ほげ
11
+
12
+ ほげほげ
13
+
14
+ ほげほげげほ
15
+ にゃ
16
+ EOS
17
+ assert_equal(
18
+ [
19
+ Facwparser::Element::P.new("ほげ\n"),
20
+ Facwparser::Element::P.new("ほげほげ\n"),
21
+ Facwparser::Element::P.new("ほげほげげほ\nにゃ\n"),
22
+ ],
23
+ Facwparser::Parser.parse1(source, {}))
24
+
25
+ end
26
+
27
+ def test_parse1_heading
28
+ source =<<EOS
29
+ h1. ほげ
30
+
31
+ ほげほげ
32
+ h3. ほげほげげほ
33
+ にゃ
34
+ EOS
35
+ assert_equal(
36
+ [
37
+ Facwparser::Element::Heading.new("h1. ほげ\n", 1, "ほげ"),
38
+ Facwparser::Element::P.new("ほげほげ\n"),
39
+ Facwparser::Element::Heading.new("h3. ほげほげげほ\n", 3, "ほげほげげほ"),
40
+ Facwparser::Element::P.new("にゃ\n"),
41
+ ],
42
+ Facwparser::Parser.parse1(source, {}))
43
+
44
+ end
45
+
46
+ def test_parse1_horizontal_rule
47
+ source =<<EOS
48
+ 1
49
+ ----
50
+ 2
51
+ ---
52
+ 3
53
+
54
+ -----
55
+ 4
56
+ EOS
57
+ assert_equal(
58
+ [
59
+ Facwparser::Element::P.new("1\n"),
60
+ Facwparser::Element::HorizontalRule.new("----\n"),
61
+ Facwparser::Element::P.new("2\n---\n3\n"),
62
+ Facwparser::Element::HorizontalRule.new("-----\n"),
63
+ Facwparser::Element::P.new("4\n"),
64
+ ],
65
+ Facwparser::Parser.parse1(source, {}))
66
+
67
+ end
68
+
69
+ def test_parse1_list_item
70
+ source =<<EOS
71
+ 1
72
+ - 2
73
+ 3
74
+ ** 4
75
+ ### 5
76
+ #*#* 6
77
+ EOS
78
+ assert_equal(
79
+ [
80
+ Facwparser::Element::P.new("1\n"),
81
+ Facwparser::Element::ListItem.new("- 2\n", '-', '2'),
82
+ Facwparser::Element::P.new("3\n"),
83
+ Facwparser::Element::ListItem.new("** 4\n", '**', '4'),
84
+ Facwparser::Element::ListItem.new("### 5\n", '###', '5'),
85
+ Facwparser::Element::ListItem.new("#*#* 6\n", '#*#*', '6'),
86
+ ],
87
+ Facwparser::Parser.parse1(source, {}))
88
+
89
+ end
90
+
91
+ def test_parse1_table
92
+ source =<<EOS
93
+ 1
94
+ ||2||3||
95
+ |4|5|
96
+ 6
97
+ EOS
98
+ assert_equal(
99
+ [
100
+ Facwparser::Element::P.new("1\n"),
101
+ Facwparser::Element::TableHeaders.new("||2||3||\n"),
102
+ Facwparser::Element::TableData.new("|4|5|\n"),
103
+ Facwparser::Element::P.new("6\n"),
104
+ ],
105
+ Facwparser::Parser.parse1(source, {}))
106
+
107
+ end
108
+
109
+ def test_parse1_toc_1
110
+ source =<<EOS
111
+ 1
112
+ {toc}
113
+ 2
114
+ EOS
115
+ assert_equal(
116
+ [
117
+ Facwparser::Element::P.new("1\n"),
118
+ Facwparser::Element::TocMacro.new("{toc}\n"),
119
+ Facwparser::Element::P.new("2\n"),
120
+ ],
121
+ Facwparser::Parser.parse1(source, {}))
122
+
123
+ end
124
+
125
+ def test_parse1_toc_2
126
+ source =<<EOS
127
+ 1
128
+ {toc:maxLevel=3}
129
+ 2
130
+ EOS
131
+ assert_equal(
132
+ [
133
+ Facwparser::Element::P.new("1\n"),
134
+ Facwparser::Element::TocMacro.new("{toc:maxLevel=3}\n", 'maxLevel=3'),
135
+ Facwparser::Element::P.new("2\n"),
136
+ ],
137
+ Facwparser::Parser.parse1(source, {}))
138
+
139
+ end
140
+
141
+ def test_parse1_pagetree
142
+ source =<<EOS
143
+ 1
144
+ {pagetree:root=@self}
145
+ 2
146
+ EOS
147
+ assert_equal(
148
+ [
149
+ Facwparser::Element::P.new("1\n"),
150
+ Facwparser::Element::PagetreeMacro.new("{pagetree:root=@self}\n", 'root=@self'),
151
+ Facwparser::Element::P.new("2\n"),
152
+ ],
153
+ Facwparser::Parser.parse1(source, {}))
154
+
155
+ end
156
+
157
+ def test_parse1_noformat
158
+ source =<<EOS
159
+ 1
160
+ {noformat}
161
+ 2
162
+ 3
163
+ {noformat}
164
+ 4
165
+ EOS
166
+ assert_equal(
167
+ [
168
+ Facwparser::Element::P.new("1\n"),
169
+ Facwparser::Element::NoformatMacro.new("{noformat}\n2\n3\n{noformat}\n", "2\n3\n"),
170
+ Facwparser::Element::P.new("4\n"),
171
+ ],
172
+ Facwparser::Parser.parse1(source, {}))
173
+
174
+ end
175
+
176
+ def test_parse1_code
177
+ source =<<EOS
178
+ 1
179
+ {code:ruby}
180
+ a = 1 + 2
181
+ 3
182
+ {code}
183
+ 4
184
+ EOS
185
+ assert_equal(
186
+ [
187
+ Facwparser::Element::P.new("1\n"),
188
+ Facwparser::Element::CodeMacro.new("{code:ruby}\na = 1 + 2\n3\n{code}\n", 'ruby', "a = 1 + 2\n3\n"),
189
+ Facwparser::Element::P.new("4\n"),
190
+ ],
191
+ Facwparser::Parser.parse1(source, {}))
192
+
193
+ end
194
+
195
+ def test_parse1_quote
196
+ source =<<EOS
197
+ 1
198
+ {quote}
199
+ 2
200
+ 3
201
+ {quote}
202
+ 4
203
+ EOS
204
+ assert_equal(
205
+ [
206
+ Facwparser::Element::P.new("1\n"),
207
+ Facwparser::Element::QuoteMacro.new("{quote}\n2\n3\n{quote}\n", "2\n3\n"),
208
+ Facwparser::Element::P.new("4\n"),
209
+ ],
210
+ Facwparser::Parser.parse1(source, {}))
211
+
212
+ end
213
+
214
+ end
@@ -0,0 +1,110 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../../../lib/facwparser/parser'
4
+
5
+
6
+ class TestParseValue < Test::Unit::TestCase
7
+
8
+ def test_parse_value_text
9
+ assert_equal([
10
+ Facwparser::Element::Text.new('1', '1')
11
+ ], Facwparser::Parser.parse_value('1', {}))
12
+ assert_equal([
13
+ Facwparser::Element::Text.new('1', '1'),
14
+ Facwparser::Element::Text.new('2', '2')
15
+ ], Facwparser::Parser.parse_value("1\n2", {}))
16
+ end
17
+
18
+ def test_parse_value_a
19
+ assert_equal([
20
+ Facwparser::Element::Text.new('1', '1'),
21
+ Facwparser::Element::A.new('[hoge]', 'hoge'),
22
+ Facwparser::Element::Text.new('2', '2')
23
+ ], Facwparser::Parser.parse_value('1[hoge]2', {}))
24
+ assert_equal([
25
+ Facwparser::Element::Text.new('1', '1'),
26
+ Facwparser::Element::A.new('[hoge\]]', 'hoge]'),
27
+ Facwparser::Element::Text.new('2', '2')
28
+ ], Facwparser::Parser.parse_value('1[hoge\]]2', {}))
29
+ assert_equal([
30
+ Facwparser::Element::A.new('[株式会社ミクシィ|https://mixi.co.jp/]', '株式会社ミクシィ|https://mixi.co.jp/'),
31
+ ], Facwparser::Parser.parse_value('[株式会社ミクシィ|https://mixi.co.jp/]', {}))
32
+ end
33
+
34
+ def test_parse_value_bold
35
+ assert_equal([
36
+ Facwparser::Element::Text.new('1', '1'),
37
+ Facwparser::Element::Bold.new('*hoge*', 'hoge'),
38
+ Facwparser::Element::Text.new('2', '2')
39
+ ], Facwparser::Parser.parse_value('1*hoge*2', {}))
40
+ end
41
+
42
+ def test_parse_value_italic
43
+ assert_equal([
44
+ Facwparser::Element::Text.new('1', '1'),
45
+ Facwparser::Element::Italic.new('_hoge_', 'hoge'),
46
+ Facwparser::Element::Text.new('2', '2')
47
+ ], Facwparser::Parser.parse_value('1_hoge_2', {}))
48
+ end
49
+
50
+ def test_parse_value_strike
51
+ assert_equal([
52
+ Facwparser::Element::Text.new('1', '1'),
53
+ Facwparser::Element::Strike.new('-hoge\-i-', 'hoge-i'),
54
+ Facwparser::Element::Text.new('2', '2')
55
+ ], Facwparser::Parser.parse_value('1-hoge\-i-2', {}))
56
+ end
57
+
58
+ def test_parse_value_under
59
+ assert_equal([
60
+ Facwparser::Element::Text.new('1', '1'),
61
+ Facwparser::Element::Under.new('+hoge+', 'hoge'),
62
+ Facwparser::Element::Text.new('2', '2')
63
+ ], Facwparser::Parser.parse_value('1+hoge+2', {}))
64
+ end
65
+
66
+ def test_parse_value_image
67
+ assert_equal([
68
+ Facwparser::Element::Text.new('1', '1'),
69
+ Facwparser::Element::Image.new('!http://www.unixuser.org/!', 'http://www.unixuser.org/'),
70
+ Facwparser::Element::Text.new('2', '2')
71
+ ], Facwparser::Parser.parse_value('1!http://www.unixuser.org/!2', {}))
72
+ end
73
+
74
+ def test_parse_value_jira_macro
75
+ assert_equal([
76
+ Facwparser::Element::Text.new('1', '1'),
77
+ Facwparser::Element::JiraMacro.new('{jira:SYSTEMRD-1}', 'SYSTEMRD-1'),
78
+ Facwparser::Element::Text.new('2', '2')
79
+ ], Facwparser::Parser.parse_value('1{jira:SYSTEMRD-1}2', {}))
80
+ end
81
+
82
+ def test_parse_value_jira_misc
83
+ assert_equal([
84
+ Facwparser::Element::Text.new('1', '1'),
85
+ Facwparser::Element::Text.new('{jira:SYSTEMRD-1', '{jira:SYSTEMRD-1'),
86
+ ], Facwparser::Parser.parse_value('1{jira:SYSTEMRD-1', {}))
87
+
88
+ assert_equal([
89
+ Facwparser::Element::Text.new('1', '1'),
90
+ Facwparser::Element::Text.new('{jira:SYSTEMRD\-1', '{jira:SYSTEMRD-1'),
91
+ ], Facwparser::Parser.parse_value('1{jira:SYSTEMRD\-1', {}))
92
+
93
+ assert_equal([
94
+ Facwparser::Element::Text.new('1', '1'),
95
+ Facwparser::Element::Text.new('\{', '{'),
96
+ Facwparser::Element::Text.new('jira:SYSTEMRD', 'jira:SYSTEMRD'),
97
+ Facwparser::Element::Text.new('\\-', '-'),
98
+ Facwparser::Element::Text.new('1', '1'),
99
+ ], Facwparser::Parser.parse_value('1\\{jira:SYSTEMRD\\-1', {}))
100
+
101
+ assert_equal([
102
+ Facwparser::Element::Text.new('1', '1'),
103
+ Facwparser::Element::Text.new('\{', '{'),
104
+ Facwparser::Element::JiraMacro.new('{jira:SYSTEMRD\-1}', 'SYSTEMRD-1'),
105
+ ], Facwparser::Parser.parse_value('1\\{{jira:SYSTEMRD\\-1}', {}))
106
+
107
+ end
108
+
109
+ end
110
+
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: facwparser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - HARUYAMA Seigo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-08 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Fuxxing Atlassian Confluence Wiki Parser
15
+ email:
16
+ - haruyama@unixuser.org
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - facwparser.gemspec
27
+ - lib/facwparser.rb
28
+ - lib/facwparser/element.rb
29
+ - lib/facwparser/parser.rb
30
+ - lib/facwparser/render.rb
31
+ - lib/facwparser/version.rb
32
+ - sample/confluence2html.rb
33
+ - tests/all_tests.rb
34
+ - tests/units/parse/test_add_list_elements.rb
35
+ - tests/units/parse/test_parse1.rb
36
+ - tests/units/parse/test_parse_value.rb
37
+ homepage: https://github.com/haruyama/facwparser
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.24
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: Parser of Atlassian Confluence Wiki Markup.
61
+ test_files: []
62
+ has_rdoc: