jekyll-mentioji 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +56 -0
  4. data/lib/jekyll-mentioji.rb +181 -0
  5. metadata +146 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2f7969c91c7033c67e9327d2cb3dac8687bc30bd
4
+ data.tar.gz: a61f334384fc26db61b2adf0a9996768f55a02c9
5
+ SHA512:
6
+ metadata.gz: 6ecf13698e63ef1cd5ce1565108e0d678b5f3610086456202fcb9091594706ae79467e0cd750200ade2d7a6344f029be16ddf0ecbb517a773b9fb6409fad39f6
7
+ data.tar.gz: 8b04cc659afae2e1f9666c9b5ca9be95444351da0e5b38ca3260b757be43310219f0717f630524222daf65518c1072600b75bef623d841533dcb769d25f2f4be
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT LICENSE
2
+
3
+ Copyright (c) 2018 Ashwin Maroli
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.
@@ -0,0 +1,56 @@
1
+ # Jekyll Mentioji
2
+
3
+ If your site uses both [`jekyll-mentions`](https://github.com/jekyll/jekyll-mentions) and [`jemoji`](https://github.com/jekyll/jemoji), then
4
+ using `jekyll-mentioji` *instead*, is going to improve your build times.
5
+
6
+ Internally, this plugin combines the code & logic behind the above two plugins and adapts the associated code in
7
+ [`html-pipeline`](https://github.com/jch/html-pipeline), which the above two plugins wrap around, to emerge as *the faster implementation*
8
+ in comparison to using the two plugins together in a site.
9
+
10
+ ## Usage
11
+
12
+ Replace the two plugins in your `Gemfile` and/or `_config.yml` with this plugin:
13
+
14
+ ```diff
15
+ # Gemfile
16
+
17
+ group :jekyll_plugins do
18
+ - gem "jekyll-mentions"
19
+ - gem "jemoji"
20
+ + gem "jekyll-mentioji"
21
+ end
22
+ ```
23
+ ```sh
24
+ bundle install
25
+ ```
26
+ ```diff
27
+ # _config.yml
28
+
29
+ plugins:
30
+ - - jekyll-mentions
31
+ - - jemoji
32
+ + - jekyll-mentioji
33
+ ```
34
+
35
+ ## Other Notes:
36
+
37
+ - This plugin aims to be a zero-config replacement for the two plugins and therefore should be compatible with existing configuration
38
+ for the two plugins. `jekyll-mentioji` will read both existing `jekyll-mentions:` and `emoji:` settings in your config file.
39
+ - A few diversions from the two official plugins:
40
+ - `@mention` can currently include the underscore (`_`) along with alphanumeric characters and hyphen (`-`)
41
+ - `@mention` will not be rendered within `<script></script>`
42
+ - configuration for emoji assets-path mirror that of `jekyll-mentions`: the value can be both a string or a dictionary
43
+
44
+ ### Build times comparison
45
+
46
+ rvm | jmentions+jemoji | *jmentioji*
47
+ :---: | :----: | :------:
48
+ 2.2.9 | 15.482 | *13.671*
49
+ 2.3.6 | 13.798 | *11.988*
50
+ 2.4.3 | 14.225 | *12.848*
51
+ 2.5.0 | 14.560 | *12.771*
52
+
53
+ (built using `jekyll:master@c7f006`)
54
+
55
+ *Disclaimer: The no.s above are averages of 3 restarted jobs on two separate Travis CI build-commits and therefore cannot be considered as
56
+ solid evidence. However, tests run locally do show an improvement of approx. 2s with `jekyll-mentioji` over the combo.*
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gemoji"
4
+ require "nokogiri"
5
+
6
+ module Jekyll
7
+ class Mentioji
8
+ MENTIONPATTERNS = %r~(?:^|\B)@((?>[\w][\w-]*))(?!/)(?=\.+[ \t\W]|\.+$|[^\w.]|$)~i
9
+
10
+ OPENING_BODY_TAG_REGEX = %r!<body(.*?)>\s*!
11
+
12
+ IGNORE_MENTION_PARENTS = %w(pre code a script style).freeze
13
+ IGNORE_EMOJI_PARENTS = %w(pre code tt).freeze
14
+
15
+ class << self
16
+ def transform(doc)
17
+ content = doc.output
18
+ return unless content.include?("@") || content.include?(":")
19
+ setup_transformer(doc.site.config)
20
+ doc.output = if content.include?("<body")
21
+ process_html_body(content)
22
+ else
23
+ process(content)
24
+ end
25
+ end
26
+
27
+ def transformable?(doc)
28
+ (doc.is_a?(Jekyll::Page) || doc.write?) &&
29
+ doc.output_ext == ".html" || (doc.permalink&.end_with?("/"))
30
+ end
31
+
32
+ private
33
+
34
+ def process_html_body(content)
35
+ head, opener, tail = content.partition(OPENING_BODY_TAG_REGEX)
36
+ body_content, *rest = tail.partition("</body>")
37
+
38
+ String.new(head) << opener << process(body_content) << rest.join
39
+ end
40
+
41
+ def process(body_content)
42
+ return body_content unless body_content =~ prelim_check_regex
43
+ parsed_body = Nokogiri::HTML::DocumentFragment.parse(body_content)
44
+ parsed_body.search(".//text()").each do |node|
45
+ content = node.text
46
+ next if !content.include?("@") && !content.include?(":")
47
+ node.replace(
48
+ mention_renderer(
49
+ node, emoji_renderer(node, content)
50
+ )
51
+ )
52
+ end
53
+ parsed_body.to_html
54
+ end
55
+
56
+ # rubocop:disable Naming/MemoizedInstanceVariableName
57
+ def setup_transformer(config)
58
+ @transconfig ||= {
59
+ "mention_base" => compute_base(
60
+ config, "jekyll-mentions", "base_url", default_mention_base
61
+ ),
62
+ "emoji_source" => compute_base(
63
+ config, "emoji", "src", default_asset_root
64
+ ),
65
+ }
66
+ end
67
+ # rubocop:enable Naming/MemoizedInstanceVariableName
68
+
69
+ def compute_base(config, key, subkey, default_value)
70
+ subject = config[key]
71
+ case subject
72
+ when nil, NilClass
73
+ default_value
74
+ when String
75
+ subject
76
+ when Hash
77
+ subject.fetch(subkey, default_value)
78
+ else
79
+ raise TypeError, "Your #{key} config has to either be a string or a hash. It's a " \
80
+ "kind of #{subject.class} right now."
81
+ end
82
+ end
83
+
84
+ def default_mention_base
85
+ if !ENV["SSL"].to_s.empty? && !ENV["GITHUB_HOSTNAME"].to_s.empty?
86
+ scheme = ENV["SSL"] == "true" ? "https://" : "http://"
87
+ "#{scheme}#{ENV["GITHUB_HOSTNAME"].chomp("/")}"
88
+ else
89
+ "https://github.com"
90
+ end
91
+ end
92
+
93
+ def default_asset_root
94
+ if ENV["ASSET_HOST_URL"].to_s.empty?
95
+ File.join("https://assets-cdn.github.com", "/images/icons")
96
+ else
97
+ File.join(ENV["ASSET_HOST_URL"], "/images/icons")
98
+ end
99
+ end
100
+
101
+ def mention_markup(username)
102
+ mention_stash[username] ||= begin
103
+ "<a href='#{@transconfig["mention_base"]}/#{username}' " \
104
+ "class='user-mention'>@#{username}</a>"
105
+ end
106
+ end
107
+
108
+ def mention_renderer(node, text)
109
+ return text unless text.include?("@")
110
+ return text if has_ancestor?(node, IGNORE_MENTION_PARENTS)
111
+ text.gsub(MENTIONPATTERNS) { mention_markup(Regexp.last_match(1)) }
112
+ end
113
+
114
+ def emoji_renderer(node, text)
115
+ return text unless text.include?(":")
116
+ return text if has_ancestor?(node, IGNORE_EMOJI_PARENTS)
117
+ text.gsub(emoji_pattern) { emoji_markup(Regexp.last_match(1)) }
118
+ end
119
+
120
+ def emoji_url(name)
121
+ File.join(
122
+ @transconfig["emoji_source"], "emoji",
123
+ ::Emoji.find_by_alias(name).image_filename
124
+ )
125
+ end
126
+
127
+ def emoji_markup(name)
128
+ emoji_stash[name] ||= begin
129
+ attrs = []
130
+ img_attrs(name).each do |key, value|
131
+ attrs << "#{key}='#{value}'"
132
+ end
133
+ "<img #{attrs.join(" ")}>"
134
+ end
135
+ end
136
+
137
+ def img_attrs(name)
138
+ {
139
+ "class" => "emoji",
140
+ "title" => ":#{name}:",
141
+ "alt" => ":#{name}:",
142
+ "src" => emoji_url(name).to_s,
143
+ "height" => "20",
144
+ "width" => "20",
145
+ }
146
+ end
147
+
148
+ def mention_stash
149
+ @mention_stash ||= {}
150
+ end
151
+
152
+ def emoji_stash
153
+ @emoji_stash ||= {}
154
+ end
155
+
156
+ def emoji_names
157
+ ::Emoji.all.flat_map(&:aliases).sort!.map! { |name| Regexp.escape(name) }
158
+ end
159
+
160
+ def emoji_pattern
161
+ @emoji_pattern ||= %r!:(#{emoji_names.join('|')}):!
162
+ end
163
+
164
+ def prelim_check_regex
165
+ @prelim_check_regex ||= %r!#{MENTIONPATTERNS}|#{emoji_pattern}!
166
+ end
167
+
168
+ # rubocop:disable Naming/PredicateName
169
+ def has_ancestor?(node, tags)
170
+ while (node = node.respond_to?(:parent) && node.parent)
171
+ break true if tags.include?(node.name.downcase)
172
+ end
173
+ end
174
+ # rubocop:enable Naming/PredicateName
175
+ end
176
+ end
177
+ end
178
+
179
+ Jekyll::Hooks.register([:pages, :documents], :post_render) do |doc|
180
+ Jekyll::Mentioji.transform(doc) if Jekyll::Mentioji.transformable?(doc)
181
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-mentioji
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ashwin Maroli
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gemoji
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jekyll
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: cucumber
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: jekyll-mentions
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: jemoji
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-jekyll
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.1'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.1'
111
+ description: Improve build times for sites using both 'jekyll-mentions and 'jemoji'
112
+ plugins
113
+ email:
114
+ - ashmaroli@gmail.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - LICENSE
120
+ - README.md
121
+ - lib/jekyll-mentioji.rb
122
+ homepage: https://github.com/ashmaroli/jekyll-mentioji
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 2.3.0
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.6.14
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Faster version of the 'Jekyll::Mentions + Jekyll::Emoji' combo
146
+ test_files: []