redcarpet-confluence 1.0.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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/README.md +41 -0
- data/Rakefile +3 -0
- data/bin/md2conf +43 -0
- data/lib/redcarpet/confluence.rb +149 -0
- data/redcarpet-confluence.gemspec +18 -0
- data/spec/redcarpet/confluence_spec.rb +285 -0
- data/spec/smoke_spec.rb +20 -0
- data/spec/spec_helper.rb +11 -0
- metadata +99 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3010153521e4234b72df560c2001a60b31a92fb5
|
4
|
+
data.tar.gz: 569031b749cb8bd4a194601370c36ae07b98b76a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bde7e967394a83eca860460d9776acb1d5b275afb68b4d283ef0a4476116e56b34ad6b9e6ff8387018811d095264715f0e39b4325f429a6032f7c1a349815df0
|
7
|
+
data.tar.gz: 1a09e09be82a1c282eb9c0b353092e41f044cf1d593e426d1d6ff36d3c4b96d1031684c1206ca17c48fd6b78f01ec706f637bf5befc38e00b995a192d348052f
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# RedcarpetConfluence
|
2
|
+
|
3
|
+
A Redcarpet renderer to convert Markdown to Confluence syntax.
|
4
|
+
|
5
|
+
Assumes text is UTF-8.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
Call `md2conf` with the Markdown text to convert. Alternatively, pipe the text to `md2conf`.
|
10
|
+
|
11
|
+
md2conf README.md
|
12
|
+
cat README.md | md2conf
|
13
|
+
|
14
|
+
If you're on a Mac, pipe the output to `pbcopy` so you can paste it directly into Confluence.
|
15
|
+
|
16
|
+
md2conf README.md | pbcopy
|
17
|
+
|
18
|
+
### From code
|
19
|
+
|
20
|
+
Create a Markdown parser with the Confluence renderer.
|
21
|
+
|
22
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Confluence)
|
23
|
+
puts markdown.render(markdown_text)
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
Add this line to your application's Gemfile:
|
28
|
+
|
29
|
+
gem 'redcarpet-confluence'
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
$ bundle
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
$ gem install redcarpet-confluence
|
38
|
+
|
39
|
+
and require it as:
|
40
|
+
|
41
|
+
require 'redcarpet/confluence'
|
data/Rakefile
ADDED
data/bin/md2conf
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby -s
|
2
|
+
|
3
|
+
# Converts the contents of the given file to Confluence syntax (or stdin) and prints the result to stdout.
|
4
|
+
#
|
5
|
+
# Automatically enables all the additional features provided by Redcarpet. Provide flags to disable features.
|
6
|
+
#
|
7
|
+
# Usage: md2conf [-noautolink] [-nofencedcode] [-intraemphasis] [-nostrikethrough] [-nosuperscript] [-notables] FILENAME
|
8
|
+
# md2conf -h
|
9
|
+
|
10
|
+
require 'redcarpet/confluence'
|
11
|
+
|
12
|
+
# == Helpers
|
13
|
+
|
14
|
+
def usage
|
15
|
+
"Usage: #{$0} [-noautolink] [-nofencedcode] [-intraemphasis] [-nostrikethrough] [-nosuperscript] [-notables] FILENAME"
|
16
|
+
end
|
17
|
+
|
18
|
+
def markdown_text
|
19
|
+
if ARGV[0]
|
20
|
+
File.read(ARGV[0])
|
21
|
+
else
|
22
|
+
$stdin.read
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# == Script
|
27
|
+
|
28
|
+
if $h
|
29
|
+
$stderr.puts usage
|
30
|
+
exit 0
|
31
|
+
end
|
32
|
+
|
33
|
+
markdown_options = {
|
34
|
+
autolink: $noautolink.nil?,
|
35
|
+
fenced_code_blocks: $nofencedcode.nil?,
|
36
|
+
no_intra_emphasis: $intraemphasis.nil?,
|
37
|
+
strikethrough: $nostrikethrough.nil?,
|
38
|
+
superscript: $nosuperscript.nil?,
|
39
|
+
tables: $notables.nil?
|
40
|
+
}
|
41
|
+
|
42
|
+
renderer = Redcarpet::Markdown.new(Redcarpet::Confluence, markdown_options)
|
43
|
+
$stdout.puts renderer.render(markdown_text)
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
|
3
|
+
require 'redcarpet'
|
4
|
+
|
5
|
+
module Redcarpet
|
6
|
+
# Public: A Redcarpet renderer to convert Markdown to Confluence syntax.
|
7
|
+
class Confluence < Redcarpet::Render::Base
|
8
|
+
|
9
|
+
# Internal: Languages supported by the code macro.
|
10
|
+
CODE_MACRO_LANGUAGES = %w(
|
11
|
+
actionscript actionscript3 bash csharp coldfusion cpp css delphi diff erlang groovy html java javafx javascript
|
12
|
+
perl php powershell python ruby scala sql vb xhtml xml
|
13
|
+
)
|
14
|
+
# Internal: List item delimiters used by Confluence.
|
15
|
+
LIST_ITEM_DELIMITER = %w( # * )
|
16
|
+
# Internal: Reserved character sequences in Confluence that need to be escaped when not intended to be used.
|
17
|
+
RESERVED_SEQUENCES = %w( { } [ ] - + * _ ^ ~ ?? bq. )
|
18
|
+
|
19
|
+
def block_code(code, language)
|
20
|
+
supported_language = CODE_MACRO_LANGUAGES.find { |lang| lang == language }
|
21
|
+
macro(:code, code, lang: supported_language || :none)
|
22
|
+
end
|
23
|
+
|
24
|
+
def block_quote(text)
|
25
|
+
macro(:quote, text)
|
26
|
+
end
|
27
|
+
|
28
|
+
def codespan(code)
|
29
|
+
"{{#{escape_reserved_sequences(code)}}}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def double_emphasis(text)
|
33
|
+
"*#{text}*"
|
34
|
+
end
|
35
|
+
|
36
|
+
def emphasis(text)
|
37
|
+
"_#{text}_"
|
38
|
+
end
|
39
|
+
|
40
|
+
def header(title, level)
|
41
|
+
"\n\nh#{level}. #{title}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def hrule
|
45
|
+
"\n\n----"
|
46
|
+
end
|
47
|
+
|
48
|
+
def image(link, title, alt)
|
49
|
+
"!#{link}#{args_string(alt: escape_reserved_sequences(alt), title: escape_reserved_sequences(title))}!"
|
50
|
+
end
|
51
|
+
|
52
|
+
def linebreak
|
53
|
+
"\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
def link(link, title, content)
|
57
|
+
link = "[#{content}|#{link}]"
|
58
|
+
link.insert(-2, "|#{escape_reserved_sequences(title)}") if title && !title.empty?
|
59
|
+
link
|
60
|
+
end
|
61
|
+
|
62
|
+
def list(content, list_type)
|
63
|
+
nested_list_prefix_regexp = /\n\n(?<matched_list_item_delimiter>#{LIST_ITEM_DELIMITER.map { |c| Regexp.escape(c) }.join('|')})/
|
64
|
+
nested_list_content = content.gsub(nested_list_prefix_regexp, '\k<matched_list_item_delimiter>')
|
65
|
+
"\n\n#{nested_list_content}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def list_item(content, list_type)
|
69
|
+
list_item_delimiter_regexp = /\n(?<matched_list_item_delimiter>#{LIST_ITEM_DELIMITER.map { |c| Regexp.escape(c) }.join('|')})/
|
70
|
+
list_item_delimiter = nil
|
71
|
+
case list_type
|
72
|
+
when :ordered
|
73
|
+
list_item_delimiter = '#'
|
74
|
+
when :unordered
|
75
|
+
list_item_delimiter = '*'
|
76
|
+
end
|
77
|
+
"#{list_item_delimiter} #{content.gsub(list_item_delimiter_regexp, "\n#{list_item_delimiter}\\k<matched_list_item_delimiter>")}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def normal_text(text)
|
81
|
+
escape_reserved_sequences(text)
|
82
|
+
end
|
83
|
+
|
84
|
+
def paragraph(text)
|
85
|
+
"\n\n#{text}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def strikethrough(text)
|
89
|
+
"-#{text}-"
|
90
|
+
end
|
91
|
+
|
92
|
+
def superscript(text)
|
93
|
+
" ^#{text}^ "
|
94
|
+
end
|
95
|
+
|
96
|
+
def table(header, body)
|
97
|
+
"\n#{header.gsub('|', '||')}#{body}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def table_row(text)
|
101
|
+
"\n|#{text}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def table_cell(text, align)
|
105
|
+
"#{text}|"
|
106
|
+
end
|
107
|
+
|
108
|
+
def triple_emphasis(text)
|
109
|
+
"_*#{text}*_"
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
# Internal: Backslash-escapes all Confluence-reserved character sequences.
|
115
|
+
#
|
116
|
+
# Returns a copy of the text with all Confluence-reserved character sequences escaped with a backslash.
|
117
|
+
def escape_reserved_sequences(text)
|
118
|
+
reserved_sequences_regexp = /(?<reserved_sequence>#{RESERVED_SEQUENCES.map { |c| Regexp.escape(c) }.join('|')})/
|
119
|
+
text ? text.gsub(reserved_sequences_regexp, '\\\\\k<reserved_sequence>') : text
|
120
|
+
end
|
121
|
+
|
122
|
+
# Internal: Wraps content in the named macro.
|
123
|
+
#
|
124
|
+
# name - The name of the macro to use.
|
125
|
+
# content - The content to go between the macro tags. Nil will act the same as the empty string.
|
126
|
+
# args - Optional Hash of arguments to pass to the macro.
|
127
|
+
#
|
128
|
+
# Returns a string with the given content wrapped in the named macro.
|
129
|
+
def macro(name, content, args = {})
|
130
|
+
# separate the macro name from the argument list with a colon
|
131
|
+
arguments = args_string(args).sub('|', ':')
|
132
|
+
"\n\n{#{name}#{arguments}}#{content}{#{name}}"
|
133
|
+
end
|
134
|
+
|
135
|
+
# Internal: Creates an argument String meant for a macro.
|
136
|
+
#
|
137
|
+
# Arguments are key-value pairs preceded by and separated by a pipe ('|').
|
138
|
+
#
|
139
|
+
# Returns the argument String
|
140
|
+
def args_string(args)
|
141
|
+
# format macro arguments string
|
142
|
+
args_string = ''
|
143
|
+
args.each do |arg, value|
|
144
|
+
args_string << "|#{arg}=#{value}" if value && !value.empty?
|
145
|
+
end
|
146
|
+
args_string
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = 'redcarpet-confluence'
|
3
|
+
gem.version = '1.0.0'
|
4
|
+
gem.authors = ['Adam Stegman']
|
5
|
+
gem.email = ['me@adamstegman.com']
|
6
|
+
gem.summary = 'A Redcarpet renderer to convert Markdown to Confluence syntax.'
|
7
|
+
gem.description = "#{gem.summary}"
|
8
|
+
gem.homepage = 'https://github.com/adamstegman/redcarpet-confluence'
|
9
|
+
|
10
|
+
gem.executable = 'md2conf'
|
11
|
+
gem.files = Dir['lib/**/*.rb', 'Gemfile', 'README.md', 'Rakefile', 'redcarpet-confluence.gemspec']
|
12
|
+
gem.test_files = Dir['spec/**/*.rb']
|
13
|
+
gem.require_paths = ['lib']
|
14
|
+
|
15
|
+
gem.add_dependency 'redcarpet', '~> 2.0'
|
16
|
+
gem.add_development_dependency 'rake'
|
17
|
+
gem.add_development_dependency 'rspec'
|
18
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'redcarpet/confluence'
|
3
|
+
|
4
|
+
describe Redcarpet::Confluence do
|
5
|
+
let(:renderer) { described_class.new }
|
6
|
+
|
7
|
+
describe '#block_code(code, language)' do
|
8
|
+
it 'wraps the code in a code macro for the given language' do
|
9
|
+
expect(renderer.block_code("some normal freakin' code", 'java')).to(
|
10
|
+
eq("\n\n{code:lang=java}some normal freakin' code{code}")
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'uses the "none" language when given an unsupported language' do
|
15
|
+
expect(renderer.block_code('code', 'unsupported')).to eq("\n\n{code:lang=none}code{code}")
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'does not escape Confluence text effects' do
|
19
|
+
expect(renderer.block_code('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??', 'java')).to(
|
20
|
+
eq("\n\n{code:lang=java}bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??{code}")
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#block_quote(text)' do
|
26
|
+
it 'wraps the text in a quote macro' do
|
27
|
+
expect(renderer.block_quote("some normal freakin' text")).to(
|
28
|
+
eq("\n\n{quote}some normal freakin' text{quote}")
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'does not escape Confluence text effects' do
|
33
|
+
expect(renderer.block_quote('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
34
|
+
eq("\n\n{quote}bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??{quote}")
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#codespan(code)' do
|
40
|
+
it 'wraps the given code in double curly braces' do
|
41
|
+
expect(renderer.codespan("some normal freakin' code")).to eq("{{some normal freakin' code}}")
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'escapes Confluence text effects that should be added in other methods' do
|
45
|
+
expect(renderer.codespan('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
46
|
+
eq('{{\bq. \*some\* \_emphasized\_ \-text\- \+words\+\^like\^\~this\~ \{\{and this\}\} \??Stegman\??}}')
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#double_emphasis(text)' do
|
52
|
+
it 'wraps the given text in asterisks' do
|
53
|
+
expect(renderer.double_emphasis("some normal freakin' text")).to eq("*some normal freakin' text*")
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'does not escape Confluence text effects' do
|
57
|
+
expect(renderer.double_emphasis('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
58
|
+
eq('*bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??*')
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#emphasis(text)' do
|
64
|
+
it 'wraps the given text in underscores' do
|
65
|
+
expect(renderer.emphasis("some normal freakin' text")).to eq("_some normal freakin' text_")
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'does not escape Confluence text effects' do
|
69
|
+
expect(renderer.emphasis('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
70
|
+
eq('_bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??_')
|
71
|
+
)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#header(title, level)' do
|
76
|
+
it 'prepends the header level to the given text' do
|
77
|
+
expect(renderer.header("some normal freakin' text", 5)).to eq("\n\nh5. some normal freakin' text")
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'does not escape Confluence text effects' do
|
81
|
+
expect(renderer.header('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??', 5)).to(
|
82
|
+
eq("\n\nh5. bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??")
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#hrule' do
|
88
|
+
it 'returns four hyphens' do
|
89
|
+
expect(renderer.hrule).to eq("\n\n----")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#image(link, title, alt)' do
|
94
|
+
it 'wraps the link in exclamation points' do
|
95
|
+
expect(renderer.image('http://google.com/', nil, nil)).to eq('!http://google.com/!')
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'passes the title and alt text to the image macro' do
|
99
|
+
expect(renderer.image('http://google.com/', 'title', 'alt text')).to(
|
100
|
+
eq('!http://google.com/|alt=alt text|title=title!')
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'escapes Confluence text effects that should be added in other methods' do
|
105
|
+
expect(renderer.image(
|
106
|
+
'http://google.com/',
|
107
|
+
'bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??',
|
108
|
+
'bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??'
|
109
|
+
)).to(
|
110
|
+
eq('!http://google.com/|alt=\bq. \*some\* \_emphasized\_ \-text\- \+words\+\^like\^\~this\~ \{\{and this\}\} \??Stegman\??|title=\bq. \*some\* \_emphasized\_ \-text\- \+words\+\^like\^\~this\~ \{\{and this\}\} \??Stegman\??!')
|
111
|
+
)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#linebreak' do
|
116
|
+
it 'returns a newline' do
|
117
|
+
expect(renderer.linebreak).to eq("\n")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#link(link, title, content)' do
|
122
|
+
it 'wraps the link and content in brackets' do
|
123
|
+
expect(renderer.link('http://google.com/', nil, 'my link')).to eq('[my link|http://google.com/]')
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'does not include the title when empty' do
|
127
|
+
expect(renderer.link('http://google.com/', '', 'my link')).to eq('[my link|http://google.com/]')
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'includes the title when given' do
|
131
|
+
expect(renderer.link('http://google.com/', 'some title', 'my link')).to(
|
132
|
+
eq('[my link|http://google.com/|some title]')
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'escapes Confluence text effects in the title' do
|
137
|
+
expect(renderer.link('http://google.com/', 'bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??', 'bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
138
|
+
eq('[bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??|http://google.com/|\bq. \*some\* \_emphasized\_ \-text\- \+words\+\^like\^\~this\~ \{\{and this\}\} \??Stegman\??]')
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '#list(content, list_type)' do
|
144
|
+
it 'returns the given content' do
|
145
|
+
expect(renderer.list('* content', :whatever)).to eq("\n\n* content")
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns a nested list' do
|
149
|
+
expect(renderer.list("* content\n\n\n*# nested content\n* more content\n\n\n*# more nested", :whatever)).to eq("\n\n* content\n*# nested content\n* more content\n*# more nested")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#list_item(content, list_type)' do
|
154
|
+
context 'given an ordered list_type' do
|
155
|
+
it 'prepends an octothorpe to the content' do
|
156
|
+
expect(renderer.list_item('content', :ordered)).to eq("# content")
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'prepends an octothorpe to each existing list item in the content' do
|
160
|
+
expect(renderer.list_item("content\n* nested content\n* more nested", :ordered)).to eq("# content\n#* nested content\n#* more nested")
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'does not escape Confluence text effects' do
|
164
|
+
expect(renderer.list_item('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??', :ordered)).to(
|
165
|
+
eq('# bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')
|
166
|
+
)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'given an unordered list type' do
|
171
|
+
it 'prepends an asterisk to the content' do
|
172
|
+
expect(renderer.list_item('content', :unordered)).to eq("* content")
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'prepends an asterisk to each existing list item in the content' do
|
176
|
+
expect(renderer.list_item("content\n# nested content", :unordered)).to eq("* content\n*# nested content")
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'does not escape Confluence text effects' do
|
180
|
+
expect(renderer.list_item('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??', :unordered)).to(
|
181
|
+
eq('* bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')
|
182
|
+
)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '#normal_text(text)' do
|
188
|
+
it 'does not modify normal text' do
|
189
|
+
expect(renderer.normal_text("some normal freakin' text")).to eq("some normal freakin' text")
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'escapes Confluence text effects that should be added in other methods' do
|
193
|
+
expect(renderer.normal_text('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
194
|
+
eq('\bq. \*some\* \_emphasized\_ \-text\- \+words\+\^like\^\~this\~ \{\{and this\}\} \??Stegman\??')
|
195
|
+
)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe '#paragraph(text)' do
|
200
|
+
it 'appends two newlines to normal text' do
|
201
|
+
expect(renderer.paragraph("some normal freakin' text")).to eq("\n\nsome normal freakin' text")
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'does not escape Confluence text effects' do
|
205
|
+
expect(renderer.paragraph('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
206
|
+
eq("\n\nbq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??")
|
207
|
+
)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#strikethrough(text)' do
|
212
|
+
it 'wraps the given text in hyphens' do
|
213
|
+
expect(renderer.strikethrough("some normal freakin' text")).to eq("-some normal freakin' text-")
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'does not escape Confluence text effects' do
|
217
|
+
expect(renderer.strikethrough('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
218
|
+
eq('-bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??-')
|
219
|
+
)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe '#superscript(text)' do
|
224
|
+
it 'wraps the given text in hyphens' do
|
225
|
+
expect(renderer.superscript("some normal freakin' text")).to eq(" ^some normal freakin' text^ ")
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'does not escape Confluence text effects' do
|
229
|
+
expect(renderer.superscript('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
230
|
+
eq(' ^bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??^ ')
|
231
|
+
)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
describe '#table(header, body)' do
|
236
|
+
it 'appends the body to the formatted header' do
|
237
|
+
expect(renderer.table("\n|header|", "\n|body|")).to eq("\n\n||header||\n|body|")
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'does not escape Confluence text effects' do
|
241
|
+
expect(renderer.table(
|
242
|
+
"\n|bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??|",
|
243
|
+
"\n|bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??|"
|
244
|
+
)).to(
|
245
|
+
eq("\n\n||bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??||\n|bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??|")
|
246
|
+
)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe '#table_row(text)' do
|
251
|
+
it 'prepends a pipe to the text' do
|
252
|
+
expect(renderer.table_row('text|')).to eq("\n|text|")
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'does not escape Confluence text effects' do
|
256
|
+
expect(renderer.table_row('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??|')).to(
|
257
|
+
eq("\n|bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??|")
|
258
|
+
)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe '#table_cell(text, align)' do
|
263
|
+
it 'appends a pipe to the text' do
|
264
|
+
expect(renderer.table_cell('text', :ignored)).to eq('text|')
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'does not escape Confluence text effects' do
|
268
|
+
expect(renderer.table_cell('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??', :ignored)).to(
|
269
|
+
eq('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??|')
|
270
|
+
)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe '#triple_emphasis(text)' do
|
275
|
+
it 'wraps the given text in asterisks and underscores' do
|
276
|
+
expect(renderer.triple_emphasis("some normal freakin' text")).to eq("_*some normal freakin' text*_")
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'does not escape Confluence text effects' do
|
280
|
+
expect(renderer.triple_emphasis('bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??')).to(
|
281
|
+
eq('_*bq. *some* _emphasized_ -text- +words+^like^~this~ {{and this}} ??Stegman??*_')
|
282
|
+
)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
data/spec/smoke_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'redcarpet/confluence'
|
3
|
+
|
4
|
+
describe 'Smoke Tests' do
|
5
|
+
let(:markdown_options) { {
|
6
|
+
autolink: true,
|
7
|
+
fenced_code_blocks: true,
|
8
|
+
no_intra_emphasis: true,
|
9
|
+
strikethrough: true,
|
10
|
+
superscript: true,
|
11
|
+
tables: true
|
12
|
+
} }
|
13
|
+
let(:renderer) { Redcarpet::Markdown.new(Redcarpet::Confluence, markdown_options) }
|
14
|
+
let(:markdown_text) { File.read(File.expand_path('../sample.md', __FILE__)).force_encoding('UTF-8') }
|
15
|
+
let(:confluence_text) { File.read(File.expand_path('../sample.confluence', __FILE__)).force_encoding('UTF-8') }
|
16
|
+
|
17
|
+
it 'renders the markdown into confluence correctly' do
|
18
|
+
expect(renderer.render(markdown_text)).to eq(confluence_text)
|
19
|
+
end
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
2
|
+
# in spec/support/ and its subdirectories.
|
3
|
+
Dir[File.join("support/**/*.rb")].each {|f| require f}
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
# Run specs in random order to surface order dependencies. If you find an
|
7
|
+
# order dependency and want to debug it, you can fix the order by providing
|
8
|
+
# the seed, which is printed after each run.
|
9
|
+
# --seed 1234
|
10
|
+
config.order = "random"
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redcarpet-confluence
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Stegman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redcarpet
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A Redcarpet renderer to convert Markdown to Confluence syntax.
|
56
|
+
email:
|
57
|
+
- me@adamstegman.com
|
58
|
+
executables:
|
59
|
+
- md2conf
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- lib/redcarpet/confluence.rb
|
64
|
+
- Gemfile
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- redcarpet-confluence.gemspec
|
68
|
+
- spec/redcarpet/confluence_spec.rb
|
69
|
+
- spec/smoke_spec.rb
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
- bin/md2conf
|
72
|
+
homepage: https://github.com/adamstegman/redcarpet-confluence
|
73
|
+
licenses: []
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.0.3
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: A Redcarpet renderer to convert Markdown to Confluence syntax.
|
95
|
+
test_files:
|
96
|
+
- spec/redcarpet/confluence_spec.rb
|
97
|
+
- spec/smoke_spec.rb
|
98
|
+
- spec/spec_helper.rb
|
99
|
+
has_rdoc:
|