qiita-markdown 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of qiita-markdown might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +5 -3
- data/CHANGELOG.md +3 -0
- data/README.md +0 -1
- data/benchmark/.rubocop.yml +4 -0
- data/benchmark/heading_anchor_rendering.rb +245 -0
- data/benchmark/sample.md +317 -0
- data/lib/qiita/markdown.rb +3 -1
- data/lib/qiita/markdown/filters/greenmat.rb +18 -22
- data/lib/qiita/markdown/greenmat/heading_rendering.rb +43 -0
- data/lib/qiita/markdown/greenmat/html_renderer.rb +55 -0
- data/lib/qiita/markdown/greenmat/html_toc_renderer.rb +67 -0
- data/lib/qiita/markdown/processor.rb +0 -1
- data/lib/qiita/markdown/version.rb +1 -1
- data/qiita-markdown.gemspec +3 -0
- data/spec/qiita/markdown/greenmat/html_renderer_spec.rb +53 -0
- data/spec/qiita/markdown/greenmat/html_toc_renderer_spec.rb +97 -0
- data/spec/qiita/markdown/processor_spec.rb +1 -0
- metadata +28 -5
- data/lib/qiita/markdown/filters/toc.rb +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d82079377c4ce72ef4a32e6a1c30d7b63f6e8f87
|
4
|
+
data.tar.gz: 8b080251af685ea2b9547266edfb4d6a554ca5be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c544a2bd69d30ca9386f03b24e688a939576179e604ca0c666b122220083943c884bf8610e15e4ca904d060e75c79860b3753f832d4cc7da9f8e4e3c6b62e1ef
|
7
|
+
data.tar.gz: 415900299a6b8277d64c0b60143b76277f2f26fedaf6e8698f5032843e88569b93c2ebae3d5ec2aad291cbc15cd40b0496598edeb45c02c87efd8e4cf24e0cf4
|
data/.travis.yml
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
before_install:
|
2
|
-
- sudo apt-get update -qq
|
3
|
-
- sudo apt-get install libicu-dev
|
2
|
+
- sudo apt-get update -qq
|
3
|
+
- sudo apt-get install libicu-dev
|
4
4
|
language: ruby
|
5
5
|
rvm:
|
6
|
-
- 2.0.0
|
6
|
+
- 2.0.0
|
7
|
+
- 2.1
|
8
|
+
- 2.2
|
7
9
|
env:
|
8
10
|
global:
|
9
11
|
secure: n8eyxYYfxLApgR4YGKqbrOgGlraIyLyoql4K4DvLZV4kqfGf9LLsPdP7Shudqrv5k2h8xIwnJVnwcPZx9YCu5WWYrJd7vmivpU2j52LwFPYRM+GFNcu7TXmzcNSPG8agnc5We9amF5zJY6XSTpzWpxyqfIwEZM75iR6XXuHuLFk=
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
## 0.5.0
|
2
|
+
- Add renderers Qiita::Markdown::Greenmat::HTMLRenderer and Qiita::Markdown::Greenmat::HTMLToCRenderer which can be passed to `Redcarpet::Markdown.new` and generate consistent heading fragment identifiers.
|
3
|
+
|
1
4
|
## 0.4.2
|
2
5
|
- Fix bug on SummaryProcessor with mention
|
3
6
|
|
data/README.md
CHANGED
@@ -0,0 +1,245 @@
|
|
1
|
+
require "benchmark/ips"
|
2
|
+
require "qiita/markdown"
|
3
|
+
|
4
|
+
# The old implementation
|
5
|
+
module PostProcess
|
6
|
+
class Processor < Qiita::Markdown::Processor
|
7
|
+
def filters
|
8
|
+
@filters ||= [
|
9
|
+
Filters::Greenmat,
|
10
|
+
Filters::Toc,
|
11
|
+
]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Filters
|
16
|
+
class Greenmat < HTML::Pipeline::TextFilter
|
17
|
+
class << self
|
18
|
+
# Memoize.
|
19
|
+
# @return [Greenmat::Markdown]
|
20
|
+
def renderer
|
21
|
+
@renderer ||= ::Greenmat::Markdown.new(
|
22
|
+
::Greenmat::Render::HTML.new(
|
23
|
+
hard_wrap: true,
|
24
|
+
),
|
25
|
+
autolink: true,
|
26
|
+
fenced_code_blocks: true,
|
27
|
+
footnotes: true,
|
28
|
+
no_intra_emphasis: true,
|
29
|
+
no_mention_emphasis: true,
|
30
|
+
strikethrough: true,
|
31
|
+
tables: true,
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Nokogiri::HTML::DocumentFragment]
|
37
|
+
def call
|
38
|
+
Nokogiri::HTML.fragment(self.class.renderer.render(@text))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Toc < HTML::Pipeline::Filter
|
43
|
+
def call
|
44
|
+
counter = Hash.new(0)
|
45
|
+
doc.css("h1, h2, h3, h4, h5, h6").each do |node|
|
46
|
+
heading = Heading.new(node, counter)
|
47
|
+
heading.add_anchor_element if heading.has_first_child?
|
48
|
+
heading.increment
|
49
|
+
end
|
50
|
+
doc
|
51
|
+
end
|
52
|
+
|
53
|
+
class Heading
|
54
|
+
def initialize(node, counter)
|
55
|
+
@node = node
|
56
|
+
@counter = counter
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_anchor_element
|
60
|
+
first_child.add_previous_sibling(anchor_element)
|
61
|
+
end
|
62
|
+
|
63
|
+
def anchor_element
|
64
|
+
%[<span id="#{suffixed_id}" class="fragment"></span><a href="##{suffixed_id}"><i class="fa fa-link"></i></a>]
|
65
|
+
end
|
66
|
+
|
67
|
+
def content
|
68
|
+
@content ||= node.children.first
|
69
|
+
end
|
70
|
+
|
71
|
+
def count
|
72
|
+
@counter[id]
|
73
|
+
end
|
74
|
+
|
75
|
+
def first_child
|
76
|
+
@first_child ||= @node.children.first
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_count?
|
80
|
+
count > 0
|
81
|
+
end
|
82
|
+
|
83
|
+
def has_first_child?
|
84
|
+
!!first_child
|
85
|
+
end
|
86
|
+
|
87
|
+
def id
|
88
|
+
@node.text.downcase.gsub(/[^\p{Word}\- ]/u, "").gsub(" ", "-")
|
89
|
+
end
|
90
|
+
|
91
|
+
def increment
|
92
|
+
@counter[id] += 1
|
93
|
+
end
|
94
|
+
|
95
|
+
def suffix
|
96
|
+
has_count? ? "-#{count}" : ""
|
97
|
+
end
|
98
|
+
|
99
|
+
def suffixed_id
|
100
|
+
"#{id}#{suffix}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# The new implementation
|
108
|
+
module Rendering
|
109
|
+
class Processor < Qiita::Markdown::Processor
|
110
|
+
def filters
|
111
|
+
@filters ||= [
|
112
|
+
Filters::Greenmat,
|
113
|
+
]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
module Filters
|
118
|
+
class Greenmat < HTML::Pipeline::TextFilter
|
119
|
+
def call
|
120
|
+
Nokogiri::HTML.fragment(greenmat.render(@text))
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Memoize.
|
126
|
+
# @return [Greenmat::Markdown]
|
127
|
+
def greenmat
|
128
|
+
@renderer ||= ::Greenmat::Markdown.new(
|
129
|
+
HTMLRenderer.new(hard_wrap: true, with_toc_data: true),
|
130
|
+
autolink: true,
|
131
|
+
fenced_code_blocks: true,
|
132
|
+
footnotes: true,
|
133
|
+
no_intra_emphasis: true,
|
134
|
+
no_mention_emphasis: true,
|
135
|
+
strikethrough: true,
|
136
|
+
tables: true,
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
class HTMLRenderer < ::Greenmat::Render::HTML
|
141
|
+
def initialize(extensions = {})
|
142
|
+
super
|
143
|
+
@with_toc_data = extensions[:with_toc_data]
|
144
|
+
end
|
145
|
+
|
146
|
+
def header(text, level)
|
147
|
+
heading = heading_class.new(text, level, counter)
|
148
|
+
heading.to_s.tap do
|
149
|
+
heading.increment
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def heading_class
|
156
|
+
@heading_class ||= (@with_toc_data ? HeadingWithAnchor : Heading)
|
157
|
+
end
|
158
|
+
|
159
|
+
def counter
|
160
|
+
@counter ||= Hash.new(0)
|
161
|
+
end
|
162
|
+
|
163
|
+
Heading = Struct.new(:text, :level, :counter) do
|
164
|
+
# For reference, C implementation of Redcarpet::Render::HTML#header is the following:
|
165
|
+
# https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L281-L296
|
166
|
+
def to_s
|
167
|
+
"\n<h#{level}>#{content}</h#{level}>\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
def increment
|
171
|
+
# no-op
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
|
176
|
+
def content
|
177
|
+
text
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class HeadingWithAnchor < Heading
|
182
|
+
def increment
|
183
|
+
counter[id] += 1
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def content
|
189
|
+
anchor_element + text
|
190
|
+
end
|
191
|
+
|
192
|
+
def anchor_element
|
193
|
+
%(<span id="#{suffixed_id}" class="fragment"></span><a href="##{suffixed_id}"><i class="fa fa-link"></i></a>)
|
194
|
+
end
|
195
|
+
|
196
|
+
def count
|
197
|
+
counter[id]
|
198
|
+
end
|
199
|
+
|
200
|
+
def has_count?
|
201
|
+
count > 0
|
202
|
+
end
|
203
|
+
|
204
|
+
def id
|
205
|
+
@id ||= text.downcase.gsub(/[^\p{Word}\- ]/u, "").gsub(" ", "-")
|
206
|
+
end
|
207
|
+
|
208
|
+
def suffix
|
209
|
+
has_count? ? "-#{count}" : ""
|
210
|
+
end
|
211
|
+
|
212
|
+
def suffixed_id
|
213
|
+
@suffixed_id ||= "#{id}#{suffix}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
markdown = File.read(File.join(File.dirname(__FILE__), "sample.md"))
|
222
|
+
|
223
|
+
Benchmark.ips do |benchmark|
|
224
|
+
benchmark.report("post process") do
|
225
|
+
PostProcess::Processor.new.call(markdown)
|
226
|
+
end
|
227
|
+
|
228
|
+
benchmark.report("rendering") do
|
229
|
+
Rendering::Processor.new.call(markdown)
|
230
|
+
end
|
231
|
+
|
232
|
+
benchmark.compare!
|
233
|
+
end
|
234
|
+
|
235
|
+
# Calculating -------------------------------------
|
236
|
+
# post process 4 i/100ms
|
237
|
+
# rendering 22 i/100ms
|
238
|
+
# -------------------------------------------------
|
239
|
+
# post process 48.3 (±16.6%) i/s - 236 in 5.027265s
|
240
|
+
# rendering 227.3 (±15.8%) i/s - 1122 in 5.084983s
|
241
|
+
#
|
242
|
+
# Comparison:
|
243
|
+
# rendering: 227.3 i/s
|
244
|
+
# post process: 48.3 i/s - 4.70x slower
|
245
|
+
#
|
data/benchmark/sample.md
ADDED
@@ -0,0 +1,317 @@
|
|
1
|
+
Markdown記法 チートシート
|
2
|
+
Markdown記法のチートシートです。
|
3
|
+
本ページではQiitaで使用可能なMarkdownのみ掲載しているため、一部原文と異なります。
|
4
|
+
Markdownの原文については、[Daring Fireball: Markdown Syntax Documentation]
|
5
|
+
(http://daringfireball.net/projects/markdown/syntax.php)をご覧下さい。
|
6
|
+
また、コードに関する記法は[GitHub Flavored Markdown](http://github.github.com/github-flavored-markdown/)に準拠しています。
|
7
|
+
Qiitaでシンタックスハイライト可能な言語一覧については、 [シンタックスハイライト可能な言語](http://qiita.com/Qiita/items/e84f5aad7757afce82ba) をご覧下さい。
|
8
|
+
|
9
|
+
## Code - コードの挿入
|
10
|
+
|
11
|
+
たとえば、Rubyで記述したコードをファイル名「qiita.rb」として投稿したいときは、 **バッククオート** を使用して以下のように投稿するとシンタックスハイライトが適用されます。
|
12
|
+
**コードブロック上下に空行を挿入しないと正しく表示されないことがあります。**
|
13
|
+
|
14
|
+
> (空行)
|
15
|
+
> \`\`\`ruby:qiita.rb
|
16
|
+
> puts 'The best way to log and share programmers knowledge.'
|
17
|
+
> \`\`\`
|
18
|
+
> (空行)
|
19
|
+
|
20
|
+
**結果**
|
21
|
+
|
22
|
+
```ruby:qiita.rb
|
23
|
+
puts 'The best way to log and share programmers knowledge.'
|
24
|
+
```
|
25
|
+
|
26
|
+
また、コードをインライン表示することも可能です。
|
27
|
+
|
28
|
+
> \` puts 'Qiita'` はプログラマのための技術情報共有サービスです。
|
29
|
+
|
30
|
+
**結果**
|
31
|
+
|
32
|
+
` puts 'Qiita'` はプログラマのための技術情報共有サービスです。
|
33
|
+
|
34
|
+
インラインコードがn個連続するバッククオートを含む場合、n+1連続のバッククオートで囲みます。
|
35
|
+
|
36
|
+
> \`\` \`バッククオート\` \`\` や \`\`\` \`\`2連続バッククオート\`\` \`\`\` も記述できます。
|
37
|
+
|
38
|
+
**結果**
|
39
|
+
|
40
|
+
`` `バッククオート` `` や ``` ``2連続バッククオート`` ``` も記述できます。
|
41
|
+
|
42
|
+
### Gist連携について
|
43
|
+
|
44
|
+
##### GitHubアカウントでQiitaにログインされている場合
|
45
|
+
|
46
|
+
投稿時、Octocatアイコンにチェックを入れていただくと連携を行います。
|
47
|
+
コードを含むアイテムを投稿するとコード部分を抽出し、同じ内容がGistにも投稿される仕組みになっています。
|
48
|
+
|
49
|
+
Gistとの連携は、
|
50
|
+
|
51
|
+
* コードの投稿
|
52
|
+
* Qiita側でのコードの編集
|
53
|
+
|
54
|
+
の2点について連携しています。
|
55
|
+
Gist側でコードを編集されても、 **Qiitaには反映されません** のでご注意下さい。
|
56
|
+
|
57
|
+
## Format Text - テキストの装飾
|
58
|
+
|
59
|
+
### Headers - 見出し
|
60
|
+
|
61
|
+
* \# これはH1タグです
|
62
|
+
* \## これはH2タグです
|
63
|
+
* \###### これはH6タグです
|
64
|
+
|
65
|
+
### Emphasis - 強調
|
66
|
+
|
67
|
+
```markdown
|
68
|
+
_イタリック体_を使うには _ か * で囲みます。
|
69
|
+
**太字**を使うには __ か ** で囲みます。
|
70
|
+
```
|
71
|
+
|
72
|
+
_イタリック体_を使うには _ か * で囲みます。
|
73
|
+
**太字**を使うには __ か ** で囲みます。
|
74
|
+
|
75
|
+
### Strikethrough - 打ち消し線
|
76
|
+
|
77
|
+
```markdown
|
78
|
+
打ち消し線を使うには ~~ で囲みます。 ~~打ち消し~~
|
79
|
+
```
|
80
|
+
|
81
|
+
打ち消し線を使うには ~~ で囲みます。 ~~打ち消し~~
|
82
|
+
|
83
|
+
イタリックや太文字と同様に前後に **半角スペース** か **改行文字** が必要です。
|
84
|
+
|
85
|
+
## Lists - リスト
|
86
|
+
|
87
|
+
### Disc型
|
88
|
+
|
89
|
+
* 文頭に「*」「+」「-」のいずれかを入れるとDisc型リストになります
|
90
|
+
* 要点をまとめる際に便利です
|
91
|
+
* リストを挿入する際は、 **リストの上下に空行がないと正しく表示されません。また「*」「+」「-」の後にはスペースが必要です**
|
92
|
+
|
93
|
+
### Decimal型
|
94
|
+
|
95
|
+
1. 文頭に「数字.」を入れるとDecimal型リストになります
|
96
|
+
2. 後からの挿入/移動を考慮して、1. 2. 3. と順番にするのではなく、1. 1. 1. という風に同じ数字にしておくといい具合です。
|
97
|
+
3. リストを挿入する際は、 **リストの上下に空行がないと正しく表示されません。また「数字.」の後にはスペースが必要です**
|
98
|
+
|
99
|
+
### Definition型
|
100
|
+
|
101
|
+
HTMLの`<dl>`タグをそのまま使うことで実現できます。
|
102
|
+
|
103
|
+
```html
|
104
|
+
<dl>
|
105
|
+
<dt>リンゴ</dt>
|
106
|
+
<dd>赤いフルーツ</dd>
|
107
|
+
<dt>オレンジ</dt>
|
108
|
+
<dd>橙色のフルーツ</dd>
|
109
|
+
</dl>
|
110
|
+
```
|
111
|
+
次のようになります。
|
112
|
+
|
113
|
+
<dl>
|
114
|
+
<dt>リンゴ</dt>
|
115
|
+
<dd>赤いフルーツ</dd>
|
116
|
+
<dt>オレンジ</dt>
|
117
|
+
<dd>橙色フルーツ</dd>
|
118
|
+
</dl>
|
119
|
+
|
120
|
+
注意するべきは、Definition型のリスト内ではMarkdown記法が使えないということです。例えば以下のように書いてはなりません。
|
121
|
+
|
122
|
+
```html
|
123
|
+
<dl>
|
124
|
+
<dt>リンゴ</dt>
|
125
|
+
<dd> とても **赤い** フルーツ </dd>
|
126
|
+
</dl>
|
127
|
+
```
|
128
|
+
|
129
|
+
次のようになってしまいます。
|
130
|
+
|
131
|
+
<dl>
|
132
|
+
<dt>リンゴ</dt>
|
133
|
+
<dd> とても **赤い** フルーツ </dd>
|
134
|
+
</dl>
|
135
|
+
|
136
|
+
Definition型リスト内ではMarkdown記法ではなくて、HTMLタグを使って修飾しなければならないので、正しくは次のようになります。
|
137
|
+
|
138
|
+
```html
|
139
|
+
<dl>
|
140
|
+
<dt>リンゴ</dt>
|
141
|
+
<dd> とても<strong>赤い</strong>フルーツ </dd>
|
142
|
+
</dl>
|
143
|
+
```
|
144
|
+
|
145
|
+
<dl>
|
146
|
+
<dt>リンゴ</dt>
|
147
|
+
<dd> とても<strong>赤い</strong>フルーツ</dd>
|
148
|
+
</dl>
|
149
|
+
|
150
|
+
Markdown記法とHTMLタグの対応は次のようになっています。
|
151
|
+
|
152
|
+
| 修飾 | Markdown | HTML |
|
153
|
+
|:----------:|:---------------:|:------------------------:|
|
154
|
+
| ボールド | `** **` | `<strong></strong>` |
|
155
|
+
| イタリック | `_ _` | `<em></em>` |
|
156
|
+
| コード | <code>``</code> | `<code></code>` |
|
157
|
+
| リンク | `[text](url)` | `<a href="url">text</a>` |
|
158
|
+
|
159
|
+
## Blockquotes - 引用
|
160
|
+
|
161
|
+
> \> 文頭に>を置くことで引用になります。
|
162
|
+
> \> 複数行にまたがる場合、改行のたびにこの記号を置く必要があります。
|
163
|
+
> \> **引用の上下にはリストと同じく空行がないと正しく表示されません**
|
164
|
+
> \> 引用の中に別のMarkdownを使用することも可能です。
|
165
|
+
|
166
|
+
> > これはネストされた引用です。
|
167
|
+
|
168
|
+
## Horizontal rules - 水平線
|
169
|
+
|
170
|
+
下記は全て水平線として表示されます
|
171
|
+
|
172
|
+
> \* * *
|
173
|
+
> \***
|
174
|
+
> \*****
|
175
|
+
> \- - -
|
176
|
+
> \---------------------------------------
|
177
|
+
|
178
|
+
## Links - リンク
|
179
|
+
|
180
|
+
* \[リンクテキスト](URL "タイトル")
|
181
|
+
* タイトル付きのリンクを投稿できます。
|
182
|
+
|
183
|
+
**例**
|
184
|
+
|
185
|
+
> *Markdown:* \[Qiita]\(http://qiita.com "Qiita")
|
186
|
+
> *結果:* [Qiita](http://qiita.com "Qiita")
|
187
|
+
|
188
|
+
* \[リンクテキスト](URL)
|
189
|
+
* こちらはタイトル無しのリンクになります。
|
190
|
+
|
191
|
+
**例**
|
192
|
+
|
193
|
+
> *Markdown:* \[Qiita]\(http://qiita.com)
|
194
|
+
> *結果:* [Qiita](http://qiita.com)
|
195
|
+
|
196
|
+
- \[リンクテキスト]\[名前]
|
197
|
+
- \[名前]:URL
|
198
|
+
- 同じURLへのリンクを複数箇所に設定することができます
|
199
|
+
|
200
|
+
**例**
|
201
|
+
|
202
|
+
>
|
203
|
+
*Markdown:*
|
204
|
+
\[ここ]\[link-1] と \[この]\[link-1] リンクは同じになります。
|
205
|
+
\[link-1][\] も可能です。
|
206
|
+
\[link-1]:http://qiita.com/drafts/c686397e4a0f4f11683d
|
207
|
+
>
|
208
|
+
*結果:*
|
209
|
+
[ここ][link-1] と [この][link-1] リンクは同じになります。
|
210
|
+
[link-1][] も可能です。
|
211
|
+
[link-1]:http://qiita.com/drafts/c686397e4a0f4f11683d
|
212
|
+
|
213
|
+
## Images - 画像埋め込み
|
214
|
+
|
215
|
+
* \![代替テキスト]\(画像のURL)
|
216
|
+
* タイトル無しの画像を埋め込む
|
217
|
+
* \![代替テキスト]\(画像のURL "画像タイトル")
|
218
|
+
* タイトル有りの画像を埋め込む
|
219
|
+
|
220
|
+
**例**
|
221
|
+
|
222
|
+
> *Markdown:* \![Qiita]\(http://qiita.com/icons/favicons/public/apple-touch-icon.png "Qiita")
|
223
|
+
> *結果:*
|
224
|
+
> ![Qiita](http://qiita.com/icons/favicons/public/apple-touch-icon.png "Qiita")
|
225
|
+
|
226
|
+
## テーブル記法
|
227
|
+
```
|
228
|
+
| Left align | Right align | Center align |
|
229
|
+
|:-----------|------------:|:------------:|
|
230
|
+
| This | This | This |
|
231
|
+
| column | column | column |
|
232
|
+
| will | will | will |
|
233
|
+
| be | be | be |
|
234
|
+
| left | right | center |
|
235
|
+
| aligned | aligned | aligned |
|
236
|
+
```
|
237
|
+
|
238
|
+
上記のように書くと,以下のように表示されます.
|
239
|
+
|
240
|
+
| Left align | Right align | Center align |
|
241
|
+
|:-----------|------------:|:------------:|
|
242
|
+
| This | This | This |
|
243
|
+
| column | column | column |
|
244
|
+
| will | will | will |
|
245
|
+
| be | be | be |
|
246
|
+
| left | right | center |
|
247
|
+
| aligned | aligned | aligned |
|
248
|
+
|
249
|
+
## 数式の挿入
|
250
|
+
|
251
|
+
コードブロックの言語指定に "math" を指定することでTeX記法を用いて数式を記述することができます。
|
252
|
+
|
253
|
+
> \`\`\`math
|
254
|
+
> \left( \sum_{k=1}^n a_k b_k \right)^{\!\!2} \leq
|
255
|
+
> \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
|
256
|
+
> \`\`\`
|
257
|
+
|
258
|
+
```math
|
259
|
+
\left( \sum_{k=1}^n a_k b_k \right)^{\!\!2} \leq
|
260
|
+
\left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
|
261
|
+
```
|
262
|
+
|
263
|
+
`$2^3$` のように数式を "$" で挟むと行中に数式を埋め込むこともできます。
|
264
|
+
|
265
|
+
> x^2 + y^2 = 1 をインライン表示すると $x^2 + y^2 = 1$ になります。
|
266
|
+
|
267
|
+
ただしインライン数式の中でコントロールシンボル(`\{`のような、バックスラッシュの後に記号が続くもの)を使うと、後述のバックスラッシュによるMarkdownのエスケープと衝突してしまいます。
|
268
|
+
|
269
|
+
```
|
270
|
+
$a = \{1, 2, 3\}$
|
271
|
+
```
|
272
|
+
|
273
|
+
> $a = \{1, 2, 3\}$
|
274
|
+
|
275
|
+
なので次のように二つのバックスラッシュを使います。
|
276
|
+
|
277
|
+
```
|
278
|
+
$a = \\{1, 2, 3\\}$
|
279
|
+
```
|
280
|
+
|
281
|
+
> $a = \\{1, 2, 3\\}$
|
282
|
+
|
283
|
+
## 目次(TOC)の自動挿入
|
284
|
+
|
285
|
+
目次は記事内の見出しを元に自動生成し、右上に自動挿入されます。詳細は[目次機能の紹介記事](http://blog.qiita.com/post/77055935852/qiita-toc)をご覧ください。
|
286
|
+
|
287
|
+
## 注釈
|
288
|
+
本文中に `[^1]` のように文字列を記述することで、脚注へのリンクを表現できます。注釈内容は、同じく本文中に `[^1]: ...` というように記述します[^1]。
|
289
|
+
|
290
|
+
[^1]: 注釈内容を記述する位置は、本文の途中でも末尾でも構いません。
|
291
|
+
|
292
|
+
## 絵文字
|
293
|
+
厳密には Markdown 記法の外ですが、`:` で囲って、絵文字を埋め込めます。
|
294
|
+
|
295
|
+
**例**
|
296
|
+
|
297
|
+
```
|
298
|
+
\:kissing_closed_eyes: chu☆
|
299
|
+
```
|
300
|
+
|
301
|
+
> \:kissing_closed_eyes: chu☆
|
302
|
+
|
303
|
+
|
304
|
+
絵文字チートシート
|
305
|
+
http://www.emoji-cheat-sheet.com/
|
306
|
+
|
307
|
+
|
308
|
+
## その他
|
309
|
+
|
310
|
+
バックスラッシュ[\\]をMarkdownの前に挿入することで、Markdownをエスケープ(無効化)することができます。
|
311
|
+
|
312
|
+
**例**
|
313
|
+
|
314
|
+
> \# H1
|
315
|
+
> エスケープされています
|
316
|
+
|
317
|
+
また本文では一部のHTMLタグも利用可能です。
|
data/lib/qiita/markdown.rb
CHANGED
@@ -15,8 +15,10 @@ require "qiita/markdown/filters/mention"
|
|
15
15
|
require "qiita/markdown/filters/sanitize"
|
16
16
|
require "qiita/markdown/filters/simplify"
|
17
17
|
require "qiita/markdown/filters/syntax_highlight"
|
18
|
-
require "qiita/markdown/filters/toc"
|
19
18
|
require "qiita/markdown/filters/truncate"
|
19
|
+
require "qiita/markdown/greenmat/heading_rendering"
|
20
|
+
require "qiita/markdown/greenmat/html_renderer"
|
21
|
+
require "qiita/markdown/greenmat/html_toc_renderer"
|
20
22
|
require "qiita/markdown/processor"
|
21
23
|
require "qiita/markdown/summary_processor"
|
22
24
|
require "qiita/markdown/version"
|
@@ -1,31 +1,27 @@
|
|
1
|
-
require "greenmat"
|
2
|
-
|
3
1
|
module Qiita
|
4
2
|
module Markdown
|
5
3
|
module Filters
|
6
4
|
class Greenmat < HTML::Pipeline::TextFilter
|
7
|
-
class << self
|
8
|
-
# Memoize.
|
9
|
-
# @return [Greenmat::Markdown]
|
10
|
-
def renderer
|
11
|
-
@renderer ||= ::Greenmat::Markdown.new(
|
12
|
-
::Greenmat::Render::HTML.new(
|
13
|
-
hard_wrap: true,
|
14
|
-
),
|
15
|
-
autolink: true,
|
16
|
-
fenced_code_blocks: true,
|
17
|
-
footnotes: true,
|
18
|
-
no_intra_emphasis: true,
|
19
|
-
no_mention_emphasis: true,
|
20
|
-
strikethrough: true,
|
21
|
-
tables: true,
|
22
|
-
)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
5
|
# @return [Nokogiri::HTML::DocumentFragment]
|
27
6
|
def call
|
28
|
-
Nokogiri::HTML.fragment(
|
7
|
+
Nokogiri::HTML.fragment(greenmat.render(@text))
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Memoize.
|
13
|
+
# @return [Greenmat::Markdown]
|
14
|
+
def greenmat
|
15
|
+
@renderer ||= ::Greenmat::Markdown.new(
|
16
|
+
Qiita::Markdown::Greenmat::HTMLRenderer.new(hard_wrap: true, with_toc_data: true),
|
17
|
+
autolink: true,
|
18
|
+
fenced_code_blocks: true,
|
19
|
+
footnotes: true,
|
20
|
+
no_intra_emphasis: true,
|
21
|
+
no_mention_emphasis: true,
|
22
|
+
strikethrough: true,
|
23
|
+
tables: true,
|
24
|
+
)
|
29
25
|
end
|
30
26
|
end
|
31
27
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Qiita
|
2
|
+
module Markdown
|
3
|
+
module Greenmat
|
4
|
+
module HeadingRendering
|
5
|
+
def heading_counter
|
6
|
+
@counter ||= Hash.new(0)
|
7
|
+
end
|
8
|
+
|
9
|
+
AbstractHeading = Struct.new(:text, :level, :counter) do
|
10
|
+
def to_s
|
11
|
+
fail NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def increment
|
15
|
+
fail NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def count
|
21
|
+
counter[id]
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_count?
|
25
|
+
count > 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def id
|
29
|
+
@id ||= text.downcase.gsub(/[^\p{Word}\- ]/u, "").gsub(" ", "-")
|
30
|
+
end
|
31
|
+
|
32
|
+
def suffix
|
33
|
+
has_count? ? "-#{count}" : ""
|
34
|
+
end
|
35
|
+
|
36
|
+
def suffixed_id
|
37
|
+
@suffixed_id ||= "#{id}#{suffix}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Qiita
|
2
|
+
module Markdown
|
3
|
+
module Greenmat
|
4
|
+
class HTMLRenderer < ::Greenmat::Render::HTML
|
5
|
+
include HeadingRendering
|
6
|
+
|
7
|
+
def initialize(extensions = {})
|
8
|
+
super
|
9
|
+
@with_toc_data = extensions[:with_toc_data]
|
10
|
+
end
|
11
|
+
|
12
|
+
def header(text, level)
|
13
|
+
heading = heading_class.new(text, level, heading_counter)
|
14
|
+
heading.to_s.tap do
|
15
|
+
heading.increment
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def heading_class
|
22
|
+
@heading_class ||= (@with_toc_data ? HeadingWithAnchor : Heading)
|
23
|
+
end
|
24
|
+
|
25
|
+
class Heading < AbstractHeading
|
26
|
+
# For reference, C implementation of Redcarpet::Render::HTML#header is the following:
|
27
|
+
# https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L281-L296
|
28
|
+
def to_s
|
29
|
+
"\n<h#{level}>#{text}</h#{level}>\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
def increment
|
33
|
+
# No-op
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class HeadingWithAnchor < AbstractHeading
|
38
|
+
def to_s
|
39
|
+
"\n<h#{level}>#{anchor_element}#{text}</h#{level}>\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
def increment
|
43
|
+
counter[id] += 1
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def anchor_element
|
49
|
+
%(<span id="#{suffixed_id}" class="fragment"></span><a href="##{suffixed_id}"><i class="fa fa-link"></i></a>)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Qiita
|
2
|
+
module Markdown
|
3
|
+
module Greenmat
|
4
|
+
class HTMLToCRenderer < ::Greenmat::Render::HTML_TOC
|
5
|
+
include HeadingRendering
|
6
|
+
|
7
|
+
def initialize(*)
|
8
|
+
super
|
9
|
+
@last_level = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
# https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L609-L642
|
13
|
+
def header(text, level)
|
14
|
+
@level_offset = level - 1 unless @level_offset
|
15
|
+
|
16
|
+
level -= @level_offset
|
17
|
+
level = 1 if level < 1
|
18
|
+
|
19
|
+
difference = level - @last_level
|
20
|
+
@last_level = level
|
21
|
+
|
22
|
+
generate_heading_html(text, level, difference)
|
23
|
+
end
|
24
|
+
|
25
|
+
# https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L652-L661
|
26
|
+
def doc_footer
|
27
|
+
"</li>\n</ul>\n" * @last_level
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def generate_heading_html(text, level, level_difference)
|
33
|
+
html = list_item_preceding_html(level_difference)
|
34
|
+
|
35
|
+
anchor = HeadingAnchor.new(text, level, heading_counter)
|
36
|
+
html << anchor.to_s
|
37
|
+
anchor.increment
|
38
|
+
|
39
|
+
html
|
40
|
+
end
|
41
|
+
|
42
|
+
def list_item_preceding_html(level_difference)
|
43
|
+
html = case
|
44
|
+
when level_difference > 0
|
45
|
+
"<ul>\n" * level_difference
|
46
|
+
when level_difference < 0
|
47
|
+
"</li>\n" << ("</ul>\n</li>\n" * level_difference.abs)
|
48
|
+
else
|
49
|
+
"</li>\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
html << "<li>\n"
|
53
|
+
end
|
54
|
+
|
55
|
+
class HeadingAnchor < AbstractHeading
|
56
|
+
def to_s
|
57
|
+
"<a href=\"##{suffixed_id}\">#{text}</a>\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
def increment
|
61
|
+
counter[id] += 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/qiita-markdown.gemspec
CHANGED
@@ -16,6 +16,8 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
17
|
spec.require_paths = ["lib"]
|
18
18
|
|
19
|
+
spec.required_ruby_version = ">= 2.0.0"
|
20
|
+
|
19
21
|
spec.add_dependency "activesupport"
|
20
22
|
spec.add_dependency "gemoji"
|
21
23
|
spec.add_dependency "github-linguist"
|
@@ -25,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
25
27
|
spec.add_dependency "greenmat", ">= 3.2.0.2", "< 4"
|
26
28
|
spec.add_dependency "rugged", ">= 0.21.1b2"
|
27
29
|
spec.add_dependency "sanitize"
|
30
|
+
spec.add_development_dependency "benchmark-ips", "~> 1.2"
|
28
31
|
spec.add_development_dependency "bundler", "~> 1.7"
|
29
32
|
spec.add_development_dependency "codeclimate-test-reporter", "0.4.4"
|
30
33
|
spec.add_development_dependency "pry"
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "active_support/core_ext/string/strip"
|
2
|
+
|
3
|
+
describe Qiita::Markdown::Greenmat::HTMLRenderer do
|
4
|
+
let(:renderer) { described_class.new(extension) }
|
5
|
+
let(:extension) { {} }
|
6
|
+
let(:greenmat) { ::Greenmat::Markdown.new(renderer) }
|
7
|
+
subject(:rendered_html) { greenmat.render(markdown) }
|
8
|
+
|
9
|
+
describe "headings" do
|
10
|
+
let(:markdown) do
|
11
|
+
<<-EOS.strip_heredoc
|
12
|
+
# a
|
13
|
+
## a
|
14
|
+
### a
|
15
|
+
### a
|
16
|
+
EOS
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with :with_toc_data extension" do
|
20
|
+
let(:extension) { { with_toc_data: true } }
|
21
|
+
|
22
|
+
it "renders headings with ToC anchor" do
|
23
|
+
should eq <<-EOS.strip_heredoc
|
24
|
+
|
25
|
+
<h1><span id="a" class="fragment"></span><a href="#a"><i class="fa fa-link"></i></a>a</h1>
|
26
|
+
|
27
|
+
<h2><span id="a-1" class="fragment"></span><a href="#a-1"><i class="fa fa-link"></i></a>a</h2>
|
28
|
+
|
29
|
+
<h3><span id="a-2" class="fragment"></span><a href="#a-2"><i class="fa fa-link"></i></a>a</h3>
|
30
|
+
|
31
|
+
<h3><span id="a-3" class="fragment"></span><a href="#a-3"><i class="fa fa-link"></i></a>a</h3>
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "without :with_toc_data extension" do
|
37
|
+
let(:extension) { { with_toc_data: false } }
|
38
|
+
|
39
|
+
it "renders headings without ToC anchor" do
|
40
|
+
should eq <<-EOS.strip_heredoc
|
41
|
+
|
42
|
+
<h1>a</h1>
|
43
|
+
|
44
|
+
<h2>a</h2>
|
45
|
+
|
46
|
+
<h3>a</h3>
|
47
|
+
|
48
|
+
<h3>a</h3>
|
49
|
+
EOS
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require "active_support/core_ext/string/strip"
|
2
|
+
|
3
|
+
describe Qiita::Markdown::Greenmat::HTMLToCRenderer do
|
4
|
+
let(:renderer) { described_class.new }
|
5
|
+
let(:greenmat) { ::Greenmat::Markdown.new(renderer) }
|
6
|
+
subject(:rendered_html) { greenmat.render(markdown) }
|
7
|
+
|
8
|
+
context "with duplicated heading names" do
|
9
|
+
let(:markdown) do
|
10
|
+
<<-EOS.strip_heredoc
|
11
|
+
# a
|
12
|
+
## a
|
13
|
+
### a
|
14
|
+
### a
|
15
|
+
EOS
|
16
|
+
end
|
17
|
+
|
18
|
+
it "renders ToC anchors with unique ids" do
|
19
|
+
should eq <<-EOS.strip_heredoc
|
20
|
+
<ul>
|
21
|
+
<li>
|
22
|
+
<a href="#a">a</a>
|
23
|
+
<ul>
|
24
|
+
<li>
|
25
|
+
<a href="#a-1">a</a>
|
26
|
+
<ul>
|
27
|
+
<li>
|
28
|
+
<a href="#a-2">a</a>
|
29
|
+
</li>
|
30
|
+
<li>
|
31
|
+
<a href="#a-3">a</a>
|
32
|
+
</li>
|
33
|
+
</ul>
|
34
|
+
</li>
|
35
|
+
</ul>
|
36
|
+
</li>
|
37
|
+
</ul>
|
38
|
+
EOS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with a document starting with level 2 heading" do
|
43
|
+
let(:markdown) do
|
44
|
+
<<-EOS.strip_heredoc
|
45
|
+
## a
|
46
|
+
### a
|
47
|
+
## a
|
48
|
+
EOS
|
49
|
+
end
|
50
|
+
|
51
|
+
it "offsets the heading levels" do
|
52
|
+
should eq <<-EOS.strip_heredoc
|
53
|
+
<ul>
|
54
|
+
<li>
|
55
|
+
<a href="#a">a</a>
|
56
|
+
<ul>
|
57
|
+
<li>
|
58
|
+
<a href="#a-1">a</a>
|
59
|
+
</li>
|
60
|
+
</ul>
|
61
|
+
</li>
|
62
|
+
<li>
|
63
|
+
<a href="#a-2">a</a>
|
64
|
+
</li>
|
65
|
+
</ul>
|
66
|
+
EOS
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "with a document starting with level 2 heading but includes level 1 heading at the end" do
|
71
|
+
let(:markdown) do
|
72
|
+
<<-EOS.strip_heredoc
|
73
|
+
## a
|
74
|
+
### a
|
75
|
+
# a
|
76
|
+
EOS
|
77
|
+
end
|
78
|
+
|
79
|
+
it "does not generate invalid list structure" do
|
80
|
+
should eq <<-EOS.strip_heredoc
|
81
|
+
<ul>
|
82
|
+
<li>
|
83
|
+
<a href="#a">a</a>
|
84
|
+
<ul>
|
85
|
+
<li>
|
86
|
+
<a href="#a-1">a</a>
|
87
|
+
</li>
|
88
|
+
</ul>
|
89
|
+
</li>
|
90
|
+
<li>
|
91
|
+
<a href="#a-2">a</a>
|
92
|
+
</li>
|
93
|
+
</ul>
|
94
|
+
EOS
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qiita-markdown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryo Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -142,6 +142,20 @@ dependencies:
|
|
142
142
|
- - ">="
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: '0'
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: benchmark-ips
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '1.2'
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '1.2'
|
145
159
|
- !ruby/object:Gem::Dependency
|
146
160
|
name: bundler
|
147
161
|
requirement: !ruby/object:Gem::Requirement
|
@@ -243,6 +257,9 @@ files:
|
|
243
257
|
- LICENSE.txt
|
244
258
|
- README.md
|
245
259
|
- Rakefile
|
260
|
+
- benchmark/.rubocop.yml
|
261
|
+
- benchmark/heading_anchor_rendering.rb
|
262
|
+
- benchmark/sample.md
|
246
263
|
- lib/qiita-markdown.rb
|
247
264
|
- lib/qiita/markdown.rb
|
248
265
|
- lib/qiita/markdown/filters/checkbox.rb
|
@@ -253,12 +270,16 @@ files:
|
|
253
270
|
- lib/qiita/markdown/filters/sanitize.rb
|
254
271
|
- lib/qiita/markdown/filters/simplify.rb
|
255
272
|
- lib/qiita/markdown/filters/syntax_highlight.rb
|
256
|
-
- lib/qiita/markdown/filters/toc.rb
|
257
273
|
- lib/qiita/markdown/filters/truncate.rb
|
274
|
+
- lib/qiita/markdown/greenmat/heading_rendering.rb
|
275
|
+
- lib/qiita/markdown/greenmat/html_renderer.rb
|
276
|
+
- lib/qiita/markdown/greenmat/html_toc_renderer.rb
|
258
277
|
- lib/qiita/markdown/processor.rb
|
259
278
|
- lib/qiita/markdown/summary_processor.rb
|
260
279
|
- lib/qiita/markdown/version.rb
|
261
280
|
- qiita-markdown.gemspec
|
281
|
+
- spec/qiita/markdown/greenmat/html_renderer_spec.rb
|
282
|
+
- spec/qiita/markdown/greenmat/html_toc_renderer_spec.rb
|
262
283
|
- spec/qiita/markdown/processor_spec.rb
|
263
284
|
- spec/qiita/markdown/summary_processor_spec.rb
|
264
285
|
- spec/spec_helper.rb
|
@@ -274,7 +295,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
274
295
|
requirements:
|
275
296
|
- - ">="
|
276
297
|
- !ruby/object:Gem::Version
|
277
|
-
version:
|
298
|
+
version: 2.0.0
|
278
299
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
279
300
|
requirements:
|
280
301
|
- - ">="
|
@@ -282,11 +303,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
282
303
|
version: '0'
|
283
304
|
requirements: []
|
284
305
|
rubyforge_project:
|
285
|
-
rubygems_version: 2.4.
|
306
|
+
rubygems_version: 2.4.6
|
286
307
|
signing_key:
|
287
308
|
specification_version: 4
|
288
309
|
summary: Qiita-specified markdown processor.
|
289
310
|
test_files:
|
311
|
+
- spec/qiita/markdown/greenmat/html_renderer_spec.rb
|
312
|
+
- spec/qiita/markdown/greenmat/html_toc_renderer_spec.rb
|
290
313
|
- spec/qiita/markdown/processor_spec.rb
|
291
314
|
- spec/qiita/markdown/summary_processor_spec.rb
|
292
315
|
- spec/spec_helper.rb
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module Qiita
|
2
|
-
module Markdown
|
3
|
-
module Filters
|
4
|
-
class Toc < HTML::Pipeline::Filter
|
5
|
-
def call
|
6
|
-
counter = Hash.new(0)
|
7
|
-
doc.css("h1, h2, h3, h4, h5, h6").each do |node|
|
8
|
-
heading = Heading.new(node, counter)
|
9
|
-
heading.add_anchor_element if heading.has_first_child?
|
10
|
-
heading.increment
|
11
|
-
end
|
12
|
-
doc
|
13
|
-
end
|
14
|
-
|
15
|
-
class Heading
|
16
|
-
def initialize(node, counter)
|
17
|
-
@node = node
|
18
|
-
@counter = counter
|
19
|
-
end
|
20
|
-
|
21
|
-
def add_anchor_element
|
22
|
-
first_child.add_previous_sibling(anchor_element)
|
23
|
-
end
|
24
|
-
|
25
|
-
def anchor_element
|
26
|
-
%[<span id="#{suffixed_id}" class="fragment"></span><a href="##{suffixed_id}"><i class="fa fa-link"></i></a>]
|
27
|
-
end
|
28
|
-
|
29
|
-
def content
|
30
|
-
@content ||= node.children.first
|
31
|
-
end
|
32
|
-
|
33
|
-
def count
|
34
|
-
@counter[id]
|
35
|
-
end
|
36
|
-
|
37
|
-
def first_child
|
38
|
-
@first_child ||= @node.children.first
|
39
|
-
end
|
40
|
-
|
41
|
-
def has_count?
|
42
|
-
count > 0
|
43
|
-
end
|
44
|
-
|
45
|
-
def has_first_child?
|
46
|
-
!!first_child
|
47
|
-
end
|
48
|
-
|
49
|
-
def id
|
50
|
-
@node.text.downcase.gsub(/[^\p{Word}\- ]/u, "").gsub(" ", "-")
|
51
|
-
end
|
52
|
-
|
53
|
-
def increment
|
54
|
-
@counter[id] += 1
|
55
|
-
end
|
56
|
-
|
57
|
-
def suffix
|
58
|
-
has_count? ? "-#{count}" : ""
|
59
|
-
end
|
60
|
-
|
61
|
-
def suffixed_id
|
62
|
-
"#{id}#{suffix}"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|