pot_markdown 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []