daimon-markdown 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +58 -0
- data/.travis.yml +9 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +90 -0
- data/Rakefile +12 -0
- data/daimon-markdown.gemspec +32 -0
- data/lib/daimon/markdown/filter/plugin.rb +37 -0
- data/lib/daimon/markdown/filter/redcarpet.rb +26 -0
- data/lib/daimon/markdown/filter.rb +9 -0
- data/lib/daimon/markdown/parser.rb +88 -0
- data/lib/daimon/markdown/plugin/base.rb +24 -0
- data/lib/daimon/markdown/plugin/chat.rb +21 -0
- data/lib/daimon/markdown/plugin/figure.rb +19 -0
- data/lib/daimon/markdown/plugin/math.rb +33 -0
- data/lib/daimon/markdown/plugin/toc.rb +60 -0
- data/lib/daimon/markdown/plugin.rb +23 -0
- data/lib/daimon/markdown/processor.rb +30 -0
- data/lib/daimon/markdown/redcarpet/html_renderer.rb +37 -0
- data/lib/daimon/markdown/version.rb +5 -0
- data/lib/daimon/markdown.rb +11 -0
- metadata +164 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 50f1024b283dae59703639438ea079cdd02d997a
|
4
|
+
data.tar.gz: 90bc18433e7e8bdb97b054232558da6c1788543c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 059181727a629fa3fbf6e4bda5b21ee986ed7db32fac7f9c7d092d12d66e72647c61d4375f516aaf375f6b2e02fc258171ed7feab95e5ee0fb14e08c093fec35
|
7
|
+
data.tar.gz: 83cb0864ab8c2ee81da57e6134ae4b2321f061bcc21868dd969151e472f57aaa5378b2263e746266bfd59d6d043355d34b97119cdba6743909a6e17a93d91323
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.3
|
3
|
+
DisplayCopNames: true
|
4
|
+
Exclude:
|
5
|
+
- "vendor/**/*"
|
6
|
+
|
7
|
+
Lint/UnderscorePrefixedVariableName:
|
8
|
+
Enabled: false
|
9
|
+
Lint/UnusedMethodArgument:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Metrics/LineLength:
|
13
|
+
Enabled: false
|
14
|
+
Metrics/ClassLength:
|
15
|
+
Exclude:
|
16
|
+
- "test/**/*.rb"
|
17
|
+
Metrics/ParameterLists:
|
18
|
+
Max: 7
|
19
|
+
Metrics/MethodLength:
|
20
|
+
Max: 30
|
21
|
+
|
22
|
+
Style/AsciiComments:
|
23
|
+
Enabled: false
|
24
|
+
Style/HashSyntax:
|
25
|
+
Exclude:
|
26
|
+
- "**/*.rake"
|
27
|
+
- "Rakefile"
|
28
|
+
Style/FrozenStringLiteralComment:
|
29
|
+
Enabled: false
|
30
|
+
Style/StringLiterals:
|
31
|
+
EnforcedStyle: double_quotes
|
32
|
+
Style/TrailingCommaInLiteral:
|
33
|
+
Enabled: false
|
34
|
+
Style/TrailingCommaInArguments:
|
35
|
+
Enabled: false
|
36
|
+
Style/FileName:
|
37
|
+
Enabled: false
|
38
|
+
Style/Documentation:
|
39
|
+
Enabled: false
|
40
|
+
Style/WordArray:
|
41
|
+
Enabled: false
|
42
|
+
Style/BarePercentLiterals:
|
43
|
+
EnforcedStyle: percent_q
|
44
|
+
Style/SpaceInsideBlockBraces:
|
45
|
+
EnforcedStyle: space
|
46
|
+
SpaceBeforeBlockParameters: false
|
47
|
+
Style/BracesAroundHashParameters:
|
48
|
+
Enabled: false
|
49
|
+
Style/MultilineMethodCallIndentation:
|
50
|
+
EnforcedStyle: indented
|
51
|
+
Style/SpaceInsideHashLiteralBraces:
|
52
|
+
EnforcedStyle: no_space
|
53
|
+
Style/BlockDelimiters:
|
54
|
+
EnforcedStyle: braces_for_chaining
|
55
|
+
Style/PercentQLiterals:
|
56
|
+
Enabled: false
|
57
|
+
Style/UnneededPercentQ:
|
58
|
+
Enabled: false
|
data/.travis.yml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
sudo: false
|
2
|
+
language: ruby
|
3
|
+
cache: bundler
|
4
|
+
rvm:
|
5
|
+
- 2.3.0
|
6
|
+
- 2.3.1
|
7
|
+
notifications:
|
8
|
+
slack:
|
9
|
+
secure: JcaUwy2K2x3nLZeU5sjMy+LPWd6SUey5FExLJf70QTSaioyYJgyvKgexZ7sR5kUEwkps+Ql9smUBUho/H/FeEEjnTidv/kq1+Fvo0Hr17VMrEuWA4m1XyMGP3TChfW1aPm2z+aL3AhX/voORD9CIevoC3GlZmDTq3aaB6T5EQGxpEqRkutJ4B9c94uEoZWaY+7w5r3c+CxQxr3lt5jiDkNzTySPDcs3s+zf/8AMoz3gwisoL0RkL5dv/80c8k/mzkYtu9V97tMK2V9sA35cU9Xnc0K8CEtJiWwx9JPvqrFQ2QQion3g9cMLzdBvmJYOazlCPaK19AJ2PfIO0JJKeJIWsSxBW3lTEUKRRXJvC+xY/HlLCNzXyRUn2TYr8Px0bQEIG1wGZdJvqBYG9xeuzgXjHRBPfCGVkXvU6xaGCIfRMoWodj7gknJCv7uimOJYLg5c57Q4sWnbp+kxtiHYSqn41j1aPkopsUL7wHCzwSscS4PbWTVyoHsXfy+P9c77pt/uLwf0he99+j4kgHsCaxPAUJ7aeTmpR8/n02rii9Vf4eWyIOKXq73FVT/Hatn/tuB72z1OmpuaGPXoWmJoo52XQRPBRwlX9fBMFklcwyAts9PG7VvB5s6l+dnSht1v44qjTGsT78nqQbUgp0lNcU3G67ld0OIvG3MkGCAZ+AL4=
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Kenji Okimoto
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Daimon::Markdown
|
2
|
+
|
3
|
+
Daimon::Markdown is a Markdown processor that has plugin functionality.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'daimon-markdown'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install daimon-markdown
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
processor = Daimon::Markdown::Processor.new
|
27
|
+
result = processor.call(input)
|
28
|
+
puts result[:output].to_s
|
29
|
+
```
|
30
|
+
|
31
|
+
## How to write plugin
|
32
|
+
|
33
|
+
TODO
|
34
|
+
|
35
|
+
### Bundled plugins
|
36
|
+
|
37
|
+
#### toc
|
38
|
+
|
39
|
+
Display table of contents.
|
40
|
+
|
41
|
+
```
|
42
|
+
{{toc}}
|
43
|
+
```
|
44
|
+
|
45
|
+
#### figure
|
46
|
+
|
47
|
+
Display image using figure tag and figcaption tag.
|
48
|
+
|
49
|
+
```
|
50
|
+
{{figure("image.png", "alt text", "caption text")}}
|
51
|
+
```
|
52
|
+
|
53
|
+
#### math
|
54
|
+
|
55
|
+
Display mathematical expression using [MathJax](https://www.mathjax.org/).
|
56
|
+
Use 2 backslashes if you want to use commands start with backslash.
|
57
|
+
|
58
|
+
Currently support LaTeX and AsciiMath.
|
59
|
+
|
60
|
+
```
|
61
|
+
# Inline style
|
62
|
+
|
63
|
+
This is a expression {{math("$1 + 1 = 2$")}}. And {{math("$2^10 = 1024$")}} .
|
64
|
+
|
65
|
+
# Block style
|
66
|
+
|
67
|
+
```
|
68
|
+
{{math("$$
|
69
|
+
\\begin{aligned}
|
70
|
+
\\dot{x} & = \\sigma(y-x) \\\\
|
71
|
+
\\dot{y} & = \\rho x - y - xz \\\\
|
72
|
+
\\dot{z} & = -\\beta z + xy
|
73
|
+
\\end{aligned}
|
74
|
+
$$")}}
|
75
|
+
```
|
76
|
+
|
77
|
+
|
78
|
+
## Development
|
79
|
+
|
80
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
81
|
+
|
82
|
+
## Contributing
|
83
|
+
|
84
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bm-sms/daimon-markdown.
|
85
|
+
|
86
|
+
|
87
|
+
## License
|
88
|
+
|
89
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
90
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
task :default => :test
|
5
|
+
|
6
|
+
desc "Run test"
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
8
|
+
t.libs << "test"
|
9
|
+
t.test_files = (Dir["test/test_*.rb"] + Dir["test/plugin/test_*.rb"]).sort
|
10
|
+
t.verbose = false
|
11
|
+
t.warning = false
|
12
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'daimon/markdown/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "daimon-markdown"
|
8
|
+
spec.version = Daimon::Markdown::VERSION
|
9
|
+
spec.authors = ["Kenji Okimoto"]
|
10
|
+
spec.email = ["okimoto@clear-code.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Markdown renderer for Daimon}
|
13
|
+
spec.description = %q{Markdown renderer for Daimon}
|
14
|
+
spec.homepage = "https://github.com/bm-sms/daimon-markdown"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.required_ruby_version = ">= 2.2.0"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
spec.bindir = "bin"
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_runtime_dependency "html-pipeline"
|
25
|
+
spec.add_runtime_dependency "redcarpet"
|
26
|
+
spec.add_runtime_dependency "rouge"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", ">= 1.12"
|
29
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
30
|
+
spec.add_development_dependency "test-unit", "> 3"
|
31
|
+
spec.add_development_dependency "test-unit-notify"
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "daimon/markdown/parser"
|
2
|
+
|
3
|
+
module Daimon
|
4
|
+
module Markdown
|
5
|
+
module Filter
|
6
|
+
class Plugin < ::HTML::Pipeline::Filter
|
7
|
+
def call
|
8
|
+
doc.search(".//text()").each do |node|
|
9
|
+
result[:plugins] = []
|
10
|
+
node.to_s.scan(/{{(.+?)}}/m) do |str|
|
11
|
+
parser = Daimon::Markdown::Parser.new(str[0])
|
12
|
+
parser.parse
|
13
|
+
plugin_class = Daimon::Markdown::Plugin.lookup(parser.name)
|
14
|
+
plugin = plugin_class.new(doc, node, result, context)
|
15
|
+
plugin.call(*parser.args)
|
16
|
+
end
|
17
|
+
unless result[:plugins].empty?
|
18
|
+
scanner = StringScanner.new(node.to_s)
|
19
|
+
new_node = ""
|
20
|
+
loop do
|
21
|
+
if scanner.match?(/{{.+?}}/)
|
22
|
+
new_node << result[:plugins].shift
|
23
|
+
scanner.pos += scanner.matched_size
|
24
|
+
else
|
25
|
+
new_node << scanner.getch
|
26
|
+
end
|
27
|
+
break if scanner.eos?
|
28
|
+
end
|
29
|
+
node.replace(new_node)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
doc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "redcarpet"
|
3
|
+
|
4
|
+
require "daimon/markdown/redcarpet/html_renderer"
|
5
|
+
|
6
|
+
module Daimon
|
7
|
+
module Markdown
|
8
|
+
module Filter
|
9
|
+
class Redcarpet < HTML::Pipeline::TextFilter
|
10
|
+
def call
|
11
|
+
Nokogiri::HTML.fragment(markdown.render(@text))
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def markdown
|
17
|
+
renderer = Daimon::Markdown::Redcarpet::HTMLRenderer.new(hard_wrap: true)
|
18
|
+
@markdown ||= ::Redcarpet::Markdown.new(
|
19
|
+
renderer,
|
20
|
+
fenced_code_blocks: true,
|
21
|
+
tables: true)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "ripper"
|
2
|
+
|
3
|
+
module Daimon
|
4
|
+
module Markdown
|
5
|
+
class Parser < Ripper
|
6
|
+
|
7
|
+
KEYWORDS = {
|
8
|
+
"nil" => nil,
|
9
|
+
"true" => true,
|
10
|
+
"false" => false
|
11
|
+
}
|
12
|
+
|
13
|
+
attr_reader :name, :args
|
14
|
+
|
15
|
+
def initialize(src)
|
16
|
+
super
|
17
|
+
@name = nil
|
18
|
+
@args = []
|
19
|
+
@level = 0
|
20
|
+
@array = []
|
21
|
+
@arrays = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_vcall(name)
|
25
|
+
@name = name
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_command(name, *args)
|
29
|
+
@name = name
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_fcall(name)
|
33
|
+
@name = name
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_tstring_content(content)
|
37
|
+
if @level == 0
|
38
|
+
@args << content
|
39
|
+
else
|
40
|
+
@arrays[@level] << content
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_int(value)
|
45
|
+
if @level == 0
|
46
|
+
@args << value.to_i
|
47
|
+
else
|
48
|
+
@arrays[@level] << value.to_i
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_float(value)
|
53
|
+
if @level == 0
|
54
|
+
@args << value.to_f
|
55
|
+
else
|
56
|
+
@arrays[@level] << value.to_f
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def on_const(name)
|
61
|
+
@args << Object.const_get(name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_kw(keyword)
|
65
|
+
@args << KEYWORDS[keyword]
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_array(args)
|
69
|
+
if @level == 0
|
70
|
+
@args << @arrays[0].first
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def on_lbracket(*args)
|
75
|
+
if @level == 0
|
76
|
+
@arrays[0] = []
|
77
|
+
end
|
78
|
+
@level += 1
|
79
|
+
@arrays[@level] = []
|
80
|
+
end
|
81
|
+
|
82
|
+
def on_rbracket(*args)
|
83
|
+
@arrays[@level - 1] << @arrays[@level]
|
84
|
+
@level -= 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "cgi/util"
|
2
|
+
|
3
|
+
module Daimon
|
4
|
+
module Markdown
|
5
|
+
class Plugin
|
6
|
+
class Base
|
7
|
+
include CGI::Util
|
8
|
+
|
9
|
+
attr_reader :doc, :node, :result, :context
|
10
|
+
|
11
|
+
def initialize(doc, node, result, context)
|
12
|
+
@doc = doc
|
13
|
+
@node = node
|
14
|
+
@result = result
|
15
|
+
@context = context
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(*args)
|
19
|
+
raise "Implement this method in subclass"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Daimon
|
2
|
+
module Markdown
|
3
|
+
class Plugin
|
4
|
+
class Chat < Base
|
5
|
+
Plugin.register("chat", self)
|
6
|
+
|
7
|
+
def call(*args)
|
8
|
+
speaches = []
|
9
|
+
args.each_slice(2) do |url, text|
|
10
|
+
speaches << <<~SPEACH.chomp
|
11
|
+
<img src="#{url}" />
|
12
|
+
<p>#{text}</p>
|
13
|
+
SPEACH
|
14
|
+
end
|
15
|
+
html = %Q(<div class="chat">\n#{speaches.join("\n")}\n</div>)
|
16
|
+
node.parent.replace(html)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Daimon
|
2
|
+
module Markdown
|
3
|
+
class Plugin
|
4
|
+
class Figure < Base
|
5
|
+
Plugin.register("figure", self)
|
6
|
+
|
7
|
+
def call(src, alt, caption)
|
8
|
+
figure = <<~HTML
|
9
|
+
<figure>
|
10
|
+
<img src="#{src}" alt="#{alt}">
|
11
|
+
<figcaption>#{caption}</figcaption>
|
12
|
+
</figure>
|
13
|
+
HTML
|
14
|
+
node.parent.replace(figure)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Daimon
|
2
|
+
module Markdown
|
3
|
+
class Plugin
|
4
|
+
class Math < Base
|
5
|
+
Plugin.register("math", self)
|
6
|
+
|
7
|
+
def self.script_tag
|
8
|
+
<<~TAG
|
9
|
+
<script type="text/javascript"
|
10
|
+
async
|
11
|
+
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">
|
12
|
+
</script>
|
13
|
+
<script type="text/x-mathjax-config">
|
14
|
+
MathJax.Hub.Config({
|
15
|
+
tex2jax: {inlineMath: [['$','$']]},
|
16
|
+
asciimath2jax: {delimiters: [['`', '`']]},
|
17
|
+
TeX: {extensions: ["mhchem.js"]}
|
18
|
+
});
|
19
|
+
</script>
|
20
|
+
TAG
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(expression)
|
24
|
+
if expression.start_with?("$$")
|
25
|
+
node.parent.replace(%Q(<div class="math">#{expression}</div>))
|
26
|
+
else
|
27
|
+
result[:plugins] << expression
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Daimon
|
2
|
+
module Markdown
|
3
|
+
class Plugin
|
4
|
+
class TableOfContents < Base
|
5
|
+
Plugin.register("toc", self)
|
6
|
+
|
7
|
+
def call
|
8
|
+
toc_html = ""
|
9
|
+
items = []
|
10
|
+
|
11
|
+
headers = Hash.new(0)
|
12
|
+
previous_level = 1
|
13
|
+
doc.css("h1, h2, h3, h4, h5, h6").each do |header_node|
|
14
|
+
level = header_node.name.tr("h", "").to_i
|
15
|
+
text = header_node.text
|
16
|
+
id = text.downcase
|
17
|
+
id.gsub!(/ /, "-")
|
18
|
+
id.gsub!(/\s/, "")
|
19
|
+
|
20
|
+
if headers[id] > 0
|
21
|
+
unique_id = "#{id}-#{headers[id]}"
|
22
|
+
else
|
23
|
+
unique_id = id
|
24
|
+
end
|
25
|
+
headers[id] += 1
|
26
|
+
header_content = header_node.children.first
|
27
|
+
# TODO: Arrange indent level
|
28
|
+
if header_content
|
29
|
+
diff = level - previous_level
|
30
|
+
case
|
31
|
+
when diff > 0
|
32
|
+
items.concat(["<ul>"] * diff)
|
33
|
+
when diff < 0
|
34
|
+
items.concat(["</ul>"] * diff.abs)
|
35
|
+
end
|
36
|
+
items << list_item(link_to(unique_id, text))
|
37
|
+
header_node["id"] = unique_id
|
38
|
+
end
|
39
|
+
previous_level = level
|
40
|
+
end
|
41
|
+
toc_class = context[:toc_class] || "section-nav"
|
42
|
+
unless items.empty?
|
43
|
+
toc_html = %Q(<ul class="#{toc_class}">\n#{items.join("\n")}\n</ul>)
|
44
|
+
end
|
45
|
+
node.parent.replace(toc_html)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def link_to(href, text)
|
51
|
+
%Q(<a href="##{href}">#{text}</a>)
|
52
|
+
end
|
53
|
+
|
54
|
+
def list_item(content)
|
55
|
+
%Q(<li>#{content}</li>)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Daimon
|
2
|
+
module Markdown
|
3
|
+
class Plugin
|
4
|
+
|
5
|
+
PLUGIN_REGISTRY = {}
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def lookup(name)
|
9
|
+
PLUGIN_REGISTRY.fetch(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def register(name, klass)
|
13
|
+
PLUGIN_REGISTRY[name] = klass
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require "daimon/markdown/plugin/base"
|
21
|
+
Dir.glob("#{__dir__}/plugin/*.rb") do |entry|
|
22
|
+
require entry
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "html/pipeline"
|
2
|
+
|
3
|
+
require "daimon/markdown/filter"
|
4
|
+
require "daimon/markdown/plugin"
|
5
|
+
|
6
|
+
module Daimon
|
7
|
+
module Markdown
|
8
|
+
class Processor
|
9
|
+
|
10
|
+
DEFAULT_FILTERS = [
|
11
|
+
Daimon::Markdown::Filter::Redcarpet,
|
12
|
+
Daimon::Markdown::Filter::Plugin
|
13
|
+
]
|
14
|
+
|
15
|
+
attr_reader :context
|
16
|
+
|
17
|
+
def initialize(context = {})
|
18
|
+
@context = context
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(input, context = {})
|
22
|
+
HTML::Pipeline.new(filters, @context).call(input, context)
|
23
|
+
end
|
24
|
+
|
25
|
+
def filters
|
26
|
+
@filters ||= DEFAULT_FILTERS.clone
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "rouge/plugins/redcarpet"
|
2
|
+
|
3
|
+
module Daimon
|
4
|
+
module Markdown
|
5
|
+
module Redcarpet
|
6
|
+
class HTMLRenderer < ::Redcarpet::Render::HTML
|
7
|
+
include Rouge::Plugins::Redcarpet
|
8
|
+
|
9
|
+
def initialize(extensions = {})
|
10
|
+
super
|
11
|
+
@plugins = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def preprocess(full_document)
|
15
|
+
full_document.scan(/{{.+?}}/m) do |m|
|
16
|
+
@plugins << m
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def postprocess(full_document)
|
21
|
+
document = ""
|
22
|
+
scanner = StringScanner.new(full_document)
|
23
|
+
loop do
|
24
|
+
if scanner.match?(/{{.+?}}/m)
|
25
|
+
document << @plugins.shift
|
26
|
+
scanner.pos += scanner.matched_size
|
27
|
+
else
|
28
|
+
document << scanner.getch
|
29
|
+
end
|
30
|
+
break if scanner.eos?
|
31
|
+
end
|
32
|
+
document
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: daimon-markdown
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kenji Okimoto
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: html-pipeline
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redcarpet
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: rouge
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.12'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.12'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '11.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '11.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: test-unit
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: test-unit-notify
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Markdown renderer for Daimon
|
112
|
+
email:
|
113
|
+
- okimoto@clear-code.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rubocop.yml"
|
120
|
+
- ".travis.yml"
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- daimon-markdown.gemspec
|
126
|
+
- lib/daimon/markdown.rb
|
127
|
+
- lib/daimon/markdown/filter.rb
|
128
|
+
- lib/daimon/markdown/filter/plugin.rb
|
129
|
+
- lib/daimon/markdown/filter/redcarpet.rb
|
130
|
+
- lib/daimon/markdown/parser.rb
|
131
|
+
- lib/daimon/markdown/plugin.rb
|
132
|
+
- lib/daimon/markdown/plugin/base.rb
|
133
|
+
- lib/daimon/markdown/plugin/chat.rb
|
134
|
+
- lib/daimon/markdown/plugin/figure.rb
|
135
|
+
- lib/daimon/markdown/plugin/math.rb
|
136
|
+
- lib/daimon/markdown/plugin/toc.rb
|
137
|
+
- lib/daimon/markdown/processor.rb
|
138
|
+
- lib/daimon/markdown/redcarpet/html_renderer.rb
|
139
|
+
- lib/daimon/markdown/version.rb
|
140
|
+
homepage: https://github.com/bm-sms/daimon-markdown
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
metadata: {}
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 2.2.0
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
requirements: []
|
159
|
+
rubyforge_project:
|
160
|
+
rubygems_version: 2.5.1
|
161
|
+
signing_key:
|
162
|
+
specification_version: 4
|
163
|
+
summary: Markdown renderer for Daimon
|
164
|
+
test_files: []
|