ngage 0.0.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 +7 -0
- data/LICENSE +22 -0
- data/exe/ngage +55 -0
- data/lib/ngage.rb +3 -0
- data/lib/ngage/jekyll.rb +204 -0
- data/lib/ngage/jekyll/cleaner.rb +111 -0
- data/lib/ngage/jekyll/collection.rb +235 -0
- data/lib/ngage/jekyll/command.rb +103 -0
- data/lib/ngage/jekyll/commands/build.rb +93 -0
- data/lib/ngage/jekyll/commands/clean.rb +45 -0
- data/lib/ngage/jekyll/commands/doctor.rb +173 -0
- data/lib/ngage/jekyll/commands/help.rb +34 -0
- data/lib/ngage/jekyll/commands/new.rb +157 -0
- data/lib/ngage/jekyll/commands/new_theme.rb +42 -0
- data/lib/ngage/jekyll/commands/serve.rb +354 -0
- data/lib/ngage/jekyll/commands/serve/live_reload_reactor.rb +122 -0
- data/lib/ngage/jekyll/commands/serve/livereload_assets/livereload.js +1183 -0
- data/lib/ngage/jekyll/commands/serve/servlet.rb +203 -0
- data/lib/ngage/jekyll/commands/serve/websockets.rb +81 -0
- data/lib/ngage/jekyll/configuration.rb +391 -0
- data/lib/ngage/jekyll/converter.rb +54 -0
- data/lib/ngage/jekyll/converters/identity.rb +41 -0
- data/lib/ngage/jekyll/converters/markdown.rb +116 -0
- data/lib/ngage/jekyll/converters/markdown/kramdown_parser.rb +122 -0
- data/lib/ngage/jekyll/converters/smartypants.rb +70 -0
- data/lib/ngage/jekyll/convertible.rb +253 -0
- data/lib/ngage/jekyll/deprecator.rb +50 -0
- data/lib/ngage/jekyll/document.rb +503 -0
- data/lib/ngage/jekyll/drops/collection_drop.rb +20 -0
- data/lib/ngage/jekyll/drops/document_drop.rb +69 -0
- data/lib/ngage/jekyll/drops/drop.rb +209 -0
- data/lib/ngage/jekyll/drops/excerpt_drop.rb +15 -0
- data/lib/ngage/jekyll/drops/jekyll_drop.rb +32 -0
- data/lib/ngage/jekyll/drops/site_drop.rb +56 -0
- data/lib/ngage/jekyll/drops/static_file_drop.rb +14 -0
- data/lib/ngage/jekyll/drops/unified_payload_drop.rb +26 -0
- data/lib/ngage/jekyll/drops/url_drop.rb +89 -0
- data/lib/ngage/jekyll/entry_filter.rb +127 -0
- data/lib/ngage/jekyll/errors.rb +20 -0
- data/lib/ngage/jekyll/excerpt.rb +180 -0
- data/lib/ngage/jekyll/external.rb +76 -0
- data/lib/ngage/jekyll/filters.rb +390 -0
- data/lib/ngage/jekyll/filters/date_filters.rb +110 -0
- data/lib/ngage/jekyll/filters/grouping_filters.rb +64 -0
- data/lib/ngage/jekyll/filters/url_filters.rb +68 -0
- data/lib/ngage/jekyll/frontmatter_defaults.rb +233 -0
- data/lib/ngage/jekyll/generator.rb +5 -0
- data/lib/ngage/jekyll/hooks.rb +106 -0
- data/lib/ngage/jekyll/layout.rb +62 -0
- data/lib/ngage/jekyll/liquid_extensions.rb +22 -0
- data/lib/ngage/jekyll/liquid_renderer.rb +63 -0
- data/lib/ngage/jekyll/liquid_renderer/file.rb +56 -0
- data/lib/ngage/jekyll/liquid_renderer/table.rb +98 -0
- data/lib/ngage/jekyll/log_adapter.rb +151 -0
- data/lib/ngage/jekyll/mime.types +825 -0
- data/lib/ngage/jekyll/page.rb +185 -0
- data/lib/ngage/jekyll/page_without_a_file.rb +14 -0
- data/lib/ngage/jekyll/plugin.rb +92 -0
- data/lib/ngage/jekyll/plugin_manager.rb +115 -0
- data/lib/ngage/jekyll/publisher.rb +23 -0
- data/lib/ngage/jekyll/reader.rb +154 -0
- data/lib/ngage/jekyll/readers/collection_reader.rb +22 -0
- data/lib/ngage/jekyll/readers/data_reader.rb +75 -0
- data/lib/ngage/jekyll/readers/layout_reader.rb +70 -0
- data/lib/ngage/jekyll/readers/page_reader.rb +25 -0
- data/lib/ngage/jekyll/readers/post_reader.rb +72 -0
- data/lib/ngage/jekyll/readers/static_file_reader.rb +25 -0
- data/lib/ngage/jekyll/readers/theme_assets_reader.rb +51 -0
- data/lib/ngage/jekyll/regenerator.rb +195 -0
- data/lib/ngage/jekyll/related_posts.rb +52 -0
- data/lib/ngage/jekyll/renderer.rb +266 -0
- data/lib/ngage/jekyll/site.rb +476 -0
- data/lib/ngage/jekyll/static_file.rb +169 -0
- data/lib/ngage/jekyll/stevenson.rb +60 -0
- data/lib/ngage/jekyll/tags/highlight.rb +108 -0
- data/lib/ngage/jekyll/tags/include.rb +226 -0
- data/lib/ngage/jekyll/tags/link.rb +40 -0
- data/lib/ngage/jekyll/tags/post_url.rb +104 -0
- data/lib/ngage/jekyll/theme.rb +73 -0
- data/lib/ngage/jekyll/theme_builder.rb +121 -0
- data/lib/ngage/jekyll/url.rb +160 -0
- data/lib/ngage/jekyll/utils.rb +370 -0
- data/lib/ngage/jekyll/utils/ansi.rb +57 -0
- data/lib/ngage/jekyll/utils/exec.rb +26 -0
- data/lib/ngage/jekyll/utils/internet.rb +37 -0
- data/lib/ngage/jekyll/utils/platforms.rb +82 -0
- data/lib/ngage/jekyll/utils/thread_event.rb +31 -0
- data/lib/ngage/jekyll/utils/win_tz.rb +75 -0
- data/lib/ngage/site_template/.gitignore +5 -0
- data/lib/ngage/site_template/404.html +25 -0
- data/lib/ngage/site_template/_config.yml +47 -0
- data/lib/ngage/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -0
- data/lib/ngage/site_template/about.markdown +18 -0
- data/lib/ngage/site_template/index.markdown +6 -0
- data/lib/ngage/theme_template/CODE_OF_CONDUCT.md.erb +74 -0
- data/lib/ngage/theme_template/Gemfile +4 -0
- data/lib/ngage/theme_template/LICENSE.txt.erb +21 -0
- data/lib/ngage/theme_template/README.md.erb +52 -0
- data/lib/ngage/theme_template/_layouts/default.html +1 -0
- data/lib/ngage/theme_template/_layouts/page.html +5 -0
- data/lib/ngage/theme_template/_layouts/post.html +5 -0
- data/lib/ngage/theme_template/example/_config.yml.erb +1 -0
- data/lib/ngage/theme_template/example/_post.md +12 -0
- data/lib/ngage/theme_template/example/index.html +14 -0
- data/lib/ngage/theme_template/example/style.scss +7 -0
- data/lib/ngage/theme_template/gitignore.erb +6 -0
- data/lib/ngage/theme_template/theme.gemspec.erb +19 -0
- data/lib/ngage/version.rb +5 -0
- metadata +328 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module Drops
|
|
5
|
+
class UrlDrop < Drop
|
|
6
|
+
extend Forwardable
|
|
7
|
+
|
|
8
|
+
mutable false
|
|
9
|
+
|
|
10
|
+
def_delegator :@obj, :cleaned_relative_path, :path
|
|
11
|
+
def_delegator :@obj, :output_ext, :output_ext
|
|
12
|
+
|
|
13
|
+
def collection
|
|
14
|
+
@obj.collection.label
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def name
|
|
18
|
+
Utils.slugify(@obj.basename_without_ext)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def title
|
|
22
|
+
Utils.slugify(@obj.data["slug"], :mode => "pretty", :cased => true) ||
|
|
23
|
+
Utils.slugify(@obj.basename_without_ext, :mode => "pretty", :cased => true)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def slug
|
|
27
|
+
Utils.slugify(@obj.data["slug"]) || Utils.slugify(@obj.basename_without_ext)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def categories
|
|
31
|
+
category_set = Set.new
|
|
32
|
+
Array(@obj.data["categories"]).each do |category|
|
|
33
|
+
category_set << category.to_s.downcase
|
|
34
|
+
end
|
|
35
|
+
category_set.to_a.join("/")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def year
|
|
39
|
+
@obj.date.strftime("%Y")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def month
|
|
43
|
+
@obj.date.strftime("%m")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def day
|
|
47
|
+
@obj.date.strftime("%d")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def hour
|
|
51
|
+
@obj.date.strftime("%H")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def minute
|
|
55
|
+
@obj.date.strftime("%M")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def second
|
|
59
|
+
@obj.date.strftime("%S")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def i_day
|
|
63
|
+
@obj.date.strftime("%-d")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def i_month
|
|
67
|
+
@obj.date.strftime("%-m")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def short_month
|
|
71
|
+
@obj.date.strftime("%b")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def short_year
|
|
75
|
+
@obj.date.strftime("%y")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def y_day
|
|
79
|
+
@obj.date.strftime("%j")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def fallback_data
|
|
85
|
+
{}
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
class EntryFilter
|
|
5
|
+
attr_reader :site
|
|
6
|
+
SPECIAL_LEADING_CHARACTERS = [
|
|
7
|
+
".", "_", "#", "~",
|
|
8
|
+
].freeze
|
|
9
|
+
|
|
10
|
+
def initialize(site, base_directory = nil)
|
|
11
|
+
@site = site
|
|
12
|
+
@base_directory = derive_base_directory(
|
|
13
|
+
@site, base_directory.to_s.dup
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def base_directory
|
|
18
|
+
@base_directory.to_s
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def derive_base_directory(site, base_dir)
|
|
22
|
+
base_dir[site.source] = "" if base_dir.start_with?(site.source)
|
|
23
|
+
base_dir
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def relative_to_source(entry)
|
|
27
|
+
File.join(
|
|
28
|
+
base_directory, entry
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def filter(entries)
|
|
33
|
+
entries.reject do |e|
|
|
34
|
+
# Reject this entry if it is a symlink.
|
|
35
|
+
next true if symlink?(e)
|
|
36
|
+
# Do not reject this entry if it is included.
|
|
37
|
+
next false if included?(e)
|
|
38
|
+
|
|
39
|
+
# Reject this entry if it is special, a backup file, or excluded.
|
|
40
|
+
special?(e) || backup?(e) || excluded?(e)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def included?(entry)
|
|
45
|
+
glob_include?(site.include, entry) ||
|
|
46
|
+
glob_include?(site.include, File.basename(entry))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def special?(entry)
|
|
50
|
+
SPECIAL_LEADING_CHARACTERS.include?(entry[0..0]) ||
|
|
51
|
+
SPECIAL_LEADING_CHARACTERS.include?(File.basename(entry)[0..0])
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def backup?(entry)
|
|
55
|
+
entry[-1..-1] == "~"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def excluded?(entry)
|
|
59
|
+
glob_include?(site.exclude, relative_to_source(entry)).tap do |excluded|
|
|
60
|
+
if excluded
|
|
61
|
+
Jekyll.logger.debug(
|
|
62
|
+
"EntryFilter:",
|
|
63
|
+
"excluded #{relative_to_source(entry)}"
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# --
|
|
70
|
+
# Check if a file is a symlink.
|
|
71
|
+
# NOTE: This can be converted to allowing even in safe,
|
|
72
|
+
# since we use Pathutil#in_path? now.
|
|
73
|
+
# --
|
|
74
|
+
def symlink?(entry)
|
|
75
|
+
site.safe && File.symlink?(entry) && symlink_outside_site_source?(entry)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# --
|
|
79
|
+
# NOTE: Pathutil#in_path? gets the realpath.
|
|
80
|
+
# @param [<Anything>] entry the entry you want to validate.
|
|
81
|
+
# Check if a path is outside of our given root.
|
|
82
|
+
# --
|
|
83
|
+
def symlink_outside_site_source?(entry)
|
|
84
|
+
!Pathutil.new(entry).in_path?(
|
|
85
|
+
site.in_source_dir
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# --
|
|
90
|
+
# Check if an entry matches a specific pattern and return true,false.
|
|
91
|
+
# Returns true if path matches against any glob pattern.
|
|
92
|
+
# --
|
|
93
|
+
def glob_include?(enum, entry)
|
|
94
|
+
entry_path = Pathutil.new(site.in_source_dir).join(entry)
|
|
95
|
+
enum.any? do |exp|
|
|
96
|
+
# Users who send a Regexp knows what they want to
|
|
97
|
+
# exclude, so let them send a Regexp to exclude files,
|
|
98
|
+
# we will not bother caring if it works or not, it's
|
|
99
|
+
# on them at this point.
|
|
100
|
+
|
|
101
|
+
if exp.is_a?(Regexp)
|
|
102
|
+
entry_path =~ exp
|
|
103
|
+
|
|
104
|
+
else
|
|
105
|
+
item = Pathutil.new(site.in_source_dir).join(exp)
|
|
106
|
+
|
|
107
|
+
# If it's a directory they want to exclude, AKA
|
|
108
|
+
# ends with a "/" then we will go on to check and
|
|
109
|
+
# see if the entry falls within that path and
|
|
110
|
+
# exclude it if that's the case.
|
|
111
|
+
|
|
112
|
+
if entry.end_with?("/")
|
|
113
|
+
entry_path.in_path?(
|
|
114
|
+
item
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
else
|
|
118
|
+
File.fnmatch?(item, entry_path) ||
|
|
119
|
+
entry_path.to_path.start_with?(
|
|
120
|
+
item
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module Errors
|
|
5
|
+
FatalException = Class.new(::RuntimeError)
|
|
6
|
+
|
|
7
|
+
InvalidThemeName = Class.new(FatalException)
|
|
8
|
+
|
|
9
|
+
DropMutationException = Class.new(FatalException)
|
|
10
|
+
InvalidPermalinkError = Class.new(FatalException)
|
|
11
|
+
InvalidYAMLFrontMatterError = Class.new(FatalException)
|
|
12
|
+
MissingDependencyException = Class.new(FatalException)
|
|
13
|
+
|
|
14
|
+
InvalidDateError = Class.new(FatalException)
|
|
15
|
+
InvalidPostNameError = Class.new(FatalException)
|
|
16
|
+
PostURLError = Class.new(FatalException)
|
|
17
|
+
InvalidURLError = Class.new(FatalException)
|
|
18
|
+
InvalidConfigurationError = Class.new(FatalException)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
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,
|
|
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
|
+
"<Excerpt: #{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
|
|
135
|
+
MKDWN_LINK_REF_REGEX = %r!^ {0,3}\[[^\]]+\]:.+$!
|
|
136
|
+
|
|
137
|
+
def extract_excerpt(doc_content)
|
|
138
|
+
head, _, tail = doc_content.to_s.partition(doc.excerpt_separator)
|
|
139
|
+
|
|
140
|
+
# append appropriate closing tag (to a Liquid block), to the "head" if the
|
|
141
|
+
# partitioning resulted in leaving the closing tag somewhere in the "tail"
|
|
142
|
+
# partition.
|
|
143
|
+
if head.include?("{%")
|
|
144
|
+
head =~ LIQUID_TAG_REGEX
|
|
145
|
+
tag_name = Regexp.last_match(1)
|
|
146
|
+
|
|
147
|
+
if liquid_block?(tag_name) && head.match(%r!{%-?\s*end#{tag_name}\s*-?%}!).nil?
|
|
148
|
+
print_build_warning
|
|
149
|
+
head << "\n{% end#{tag_name} %}"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
if tail.empty?
|
|
154
|
+
head
|
|
155
|
+
else
|
|
156
|
+
head.to_s.dup << "\n\n" << tail.scan(MKDWN_LINK_REF_REGEX).join("\n")
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
|
|
162
|
+
def liquid_block?(tag_name)
|
|
163
|
+
Liquid::Template.tags[tag_name].superclass == Liquid::Block
|
|
164
|
+
rescue NoMethodError
|
|
165
|
+
Jekyll.logger.error "Error:",
|
|
166
|
+
"A Liquid tag in the excerpt of #{doc.relative_path} couldn't be parsed."
|
|
167
|
+
raise
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def print_build_warning
|
|
171
|
+
Jekyll.logger.warn "Warning:", "Excerpt modified in #{doc.relative_path}!"
|
|
172
|
+
Jekyll.logger.warn "",
|
|
173
|
+
"Found a Liquid block containing separator '#{doc.excerpt_separator}'" \
|
|
174
|
+
" and has been modified with the appropriate closing tag."
|
|
175
|
+
Jekyll.logger.warn "",
|
|
176
|
+
"Feel free to define a custom excerpt or excerpt_separator in the" \
|
|
177
|
+
" document's Front Matter if the generated excerpt is unsatisfactory."
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
The full error message from Ruby is: '#{e.message}'
|
|
67
|
+
|
|
68
|
+
If you run into trouble, you can find helpful resources at https://jekyllrb.com/help/!
|
|
69
|
+
MSG
|
|
70
|
+
raise Jekyll::Errors::MissingDependencyException, name
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|