jekyll_href 1.1.0 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/href_tag.rb ADDED
@@ -0,0 +1,214 @@
1
+ require 'jekyll_all_collections'
2
+ require 'jekyll_plugin_logger'
3
+ require 'jekyll_plugin_support'
4
+ require 'liquid'
5
+ require_relative 'jekyll_href/version'
6
+ require_relative 'hash_array'
7
+
8
+ # @author Copyright 2020 Michael Slinn
9
+ # @license SPDX-License-Identifier: Apache-2.0
10
+ # Generates an href.
11
+
12
+ module HrefTag
13
+ MiniHref = Struct.new(:follow, :html, :link, :line_number, :link_save, :path, :summary_exclude, :summary_href, keyword_init: true)
14
+
15
+ # Implements href Jekyll tag
16
+ class HrefTag < JekyllSupport::JekyllTag # rubocop:disable Metrics/ClassLength
17
+ attr_reader :follow, :helper, :line_number, :link_save, :match, :page, :path, :site,
18
+ :summary, :summary_exclude, :summary_href, :target, :text, :url
19
+ attr_accessor :link
20
+
21
+ include JekyllHrefVersion
22
+ include HashArray
23
+ include Comparable
24
+
25
+ def <=>(other)
26
+ return nil unless other.is_a?(self.class)
27
+
28
+ [follow, match, path, target, text] <=> [other.follow, other.match, other.path, other.target, other.text]
29
+ end
30
+
31
+ def to_s
32
+ "On line #{line_number} of #{path}: #{follow} #{match} #{target} #{link} => '#{text}'"
33
+ end
34
+
35
+ # Method prescribed by the Jekyll plugin lifecycle.
36
+ # @param liquid_context [Liquid::Context]
37
+ # @return [String]
38
+ def render_impl
39
+ globals_initial
40
+ linkk = compute_linkk
41
+ linkk = replace_vars(linkk)
42
+ linkk.delete_prefix('./') # normalize relative links
43
+ @url = linkk if @url
44
+ @link_save = linkk
45
+ @helper_save = @helper.clone
46
+ globals_update(@helper.argv, linkk) # Sets @link and @text, might clear @follow and @target
47
+ handle_match if @match
48
+ save_summary
49
+ "<a href='#{@link}'#{@target}#{@follow}>#{@text}</a>"
50
+ end
51
+
52
+ private
53
+
54
+ def save_summary
55
+ return if @summary_exclude || @link_save.start_with?('mailto:') || @link_save.start_with?('#')
56
+
57
+ @summary = @summary.to_s.empty? ? @text : @summary.to_s
58
+ @summary = @summary[0].upcase + @summary[1..]
59
+ @summary_href = "<a href='#{@link_save}'#{@target}#{@follow}>#{@summary}</a>"
60
+ mini_href = MiniHref.new(
61
+ follow: @follow,
62
+ html: @summary_href,
63
+ line_number: @line_number,
64
+ link: @link_save,
65
+ link_save: @link_save,
66
+ path: @path,
67
+ summary_exclude: @summary_exclude,
68
+ summary_href: @summary_href
69
+ )
70
+ if @link_save.start_with? 'http'
71
+ add_global_link_for_page mini_href
72
+ else
73
+ add_local_link_for_page mini_href
74
+ end
75
+ end
76
+
77
+ # Does not look at or compute @link
78
+ def compute_linkk
79
+ return @link if @link
80
+
81
+ linkk = @url
82
+ if linkk.nil? || !linkk
83
+ linkk = @helper.argv&.shift
84
+ @helper.params&.shift
85
+ @helper.keys_values&.delete(linkk)
86
+ dump_linkk_relations(linkk) if linkk.nil?
87
+ elsif @url.to_s.empty?
88
+ dump_linkk_relations(linkk)
89
+ end
90
+ linkk
91
+ end
92
+
93
+ def dump_linkk_relations(linkk)
94
+ msg = <<~END_MESSAGE
95
+ jekyll_href error: no url was provided on #{@path}:#{@line_number}.
96
+ @helper.markup=#{@helper.markup}
97
+ @helper.argv='#{@helper.argv}'
98
+ linkk='#{linkk}'
99
+ @match='#{@match}'
100
+ @url='#{@url}'
101
+ @follow='#{@follow}
102
+ @target='#{@target}'
103
+ END_MESSAGE
104
+ abort msg.red
105
+ end
106
+
107
+ # Sets @follow, @helper, @match, @path, @shy, @target, @url, @wbr
108
+ def globals_initial
109
+ @path = @page['path']
110
+ AllCollectionsHooks.compute(@site)
111
+
112
+ @follow = @helper.parameter_specified?('follow') ? '' : " rel='nofollow'"
113
+ @match = @helper.parameter_specified? 'match'
114
+ @blank = @helper.parameter_specified? 'blank'
115
+ @summary_exclude = @helper.parameter_specified? 'summary_exclude'
116
+ @shy = @helper.parameter_specified? 'shy'
117
+ @summary = @helper.parameter_specified? 'summary'
118
+ @target = @blank ? " target='_blank'" : nil
119
+ @target ||= @helper.parameter_specified?('notarget') ? '' : " target='_blank'"
120
+ @url = @helper.parameter_specified? 'url'
121
+ @wbr = @helper.parameter_specified? 'wbr'
122
+ end
123
+
124
+ # Might set @follow, @linkk, @target, and @text
125
+ def globals_update(tokens, linkk)
126
+ if linkk.start_with? 'mailto:'
127
+ @link = linkk
128
+ @target = @follow = ''
129
+ @text = @helper.argv.join(' ')
130
+ if @text.empty?
131
+ text = linkk.delete_prefix('mailto:')
132
+ @text = "<code>#{text}</code>"
133
+ end
134
+ return
135
+ else
136
+ @text = tokens.join(' ').strip
137
+ if @text.to_s.empty?
138
+ text = linkk
139
+ text = linkk.gsub('/', '/&shy;') if @shy
140
+ text = linkk.gsub('/', '/<wbr>') if @wbr
141
+ @text = "<code>#{text}</code>"
142
+ @link = linkk.start_with?('http') ? linkk : "https://#{linkk}"
143
+ else
144
+ @link = if @shy
145
+ linkk.gsub('/', '/&shy;')
146
+ elsif @wbr
147
+ linkk.gsub('/', '/<wbr>')
148
+ else
149
+ linkk
150
+ end
151
+ end
152
+ @link_save = @link
153
+ end
154
+
155
+ return if @link.start_with? 'http'
156
+
157
+ @follow = ''
158
+ @target = '' unless @blank
159
+ end
160
+
161
+ def handle_match
162
+ match_post
163
+ @follow = ''
164
+ @target = '' unless @blank
165
+ end
166
+
167
+ # Might set @link and @text
168
+ def match_post
169
+ config = @site.config['href']
170
+ @die_if_nomatch = !config.nil? && config['nomatch'] && config['nomatch'] == 'fatal'
171
+ @path, @fragment = @link.split('#')
172
+
173
+ @logger.debug do
174
+ <<~END_DEBUG
175
+ @link=#{@link}
176
+ @site.posts.docs[0].url = #{@site.posts.docs[0].url}
177
+ @site.posts.docs[0].path = #{@site.posts.docs[0].path}
178
+ END_DEBUG
179
+ end
180
+
181
+ all_urls = @site.all_collections.map(&:url)
182
+ compute_link_and_text(all_urls)
183
+ end
184
+
185
+ def compute_link_and_text(all_urls)
186
+ url_matches = all_urls.select { |url| url&.include? @path }
187
+ case url_matches.length
188
+ when 0
189
+ abort "href error: No url matches '#{@link}'" if @die_if_nomatch
190
+ @link_save = @link = '#'
191
+ @text = "<i>#{@link} is not available</i>"
192
+ when 1
193
+ @link = url_matches.first
194
+ @link = "#{@link}##{@fragment}" if @fragment
195
+ @link_save = @link
196
+ else
197
+ abort "Error: More than one url matched '#{@path}': #{url_matches.join(', ')}"
198
+ end
199
+ end
200
+
201
+ # Replace names in plugin-vars with values
202
+ def replace_vars(text)
203
+ variables = @site.config['plugin-vars']
204
+ return text unless variables
205
+
206
+ variables.each do |name, value|
207
+ text = text.gsub "{{#{name}}}", value
208
+ end
209
+ text
210
+ end
211
+
212
+ JekyllPluginHelper.register(self, 'href')
213
+ end
214
+ end
@@ -1,3 +1,3 @@
1
1
  module JekyllHrefVersion
2
- VERSION = '1.1.0'.freeze
2
+ VERSION = '1.2.2'.freeze
3
3
  end
data/lib/jekyll_href.rb CHANGED
@@ -1,177 +1,9 @@
1
- require 'jekyll_all_collections'
2
- require 'jekyll_plugin_logger'
3
- require 'liquid'
4
- require_relative 'jekyll_href/version'
5
- require_relative './jekyll_tag_helper2'
1
+ require_relative 'href_tag'
2
+ require_relative 'href_summary_tag'
6
3
 
7
- # @author Copyright 2020 Michael Slinn
8
- # @license SPDX-License-Identifier: Apache-2.0
9
- # Generates an href.
4
+ HrefError = Class.new(Liquid::Error)
10
5
 
11
- # Implements href Jekyll tag
12
- class ExternalHref < Liquid::Tag # rubocop:disable Metrics/ClassLength
13
- attr_reader :follow, :helper, :line_number, :match, :page, :path, :site, :text, :target, :url
14
- attr_accessor :link
15
-
16
- # @param tag_name [String] is the name of the tag, which we already know.
17
- # @param markup [String] the arguments from the web page.
18
- # @param _tokens [Liquid::ParseContext] tokenized command line
19
- # By default it has two keys: :locale and :line_numbers, the first is a Liquid::I18n object, and the second,
20
- # a boolean parameter that determines if error messages should display the line number the error occurred.
21
- # This argument is used mostly to display localized error messages on Liquid built-in Tags and Filters.
22
- # See https://github.com/Shopify/liquid/wiki/Liquid-for-Programmers#create-your-own-tags
23
- # @return [void]
24
- def initialize(tag_name, markup, _tokens)
25
- super
26
- markup = '' if markup.nil?
27
- markup.strip!
28
-
29
- @logger = PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
30
- @helper = JekyllTagHelper2.new(tag_name, markup, @logger)
31
- end
32
-
33
- # Method prescribed by the Jekyll plugin lifecycle.
34
- # @param liquid_context [Liquid::Context]
35
- # @return [String]
36
- def render(liquid_context)
37
- super
38
- globals_initial(liquid_context)
39
- linkk = compute_linkk
40
- linkk = replace_vars(linkk)
41
- @link_save = linkk
42
- @helper_save = @helper.clone
43
- globals_update(@helper.argv, linkk) # Sets @link and @text, might clear @follow and @target
44
- handle_match if @match
45
- "<a href='#{@link}'#{@target}#{@follow}>#{@text}</a>"
46
- end
47
-
48
- private
49
-
50
- # Does not look at or compute @link
51
- def compute_linkk
52
- return @link if @link
53
-
54
- linkk = @url
55
- if linkk.nil? || !linkk
56
- linkk = @helper.argv&.shift
57
- @helper.params&.shift
58
- @helper.keys_values&.delete(linkk)
59
- dump_linkk_relations(linkk) if linkk.nil?
60
- elsif @url.to_s.empty?
61
- dump_linkk_relations(linkk)
62
- end
63
- linkk
64
- end
65
-
66
- def dump_linkk_relations(linkk)
67
- msg = <<~END_MESSAGE
68
- jekyll_href error: no url was provided on #{@path}:#{@line_number}.
69
- @helper.markup=#{@helper.markup}
70
- @helper.argv='#{@helper.argv}'
71
- linkk='#{linkk}'
72
- @match='#{@match}'
73
- @url='#{@url}'
74
- @follow='#{@follow}
75
- @target='#{@target}'
76
- END_MESSAGE
77
- abort msg.red
78
- end
79
-
80
- def globals_initial(liquid_context)
81
- # Sets @follow, @helper, @match, @page, @path, @site, @target, @url
82
- @helper.liquid_context = liquid_context
83
-
84
- @page = liquid_context.registers[:page]
85
- @path = @page['path']
86
- @site = liquid_context.registers[:site]
87
- AllCollectionsHooks.compute(@site)
88
-
89
- @follow = @helper.parameter_specified?('follow') ? '' : " rel='nofollow'"
90
- @match = @helper.parameter_specified?('match')
91
- @blank = @helper.parameter_specified?('blank')
92
- @target = @blank ? " target='_blank'" : nil
93
- @target ||= @helper.parameter_specified?('notarget') ? '' : " target='_blank'"
94
- @url = @helper.parameter_specified?('url')
95
- end
96
-
97
- # Might set @follow, @linkk, @target, and @text
98
- def globals_update(tokens, linkk)
99
- if linkk.start_with? 'mailto:'
100
- @link = linkk
101
- @target = @follow = ''
102
- @text = @helper.argv.join(' ')
103
- if @text.empty?
104
- text = linkk.delete_prefix('mailto:')
105
- @text = "<code>#{text}</code>"
106
- end
107
- return
108
- else
109
- @text = tokens.join(' ').strip
110
- if @text.to_s.empty?
111
- @text = "<code>#{linkk}</code>"
112
- @link = "https://#{linkk}"
113
- else
114
- @link = linkk
115
- end
116
- end
117
-
118
- return if @link.start_with? 'http'
119
-
120
- @follow = ''
121
- @target = '' unless @blank
122
- end
123
-
124
- def handle_match
125
- match_post
126
- @follow = ''
127
- @target = '' unless @blank
128
- end
129
-
130
- # Might set @link and @text
131
- def match_post
132
- config = @site.config['href']
133
- @die_if_nomatch = !config.nil? && config['nomatch'] && config['nomatch'] == 'fatal'
134
- @path, @fragment = @link.split('#')
135
-
136
- @logger.debug do
137
- <<~END_DEBUG
138
- @link=#{@link}
139
- @site.posts.docs[0].url = #{@site.posts.docs[0].url}
140
- @site.posts.docs[0].path = #{@site.posts.docs[0].path}
141
- END_DEBUG
142
- end
143
-
144
- all_urls = @site.all_collections.map(&:url)
145
- compute_link_and_text(all_urls)
146
- end
147
-
148
- def compute_link_and_text(all_urls)
149
- url_matches = all_urls.select { |url| url&.include? @path }
150
- case url_matches.length
151
- when 0
152
- abort "href error: No url matches '#{@link}'" if @die_if_nomatch
153
- @link = '#'
154
- @text = "<i>#{@link} is not available</i>"
155
- when 1
156
- @link = url_matches.first
157
- @link = "#{@link}\##{@fragment}" if @fragment
158
- else
159
- abort "Error: More than one url matched '#{@path}': #{url_matches.join(', ')}"
160
- end
161
- end
162
-
163
- # Replace names in plugin-vars with values
164
- def replace_vars(text)
165
- variables = @site.config['plugin-vars']
166
- return text unless variables
167
-
168
- variables.each do |name, value|
169
- text = text.gsub "{{#{name}}}", value
170
- end
171
- @logger.debug { "@link=#{@link}" }
172
- text
173
- end
6
+ module JekyllHrefModule
7
+ include HrefTag
8
+ include HrefSummaryTag
174
9
  end
175
-
176
- PluginMetaLogger.instance.info { "Loaded jekyll_href v#{JekyllHrefVersion::VERSION} plugin." }
177
- Liquid::Template.register_tag('href', ExternalHref)
@@ -0,0 +1,43 @@
1
+ module HashArraySpec
2
+ require_relative '../lib/hash_array'
3
+
4
+ RSpec.describe HashArray do
5
+ let(:logger) do
6
+ PluginMetaLogger.instance.new_logger(self, PluginMetaLogger.instance.config)
7
+ end
8
+
9
+ let(:parse_context) { TestParseContext.new }
10
+
11
+ [1, 2, 3, 4, 11, 22, 33, 44].each do |x|
12
+ let("href#{x}".to_sym) do
13
+ domain, where = if x.even?
14
+ ['https://domain.com/', 'External']
15
+ else
16
+ ['', 'Internal']
17
+ end
18
+ href = HrefTag::HrefTag.send(
19
+ :new,
20
+ 'href',
21
+ + "#{domain}path/page#{x}.html #{where} link text #{x}",
22
+ parse_context
23
+ )
24
+ href.render(TestLiquidContext.new)
25
+ href
26
+ end
27
+ end
28
+
29
+ it 'accumulates arrays of href_tag' do
30
+ described_class.reset
31
+ [href1, href3, href11, href33].each { |x| described_class.add_local_link_for_page x }
32
+ [href2, href4, href22, href44].each { |x| described_class.add_global_link_for_page x }
33
+
34
+ local_hrefs = described_class.instance_variable_get :@local_hrefs
35
+ value = { 'index.html' => [href1, href3, href11, href33] }
36
+ expect(local_hrefs).to match_array(value)
37
+
38
+ global_hrefs = described_class.instance_variable_get :@global_hrefs
39
+ value = { 'index.html' => [href2, href4, href22, href44] }
40
+ expect(global_hrefs).to match_array(value)
41
+ end
42
+ end
43
+ end