minidown 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +9 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +73 -0
  7. data/Rakefile +4 -0
  8. data/bin/minidown +33 -0
  9. data/lib/minidown.rb +13 -0
  10. data/lib/minidown/document.rb +142 -0
  11. data/lib/minidown/element.rb +40 -0
  12. data/lib/minidown/elements.rb +15 -0
  13. data/lib/minidown/elements/block_element.rb +37 -0
  14. data/lib/minidown/elements/code_block_element.rb +44 -0
  15. data/lib/minidown/elements/dividing_line_element.rb +11 -0
  16. data/lib/minidown/elements/html_element.rb +22 -0
  17. data/lib/minidown/elements/indent_code_element.rb +23 -0
  18. data/lib/minidown/elements/line_element.rb +28 -0
  19. data/lib/minidown/elements/list_element.rb +36 -0
  20. data/lib/minidown/elements/list_group_element.rb +87 -0
  21. data/lib/minidown/elements/order_list_element.rb +20 -0
  22. data/lib/minidown/elements/paragraph_element.rb +56 -0
  23. data/lib/minidown/elements/raw_html_element.rb +11 -0
  24. data/lib/minidown/elements/table_element.rb +80 -0
  25. data/lib/minidown/elements/text_element.rb +198 -0
  26. data/lib/minidown/elements/unorder_list_element.rb +31 -0
  27. data/lib/minidown/html_helper.rb +18 -0
  28. data/lib/minidown/parser.rb +19 -0
  29. data/lib/minidown/utils.rb +28 -0
  30. data/lib/minidown/version.rb +3 -0
  31. data/minidown.gemspec +26 -0
  32. data/spec/blank_line_spec.rb +21 -0
  33. data/spec/code_block_spec.rb +182 -0
  34. data/spec/dividing_line_spec.rb +35 -0
  35. data/spec/h1_and_h2_spec.rb +55 -0
  36. data/spec/indent_block_spec.rb +17 -0
  37. data/spec/li_spec.rb +354 -0
  38. data/spec/minidown_spec.rb +12 -0
  39. data/spec/paragraph_spec.rb +17 -0
  40. data/spec/raw_html_spec.rb +43 -0
  41. data/spec/spec_helper.rb +2 -0
  42. data/spec/start_with_gt_spec.rb +70 -0
  43. data/spec/start_with_shape_spec.rb +42 -0
  44. data/spec/table_spec.rb +63 -0
  45. data/spec/task_list_spec.rb +18 -0
  46. data/spec/text_element_spec.rb +317 -0
  47. metadata +175 -0
@@ -0,0 +1,31 @@
1
+ module Minidown
2
+ class UnorderListElement < ListGroupElement
3
+ TaskRegexp = /\A\[([ x])\](.+)/
4
+ NestRegexp = /\A(\s*)[*\-+]\s+(.+)/
5
+ ListRegexp = Minidown::Utils::Regexp[:unorder_list]
6
+
7
+ def initialize doc, line, indent_level = 0
8
+ super doc, line
9
+ if content =~ TaskRegexp
10
+ @task_ul ||= true
11
+ list = ListElement.new(doc, $2)
12
+ list.task_list = true
13
+ list.checked = ($1 == 'x'.freeze)
14
+ else
15
+ list = ListElement.new(doc, content)
16
+ end
17
+ @children << list
18
+ @lists = @children.dup
19
+ @indent_level = indent_level
20
+ @put_back = []
21
+ end
22
+
23
+ def to_html
24
+ attr = nil
25
+ attr = {class: 'task-list'.freeze} if @task_ul
26
+ build_tag 'ul'.freeze, attr do |content|
27
+ children.each { |child| content << child.to_html}
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,18 @@
1
+ module Minidown
2
+ module HtmlHelper
3
+ def build_tag name, attr = nil
4
+ content = ''
5
+ yield content if block_given?
6
+ if attr
7
+ attr = attr.map{|k, v| "#{k}=\"#{v}\""}.join ' '.freeze
8
+ "<#{name} #{attr}>#{content}</#{name}>"
9
+ else
10
+ "<#{name}>#{content}</#{name}>"
11
+ end
12
+ end
13
+
14
+ def br_tag
15
+ '<br>'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module Minidown
2
+ class Parser
3
+ def initialize options = {}
4
+ @options = options.freeze
5
+ end
6
+
7
+ def render str
8
+ parse(str).to_html
9
+ end
10
+
11
+ protected
12
+ def parse str
13
+ lines = str.split Utils::Regexp[:lines]
14
+ doc = Document.new lines, @options
15
+ doc.parse
16
+ doc
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module Minidown
2
+ module Utils
3
+ Regexp = {
4
+ lines: /\n|\r\n/,
5
+ blank_line: /\A\s*\z/,
6
+ raw_html: /\A\s*(\<(?=[^\<\>]).+(?<=[^\<\>])\>)*\s*\z/,
7
+ h1_or_h2: /\A([=-]{3,})(.*)/,
8
+ start_with_shape: /\A(\#{1,6})\s*(.+?)\s*#*\z/,
9
+ start_with_quote: /\A\>\s*(.+)/,
10
+ unorder_list: /\A(\s*)[*\-+]\s+(.+)/,
11
+ order_list: /\A(\s*)\d+\.\s+(.+)/,
12
+ code_block: /\A\s*[`~]{3,}\s*(\S*)/,
13
+ table: /\A\|?([^\|]+(?:\|[^\|]*)*)\|?\s*\z/,
14
+ dividing_line: /\A(\s*[*-]\s*){3,}\z/,
15
+ indent_code: /\A\s{4}(.+)/,
16
+ pipe_symbol: /\|/
17
+ }.freeze
18
+
19
+ class << self
20
+ def escape_html str
21
+ sanitized_str = str.dup
22
+ sanitized_str.gsub! "<".freeze, "&lt;".freeze
23
+ sanitized_str.gsub! ">".freeze, "&gt;".freeze
24
+ sanitized_str
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module Minidown
2
+ VERSION = "2.1.1"
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'minidown/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "minidown"
8
+ spec.version = Minidown::VERSION
9
+ spec.authors = ["jjy"]
10
+ spec.email = ["jjyruby@gmail.com"]
11
+ spec.description = %q{Minidown is a lightweight & fast markdown parser, with complete GFM support.}
12
+ spec.summary = %q{Minidown is a lightweight & fast markdown parser, with complete GFM support.}
13
+ spec.homepage = "https://github.com/jjyr/minidown"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "pry-nav"
26
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minidown do
4
+ describe 'blank line' do
5
+ it 'should parse as nothing' do
6
+ ['', "\n", "\n\n", "\n\n\n\n"].each do |str|
7
+ Minidown.render(str).should == ''
8
+ end
9
+ end
10
+
11
+ it 'should be ignore when blank is the first line' do
12
+ str = "\na"
13
+ Minidown.render(str).should == "<p>a</p>"
14
+ str = "\n\n h"
15
+ Minidown.render(str).should == "<p> h</p>"
16
+ ["\n \n", "\n \n\n\n"].each do |str|
17
+ Minidown.render(str).should == "#{str.split(Minidown::Utils::Regexp[:lines]).last}".strip
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minidown do
4
+ describe 'code_block' do
5
+ it 'should parse correct' do
6
+ str =<<HERE
7
+ ```
8
+ should in code block
9
+
10
+ in block
11
+ ```
12
+ HERE
13
+ Minidown.render(str).should == "<pre><code>should in code block\n\nin block</code></pre>"
14
+ end
15
+
16
+ it 'should allow tildes as well as backquotes' do
17
+ str =<<HERE
18
+ ~~~
19
+ should in code block
20
+
21
+ in block
22
+ ~~~
23
+ HERE
24
+ Minidown.render(str).should == "<pre><code>should in code block\n\nin block</code></pre>"
25
+ end
26
+
27
+ it 'should allow arbitrary number of `' do
28
+ str =<<HERE
29
+ ````````````
30
+ should in code block
31
+
32
+ in block
33
+ ````````````
34
+ HERE
35
+ Minidown.render(str).should == "<pre><code>should in code block\n\nin block</code></pre>"
36
+ end
37
+
38
+ it 'should allow arbitrary number of tildes' do
39
+ str =<<HERE
40
+ ~~~~~~~~~~~
41
+ should in code block
42
+
43
+ in block
44
+ ~~~~~~~~~~~
45
+ HERE
46
+ Minidown.render(str).should == "<pre><code>should in code block\n\nin block</code></pre>"
47
+ end
48
+
49
+
50
+ it 'should ignore space' do
51
+ str =<<HERE
52
+ ```
53
+ should in code block
54
+ in block
55
+ ```
56
+ HERE
57
+ Minidown.render(str).should == "<pre><code>should in code block\nin block</code></pre>"
58
+ end
59
+
60
+ it 'should have lang attribute' do
61
+ str =<<HERE
62
+ ``` ruby
63
+ should in code block
64
+
65
+ in block
66
+ ```
67
+ HERE
68
+ Minidown.render(str).should == "<pre><code class=\"ruby\">should in code block\n\nin block</code></pre>"
69
+ end
70
+
71
+ it 'should have lang attribute with tildes' do
72
+ str =<<HERE
73
+ ~~~ ruby
74
+ should in code block
75
+
76
+ in block
77
+ ~~~
78
+ HERE
79
+ Minidown.render(str).should == "<pre><code class=\"ruby\">should in code block\n\nin block</code></pre>"
80
+ end
81
+
82
+ it 'should allow escape' do
83
+ str =<<HERE
84
+ \\```
85
+ should in code block
86
+
87
+ in block
88
+ \\```
89
+ HERE
90
+ Minidown.render(str).should == "<p>```<br>should in code block</p><p>in block<br>```</p>"
91
+ str =<<HERE
92
+ \\~~~
93
+ should in code block
94
+
95
+ in block
96
+ \\~~~
97
+ HERE
98
+ Minidown.render(str).should == "<p>~~~<br>should in code block</p><p>in block<br>~~~</p>"
99
+ end
100
+
101
+ it 'should not escape content' do
102
+ str =<<HERE
103
+ ```
104
+ \\+
105
+ \\.
106
+ \\-
107
+ \\*
108
+ <>
109
+ ```
110
+ HERE
111
+ Minidown.render(str).should == "<pre><code>\\+\n\\.\n\\-\n\\*\n&lt;&gt;</code></pre>"
112
+ str =<<HERE
113
+ ~~~
114
+ \\+
115
+ \\.
116
+ \\-
117
+ \\*
118
+ <>
119
+ ~~~
120
+ HERE
121
+ Minidown.render(str).should == "<pre><code>\\+\n\\.\n\\-\n\\*\n&lt;&gt;</code></pre>"
122
+ end
123
+
124
+ it 'should escape html tag' do
125
+ str ='```
126
+ <a>hello</a>
127
+ ```'
128
+ Minidown.render(str).should == "<pre><code>&lt;a&gt;hello&lt;/a&gt;</code></pre>"
129
+ str ='~~~
130
+ <a>hello</a>
131
+ ~~~'
132
+ Minidown.render(str).should == "<pre><code>&lt;a&gt;hello&lt;/a&gt;</code></pre>"
133
+ end
134
+
135
+ it 'should not auto convert' do
136
+ str = '```
137
+ jjyruby@gmail.com
138
+ ```'
139
+ Minidown.render(str).should == '<pre><code>jjyruby@gmail.com</code></pre>'
140
+ str = '~~~
141
+ jjyruby@gmail.com
142
+ ~~~'
143
+ Minidown.render(str).should == '<pre><code>jjyruby@gmail.com</code></pre>'
144
+ end
145
+
146
+ describe "work with code block handler" do
147
+ it "work with handler" do
148
+ str = '``` ruby
149
+ puts "We love ruby!"
150
+ ```'
151
+ handler = ->(lang, content){"`#{content}` is write in #{lang}"}
152
+ Minidown.render(str, code_block_handler: handler).should == '`puts "We love ruby!"` is write in ruby'
153
+ end
154
+
155
+ it "lang should return empty if not specific language" do
156
+ str = '```
157
+ not specific language
158
+ ```'
159
+ handler = ->(lang, content){ "#{content}, so lang is #{lang.inspect}" }
160
+ Minidown.render(str, code_block_handler: handler).should == 'not specific language, so lang is nil'
161
+ end
162
+
163
+ it "handler should pass raw content" do
164
+ str = '```
165
+ <script>
166
+ ```'
167
+ handler = ->(lang, content){ content.gsub("<", "{").gsub(">", "}") }
168
+ Minidown.render(str, code_block_handler: handler).should == '{script}'
169
+ end
170
+
171
+ it "should not escape <>" do
172
+ test_cases = %w{<script> <> < >}
173
+ handler = ->(lang, content){ content }
174
+ parser = Minidown::Parser.new(code_block_handler: handler)
175
+ test_cases.each do |case_s|
176
+ str = "```\n#{case_s}\n```"
177
+ parser.render(str).should == case_s
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minidown do
4
+ describe 'dividing line' do
5
+ it 'parsed correct' do
6
+ str = '***'
7
+ Minidown.render(str).should == '<hr>'
8
+ str = '---'
9
+ Minidown.render(str).should == '<hr>'
10
+ str = ' *** '
11
+ Minidown.render(str).should == '<hr>'
12
+ str = ' * * * '
13
+ Minidown.render(str).should == '<hr>'
14
+ str = ' -- - '
15
+ Minidown.render(str).should == '<hr>'
16
+ str = '----'
17
+ Minidown.render(str).should == '<hr>'
18
+ end
19
+
20
+ it 'should not parse if any other character' do
21
+ str = 'f---'
22
+ Minidown.render(str).should == '<p>f---</p>'
23
+
24
+ str = '* * *z'
25
+ Minidown.render(str).should == '<ul><li><em> </em>z</li></ul>'
26
+ end
27
+
28
+ it 'should allow escape' do
29
+ str = "\\----"
30
+ Minidown.render(str).should == '<p>----</p>'
31
+ str = "\\* * *"
32
+ Minidown.render(str).should == '<p>* <em> </em></p>'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minidown do
4
+ describe '======== or -------' do
5
+ it 'should parse as text' do
6
+ %w{===== =====hello ------nihao}.each do |str|
7
+ Minidown.render(str).should == "<p>#{str}</p>"
8
+ end
9
+ end
10
+
11
+ it 'should parse as h1' do
12
+ %w{======= ==== === = ==}.each do |s|
13
+ str =<<HERE
14
+ h1
15
+ #{s}
16
+ HERE
17
+ if s.size < 3
18
+ Minidown.render(str).should == "<p>h1<br>#{s}</p>"
19
+ else
20
+ Minidown.render(str).should == "<h1>h1</h1>"
21
+ end
22
+ end
23
+ end
24
+
25
+ it 'should parse as h2' do
26
+ %w{------- ---- --- - --}.each do |s|
27
+ str =<<HERE
28
+ h2
29
+ #{s}
30
+ HERE
31
+ if s.size < 3
32
+ Minidown.render(str).should == "<p>h2<br>#{s}</p>"
33
+ else
34
+ Minidown.render(str).should == "<h2>h2</h2>"
35
+ end
36
+ end
37
+ end
38
+
39
+ it 'should parse newtext' do
40
+ %w{------ =======}.each do |s|
41
+ str =<<HERE
42
+ title
43
+ #{s}should show text
44
+ HERE
45
+ tag = (s[0] == '-' ? 'h2' : 'h1')
46
+ Minidown.render(str).should == "<#{tag}>title</#{tag}><p>should show text</p>"
47
+ end
48
+ end
49
+
50
+ it 'should not parse as h2 if preline is h tag' do
51
+ str = "#### [ruby](http://ruby-lang.org/)\n---"
52
+ Minidown.render(str).should == "<h4><a href=\"http://ruby-lang.org/\">ruby</a></h4><hr>"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Minidown do
4
+ describe 'indent should parse as code block' do
5
+ it 'should parse correct' do
6
+ str =<<HERE
7
+ Here is a Python code example
8
+ without syntax highlighting:
9
+
10
+ def foo:
11
+ if not bar:
12
+ return true
13
+ HERE
14
+ Minidown.render(str).should == "<p>Here is a Python code example<br>without syntax highlighting:</p><pre><code>def foo:\n if not bar:\n return true</code></pre>"
15
+ end
16
+ end
17
+ end