jekyll 4.2.2 → 4.3.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +150 -26
  3. data/README.markdown +16 -19
  4. data/lib/jekyll/cache.rb +3 -7
  5. data/lib/jekyll/cleaner.rb +1 -1
  6. data/lib/jekyll/collection.rb +1 -0
  7. data/lib/jekyll/commands/build.rb +2 -13
  8. data/lib/jekyll/commands/clean.rb +1 -2
  9. data/lib/jekyll/commands/doctor.rb +13 -13
  10. data/lib/jekyll/commands/new.rb +5 -9
  11. data/lib/jekyll/commands/new_theme.rb +3 -4
  12. data/lib/jekyll/commands/serve/live_reload_reactor.rb +3 -6
  13. data/lib/jekyll/commands/serve/mime_types_charset.json +71 -0
  14. data/lib/jekyll/commands/serve/servlet.rb +13 -9
  15. data/lib/jekyll/commands/serve.rb +23 -18
  16. data/lib/jekyll/configuration.rb +2 -2
  17. data/lib/jekyll/converters/markdown/kramdown_parser.rb +13 -15
  18. data/lib/jekyll/data_entry.rb +83 -0
  19. data/lib/jekyll/data_hash.rb +61 -0
  20. data/lib/jekyll/deprecator.rb +1 -1
  21. data/lib/jekyll/document.rb +2 -3
  22. data/lib/jekyll/drops/document_drop.rb +1 -0
  23. data/lib/jekyll/drops/excerpt_drop.rb +4 -0
  24. data/lib/jekyll/drops/site_drop.rb +6 -1
  25. data/lib/jekyll/drops/theme_drop.rb +36 -0
  26. data/lib/jekyll/drops/unified_payload_drop.rb +6 -2
  27. data/lib/jekyll/entry_filter.rb +2 -6
  28. data/lib/jekyll/excerpt.rb +5 -6
  29. data/lib/jekyll/external.rb +17 -21
  30. data/lib/jekyll/filters.rb +11 -14
  31. data/lib/jekyll/frontmatter_defaults.rb +2 -4
  32. data/lib/jekyll/hooks.rb +2 -2
  33. data/lib/jekyll/layout.rb +8 -20
  34. data/lib/jekyll/mime.types +146 -73
  35. data/lib/jekyll/page.rb +2 -4
  36. data/lib/jekyll/path_manager.rb +7 -7
  37. data/lib/jekyll/plugin_manager.rb +12 -4
  38. data/lib/jekyll/profiler.rb +0 -3
  39. data/lib/jekyll/reader.rb +18 -1
  40. data/lib/jekyll/readers/data_reader.rb +51 -14
  41. data/lib/jekyll/renderer.rb +8 -10
  42. data/lib/jekyll/site.rb +52 -21
  43. data/lib/jekyll/static_file.rb +6 -9
  44. data/lib/jekyll/tags/highlight.rb +13 -9
  45. data/lib/jekyll/tags/include.rb +4 -4
  46. data/lib/jekyll/tags/post_url.rb +5 -5
  47. data/lib/jekyll/theme.rb +6 -2
  48. data/lib/jekyll/theme_builder.rb +1 -1
  49. data/lib/jekyll/url.rb +1 -1
  50. data/lib/jekyll/utils/ansi.rb +1 -1
  51. data/lib/jekyll/utils/win_tz.rb +18 -47
  52. data/lib/jekyll/utils.rb +18 -7
  53. data/lib/jekyll/version.rb +1 -1
  54. data/lib/jekyll.rb +3 -1
  55. data/lib/site_template/_config.yml +1 -1
  56. data/lib/theme_template/README.md.erb +1 -3
  57. metadata +61 -13
data/lib/jekyll/page.rb CHANGED
@@ -5,9 +5,7 @@ module Jekyll
5
5
  include Convertible
6
6
 
7
7
  attr_writer :dir
8
- attr_accessor :site, :pager
9
- attr_accessor :name, :ext, :basename
10
- attr_accessor :data, :content, :output
8
+ attr_accessor :basename, :content, :data, :ext, :name, :output, :pager, :site
11
9
 
12
10
  alias_method :extname, :ext
13
11
 
@@ -144,7 +142,7 @@ module Jekyll
144
142
 
145
143
  # The path to the page source file, relative to the site source
146
144
  def relative_path
147
- @relative_path ||= PathManager.join(@dir, @name).sub(%r!\A/!, "")
145
+ @relative_path ||= PathManager.join(@dir, @name).delete_prefix("/")
148
146
  end
149
147
 
150
148
  # Obtain destination path.
@@ -36,13 +36,13 @@ module Jekyll
36
36
  def sanitized_path(base_directory, questionable_path)
37
37
  @sanitized_path ||= {}
38
38
  @sanitized_path[base_directory] ||= {}
39
- @sanitized_path[base_directory][questionable_path] ||= begin
40
- if questionable_path.nil?
41
- base_directory.freeze
42
- else
43
- sanitize_and_join(base_directory, questionable_path).freeze
44
- end
45
- end
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
46
  end
47
47
 
48
48
  private
@@ -46,7 +46,7 @@ module Jekyll
46
46
  end
47
47
 
48
48
  def self.require_from_bundler
49
- if !ENV["JEKYLL_NO_BUNDLER_REQUIRE"] && File.file?("Gemfile")
49
+ if !ENV["JEKYLL_NO_BUNDLER_REQUIRE"] && gemfile_exists?
50
50
  require "bundler"
51
51
 
52
52
  Bundler.setup
@@ -61,6 +61,13 @@ module Jekyll
61
61
  end
62
62
  end
63
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
+
64
71
  # Check whether a gem plugin is allowed to be used during this build.
65
72
  #
66
73
  # plugin_name - the name of the plugin
@@ -106,9 +113,10 @@ module Jekyll
106
113
  pagination_included = (site.config["plugins"] || []).include?("jekyll-paginate") ||
107
114
  defined?(Jekyll::Paginate)
108
115
  if site.config["paginate"] && !pagination_included
109
- Jekyll::Deprecator.deprecation_message "You appear to have pagination " \
110
- "turned on, but you haven't included the `jekyll-paginate` gem. " \
111
- "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
112
120
  end
113
121
  end
114
122
  end
@@ -14,15 +14,12 @@ module Jekyll
14
14
 
15
15
  rows = table_rows.dup
16
16
  header = rows.shift
17
- footer = rows.pop
18
17
  output = +"\n"
19
18
 
20
19
  table = Terminal::Table.new do |t|
21
20
  t << header
22
21
  t << :separator
23
22
  rows.each { |row| t << row }
24
- t << :separator
25
- t << footer
26
23
  t.style = TERMINAL_TABLE_STYLES
27
24
  t.align_column(0, :left)
28
25
  end
data/lib/jekyll/reader.rb CHANGED
@@ -16,9 +16,26 @@ module Jekyll
16
16
  read_directories
17
17
  read_included_excludes
18
18
  sort_files!
19
- @site.data = DataReader.new(site).read(site.config["data_dir"])
20
19
  CollectionReader.new(site).read
21
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)
22
39
  end
23
40
 
24
41
  # Sorts posts, pages, and static files.
@@ -4,11 +4,12 @@ module Jekyll
4
4
  class DataReader
5
5
  attr_reader :site, :content
6
6
 
7
- def initialize(site)
7
+ def initialize(site, in_source_dir: nil)
8
8
  @site = site
9
- @content = {}
9
+ @content = DataHash.new
10
10
  @entry_filter = EntryFilter.new(site)
11
- @source_dir = site.in_source_dir("/")
11
+ @in_source_dir = in_source_dir || @site.method(:in_source_dir)
12
+ @source_dir = @in_source_dir.call("/")
12
13
  end
13
14
 
14
15
  # Read all the files in <dir> and adds them to @content
@@ -18,11 +19,13 @@ module Jekyll
18
19
  # Returns @content, a Hash of the .yaml, .yml,
19
20
  # .json, and .csv files in the base directory
20
21
  def read(dir)
21
- base = site.in_source_dir(dir)
22
+ base = @in_source_dir.call(dir)
22
23
  read_data_to(base, @content)
23
24
  @content
24
25
  end
25
26
 
27
+ # rubocop:disable Metrics/AbcSize
28
+
26
29
  # Read and parse all .yaml, .yml, .json, .csv and .tsv
27
30
  # files under <dir> and add them to the <data> variable.
28
31
  #
@@ -38,17 +41,18 @@ module Jekyll
38
41
  end
39
42
 
40
43
  entries.each do |entry|
41
- path = @site.in_source_dir(dir, entry)
44
+ path = @in_source_dir.call(dir, entry)
42
45
  next if @entry_filter.symlink?(path)
43
46
 
44
47
  if File.directory?(path)
45
- read_data_to(path, data[sanitize_filename(entry)] = {})
48
+ read_data_to(path, data[sanitize_filename(entry)] = DataHash.new)
46
49
  else
47
50
  key = sanitize_filename(File.basename(entry, ".*"))
48
- data[key] = read_data_file(path)
51
+ data[key] = DataEntry.new(site, path, read_data_file(path))
49
52
  end
50
53
  end
51
54
  end
55
+ # rubocop:enable Metrics/AbcSize
52
56
 
53
57
  # Determines how to read a data file.
54
58
  #
@@ -58,14 +62,9 @@ module Jekyll
58
62
 
59
63
  case File.extname(path).downcase
60
64
  when ".csv"
61
- CSV.read(path,
62
- :headers => true,
63
- :encoding => site.config["encoding"]).map(&:to_hash)
65
+ CSV.read(path, **csv_config).map { |row| convert_row(row) }
64
66
  when ".tsv"
65
- CSV.read(path,
66
- :col_sep => "\t",
67
- :headers => true,
68
- :encoding => site.config["encoding"]).map(&:to_hash)
67
+ CSV.read(path, **tsv_config).map { |row| convert_row(row) }
69
68
  else
70
69
  SafeYAML.load_file(path)
71
70
  end
@@ -75,5 +74,43 @@ module Jekyll
75
74
  name.gsub(%r![^\w\s-]+|(?<=^|\b\s)\s+(?=$|\s?\b)!, "")
76
75
  .gsub(%r!\s+!, "_")
77
76
  end
77
+
78
+ private
79
+
80
+ # @return [Hash]
81
+ def csv_config
82
+ @csv_config ||= read_config("csv_reader")
83
+ end
84
+
85
+ # @return [Hash]
86
+ def tsv_config
87
+ @tsv_config ||= read_config("tsv_reader", { :col_sep => "\t" })
88
+ end
89
+
90
+ # @param config_key [String]
91
+ # @param overrides [Hash]
92
+ # @return [Hash]
93
+ # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/csv/rdoc/CSV.html#Converters
94
+ def read_config(config_key, overrides = {})
95
+ reader_config = config[config_key] || {}
96
+
97
+ defaults = {
98
+ :converters => reader_config.fetch("csv_converters", []).map(&:to_sym),
99
+ :headers => reader_config.fetch("headers", true),
100
+ :encoding => reader_config.fetch("encoding", config["encoding"]),
101
+ }
102
+
103
+ defaults.merge(overrides)
104
+ end
105
+
106
+ def config
107
+ @config ||= site.config
108
+ end
109
+
110
+ # @param row [Array, CSV::Row]
111
+ # @return [Array, Hash]
112
+ def convert_row(row)
113
+ row.instance_of?(CSV::Row) ? row.to_hash : row
114
+ end
78
115
  end
79
116
  end
@@ -102,15 +102,13 @@ module Jekyll
102
102
  # Returns String the converted content.
103
103
  def convert(content)
104
104
  converters.reduce(content) do |output, converter|
105
- begin
106
- converter.convert output
107
- rescue StandardError => e
108
- Jekyll.logger.error "Conversion error:",
109
- "#{converter.class} encountered an error while "\
110
- "converting '#{document.relative_path}':"
111
- Jekyll.logger.error("", e.to_s)
112
- raise e
113
- end
105
+ converter.convert output
106
+ rescue StandardError => e
107
+ Jekyll.logger.error "Conversion error:",
108
+ "#{converter.class} encountered an error while " \
109
+ "converting '#{document.relative_path}':"
110
+ Jekyll.logger.error("", e.to_s)
111
+ raise e
114
112
  end
115
113
  end
116
114
 
@@ -181,7 +179,7 @@ module Jekyll
181
179
  return unless invalid_layout?(layout)
182
180
 
183
181
  Jekyll.logger.warn "Build Warning:", "Layout '#{document.data["layout"]}' requested " \
184
- "in #{document.relative_path} does not exist."
182
+ "in #{document.relative_path} does not exist."
185
183
  end
186
184
 
187
185
  # Render layout content into document.output
data/lib/jekyll/site.rb CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  module Jekyll
4
4
  class Site
5
- attr_reader :source, :dest, :cache_dir, :config
6
- attr_accessor :layouts, :pages, :static_files, :drafts, :inclusions,
7
- :exclude, :include, :lsi, :highlighter, :permalink_style,
8
- :time, :future, :unpublished, :safe, :plugins, :limit_posts,
9
- :show_drafts, :keep_files, :baseurl, :data, :file_read_opts,
10
- :gems, :plugin_manager, :theme
5
+ attr_accessor :baseurl, :converters, :data, :drafts, :exclude,
6
+ :file_read_opts, :future, :gems, :generators, :highlighter,
7
+ :include, :inclusions, :keep_files, :layouts, :limit_posts,
8
+ :lsi, :pages, :permalink_style, :plugin_manager, :plugins,
9
+ :reader, :safe, :show_drafts, :static_files, :theme, :time,
10
+ :unpublished
11
11
 
12
- attr_accessor :converters, :generators, :reader
13
- attr_reader :regenerator, :liquid_renderer, :includes_load_paths, :filter_cache, :profiler
12
+ attr_reader :cache_dir, :config, :dest, :filter_cache, :includes_load_paths,
13
+ :liquid_renderer, :profiler, :regenerator, :source
14
14
 
15
15
  # Public: Initialize a new Site.
16
16
  #
@@ -304,10 +304,10 @@ module Jekyll
304
304
  # klass - The Class of the Converter to fetch.
305
305
  def find_converter_instance(klass)
306
306
  @find_converter_instance ||= {}
307
- @find_converter_instance[klass] ||= begin
308
- converters.find { |converter| converter.instance_of?(klass) } || \
309
- raise("No Converters found for #{klass}")
310
- end
307
+ @find_converter_instance[klass] ||= converters.find do |converter|
308
+ converter.instance_of?(klass)
309
+ end || \
310
+ raise("No Converters found for #{klass}")
311
311
  end
312
312
 
313
313
  # klass - class or module containing the subclasses.
@@ -328,11 +328,11 @@ module Jekyll
328
328
  # Returns
329
329
  def relative_permalinks_are_deprecated
330
330
  if config["relative_permalinks"]
331
- Jekyll.logger.abort_with "Since v3.0, permalinks for pages" \
332
- " in subfolders must be relative to the" \
333
- " site source directory, not the parent" \
334
- " directory. Check https://jekyllrb.com/docs/upgrading/"\
335
- " for more info."
331
+ Jekyll.logger.abort_with "Since v3.0, permalinks for pages " \
332
+ "in subfolders must be relative to the " \
333
+ "site source directory, not the parent " \
334
+ "directory. Check https://jekyllrb.com/docs/upgrading/ " \
335
+ "for more info."
336
336
  end
337
337
  end
338
338
 
@@ -343,6 +343,13 @@ module Jekyll
343
343
  documents.select(&:write?)
344
344
  end
345
345
 
346
+ # Get the to be written static files
347
+ #
348
+ # Returns an Array of StaticFiles which should be written
349
+ def static_files_to_write
350
+ static_files.select(&:write?)
351
+ end
352
+
346
353
  # Get all the documents
347
354
  #
348
355
  # Returns an Array of all Documents
@@ -353,9 +360,13 @@ module Jekyll
353
360
  end
354
361
 
355
362
  def each_site_file
356
- %w(pages static_files docs_to_write).each do |type|
363
+ seen_files = []
364
+ %w(pages static_files_to_write docs_to_write).each do |type|
357
365
  send(type).each do |item|
366
+ next if seen_files.include?(item)
367
+
358
368
  yield item
369
+ seen_files << item
359
370
  end
360
371
  end
361
372
  end
@@ -469,7 +480,11 @@ module Jekyll
469
480
  theme_config.delete_if { |key, _| Configuration::DEFAULTS.key?(key) }
470
481
 
471
482
  # Override theme_config with existing config and return the result.
483
+ # Additionally ensure we return a `Jekyll::Configuration` instance instead of a Hash.
472
484
  Utils.deep_merge_hashes(theme_config, config)
485
+ .each_with_object(Jekyll::Configuration.new) do |(key, value), conf|
486
+ conf[key] = value
487
+ end
473
488
  end
474
489
 
475
490
  # Limits the current posts; removes the posts which exceed the limit_posts
@@ -490,10 +505,26 @@ module Jekyll
490
505
  @site_cleaner ||= Cleaner.new(self)
491
506
  end
492
507
 
508
+ def hide_cache_dir_from_git
509
+ @cache_gitignore_path ||= in_source_dir(config["cache_dir"], ".gitignore")
510
+ return if File.exist?(@cache_gitignore_path)
511
+
512
+ cache_dir_path = in_source_dir(config["cache_dir"])
513
+ FileUtils.mkdir_p(cache_dir_path) unless File.directory?(cache_dir_path)
514
+
515
+ File.open(@cache_gitignore_path, "wb") do |file|
516
+ file.puts("# ignore everything in this directory\n*")
517
+ end
518
+ end
519
+
493
520
  # Disable Marshaling cache to disk in Safe Mode
494
521
  def configure_cache
495
522
  Jekyll::Cache.cache_dir = in_source_dir(config["cache_dir"], "Jekyll/Cache")
496
- Jekyll::Cache.disable_disk_cache! if safe || config["disable_disk_cache"]
523
+ if safe || config["disable_disk_cache"]
524
+ Jekyll::Cache.disable_disk_cache!
525
+ else
526
+ hide_cache_dir_from_git
527
+ end
497
528
  end
498
529
 
499
530
  def configure_plugins
@@ -509,8 +540,8 @@ module Jekyll
509
540
  if config["theme"].is_a?(String)
510
541
  Jekyll::Theme.new(config["theme"])
511
542
  else
512
- Jekyll.logger.warn "Theme:", "value of 'theme' in config should be " \
513
- "String to use gem-based themes, but got #{config["theme"].class}"
543
+ Jekyll.logger.warn "Theme:", "value of 'theme' in config should be String to use " \
544
+ "gem-based themes, but got #{config["theme"].class}"
514
545
  nil
515
546
  end
516
547
  end
@@ -39,14 +39,11 @@ module Jekyll
39
39
 
40
40
  # Returns source file path.
41
41
  def path
42
- @path ||= begin
43
- # Static file is from a collection inside custom collections directory
44
- if !@collection.nil? && !@site.config["collections_dir"].empty?
45
- File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact)
46
- else
47
- File.join(*[@base, @dir, @name].compact)
48
- end
49
- end
42
+ @path ||= if !@collection.nil? && !@site.config["collections_dir"].empty?
43
+ File.join(*[@base, @site.config["collections_dir"], @dir, @name].compact)
44
+ else
45
+ File.join(*[@base, @dir, @name].compact)
46
+ end
50
47
  end
51
48
 
52
49
  # Obtain destination path.
@@ -159,7 +156,7 @@ module Jekyll
159
156
 
160
157
  # Applies a similar URL-building technique as Jekyll::Document that takes
161
158
  # the collection's URL template into account. The default URL template can
162
- # be overriden in the collection's configuration in _config.yml.
159
+ # be overridden in the collection's configuration in _config.yml.
163
160
  def url
164
161
  @url ||= begin
165
162
  base = if @collection.nil?
@@ -80,13 +80,17 @@ module Jekyll
80
80
 
81
81
  def render_rouge(code)
82
82
  require "rouge"
83
- formatter = ::Rouge::Formatters::HTMLLegacy.new(
84
- :line_numbers => @highlight_options[:linenos],
85
- :wrap => false,
86
- :css_class => "highlight",
87
- :gutter_class => "gutter",
88
- :code_class => "code"
89
- )
83
+ formatter = ::Rouge::Formatters::HTML.new
84
+ if @highlight_options[:linenos]
85
+ formatter = ::Rouge::Formatters::HTMLTable.new(
86
+ formatter,
87
+ {
88
+ :css_class => "highlight",
89
+ :gutter_class => "gutter",
90
+ :code_class => "code",
91
+ }
92
+ )
93
+ end
90
94
  lexer = ::Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText
91
95
  formatter.format(lexer.lex(code))
92
96
  end
@@ -100,8 +104,8 @@ module Jekyll
100
104
  "class=\"language-#{@lang.to_s.tr("+", "-")}\"",
101
105
  "data-lang=\"#{@lang}\"",
102
106
  ].join(" ")
103
- "<figure class=\"highlight\"><pre><code #{code_attributes}>"\
104
- "#{code.chomp}</code></pre></figure>"
107
+ "<figure class=\"highlight\"><pre><code #{code_attributes}>" \
108
+ "#{code.chomp}</code></pre></figure>"
105
109
  end
106
110
  end
107
111
  end
@@ -13,7 +13,7 @@ module Jekyll
13
13
  !mx.freeze
14
14
 
15
15
  FULL_VALID_SYNTAX = %r!\A\s*(?:#{VALID_SYNTAX}(?=\s|\z)\s*)*\z!.freeze
16
- VALID_FILENAME_CHARS = %r!^[\w/.-]+$!.freeze
16
+ VALID_FILENAME_CHARS = %r!^[\w/.\-()+~\#@]+$!.freeze
17
17
  INVALID_SEQUENCES = %r![./]{2,}!.freeze
18
18
 
19
19
  def initialize(tag_name, markup, tokens)
@@ -179,8 +179,8 @@ module Jekyll
179
179
  private
180
180
 
181
181
  def could_not_locate_message(file, includes_dirs, safe)
182
- message = "Could not locate the included file '#{file}' in any of "\
183
- "#{includes_dirs}. Ensure it exists in one of those directories and"
182
+ message = "Could not locate the included file '#{file}' in any of #{includes_dirs}. " \
183
+ "Ensure it exists in one of those directories and"
184
184
  message + if safe
185
185
  " is not a symlink as those are not allowed in safe mode."
186
186
  else
@@ -265,7 +265,7 @@ module Jekyll
265
265
  def resource_path(page, site)
266
266
  path = page["path"]
267
267
  path = File.join(site.config["collections_dir"], path) if page["collection"]
268
- path.sub(%r!/#excerpt\z!, "")
268
+ path.delete_suffix("/#excerpt")
269
269
  end
270
270
  end
271
271
  end
@@ -86,11 +86,11 @@ module Jekyll
86
86
  site.posts.docs.each do |document|
87
87
  next unless @post.deprecated_equality document
88
88
 
89
- Jekyll::Deprecator.deprecation_message "A call to "\
90
- "'{% post_url #{@post.name} %}' did not match " \
91
- "a post using the new matching method of checking name " \
92
- "(path-date-slug) equality. Please make sure that you " \
93
- "change this tag to match the post's name exactly."
89
+ Jekyll::Deprecator.deprecation_message(
90
+ "A call to '{% post_url #{@post.name} %}' did not match a post using the new " \
91
+ "matching method of checking name (path-date-slug) equality. Please make sure " \
92
+ "that you change this tag to match the post's name exactly."
93
+ )
94
94
  return relative_url(document)
95
95
  end
96
96
 
data/lib/jekyll/theme.rb CHANGED
@@ -18,8 +18,8 @@ module Jekyll
18
18
  # Otherwise, Jekyll.sanitized path with prepend the unresolved root
19
19
  @root ||= File.realpath(gemspec.full_gem_path)
20
20
  rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
21
- raise "Path #{gemspec.full_gem_path} does not exist, is not accessible "\
22
- "or includes a symbolic link loop"
21
+ raise "Path #{gemspec.full_gem_path} does not exist, is not accessible or includes " \
22
+ "a symbolic link loop"
23
23
  end
24
24
 
25
25
  # The name of theme directory
@@ -43,6 +43,10 @@ module Jekyll
43
43
  @assets_path ||= path_for "assets"
44
44
  end
45
45
 
46
+ def data_path
47
+ @data_path ||= path_for "_data"
48
+ end
49
+
46
50
  def runtime_dependencies
47
51
  gemspec.runtime_dependencies
48
52
  end
@@ -3,7 +3,7 @@
3
3
  module Jekyll
4
4
  class ThemeBuilder
5
5
  SCAFFOLD_DIRECTORIES = %w(
6
- assets _layouts _includes _sass
6
+ assets _data _layouts _includes _sass
7
7
  ).freeze
8
8
 
9
9
  attr_reader :name, :path, :code_of_conduct
data/lib/jekyll/url.rb CHANGED
@@ -100,7 +100,7 @@ module Jekyll
100
100
  winner = pool.find { |key| @placeholders.key?(key) }
101
101
  if winner.nil?
102
102
  raise NoMethodError,
103
- "The URL template doesn't have #{pool.join(" or ")} keys. "\
103
+ "The URL template doesn't have #{pool.join(" or ")} keys. " \
104
104
  "Check your permalink template!"
105
105
  end
106
106
 
@@ -1,4 +1,4 @@
1
- # Frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Jekyll
4
4
  module Utils
@@ -11,64 +11,35 @@ module Jekyll
11
11
  # timezone - the IANA Time Zone specified in "_config.yml"
12
12
  #
13
13
  # Returns a string that ultimately re-defines ENV["TZ"] in Windows
14
- def calculate(timezone)
14
+ def calculate(timezone, now = Time.now)
15
15
  External.require_with_graceful_fail("tzinfo") unless defined?(TZInfo)
16
16
  tz = TZInfo::Timezone.get(timezone)
17
- difference = Time.now.to_i - tz.now.to_i
17
+
18
+ #
19
+ # Use period_for_utc and utc_total_offset instead of
20
+ # period_for and observed_utc_offset for compatibility with tzinfo v1.
21
+ offset = tz.period_for_utc(now.getutc).utc_total_offset
22
+
18
23
  #
19
24
  # POSIX style definition reverses the offset sign.
20
25
  # e.g. Eastern Standard Time (EST) that is 5Hrs. to the 'west' of Prime Meridian
21
26
  # is denoted as:
22
27
  # EST+5 (or) EST+05:00
23
- # Reference: http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
24
- sign = difference.negative? ? "-" : "+"
25
- offset = sign == "-" ? "+" : "-" unless difference.zero?
26
- #
27
- # convert the difference (in seconds) to hours, as a rational number, and perform
28
- # a modulo operation on it.
29
- modulo = modulo_of(rational_hour(difference))
28
+ # Reference: https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
29
+ sign = offset.positive? ? "-" : "+"
30
+
31
+ rational_hours = offset.abs.to_r / 3600
32
+ hours = rational_hours.to_i
33
+ minutes = ((rational_hours - hours) * 60).to_i
34
+
30
35
  #
31
- # Format the hour as a two-digit number.
32
- # Establish the minutes based on modulo expression.
33
- hh = format("%<hour>02d", :hour => absolute_hour(difference).ceil)
34
- mm = modulo.zero? ? "00" : "30"
36
+ # Format the hours and minutes as two-digit numbers.
37
+ time = format("%<hours>02d:%<minutes>02d", :hours => hours, :minutes => minutes)
35
38
 
36
- Jekyll.logger.debug "Timezone:", "#{timezone} #{offset}#{hh}:#{mm}"
39
+ Jekyll.logger.debug "Timezone:", "#{timezone} #{sign}#{time}"
37
40
  #
38
41
  # Note: The 3-letter-word below doesn't have a particular significance.
39
- "WTZ#{sign}#{hh}:#{mm}"
40
- end
41
-
42
- private
43
-
44
- # Private: Convert given seconds to an hour as a rational number.
45
- #
46
- # seconds - supplied as an integer, it is converted to a rational number.
47
- # 3600 - no. of seconds in an hour.
48
- #
49
- # Returns a rational number.
50
- def rational_hour(seconds)
51
- seconds.to_r / 3600
52
- end
53
-
54
- # Private: Convert given seconds to an hour as an absolute number.
55
- #
56
- # seconds - supplied as an integer, it is converted to its absolute.
57
- # 3600 - no. of seconds in an hour.
58
- #
59
- # Returns an integer.
60
- def absolute_hour(seconds)
61
- seconds.abs / 3600
62
- end
63
-
64
- # Private: Perform a modulo operation on a given fraction.
65
- #
66
- # fraction - supplied as a rational number, its numerator is divided
67
- # by its denominator and the remainder returned.
68
- #
69
- # Returns an integer.
70
- def modulo_of(fraction)
71
- fraction.numerator % fraction.denominator
42
+ "WTZ#{sign}#{time}"
72
43
  end
73
44
  end
74
45
  end