reverse_markdown 0.2.1 → 0.3.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/.gitignore +6 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/README.md +49 -0
- data/Rakefile +5 -0
- data/lib/reverse_markdown.rb +14 -218
- data/lib/reverse_markdown/errors.rb +3 -0
- data/lib/reverse_markdown/mapper.rb +114 -0
- data/lib/reverse_markdown/version.rb +3 -0
- data/reverse_markdown.gemspec +27 -0
- data/spec/assets/anchors.html +10 -0
- data/spec/assets/basic.html +12 -0
- data/spec/assets/full_example.html +49 -0
- data/spec/assets/lists.html +27 -0
- data/spec/assets/minimum.html +4 -0
- data/spec/assets/paragraphs.html +12 -0
- data/spec/assets/quotation.html +12 -0
- data/spec/components/anchors_spec.rb +14 -0
- data/spec/components/basic_spec.rb +18 -0
- data/spec/components/lists_spec.rb +15 -0
- data/spec/components/paragraphs_spec.rb +11 -0
- data/spec/components/quotation_spec.rb +12 -0
- data/spec/mapper_spec.rb +39 -0
- data/spec/reverse_markdown_spec.rb +19 -0
- data/spec/spec_helper.rb +14 -0
- metadata +104 -12
- data/test/test.rb +0 -72
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Summary
|
2
|
+
|
3
|
+
Transform existing html into markdown in a simple way, for example if you want to import existings tags into your markdown based application.
|
4
|
+
|
5
|
+
[](http://travis-ci.org/#!/xijo/reverse_markdown)
|
6
|
+
|
7
|
+
# Installation
|
8
|
+
|
9
|
+
Install the gem:
|
10
|
+
|
11
|
+
[sudo] gem install reverse_markdown
|
12
|
+
|
13
|
+
If you want to use it in Rails context, add it to your Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'reverse_markdown'
|
17
|
+
```
|
18
|
+
|
19
|
+
# Synopsis
|
20
|
+
|
21
|
+
Given you have html content as string or Nokogiri document or element just pass it over to the module like this:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
ReverseMarkdown.parse content
|
25
|
+
````
|
26
|
+
|
27
|
+
However, the old syntax is still supported:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
ReverseMarkdown.parse_element content
|
31
|
+
ReverseMarkdown.parse_string content
|
32
|
+
````
|
33
|
+
|
34
|
+
# Tag support
|
35
|
+
|
36
|
+
Only basic html tags are supported right now. However, it should not be to difficult to add some. Feel free to contribute or notify me about missing stuff.
|
37
|
+
|
38
|
+
- supported tags: h1, h2, h3, h4, h5, h6, p, em, strong, blockquote, code, img, a, hr, li, ol, ul
|
39
|
+
- nested lists
|
40
|
+
- inline and block code
|
41
|
+
|
42
|
+
# See as well
|
43
|
+
|
44
|
+
- [wmd-editor](http://wmd-editor.com)
|
45
|
+
- [markdown syntax](http://daringfireball.net/projects/markdown)
|
46
|
+
|
47
|
+
# Thanks
|
48
|
+
|
49
|
+
..to Ben Woosley for his improvements to the first version.
|
data/Rakefile
ADDED
data/lib/reverse_markdown.rb
CHANGED
@@ -1,226 +1,22 @@
|
|
1
|
+
require 'reverse_markdown/version'
|
2
|
+
require 'reverse_markdown/mapper'
|
3
|
+
require 'reverse_markdown/errors'
|
1
4
|
require 'nokogiri'
|
2
5
|
|
3
|
-
|
4
|
-
# author: JO
|
5
|
-
# e-mail: xijo@gmx.de
|
6
|
-
# date: 14.7.2009
|
7
|
-
# version: 0.1
|
8
|
-
# license: GPL
|
9
|
-
# taken from https://github.com/xijo/reverse-markdown/raw/master/reverse_markdown.rb
|
6
|
+
module ReverseMarkdown
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
attr_reader :errors
|
17
|
-
|
18
|
-
class << self
|
19
|
-
def parse_string(string)
|
20
|
-
new.parse_string(string)
|
21
|
-
end
|
22
|
-
|
23
|
-
def parse_element(element)
|
24
|
-
new.parse_element(element)
|
8
|
+
def self.parse(input)
|
9
|
+
root = case input
|
10
|
+
when String then Nokogiri::HTML(input).root
|
11
|
+
when Nokogiri::XML::Document then input.root
|
12
|
+
when Nokogiri::XML::Node then input
|
25
13
|
end
|
14
|
+
ReverseMarkdown::Mapper.new.process_element(root)
|
26
15
|
end
|
27
16
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
# - @outout: fancy markdown code in here!
|
33
|
-
# - @indent: control indention level for nested lists
|
34
|
-
# - @errors: appearing errors, like unknown tags, go into this array
|
35
|
-
def initialize(options = {})
|
36
|
-
@options = {links: :inline}.merge(options)
|
37
|
-
@li_counter = 0
|
38
|
-
@links = []
|
39
|
-
@output = ""
|
40
|
-
@indent = 0
|
41
|
-
@errors = []
|
42
|
-
end
|
43
|
-
|
44
|
-
# Invokes the HTML parsing by using a string. Returns the markdown code in @output.
|
45
|
-
# To garantuee well-formed xml for REXML a <root> element will be added, but has no effect.
|
46
|
-
# After parsing all elements, the 'reference style'-links will be inserted.
|
47
|
-
def parse_string(string)
|
48
|
-
parse_element(Nokogiri::HTML.fragment(string))
|
49
|
-
insert_links
|
50
|
-
@output
|
51
|
-
end
|
52
|
-
|
53
|
-
# Parsing an element and its children (recursive) and writing its markdown code to @output
|
54
|
-
# 1. do indent for nested list items
|
55
|
-
# 2. add the markdown opening tag for this element
|
56
|
-
# 3a. if element only contains text, handle it like a text node
|
57
|
-
# 3b. if element is a container handle its children, which may be text- or element nodes
|
58
|
-
# 4. finally add the markdown ending tag for this element
|
59
|
-
def parse_element(element, parent = nil)
|
60
|
-
name = element.name.to_sym
|
61
|
-
# 1.
|
62
|
-
@output << (" " * @indent) if name.eql?(:li)
|
63
|
-
# 2.
|
64
|
-
@output << opening(element, parent)
|
65
|
-
|
66
|
-
# 3a.
|
67
|
-
if element.children.size == 1 && element.children.first.text?
|
68
|
-
@output << text_node(element, parent)
|
69
|
-
else
|
70
|
-
# 3b.
|
71
|
-
element.children.each do |child|
|
72
|
-
# increase indent if nested list
|
73
|
-
@indent += 1 if nested_list?(element, parent)
|
74
|
-
|
75
|
-
if child.element?
|
76
|
-
parse_element(child, element.name.to_sym)
|
77
|
-
else
|
78
|
-
@output <<
|
79
|
-
if parent.eql?(:blockquote)
|
80
|
-
child.inner_text.gsub("\n ", "\n>")
|
81
|
-
else
|
82
|
-
child.inner_text
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# decrease indent if end of nested list
|
87
|
-
@indent -= 1 if nested_list?(element, parent)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# 4.
|
92
|
-
@output << ending(element, parent)
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
|
97
|
-
def nested_list?(element, parent)
|
98
|
-
element.name=~/(ul|ol)/ and parent.eql?(:li)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Returns opening markdown tag for the element. Its parent matters sometimes!
|
102
|
-
def opening(type, parent_name)
|
103
|
-
case type.name.to_sym
|
104
|
-
when :h1
|
105
|
-
"# "
|
106
|
-
when :li
|
107
|
-
parent_name == :ul ? " - " : " "+(@li_counter+=1).to_s+". "
|
108
|
-
when :ol
|
109
|
-
@li_counter = 0
|
110
|
-
""
|
111
|
-
when :ul
|
112
|
-
""
|
113
|
-
when :h2
|
114
|
-
"## "
|
115
|
-
when :h3
|
116
|
-
"### "
|
117
|
-
when :h4
|
118
|
-
"#### "
|
119
|
-
when :h5
|
120
|
-
"##### "
|
121
|
-
when :h6
|
122
|
-
"###### "
|
123
|
-
when :em
|
124
|
-
"*"
|
125
|
-
when :strong
|
126
|
-
"**"
|
127
|
-
when :blockquote
|
128
|
-
# remove leading newline
|
129
|
-
type.children.first.content = ""
|
130
|
-
"> "
|
131
|
-
when :code
|
132
|
-
parent_name == :pre ? " " : "`"
|
133
|
-
when :a
|
134
|
-
"["
|
135
|
-
when :img
|
136
|
-
"!["
|
137
|
-
when :hr
|
138
|
-
"----------\n\n"
|
139
|
-
else
|
140
|
-
@errors << "unknown start tag: "+type.name.to_s
|
141
|
-
""
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# Returns the closing markdown tag, like opening()
|
146
|
-
def ending(type, parent)
|
147
|
-
case type.name.to_sym
|
148
|
-
when :h1
|
149
|
-
" #\n\n"
|
150
|
-
when :h2
|
151
|
-
" ##\n\n"
|
152
|
-
when :h3
|
153
|
-
" ###\n\n"
|
154
|
-
when :h4
|
155
|
-
" ####\n\n"
|
156
|
-
when :h5
|
157
|
-
" #####\n\n"
|
158
|
-
when :h6
|
159
|
-
" ######\n\n"
|
160
|
-
when :p
|
161
|
-
parent.eql?(:root) ? "\n\n" : "\n"
|
162
|
-
when :ol
|
163
|
-
parent.eql?(:li) ? "" : "\n"
|
164
|
-
when :ul
|
165
|
-
parent.eql?(:li) ? "" : "\n"
|
166
|
-
when :em
|
167
|
-
"*"
|
168
|
-
when :strong
|
169
|
-
"**"
|
170
|
-
when :li
|
171
|
-
""
|
172
|
-
when :blockquote
|
173
|
-
""
|
174
|
-
when :code
|
175
|
-
parent.eql?(:pre) ? "" : "`"
|
176
|
-
when :a
|
177
|
-
if @options[:links] == :inline
|
178
|
-
"](#{type['href']})"
|
179
|
-
else
|
180
|
-
@links << type['href']
|
181
|
-
"][#{@links.size}] "
|
182
|
-
end
|
183
|
-
when :img
|
184
|
-
@links << type['src']
|
185
|
-
"#{type['alt']}][#{@links.size}] "
|
186
|
-
else
|
187
|
-
@errors << " unknown end tag: "+type.name.to_s
|
188
|
-
""
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
# Return the content of element, which should be just text.
|
193
|
-
# If its a code block to indent of 4 spaces.
|
194
|
-
# For block quotation add a leading '>'
|
195
|
-
def text_node(element, parent)
|
196
|
-
text_node = element.children.first
|
197
|
-
if text_node.text?
|
198
|
-
text = text_node.text
|
199
|
-
if element.name.to_sym.eql?(:code) and parent.eql?(:pre)
|
200
|
-
text.gsub("\n","\n ") << "\n"
|
201
|
-
elsif parent.eql?(:blockquote)
|
202
|
-
text.gsub!("\n ","\n>")
|
203
|
-
else
|
204
|
-
text
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Insert the mentioned reference style links.
|
210
|
-
def insert_links
|
211
|
-
@output << "\n"
|
212
|
-
@output << @links.each_with_index.map do |link, index|
|
213
|
-
" [#{index+1}]: #{link}\n"
|
214
|
-
end.join
|
215
|
-
end
|
216
|
-
|
217
|
-
# Perform a benchmark on a given string n-times.
|
218
|
-
def speed_benchmark(string, n)
|
219
|
-
require 'benchmark'
|
220
|
-
initialize()
|
221
|
-
Benchmark.bm(15) do |test|
|
222
|
-
test.report("reverse markdown:") { n.times do; parse_string(string); initialize(); end; }
|
223
|
-
end
|
17
|
+
# 2012/08/11 joe: possibly deprecate in favour of #parse
|
18
|
+
class << self
|
19
|
+
alias parse_string parse
|
20
|
+
alias parse_element parse
|
224
21
|
end
|
225
|
-
|
226
22
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module ReverseMarkdown
|
2
|
+
class Mapper
|
3
|
+
attr_accessor :raise_errors
|
4
|
+
attr_accessor :log_enabled, :log_level
|
5
|
+
attr_accessor :li_counter
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
self.log_level = :info
|
9
|
+
self.log_enabled = true
|
10
|
+
self.li_counter = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def process_element(element)
|
14
|
+
output = ''
|
15
|
+
output << if element.text?
|
16
|
+
element.text.strip
|
17
|
+
else
|
18
|
+
opening(element)
|
19
|
+
end
|
20
|
+
element.children.each do |child|
|
21
|
+
output << process_element(child)
|
22
|
+
end
|
23
|
+
output << ending(element) unless element.text?
|
24
|
+
output
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def opening(element)
|
30
|
+
parent = element.parent ? element.parent.name.to_sym : nil
|
31
|
+
case element.name.to_sym
|
32
|
+
when :html, :body
|
33
|
+
""
|
34
|
+
when :li
|
35
|
+
indent = ' ' * [(element.ancestors('ol').count + element.ancestors('ul').count - 1), 0].max
|
36
|
+
if parent == :ol
|
37
|
+
"#{indent}#{self.li_counter += 1}. "
|
38
|
+
else
|
39
|
+
"#{indent}- "
|
40
|
+
end
|
41
|
+
when :pre
|
42
|
+
"\n"
|
43
|
+
when :ol
|
44
|
+
self.li_counter = 0
|
45
|
+
"\n"
|
46
|
+
when :ul, :root#, :p
|
47
|
+
"\n"
|
48
|
+
when :p
|
49
|
+
if element.ancestors.map(&:name).include?('blockquote')
|
50
|
+
"\n\n> "
|
51
|
+
else
|
52
|
+
"\n\n"
|
53
|
+
end
|
54
|
+
when :h1, :h2, :h3, :h4 # /h(\d)/ for 1.9
|
55
|
+
element.name =~ /h(\d)/
|
56
|
+
'#' * $1.to_i + ' '
|
57
|
+
when :em
|
58
|
+
"*"
|
59
|
+
when :strong
|
60
|
+
"**"
|
61
|
+
when :blockquote
|
62
|
+
"> "
|
63
|
+
when :code
|
64
|
+
parent == :pre ? " " : "`"
|
65
|
+
when :a
|
66
|
+
"["
|
67
|
+
when :img
|
68
|
+
".to_s}) "
|
94
|
+
when :img
|
95
|
+
if element.has_attribute?('alt')
|
96
|
+
"#{element.attribute('alt')}][#{element.attribute('src')}] "
|
97
|
+
else
|
98
|
+
"#{element.attribute('src')}] "
|
99
|
+
end
|
100
|
+
else
|
101
|
+
handle_error "unknown end tag: #{element.name}"
|
102
|
+
""
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def handle_error(message)
|
107
|
+
if raise_errors
|
108
|
+
raise ReverseMarkdown::ParserError, message
|
109
|
+
elsif log_enabled && defined?(Rails)
|
110
|
+
Rails.logger.__send__(log_level, message)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "reverse_markdown/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "reverse_markdown"
|
7
|
+
s.version = ReverseMarkdown::VERSION
|
8
|
+
s.authors = ["Johannes Opper"]
|
9
|
+
s.email = ["xijo@gmx.de"]
|
10
|
+
s.homepage = "http://github.com/xijo/reverse_markdown"
|
11
|
+
s.summary = %q{Transform html code into markdown.}
|
12
|
+
s.description = %q{Map simple html back into markdown, e.g. if you want to import existing html data in your application.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "reverse_markdown"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_dependency 'nokogiri'
|
23
|
+
s.add_development_dependency 'rspec'
|
24
|
+
s.add_development_dependency 'simplecov'
|
25
|
+
s.add_development_dependency 'rake'
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<html>
|
2
|
+
<body>
|
3
|
+
<ul>
|
4
|
+
<li>li 1</li>
|
5
|
+
<li>li 2</li>
|
6
|
+
<li>li 3</li>
|
7
|
+
</ul>
|
8
|
+
<ul>
|
9
|
+
<li>li 1</li>
|
10
|
+
<li>li 2</li>
|
11
|
+
<li>li 3</li>
|
12
|
+
</ul>
|
13
|
+
<ol>
|
14
|
+
<li>li 1</li>
|
15
|
+
<li>
|
16
|
+
<ul>
|
17
|
+
<li>eins</li>
|
18
|
+
<li>eins</li>
|
19
|
+
<li>eins</li>
|
20
|
+
</ul>
|
21
|
+
</li>
|
22
|
+
</ol>
|
23
|
+
<ol>
|
24
|
+
<li>li 1</li>
|
25
|
+
<li>li 2</li>
|
26
|
+
</ol>
|
27
|
+
<h1>h1</h1>
|
28
|
+
<h2>h2</h2>
|
29
|
+
<h3>h3</h3>
|
30
|
+
<h4>h4</h4>
|
31
|
+
<p>
|
32
|
+
Hallo <em>em</em> Text
|
33
|
+
</p>
|
34
|
+
<p>
|
35
|
+
<strong>strong</strong>
|
36
|
+
</p>
|
37
|
+
<pre>
|
38
|
+
<code>Block of code</code>
|
39
|
+
</pre>
|
40
|
+
|
41
|
+
<blockquote>
|
42
|
+
<p>First quoted paragraph</p>
|
43
|
+
<p>Second quoted paragraph</p>
|
44
|
+
</blockquote>
|
45
|
+
<a href="http://www.bla.com">link</a>
|
46
|
+
<img src="http://raw.com">
|
47
|
+
<hr>
|
48
|
+
</body>
|
49
|
+
</html>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<html>
|
2
|
+
<body>
|
3
|
+
<ul>
|
4
|
+
<li>unordered list entry</li>
|
5
|
+
<li>unordered list entry</li>
|
6
|
+
</ul>
|
7
|
+
|
8
|
+
<ol>
|
9
|
+
<li>ordered list entry</li>
|
10
|
+
<li>ordered list entry</li>
|
11
|
+
</ol>
|
12
|
+
|
13
|
+
<ol>
|
14
|
+
<li>list entry 1st hierarchy</li>
|
15
|
+
<li>
|
16
|
+
<ul>
|
17
|
+
<li>nested unsorted list entry</li>
|
18
|
+
<li>
|
19
|
+
<ol>
|
20
|
+
<li>deep nested list entry</li>
|
21
|
+
<ol>
|
22
|
+
</li>
|
23
|
+
</ul>
|
24
|
+
</li>
|
25
|
+
</ol>
|
26
|
+
</body>
|
27
|
+
</html>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReverseMarkdown::Mapper do
|
4
|
+
|
5
|
+
let(:input) { File.read('spec/assets/anchors.html') }
|
6
|
+
let(:document) { Nokogiri::HTML(input) }
|
7
|
+
subject { ReverseMarkdown.parse_string(input) }
|
8
|
+
|
9
|
+
it { subject.should include '[Foobar](http://foobar.com)' }
|
10
|
+
it { subject.should include '[**Strong foobar**](http://strong.foobar.com)' }
|
11
|
+
it { subject.should include '![http://foobar.com/logo.png]' }
|
12
|
+
it { subject.should include '![foobar image][http://foobar.com/foobar.png]' }
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReverseMarkdown::Mapper do
|
4
|
+
|
5
|
+
let(:input) { File.read('spec/assets/basic.html') }
|
6
|
+
let(:document) { Nokogiri::HTML(input) }
|
7
|
+
subject { ReverseMarkdown.parse_string(input) }
|
8
|
+
|
9
|
+
it { subject.should match /# h1\n/ }
|
10
|
+
it { subject.should match /## h2\n/ }
|
11
|
+
it { subject.should match /### h3\n/ }
|
12
|
+
it { subject.should match /#### h4\n/ }
|
13
|
+
it { subject.should match /\*em\*/ }
|
14
|
+
it { subject.should match /\*\*strong\*\*/ }
|
15
|
+
it { subject.should match /`code`/ }
|
16
|
+
it { subject.should match /---/ }
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReverseMarkdown::Mapper do
|
4
|
+
|
5
|
+
let(:input) { File.read('spec/assets/lists.html') }
|
6
|
+
let(:document) { Nokogiri::HTML(input) }
|
7
|
+
subject { ReverseMarkdown.parse_string(input) }
|
8
|
+
|
9
|
+
it { subject.should match /- unordered list entry\n/ }
|
10
|
+
it { subject.should match /1. ordered list entry\n/ }
|
11
|
+
it { subject.should match /1. list entry 1st hierarchy\n/ }
|
12
|
+
it { subject.should match /\s{2}- nested unsorted list entry/ }
|
13
|
+
it { subject.should match /\s{4}1. deep nested list entry/ }
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReverseMarkdown::Mapper do
|
4
|
+
|
5
|
+
let(:input) { File.read('spec/assets/paragraphs.html') }
|
6
|
+
let(:document) { Nokogiri::HTML(input) }
|
7
|
+
subject { ReverseMarkdown.parse_string(input) }
|
8
|
+
|
9
|
+
it { subject.should match /First content\n\nSecond content\n\n/ }
|
10
|
+
it { subject.should include "\n\n*Complex*\n Content" }
|
11
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReverseMarkdown::Mapper do
|
4
|
+
|
5
|
+
let(:input) { File.read('spec/assets/quotation.html') }
|
6
|
+
let(:document) { Nokogiri::HTML(input) }
|
7
|
+
subject { ReverseMarkdown.parse_string(input) }
|
8
|
+
|
9
|
+
it { subject.should include "\n Block of code" }
|
10
|
+
it { subject.should include "\n> First quoted paragraph\n\n> Second quoted paragraph" }
|
11
|
+
|
12
|
+
end
|
data/spec/mapper_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReverseMarkdown::Mapper do
|
4
|
+
let(:input) { File.read('spec/assets/minimum.html') }
|
5
|
+
let(:document) { Nokogiri::HTML(input) }
|
6
|
+
let(:mapper) { ReverseMarkdown::Mapper.new }
|
7
|
+
|
8
|
+
context "error handling" do
|
9
|
+
|
10
|
+
let(:unknown_element) { Nokogiri::XML::Node.new('foo', document) }
|
11
|
+
|
12
|
+
it "raises error if told so" do
|
13
|
+
mapper.raise_errors = true
|
14
|
+
expect {
|
15
|
+
mapper.__send__(:opening, unknown_element)
|
16
|
+
}.to raise_error(ReverseMarkdown::ParserError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "supresses errors if told so" do
|
20
|
+
mapper.raise_errors = false
|
21
|
+
expect {
|
22
|
+
mapper.__send__(:opening, unknown_element)
|
23
|
+
}.not_to raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
context "with Rails present" do
|
27
|
+
|
28
|
+
module Rails # Fake Rails for specs
|
29
|
+
def self.logger; @@logger ||= Logger.new; end
|
30
|
+
class Logger; def info(message); end; end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "logs with Rails.logger if present" do
|
34
|
+
Rails.logger.should_receive(:info)
|
35
|
+
mapper.__send__(:ending, unknown_element)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ReverseMarkdown do
|
4
|
+
let(:input) { File.read('spec/assets/minimum.html') }
|
5
|
+
let(:document) { Nokogiri::HTML(input) }
|
6
|
+
|
7
|
+
it "parses nokogiri documents" do
|
8
|
+
lambda { ReverseMarkdown.parse_element(document) }.should_not raise_error
|
9
|
+
end
|
10
|
+
|
11
|
+
it "parses nokogiri elements" do
|
12
|
+
lambda { ReverseMarkdown.parse_element(document.root) }.should_not raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "parses string input" do
|
16
|
+
lambda { ReverseMarkdown.parse_string(input) }.should_not raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
SimpleCov.adapters.define 'gem' do
|
4
|
+
add_filter '/spec/'
|
5
|
+
add_filter '/autotest/'
|
6
|
+
add_group 'Libraries', '/lib/'
|
7
|
+
end
|
8
|
+
SimpleCov.start 'gem'
|
9
|
+
|
10
|
+
require 'reverse_markdown'
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.color_enabled = true
|
14
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reverse_markdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
9
|
-
- Ben Woosley
|
8
|
+
- Johannes Opper
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2012-
|
12
|
+
date: 2012-08-13 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: nokogiri
|
@@ -28,15 +27,88 @@ dependencies:
|
|
28
27
|
- - ! '>='
|
29
28
|
- !ruby/object:Gem::Version
|
30
29
|
version: '0'
|
31
|
-
|
32
|
-
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: simplecov
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Map simple html back into markdown, e.g. if you want to import existing
|
79
|
+
html data in your application.
|
80
|
+
email:
|
81
|
+
- xijo@gmx.de
|
33
82
|
executables: []
|
34
83
|
extensions: []
|
35
84
|
extra_rdoc_files: []
|
36
85
|
files:
|
86
|
+
- .gitignore
|
87
|
+
- .travis.yml
|
88
|
+
- Gemfile
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
37
91
|
- lib/reverse_markdown.rb
|
38
|
-
-
|
39
|
-
|
92
|
+
- lib/reverse_markdown/errors.rb
|
93
|
+
- lib/reverse_markdown/mapper.rb
|
94
|
+
- lib/reverse_markdown/version.rb
|
95
|
+
- reverse_markdown.gemspec
|
96
|
+
- spec/assets/anchors.html
|
97
|
+
- spec/assets/basic.html
|
98
|
+
- spec/assets/full_example.html
|
99
|
+
- spec/assets/lists.html
|
100
|
+
- spec/assets/minimum.html
|
101
|
+
- spec/assets/paragraphs.html
|
102
|
+
- spec/assets/quotation.html
|
103
|
+
- spec/components/anchors_spec.rb
|
104
|
+
- spec/components/basic_spec.rb
|
105
|
+
- spec/components/lists_spec.rb
|
106
|
+
- spec/components/paragraphs_spec.rb
|
107
|
+
- spec/components/quotation_spec.rb
|
108
|
+
- spec/mapper_spec.rb
|
109
|
+
- spec/reverse_markdown_spec.rb
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
homepage: http://github.com/xijo/reverse_markdown
|
40
112
|
licenses: []
|
41
113
|
post_install_message:
|
42
114
|
rdoc_options: []
|
@@ -48,17 +120,37 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
120
|
- - ! '>='
|
49
121
|
- !ruby/object:Gem::Version
|
50
122
|
version: '0'
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
hash: -1059485323114314033
|
51
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
127
|
none: false
|
53
128
|
requirements:
|
54
129
|
- - ! '>='
|
55
130
|
- !ruby/object:Gem::Version
|
56
131
|
version: '0'
|
132
|
+
segments:
|
133
|
+
- 0
|
134
|
+
hash: -1059485323114314033
|
57
135
|
requirements: []
|
58
|
-
rubyforge_project:
|
59
|
-
rubygems_version: 1.8.
|
136
|
+
rubyforge_project: reverse_markdown
|
137
|
+
rubygems_version: 1.8.24
|
60
138
|
signing_key:
|
61
139
|
specification_version: 3
|
62
|
-
summary:
|
140
|
+
summary: Transform html code into markdown.
|
63
141
|
test_files:
|
64
|
-
-
|
142
|
+
- spec/assets/anchors.html
|
143
|
+
- spec/assets/basic.html
|
144
|
+
- spec/assets/full_example.html
|
145
|
+
- spec/assets/lists.html
|
146
|
+
- spec/assets/minimum.html
|
147
|
+
- spec/assets/paragraphs.html
|
148
|
+
- spec/assets/quotation.html
|
149
|
+
- spec/components/anchors_spec.rb
|
150
|
+
- spec/components/basic_spec.rb
|
151
|
+
- spec/components/lists_spec.rb
|
152
|
+
- spec/components/paragraphs_spec.rb
|
153
|
+
- spec/components/quotation_spec.rb
|
154
|
+
- spec/mapper_spec.rb
|
155
|
+
- spec/reverse_markdown_spec.rb
|
156
|
+
- spec/spec_helper.rb
|
data/test/test.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require './lib/reverse_markdown'
|
4
|
-
|
5
|
-
# Example HTML Code for parsing
|
6
|
-
example = <<-EOF
|
7
|
-
This text, though not within an element, should also be shown.
|
8
|
-
|
9
|
-
<h2>heading 1.1</h2>
|
10
|
-
|
11
|
-
<p>text *italic* and **bold**.</p>
|
12
|
-
|
13
|
-
<pre><code>text *italic* and **bold**.
|
14
|
-
sdfsdff
|
15
|
-
sdfsd
|
16
|
-
sdf sdfsdf
|
17
|
-
</code></pre>
|
18
|
-
|
19
|
-
<blockquote>
|
20
|
-
<p>text <em>italic</em> and <strong>bold</strong>. sdfsdff
|
21
|
-
sdfsd sdf sdfsdf</p>
|
22
|
-
</blockquote>
|
23
|
-
|
24
|
-
<p>asdasd <code>sdfsdfsdf</code> asdad <a href="http://www.bla.de">link text</a></p>
|
25
|
-
|
26
|
-
<p><a href="http://www.bla.de">link <strong>text</strong></a></p>
|
27
|
-
|
28
|
-
<ol>
|
29
|
-
<li>List item</li>
|
30
|
-
<li>List <em>item</em>
|
31
|
-
<ol><li>List item</li>
|
32
|
-
<li>dsfdsf
|
33
|
-
<ul><li>dfwe</li>
|
34
|
-
<li>dsfsdfsdf</li></ul></li>
|
35
|
-
<li>lidsf <img src="http://www.dfgdfg.de/dsf.jpe" alt="item" title="" /></li></ol></li>
|
36
|
-
<li>sdfsdfsdf
|
37
|
-
<ul><li>sdfsdfsdf</li>
|
38
|
-
<li>sdfsdfsdf <strong>sdfsdf</strong></li></ul></li>
|
39
|
-
</ol>
|
40
|
-
|
41
|
-
<blockquote>
|
42
|
-
<p>Lorem ipsum dolor sit amet, consetetur
|
43
|
-
voluptua. At vero eos et accusam et
|
44
|
-
justo duo dolores et ea rebum. Stet
|
45
|
-
clita kasd gubergren, no sea takimata
|
46
|
-
sanctus est Lorem ipsum dolor sit
|
47
|
-
amet. <em>italic</em></p>
|
48
|
-
</blockquote>
|
49
|
-
|
50
|
-
<hr />
|
51
|
-
|
52
|
-
<blockquote>
|
53
|
-
<p>Lorem ipsum dolor sit amet, consetetur
|
54
|
-
sadipscing elitr, sed diam nonumy
|
55
|
-
eirmod tempor invidunt ut labore et
|
56
|
-
dolore magna aliquyam erat, sed</p>
|
57
|
-
</blockquote>
|
58
|
-
|
59
|
-
This should also be shown, even if it's not wrapped in an element.
|
60
|
-
|
61
|
-
<p>nur ein text! nur eine maschine!</p>
|
62
|
-
|
63
|
-
This text should not be invisible!
|
64
|
-
EOF
|
65
|
-
|
66
|
-
r = ReverseMarkdown.new
|
67
|
-
|
68
|
-
puts r.parse_string(example)
|
69
|
-
|
70
|
-
#r.print_errors
|
71
|
-
|
72
|
-
#r.speed_benchmark(example, 100)
|