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
data/lib/jekyll/utils.rb CHANGED
@@ -7,25 +7,17 @@ module Jekyll
7
7
  autoload :Exec, "jekyll/utils/exec"
8
8
  autoload :Internet, "jekyll/utils/internet"
9
9
  autoload :Platforms, "jekyll/utils/platforms"
10
- autoload :Rouge, "jekyll/utils/rouge"
11
10
  autoload :ThreadEvent, "jekyll/utils/thread_event"
12
11
  autoload :WinTZ, "jekyll/utils/win_tz"
13
12
 
14
13
  # Constants for use in #slugify
15
14
  SLUGIFY_MODES = %w(raw default pretty ascii latin).freeze
16
15
  SLUGIFY_RAW_REGEXP = Regexp.new('\\s+').freeze
17
- SLUGIFY_DEFAULT_REGEXP = Regexp.new("[^[:alnum:]]+").freeze
18
- SLUGIFY_PRETTY_REGEXP = Regexp.new("[^[:alnum:]._~!$&'()+,;=@]+").freeze
16
+ SLUGIFY_DEFAULT_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}]+").freeze
17
+ SLUGIFY_PRETTY_REGEXP = Regexp.new("[^\\p{M}\\p{L}\\p{Nd}._~!$&'()+,;=@]+").freeze
19
18
  SLUGIFY_ASCII_REGEXP = Regexp.new("[^[A-Za-z0-9]]+").freeze
20
19
 
21
- # Takes an indented string and removes the preceding spaces on each line
22
-
23
- def strip_heredoc(str)
24
- str.gsub(%r!^[ \t]{#{(str.scan(%r!^[ \t]*(?=\S)!).min || "").size}}!, "")
25
- end
26
-
27
20
  # Takes a slug and turns it into a simple title.
28
-
29
21
  def titleize_slug(slug)
30
22
  slug.split("-").map!(&:capitalize).join(" ")
31
23
  end
@@ -76,11 +68,14 @@ module Jekyll
76
68
  #
77
69
  # Returns an array
78
70
  def pluralized_array_from_hash(hash, singular_key, plural_key)
79
- [].tap do |array|
80
- value = value_from_singular_key(hash, singular_key)
81
- value ||= value_from_plural_key(hash, plural_key)
82
- array << value
83
- end.flatten.compact
71
+ array = []
72
+ value = value_from_singular_key(hash, singular_key)
73
+ value ||= value_from_plural_key(hash, plural_key)
74
+
75
+ array << value
76
+ array.flatten!
77
+ array.compact!
78
+ array
84
79
  end
85
80
 
86
81
  def value_from_singular_key(hash, key)
@@ -133,7 +128,8 @@ module Jekyll
133
128
  # Returns the parsed date if successful, throws a FatalException
134
129
  # if not
135
130
  def parse_date(input, msg = "Input could not be parsed.")
136
- Time.parse(input).localtime
131
+ @parse_date_cache ||= {}
132
+ @parse_date_cache[input] ||= Time.parse(input).localtime
137
133
  rescue ArgumentError
138
134
  raise Errors::InvalidDateError, "Invalid date '#{input}': #{msg}"
139
135
  end
@@ -141,21 +137,22 @@ module Jekyll
141
137
  # Determines whether a given file has
142
138
  #
143
139
  # Returns true if the YAML front matter is present.
144
- # rubocop: disable PredicateName
140
+ # rubocop: disable Naming/PredicateName
145
141
  def has_yaml_header?(file)
146
- !!(File.open(file, "rb", &:readline) =~ %r!\A---\s*\r?\n!)
142
+ File.open(file, "rb", &:readline).match? %r!\A---\s*\r?\n!
147
143
  rescue EOFError
148
144
  false
149
145
  end
150
146
 
151
- # Determine whether the given content string contains Liquid Tags or Vaiables
147
+ # Determine whether the given content string contains Liquid Tags or Variables
152
148
  #
153
149
  # Returns true is the string contains sequences of `{%` or `{{`
154
150
  def has_liquid_construct?(content)
155
151
  return false if content.nil? || content.empty?
152
+
156
153
  content.include?("{%") || content.include?("{{")
157
154
  end
158
- # rubocop: enable PredicateName
155
+ # rubocop: enable Naming/PredicateName
159
156
 
160
157
  # Slugify a filename or title.
161
158
  #
@@ -219,9 +216,10 @@ module Jekyll
219
216
  slug = replace_character_sequence_with_hyphen(string, :mode => mode)
220
217
 
221
218
  # Remove leading/trailing hyphen
222
- slug.gsub!(%r!^\-|\-$!i, "")
219
+ slug.gsub!(%r!^-|-$!i, "")
223
220
 
224
221
  slug.downcase! unless cased
222
+ Jekyll.logger.warn("Warning:", "Empty `slug` generated for '#{string}'.") if slug.empty?
225
223
  slug
226
224
  end
227
225
 
@@ -268,7 +266,7 @@ module Jekyll
268
266
  template
269
267
  end
270
268
 
271
- # Work the same way as Dir.glob but seperating the input into two parts
269
+ # Work the same way as Dir.glob but separating the input into two parts
272
270
  # ('dir' + '/' + 'pattern') to make sure the first part('dir') does not act
273
271
  # as a pattern.
274
272
  #
@@ -290,11 +288,13 @@ module Jekyll
290
288
  # patterns - the patterns (or the pattern) which will be applied under the dir
291
289
  # flags - the flags which will be applied to the pattern
292
290
  #
293
- # Returns matched pathes
291
+ # Returns matched paths
294
292
  def safe_glob(dir, patterns, flags = 0)
295
293
  return [] unless Dir.exist?(dir)
294
+
296
295
  pattern = File.join(Array(patterns))
297
296
  return [dir] if pattern.empty?
297
+
298
298
  Dir.chdir(dir) do
299
299
  Dir.glob(pattern, flags).map { |f| File.join(dir, f) }
300
300
  end
@@ -304,16 +304,20 @@ module Jekyll
304
304
  # and a given param
305
305
  def merged_file_read_opts(site, opts)
306
306
  merged = (site ? site.file_read_opts : {}).merge(opts)
307
- if merged[:encoding] && !merged[:encoding].start_with?("bom|")
307
+
308
+ # always use BOM when reading UTF-encoded files
309
+ if merged[:encoding]&.downcase&.start_with?("utf-")
308
310
  merged[:encoding] = "bom|#{merged[:encoding]}"
309
311
  end
310
- if merged["encoding"] && !merged["encoding"].start_with?("bom|")
312
+ if merged["encoding"]&.downcase&.start_with?("utf-")
311
313
  merged["encoding"] = "bom|#{merged["encoding"]}"
312
314
  end
315
+
313
316
  merged
314
317
  end
315
318
 
316
319
  private
320
+
317
321
  def merge_values(target, overwrite)
318
322
  target.merge!(overwrite) do |_key, old_val, new_val|
319
323
  if new_val.nil?
@@ -326,14 +330,12 @@ module Jekyll
326
330
  end
327
331
  end
328
332
 
329
- private
330
333
  def merge_default_proc(target, overwrite)
331
334
  if target.is_a?(Hash) && overwrite.is_a?(Hash) && target.default_proc.nil?
332
335
  target.default_proc = overwrite.default_proc
333
336
  end
334
337
  end
335
338
 
336
- private
337
339
  def duplicate_frozen_values(target)
338
340
  target.each do |key, val|
339
341
  target[key] = val.dup if val.frozen? && duplicable?(val)
@@ -344,7 +346,6 @@ module Jekyll
344
346
  #
345
347
  # See Utils#slugify for a description of the character sequence specified
346
348
  # by each mode.
347
- private
348
349
  def replace_character_sequence_with_hyphen(string, mode: "default")
349
350
  replaceable_char =
350
351
  case mode
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jekyll
4
- VERSION = "3.9.3".freeze
4
+ VERSION = "4.4.1"
5
5
  end
data/lib/jekyll.rb CHANGED
@@ -50,10 +50,13 @@ module Jekyll
50
50
  autoload :EntryFilter, "jekyll/entry_filter"
51
51
  autoload :Errors, "jekyll/errors"
52
52
  autoload :Excerpt, "jekyll/excerpt"
53
+ autoload :PageExcerpt, "jekyll/page_excerpt"
53
54
  autoload :External, "jekyll/external"
54
55
  autoload :FrontmatterDefaults, "jekyll/frontmatter_defaults"
55
56
  autoload :Hooks, "jekyll/hooks"
56
57
  autoload :Layout, "jekyll/layout"
58
+ autoload :Inclusion, "jekyll/inclusion"
59
+ autoload :Cache, "jekyll/cache"
57
60
  autoload :CollectionReader, "jekyll/readers/collection_reader"
58
61
  autoload :DataReader, "jekyll/readers/data_reader"
59
62
  autoload :LayoutReader, "jekyll/readers/layout_reader"
@@ -64,8 +67,10 @@ module Jekyll
64
67
  autoload :LogAdapter, "jekyll/log_adapter"
65
68
  autoload :Page, "jekyll/page"
66
69
  autoload :PageWithoutAFile, "jekyll/page_without_a_file"
70
+ autoload :PathManager, "jekyll/path_manager"
67
71
  autoload :PluginManager, "jekyll/plugin_manager"
68
72
  autoload :Publisher, "jekyll/publisher"
73
+ autoload :Profiler, "jekyll/profiler"
69
74
  autoload :Reader, "jekyll/reader"
70
75
  autoload :Regenerator, "jekyll/regenerator"
71
76
  autoload :RelatedPosts, "jekyll/related_posts"
@@ -143,7 +148,7 @@ module Jekyll
143
148
 
144
149
  # Public: Set the log writer.
145
150
  # New log writer must respond to the same methods
146
- # as Ruby's interal Logger.
151
+ # as Ruby's internal Logger.
147
152
  #
148
153
  # writer - the new Logger-compatible log transport
149
154
  #
@@ -168,23 +173,13 @@ module Jekyll
168
173
  # Returns the sanitized path.
169
174
  def sanitized_path(base_directory, questionable_path)
170
175
  return base_directory if base_directory.eql?(questionable_path)
176
+ return base_directory if questionable_path.nil?
171
177
 
172
- clean_path = questionable_path.dup
173
- clean_path.insert(0, "/") if clean_path.start_with?("~")
174
- clean_path = File.expand_path(clean_path, "/")
175
-
176
- return clean_path if clean_path.eql?(base_directory)
177
-
178
- if clean_path.start_with?(base_directory.sub(%r!\z!, "/"))
179
- clean_path
180
- else
181
- clean_path.sub!(%r!\A\w:/!, "/")
182
- File.join(base_directory, clean_path)
183
- end
178
+ +Jekyll::PathManager.sanitized_path(base_directory, questionable_path)
184
179
  end
185
180
 
186
181
  # Conditional optimizations
187
- Jekyll::External.require_if_present("liquid-c")
182
+ Jekyll::External.require_if_present("liquid/c")
188
183
  end
189
184
  end
190
185
 
@@ -1,3 +1,5 @@
1
1
  _site
2
2
  .sass-cache
3
+ .jekyll-cache
3
4
  .jekyll-metadata
5
+ vendor
@@ -1,5 +1,6 @@
1
1
  ---
2
- layout: default
2
+ permalink: /404.html
3
+ layout: page
3
4
  ---
4
5
 
5
6
  <style type="text/css" media="screen">
@@ -7,12 +7,17 @@
7
7
  #
8
8
  # For technical reasons, this file is *NOT* reloaded automatically when you use
9
9
  # 'bundle exec jekyll serve'. If you change this file, please restart the server process.
10
-
10
+ #
11
+ # If you need help with YAML syntax, here are some quick references for you:
12
+ # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml
13
+ # https://learnxinyminutes.com/docs/yaml/
14
+ #
11
15
  # Site settings
12
16
  # These are used to personalize your new site. If you look in the HTML files,
13
17
  # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
14
18
  # You can create any custom variable you would like, and they will be accessible
15
19
  # in the templates via {{ site.myvariable }}.
20
+
16
21
  title: Your awesome title
17
22
  email: your-email@example.com
18
23
  description: >- # this means to ignore newlines until "baseurl:"
@@ -25,18 +30,25 @@ twitter_username: jekyllrb
25
30
  github_username: jekyll
26
31
 
27
32
  # Build settings
28
- markdown: kramdown
29
33
  theme: minima
30
34
  plugins:
31
35
  - jekyll-feed
32
36
 
33
37
  # Exclude from processing.
34
- # The following items will not be processed, by default. Create a custom list
35
- # to override the default setting.
38
+ # The following items will not be processed, by default.
39
+ # Any item listed under the `exclude:` key here will be automatically added to
40
+ # the internal "default list".
41
+ #
42
+ # Excluded items can be processed by explicitly listing the directories or
43
+ # their entries' file path in the `include:` list.
44
+ #
36
45
  # exclude:
46
+ # - .sass-cache/
47
+ # - .jekyll-cache/
48
+ # - gemfiles/
37
49
  # - Gemfile
38
50
  # - Gemfile.lock
39
- # - node_modules
51
+ # - node_modules/
40
52
  # - vendor/bundle/
41
53
  # - vendor/cache/
42
54
  # - vendor/gems/
@@ -6,7 +6,11 @@ categories: jekyll update
6
6
  ---
7
7
  You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated.
8
8
 
9
- To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.
9
+ Jekyll requires blog post files to be named according to the following format:
10
+
11
+ `YEAR-MONTH-DAY-title.MARKUP`
12
+
13
+ Where `YEAR` is a four-digit number, `MONTH` and `DAY` are both two-digit numbers, and `MARKUP` is the file extension representing the format used in the file. After that, include the necessary front matter. Take a look at the source for this post to get an idea about how it works.
10
14
 
11
15
  Jekyll also offers powerful support for code snippets:
12
16
 
@@ -6,7 +6,6 @@ To experiment with this code, add some sample content and run `bundle exec jekyl
6
6
 
7
7
  TODO: Delete this and the text above, and describe your gem
8
8
 
9
-
10
9
  ## Installation
11
10
 
12
11
  Add this line to your Jekyll site's `Gemfile`:
@@ -35,7 +34,7 @@ TODO: Write usage instructions here. Describe your available layouts, includes,
35
34
 
36
35
  ## Contributing
37
36
 
38
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hello. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/<%= theme_name %>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct.
39
38
 
40
39
  ## Development
41
40
 
@@ -49,4 +48,3 @@ To add a custom directory to your theme-gem, please edit the regexp in `<%= them
49
48
  ## License
50
49
 
51
50
  The theme is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
52
-
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
+ .jekyll-cache
3
4
  .sass-cache
4
5
  _site
5
6
  Gemfile.lock
@@ -10,10 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.homepage = "TODO: Put your gem's website or public repo URL here."
11
11
  spec.license = "MIT"
12
12
 
13
- spec.files = `git ls-files -z`.split("\x0").select { |f| f.match(%r!^(<%= theme_directories.join("|") %>|LICENSE|README)!i) }
13
+ spec.files = `git ls-files -z`.split("\x0").select { |f| f.match(%r!^(<%= theme_directories.join("|") %>|LICENSE|README|_config\.yml)!i) }
14
14
 
15
15
  spec.add_runtime_dependency "jekyll", "~> <%= jekyll_version_with_minor %>"
16
-
17
- spec.add_development_dependency "bundler", "~> 1.16"
18
- spec.add_development_dependency "rake", "~> 12.0"
19
16
  end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Jekyll
6
+ # Checks for `assert_equal(exp, act, msg = nil)` calls containing literal values as
7
+ # second argument. The second argument should ideally be a method called on the tested
8
+ # instance.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # assert_equal @foo.bar, "foobar"
13
+ # assert_equal @alpha.beta, { "foo" => "bar", "lorem" => "ipsum" }
14
+ # assert_equal @alpha.omega, ["foobar", "lipsum"]
15
+ #
16
+ # # good
17
+ # assert_equal "foobar", @foo.bar
18
+ #
19
+ # assert_equal(
20
+ # { "foo" => "bar", "lorem" => "ipsum" },
21
+ # @alpha.beta
22
+ # )
23
+ #
24
+ # assert_equal(
25
+ # ["foobar", "lipsum"],
26
+ # @alpha.omega
27
+ # )
28
+ #
29
+ class AssertEqualLiteralActual < Base
30
+ extend AutoCorrector
31
+
32
+ MSG = "Provide the 'expected value' as the first argument to `assert_equal`."
33
+ RESTRICT_ON_SEND = %i[assert_equal].freeze
34
+
35
+ SIMPLE_LITERALS = %i(
36
+ true
37
+ false
38
+ nil
39
+ int
40
+ float
41
+ str
42
+ sym
43
+ complex
44
+ rational
45
+ regopt
46
+ ).freeze
47
+
48
+ COMPLEX_LITERALS = %i(
49
+ array
50
+ hash
51
+ pair
52
+ irange
53
+ erange
54
+ regexp
55
+ ).freeze
56
+
57
+ def_node_matcher :literal_actual?, <<-PATTERN
58
+ (send nil? :assert_equal $(send ...) $#literal?)
59
+ PATTERN
60
+
61
+ def_node_matcher :literal_actual_with_msg?, <<-PATTERN
62
+ (send nil? :assert_equal $(send ...) $#literal? $#opt_msg?)
63
+ PATTERN
64
+
65
+ def on_send(node)
66
+ return unless literal_actual?(node) || literal_actual_with_msg?(node)
67
+
68
+ range = node.loc.expression
69
+ add_offense(range) do |corrector|
70
+ corrector.replace(range, replacement(node))
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def opt_msg?(node)
77
+ node&.source
78
+ end
79
+
80
+ # This is not implement using a NodePattern because it seems
81
+ # to not be able to match against an explicit (nil) sexp
82
+ def literal?(node)
83
+ node && (simple_literal?(node) || complex_literal?(node))
84
+ end
85
+
86
+ def simple_literal?(node)
87
+ SIMPLE_LITERALS.include?(node.type)
88
+ end
89
+
90
+ def complex_literal?(node)
91
+ COMPLEX_LITERALS.include?(node.type) &&
92
+ node.each_child_node.all?(&method(:literal?))
93
+ end
94
+
95
+ def replacement(node)
96
+ _, _, first_param, second_param, optional_param = *node
97
+
98
+ replaced_text = \
99
+ if second_param.type == :hash
100
+ replace_hash_with_variable(first_param.source, second_param.source)
101
+ elsif second_param.type == :array && second_param.source != "[]"
102
+ replace_array_with_variable(first_param.source, second_param.source)
103
+ else
104
+ replace_based_on_line_length(first_param.source, second_param.source)
105
+ end
106
+
107
+ return "#{replaced_text}, #{optional_param.source}" if optional_param
108
+ replaced_text
109
+ end
110
+
111
+ def replace_based_on_line_length(first_expression, second_expression)
112
+ result = "assert_equal #{second_expression}, #{first_expression}"
113
+ return result if result.length < 80
114
+
115
+ # fold long lines independent of Rubocop configuration for better readability
116
+ <<~TEXT
117
+ assert_equal(
118
+ #{second_expression},
119
+ #{first_expression}
120
+ )
121
+ TEXT
122
+ end
123
+
124
+ def replace_hash_with_variable(first_expression, second_expression)
125
+ expect_expression = if second_expression.start_with?("{")
126
+ second_expression
127
+ else
128
+ "{#{second_expression}}"
129
+ end
130
+ <<~TEXT
131
+ expected = #{expect_expression}
132
+ assert_equal expected, #{first_expression}
133
+ TEXT
134
+ end
135
+
136
+ def replace_array_with_variable(first_expression, second_expression)
137
+ expect_expression = if second_expression.start_with?("%")
138
+ second_expression
139
+ else
140
+ Array(second_expression)
141
+ end
142
+ <<~TEXT
143
+ expected = #{expect_expression}
144
+ assert_equal expected, #{first_expression}
145
+ TEXT
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -1,20 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rubocop"
4
-
5
3
  module RuboCop
6
4
  module Cop
7
5
  module Jekyll
8
- class NoPAllowed < Cop
9
- MSG = "Avoid using `p` to print things. Use `Jekyll.logger` instead.".freeze
6
+ class NoPAllowed < Base
7
+ MSG = "Avoid using `p` to print things. Use `Jekyll.logger` instead."
8
+ RESTRICT_ON_SEND = %i[p].freeze
10
9
 
11
10
  def_node_search :p_called?, <<-PATTERN
12
- (send _ :p _)
11
+ (send _ :p _)
13
12
  PATTERN
14
13
 
15
14
  def on_send(node)
16
15
  if p_called?(node)
17
- add_offense(node, :location => :selector)
16
+ add_offense(node.loc.selector)
18
17
  end
19
18
  end
20
19
  end
@@ -1,20 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rubocop"
4
-
5
3
  module RuboCop
6
4
  module Cop
7
5
  module Jekyll
8
- class NoPutsAllowed < Cop
9
- MSG = "Avoid using `puts` to print things. Use `Jekyll.logger` instead.".freeze
6
+ class NoPutsAllowed < Base
7
+ MSG = "Avoid using `puts` to print things. Use `Jekyll.logger` instead."
8
+ RESTRICT_ON_SEND = %i[puts].freeze
10
9
 
11
10
  def_node_search :puts_called?, <<-PATTERN
12
- (send nil? :puts _)
11
+ (send nil? :puts _)
13
12
  PATTERN
14
13
 
15
14
  def on_send(node)
16
15
  if puts_called?(node)
17
- add_offense(node, :location => :selector)
16
+ add_offense(node.loc.selector)
18
17
  end
19
18
  end
20
19
  end