pot_markdown 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fc4198215a42e5cd6a0036b8a54a0c26b81cbd2b
4
+ data.tar.gz: b8ffad58b41b1a57cfdca3da7a593c2711fbfab5
5
+ SHA512:
6
+ metadata.gz: ab1aa42c91f747191b806c75c8116b309d53b655cc015b3b51c1e6a9598e8c5f358a5aba7a4312eed00d2a862ae8cf12d31342cd9872a41839168613637bf13c
7
+ data.tar.gz: 8207218248059fc0a5d6ba3062d0ed2c9e76b4524147425fcfd54e85f33276d46278d4dcdaa741ad365a2ff43c84773dbd1e66fc2e1ea290979d1a5dcf391b47
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,27 @@
1
+ AllCops:
2
+ Exclude:
3
+ - bin/**/*
4
+ - tmp/**/*
5
+ - vendor/**/*
6
+ - test/files/**/*
7
+
8
+ AsciiComments:
9
+ Enabled: false
10
+
11
+ ClassLength:
12
+ Max: 200
13
+
14
+ Documentation:
15
+ Enabled: false
16
+
17
+ LineLength:
18
+ Max: 120
19
+
20
+ MethodLength:
21
+ Max: 30
22
+
23
+ PerceivedComplexity:
24
+ Exclude:
25
+ - lib/kramdown/**/*
26
+
27
+ inherit_from: .rubocop_todo.yml
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,12 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-02-28 03:04:33 +0900 using RuboCop version 0.37.2.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ Metrics/AbcSize:
11
+ Max: 35
12
+
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3.0
7
+ - ruby-head
8
+ before_install:
9
+ - gem install bundler
10
+ script:
11
+ - bundle exec rake
12
+ - bundle exec rubocop
13
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # PotMarkdown
2
+
3
+ [![Build Status](https://travis-ci.org/rutan/pot_markdown.svg)](https://travis-ci.org/rutan/pot_markdown)
4
+
5
+ PotMarkdown is markdown processor for [Potmum](https://github.com/rutan/potmum).
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'pot_markdown'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install pot_markdown
22
+
23
+ ## Usage
24
+
25
+ ```ruby
26
+ require 'pot_markdown'
27
+
28
+ processor = PotMarkdown::Processor.new
29
+ context = {
30
+ safe_script_url: false
31
+ }
32
+ processor.call("# title\n\n Hello, **Potmum!** ...", context)
33
+ # => {
34
+ # toc: "<ul><li><a href=\"#id-title\">title ...",
35
+ # output: "<h1 id=\"id-title\">title</h1>...",
36
+ # mentioned_usernames: ['rutan', ...]
37
+ # }
38
+ ```
39
+
40
+ ## context
41
+
42
+ - `anchor_icon`
43
+ - header link icon
44
+ - default)
45
+ - `<i class="fa fa-link"></i>`
46
+ - `checkbox_enable`
47
+ - not set attribute `disabled` to checkbox
48
+ - default: `false`
49
+ - `checkbox_class`
50
+ - `<li>` 's class with checkbox
51
+ - default: `task-list-item`
52
+ - `sanitize_rule`
53
+ - [sanitize gem](https://github.com/rgrove/sanitize) parameters.
54
+ - `sanitize_use_external`
55
+ - to enable the particular script/iframe
56
+ - ex)
57
+ - Youtube
58
+ - Twitter
59
+ - niconico
60
+ - SlideShare
61
+ - and more... (see SanitizeIframeFilter and SanitizeScriptFilter)
62
+ - `safe_iframe_url`
63
+ - enable iframe url, if use sanitize_use_external
64
+ - `safe_script_url`
65
+ - enable script url, if use sanitize_use_external
66
+
67
+ ### others
68
+
69
+ PotMarkdown used these filters.
70
+
71
+ - HTML::Pipeline::AutolinkFilter
72
+ - HTML::Pipeline::EmojiFilter
73
+ - HTML::Pipeline::MentionFilter
74
+
75
+ please see [html-pipeline](https://github.com/jch/html-pipeline) documents :)
76
+
77
+ ## Contributing
78
+
79
+ Bug reports and pull requests are welcome on GitHub at https://github.com/rutan/pot_markdown
80
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.test_files = FileList['test/**/*_test.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'pot_markdown'
5
+ require 'pry'
6
+ Pry.start
7
+
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,90 @@
1
+ require 'kramdown/parser'
2
+ require 'rouge'
3
+
4
+ module Kramdown
5
+ module Parser
6
+ class PotMarkdown < Kramdown::Parser::GFM
7
+ def initialize(source, options)
8
+ super
9
+ @span_parsers << :strikethrough_pot unless methods.include?(:parse_strikethrough_gfm)
10
+ end
11
+
12
+ def parse_atx_header
13
+ # ↓ removed in pot_markdown
14
+ # return false if !after_block_boundary?
15
+
16
+ start_line_number = @src.current_line_number
17
+ @src.check(ATX_HEADER_MATCH)
18
+ level = @src[1]
19
+ text = @src[2].to_s.strip
20
+ id = @src[3]
21
+ return false if text.empty?
22
+
23
+ @src.pos += @src.matched_size
24
+ el = new_block_el(:header, nil, nil, level: level.length, raw_text: text, location: start_line_number)
25
+ add_text(text, el)
26
+ el.attr['id'] = id if id
27
+ @tree.children << el
28
+ true
29
+ end
30
+
31
+ FENCED_CODEBLOCK_MATCH = /^(([~`]){3,})\s*?((\w[\w\:\.-]*)(?:\?\S*)?)?\s*?\n(.*?)^\1\2*\s*?\n/m
32
+
33
+ def parse_codeblock_fenced
34
+ if @src.check(self.class::FENCED_CODEBLOCK_MATCH)
35
+ start_line_number = @src.current_line_number
36
+ @src.pos += @src.matched_size
37
+ el = new_block_el(:codeblock, @src[5], nil, location: start_line_number)
38
+ lang = @src[3].to_s.strip
39
+ unless lang.empty?
40
+ lang, filename = lang.split(':', 2)
41
+ if filename.nil? && lang.include?('.')
42
+ filename = lang
43
+ lang = Rouge::Lexer.guess_by_filename(filename).name.match(/[^\:]+\z/).to_s.downcase
44
+ end
45
+ el.options[:lang] = lang
46
+ el.attr['data-lang'] = lang
47
+ if filename
48
+ el.attr['class'] = "language-#{lang} has-filename"
49
+ el.attr['data-filename'] = filename
50
+ else
51
+ el.attr['class'] = "language-#{lang}"
52
+ end
53
+ end
54
+ @tree.children << el
55
+ true
56
+ else
57
+ false
58
+ end
59
+ end
60
+
61
+ unless instance_methods.include?(:parse_strikethrough_gfm)
62
+ STRIKETHROUGH_POT_DELIMITER = /~~/
63
+
64
+ def parse_strikethrough_pot
65
+ start_line_number = @src.current_line_number
66
+ result = @src.scan(STRIKETHROUGH_POT_DELIMITER)
67
+ saved_pos = @src.save_pos
68
+
69
+ if @src.pre_match =~ /\s\Z/ && @src.match?(/\s/)
70
+ add_text(result)
71
+ return
72
+ end
73
+
74
+ text = @src.scan_until(/#{result}/)
75
+ if text
76
+ text.sub!(/#{result}\Z/, '')
77
+ del = Element.new(:html_element, 'del', {}, category: :span, line: start_line_number)
78
+ del.children << Element.new(:text, text, category: :span, line: start_line_number)
79
+ @tree.children << del
80
+ else
81
+ @src.revert_pos(saved_pos)
82
+ add_text(result)
83
+ end
84
+ end
85
+
86
+ define_parser(:strikethrough_pot, STRIKETHROUGH_POT_DELIMITER, '~')
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,39 @@
1
+ module PotMarkdown
2
+ module Filters
3
+ class CheckboxFilter < HTML::Pipeline::Filter
4
+ def call
5
+ doc.xpath('.//li').each do |node|
6
+ child = node.children.first
7
+ next unless child.name == 'text'
8
+ checkbox, text = checkbox_filter(child.text)
9
+ next unless checkbox
10
+ node.children.first.replace(text)
11
+ node.children.first.add_previous_sibling(checkbox)
12
+ node.set_attribute('class', "#{node.attribute('class')} #{checkbox_class}".strip)
13
+ end
14
+ doc
15
+ end
16
+
17
+ def checkbox_filter(text)
18
+ checkbox = nil
19
+ text = text.gsub(CHECKBOX_PATTERN) do
20
+ checked = (Regexp.last_match(1) == 'x')
21
+ checkbox =
22
+ "<input type=\"checkbox\"#{' checked="checked"' if checked}#{' disabled="disabled"' if disable?} />"
23
+ ''
24
+ end
25
+ [checkbox, text]
26
+ end
27
+
28
+ def disable?
29
+ context[:checkbox_enable].nil? || context[:checkbox_enable]
30
+ end
31
+
32
+ def checkbox_class
33
+ context[:checkbox_class] || 'task-list-item'
34
+ end
35
+
36
+ CHECKBOX_PATTERN = /\A\[(?<type>\s+|x)\]/
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ require 'nokogiri'
2
+ require 'kramdown'
3
+ require 'kramdown/parser/pot_markdown'
4
+
5
+ module PotMarkdown
6
+ module Filters
7
+ class MarkdownFilter < HTML::Pipeline::TextFilter
8
+ def initialize(text, context = nil, result = nil)
9
+ super
10
+ @text = @text.delete("\r").strip
11
+ end
12
+
13
+ def call
14
+ Nokogiri::HTML.fragment Kramdown::Document.new(
15
+ @text,
16
+ input: 'PotMarkdown',
17
+ auto_id_prefix: 'id-',
18
+ syntax_highlighter: 'rouge',
19
+ math_engine: nil
20
+ ).to_html.rstrip!
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ require 'nokogiri'
2
+ require 'sanitize'
3
+
4
+ module PotMarkdown
5
+ module Filters
6
+ class MentionFilter < HTML::Pipeline::MentionFilter
7
+ USER_NAME_PATTERN = /[A-Za-z0-9][A-Za-z0-9\-\_]+/
8
+
9
+ def call
10
+ result[:mentioned_usernames] ||= []
11
+
12
+ doc.xpath('.//text()').each do |node|
13
+ content = node.text
14
+ next unless content.include?('@')
15
+ next if has_ancestor?(node, IGNORE_PARENTS)
16
+ html = mention_link_filter(content, base_url, info_url, username_pattern)
17
+ next if html == content
18
+ node.replace(html)
19
+ end
20
+ doc
21
+ end
22
+
23
+ def username_pattern
24
+ context[:username_pattern] || USER_NAME_PATTERN
25
+ end
26
+
27
+ def link_to_mentioned_user(login)
28
+ result[:mentioned_usernames] |= [login]
29
+ "<a href='#{base_url}#{login}' class='user-mention'>@#{login}</a>"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,159 @@
1
+ require 'nokogiri'
2
+ require 'sanitize'
3
+
4
+ require 'pot_markdown/filters/sanitize_transformers/list_transformer'
5
+ require 'pot_markdown/filters/sanitize_transformers/table_transformer'
6
+
7
+ module PotMarkdown
8
+ module Filters
9
+ class SanitizeHTMLFilter < HTML::Pipeline::Filter
10
+ def call
11
+ Sanitize.clean_node!(doc, rule)
12
+ end
13
+
14
+ RULE = {
15
+ elements: %w(
16
+ a
17
+ b
18
+ blockquote
19
+ br
20
+ code
21
+ dd
22
+ del
23
+ details
24
+ div
25
+ dl
26
+ dt
27
+ em
28
+ h1
29
+ h2
30
+ h3
31
+ h4
32
+ h5
33
+ h6
34
+ hr
35
+ i
36
+ img
37
+ input
38
+ ins
39
+ kbd
40
+ li
41
+ ol
42
+ p
43
+ pre
44
+ q
45
+ rp
46
+ rt
47
+ ruby
48
+ s
49
+ samp
50
+ span
51
+ strike
52
+ strong
53
+ sub
54
+ summary
55
+ sup
56
+ table
57
+ tbody
58
+ td
59
+ tfoot
60
+ th
61
+ thead
62
+ tr
63
+ tt
64
+ ul
65
+ var
66
+ ),
67
+ attributes: {
68
+ all: %w(
69
+ abbr
70
+ align
71
+ alt
72
+ border
73
+ cellpadding
74
+ cellspacing
75
+ cite
76
+ class
77
+ color
78
+ cols
79
+ colspan
80
+ datetime
81
+ height
82
+ hreflang
83
+ itemprop
84
+ lang
85
+ name
86
+ rowspan
87
+ style
88
+ tabindex
89
+ target
90
+ title
91
+ width
92
+ ) + [:data],
93
+ 'a' => %w(
94
+ href
95
+ ),
96
+ 'div' => %w(
97
+ itemscope
98
+ itemtype
99
+ ),
100
+ 'iframe' => %w(
101
+ allowfullscreen
102
+ frameborder
103
+ src
104
+ scrolling
105
+ ),
106
+ 'img' => %w(
107
+ src
108
+ ),
109
+ 'input' => %w(
110
+ checked
111
+ disabled
112
+ type
113
+ ),
114
+ 'script' => %w(
115
+ src
116
+ )
117
+ },
118
+ css: {
119
+ properties: %w(
120
+ border
121
+ color
122
+ height
123
+ text-align
124
+ width
125
+ )
126
+ },
127
+ protocols: {
128
+ 'a' => {
129
+ 'href' => ['http', 'https', :relative]
130
+ },
131
+ 'img' => {
132
+ 'src' => ['http', 'https', :relative]
133
+ }
134
+ },
135
+ transformers: [
136
+ SanitizeTransformers::ListTransformer,
137
+ SanitizeTransformers::TableTransformer
138
+ ]
139
+ }.freeze
140
+
141
+ RULE_EXT = RULE.dup.tap do |rule|
142
+ rule[:elements] += %w(script iframe)
143
+ end
144
+
145
+ private
146
+
147
+ def rule
148
+ case
149
+ when context[:sanitize_rule]
150
+ context[:sanitize_rule]
151
+ when context[:sanitize_use_external]
152
+ RULE_EXT
153
+ else
154
+ RULE
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,49 @@
1
+ require 'nokogiri'
2
+ require 'sanitize'
3
+
4
+ module PotMarkdown
5
+ module Filters
6
+ class SanitizeIframeFilter < HTML::Pipeline::Filter
7
+ def call
8
+ doc.xpath('.//iframe').each do |element|
9
+ element.remove unless safe?(element)
10
+ end
11
+ doc
12
+ end
13
+
14
+ SAFE_IFRAME_URL = [
15
+ # youtube
16
+ %r{\Ahttps://www.youtube.com/embed/[^/]+\z},
17
+
18
+ # nicovideo
19
+ %r{\Ahttps?://ext.nicovideo.jp/thumb/[^/]+\z},
20
+
21
+ # nicolive
22
+ %r{\Ahttps?://live.nicovideo.jp/embed/.+\z},
23
+
24
+ # nicoseiga
25
+ %r{\Ahttps?://ext.seiga.nicovideo.jp/thumb/[^/]+\z},
26
+
27
+ # niconisolid
28
+ %r{\Ahttps?://3d.nicovideo.jp/externals/(?:widget|embedded)\?id=td\d+\z},
29
+
30
+ # slideshare
31
+ %r{\A(https?:)?//www.slideshare.net/slideshow/embed_code/key/[^/]+\z},
32
+
33
+ # plicy
34
+ %r{\Ahttps?://plicy.net/GameEmbed/\d+\z}
35
+ ].freeze
36
+
37
+ private
38
+
39
+ def safe?(element)
40
+ src = element['src']
41
+ safe_iframe_list.any? { |reg| src =~ reg }
42
+ end
43
+
44
+ def safe_iframe_list
45
+ context[:safe_iframe_url] || SAFE_IFRAME_URL
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,47 @@
1
+ require 'nokogiri'
2
+ require 'sanitize'
3
+
4
+ module PotMarkdown
5
+ module Filters
6
+ class SanitizeScriptFilter < HTML::Pipeline::Filter
7
+ def call
8
+ doc.xpath('.//script').each do |element|
9
+ if safe?(element)
10
+ element.children.remove
11
+ else
12
+ element.remove
13
+ end
14
+ end
15
+ doc
16
+ end
17
+
18
+ SAFE_SCRIPT_URL = [
19
+ # nicovideo
20
+ %r{\Ahttps?://ext.nicovideo.jp/thumb_watch/[^/]+\z},
21
+
22
+ # speakerdeck
23
+ %r{\A(https?:)?//speakerdeck.com/assets/embed.js\z},
24
+
25
+ # pixiv
26
+ %r{\Ahttps?://source.pixiv.net/source/embed.js\z},
27
+
28
+ # twitter
29
+ %r{\A(https:)?//platform.twitter.com/widgets.js\z},
30
+
31
+ # gist
32
+ %r{\Ahttps://gist.github.com/[A-Za-z0-9\-]+/[a-f0-9]+\.js\z}
33
+ ].freeze
34
+
35
+ private
36
+
37
+ def safe?(element)
38
+ src = element['src']
39
+ safe_script_list.any? { |reg| src =~ reg }
40
+ end
41
+
42
+ def safe_script_list
43
+ context[:safe_script_url] || SAFE_SCRIPT_URL
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,29 @@
1
+ module PotMarkdown
2
+ module Filters
3
+ module SanitizeTransformers
4
+ class ListTransformer
5
+ def self.call(*args)
6
+ new(*args).transform
7
+ end
8
+
9
+ def initialize(env)
10
+ @env = env
11
+ @name = env[:node_name]
12
+ @node = env[:node]
13
+ end
14
+
15
+ attr_reader :name, :node
16
+
17
+ def transform
18
+ return unless @name == NAME
19
+ return if node.ancestors.any? { |n| LIST_PARENT.include?(n.name) }
20
+
21
+ node.replace(node.children)
22
+ end
23
+
24
+ NAME = 'li'.freeze
25
+ LIST_PARENT = Set.new(%w(ul ol)).freeze
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ module PotMarkdown
2
+ module Filters
3
+ module SanitizeTransformers
4
+ class TableTransformer
5
+ def self.call(*args)
6
+ new(*args).transform
7
+ end
8
+
9
+ def initialize(env)
10
+ @env = env
11
+ @name = env[:node_name]
12
+ @node = env[:node]
13
+ end
14
+
15
+ attr_reader :name, :node
16
+
17
+ def transform
18
+ return unless NAMES.include?(name)
19
+ return if node.ancestors.any? { |n| n.name == LIST_PARENT }
20
+
21
+ node.replace(node.children)
22
+ end
23
+
24
+ NAMES = Set.new(%w(thead tbody tfoot tr td th)).freeze
25
+ LIST_PARENT = 'table'.freeze
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,64 @@
1
+ require 'nokogiri'
2
+
3
+ module PotMarkdown
4
+ module Filters
5
+ class TOCFilter < HTML::Pipeline::Filter
6
+ def call
7
+ result[:toc] = generate_toc(doc)
8
+ doc
9
+ end
10
+
11
+ private
12
+
13
+ def generate_toc(doc)
14
+ toc = Nokogiri::XML::Document.new
15
+ prev_level = nil
16
+
17
+ Nokogiri::XML::Element.new('ul', doc).tap do |ul|
18
+ doc.xpath('.//h1|.//h2|.//h3|.//h4|.//h5|.//h6').each do |element|
19
+ level = element.name.delete('h').to_i
20
+ prev_level = level unless prev_level
21
+
22
+ diff = level - prev_level
23
+ diff.abs.times do |_i|
24
+ if diff > 0
25
+ ul.add_child(Nokogiri::XML::Element.new('li', doc)) if ul.children.empty?
26
+ old_ul = ul
27
+ ul = Nokogiri::XML::Element.new('ul', doc)
28
+ old_ul.children.last.add_child(ul)
29
+ elsif ul.parent && ul.parent.parent
30
+ ul = ul.parent.parent
31
+ end
32
+ end
33
+
34
+ ul.add_child(create_item(toc, element))
35
+ element.children.first.add_previous_sibling(create_jump_icon(doc, element))
36
+
37
+ prev_level = level
38
+ end
39
+ end
40
+ end
41
+
42
+ def create_item(toc, element)
43
+ Nokogiri::XML::Element.new('li', toc).tap do |li|
44
+ link = Nokogiri::XML::Element.new('a', doc)
45
+ link.set_attribute('href', "##{element['id']}")
46
+ link.add_child(element.children.text.dup)
47
+ li.add_child(link)
48
+ end
49
+ end
50
+
51
+ def create_jump_icon(doc, element)
52
+ Nokogiri::XML::Element.new('a', doc).tap do |link|
53
+ link.set_attribute('href', "##{element['id']}")
54
+ anchor_icon_html = Nokogiri::HTML.fragment(anchor_icon)
55
+ link.add_child(anchor_icon_html)
56
+ end
57
+ end
58
+
59
+ def anchor_icon
60
+ context[:anchor_icon] || '<i class="fa fa-link"></i>'
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,41 @@
1
+ require 'html/pipeline'
2
+
3
+ require 'pot_markdown/filters/markdown_filter'
4
+ require 'pot_markdown/filters/sanitize_html_filter'
5
+ require 'pot_markdown/filters/sanitize_script_filter'
6
+ require 'pot_markdown/filters/sanitize_iframe_filter'
7
+ require 'pot_markdown/filters/mention_filter'
8
+ require 'pot_markdown/filters/toc_filter'
9
+ require 'pot_markdown/filters/checkbox_filter'
10
+
11
+ module PotMarkdown
12
+ class Processor
13
+ def initialize(default_context = {})
14
+ @default_context = DEFAULT_CONTEXT.merge(default_context)
15
+ end
16
+
17
+ def call(str, context = {})
18
+ HTML::Pipeline.new(filters, @default_context.merge(context)).call(str)
19
+ end
20
+
21
+ def filters
22
+ @filters ||= DEFAULT_FILTERS.dup
23
+ end
24
+
25
+ DEFAULT_CONTEXT = {
26
+ asset_root: '/assets'
27
+ }.freeze
28
+
29
+ DEFAULT_FILTERS = [
30
+ PotMarkdown::Filters::MarkdownFilter,
31
+ PotMarkdown::Filters::TOCFilter,
32
+ PotMarkdown::Filters::MentionFilter,
33
+ PotMarkdown::Filters::CheckboxFilter,
34
+ HTML::Pipeline::AutolinkFilter,
35
+ HTML::Pipeline::EmojiFilter,
36
+ PotMarkdown::Filters::SanitizeHTMLFilter,
37
+ PotMarkdown::Filters::SanitizeScriptFilter,
38
+ PotMarkdown::Filters::SanitizeIframeFilter
39
+ ].freeze
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module PotMarkdown
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'pot_markdown/version'
2
+ require 'pot_markdown/processor'
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pot_markdown/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'pot_markdown'
8
+ spec.version = PotMarkdown::VERSION
9
+ spec.authors = ['ru_shalm']
10
+ spec.email = ['ru_shalm@hazimu.com']
11
+
12
+ spec.summary = 'Markdown processor like GitHub'
13
+ spec.homepage = 'https://github.com/rutan/pot_markdown'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = 'exe'
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'html-pipeline', '~> 2.0'
21
+ spec.add_dependency 'kramdown', '~> 1.9'
22
+ spec.add_dependency 'rouge'
23
+ spec.add_dependency 'gemoji'
24
+ spec.add_dependency 'rinku'
25
+ spec.add_dependency 'sanitize'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.11'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'pry'
30
+ spec.add_development_dependency 'benchmark-ips'
31
+ spec.add_development_dependency 'test-unit'
32
+ spec.add_development_dependency 'diffy'
33
+ spec.add_development_dependency 'rubocop'
34
+ spec.add_development_dependency 'activesupport'
35
+ end
metadata ADDED
@@ -0,0 +1,262 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pot_markdown
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ru_shalm
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-03-05 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: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: kramdown
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.9'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.9'
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: gemoji
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rinku
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sanitize
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.11'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.11'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: benchmark-ips
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: test-unit
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: diffy
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rubocop
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: activesupport
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ description:
210
+ email:
211
+ - ru_shalm@hazimu.com
212
+ executables: []
213
+ extensions: []
214
+ extra_rdoc_files: []
215
+ files:
216
+ - ".gitignore"
217
+ - ".rubocop.yml"
218
+ - ".rubocop_todo.yml"
219
+ - ".travis.yml"
220
+ - Gemfile
221
+ - README.md
222
+ - Rakefile
223
+ - bin/console
224
+ - bin/setup
225
+ - lib/kramdown/parser/pot_markdown.rb
226
+ - lib/pot_markdown.rb
227
+ - lib/pot_markdown/filters/checkbox_filter.rb
228
+ - lib/pot_markdown/filters/markdown_filter.rb
229
+ - lib/pot_markdown/filters/mention_filter.rb
230
+ - lib/pot_markdown/filters/sanitize_html_filter.rb
231
+ - lib/pot_markdown/filters/sanitize_iframe_filter.rb
232
+ - lib/pot_markdown/filters/sanitize_script_filter.rb
233
+ - lib/pot_markdown/filters/sanitize_transformers/list_transformer.rb
234
+ - lib/pot_markdown/filters/sanitize_transformers/table_transformer.rb
235
+ - lib/pot_markdown/filters/toc_filter.rb
236
+ - lib/pot_markdown/processor.rb
237
+ - lib/pot_markdown/version.rb
238
+ - pot_markdown.gemspec
239
+ homepage: https://github.com/rutan/pot_markdown
240
+ licenses: []
241
+ metadata: {}
242
+ post_install_message:
243
+ rdoc_options: []
244
+ require_paths:
245
+ - lib
246
+ required_ruby_version: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ required_rubygems_version: !ruby/object:Gem::Requirement
252
+ requirements:
253
+ - - ">="
254
+ - !ruby/object:Gem::Version
255
+ version: '0'
256
+ requirements: []
257
+ rubyforge_project:
258
+ rubygems_version: 2.5.1
259
+ signing_key:
260
+ specification_version: 4
261
+ summary: Markdown processor like GitHub
262
+ test_files: []