jekyll 3.9.3 → 4.4.1
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 +4 -4
- data/.rubocop.yml +511 -89
- data/LICENSE +1 -1
- data/README.markdown +48 -27
- data/lib/blank_template/_config.yml +3 -0
- data/lib/blank_template/_layouts/default.html +12 -0
- data/lib/blank_template/_sass/base.scss +9 -0
- data/lib/blank_template/assets/css/main.scss +4 -0
- data/lib/blank_template/index.md +8 -0
- data/lib/jekyll/cache.rb +186 -0
- data/lib/jekyll/cleaner.rb +8 -7
- data/lib/jekyll/collection.rb +84 -11
- data/lib/jekyll/command.rb +33 -6
- data/lib/jekyll/commands/build.rb +8 -28
- data/lib/jekyll/commands/clean.rb +3 -2
- data/lib/jekyll/commands/doctor.rb +46 -35
- data/lib/jekyll/commands/help.rb +1 -1
- data/lib/jekyll/commands/new.rb +44 -50
- data/lib/jekyll/commands/new_theme.rb +27 -28
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +9 -16
- data/lib/jekyll/commands/serve/servlet.rb +21 -22
- data/lib/jekyll/commands/serve/websockets.rb +1 -1
- data/lib/jekyll/commands/serve.rb +75 -97
- data/lib/jekyll/configuration.rb +66 -158
- data/lib/jekyll/converters/identity.rb +18 -0
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +83 -33
- data/lib/jekyll/converters/markdown.rb +49 -40
- data/lib/jekyll/converters/smartypants.rb +34 -14
- data/lib/jekyll/convertible.rb +36 -34
- data/lib/jekyll/deprecator.rb +2 -4
- data/lib/jekyll/document.rb +107 -72
- data/lib/jekyll/drops/collection_drop.rb +3 -4
- data/lib/jekyll/drops/document_drop.rb +9 -3
- data/lib/jekyll/drops/drop.rb +115 -33
- data/lib/jekyll/drops/excerpt_drop.rb +8 -0
- data/lib/jekyll/drops/site_drop.rb +9 -8
- data/lib/jekyll/drops/static_file_drop.rb +4 -4
- data/lib/jekyll/drops/theme_drop.rb +39 -0
- data/lib/jekyll/drops/unified_payload_drop.rb +7 -2
- data/lib/jekyll/drops/url_drop.rb +55 -3
- data/lib/jekyll/entry_filter.rb +42 -51
- data/lib/jekyll/excerpt.rb +48 -38
- data/lib/jekyll/external.rb +20 -19
- data/lib/jekyll/filters/date_filters.rb +6 -3
- data/lib/jekyll/filters/grouping_filters.rb +1 -2
- data/lib/jekyll/filters/url_filters.rb +50 -15
- data/lib/jekyll/filters.rb +211 -50
- data/lib/jekyll/frontmatter_defaults.rb +45 -36
- data/lib/jekyll/hooks.rb +26 -26
- data/lib/jekyll/inclusion.rb +32 -0
- data/lib/jekyll/layout.rb +12 -19
- data/lib/jekyll/liquid_extensions.rb +0 -2
- data/lib/jekyll/liquid_renderer/file.rb +24 -3
- data/lib/jekyll/liquid_renderer/table.rb +26 -77
- data/lib/jekyll/liquid_renderer.rb +31 -16
- data/lib/jekyll/log_adapter.rb +5 -1
- data/lib/jekyll/page.rb +51 -23
- data/lib/jekyll/page_excerpt.rb +25 -0
- data/lib/jekyll/page_without_a_file.rb +0 -4
- data/lib/jekyll/path_manager.rb +74 -0
- data/lib/jekyll/plugin.rb +5 -11
- data/lib/jekyll/plugin_manager.rb +15 -5
- data/lib/jekyll/profiler.rb +51 -0
- data/lib/jekyll/reader.rb +65 -10
- data/lib/jekyll/readers/collection_reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +48 -10
- data/lib/jekyll/readers/layout_reader.rb +3 -12
- data/lib/jekyll/readers/page_reader.rb +5 -5
- data/lib/jekyll/readers/post_reader.rb +32 -19
- data/lib/jekyll/readers/static_file_reader.rb +4 -4
- data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
- data/lib/jekyll/regenerator.rb +4 -12
- data/lib/jekyll/related_posts.rb +1 -1
- data/lib/jekyll/renderer.rb +34 -49
- data/lib/jekyll/site.rb +151 -58
- data/lib/jekyll/static_file.rb +64 -28
- data/lib/jekyll/stevenson.rb +4 -8
- data/lib/jekyll/tags/highlight.rb +44 -57
- data/lib/jekyll/tags/include.rb +114 -80
- data/lib/jekyll/tags/link.rb +12 -7
- data/lib/jekyll/tags/post_url.rb +33 -30
- data/lib/jekyll/theme.rb +20 -18
- data/lib/jekyll/theme_builder.rb +91 -89
- data/lib/jekyll/url.rb +18 -10
- data/lib/jekyll/utils/ansi.rb +2 -2
- data/lib/jekyll/utils/exec.rb +0 -1
- data/lib/jekyll/utils/internet.rb +2 -4
- data/lib/jekyll/utils/platforms.rb +37 -52
- data/lib/jekyll/utils/thread_event.rb +1 -5
- data/lib/jekyll/utils.rb +29 -28
- data/lib/jekyll/version.rb +1 -1
- data/lib/jekyll.rb +9 -14
- data/lib/site_template/.gitignore +2 -0
- data/lib/site_template/404.html +2 -1
- data/lib/site_template/_config.yml +17 -5
- data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
- data/lib/theme_template/README.md.erb +1 -3
- data/lib/theme_template/gitignore.erb +1 -0
- data/lib/theme_template/theme.gemspec.erb +1 -4
- data/rubocop/jekyll/assert_equal_literal_actual.rb +150 -0
- data/rubocop/jekyll/no_p_allowed.rb +5 -6
- data/rubocop/jekyll/no_puts_allowed.rb +5 -6
- metadata +149 -37
- data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
- data/lib/jekyll/utils/rouge.rb +0 -22
- /data/lib/site_template/{about.md → about.markdown} +0 -0
- /data/lib/site_template/{index.md → index.markdown} +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
# A singleton class that caches frozen instances of path strings returned from its methods.
|
|
5
|
+
#
|
|
6
|
+
# NOTE:
|
|
7
|
+
# This class exists because `File.join` allocates an Array and returns a new String on every
|
|
8
|
+
# call using **the same arguments**. Caching the result means reduced memory usage.
|
|
9
|
+
# However, the caches are never flushed so that they can be used even when a site is
|
|
10
|
+
# regenerating. The results are frozen to deter mutation of the cached string.
|
|
11
|
+
#
|
|
12
|
+
# Therefore, employ this class only for situations where caching the result is necessary
|
|
13
|
+
# for performance reasons.
|
|
14
|
+
#
|
|
15
|
+
class PathManager
|
|
16
|
+
# This class cannot be initialized from outside
|
|
17
|
+
private_class_method :new
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
# Wraps `File.join` to cache the frozen result.
|
|
21
|
+
# Reassigns `nil`, empty strings and empty arrays to a frozen empty string beforehand.
|
|
22
|
+
#
|
|
23
|
+
# Returns a frozen string.
|
|
24
|
+
def join(base, item)
|
|
25
|
+
base = "" if base.nil? || base.empty?
|
|
26
|
+
item = "" if item.nil? || item.empty?
|
|
27
|
+
@join ||= {}
|
|
28
|
+
@join[base] ||= {}
|
|
29
|
+
@join[base][item] ||= File.join(base, item).freeze
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Ensures the questionable path is prefixed with the base directory
|
|
33
|
+
# and prepends the questionable path with the base directory if false.
|
|
34
|
+
#
|
|
35
|
+
# Returns a frozen string.
|
|
36
|
+
def sanitized_path(base_directory, questionable_path)
|
|
37
|
+
@sanitized_path ||= {}
|
|
38
|
+
@sanitized_path[base_directory] ||= {}
|
|
39
|
+
@sanitized_path[base_directory][questionable_path] ||= if questionable_path.nil?
|
|
40
|
+
base_directory.freeze
|
|
41
|
+
else
|
|
42
|
+
sanitize_and_join(
|
|
43
|
+
base_directory, questionable_path
|
|
44
|
+
).freeze
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def sanitize_and_join(base_directory, questionable_path)
|
|
51
|
+
clean_path = if questionable_path.start_with?("~")
|
|
52
|
+
questionable_path.dup.insert(0, "/")
|
|
53
|
+
else
|
|
54
|
+
questionable_path
|
|
55
|
+
end
|
|
56
|
+
clean_path = File.expand_path(clean_path, "/")
|
|
57
|
+
return clean_path if clean_path.eql?(base_directory)
|
|
58
|
+
|
|
59
|
+
# remove any remaining extra leading slashes not stripped away by calling
|
|
60
|
+
# `File.expand_path` above.
|
|
61
|
+
clean_path.squeeze!("/")
|
|
62
|
+
return clean_path if clean_path.start_with?(slashed_dir_cache(base_directory))
|
|
63
|
+
|
|
64
|
+
clean_path.sub!(%r!\A\w:/!, "/")
|
|
65
|
+
join(base_directory, clean_path)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def slashed_dir_cache(base_directory)
|
|
69
|
+
@slashed_dir_cache ||= {}
|
|
70
|
+
@slashed_dir_cache[base_directory] ||= base_directory.sub(%r!\z!, "/")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/lib/jekyll/plugin.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Jekyll
|
|
|
13
13
|
#
|
|
14
14
|
|
|
15
15
|
def self.inherited(const)
|
|
16
|
-
|
|
16
|
+
catch_inheritance(const) do |const_|
|
|
17
17
|
catch_inheritance(const_)
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -23,9 +23,7 @@ module Jekyll
|
|
|
23
23
|
def self.catch_inheritance(const)
|
|
24
24
|
const.define_singleton_method :inherited do |const_|
|
|
25
25
|
(@children ||= Set.new).add const_
|
|
26
|
-
if block_given?
|
|
27
|
-
yield const_
|
|
28
|
-
end
|
|
26
|
+
yield const_ if block_given?
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
|
|
@@ -48,9 +46,7 @@ module Jekyll
|
|
|
48
46
|
# Returns the Symbol priority.
|
|
49
47
|
def self.priority(priority = nil)
|
|
50
48
|
@priority ||= nil
|
|
51
|
-
if priority && PRIORITIES.key?(priority)
|
|
52
|
-
@priority = priority
|
|
53
|
-
end
|
|
49
|
+
@priority = priority if priority && PRIORITIES.key?(priority)
|
|
54
50
|
@priority || :normal
|
|
55
51
|
end
|
|
56
52
|
|
|
@@ -62,9 +58,7 @@ module Jekyll
|
|
|
62
58
|
#
|
|
63
59
|
# Returns the safety Boolean.
|
|
64
60
|
def self.safe(safe = nil)
|
|
65
|
-
unless defined?(@safe) && safe.nil?
|
|
66
|
-
@safe = safe
|
|
67
|
-
end
|
|
61
|
+
@safe = safe unless defined?(@safe) && safe.nil?
|
|
68
62
|
@safe || false
|
|
69
63
|
end
|
|
70
64
|
|
|
@@ -74,7 +68,7 @@ module Jekyll
|
|
|
74
68
|
#
|
|
75
69
|
# Returns -1, 0, 1.
|
|
76
70
|
def self.<=>(other)
|
|
77
|
-
PRIORITIES[other.priority] <=> PRIORITIES[
|
|
71
|
+
PRIORITIES[other.priority] <=> PRIORITIES[priority]
|
|
78
72
|
end
|
|
79
73
|
|
|
80
74
|
# Spaceship is priority [higher -> lower]
|
|
@@ -37,14 +37,16 @@ module Jekyll
|
|
|
37
37
|
# Returns false only if no dependencies have been specified, otherwise nothing.
|
|
38
38
|
def require_theme_deps
|
|
39
39
|
return false unless site.theme.runtime_dependencies
|
|
40
|
+
|
|
40
41
|
site.theme.runtime_dependencies.each do |dep|
|
|
41
42
|
next if dep.name == "jekyll"
|
|
43
|
+
|
|
42
44
|
External.require_with_graceful_fail(dep.name) if plugin_allowed?(dep.name)
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
def self.require_from_bundler
|
|
47
|
-
if !ENV["JEKYLL_NO_BUNDLER_REQUIRE"] &&
|
|
49
|
+
if !ENV["JEKYLL_NO_BUNDLER_REQUIRE"] && gemfile_exists?
|
|
48
50
|
require "bundler"
|
|
49
51
|
|
|
50
52
|
Bundler.setup
|
|
@@ -59,6 +61,13 @@ module Jekyll
|
|
|
59
61
|
end
|
|
60
62
|
end
|
|
61
63
|
|
|
64
|
+
# Check for the existence of a Gemfile.
|
|
65
|
+
#
|
|
66
|
+
# Returns true if a Gemfile exists in the places bundler will look
|
|
67
|
+
def self.gemfile_exists?
|
|
68
|
+
File.file?("Gemfile") || (ENV["BUNDLE_GEMFILE"] && File.file?(ENV["BUNDLE_GEMFILE"]))
|
|
69
|
+
end
|
|
70
|
+
|
|
62
71
|
# Check whether a gem plugin is allowed to be used during this build.
|
|
63
72
|
#
|
|
64
73
|
# plugin_name - the name of the plugin
|
|
@@ -74,7 +83,7 @@ module Jekyll
|
|
|
74
83
|
# Returns an array of strings, each string being the name of a gem name
|
|
75
84
|
# that is allowed to be used.
|
|
76
85
|
def whitelist
|
|
77
|
-
@whitelist ||=
|
|
86
|
+
@whitelist ||= [site.config["whitelist"]].flatten
|
|
78
87
|
end
|
|
79
88
|
|
|
80
89
|
# Require all .rb files if safe mode is off
|
|
@@ -104,9 +113,10 @@ module Jekyll
|
|
|
104
113
|
pagination_included = (site.config["plugins"] || []).include?("jekyll-paginate") ||
|
|
105
114
|
defined?(Jekyll::Paginate)
|
|
106
115
|
if site.config["paginate"] && !pagination_included
|
|
107
|
-
Jekyll::Deprecator.deprecation_message
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
Jekyll::Deprecator.deprecation_message <<~MSG
|
|
117
|
+
You appear to have pagination turned on, but you haven't included the `jekyll-paginate`
|
|
118
|
+
gem. Ensure you have `plugins: [jekyll-paginate]` in your configuration file.
|
|
119
|
+
MSG
|
|
110
120
|
end
|
|
111
121
|
end
|
|
112
122
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
class Profiler
|
|
5
|
+
TERMINAL_TABLE_STYLES = {
|
|
6
|
+
:alignment => :right,
|
|
7
|
+
:border_top => false,
|
|
8
|
+
:border_bottom => false,
|
|
9
|
+
}.freeze
|
|
10
|
+
private_constant :TERMINAL_TABLE_STYLES
|
|
11
|
+
|
|
12
|
+
def self.tabulate(table_rows)
|
|
13
|
+
require "terminal-table"
|
|
14
|
+
|
|
15
|
+
rows = table_rows.dup
|
|
16
|
+
header = rows.shift
|
|
17
|
+
output = +"\n"
|
|
18
|
+
|
|
19
|
+
table = Terminal::Table.new do |t|
|
|
20
|
+
t << header
|
|
21
|
+
t << :separator
|
|
22
|
+
rows.each { |row| t << row }
|
|
23
|
+
t.style = TERMINAL_TABLE_STYLES
|
|
24
|
+
t.align_column(0, :left)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
output << table.to_s << "\n"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def initialize(site)
|
|
31
|
+
@site = site
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def profile_process
|
|
35
|
+
profile_data = { "PHASE" => "TIME" }
|
|
36
|
+
|
|
37
|
+
[:reset, :read, :generate, :render, :cleanup, :write].each do |method|
|
|
38
|
+
start_time = Time.now
|
|
39
|
+
@site.send(method)
|
|
40
|
+
end_time = (Time.now - start_time).round(4)
|
|
41
|
+
profile_data[method.to_s.upcase] = format("%.4f", end_time)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
Jekyll.logger.info "\nBuild Process Summary:"
|
|
45
|
+
Jekyll.logger.info Profiler.tabulate(Array(profile_data))
|
|
46
|
+
|
|
47
|
+
Jekyll.logger.info "\nSite Render Stats:"
|
|
48
|
+
@site.print_stats
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/jekyll/reader.rb
CHANGED
|
@@ -14,10 +14,28 @@ module Jekyll
|
|
|
14
14
|
def read
|
|
15
15
|
@site.layouts = LayoutReader.new(site).read
|
|
16
16
|
read_directories
|
|
17
|
+
read_included_excludes
|
|
17
18
|
sort_files!
|
|
18
|
-
@site.data = DataReader.new(site).read(site.config["data_dir"])
|
|
19
19
|
CollectionReader.new(site).read
|
|
20
20
|
ThemeAssetsReader.new(site).read
|
|
21
|
+
read_data
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Read and merge the data files.
|
|
25
|
+
# If a theme is specified and it contains data, it will be read.
|
|
26
|
+
# Site data will overwrite theme data with the same key using the
|
|
27
|
+
# semantics of Utils.deep_merge_hashes.
|
|
28
|
+
#
|
|
29
|
+
# Returns nothing.
|
|
30
|
+
def read_data
|
|
31
|
+
@site.data = DataReader.new(site).read(site.config["data_dir"])
|
|
32
|
+
return unless site.theme&.data_path
|
|
33
|
+
|
|
34
|
+
theme_data = DataReader.new(
|
|
35
|
+
site,
|
|
36
|
+
:in_source_dir => site.method(:in_theme_dir)
|
|
37
|
+
).read(site.theme.data_path)
|
|
38
|
+
@site.data = Jekyll::Utils.deep_merge_hashes(theme_data, @site.data)
|
|
21
39
|
end
|
|
22
40
|
|
|
23
41
|
# Sorts posts, pages, and static files.
|
|
@@ -39,13 +57,21 @@ module Jekyll
|
|
|
39
57
|
|
|
40
58
|
return unless File.directory?(base)
|
|
41
59
|
|
|
60
|
+
dot_dirs = []
|
|
61
|
+
dot_pages = []
|
|
62
|
+
dot_static_files = []
|
|
63
|
+
|
|
42
64
|
dot = Dir.chdir(base) { filter_entries(Dir.entries("."), base) }
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
65
|
+
dot.each do |entry|
|
|
66
|
+
file_path = @site.in_source_dir(base, entry)
|
|
67
|
+
if File.directory?(file_path)
|
|
68
|
+
dot_dirs << entry
|
|
69
|
+
elsif Utils.has_yaml_header?(file_path)
|
|
70
|
+
dot_pages << entry
|
|
71
|
+
else
|
|
72
|
+
dot_static_files << entry
|
|
73
|
+
end
|
|
47
74
|
end
|
|
48
|
-
dot_static_files = dot_files - dot_pages
|
|
49
75
|
|
|
50
76
|
retrieve_posts(dir)
|
|
51
77
|
retrieve_dirs(base, dir, dot_dirs)
|
|
@@ -61,6 +87,7 @@ module Jekyll
|
|
|
61
87
|
# Returns nothing.
|
|
62
88
|
def retrieve_posts(dir)
|
|
63
89
|
return if outside_configured_directory?(dir)
|
|
90
|
+
|
|
64
91
|
site.posts.docs.concat(post_reader.read_posts(dir))
|
|
65
92
|
site.posts.docs.concat(post_reader.read_drafts(dir)) if site.show_drafts
|
|
66
93
|
end
|
|
@@ -75,10 +102,8 @@ module Jekyll
|
|
|
75
102
|
def retrieve_dirs(_base, dir, dot_dirs)
|
|
76
103
|
dot_dirs.each do |file|
|
|
77
104
|
dir_path = site.in_source_dir(dir, file)
|
|
78
|
-
rel_path =
|
|
79
|
-
unless @site.dest.chomp("/") == dir_path
|
|
80
|
-
@site.reader.read_directories(rel_path)
|
|
81
|
-
end
|
|
105
|
+
rel_path = PathManager.join(dir, file)
|
|
106
|
+
@site.reader.read_directories(rel_path) unless @site.dest.chomp("/") == dir_path
|
|
82
107
|
end
|
|
83
108
|
end
|
|
84
109
|
|
|
@@ -126,6 +151,7 @@ module Jekyll
|
|
|
126
151
|
def get_entries(dir, subfolder)
|
|
127
152
|
base = site.in_source_dir(dir, subfolder)
|
|
128
153
|
return [] unless File.exist?(base)
|
|
154
|
+
|
|
129
155
|
entries = Dir.chdir(base) { filter_entries(Dir["**/*"], base) }
|
|
130
156
|
entries.delete_if { |e| File.directory?(site.in_source_dir(base, e)) }
|
|
131
157
|
end
|
|
@@ -150,5 +176,34 @@ module Jekyll
|
|
|
150
176
|
def post_reader
|
|
151
177
|
@post_reader ||= PostReader.new(site)
|
|
152
178
|
end
|
|
179
|
+
|
|
180
|
+
def read_included_excludes
|
|
181
|
+
entry_filter = EntryFilter.new(site)
|
|
182
|
+
|
|
183
|
+
site.include.each do |entry|
|
|
184
|
+
entry_path = site.in_source_dir(entry)
|
|
185
|
+
next if File.directory?(entry_path)
|
|
186
|
+
next if entry_filter.symlink?(entry_path)
|
|
187
|
+
|
|
188
|
+
read_included_file(entry_path) if File.file?(entry_path)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def read_included_file(entry_path)
|
|
193
|
+
if Utils.has_yaml_header?(entry_path)
|
|
194
|
+
conditionally_generate_entry(entry_path, site.pages, PageReader)
|
|
195
|
+
else
|
|
196
|
+
conditionally_generate_entry(entry_path, site.static_files, StaticFileReader)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def conditionally_generate_entry(entry_path, container, reader)
|
|
201
|
+
return if container.find { |item| site.in_source_dir(item.relative_path) == entry_path }
|
|
202
|
+
|
|
203
|
+
dir, files = File.split(entry_path)
|
|
204
|
+
dir.sub!(site.source, "")
|
|
205
|
+
files = Array(files)
|
|
206
|
+
container.concat(reader.new(site, dir).read(files))
|
|
207
|
+
end
|
|
153
208
|
end
|
|
154
209
|
end
|
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
class DataReader
|
|
5
5
|
attr_reader :site, :content
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
def initialize(site, in_source_dir: nil)
|
|
7
8
|
@site = site
|
|
8
9
|
@content = {}
|
|
9
10
|
@entry_filter = EntryFilter.new(site)
|
|
11
|
+
@in_source_dir = in_source_dir || @site.method(:in_source_dir)
|
|
12
|
+
@source_dir = @in_source_dir.call("/")
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
# Read all the files in <dir> and adds them to @content
|
|
@@ -16,7 +19,7 @@ module Jekyll
|
|
|
16
19
|
# Returns @content, a Hash of the .yaml, .yml,
|
|
17
20
|
# .json, and .csv files in the base directory
|
|
18
21
|
def read(dir)
|
|
19
|
-
base =
|
|
22
|
+
base = @in_source_dir.call(dir)
|
|
20
23
|
read_data_to(base, @content)
|
|
21
24
|
@content
|
|
22
25
|
end
|
|
@@ -36,7 +39,7 @@ module Jekyll
|
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
entries.each do |entry|
|
|
39
|
-
path = @
|
|
42
|
+
path = @in_source_dir.call(dir, entry)
|
|
40
43
|
next if @entry_filter.symlink?(path)
|
|
41
44
|
|
|
42
45
|
if File.directory?(path)
|
|
@@ -52,16 +55,13 @@ module Jekyll
|
|
|
52
55
|
#
|
|
53
56
|
# Returns the contents of the data file.
|
|
54
57
|
def read_data_file(path)
|
|
58
|
+
Jekyll.logger.debug "Reading:", path.sub(@source_dir, "")
|
|
59
|
+
|
|
55
60
|
case File.extname(path).downcase
|
|
56
61
|
when ".csv"
|
|
57
|
-
CSV.read(path,
|
|
58
|
-
:headers => true,
|
|
59
|
-
:encoding => site.config["encoding"]).map(&:to_hash)
|
|
62
|
+
CSV.read(path, **csv_config).map { |row| convert_row(row) }
|
|
60
63
|
when ".tsv"
|
|
61
|
-
CSV.read(path,
|
|
62
|
-
:col_sep => "\t",
|
|
63
|
-
:headers => true,
|
|
64
|
-
:encoding => site.config["encoding"]).map(&:to_hash)
|
|
64
|
+
CSV.read(path, **tsv_config).map { |row| convert_row(row) }
|
|
65
65
|
else
|
|
66
66
|
SafeYAML.load_file(path)
|
|
67
67
|
end
|
|
@@ -71,5 +71,43 @@ module Jekyll
|
|
|
71
71
|
name.gsub(%r![^\w\s-]+|(?<=^|\b\s)\s+(?=$|\s?\b)!, "")
|
|
72
72
|
.gsub(%r!\s+!, "_")
|
|
73
73
|
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# @return [Hash]
|
|
78
|
+
def csv_config
|
|
79
|
+
@csv_config ||= read_config("csv_reader")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [Hash]
|
|
83
|
+
def tsv_config
|
|
84
|
+
@tsv_config ||= read_config("tsv_reader", { :col_sep => "\t" })
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @param config_key [String]
|
|
88
|
+
# @param overrides [Hash]
|
|
89
|
+
# @return [Hash]
|
|
90
|
+
# @see https://ruby-doc.org/stdlib-2.5.0/libdoc/csv/rdoc/CSV.html#Converters
|
|
91
|
+
def read_config(config_key, overrides = {})
|
|
92
|
+
reader_config = config[config_key] || {}
|
|
93
|
+
|
|
94
|
+
defaults = {
|
|
95
|
+
:converters => reader_config.fetch("csv_converters", []).map(&:to_sym),
|
|
96
|
+
:headers => reader_config.fetch("headers", true),
|
|
97
|
+
:encoding => reader_config.fetch("encoding", config["encoding"]),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
defaults.merge(overrides)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def config
|
|
104
|
+
@config ||= site.config
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @param row [Array, CSV::Row]
|
|
108
|
+
# @return [Array, Hash]
|
|
109
|
+
def convert_row(row)
|
|
110
|
+
row.instance_of?(CSV::Row) ? row.to_hash : row
|
|
111
|
+
end
|
|
74
112
|
end
|
|
75
113
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
class LayoutReader
|
|
5
5
|
attr_reader :site
|
|
6
|
+
|
|
6
7
|
def initialize(site)
|
|
7
8
|
@site = site
|
|
8
9
|
@layouts = {}
|
|
@@ -23,7 +24,7 @@ module Jekyll
|
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
def layout_directory
|
|
26
|
-
@layout_directory ||= (
|
|
27
|
+
@layout_directory ||= site.in_source_dir(site.config["layouts_dir"])
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def theme_layout_directory
|
|
@@ -54,18 +55,8 @@ module Jekyll
|
|
|
54
55
|
|
|
55
56
|
def within(directory)
|
|
56
57
|
return unless File.exist?(directory)
|
|
57
|
-
Dir.chdir(directory) { yield }
|
|
58
|
-
end
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
site.in_source_dir(site.config["layouts_dir"])
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def layout_directory_in_cwd
|
|
65
|
-
dir = Jekyll.sanitized_path(Dir.pwd, site.config["layouts_dir"])
|
|
66
|
-
if File.directory?(dir) && !site.safe
|
|
67
|
-
dir
|
|
68
|
-
end
|
|
59
|
+
Dir.chdir(directory) { yield }
|
|
69
60
|
end
|
|
70
61
|
end
|
|
71
62
|
end
|
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
class PageReader
|
|
5
5
|
attr_reader :site, :dir, :unfiltered_content
|
|
6
|
+
|
|
6
7
|
def initialize(site, dir)
|
|
7
8
|
@site = site
|
|
8
9
|
@dir = dir
|
|
9
10
|
@unfiltered_content = []
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
#
|
|
13
|
-
# object for each file.
|
|
13
|
+
# Create a new `Jekyll::Page` object for each entry in a given array.
|
|
14
14
|
#
|
|
15
|
-
#
|
|
15
|
+
# files - An array of file names inside `@dir`
|
|
16
16
|
#
|
|
17
|
-
# Returns an array of
|
|
17
|
+
# Returns an array of publishable `Jekyll::Page` objects.
|
|
18
18
|
def read(files)
|
|
19
|
-
files.
|
|
19
|
+
files.each do |page|
|
|
20
20
|
@unfiltered_content << Page.new(@site, @site.source, @dir, page)
|
|
21
21
|
end
|
|
22
22
|
@unfiltered_content.select { |page| site.publisher.publish?(page) }
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
class PostReader
|
|
5
5
|
attr_reader :site, :unfiltered_content
|
|
6
|
+
|
|
6
7
|
def initialize(site)
|
|
7
8
|
@site = site
|
|
8
9
|
end
|
|
@@ -34,19 +35,9 @@ module Jekyll
|
|
|
34
35
|
#
|
|
35
36
|
# Returns nothing.
|
|
36
37
|
def read_publishable(dir, magic_dir, matcher)
|
|
37
|
-
read_content(dir, magic_dir, matcher)
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
site.publisher.publish?(doc).tap do |will_publish|
|
|
41
|
-
if !will_publish && site.publisher.hidden_in_the_future?(doc)
|
|
42
|
-
Jekyll.logger.debug "Skipping:", "#{doc.relative_path} has a future date"
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
else
|
|
46
|
-
Jekyll.logger.debug "Skipping:", "#{doc.relative_path} is not valid UTF-8"
|
|
47
|
-
false
|
|
48
|
-
end
|
|
49
|
-
end
|
|
38
|
+
read_content(dir, magic_dir, matcher)
|
|
39
|
+
.tap { |docs| docs.each(&:read) }
|
|
40
|
+
.select { |doc| processable?(doc) }
|
|
50
41
|
end
|
|
51
42
|
|
|
52
43
|
# Read all the content files from <source>/<dir>/magic_dir
|
|
@@ -60,13 +51,35 @@ module Jekyll
|
|
|
60
51
|
# Returns klass type of content files
|
|
61
52
|
def read_content(dir, magic_dir, matcher)
|
|
62
53
|
@site.reader.get_entries(dir, magic_dir).map do |entry|
|
|
63
|
-
next unless entry
|
|
54
|
+
next unless matcher.match?(entry)
|
|
55
|
+
|
|
64
56
|
path = @site.in_source_dir(File.join(dir, magic_dir, entry))
|
|
65
|
-
Document.new(path,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
Document.new(path,
|
|
58
|
+
:site => @site,
|
|
59
|
+
:collection => @site.posts)
|
|
60
|
+
end.tap(&:compact!)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def processable?(doc)
|
|
66
|
+
if doc.content.nil?
|
|
67
|
+
Jekyll.logger.debug "Skipping:", "Content in #{doc.relative_path} is nil"
|
|
68
|
+
false
|
|
69
|
+
elsif !doc.content.valid_encoding?
|
|
70
|
+
Jekyll.logger.debug "Skipping:", "#{doc.relative_path} is not valid UTF-8"
|
|
71
|
+
false
|
|
72
|
+
else
|
|
73
|
+
publishable?(doc)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def publishable?(doc)
|
|
78
|
+
site.publisher.publish?(doc).tap do |will_publish|
|
|
79
|
+
if !will_publish && site.publisher.hidden_in_the_future?(doc)
|
|
80
|
+
Jekyll.logger.warn "Skipping:", "#{doc.relative_path} has a future date"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
70
83
|
end
|
|
71
84
|
end
|
|
72
85
|
end
|
|
@@ -3,20 +3,20 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
class StaticFileReader
|
|
5
5
|
attr_reader :site, :dir, :unfiltered_content
|
|
6
|
+
|
|
6
7
|
def initialize(site, dir)
|
|
7
8
|
@site = site
|
|
8
9
|
@dir = dir
|
|
9
10
|
@unfiltered_content = []
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
#
|
|
13
|
-
# object for each file.
|
|
13
|
+
# Create a new StaticFile object for every entry in a given list of basenames.
|
|
14
14
|
#
|
|
15
|
-
#
|
|
15
|
+
# files - an array of file basenames.
|
|
16
16
|
#
|
|
17
17
|
# Returns an array of static files.
|
|
18
18
|
def read(files)
|
|
19
|
-
files.
|
|
19
|
+
files.each do |file|
|
|
20
20
|
@unfiltered_content << StaticFile.new(@site, @site.source, @dir, file)
|
|
21
21
|
end
|
|
22
22
|
@unfiltered_content
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
class ThemeAssetsReader
|
|
5
5
|
attr_reader :site
|
|
6
|
+
|
|
6
7
|
def initialize(site)
|
|
7
8
|
@site = site
|
|
8
9
|
end
|
|
9
10
|
|
|
10
11
|
def read
|
|
11
|
-
return unless site.theme
|
|
12
|
+
return unless site.theme&.assets_path
|
|
12
13
|
|
|
13
14
|
Find.find(site.theme.assets_path) do |path|
|
|
14
15
|
next if File.directory?(path)
|
|
16
|
+
|
|
15
17
|
if File.symlink?(path)
|
|
16
18
|
Jekyll.logger.warn "Theme reader:", "Ignored symlinked asset: #{path}"
|
|
17
19
|
else
|
|
@@ -21,6 +23,7 @@ module Jekyll
|
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
private
|
|
26
|
+
|
|
24
27
|
def read_theme_asset(path)
|
|
25
28
|
base = site.theme.root
|
|
26
29
|
dir = File.dirname(path.sub("#{site.theme.root}/", ""))
|
|
@@ -28,18 +31,18 @@ module Jekyll
|
|
|
28
31
|
|
|
29
32
|
if Utils.has_yaml_header?(path)
|
|
30
33
|
append_unless_exists site.pages,
|
|
31
|
-
|
|
34
|
+
Jekyll::Page.new(site, base, dir, name)
|
|
32
35
|
else
|
|
33
36
|
append_unless_exists site.static_files,
|
|
34
|
-
|
|
37
|
+
Jekyll::StaticFile.new(site, base, "/#{dir}", name)
|
|
35
38
|
end
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
def append_unless_exists(haystack, new_item)
|
|
39
42
|
if haystack.any? { |file| file.relative_path == new_item.relative_path }
|
|
40
43
|
Jekyll.logger.debug "Theme:",
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
"Ignoring #{new_item.relative_path} in theme due to existing file " \
|
|
45
|
+
"with that path in site."
|
|
43
46
|
return
|
|
44
47
|
end
|
|
45
48
|
|