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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +511 -89
  3. data/LICENSE +1 -1
  4. data/README.markdown +48 -27
  5. data/lib/blank_template/_config.yml +3 -0
  6. data/lib/blank_template/_layouts/default.html +12 -0
  7. data/lib/blank_template/_sass/base.scss +9 -0
  8. data/lib/blank_template/assets/css/main.scss +4 -0
  9. data/lib/blank_template/index.md +8 -0
  10. data/lib/jekyll/cache.rb +186 -0
  11. data/lib/jekyll/cleaner.rb +8 -7
  12. data/lib/jekyll/collection.rb +84 -11
  13. data/lib/jekyll/command.rb +33 -6
  14. data/lib/jekyll/commands/build.rb +8 -28
  15. data/lib/jekyll/commands/clean.rb +3 -2
  16. data/lib/jekyll/commands/doctor.rb +46 -35
  17. data/lib/jekyll/commands/help.rb +1 -1
  18. data/lib/jekyll/commands/new.rb +44 -50
  19. data/lib/jekyll/commands/new_theme.rb +27 -28
  20. data/lib/jekyll/commands/serve/live_reload_reactor.rb +9 -16
  21. data/lib/jekyll/commands/serve/servlet.rb +21 -22
  22. data/lib/jekyll/commands/serve/websockets.rb +1 -1
  23. data/lib/jekyll/commands/serve.rb +75 -97
  24. data/lib/jekyll/configuration.rb +66 -158
  25. data/lib/jekyll/converters/identity.rb +18 -0
  26. data/lib/jekyll/converters/markdown/kramdown_parser.rb +83 -33
  27. data/lib/jekyll/converters/markdown.rb +49 -40
  28. data/lib/jekyll/converters/smartypants.rb +34 -14
  29. data/lib/jekyll/convertible.rb +36 -34
  30. data/lib/jekyll/deprecator.rb +2 -4
  31. data/lib/jekyll/document.rb +107 -72
  32. data/lib/jekyll/drops/collection_drop.rb +3 -4
  33. data/lib/jekyll/drops/document_drop.rb +9 -3
  34. data/lib/jekyll/drops/drop.rb +115 -33
  35. data/lib/jekyll/drops/excerpt_drop.rb +8 -0
  36. data/lib/jekyll/drops/site_drop.rb +9 -8
  37. data/lib/jekyll/drops/static_file_drop.rb +4 -4
  38. data/lib/jekyll/drops/theme_drop.rb +39 -0
  39. data/lib/jekyll/drops/unified_payload_drop.rb +7 -2
  40. data/lib/jekyll/drops/url_drop.rb +55 -3
  41. data/lib/jekyll/entry_filter.rb +42 -51
  42. data/lib/jekyll/excerpt.rb +48 -38
  43. data/lib/jekyll/external.rb +20 -19
  44. data/lib/jekyll/filters/date_filters.rb +6 -3
  45. data/lib/jekyll/filters/grouping_filters.rb +1 -2
  46. data/lib/jekyll/filters/url_filters.rb +50 -15
  47. data/lib/jekyll/filters.rb +211 -50
  48. data/lib/jekyll/frontmatter_defaults.rb +45 -36
  49. data/lib/jekyll/hooks.rb +26 -26
  50. data/lib/jekyll/inclusion.rb +32 -0
  51. data/lib/jekyll/layout.rb +12 -19
  52. data/lib/jekyll/liquid_extensions.rb +0 -2
  53. data/lib/jekyll/liquid_renderer/file.rb +24 -3
  54. data/lib/jekyll/liquid_renderer/table.rb +26 -77
  55. data/lib/jekyll/liquid_renderer.rb +31 -16
  56. data/lib/jekyll/log_adapter.rb +5 -1
  57. data/lib/jekyll/page.rb +51 -23
  58. data/lib/jekyll/page_excerpt.rb +25 -0
  59. data/lib/jekyll/page_without_a_file.rb +0 -4
  60. data/lib/jekyll/path_manager.rb +74 -0
  61. data/lib/jekyll/plugin.rb +5 -11
  62. data/lib/jekyll/plugin_manager.rb +15 -5
  63. data/lib/jekyll/profiler.rb +51 -0
  64. data/lib/jekyll/reader.rb +65 -10
  65. data/lib/jekyll/readers/collection_reader.rb +1 -0
  66. data/lib/jekyll/readers/data_reader.rb +48 -10
  67. data/lib/jekyll/readers/layout_reader.rb +3 -12
  68. data/lib/jekyll/readers/page_reader.rb +5 -5
  69. data/lib/jekyll/readers/post_reader.rb +32 -19
  70. data/lib/jekyll/readers/static_file_reader.rb +4 -4
  71. data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
  72. data/lib/jekyll/regenerator.rb +4 -12
  73. data/lib/jekyll/related_posts.rb +1 -1
  74. data/lib/jekyll/renderer.rb +34 -49
  75. data/lib/jekyll/site.rb +151 -58
  76. data/lib/jekyll/static_file.rb +64 -28
  77. data/lib/jekyll/stevenson.rb +4 -8
  78. data/lib/jekyll/tags/highlight.rb +44 -57
  79. data/lib/jekyll/tags/include.rb +114 -80
  80. data/lib/jekyll/tags/link.rb +12 -7
  81. data/lib/jekyll/tags/post_url.rb +33 -30
  82. data/lib/jekyll/theme.rb +20 -18
  83. data/lib/jekyll/theme_builder.rb +91 -89
  84. data/lib/jekyll/url.rb +18 -10
  85. data/lib/jekyll/utils/ansi.rb +2 -2
  86. data/lib/jekyll/utils/exec.rb +0 -1
  87. data/lib/jekyll/utils/internet.rb +2 -4
  88. data/lib/jekyll/utils/platforms.rb +37 -52
  89. data/lib/jekyll/utils/thread_event.rb +1 -5
  90. data/lib/jekyll/utils.rb +29 -28
  91. data/lib/jekyll/version.rb +1 -1
  92. data/lib/jekyll.rb +9 -14
  93. data/lib/site_template/.gitignore +2 -0
  94. data/lib/site_template/404.html +2 -1
  95. data/lib/site_template/_config.yml +17 -5
  96. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
  97. data/lib/theme_template/README.md.erb +1 -3
  98. data/lib/theme_template/gitignore.erb +1 -0
  99. data/lib/theme_template/theme.gemspec.erb +1 -4
  100. data/rubocop/jekyll/assert_equal_literal_actual.rb +150 -0
  101. data/rubocop/jekyll/no_p_allowed.rb +5 -6
  102. data/rubocop/jekyll/no_puts_allowed.rb +5 -6
  103. metadata +149 -37
  104. data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
  105. data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
  106. data/lib/jekyll/utils/rouge.rb +0 -22
  107. /data/lib/site_template/{about.md → about.markdown} +0 -0
  108. /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
- return catch_inheritance(const) do |const_|
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[self.priority]
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"] && File.file?("Gemfile")
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 ||= Array[site.config["whitelist"]].flatten
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 "You appear to have pagination " \
108
- "turned on, but you haven't included the `jekyll-paginate` gem. " \
109
- "Ensure you have `plugins: [jekyll-paginate]` in your configuration file."
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
- dot_dirs = dot.select { |file| File.directory?(@site.in_source_dir(base, file)) }
44
- dot_files = (dot - dot_dirs)
45
- dot_pages = dot_files.select do |file|
46
- Utils.has_yaml_header?(@site.in_source_dir(base, file))
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 = File.join(dir, file)
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
@@ -5,6 +5,7 @@ module Jekyll
5
5
  SPECIAL_COLLECTIONS = %w(posts data).freeze
6
6
 
7
7
  attr_reader :site, :content
8
+
8
9
  def initialize(site)
9
10
  @site = site
10
11
  @content = {}
@@ -3,10 +3,13 @@
3
3
  module Jekyll
4
4
  class DataReader
5
5
  attr_reader :site, :content
6
- def initialize(site)
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 = site.in_source_dir(dir)
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 = @site.in_source_dir(dir, entry)
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 ||= (layout_directory_in_cwd || layout_directory_inside_source)
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
- def layout_directory_inside_source
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
- # Read all the files in <source>/<dir>/ for Yaml header and create a new Page
13
- # object for each file.
13
+ # Create a new `Jekyll::Page` object for each entry in a given array.
14
14
  #
15
- # dir - The String relative path of the directory to read.
15
+ # files - An array of file names inside `@dir`
16
16
  #
17
- # Returns an array of static pages.
17
+ # Returns an array of publishable `Jekyll::Page` objects.
18
18
  def read(files)
19
- files.map do |page|
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).tap { |docs| docs.each(&:read) }
38
- .select do |doc|
39
- if doc.content.valid_encoding?
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 =~ matcher
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
- :site => @site,
67
- :collection => @site.posts,
68
- })
69
- end.reject(&:nil?)
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
- # Read all the files in <source>/<dir>/ for Yaml header and create a new Page
13
- # object for each file.
13
+ # Create a new StaticFile object for every entry in a given list of basenames.
14
14
  #
15
- # dir - The String relative path of the directory to read.
15
+ # files - an array of file basenames.
16
16
  #
17
17
  # Returns an array of static files.
18
18
  def read(files)
19
- files.map do |file|
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 && site.theme.assets_path
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
- Jekyll::Page.new(site, base, dir, name)
34
+ Jekyll::Page.new(site, base, dir, name)
32
35
  else
33
36
  append_unless_exists site.static_files,
34
- Jekyll::StaticFile.new(site, base, "/#{dir}", name)
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
- "Ignoring #{new_item.relative_path} in theme due to existing file " \
42
- "with that path in site."
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