jekyll 3.8.7 → 4.1.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +71 -62
- data/LICENSE +1 -1
- data/README.markdown +46 -17
- data/lib/blank_template/_config.yml +3 -0
- data/lib/blank_template/_layouts/default.html +12 -0
- data/lib/blank_template/_sass/main.scss +9 -0
- data/lib/blank_template/assets/css/main.scss +4 -0
- data/lib/blank_template/index.md +8 -0
- data/lib/jekyll.rb +10 -1
- data/lib/jekyll/cache.rb +190 -0
- data/lib/jekyll/cleaner.rb +5 -4
- data/lib/jekyll/collection.rb +82 -10
- data/lib/jekyll/command.rb +33 -6
- data/lib/jekyll/commands/build.rb +11 -20
- data/lib/jekyll/commands/clean.rb +2 -0
- data/lib/jekyll/commands/doctor.rb +15 -8
- data/lib/jekyll/commands/help.rb +1 -1
- data/lib/jekyll/commands/new.rb +37 -35
- data/lib/jekyll/commands/new_theme.rb +30 -28
- data/lib/jekyll/commands/serve.rb +55 -81
- data/lib/jekyll/commands/serve/live_reload_reactor.rb +6 -10
- data/lib/jekyll/commands/serve/servlet.rb +22 -25
- data/lib/jekyll/commands/serve/websockets.rb +1 -1
- data/lib/jekyll/configuration.rb +61 -149
- data/lib/jekyll/converters/identity.rb +18 -0
- data/lib/jekyll/converters/markdown.rb +49 -40
- data/lib/jekyll/converters/markdown/kramdown_parser.rb +84 -11
- data/lib/jekyll/converters/smartypants.rb +34 -14
- data/lib/jekyll/convertible.rb +30 -31
- data/lib/jekyll/deprecator.rb +1 -3
- data/lib/jekyll/document.rb +89 -61
- data/lib/jekyll/drops/collection_drop.rb +2 -3
- data/lib/jekyll/drops/document_drop.rb +14 -1
- data/lib/jekyll/drops/drop.rb +17 -14
- data/lib/jekyll/drops/excerpt_drop.rb +4 -0
- data/lib/jekyll/drops/page_drop.rb +18 -0
- data/lib/jekyll/drops/site_drop.rb +6 -5
- data/lib/jekyll/drops/unified_payload_drop.rb +1 -0
- data/lib/jekyll/drops/url_drop.rb +53 -1
- data/lib/jekyll/entry_filter.rb +42 -45
- data/lib/jekyll/excerpt.rb +45 -34
- data/lib/jekyll/external.rb +10 -5
- data/lib/jekyll/filters.rb +200 -40
- data/lib/jekyll/filters/date_filters.rb +6 -3
- data/lib/jekyll/filters/grouping_filters.rb +1 -2
- data/lib/jekyll/filters/url_filters.rb +46 -14
- data/lib/jekyll/frontmatter_defaults.rb +46 -35
- data/lib/jekyll/hooks.rb +4 -8
- data/lib/jekyll/inclusion.rb +32 -0
- data/lib/jekyll/liquid_extensions.rb +0 -2
- data/lib/jekyll/liquid_renderer.rb +31 -16
- data/lib/jekyll/liquid_renderer/file.rb +24 -3
- data/lib/jekyll/liquid_renderer/table.rb +36 -77
- data/lib/jekyll/log_adapter.rb +5 -1
- data/lib/jekyll/mime.types +53 -11
- data/lib/jekyll/page.rb +54 -12
- data/lib/jekyll/page_excerpt.rb +26 -0
- data/lib/jekyll/page_without_a_file.rb +0 -4
- data/lib/jekyll/path_manager.rb +31 -0
- data/lib/jekyll/plugin.rb +5 -11
- data/lib/jekyll/plugin_manager.rb +2 -0
- data/lib/jekyll/profiler.rb +58 -0
- data/lib/jekyll/reader.rb +42 -9
- data/lib/jekyll/readers/collection_reader.rb +1 -0
- data/lib/jekyll/readers/data_reader.rb +8 -9
- data/lib/jekyll/readers/layout_reader.rb +3 -12
- data/lib/jekyll/readers/page_reader.rb +5 -5
- data/lib/jekyll/readers/post_reader.rb +31 -18
- data/lib/jekyll/readers/static_file_reader.rb +4 -4
- data/lib/jekyll/readers/theme_assets_reader.rb +8 -5
- data/lib/jekyll/regenerator.rb +4 -12
- data/lib/jekyll/renderer.rb +23 -40
- data/lib/jekyll/site.rb +91 -38
- data/lib/jekyll/static_file.rb +62 -21
- data/lib/jekyll/stevenson.rb +2 -3
- data/lib/jekyll/tags/highlight.rb +19 -51
- data/lib/jekyll/tags/include.rb +82 -42
- data/lib/jekyll/tags/link.rb +11 -7
- data/lib/jekyll/tags/post_url.rb +25 -21
- data/lib/jekyll/theme.rb +16 -18
- data/lib/jekyll/theme_builder.rb +91 -89
- data/lib/jekyll/url.rb +10 -5
- data/lib/jekyll/utils.rb +18 -21
- data/lib/jekyll/utils/ansi.rb +1 -1
- data/lib/jekyll/utils/exec.rb +0 -1
- data/lib/jekyll/utils/internet.rb +2 -4
- data/lib/jekyll/utils/platforms.rb +8 -8
- data/lib/jekyll/utils/thread_event.rb +1 -5
- data/lib/jekyll/utils/win_tz.rb +2 -2
- data/lib/jekyll/version.rb +1 -1
- data/lib/site_template/.gitignore +2 -0
- data/lib/site_template/404.html +1 -0
- data/lib/site_template/_config.yml +17 -5
- data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +5 -1
- data/lib/site_template/{about.md → about.markdown} +0 -0
- data/lib/site_template/{index.md → index.markdown} +0 -0
- data/lib/theme_template/gitignore.erb +1 -0
- data/lib/theme_template/theme.gemspec.erb +1 -4
- data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -0
- metadata +69 -31
- data/lib/jekyll/converters/markdown/rdiscount_parser.rb +0 -37
- data/lib/jekyll/converters/markdown/redcarpet_parser.rb +0 -112
- data/lib/jekyll/utils/rouge.rb +0 -22
data/lib/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("[
|
|
18
|
-
SLUGIFY_PRETTY_REGEXP = Regexp.new("[
|
|
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
|
-
[]
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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)
|
|
@@ -141,9 +136,9 @@ module Jekyll
|
|
|
141
136
|
# Determines whether a given file has
|
|
142
137
|
#
|
|
143
138
|
# Returns true if the YAML front matter is present.
|
|
144
|
-
# rubocop: disable PredicateName
|
|
139
|
+
# rubocop: disable Naming/PredicateName
|
|
145
140
|
def has_yaml_header?(file)
|
|
146
|
-
|
|
141
|
+
File.open(file, "rb", &:readline).match? %r!\A---\s*\r?\n!
|
|
147
142
|
rescue EOFError
|
|
148
143
|
false
|
|
149
144
|
end
|
|
@@ -153,9 +148,10 @@ module Jekyll
|
|
|
153
148
|
# Returns true is the string contains sequences of `{%` or `{{`
|
|
154
149
|
def has_liquid_construct?(content)
|
|
155
150
|
return false if content.nil? || content.empty?
|
|
151
|
+
|
|
156
152
|
content.include?("{%") || content.include?("{{")
|
|
157
153
|
end
|
|
158
|
-
# rubocop: enable PredicateName
|
|
154
|
+
# rubocop: enable Naming/PredicateName
|
|
159
155
|
|
|
160
156
|
# Slugify a filename or title.
|
|
161
157
|
#
|
|
@@ -222,6 +218,7 @@ module Jekyll
|
|
|
222
218
|
slug.gsub!(%r!^\-|\-$!i, "")
|
|
223
219
|
|
|
224
220
|
slug.downcase! unless cased
|
|
221
|
+
Jekyll.logger.warn("Warning:", "Empty `slug` generated for '#{string}'.") if slug.empty?
|
|
225
222
|
slug
|
|
226
223
|
end
|
|
227
224
|
|
|
@@ -293,8 +290,10 @@ module Jekyll
|
|
|
293
290
|
# Returns matched pathes
|
|
294
291
|
def safe_glob(dir, patterns, flags = 0)
|
|
295
292
|
return [] unless Dir.exist?(dir)
|
|
293
|
+
|
|
296
294
|
pattern = File.join(Array(patterns))
|
|
297
295
|
return [dir] if pattern.empty?
|
|
296
|
+
|
|
298
297
|
Dir.chdir(dir) do
|
|
299
298
|
Dir.glob(pattern, flags).map { |f| File.join(dir, f) }
|
|
300
299
|
end
|
|
@@ -314,6 +313,7 @@ module Jekyll
|
|
|
314
313
|
end
|
|
315
314
|
|
|
316
315
|
private
|
|
316
|
+
|
|
317
317
|
def merge_values(target, overwrite)
|
|
318
318
|
target.merge!(overwrite) do |_key, old_val, new_val|
|
|
319
319
|
if new_val.nil?
|
|
@@ -326,14 +326,12 @@ module Jekyll
|
|
|
326
326
|
end
|
|
327
327
|
end
|
|
328
328
|
|
|
329
|
-
private
|
|
330
329
|
def merge_default_proc(target, overwrite)
|
|
331
330
|
if target.is_a?(Hash) && overwrite.is_a?(Hash) && target.default_proc.nil?
|
|
332
331
|
target.default_proc = overwrite.default_proc
|
|
333
332
|
end
|
|
334
333
|
end
|
|
335
334
|
|
|
336
|
-
private
|
|
337
335
|
def duplicate_frozen_values(target)
|
|
338
336
|
target.each do |key, val|
|
|
339
337
|
target[key] = val.dup if val.frozen? && duplicable?(val)
|
|
@@ -344,7 +342,6 @@ module Jekyll
|
|
|
344
342
|
#
|
|
345
343
|
# See Utils#slugify for a description of the character sequence specified
|
|
346
344
|
# by each mode.
|
|
347
|
-
private
|
|
348
345
|
def replace_character_sequence_with_hyphen(string, mode: "default")
|
|
349
346
|
replaceable_char =
|
|
350
347
|
case mode
|
data/lib/jekyll/utils/ansi.rb
CHANGED
data/lib/jekyll/utils/exec.rb
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
module Jekyll
|
|
4
4
|
module Utils
|
|
5
5
|
module Internet
|
|
6
|
-
|
|
7
6
|
# Public: Determine whether the present device has a connection to
|
|
8
7
|
# the Internet. This allows plugin writers which require the outside
|
|
9
8
|
# world to have a neat fallback mechanism for offline building.
|
|
@@ -18,13 +17,13 @@ module Jekyll
|
|
|
18
17
|
# end
|
|
19
18
|
#
|
|
20
19
|
# Returns true if a DNS call can successfully be made, or false if not.
|
|
20
|
+
|
|
21
21
|
module_function
|
|
22
|
+
|
|
22
23
|
def connected?
|
|
23
24
|
!dns("example.com").nil?
|
|
24
25
|
end
|
|
25
26
|
|
|
26
|
-
private
|
|
27
|
-
module_function
|
|
28
27
|
def dns(domain)
|
|
29
28
|
require "resolv"
|
|
30
29
|
Resolv::DNS.open do |resolver|
|
|
@@ -33,7 +32,6 @@ module Jekyll
|
|
|
33
32
|
rescue Resolv::ResolvError, Resolv::ResolvTimeout
|
|
34
33
|
nil
|
|
35
34
|
end
|
|
36
|
-
|
|
37
35
|
end
|
|
38
36
|
end
|
|
39
37
|
end
|
|
@@ -31,7 +31,7 @@ module Jekyll
|
|
|
31
31
|
# --
|
|
32
32
|
|
|
33
33
|
alias_method :really_windows?, \
|
|
34
|
-
|
|
34
|
+
:vanilla_windows?
|
|
35
35
|
|
|
36
36
|
#
|
|
37
37
|
|
|
@@ -68,14 +68,14 @@ module Jekyll
|
|
|
68
68
|
#
|
|
69
69
|
|
|
70
70
|
private
|
|
71
|
+
|
|
71
72
|
def proc_version
|
|
72
|
-
@proc_version ||=
|
|
73
|
-
|
|
74
|
-
"/proc/version"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
end
|
|
73
|
+
@proc_version ||=
|
|
74
|
+
begin
|
|
75
|
+
File.read("/proc/version")
|
|
76
|
+
rescue Errno::ENOENT, Errno::EACCES
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "thread"
|
|
4
|
-
|
|
5
3
|
module Jekyll
|
|
6
4
|
module Utils
|
|
7
5
|
# Based on the pattern and code from
|
|
@@ -25,9 +23,7 @@ module Jekyll
|
|
|
25
23
|
|
|
26
24
|
def wait
|
|
27
25
|
@lock.synchronize do
|
|
28
|
-
unless @flag
|
|
29
|
-
@cond.wait(@lock)
|
|
30
|
-
end
|
|
26
|
+
@cond.wait(@lock) unless @flag
|
|
31
27
|
end
|
|
32
28
|
end
|
|
33
29
|
end
|
data/lib/jekyll/utils/win_tz.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Jekyll
|
|
|
21
21
|
# is denoted as:
|
|
22
22
|
# EST+5 (or) EST+05:00
|
|
23
23
|
# Reference: http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
|
24
|
-
sign = difference
|
|
24
|
+
sign = difference.negative? ? "-" : "+"
|
|
25
25
|
offset = sign == "-" ? "+" : "-" unless difference.zero?
|
|
26
26
|
#
|
|
27
27
|
# convert the difference (in seconds) to hours, as a rational number, and perform
|
|
@@ -30,7 +30,7 @@ module Jekyll
|
|
|
30
30
|
#
|
|
31
31
|
# Format the hour as a two-digit number.
|
|
32
32
|
# Establish the minutes based on modulo expression.
|
|
33
|
-
hh = format("
|
|
33
|
+
hh = format("%<hour>02d", :hour => absolute_hour(difference).ceil)
|
|
34
34
|
mm = modulo.zero? ? "00" : "30"
|
|
35
35
|
|
|
36
36
|
Jekyll.logger.debug "Timezone:", "#{timezone} #{offset}#{hh}:#{mm}"
|
data/lib/jekyll/version.rb
CHANGED
data/lib/site_template/404.html
CHANGED
|
@@ -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.
|
|
35
|
-
#
|
|
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
|
-
|
|
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
|
|
|
File without changes
|
|
File without changes
|
|
@@ -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,149 @@
|
|
|
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 < Cop
|
|
30
|
+
MSG = "Provide the 'expected value' as the first argument to `assert_equal`.".freeze
|
|
31
|
+
|
|
32
|
+
SIMPLE_LITERALS = %i(
|
|
33
|
+
true
|
|
34
|
+
false
|
|
35
|
+
nil
|
|
36
|
+
int
|
|
37
|
+
float
|
|
38
|
+
str
|
|
39
|
+
sym
|
|
40
|
+
complex
|
|
41
|
+
rational
|
|
42
|
+
regopt
|
|
43
|
+
).freeze
|
|
44
|
+
|
|
45
|
+
COMPLEX_LITERALS = %i(
|
|
46
|
+
array
|
|
47
|
+
hash
|
|
48
|
+
pair
|
|
49
|
+
irange
|
|
50
|
+
erange
|
|
51
|
+
regexp
|
|
52
|
+
).freeze
|
|
53
|
+
|
|
54
|
+
def_node_matcher :literal_actual?, <<-PATTERN
|
|
55
|
+
(send nil? :assert_equal $(send ...) $#literal?)
|
|
56
|
+
PATTERN
|
|
57
|
+
|
|
58
|
+
def_node_matcher :literal_actual_with_msg?, <<-PATTERN
|
|
59
|
+
(send nil? :assert_equal $(send ...) $#literal? $#opt_msg?)
|
|
60
|
+
PATTERN
|
|
61
|
+
|
|
62
|
+
def on_send(node)
|
|
63
|
+
return unless literal_actual?(node) || literal_actual_with_msg?(node)
|
|
64
|
+
add_offense(node, location: :expression)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def autocorrect(node)
|
|
68
|
+
lambda do |corrector|
|
|
69
|
+
corrector.replace(node.loc.expression, replacement(node))
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def opt_msg?(node)
|
|
76
|
+
node&.source
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# This is not implement using a NodePattern because it seems
|
|
80
|
+
# to not be able to match against an explicit (nil) sexp
|
|
81
|
+
def literal?(node)
|
|
82
|
+
node && (simple_literal?(node) || complex_literal?(node))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def simple_literal?(node)
|
|
86
|
+
SIMPLE_LITERALS.include?(node.type)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def complex_literal?(node)
|
|
90
|
+
COMPLEX_LITERALS.include?(node.type) &&
|
|
91
|
+
node.each_child_node.all?(&method(:literal?))
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def replacement(node)
|
|
95
|
+
_, _, first_param, second_param, optional_param = *node
|
|
96
|
+
|
|
97
|
+
replaced_text = \
|
|
98
|
+
if second_param.type == :hash
|
|
99
|
+
replace_hash_with_variable(first_param.source, second_param.source)
|
|
100
|
+
elsif second_param.type == :array && second_param.source != "[]"
|
|
101
|
+
replace_array_with_variable(first_param.source, second_param.source)
|
|
102
|
+
else
|
|
103
|
+
replace_based_on_line_length(first_param.source, second_param.source)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
return "#{replaced_text}, #{optional_param.source}" if optional_param
|
|
107
|
+
replaced_text
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def replace_based_on_line_length(first_expression, second_expression)
|
|
111
|
+
result = "assert_equal #{second_expression}, #{first_expression}"
|
|
112
|
+
return result if result.length < 80
|
|
113
|
+
|
|
114
|
+
# fold long lines independent of Rubocop configuration for better readability
|
|
115
|
+
<<~TEXT
|
|
116
|
+
assert_equal(
|
|
117
|
+
#{second_expression},
|
|
118
|
+
#{first_expression}
|
|
119
|
+
)
|
|
120
|
+
TEXT
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def replace_hash_with_variable(first_expression, second_expression)
|
|
124
|
+
expect_expression = if second_expression.start_with?("{")
|
|
125
|
+
second_expression
|
|
126
|
+
else
|
|
127
|
+
"{#{second_expression}}"
|
|
128
|
+
end
|
|
129
|
+
<<~TEXT
|
|
130
|
+
expected = #{expect_expression}
|
|
131
|
+
assert_equal expected, #{first_expression}
|
|
132
|
+
TEXT
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def replace_array_with_variable(first_expression, second_expression)
|
|
136
|
+
expect_expression = if second_expression.start_with?("%")
|
|
137
|
+
second_expression
|
|
138
|
+
else
|
|
139
|
+
Array(second_expression)
|
|
140
|
+
end
|
|
141
|
+
<<~TEXT
|
|
142
|
+
expected = #{expect_expression}
|
|
143
|
+
assert_equal expected, #{first_expression}
|
|
144
|
+
TEXT
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|