html-pipeline 1.11.0 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e02d528270e77bac532de323b85833d8cd1e291f
4
- data.tar.gz: 34b71d6b7e4cc37953be770f478f4c8a61406494
3
+ metadata.gz: 81ea1429ab17d2b994718b0332f25cca4587258e
4
+ data.tar.gz: 1e88eb99b9689beaa37be9f07dd337b587e7f6de
5
5
  SHA512:
6
- metadata.gz: bce2524133b63fd81edb803e16e4f33be361a02bbec16c1be5d81bb045b0fc85df90e380e0a1b36b9ae37beb06b2f08302f8ed964bd6ff2138fee1d798992db0
7
- data.tar.gz: 0dd07655ca6e4efd6bfe74be9282722c52add045543f34b26c4fdb5a4cec7d32687d7d43d03854e0477c3db1479adbdf27b33b6860334f52bffbf78931665743
6
+ metadata.gz: 53dcb279bc816247b352642d0037dfdf7200622f8ec81e0f4e7e2f16f93dfb1131a159274cac6cd37822b6b9486f4160d20e78ec439a4a3a4731d10da23b60a7
7
+ data.tar.gz: 435e84847668fac1e7f8ea78e6dac82b7e646885523440ce57dc19e711e69875a1b2b0eca5aade300dbbefe0a5c064f4af66a7dbaa5af1d48a0ad1f9ba5b1d7d
data/.travis.yml CHANGED
@@ -7,13 +7,12 @@ before_install:
7
7
  script: "bundle exec rake"
8
8
 
9
9
  rvm:
10
- - 1.9.2
11
- - 1.9.3
12
- - 2.0.0
13
- - 2.1.1
14
- - ree
10
+ - 2.0
11
+ - 2.1
12
+ - 2.2
13
+ - ruby-head
15
14
 
16
15
  matrix:
17
16
  fast_finish: true
18
17
  allow_failures:
19
- - rvm: ree
18
+ - rvm: ruby-head
data/CHANGELOG.md CHANGED
@@ -1,9 +1,30 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.0
4
+
5
+ **New**
6
+
7
+ * Implement new EmojiFilter context option: ignored_ancestor_tags to accept more ignored tags. [#170](https://github.com/jch/html-pipeline/pull/170) @JuanitoFatas
8
+ * Add GitHub flavor Markdown Task List extension [#162](https://github.com/jch/html-pipeline/pull/162) @simeonwillbanks
9
+ * @mention allow for custom regex to identify usernames. [#157](https://github.com/jch/html-pipeline/pull/157) @brittballard
10
+ * EmojiFilter now requires gemoji ~> 2. [#159](https://github.com/jch/html-pipeline/pull/159) @jch
11
+
12
+ **Changes**
13
+
14
+ * Restrict nokogiri to >= 1.4, <= 1.6.5 [#176](https://github.com/jch/html-pipeline/pull/176) @simeonwillbanks
15
+ * MentionFilter#link_to_mentioned_user: Replace String introspection with Regexp match [#172](https://github.com/jch/html-pipeline/pull/172) @simeonwillbanks
16
+ * Whitelist summary and details element. [#171](https://github.com/jch/html-pipeline/pull/171) @JuanitoFatas
17
+ * Support ~login for MentionFilter. [#167](https://github.com/jch/html-pipeline/pull/167) @JuanitoFatas
18
+ * Revert "Search for text nodes on DocumentFragments without root tags" [#158](https://github.com/jch/html-pipeline/pull/158) @jch
19
+ * Drop support for ruby ree, 1.9.2, 1.9.3 [#156](https://github.com/jch/html-pipeline/pull/156) @jch
20
+ * Skip EmojiFilter in `<tt>` tags [#147](https://github.com/jch/html-pipeline/pull/147) @moskvax
21
+ * Use Linguist lexers [#153](https://github.com/jch/html-pipeline/pull/153) @pchaigno
22
+ * Constrain Active Support >= 2, < 5 [#180](https://github.com/jch/html-pipeline/pull/180) @jch
23
+
3
24
  ## 1.11.0
4
25
 
5
26
  * Search for text nodes on DocumentFragments without root tags #146 Razer6
6
- * Don't filter @mentions in <style> tags #145 jch
27
+ * Don't filter @mentions in `<style>` tags #145 jch
7
28
  * Prefer `http_url` in HttpsFilter. `base_url` still works. #142 bkeepers
8
29
  * Remove duplicate check in EmojiFilter #141 Razer6
9
30
 
data/Gemfile CHANGED
@@ -11,10 +11,11 @@ end
11
11
  group :test do
12
12
  gem "minitest", "~> 5.3"
13
13
  gem "rinku", "~> 1.7", :require => false
14
- gem "gemoji", "~> 1.0", :require => false
14
+ gem "gemoji", "~> 2.0", :require => false
15
15
  gem "RedCloth", "~> 4.2.9", :require => false
16
16
  gem "github-markdown", "~> 0.5", :require => false
17
17
  gem "email_reply_parser", "~> 0.5", :require => false
18
+ gem "sanitize", "~> 2.0", :require => false
18
19
 
19
20
  if RUBY_VERSION < "2.1.0"
20
21
  gem "escape_utils", "~> 0.3", :require => false
@@ -24,13 +25,6 @@ group :test do
24
25
  gem "github-linguist", "~> 2.10", :require => false
25
26
  end
26
27
 
27
- if RUBY_VERSION < "1.9.2"
28
- gem "sanitize", ">= 2", "< 2.0.4", :require => false
29
- gem "nokogiri", ">= 1.4", "< 1.6"
30
- else
31
- gem "sanitize", "~> 2.0", :require => false
32
- end
33
-
34
28
  if RUBY_VERSION < "1.9.3"
35
29
  gem "activesupport", ">= 2", "< 4"
36
30
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # HTML::Pipeline [![Build Status](https://secure.travis-ci.org/jch/html-pipeline.png)](http://travis-ci.org/jch/html-pipeline)
1
+ # HTML::Pipeline [![Build Status](https://travis-ci.org/jch/html-pipeline.svg?branch=master)](https://travis-ci.org/jch/html-pipeline)
2
2
 
3
3
  GitHub HTML processing filters and utilities. This module includes a small
4
4
  framework for defining DOM based content filters and applying them to user
@@ -78,10 +78,8 @@ Prints:
78
78
  ```html
79
79
  <p>This is <em>great</em>:</p>
80
80
 
81
- <div class="highlight">
82
- <pre><span class="n">some_code</span><span class="p">(</span><span class="ss">:first</span><span class="p">)</span>
83
- </pre>
84
- </div>
81
+ <pre><code>some_code(:first)
82
+ </code></pre>
85
83
  ```
86
84
 
87
85
  To generate CSS for HTML formatted code, use the [pygments.rb](https://github.com/tmm1/pygments.rb#usage) `#css` method. `pygments.rb` is a dependency of the `SyntaxHighlightFilter`.
@@ -141,6 +139,7 @@ NonGFMMarkdownPipeline = Pipeline.new(MarkdownPipeline.filters,
141
139
  # Pipelines aren't limited to the web. You can use them for email
142
140
  # processing also.
143
141
  HtmlEmailPipeline = Pipeline.new [
142
+ PlainTextInputFilter,
144
143
  ImageMaxWidthFilter
145
144
  ], {}
146
145
 
@@ -233,7 +232,19 @@ If you have an idea for a filter, propose it as
233
232
  whether the filter is a common enough use case to belong in this gem, or should be
234
233
  built as an external gem.
235
234
 
236
- * [html-pipeline-asciidoc_filter](https://github.com/asciidoctor/html-pipeline-asciidoc_filter) - asciidoc support
235
+ Here are some extensions people have built:
236
+
237
+ * [html-pipeline-asciidoc_filter](https://github.com/asciidoctor/html-pipeline-asciidoc_filter)
238
+ * [jekyll-html-pipeline](https://github.com/gjtorikian/jekyll-html-pipeline)
239
+ * [nanoc-html-pipeline](https://github.com/burnto/nanoc-html-pipeline)
240
+ * [html-pipeline-bity](https://github.com/dewski/html-pipeline-bitly)
241
+ * [html-pipeline-cite](https://github.com/lifted-studios/html-pipeline-cite)
242
+ * [tilt-html-pipeline](https://github.com/bradgessler/tilt-html-pipeline)
243
+ * [html-pipeline-wiki-link'](https://github.com/lifted-studios/html-pipeline-wiki-link) - WikiMedia-style wiki links
244
+ * [task_list](https://github.com/github/task_list) - GitHub flavor Markdown Task List
245
+ * [html-pipeline-rouge_filter](https://github.com/JuanitoFatas/html-pipeline-rouge_filter) - Syntax highlight with [Rouge](https://github.com/jneen/rouge/)
246
+ * [html-pipeline-nico_link](https://github.com/rutan/html-pipeline-nico_link) - An HTML::Pipeline filter for [niconico](http://www.nicovideo.jp) description links
247
+ * [html-pipeline-gitlab](https://gitlab.com/gitlab-org/html-pipeline-gitlab) - This gem implements various filters for html-pipeline used by GitLab
237
248
 
238
249
  ## Instrumenting
239
250
 
@@ -285,6 +296,36 @@ service.subscribe "call_pipeline.html_pipeline" do |event, start, ending, transa
285
296
  end
286
297
  ```
287
298
 
299
+ ## FAQ
300
+
301
+ ### 1. Why doesn't my pipeline work when there's no root element in the document?
302
+
303
+ To make a pipeline work on a plain text document, put the `PlainTextInputFilter`
304
+ at the beginning of your pipeline. This will wrap the content in a `div` so the
305
+ filters have a root element to work with. If you're passing in an HTML fragment,
306
+ but it doesn't have a root element, you can wrap the content in a `div`
307
+ yourself. For example:
308
+
309
+ ```ruby
310
+ EmojiPipeline = Pipeline.new [
311
+ PlainTextInputFilter, # <- Wraps input in a div and escapes html tags
312
+ EmojiFilter
313
+ ], context
314
+
315
+ plain_text = "Gutentag! :wave:"
316
+ EmojiPipeline.call(plain_text)
317
+
318
+ html_fragment = "This is outside of an html element, but <strong>this isn't. :+1:</strong>"
319
+ EmojiPipeline.call("<div>#{html_fragment}</div>") # <- Wrap your own html fragments to avoid escaping
320
+ ```
321
+
322
+ ### 2. How do I customize a whitelist for `SanitizationFilter`s?
323
+
324
+ `SanitizationFilter::WHITELIST` is the default whitelist used if no `:whitelist`
325
+ argument is given in the context. The default is a good starting template for
326
+ you to add additional elements. You can either modify the constant's value, or
327
+ re-define your own constant and pass that in via the context.
328
+
288
329
  ## Contributing
289
330
 
290
331
  Please review the [Contributing Guide](https://github.com/jch/html-pipeline/blob/master/CONTRIBUTING.md).
@@ -307,6 +348,9 @@ Project is a member of the [OSS Manifesto](http://ossmanifesto.org/).
307
348
 
308
349
  This section is for gem maintainers to cut a new version of the gem.
309
350
 
310
- * update lib/html/pipeline/version.rb to next version number X.X.X following [semver](http://semver.org).
311
- * update CHANGELOG.md. Get latest changes with `git log --oneline vLAST_RELEASE..HEAD | grep Merge`
351
+ * create a new branch named `release-x.y.z` where `x.y.z` follows [semver](http://semver.org)
352
+ * update lib/html/pipeline/version.rb to next version number X.X.X
353
+ * update CHANGELOG.md. Prepare a draft with `script/changelog`
354
+ * push branch and create a new pull request
355
+ * after tests are green, merge to master
312
356
  * on the master branch, run `script/release`
@@ -15,8 +15,8 @@ Gem::Specification.new do |gem|
15
15
  gem.test_files = gem.files.grep(%r{^test})
16
16
  gem.require_paths = ["lib"]
17
17
 
18
- gem.add_dependency "nokogiri", "~> 1.4"
19
- gem.add_dependency "activesupport", ">= 2"
18
+ gem.add_dependency "nokogiri", [">= 1.4", "<= 1.6.5"]
19
+ gem.add_dependency "activesupport", [">= 2", "< 5"]
20
20
 
21
21
  gem.post_install_message = <<msg
22
22
  -------------------------------------------------
@@ -11,6 +11,8 @@ module HTML
11
11
  # mention.
12
12
  # :info_url - Used to link to "more info" when someone mentions @mention
13
13
  # or @mentioned.
14
+ # :username_pattern - Used to provide a custom regular expression to
15
+ # identify usernames
14
16
  #
15
17
  class MentionFilter < Filter
16
18
  # Public: Find user @mentions in text. See
@@ -27,25 +29,31 @@ module HTML
27
29
  # the original text.
28
30
  #
29
31
  # Returns a String replaced with the return of the block.
30
- def self.mentioned_logins_in(text)
31
- text.gsub MentionPattern do |match|
32
+ def self.mentioned_logins_in(text, username_pattern=UsernamePattern)
33
+ text.gsub MentionPatterns[username_pattern] do |match|
32
34
  login = $1
33
35
  yield match, login, MentionLogins.include?(login.downcase)
34
36
  end
35
37
  end
36
38
 
37
- # Pattern used to extract @mentions from text.
38
- MentionPattern = /
39
- (?:^|\W) # beginning of string or non-word char
40
- @((?>[a-z0-9][a-z0-9-]*)) # @username
41
- (?!\/) # without a trailing slash
42
- (?=
43
- \.+[ \t\W]| # dots followed by space or non-word character
44
- \.+$| # dots at end of line
45
- [^0-9a-zA-Z_.]| # non-word character except dot
46
- $ # end of line
47
- )
48
- /ix
39
+ # Hash that contains all of the mention patterns used by the pipeline
40
+ MentionPatterns = Hash.new do |hash, key|
41
+ hash[key] = /
42
+ (?:^|\W) # beginning of string or non-word char
43
+ @((?>#{key})) # @username
44
+ (?!\/) # without a trailing slash
45
+ (?=
46
+ \.+[ \t\W]| # dots followed by space or non-word character
47
+ \.+$| # dots at end of line
48
+ [^0-9a-zA-Z_.]| # non-word character except dot
49
+ $ # end of line
50
+ )
51
+ /ix
52
+ end
53
+
54
+ # Default pattern used to extract usernames from text. The value can be
55
+ # overriden by providing the username_pattern variable in the context.
56
+ UsernamePattern = /[a-z0-9][a-z0-9-]*/
49
57
 
50
58
  # List of username logins that, when mentioned, link to the blog post
51
59
  # about @mentions instead of triggering a real mention.
@@ -62,11 +70,11 @@ module HTML
62
70
  def call
63
71
  result[:mentioned_usernames] ||= []
64
72
 
65
- search_text_nodes(doc).each do |node|
73
+ doc.search('text()').each do |node|
66
74
  content = node.to_html
67
75
  next if !content.include?('@')
68
76
  next if has_ancestor?(node, IGNORE_PARENTS)
69
- html = mention_link_filter(content, base_url, info_url)
77
+ html = mention_link_filter(content, base_url, info_url, username_pattern)
70
78
  next if html == content
71
79
  node.replace(html)
72
80
  end
@@ -79,6 +87,10 @@ module HTML
79
87
  context[:info_url] || nil
80
88
  end
81
89
 
90
+ def username_pattern
91
+ context[:username_pattern] || UsernamePattern
92
+ end
93
+
82
94
  # Replace user @mentions in text with links to the mentioned user's
83
95
  # profile page.
84
96
  #
@@ -86,11 +98,13 @@ module HTML
86
98
  # base_url - The base URL used to construct user profile URLs.
87
99
  # info_url - The "more info" URL used to link to more info on @mentions.
88
100
  # If nil we don't link @mention or @mentioned.
101
+ # username_pattern - Regular expression used to identify usernames in
102
+ # text
89
103
  #
90
104
  # Returns a string with @mentions replaced with links. All links have a
91
105
  # 'user-mention' class name attached for styling.
92
- def mention_link_filter(text, base_url='/', info_url=nil)
93
- self.class.mentioned_logins_in(text) do |match, login, is_mentioned|
106
+ def mention_link_filter(text, base_url='/', info_url=nil, username_pattern)
107
+ self.class.mentioned_logins_in(text, username_pattern) do |match, login, is_mentioned|
94
108
  link =
95
109
  if is_mentioned
96
110
  link_to_mention_info(login, info_url)
@@ -111,8 +125,11 @@ module HTML
111
125
 
112
126
  def link_to_mentioned_user(login)
113
127
  result[:mentioned_usernames] |= [login]
114
- url = File.join(base_url, login)
115
- "<a href='#{url}' class='user-mention'>" +
128
+
129
+ url = base_url.dup
130
+ url << "/" unless url =~ /[\/~]\z/
131
+
132
+ "<a href='#{url << login}' class='user-mention'>" +
116
133
  "@#{login}" +
117
134
  "</a>"
118
135
  end
@@ -13,19 +13,23 @@ module HTML
13
13
  # Context:
14
14
  # :asset_root (required) - base url to link to emoji sprite
15
15
  # :asset_path (optional) - url path to link to emoji sprite. :file_name can be used as a placeholder for the sprite file name. If no asset_path is set "emoji/:file_name" is used.
16
+ # :ignored_ancestor_tags (optional) - Tags to stop the emojification. Node has matched ancestor HTML tags will not be emojified. Default to pre, code, and tt tags. Extra tags please pass in the form of array, e.g., %w(blockquote summary).
16
17
  class EmojiFilter < Filter
18
+
19
+ DEFAULT_IGNORED_ANCESTOR_TAGS = %w(pre code tt).freeze
20
+
17
21
  def call
18
- search_text_nodes(doc).each do |node|
22
+ doc.search('text()').each do |node|
19
23
  content = node.to_html
20
24
  next unless content.include?(':')
21
- next if has_ancestor?(node, %w(pre code))
25
+ next if has_ancestor?(node, ignored_ancestor_tags)
22
26
  html = emoji_image_filter(content)
23
27
  next if html == content
24
28
  node.replace(html)
25
29
  end
26
30
  doc
27
31
  end
28
-
32
+
29
33
  # Implementation of validate hook.
30
34
  # Errors should raise exceptions or use an existing validator.
31
35
  def validate
@@ -79,23 +83,22 @@ module HTML
79
83
  self.class.emoji_pattern
80
84
  end
81
85
 
82
- # Detect gemoji v2 which has a new API
83
- # https://github.com/jch/html-pipeline/pull/129
84
- if Emoji.respond_to?(:all)
85
- def self.emoji_names
86
- Emoji.all.map(&:aliases).flatten.sort
87
- end
86
+ def self.emoji_names
87
+ Emoji.all.map(&:aliases).flatten.sort
88
+ end
88
89
 
89
- def emoji_filename(name)
90
- Emoji.find_by_alias(name).image_filename
91
- end
92
- else
93
- def self.emoji_names
94
- Emoji.names
95
- end
90
+ def emoji_filename(name)
91
+ Emoji.find_by_alias(name).image_filename
92
+ end
96
93
 
97
- def emoji_filename(name)
98
- "#{::CGI.escape(name)}.png"
94
+ # Return ancestor tags to stop the emojification.
95
+ #
96
+ # @return [Array<String>] Ancestor tags.
97
+ def ignored_ancestor_tags
98
+ if context[:ignored_ancestor_tags]
99
+ DEFAULT_IGNORED_ANCESTOR_TAGS | context[:ignored_ancestor_tags]
100
+ else
101
+ DEFAULT_IGNORED_ANCESTOR_TAGS
99
102
  end
100
103
  end
101
104
  end
@@ -59,13 +59,6 @@ module HTML
59
59
  @doc ||= parse_html(html)
60
60
  end
61
61
 
62
- # Searches a Nokogiri::HTML::DocumentFragment for text nodes. If no elements
63
- # are found, a second search without root tags is invoked.
64
- def search_text_nodes(doc)
65
- nodes = doc.xpath('.//text()')
66
- nodes.empty? ? doc.xpath('text()') : nodes
67
- end
68
-
69
62
  # The String representation of the document. If a DocumentFragment was
70
63
  # provided to the Filter, it is serialized into a String when this method is
71
64
  # called.
@@ -45,7 +45,7 @@ module HTML
45
45
  :elements => %w(
46
46
  h1 h2 h3 h4 h5 h6 h7 h8 br b i strong em a pre code img tt
47
47
  div ins del sup sub p ol ul table thead tbody tfoot blockquote
48
- dl dt dd kbd q samp var hr ruby rt rp li tr td th s strike
48
+ dl dt dd kbd q samp var hr ruby rt rp li tr td th s strike summary details
49
49
  ),
50
50
  :remove_contents => ['script'],
51
51
  :attributes => {
@@ -57,13 +57,13 @@ module HTML
57
57
  'border', 'cellpadding', 'cellspacing', 'char',
58
58
  'charoff', 'charset', 'checked', 'cite',
59
59
  'clear', 'cols', 'colspan', 'color',
60
- 'compact', 'coords', 'datetime', 'details', 'dir',
60
+ 'compact', 'coords', 'datetime', 'dir',
61
61
  'disabled', 'enctype', 'for', 'frame',
62
62
  'headers', 'height', 'hreflang',
63
63
  'hspace', 'ismap', 'label', 'lang',
64
64
  'longdesc', 'maxlength', 'media', 'method',
65
65
  'multiple', 'name', 'nohref', 'noshade',
66
- 'nowrap', 'prompt', 'readonly', 'rel', 'rev',
66
+ 'nowrap', 'open', 'prompt', 'readonly', 'rel', 'rev',
67
67
  'rows', 'rowspan', 'rules', 'scope',
68
68
  'selected', 'shape', 'size', 'span',
69
69
  'start', 'summary', 'tabindex', 'target',
@@ -13,7 +13,7 @@ module HTML
13
13
  doc.search('pre').each do |node|
14
14
  default = context[:highlight] && context[:highlight].to_s
15
15
  next unless lang = node['lang'] || default
16
- next unless lexer = Pygments::Lexer[lang]
16
+ next unless lexer = lexer_for(lang)
17
17
  text = node.inner_text
18
18
 
19
19
  html = highlight_with_timeout_handling(lexer, text)
@@ -34,6 +34,10 @@ module HTML
34
34
  rescue Timeout::Error => boom
35
35
  nil
36
36
  end
37
+
38
+ def lexer_for(lang)
39
+ (Linguist::Language[lang] && Linguist::Language[lang].lexer) || Pygments::Lexer[lang]
40
+ end
37
41
  end
38
42
  end
39
43
  end
@@ -1,5 +1,5 @@
1
1
  module HTML
2
2
  class Pipeline
3
- VERSION = "1.11.0"
3
+ VERSION = "2.0"
4
4
  end
5
5
  end
data/script/changelog ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env sh
2
+ # Usage: script/changelog [-r <repo>] [-b <base>] [-h <head>]
3
+ #
4
+ # repo: base string of GitHub repository url. e.g. "user_or_org/repository". Defaults to git remote url.
5
+ # base: git ref to compare from. e.g. "v1.3.1". Defaults to latest git tag.
6
+ # head: git ref to compare to. Defaults to "HEAD".
7
+ #
8
+ # Generate a changelog preview from pull requests merged between `base` and
9
+ # `head`.
10
+ #
11
+ # https://github.com/jch/release-scripts
12
+ set -e
13
+
14
+ [ $# -eq 0 ] && set -- --help
15
+
16
+ # parse args
17
+ repo='jch/html-pipeline'
18
+ base=$(git tag -l | sort -t. -k 1,1n -k 2,2n -k 3,3n | tail -n 1)
19
+ head="HEAD"
20
+ api_url="https://api.github.com"
21
+
22
+ echo "# $repo $base..$head"
23
+ echo
24
+
25
+ # get merged PR's. Better way is to query the API for these, but this is easier
26
+ for pr in $(git log --oneline $base..$head | grep "Merge pull request" | awk '{gsub("#",""); print $5}')
27
+ do
28
+ # frustrated with trying to pull out the right values, fell back to ruby
29
+ curl -s "$api_url/repos/$repo/pulls/$pr" | ruby -rjson -e 'pr=JSON.parse(STDIN.read); puts "* #{pr[%q(title)]} [##{pr[%q(number)]}](#{pr[%q(html_url)]}) @#{pr[%q(user)][%q(login)]}"'
30
+ done
@@ -2,28 +2,22 @@ require 'test_helper'
2
2
 
3
3
  class HTML::Pipeline::EmojiFilterTest < Minitest::Test
4
4
  EmojiFilter = HTML::Pipeline::EmojiFilter
5
-
5
+
6
6
  def test_emojify
7
7
  filter = EmojiFilter.new("<p>:shipit:</p>", {:asset_root => 'https://foo.com'})
8
8
  doc = filter.call
9
9
  assert_match "https://foo.com/emoji/shipit.png", doc.search('img').attr('src').value
10
10
  end
11
11
 
12
- def test_emojify_on_string
13
- filter = EmojiFilter.new(":shipit:", {:asset_root => 'https://foo.com'})
14
- doc = filter.call
15
- assert_match "https://foo.com/emoji/shipit.png", doc.search('img').attr('src').value
16
- end
17
-
18
12
  def test_uri_encoding
19
13
  filter = EmojiFilter.new("<p>:+1:</p>", {:asset_root => 'https://foo.com'})
20
14
  doc = filter.call
21
- assert_match "https://foo.com/emoji/%2B1.png", doc.search('img').attr('src').value
15
+ assert_match "https://foo.com/emoji/unicode/1f44d.png", doc.search('img').attr('src').value
22
16
  end
23
-
17
+
24
18
  def test_required_context_validation
25
- exception = assert_raises(ArgumentError) {
26
- EmojiFilter.call("", {})
19
+ exception = assert_raises(ArgumentError) {
20
+ EmojiFilter.call("", {})
27
21
  }
28
22
  assert_match /:asset_root/, exception.message
29
23
  end
@@ -31,6 +25,41 @@ class HTML::Pipeline::EmojiFilterTest < Minitest::Test
31
25
  def test_custom_asset_path
32
26
  filter = EmojiFilter.new("<p>:+1:</p>", {:asset_path => ':file_name', :asset_root => 'https://foo.com'})
33
27
  doc = filter.call
34
- assert_match "https://foo.com/%2B1.png", doc.search('img').attr('src').value
28
+ assert_match "https://foo.com/unicode/1f44d.png", doc.search('img').attr('src').value
29
+ end
30
+
31
+ def test_not_emojify_in_code_tags
32
+ body = "<code>:shipit:</code>"
33
+ filter = EmojiFilter.new(body, {:asset_root => 'https://foo.com'})
34
+ doc = filter.call
35
+ assert_equal body, doc.to_html
36
+ end
37
+
38
+ def test_not_emojify_in_tt_tags
39
+ body = "<tt>:shipit:</tt>"
40
+ filter = EmojiFilter.new(body, {:asset_root => 'https://foo.com'})
41
+ doc = filter.call
42
+ assert_equal body, doc.to_html
43
+ end
44
+
45
+ def test_not_emojify_in_pre_tags
46
+ body = "<pre>:shipit:</pre>"
47
+ filter = EmojiFilter.new(body, {:asset_root => 'https://foo.com'})
48
+ doc = filter.call
49
+ assert_equal body, doc.to_html
50
+ end
51
+
52
+ def test_not_emojify_in_custom_single_tag_foo
53
+ body = "<foo>:shipit:</foo>"
54
+ filter = EmojiFilter.new(body, {:asset_root => 'https://foo.com', ignored_ancestor_tags: %w(foo)})
55
+ doc = filter.call
56
+ assert_equal body, doc.to_html
57
+ end
58
+
59
+ def test_not_emojify_in_custom_multiple_tags_foo_and_bar
60
+ body = "<bar>:shipit:</bar>"
61
+ filter = EmojiFilter.new(body, {:asset_root => 'https://foo.com', ignored_ancestor_tags: %w(foo bar)})
62
+ doc = filter.call
63
+ assert_equal body, doc.to_html
35
64
  end
36
65
  end
@@ -1,8 +1,8 @@
1
1
  require "test_helper"
2
2
 
3
3
  class HTML::Pipeline::MentionFilterTest < Minitest::Test
4
- def filter(html, base_url='/', info_url=nil)
5
- HTML::Pipeline::MentionFilter.call(html, :base_url => base_url, :info_url => info_url)
4
+ def filter(html, base_url='/', info_url=nil, username_pattern=nil)
5
+ HTML::Pipeline::MentionFilter.call(html, :base_url => base_url, :info_url => info_url, :username_pattern => username_pattern)
6
6
  end
7
7
 
8
8
  def test_filtering_a_documentfragment
@@ -72,6 +72,27 @@ class HTML::Pipeline::MentionFilterTest < Minitest::Test
72
72
  filter(body, '/', 'https://github.com/blog/821').to_html
73
73
  end
74
74
 
75
+ def test_base_url_slash
76
+ body = "<p>Hi, @jch!</p>"
77
+ link = "<a href=\"/jch\" class=\"user-mention\">@jch</a>"
78
+ assert_equal "<p>Hi, #{link}!</p>",
79
+ filter(body, '/').to_html
80
+ end
81
+
82
+ def test_base_url_under_custom_route
83
+ body = "<p>Hi, @jch!</p>"
84
+ link = "<a href=\"/userprofile/jch\" class=\"user-mention\">@jch</a>"
85
+ assert_equal "<p>Hi, #{link}!</p>",
86
+ filter(body, '/userprofile').to_html
87
+ end
88
+
89
+ def test_base_url_slash_with_tilde
90
+ body = "<p>Hi, @jch!</p>"
91
+ link = "<a href=\"/~jch\" class=\"user-mention\">@jch</a>"
92
+ assert_equal "<p>Hi, #{link}!</p>",
93
+ filter(body, '/~').to_html
94
+ end
95
+
75
96
  MarkdownPipeline =
76
97
  HTML::Pipeline.new [
77
98
  HTML::Pipeline::MarkdownFilter,
@@ -158,4 +179,28 @@ class HTML::Pipeline::MentionFilterTest < Minitest::Test
158
179
  @body = "(We're talking 'bout @ymendel.)"
159
180
  assert_equal %w[ymendel], mentioned_usernames
160
181
  end
182
+
183
+ def test_username_pattern_can_be_customized
184
+ body = "<p>@_abc: test.</p>"
185
+ doc = Nokogiri::HTML::DocumentFragment.parse(body)
186
+
187
+ res = filter(doc, '/', nil, /(_[a-z]{3})/)
188
+
189
+ link = "<a href=\"/_abc\" class=\"user-mention\">@_abc</a>"
190
+ assert_equal "<p>#{link}: test.</p>",
191
+ res.to_html
192
+ end
193
+
194
+ def test_filter_does_not_create_a_new_object_for_default_username_pattern
195
+ body = "<div>@test</div>"
196
+ doc = Nokogiri::HTML::DocumentFragment.parse(body)
197
+
198
+ filter(doc.clone, '/', nil)
199
+ pattern_count = HTML::Pipeline::MentionFilter::MentionPatterns.length
200
+ filter(doc.clone, '/', nil)
201
+
202
+ assert_equal pattern_count, HTML::Pipeline::MentionFilter::MentionPatterns.length
203
+ filter(doc.clone, '/', nil, /test/)
204
+ assert_equal pattern_count + 1, HTML::Pipeline::MentionFilter::MentionPatterns.length
205
+ end
161
206
  end
@@ -127,4 +127,28 @@ class HTML::Pipeline::SanitizationFilterTest < Minitest::Test
127
127
  </table>)
128
128
  assert_equal orig, SanitizationFilter.call(orig).to_s
129
129
  end
130
+
131
+ def test_summary_tag_are_not_removed
132
+ orig = %(<summary>Foo</summary>)
133
+ assert_equal orig, SanitizationFilter.call(orig).to_s
134
+ end
135
+
136
+ def test_details_tag_and_open_attribute_are_not_removed
137
+ orig = %(<details open>Foo</details>)
138
+ assert_equal orig, SanitizationFilter.call(orig).to_s
139
+ end
140
+
141
+ def test_nested_details_tag_are_not_removed
142
+ orig = <<-NESTED
143
+ <details>
144
+ <summary>Foo</summary>
145
+ <details>
146
+ Bar
147
+ <summary>Baz</summary>
148
+ </details>
149
+ Qux
150
+ </details>
151
+ NESTED
152
+ assert_equal orig, SanitizationFilter.call(orig).to_s
153
+ end
130
154
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-pipeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.11.0
4
+ version: '2.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Tomayko
@@ -9,36 +9,48 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-09-15 00:00:00.000000000 Z
12
+ date: 2015-07-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ~>
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '1.4'
21
+ - - "<="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.6.5
21
24
  type: :runtime
22
25
  prerelease: false
23
26
  version_requirements: !ruby/object:Gem::Requirement
24
27
  requirements:
25
- - - ~>
28
+ - - ">="
26
29
  - !ruby/object:Gem::Version
27
30
  version: '1.4'
31
+ - - "<="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.6.5
28
34
  - !ruby/object:Gem::Dependency
29
35
  name: activesupport
30
36
  requirement: !ruby/object:Gem::Requirement
31
37
  requirements:
32
- - - '>='
38
+ - - ">="
33
39
  - !ruby/object:Gem::Version
34
40
  version: '2'
41
+ - - "<"
42
+ - !ruby/object:Gem::Version
43
+ version: '5'
35
44
  type: :runtime
36
45
  prerelease: false
37
46
  version_requirements: !ruby/object:Gem::Requirement
38
47
  requirements:
39
- - - '>='
48
+ - - ">="
40
49
  - !ruby/object:Gem::Version
41
50
  version: '2'
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: '5'
42
54
  description: GitHub HTML processing filters and utilities
43
55
  email:
44
56
  - ryan@github.com
@@ -47,8 +59,8 @@ executables: []
47
59
  extensions: []
48
60
  extra_rdoc_files: []
49
61
  files:
50
- - .gitignore
51
- - .travis.yml
62
+ - ".gitignore"
63
+ - ".travis.yml"
52
64
  - CHANGELOG.md
53
65
  - CONTRIBUTING.md
54
66
  - Gemfile
@@ -76,6 +88,7 @@ files:
76
88
  - lib/html/pipeline/textile_filter.rb
77
89
  - lib/html/pipeline/toc_filter.rb
78
90
  - lib/html/pipeline/version.rb
91
+ - script/changelog
79
92
  - script/package
80
93
  - script/release
81
94
  - test/helpers/mocked_instrumentation_service.rb
@@ -109,12 +122,12 @@ require_paths:
109
122
  - lib
110
123
  required_ruby_version: !ruby/object:Gem::Requirement
111
124
  requirements:
112
- - - '>='
125
+ - - ">="
113
126
  - !ruby/object:Gem::Version
114
127
  version: '0'
115
128
  required_rubygems_version: !ruby/object:Gem::Requirement
116
129
  requirements:
117
- - - '>='
130
+ - - ">="
118
131
  - !ruby/object:Gem::Version
119
132
  version: '0'
120
133
  requirements: []