jekyll 4.2.1 → 4.2.2

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.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +350 -350
  3. data/LICENSE +21 -21
  4. data/README.markdown +86 -86
  5. data/exe/jekyll +57 -57
  6. data/lib/blank_template/_config.yml +3 -3
  7. data/lib/blank_template/_layouts/default.html +12 -12
  8. data/lib/blank_template/_sass/main.scss +9 -9
  9. data/lib/blank_template/assets/css/main.scss +4 -4
  10. data/lib/blank_template/index.md +8 -8
  11. data/lib/jekyll/cache.rb +190 -190
  12. data/lib/jekyll/cleaner.rb +111 -111
  13. data/lib/jekyll/collection.rb +309 -309
  14. data/lib/jekyll/command.rb +105 -105
  15. data/lib/jekyll/commands/build.rb +93 -93
  16. data/lib/jekyll/commands/clean.rb +45 -45
  17. data/lib/jekyll/commands/doctor.rb +177 -177
  18. data/lib/jekyll/commands/help.rb +34 -34
  19. data/lib/jekyll/commands/new.rb +172 -169
  20. data/lib/jekyll/commands/new_theme.rb +40 -40
  21. data/lib/jekyll/commands/serve/live_reload_reactor.rb +122 -122
  22. data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -1183
  23. data/lib/jekyll/commands/serve/servlet.rb +202 -202
  24. data/lib/jekyll/commands/serve/websockets.rb +81 -81
  25. data/lib/jekyll/commands/serve.rb +362 -362
  26. data/lib/jekyll/configuration.rb +313 -313
  27. data/lib/jekyll/converter.rb +54 -54
  28. data/lib/jekyll/converters/identity.rb +41 -41
  29. data/lib/jekyll/converters/markdown/kramdown_parser.rb +199 -199
  30. data/lib/jekyll/converters/markdown.rb +113 -113
  31. data/lib/jekyll/converters/smartypants.rb +70 -70
  32. data/lib/jekyll/convertible.rb +257 -257
  33. data/lib/jekyll/deprecator.rb +50 -50
  34. data/lib/jekyll/document.rb +544 -544
  35. data/lib/jekyll/drops/collection_drop.rb +20 -20
  36. data/lib/jekyll/drops/document_drop.rb +70 -70
  37. data/lib/jekyll/drops/drop.rb +293 -293
  38. data/lib/jekyll/drops/excerpt_drop.rb +19 -19
  39. data/lib/jekyll/drops/jekyll_drop.rb +32 -32
  40. data/lib/jekyll/drops/site_drop.rb +66 -66
  41. data/lib/jekyll/drops/static_file_drop.rb +14 -14
  42. data/lib/jekyll/drops/unified_payload_drop.rb +26 -26
  43. data/lib/jekyll/drops/url_drop.rb +140 -140
  44. data/lib/jekyll/entry_filter.rb +121 -121
  45. data/lib/jekyll/errors.rb +20 -20
  46. data/lib/jekyll/excerpt.rb +201 -201
  47. data/lib/jekyll/external.rb +79 -79
  48. data/lib/jekyll/filters/date_filters.rb +110 -110
  49. data/lib/jekyll/filters/grouping_filters.rb +64 -64
  50. data/lib/jekyll/filters/url_filters.rb +98 -98
  51. data/lib/jekyll/filters.rb +535 -535
  52. data/lib/jekyll/frontmatter_defaults.rb +240 -240
  53. data/lib/jekyll/generator.rb +5 -5
  54. data/lib/jekyll/hooks.rb +107 -107
  55. data/lib/jekyll/inclusion.rb +32 -32
  56. data/lib/jekyll/layout.rb +67 -67
  57. data/lib/jekyll/liquid_extensions.rb +22 -22
  58. data/lib/jekyll/liquid_renderer/file.rb +77 -77
  59. data/lib/jekyll/liquid_renderer/table.rb +55 -55
  60. data/lib/jekyll/liquid_renderer.rb +80 -80
  61. data/lib/jekyll/log_adapter.rb +151 -151
  62. data/lib/jekyll/mime.types +866 -866
  63. data/lib/jekyll/page.rb +217 -217
  64. data/lib/jekyll/page_excerpt.rb +25 -25
  65. data/lib/jekyll/page_without_a_file.rb +14 -14
  66. data/lib/jekyll/path_manager.rb +74 -74
  67. data/lib/jekyll/plugin.rb +92 -92
  68. data/lib/jekyll/plugin_manager.rb +115 -115
  69. data/lib/jekyll/profiler.rb +58 -58
  70. data/lib/jekyll/publisher.rb +23 -23
  71. data/lib/jekyll/reader.rb +192 -192
  72. data/lib/jekyll/readers/collection_reader.rb +23 -23
  73. data/lib/jekyll/readers/data_reader.rb +79 -79
  74. data/lib/jekyll/readers/layout_reader.rb +62 -62
  75. data/lib/jekyll/readers/page_reader.rb +25 -25
  76. data/lib/jekyll/readers/post_reader.rb +85 -85
  77. data/lib/jekyll/readers/static_file_reader.rb +25 -25
  78. data/lib/jekyll/readers/theme_assets_reader.rb +52 -52
  79. data/lib/jekyll/regenerator.rb +195 -195
  80. data/lib/jekyll/related_posts.rb +52 -52
  81. data/lib/jekyll/renderer.rb +265 -265
  82. data/lib/jekyll/site.rb +551 -551
  83. data/lib/jekyll/static_file.rb +208 -208
  84. data/lib/jekyll/stevenson.rb +60 -60
  85. data/lib/jekyll/tags/highlight.rb +110 -110
  86. data/lib/jekyll/tags/include.rb +275 -275
  87. data/lib/jekyll/tags/link.rb +42 -42
  88. data/lib/jekyll/tags/post_url.rb +106 -106
  89. data/lib/jekyll/theme.rb +86 -86
  90. data/lib/jekyll/theme_builder.rb +121 -121
  91. data/lib/jekyll/url.rb +167 -167
  92. data/lib/jekyll/utils/ansi.rb +57 -57
  93. data/lib/jekyll/utils/exec.rb +26 -26
  94. data/lib/jekyll/utils/internet.rb +37 -37
  95. data/lib/jekyll/utils/platforms.rb +67 -67
  96. data/lib/jekyll/utils/thread_event.rb +31 -31
  97. data/lib/jekyll/utils/win_tz.rb +75 -75
  98. data/lib/jekyll/utils.rb +367 -367
  99. data/lib/jekyll/version.rb +5 -5
  100. data/lib/jekyll.rb +195 -195
  101. data/lib/site_template/.gitignore +5 -5
  102. data/lib/site_template/404.html +25 -25
  103. data/lib/site_template/_config.yml +55 -55
  104. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -29
  105. data/lib/site_template/about.markdown +18 -18
  106. data/lib/site_template/index.markdown +6 -6
  107. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -74
  108. data/lib/theme_template/Gemfile +4 -4
  109. data/lib/theme_template/LICENSE.txt.erb +21 -21
  110. data/lib/theme_template/README.md.erb +52 -52
  111. data/lib/theme_template/_layouts/default.html +1 -1
  112. data/lib/theme_template/_layouts/page.html +5 -5
  113. data/lib/theme_template/_layouts/post.html +5 -5
  114. data/lib/theme_template/example/_config.yml.erb +1 -1
  115. data/lib/theme_template/example/_post.md +12 -12
  116. data/lib/theme_template/example/index.html +14 -14
  117. data/lib/theme_template/example/style.scss +7 -7
  118. data/lib/theme_template/gitignore.erb +6 -6
  119. data/lib/theme_template/theme.gemspec.erb +16 -16
  120. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -149
  121. data/rubocop/jekyll/no_p_allowed.rb +23 -23
  122. data/rubocop/jekyll/no_puts_allowed.rb +23 -23
  123. data/rubocop/jekyll.rb +5 -5
  124. metadata +3 -3
@@ -1,201 +1,201 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- class Excerpt
5
- extend Forwardable
6
-
7
- attr_accessor :doc
8
- attr_accessor :content, :ext
9
- attr_writer :output
10
-
11
- def_delegators :@doc,
12
- :site, :name, :ext, :extname,
13
- :collection, :related_posts, :type,
14
- :coffeescript_file?, :yaml_file?,
15
- :url, :next_doc, :previous_doc
16
-
17
- private :coffeescript_file?, :yaml_file?
18
-
19
- # Initialize this Excerpt instance.
20
- #
21
- # doc - The Document.
22
- #
23
- # Returns the new Excerpt.
24
- def initialize(doc)
25
- self.doc = doc
26
- self.content = extract_excerpt(doc.content)
27
- end
28
-
29
- # Fetch YAML front-matter data from related doc, without layout key
30
- #
31
- # Returns Hash of doc data
32
- def data
33
- @data ||= doc.data.dup
34
- @data.delete("layout")
35
- @data.delete("excerpt")
36
- @data
37
- end
38
-
39
- def trigger_hooks(*); end
40
-
41
- # 'Path' of the excerpt.
42
- #
43
- # Returns the path for the doc this excerpt belongs to with #excerpt appended
44
- def path
45
- File.join(doc.path, "#excerpt")
46
- end
47
-
48
- # 'Relative Path' of the excerpt.
49
- #
50
- # Returns the relative_path for the doc this excerpt belongs to with #excerpt appended
51
- def relative_path
52
- @relative_path ||= File.join(doc.relative_path, "#excerpt")
53
- end
54
-
55
- # Check if excerpt includes a string
56
- #
57
- # Returns true if the string passed in
58
- def include?(something)
59
- output&.include?(something) || content.include?(something)
60
- end
61
-
62
- # The UID for this doc (useful in feeds).
63
- # e.g. /2008/11/05/my-awesome-doc
64
- #
65
- # Returns the String UID.
66
- def id
67
- "#{doc.id}#excerpt"
68
- end
69
-
70
- def to_s
71
- output || content
72
- end
73
-
74
- def to_liquid
75
- Jekyll::Drops::ExcerptDrop.new(self)
76
- end
77
-
78
- # Returns the shorthand String identifier of this doc.
79
- def inspect
80
- "<#{self.class} id=#{id}>"
81
- end
82
-
83
- def output
84
- @output ||= Renderer.new(doc.site, self, site.site_payload).run
85
- end
86
-
87
- def place_in_layout?
88
- false
89
- end
90
-
91
- def render_with_liquid?
92
- return false if data["render_with_liquid"] == false
93
-
94
- !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content))
95
- end
96
-
97
- protected
98
-
99
- # Internal: Extract excerpt from the content
100
- #
101
- # By default excerpt is your first paragraph of a doc: everything before
102
- # the first two new lines:
103
- #
104
- # ---
105
- # title: Example
106
- # ---
107
- #
108
- # First paragraph with [link][1].
109
- #
110
- # Second paragraph.
111
- #
112
- # [1]: http://example.com/
113
- #
114
- # This is fairly good option for Markdown and Textile files. But might cause
115
- # problems for HTML docs (which is quite unusual for Jekyll). If default
116
- # excerpt delimiter is not good for you, you might want to set your own via
117
- # configuration option `excerpt_separator`. For example, following is a good
118
- # alternative for HTML docs:
119
- #
120
- # # file: _config.yml
121
- # excerpt_separator: "<!-- more -->"
122
- #
123
- # Notice that all markdown-style link references will be appended to the
124
- # excerpt. So the example doc above will have this excerpt source:
125
- #
126
- # First paragraph with [link][1].
127
- #
128
- # [1]: http://example.com/
129
- #
130
- # Excerpts are rendered same time as content is rendered.
131
- #
132
- # Returns excerpt String
133
-
134
- LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m.freeze
135
- MKDWN_LINK_REF_REGEX = %r!^ {0,3}(?:(\[[^\]]+\])(:.+))$!.freeze
136
-
137
- def extract_excerpt(doc_content)
138
- head, _, tail = doc_content.to_s.partition(doc.excerpt_separator)
139
- return head if tail.empty?
140
-
141
- head = sanctify_liquid_tags(head) if head.include?("{%")
142
- definitions = extract_markdown_link_reference_defintions(head, tail)
143
- return head if definitions.empty?
144
-
145
- head << "\n\n" << definitions.join("\n")
146
- end
147
-
148
- private
149
-
150
- # append appropriate closing tag(s) (for each Liquid block), to the `head` if the
151
- # partitioning resulted in leaving the closing tag somewhere in the `tail` partition.
152
- def sanctify_liquid_tags(head)
153
- modified = false
154
- tag_names = head.scan(LIQUID_TAG_REGEX)
155
- tag_names.flatten!
156
- tag_names.reverse_each do |tag_name|
157
- next unless liquid_block?(tag_name)
158
- next if endtag_regex_stash(tag_name).match?(head)
159
-
160
- modified = true
161
- head << "\n{% end#{tag_name} %}"
162
- end
163
-
164
- print_build_warning if modified
165
- head
166
- end
167
-
168
- def extract_markdown_link_reference_defintions(head, tail)
169
- [].tap do |definitions|
170
- tail.scan(MKDWN_LINK_REF_REGEX).each do |segments|
171
- definitions << segments.join if head.include?(segments[0])
172
- end
173
- end
174
- end
175
-
176
- def endtag_regex_stash(tag_name)
177
- @endtag_regex_stash ||= {}
178
- @endtag_regex_stash[tag_name] ||= %r!{%-?\s*end#{tag_name}.*?\s*-?%}!m
179
- end
180
-
181
- def liquid_block?(tag_name)
182
- return false unless tag_name.is_a?(String)
183
- return false unless Liquid::Template.tags[tag_name]
184
-
185
- Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block)
186
- rescue NoMethodError
187
- Jekyll.logger.error "Error:",
188
- "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed."
189
- raise
190
- end
191
-
192
- def print_build_warning
193
- Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!"
194
- Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator" \
195
- " #{doc.excerpt_separator.inspect}. "
196
- Jekyll.logger.warn "", "The block has been modified with the appropriate closing tag."
197
- Jekyll.logger.warn "", "Feel free to define a custom excerpt or excerpt_separator in the"
198
- Jekyll.logger.warn "", "document's Front Matter if the generated excerpt is unsatisfactory."
199
- end
200
- end
201
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class Excerpt
5
+ extend Forwardable
6
+
7
+ attr_accessor :doc
8
+ attr_accessor :content, :ext
9
+ attr_writer :output
10
+
11
+ def_delegators :@doc,
12
+ :site, :name, :ext, :extname,
13
+ :collection, :related_posts, :type,
14
+ :coffeescript_file?, :yaml_file?,
15
+ :url, :next_doc, :previous_doc
16
+
17
+ private :coffeescript_file?, :yaml_file?
18
+
19
+ # Initialize this Excerpt instance.
20
+ #
21
+ # doc - The Document.
22
+ #
23
+ # Returns the new Excerpt.
24
+ def initialize(doc)
25
+ self.doc = doc
26
+ self.content = extract_excerpt(doc.content)
27
+ end
28
+
29
+ # Fetch YAML front-matter data from related doc, without layout key
30
+ #
31
+ # Returns Hash of doc data
32
+ def data
33
+ @data ||= doc.data.dup
34
+ @data.delete("layout")
35
+ @data.delete("excerpt")
36
+ @data
37
+ end
38
+
39
+ def trigger_hooks(*); end
40
+
41
+ # 'Path' of the excerpt.
42
+ #
43
+ # Returns the path for the doc this excerpt belongs to with #excerpt appended
44
+ def path
45
+ File.join(doc.path, "#excerpt")
46
+ end
47
+
48
+ # 'Relative Path' of the excerpt.
49
+ #
50
+ # Returns the relative_path for the doc this excerpt belongs to with #excerpt appended
51
+ def relative_path
52
+ @relative_path ||= File.join(doc.relative_path, "#excerpt")
53
+ end
54
+
55
+ # Check if excerpt includes a string
56
+ #
57
+ # Returns true if the string passed in
58
+ def include?(something)
59
+ output&.include?(something) || content.include?(something)
60
+ end
61
+
62
+ # The UID for this doc (useful in feeds).
63
+ # e.g. /2008/11/05/my-awesome-doc
64
+ #
65
+ # Returns the String UID.
66
+ def id
67
+ "#{doc.id}#excerpt"
68
+ end
69
+
70
+ def to_s
71
+ output || content
72
+ end
73
+
74
+ def to_liquid
75
+ Jekyll::Drops::ExcerptDrop.new(self)
76
+ end
77
+
78
+ # Returns the shorthand String identifier of this doc.
79
+ def inspect
80
+ "<#{self.class} id=#{id}>"
81
+ end
82
+
83
+ def output
84
+ @output ||= Renderer.new(doc.site, self, site.site_payload).run
85
+ end
86
+
87
+ def place_in_layout?
88
+ false
89
+ end
90
+
91
+ def render_with_liquid?
92
+ return false if data["render_with_liquid"] == false
93
+
94
+ !(coffeescript_file? || yaml_file? || !Utils.has_liquid_construct?(content))
95
+ end
96
+
97
+ protected
98
+
99
+ # Internal: Extract excerpt from the content
100
+ #
101
+ # By default excerpt is your first paragraph of a doc: everything before
102
+ # the first two new lines:
103
+ #
104
+ # ---
105
+ # title: Example
106
+ # ---
107
+ #
108
+ # First paragraph with [link][1].
109
+ #
110
+ # Second paragraph.
111
+ #
112
+ # [1]: http://example.com/
113
+ #
114
+ # This is fairly good option for Markdown and Textile files. But might cause
115
+ # problems for HTML docs (which is quite unusual for Jekyll). If default
116
+ # excerpt delimiter is not good for you, you might want to set your own via
117
+ # configuration option `excerpt_separator`. For example, following is a good
118
+ # alternative for HTML docs:
119
+ #
120
+ # # file: _config.yml
121
+ # excerpt_separator: "<!-- more -->"
122
+ #
123
+ # Notice that all markdown-style link references will be appended to the
124
+ # excerpt. So the example doc above will have this excerpt source:
125
+ #
126
+ # First paragraph with [link][1].
127
+ #
128
+ # [1]: http://example.com/
129
+ #
130
+ # Excerpts are rendered same time as content is rendered.
131
+ #
132
+ # Returns excerpt String
133
+
134
+ LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m.freeze
135
+ MKDWN_LINK_REF_REGEX = %r!^ {0,3}(?:(\[[^\]]+\])(:.+))$!.freeze
136
+
137
+ def extract_excerpt(doc_content)
138
+ head, _, tail = doc_content.to_s.partition(doc.excerpt_separator)
139
+ return head if tail.empty?
140
+
141
+ head = sanctify_liquid_tags(head) if head.include?("{%")
142
+ definitions = extract_markdown_link_reference_defintions(head, tail)
143
+ return head if definitions.empty?
144
+
145
+ head << "\n\n" << definitions.join("\n")
146
+ end
147
+
148
+ private
149
+
150
+ # append appropriate closing tag(s) (for each Liquid block), to the `head` if the
151
+ # partitioning resulted in leaving the closing tag somewhere in the `tail` partition.
152
+ def sanctify_liquid_tags(head)
153
+ modified = false
154
+ tag_names = head.scan(LIQUID_TAG_REGEX)
155
+ tag_names.flatten!
156
+ tag_names.reverse_each do |tag_name|
157
+ next unless liquid_block?(tag_name)
158
+ next if endtag_regex_stash(tag_name).match?(head)
159
+
160
+ modified = true
161
+ head << "\n{% end#{tag_name} %}"
162
+ end
163
+
164
+ print_build_warning if modified
165
+ head
166
+ end
167
+
168
+ def extract_markdown_link_reference_defintions(head, tail)
169
+ [].tap do |definitions|
170
+ tail.scan(MKDWN_LINK_REF_REGEX).each do |segments|
171
+ definitions << segments.join if head.include?(segments[0])
172
+ end
173
+ end
174
+ end
175
+
176
+ def endtag_regex_stash(tag_name)
177
+ @endtag_regex_stash ||= {}
178
+ @endtag_regex_stash[tag_name] ||= %r!{%-?\s*end#{tag_name}.*?\s*-?%}!m
179
+ end
180
+
181
+ def liquid_block?(tag_name)
182
+ return false unless tag_name.is_a?(String)
183
+ return false unless Liquid::Template.tags[tag_name]
184
+
185
+ Liquid::Template.tags[tag_name].ancestors.include?(Liquid::Block)
186
+ rescue NoMethodError
187
+ Jekyll.logger.error "Error:",
188
+ "A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed."
189
+ raise
190
+ end
191
+
192
+ def print_build_warning
193
+ Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!"
194
+ Jekyll.logger.warn "", "Found a Liquid block containing the excerpt separator" \
195
+ " #{doc.excerpt_separator.inspect}. "
196
+ Jekyll.logger.warn "", "The block has been modified with the appropriate closing tag."
197
+ Jekyll.logger.warn "", "Feel free to define a custom excerpt or excerpt_separator in the"
198
+ Jekyll.logger.warn "", "document's Front Matter if the generated excerpt is unsatisfactory."
199
+ end
200
+ end
201
+ end
@@ -1,79 +1,79 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- module External
5
- class << self
6
- #
7
- # Gems that, if installed, should be loaded.
8
- # Usually contain subcommands.
9
- #
10
- def blessed_gems
11
- %w(
12
- jekyll-compose
13
- jekyll-docs
14
- jekyll-import
15
- )
16
- end
17
-
18
- #
19
- # Require a gem or file if it's present, otherwise silently fail.
20
- #
21
- # names - a string gem name or array of gem names
22
- #
23
- def require_if_present(names)
24
- Array(names).each do |name|
25
- begin
26
- require name
27
- rescue LoadError
28
- Jekyll.logger.debug "Couldn't load #{name}. Skipping."
29
- yield(name, version_constraint(name)) if block_given?
30
- false
31
- end
32
- end
33
- end
34
-
35
- #
36
- # The version constraint required to activate a given gem.
37
- # Usually the gem version requirement is "> 0," because any version
38
- # will do. In the case of jekyll-docs, however, we require the exact
39
- # same version as Jekyll.
40
- #
41
- # Returns a String version constraint in a parseable form for
42
- # RubyGems.
43
- def version_constraint(gem_name)
44
- return "= #{Jekyll::VERSION}" if gem_name.to_s.eql?("jekyll-docs")
45
-
46
- "> 0"
47
- end
48
-
49
- #
50
- # Require a gem or gems. If it's not present, show a very nice error
51
- # message that explains everything and is much more helpful than the
52
- # normal LoadError.
53
- #
54
- # names - a string gem name or array of gem names
55
- #
56
- def require_with_graceful_fail(names)
57
- Array(names).each do |name|
58
- begin
59
- Jekyll.logger.debug "Requiring:", name.to_s
60
- require name
61
- rescue LoadError => e
62
- Jekyll.logger.error "Dependency Error:", <<~MSG
63
- Yikes! It looks like you don't have #{name} or one of its dependencies installed.
64
- In order to use Jekyll as currently configured, you'll need to install this gem.
65
-
66
- If you've run Jekyll with `bundle exec`, ensure that you have included the #{name}
67
- gem in your Gemfile as well.
68
-
69
- The full error message from Ruby is: '#{e.message}'
70
-
71
- If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/!
72
- MSG
73
- raise Jekyll::Errors::MissingDependencyException, name
74
- end
75
- end
76
- end
77
- end
78
- end
79
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module External
5
+ class << self
6
+ #
7
+ # Gems that, if installed, should be loaded.
8
+ # Usually contain subcommands.
9
+ #
10
+ def blessed_gems
11
+ %w(
12
+ jekyll-compose
13
+ jekyll-docs
14
+ jekyll-import
15
+ )
16
+ end
17
+
18
+ #
19
+ # Require a gem or file if it's present, otherwise silently fail.
20
+ #
21
+ # names - a string gem name or array of gem names
22
+ #
23
+ def require_if_present(names)
24
+ Array(names).each do |name|
25
+ begin
26
+ require name
27
+ rescue LoadError
28
+ Jekyll.logger.debug "Couldn't load #{name}. Skipping."
29
+ yield(name, version_constraint(name)) if block_given?
30
+ false
31
+ end
32
+ end
33
+ end
34
+
35
+ #
36
+ # The version constraint required to activate a given gem.
37
+ # Usually the gem version requirement is "> 0," because any version
38
+ # will do. In the case of jekyll-docs, however, we require the exact
39
+ # same version as Jekyll.
40
+ #
41
+ # Returns a String version constraint in a parseable form for
42
+ # RubyGems.
43
+ def version_constraint(gem_name)
44
+ return "= #{Jekyll::VERSION}" if gem_name.to_s.eql?("jekyll-docs")
45
+
46
+ "> 0"
47
+ end
48
+
49
+ #
50
+ # Require a gem or gems. If it's not present, show a very nice error
51
+ # message that explains everything and is much more helpful than the
52
+ # normal LoadError.
53
+ #
54
+ # names - a string gem name or array of gem names
55
+ #
56
+ def require_with_graceful_fail(names)
57
+ Array(names).each do |name|
58
+ begin
59
+ Jekyll.logger.debug "Requiring:", name.to_s
60
+ require name
61
+ rescue LoadError => e
62
+ Jekyll.logger.error "Dependency Error:", <<~MSG
63
+ Yikes! It looks like you don't have #{name} or one of its dependencies installed.
64
+ In order to use Jekyll as currently configured, you'll need to install this gem.
65
+
66
+ If you've run Jekyll with `bundle exec`, ensure that you have included the #{name}
67
+ gem in your Gemfile as well.
68
+
69
+ The full error message from Ruby is: '#{e.message}'
70
+
71
+ If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/!
72
+ MSG
73
+ raise Jekyll::Errors::MissingDependencyException, name
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end