jekyll 3.9.1 → 4.0.0.pre.alpha1

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +27 -50
  3. data/LICENSE +1 -1
  4. data/README.markdown +46 -17
  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/main.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.rb +5 -0
  11. data/lib/jekyll/cache.rb +183 -0
  12. data/lib/jekyll/cleaner.rb +2 -1
  13. data/lib/jekyll/collection.rb +78 -8
  14. data/lib/jekyll/command.rb +31 -6
  15. data/lib/jekyll/commands/build.rb +11 -20
  16. data/lib/jekyll/commands/clean.rb +2 -0
  17. data/lib/jekyll/commands/doctor.rb +15 -8
  18. data/lib/jekyll/commands/help.rb +1 -1
  19. data/lib/jekyll/commands/new.rb +37 -39
  20. data/lib/jekyll/commands/new_theme.rb +30 -28
  21. data/lib/jekyll/commands/serve.rb +46 -80
  22. data/lib/jekyll/commands/serve/live_reload_reactor.rb +6 -10
  23. data/lib/jekyll/commands/serve/servlet.rb +9 -11
  24. data/lib/jekyll/configuration.rb +26 -26
  25. data/lib/jekyll/converters/identity.rb +18 -0
  26. data/lib/jekyll/converters/markdown.rb +49 -40
  27. data/lib/jekyll/converters/markdown/kramdown_parser.rb +1 -10
  28. data/lib/jekyll/converters/smartypants.rb +34 -14
  29. data/lib/jekyll/convertible.rb +11 -13
  30. data/lib/jekyll/deprecator.rb +1 -3
  31. data/lib/jekyll/document.rb +44 -41
  32. data/lib/jekyll/drops/collection_drop.rb +2 -3
  33. data/lib/jekyll/drops/document_drop.rb +2 -1
  34. data/lib/jekyll/drops/drop.rb +3 -6
  35. data/lib/jekyll/drops/excerpt_drop.rb +4 -0
  36. data/lib/jekyll/drops/site_drop.rb +4 -13
  37. data/lib/jekyll/drops/unified_payload_drop.rb +1 -0
  38. data/lib/jekyll/drops/url_drop.rb +1 -0
  39. data/lib/jekyll/entry_filter.rb +2 -1
  40. data/lib/jekyll/excerpt.rb +45 -34
  41. data/lib/jekyll/external.rb +10 -5
  42. data/lib/jekyll/filters.rb +72 -31
  43. data/lib/jekyll/filters/date_filters.rb +6 -3
  44. data/lib/jekyll/filters/grouping_filters.rb +1 -2
  45. data/lib/jekyll/filters/url_filters.rb +6 -1
  46. data/lib/jekyll/frontmatter_defaults.rb +35 -19
  47. data/lib/jekyll/hooks.rb +2 -3
  48. data/lib/jekyll/liquid_extensions.rb +0 -2
  49. data/lib/jekyll/liquid_renderer.rb +13 -1
  50. data/lib/jekyll/liquid_renderer/file.rb +14 -3
  51. data/lib/jekyll/liquid_renderer/table.rb +67 -65
  52. data/lib/jekyll/log_adapter.rb +5 -1
  53. data/lib/jekyll/page.rb +10 -11
  54. data/lib/jekyll/page_without_a_file.rb +0 -4
  55. data/lib/jekyll/plugin.rb +5 -11
  56. data/lib/jekyll/plugin_manager.rb +2 -0
  57. data/lib/jekyll/reader.rb +38 -8
  58. data/lib/jekyll/readers/data_reader.rb +7 -9
  59. data/lib/jekyll/readers/layout_reader.rb +2 -12
  60. data/lib/jekyll/readers/post_reader.rb +29 -17
  61. data/lib/jekyll/readers/static_file_reader.rb +1 -1
  62. data/lib/jekyll/readers/theme_assets_reader.rb +7 -5
  63. data/lib/jekyll/regenerator.rb +4 -12
  64. data/lib/jekyll/renderer.rb +14 -25
  65. data/lib/jekyll/site.rb +78 -34
  66. data/lib/jekyll/static_file.rb +47 -11
  67. data/lib/jekyll/stevenson.rb +2 -3
  68. data/lib/jekyll/tags/highlight.rb +22 -52
  69. data/lib/jekyll/tags/include.rb +22 -38
  70. data/lib/jekyll/tags/link.rb +11 -7
  71. data/lib/jekyll/tags/post_url.rb +17 -16
  72. data/lib/jekyll/theme.rb +12 -23
  73. data/lib/jekyll/theme_builder.rb +91 -89
  74. data/lib/jekyll/url.rb +3 -2
  75. data/lib/jekyll/utils.rb +5 -4
  76. data/lib/jekyll/utils/ansi.rb +1 -1
  77. data/lib/jekyll/utils/exec.rb +0 -1
  78. data/lib/jekyll/utils/internet.rb +2 -4
  79. data/lib/jekyll/utils/platforms.rb +8 -8
  80. data/lib/jekyll/utils/thread_event.rb +1 -5
  81. data/lib/jekyll/utils/win_tz.rb +1 -1
  82. data/lib/jekyll/version.rb +1 -1
  83. data/lib/site_template/.gitignore +2 -0
  84. data/lib/site_template/404.html +1 -0
  85. data/lib/site_template/_config.yml +17 -5
  86. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
  87. data/lib/site_template/{about.md → about.markdown} +0 -0
  88. data/lib/site_template/{index.md → index.markdown} +0 -0
  89. data/lib/theme_template/gitignore.erb +1 -0
  90. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -0
  91. metadata +85 -51
  92. data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
  93. data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
  94. data/lib/jekyll/utils/rouge.rb +0 -22
@@ -41,16 +41,15 @@ module Jekyll
41
41
  end
42
42
 
43
43
  private
44
+
44
45
  def parse_expression(str)
45
46
  Liquid::Variable.new(str, Liquid::ParseContext.new)
46
47
  end
47
48
 
48
- private
49
49
  def groupable?(element)
50
50
  element.respond_to?(:group_by)
51
51
  end
52
52
 
53
- private
54
53
  def grouped_array(groups)
55
54
  groups.each_with_object([]) do |item, array|
56
55
  array << {
@@ -10,10 +10,13 @@ module Jekyll
10
10
  # Returns the absolute URL as a String.
11
11
  def absolute_url(input)
12
12
  return if input.nil?
13
+
13
14
  input = input.url if input.respond_to?(:url)
14
15
  return input if Addressable::URI.parse(input.to_s).absolute?
16
+
15
17
  site = @context.registers[:site]
16
18
  return relative_url(input) if site.config["url"].nil?
19
+
17
20
  Addressable::URI.parse(
18
21
  site.config["url"].to_s + relative_url(input)
19
22
  ).normalize.to_s
@@ -27,6 +30,7 @@ module Jekyll
27
30
  # Returns a URL relative to the domain root as a String.
28
31
  def relative_url(input)
29
32
  return if input.nil?
33
+
30
34
  input = input.url if input.respond_to?(:url)
31
35
  return input if Addressable::URI.parse(input.to_s).absolute?
32
36
 
@@ -43,6 +47,7 @@ module Jekyll
43
47
  # Returns a URL with the trailing `/index.html` removed
44
48
  def strip_index(input)
45
49
  return if input.nil? || input.to_s.empty?
50
+
46
51
  input.sub(%r!/index\.html?$!, "/")
47
52
  end
48
53
 
@@ -55,9 +60,9 @@ module Jekyll
55
60
 
56
61
  def ensure_leading_slash(input)
57
62
  return input if input.nil? || input.empty? || input.start_with?("/")
63
+
58
64
  "/#{input}"
59
65
  end
60
-
61
66
  end
62
67
  end
63
68
  end
@@ -10,6 +10,11 @@ module Jekyll
10
10
  # Initializes a new instance.
11
11
  def initialize(site)
12
12
  @site = site
13
+ reset
14
+ end
15
+
16
+ def reset
17
+ @glob_cache = {}
13
18
  end
14
19
 
15
20
  def update_deprecated_types(set)
@@ -36,6 +41,7 @@ module Jekyll
36
41
  def ensure_time!(set)
37
42
  return set unless set.key?("values") && set["values"].key?("date")
38
43
  return set if set["values"]["date"].is_a?(Time)
44
+
39
45
  set["values"]["date"] = Utils.parse_date(
40
46
  set["values"]["date"],
41
47
  "An invalid date format was found in a front-matter default set: #{set}"
@@ -92,39 +98,44 @@ module Jekyll
92
98
  # path - the path to check for
93
99
  # type - the type (:post, :page or :draft) to check for
94
100
  #
95
- # Returns true if the scope applies to the given path and type
101
+ # Returns true if the scope applies to the given type and path
96
102
  def applies?(scope, path, type)
97
- applies_path?(scope, path) && applies_type?(scope, type)
103
+ applies_type?(scope, type) && applies_path?(scope, path)
98
104
  end
99
105
 
100
- # rubocop:disable Metrics/AbcSize
101
106
  def applies_path?(scope, path)
102
107
  return true if !scope.key?("path") || scope["path"].empty?
103
108
 
104
109
  sanitized_path = Pathname.new(sanitize_path(path))
105
- site_path = Pathname.new(@site.source)
106
110
  rel_scope_path = Pathname.new(scope["path"])
107
- abs_scope_path = File.join(@site.source, rel_scope_path)
108
111
 
109
112
  if scope["path"].to_s.include?("*")
110
- Dir.glob(abs_scope_path).each do |scope_path|
111
- scope_path = Pathname.new(scope_path).relative_path_from(site_path)
112
- scope_path = strip_collections_dir(scope_path)
113
- Jekyll.logger.debug "Globbed Scope Path:", scope_path
114
- return true if path_is_subpath?(sanitized_path, scope_path)
115
- end
116
- false
113
+ glob_scope(sanitized_path, rel_scope_path)
117
114
  else
118
115
  path_is_subpath?(sanitized_path, strip_collections_dir(rel_scope_path))
119
116
  end
120
117
  end
121
- # rubocop:enable Metrics/AbcSize
118
+
119
+ def glob_scope(sanitized_path, rel_scope_path)
120
+ site_source = Pathname.new(@site.source)
121
+ abs_scope_path = site_source.join(rel_scope_path).to_s
122
+
123
+ glob_cache(abs_scope_path).each do |scope_path|
124
+ scope_path = Pathname.new(scope_path).relative_path_from(site_source)
125
+ scope_path = strip_collections_dir(scope_path)
126
+ Jekyll.logger.debug "Globbed Scope Path:", scope_path
127
+ return true if path_is_subpath?(sanitized_path, scope_path)
128
+ end
129
+ false
130
+ end
131
+
132
+ def glob_cache(path)
133
+ @glob_cache[path] ||= Dir.glob(path)
134
+ end
122
135
 
123
136
  def path_is_subpath?(path, parent_path)
124
137
  path.ascend do |ascended_path|
125
- if ascended_path.to_s == parent_path.to_s
126
- return true
127
- end
138
+ return true if ascended_path.to_s == parent_path.to_s
128
139
  end
129
140
 
130
141
  false
@@ -134,6 +145,7 @@ module Jekyll
134
145
  collections_dir = @site.config["collections_dir"]
135
146
  slashed_coll_dir = "#{collections_dir}/"
136
147
  return path if collections_dir.empty? || !path.to_s.start_with?(slashed_coll_dir)
148
+
137
149
  path.sub(slashed_coll_dir, "")
138
150
  end
139
151
 
@@ -188,8 +200,12 @@ module Jekyll
188
200
  #
189
201
  # Returns an array of hashes
190
202
  def matching_sets(path, type)
191
- valid_sets.select do |set|
192
- !set.key?("scope") || applies?(set["scope"], path, type)
203
+ @matched_set_cache ||= {}
204
+ @matched_set_cache[path] ||= {}
205
+ @matched_set_cache[path][type] ||= begin
206
+ valid_sets.select do |set|
207
+ !set.key?("scope") || applies?(set["scope"], path, type)
208
+ end
193
209
  end
194
210
  end
195
211
 
@@ -216,7 +232,7 @@ module Jekyll
216
232
 
217
233
  # Sanitizes the given path by removing a leading and adding a trailing slash
218
234
 
219
- SANITIZATION_REGEX = %r!\A/|(?<=[^/])\z!
235
+ SANITIZATION_REGEX = %r!\A/|(?<=[^/])\z!.freeze
220
236
 
221
237
  def sanitize_path(path)
222
238
  if path.nil? || path.empty?
data/lib/jekyll/hooks.rb CHANGED
@@ -60,6 +60,7 @@ module Jekyll
60
60
  # Ensure the priority is a Fixnum
61
61
  def self.priority_value(priority)
62
62
  return priority if priority.is_a?(Integer)
63
+
63
64
  PRIORITY_MAP[priority] || DEFAULT_PRIORITY
64
65
  end
65
66
 
@@ -77,9 +78,7 @@ module Jekyll
77
78
  "following hooks #{@registry[owner].keys.inspect}"
78
79
  end
79
80
 
80
- unless block.respond_to? :call
81
- raise Uncallable, "Hooks must respond to :call"
82
- end
81
+ raise Uncallable, "Hooks must respond to :call" unless block.respond_to? :call
83
82
 
84
83
  insert_hook owner, event, priority, &block
85
84
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Jekyll
4
4
  module LiquidExtensions
5
-
6
5
  # Lookup a Liquid variable in the given context.
7
6
  #
8
7
  # context - the Liquid context in question.
@@ -19,6 +18,5 @@ module Jekyll
19
18
 
20
19
  lookup || variable
21
20
  end
22
-
23
21
  end
24
22
  end
@@ -18,6 +18,7 @@ module Jekyll
18
18
 
19
19
  def reset
20
20
  @stats = {}
21
+ @cache = {}
21
22
  end
22
23
 
23
24
  def file(filename)
@@ -30,7 +31,6 @@ module Jekyll
30
31
  end
31
32
  LiquidRenderer::File.new(self, filename).tap do
32
33
  @stats[filename] ||= new_profile_hash
33
- @stats[filename][:count] += 1
34
34
  end
35
35
  end
36
36
 
@@ -42,6 +42,10 @@ module Jekyll
42
42
  @stats[filename][:time] += time
43
43
  end
44
44
 
45
+ def increment_count(filename)
46
+ @stats[filename][:count] += 1
47
+ end
48
+
45
49
  def stats_table(num_of_rows = 50)
46
50
  LiquidRenderer::Table.new(@stats).to_s(num_of_rows)
47
51
  end
@@ -50,6 +54,14 @@ module Jekyll
50
54
  "#{error.message} in #{path}"
51
55
  end
52
56
 
57
+ # A persistent cache to store and retrieve parsed templates based on the filename
58
+ # via `LiquidRenderer::File#parse`
59
+ #
60
+ # It is emptied when `self.reset` is called.
61
+ def cache
62
+ @cache ||= {}
63
+ end
64
+
53
65
  private
54
66
 
55
67
  def filename_regex
@@ -10,8 +10,9 @@ module Jekyll
10
10
 
11
11
  def parse(content)
12
12
  measure_time do
13
- @template = Liquid::Template.parse(content, :line_numbers => true)
13
+ @renderer.cache[@filename] ||= Liquid::Template.parse(content, :line_numbers => true)
14
14
  end
15
+ @template = @renderer.cache[@filename]
15
16
 
16
17
  self
17
18
  end
@@ -19,15 +20,20 @@ module Jekyll
19
20
  def render(*args)
20
21
  measure_time do
21
22
  measure_bytes do
22
- @template.render(*args)
23
+ measure_counts do
24
+ @template.render(*args)
25
+ end
23
26
  end
24
27
  end
25
28
  end
26
29
 
30
+ # This method simply 'rethrows any error' before attempting to render the template.
27
31
  def render!(*args)
28
32
  measure_time do
29
33
  measure_bytes do
30
- @template.render!(*args)
34
+ measure_counts do
35
+ @template.render!(*args)
36
+ end
31
37
  end
32
38
  end
33
39
  end
@@ -38,6 +44,11 @@ module Jekyll
38
44
 
39
45
  private
40
46
 
47
+ def measure_counts
48
+ @renderer.increment_count(@filename)
49
+ yield
50
+ end
51
+
41
52
  def measure_bytes
42
53
  yield.tap do |str|
43
54
  @renderer.increment_bytes(@filename, str.bytesize)
@@ -1,96 +1,98 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jekyll
4
- class LiquidRenderer::Table
5
- def initialize(stats)
6
- @stats = stats
7
- end
4
+ class LiquidRenderer
5
+ class Table
6
+ def initialize(stats)
7
+ @stats = stats
8
+ end
8
9
 
9
- def to_s(num_of_rows = 50)
10
- data = data_for_table(num_of_rows)
11
- widths = table_widths(data)
12
- generate_table(data, widths)
13
- end
10
+ def to_s(num_of_rows = 50)
11
+ data = data_for_table(num_of_rows)
12
+ widths = table_widths(data)
13
+ generate_table(data, widths)
14
+ end
14
15
 
15
- private
16
+ private
16
17
 
17
- def generate_table(data, widths)
18
- str = String.new("\n")
18
+ def generate_table(data, widths)
19
+ str = +"\n"
19
20
 
20
- table_head = data.shift
21
- str << generate_row(table_head, widths)
22
- str << generate_table_head_border(table_head, widths)
21
+ table_head = data.shift
22
+ str << generate_row(table_head, widths)
23
+ str << generate_table_head_border(table_head, widths)
23
24
 
24
- data.each do |row_data|
25
- str << generate_row(row_data, widths)
25
+ data.each do |row_data|
26
+ str << generate_row(row_data, widths)
27
+ end
28
+
29
+ str << "\n"
30
+ str
26
31
  end
27
32
 
28
- str << "\n"
29
- str
30
- end
33
+ def generate_table_head_border(row_data, widths)
34
+ str = +""
31
35
 
32
- def generate_table_head_border(row_data, widths)
33
- str = String.new("")
36
+ row_data.each_index do |cell_index|
37
+ str << "-" * widths[cell_index]
38
+ str << "-+-" unless cell_index == row_data.length - 1
39
+ end
34
40
 
35
- row_data.each_index do |cell_index|
36
- str << "-" * widths[cell_index]
37
- str << "-+-" unless cell_index == row_data.length - 1
41
+ str << "\n"
42
+ str
38
43
  end
39
44
 
40
- str << "\n"
41
- str
42
- end
45
+ def generate_row(row_data, widths)
46
+ str = +""
43
47
 
44
- def generate_row(row_data, widths)
45
- str = String.new("")
48
+ row_data.each_with_index do |cell_data, cell_index|
49
+ str << if cell_index.zero?
50
+ cell_data.ljust(widths[cell_index], " ")
51
+ else
52
+ cell_data.rjust(widths[cell_index], " ")
53
+ end
46
54
 
47
- row_data.each_with_index do |cell_data, cell_index|
48
- str << if cell_index.zero?
49
- cell_data.ljust(widths[cell_index], " ")
50
- else
51
- cell_data.rjust(widths[cell_index], " ")
52
- end
55
+ str << " | " unless cell_index == row_data.length - 1
56
+ end
53
57
 
54
- str << " | " unless cell_index == row_data.length - 1
58
+ str << "\n"
59
+ str
55
60
  end
56
61
 
57
- str << "\n"
58
- str
59
- end
60
-
61
- def table_widths(data)
62
- widths = []
62
+ def table_widths(data)
63
+ widths = []
63
64
 
64
- data.each do |row|
65
- row.each_with_index do |cell, index|
66
- widths[index] = [cell.length, widths[index]].compact.max
65
+ data.each do |row|
66
+ row.each_with_index do |cell, index|
67
+ widths[index] = [cell.length, widths[index]].compact.max
68
+ end
67
69
  end
70
+
71
+ widths
68
72
  end
69
73
 
70
- widths
71
- end
74
+ def data_for_table(num_of_rows)
75
+ sorted = @stats.sort_by { |_, file_stats| -file_stats[:time] }
76
+ sorted = sorted.slice(0, num_of_rows)
72
77
 
73
- def data_for_table(num_of_rows)
74
- sorted = @stats.sort_by { |_, file_stats| -file_stats[:time] }
75
- sorted = sorted.slice(0, num_of_rows)
78
+ table = [%w(Filename Count Bytes Time)]
76
79
 
77
- table = [%w(Filename Count Bytes Time)]
80
+ sorted.each do |filename, file_stats|
81
+ row = []
82
+ row << filename
83
+ row << file_stats[:count].to_s
84
+ row << format_bytes(file_stats[:bytes])
85
+ row << format("%.3f", file_stats[:time])
86
+ table << row
87
+ end
78
88
 
79
- sorted.each do |filename, file_stats|
80
- row = []
81
- row << filename
82
- row << file_stats[:count].to_s
83
- row << format_bytes(file_stats[:bytes])
84
- row << format("%.3f", file_stats[:time])
85
- table << row
89
+ table
86
90
  end
87
91
 
88
- table
89
- end
90
-
91
- def format_bytes(bytes)
92
- bytes /= 1024.0
93
- format("%.2fK", bytes)
92
+ def format_bytes(bytes)
93
+ bytes /= 1024.0
94
+ format("%.2fK", bytes)
95
+ end
94
96
  end
95
97
  end
96
98
  end