jekyll 4.0.1 → 4.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +350 -163
  3. data/LICENSE +21 -21
  4. data/README.markdown +86 -90
  5. data/exe/jekyll +57 -57
  6. data/lib/blank_template/_config.yml +3 -3
  7. data/lib/blank_template/_layouts/default.html +12 -12
  8. data/lib/blank_template/_sass/main.scss +9 -9
  9. data/lib/blank_template/assets/css/main.scss +4 -4
  10. data/lib/blank_template/index.md +8 -8
  11. data/lib/jekyll/cache.rb +190 -190
  12. data/lib/jekyll/cleaner.rb +111 -111
  13. data/lib/jekyll/collection.rb +309 -309
  14. data/lib/jekyll/command.rb +105 -103
  15. data/lib/jekyll/commands/build.rb +93 -93
  16. data/lib/jekyll/commands/clean.rb +45 -45
  17. data/lib/jekyll/commands/doctor.rb +177 -173
  18. data/lib/jekyll/commands/help.rb +34 -34
  19. data/lib/jekyll/commands/new.rb +169 -169
  20. data/lib/jekyll/commands/new_theme.rb +40 -42
  21. data/lib/jekyll/commands/serve/live_reload_reactor.rb +122 -122
  22. data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -1183
  23. data/lib/jekyll/commands/serve/servlet.rb +202 -202
  24. data/lib/jekyll/commands/serve/websockets.rb +81 -81
  25. data/lib/jekyll/commands/serve.rb +362 -354
  26. data/lib/jekyll/configuration.rb +313 -316
  27. data/lib/jekyll/converter.rb +54 -54
  28. data/lib/jekyll/converters/identity.rb +41 -41
  29. data/lib/jekyll/converters/markdown/kramdown_parser.rb +199 -130
  30. data/lib/jekyll/converters/markdown.rb +113 -113
  31. data/lib/jekyll/converters/smartypants.rb +70 -70
  32. data/lib/jekyll/convertible.rb +257 -254
  33. data/lib/jekyll/deprecator.rb +50 -50
  34. data/lib/jekyll/document.rb +544 -522
  35. data/lib/jekyll/drops/collection_drop.rb +20 -20
  36. data/lib/jekyll/drops/document_drop.rb +70 -69
  37. data/lib/jekyll/drops/drop.rb +293 -215
  38. data/lib/jekyll/drops/excerpt_drop.rb +19 -19
  39. data/lib/jekyll/drops/jekyll_drop.rb +32 -32
  40. data/lib/jekyll/drops/site_drop.rb +66 -66
  41. data/lib/jekyll/drops/static_file_drop.rb +14 -14
  42. data/lib/jekyll/drops/unified_payload_drop.rb +26 -26
  43. data/lib/jekyll/drops/url_drop.rb +140 -132
  44. data/lib/jekyll/entry_filter.rb +121 -110
  45. data/lib/jekyll/errors.rb +20 -20
  46. data/lib/jekyll/excerpt.rb +201 -201
  47. data/lib/jekyll/external.rb +79 -79
  48. data/lib/jekyll/filters/date_filters.rb +110 -110
  49. data/lib/jekyll/filters/grouping_filters.rb +64 -64
  50. data/lib/jekyll/filters/url_filters.rb +98 -68
  51. data/lib/jekyll/filters.rb +535 -454
  52. data/lib/jekyll/frontmatter_defaults.rb +240 -245
  53. data/lib/jekyll/generator.rb +5 -5
  54. data/lib/jekyll/hooks.rb +107 -106
  55. data/lib/jekyll/inclusion.rb +32 -0
  56. data/lib/jekyll/layout.rb +67 -62
  57. data/lib/jekyll/liquid_extensions.rb +22 -22
  58. data/lib/jekyll/liquid_renderer/file.rb +77 -77
  59. data/lib/jekyll/liquid_renderer/table.rb +55 -75
  60. data/lib/jekyll/liquid_renderer.rb +80 -77
  61. data/lib/jekyll/log_adapter.rb +151 -151
  62. data/lib/jekyll/mime.types +866 -866
  63. data/lib/jekyll/page.rb +217 -186
  64. data/lib/jekyll/page_excerpt.rb +25 -0
  65. data/lib/jekyll/page_without_a_file.rb +14 -14
  66. data/lib/jekyll/path_manager.rb +74 -31
  67. data/lib/jekyll/plugin.rb +92 -92
  68. data/lib/jekyll/plugin_manager.rb +115 -115
  69. data/lib/jekyll/profiler.rb +58 -0
  70. data/lib/jekyll/publisher.rb +23 -23
  71. data/lib/jekyll/reader.rb +192 -187
  72. data/lib/jekyll/readers/collection_reader.rb +23 -22
  73. data/lib/jekyll/readers/data_reader.rb +79 -75
  74. data/lib/jekyll/readers/layout_reader.rb +62 -61
  75. data/lib/jekyll/readers/page_reader.rb +25 -24
  76. data/lib/jekyll/readers/post_reader.rb +85 -84
  77. data/lib/jekyll/readers/static_file_reader.rb +25 -24
  78. data/lib/jekyll/readers/theme_assets_reader.rb +52 -51
  79. data/lib/jekyll/regenerator.rb +195 -195
  80. data/lib/jekyll/related_posts.rb +52 -52
  81. data/lib/jekyll/renderer.rb +265 -267
  82. data/lib/jekyll/site.rb +551 -527
  83. data/lib/jekyll/static_file.rb +208 -203
  84. data/lib/jekyll/stevenson.rb +60 -60
  85. data/lib/jekyll/tags/highlight.rb +110 -110
  86. data/lib/jekyll/tags/include.rb +275 -221
  87. data/lib/jekyll/tags/link.rb +42 -41
  88. data/lib/jekyll/tags/post_url.rb +106 -107
  89. data/lib/jekyll/theme.rb +86 -80
  90. data/lib/jekyll/theme_builder.rb +121 -121
  91. data/lib/jekyll/url.rb +167 -164
  92. data/lib/jekyll/utils/ansi.rb +57 -57
  93. data/lib/jekyll/utils/exec.rb +26 -26
  94. data/lib/jekyll/utils/internet.rb +37 -37
  95. data/lib/jekyll/utils/platforms.rb +67 -82
  96. data/lib/jekyll/utils/thread_event.rb +31 -31
  97. data/lib/jekyll/utils/win_tz.rb +75 -75
  98. data/lib/jekyll/utils.rb +367 -367
  99. data/lib/jekyll/version.rb +5 -5
  100. data/lib/jekyll.rb +195 -206
  101. data/lib/site_template/.gitignore +5 -5
  102. data/lib/site_template/404.html +25 -25
  103. data/lib/site_template/_config.yml +55 -55
  104. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -29
  105. data/lib/site_template/about.markdown +18 -18
  106. data/lib/site_template/index.markdown +6 -6
  107. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -74
  108. data/lib/theme_template/Gemfile +4 -4
  109. data/lib/theme_template/LICENSE.txt.erb +21 -21
  110. data/lib/theme_template/README.md.erb +52 -52
  111. data/lib/theme_template/_layouts/default.html +1 -1
  112. data/lib/theme_template/_layouts/page.html +5 -5
  113. data/lib/theme_template/_layouts/post.html +5 -5
  114. data/lib/theme_template/example/_config.yml.erb +1 -1
  115. data/lib/theme_template/example/_post.md +12 -12
  116. data/lib/theme_template/example/index.html +14 -14
  117. data/lib/theme_template/example/style.scss +7 -7
  118. data/lib/theme_template/gitignore.erb +6 -6
  119. data/lib/theme_template/theme.gemspec.erb +16 -19
  120. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -149
  121. data/rubocop/jekyll/no_p_allowed.rb +23 -23
  122. data/rubocop/jekyll/no_puts_allowed.rb +23 -23
  123. data/rubocop/jekyll.rb +5 -5
  124. metadata +20 -38
@@ -1,75 +1,55 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- class LiquidRenderer
5
- class Table
6
- GAUGES = [:count, :bytes, :time].freeze
7
-
8
- def initialize(stats)
9
- @stats = stats
10
- end
11
-
12
- def to_s(num_of_rows = 50)
13
- tabulate(data_for_table(num_of_rows))
14
- end
15
-
16
- private
17
-
18
- def tabulate(data)
19
- require "terminal-table"
20
-
21
- header = data.shift
22
- footer = data.pop
23
- output = +"\n"
24
-
25
- table = Terminal::Table.new do |t|
26
- t << header
27
- t << :separator
28
- data.each { |row| t << row }
29
- t << :separator
30
- t << footer
31
- t.style = { :alignment => :right, :border_top => false, :border_bottom => false }
32
- t.align_column(0, :left)
33
- end
34
-
35
- output << table.to_s << "\n"
36
- end
37
-
38
- # rubocop:disable Metrics/AbcSize
39
- def data_for_table(num_of_rows)
40
- sorted = @stats.sort_by { |_, file_stats| -file_stats[:time] }
41
- sorted = sorted.slice(0, num_of_rows)
42
-
43
- table = [header_labels]
44
- totals = Hash.new { |hash, key| hash[key] = 0 }
45
-
46
- sorted.each do |filename, file_stats|
47
- GAUGES.each { |gauge| totals[gauge] += file_stats[gauge] }
48
- row = []
49
- row << filename
50
- row << file_stats[:count].to_s
51
- row << format_bytes(file_stats[:bytes])
52
- row << format("%.3f", file_stats[:time])
53
- table << row
54
- end
55
-
56
- footer = []
57
- footer << "TOTAL (for #{sorted.size} files)"
58
- footer << totals[:count].to_s
59
- footer << format_bytes(totals[:bytes])
60
- footer << format("%.3f", totals[:time])
61
- table << footer
62
- end
63
- # rubocop:enable Metrics/AbcSize
64
-
65
- def header_labels
66
- GAUGES.map { |gauge| gauge.to_s.capitalize }.unshift("Filename")
67
- end
68
-
69
- def format_bytes(bytes)
70
- bytes /= 1024.0
71
- format("%.2fK", bytes)
72
- end
73
- end
74
- end
75
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class LiquidRenderer
5
+ class Table
6
+ GAUGES = [:count, :bytes, :time].freeze
7
+
8
+ def initialize(stats)
9
+ @stats = stats
10
+ end
11
+
12
+ def to_s(num_of_rows = 50)
13
+ Jekyll::Profiler.tabulate(data_for_table(num_of_rows))
14
+ end
15
+
16
+ private
17
+
18
+ # rubocop:disable Metrics/AbcSize
19
+ def data_for_table(num_of_rows)
20
+ sorted = @stats.sort_by { |_, file_stats| -file_stats[:time] }
21
+ sorted = sorted.slice(0, num_of_rows)
22
+
23
+ table = [header_labels]
24
+ totals = Hash.new { |hash, key| hash[key] = 0 }
25
+
26
+ sorted.each do |filename, file_stats|
27
+ GAUGES.each { |gauge| totals[gauge] += file_stats[gauge] }
28
+ row = []
29
+ row << filename
30
+ row << file_stats[:count].to_s
31
+ row << format_bytes(file_stats[:bytes])
32
+ row << format("%.3f", file_stats[:time])
33
+ table << row
34
+ end
35
+
36
+ footer = []
37
+ footer << "TOTAL (for #{sorted.size} files)"
38
+ footer << totals[:count].to_s
39
+ footer << format_bytes(totals[:bytes])
40
+ footer << format("%.3f", totals[:time])
41
+ table << footer
42
+ end
43
+ # rubocop:enable Metrics/AbcSize
44
+
45
+ def header_labels
46
+ GAUGES.map { |gauge| gauge.to_s.capitalize }.unshift("Filename")
47
+ end
48
+
49
+ def format_bytes(bytes)
50
+ bytes /= 1024.0
51
+ format("%.2fK", bytes)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,77 +1,80 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "liquid_renderer/file"
4
- require_relative "liquid_renderer/table"
5
-
6
- module Jekyll
7
- class LiquidRenderer
8
- extend Forwardable
9
-
10
- private def_delegator :@site, :in_source_dir, :source_dir
11
- private def_delegator :@site, :in_theme_dir, :theme_dir
12
-
13
- def initialize(site)
14
- @site = site
15
- Liquid::Template.error_mode = @site.config["liquid"]["error_mode"].to_sym
16
- reset
17
- end
18
-
19
- def reset
20
- @stats = {}
21
- @cache = {}
22
- end
23
-
24
- def file(filename)
25
- filename.match(filename_regex)
26
- filename =
27
- if Regexp.last_match(1) == theme_dir("")
28
- ::File.join(::File.basename(Regexp.last_match(1)), Regexp.last_match(2))
29
- else
30
- Regexp.last_match(2)
31
- end
32
- LiquidRenderer::File.new(self, filename).tap do
33
- @stats[filename] ||= new_profile_hash
34
- end
35
- end
36
-
37
- def increment_bytes(filename, bytes)
38
- @stats[filename][:bytes] += bytes
39
- end
40
-
41
- def increment_time(filename, time)
42
- @stats[filename][:time] += time
43
- end
44
-
45
- def increment_count(filename)
46
- @stats[filename][:count] += 1
47
- end
48
-
49
- def stats_table(num_of_rows = 50)
50
- LiquidRenderer::Table.new(@stats).to_s(num_of_rows)
51
- end
52
-
53
- def self.format_error(error, path)
54
- "#{error.message} in #{path}"
55
- end
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
-
65
- private
66
-
67
- def filename_regex
68
- @filename_regex ||= begin
69
- %r!\A(#{Regexp.escape(source_dir)}/|#{Regexp.escape(theme_dir.to_s)}/|/*)(.*)!i
70
- end
71
- end
72
-
73
- def new_profile_hash
74
- Hash.new { |hash, key| hash[key] = 0 }
75
- end
76
- end
77
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "liquid_renderer/file"
4
+ require_relative "liquid_renderer/table"
5
+
6
+ module Jekyll
7
+ class LiquidRenderer
8
+ def initialize(site)
9
+ @site = site
10
+ Liquid::Template.error_mode = @site.config["liquid"]["error_mode"].to_sym
11
+ reset
12
+ end
13
+
14
+ def reset
15
+ @stats = {}
16
+ @cache = {}
17
+ end
18
+
19
+ def file(filename)
20
+ filename = normalize_path(filename)
21
+ LiquidRenderer::File.new(self, filename).tap do
22
+ @stats[filename] ||= new_profile_hash
23
+ end
24
+ end
25
+
26
+ def increment_bytes(filename, bytes)
27
+ @stats[filename][:bytes] += bytes
28
+ end
29
+
30
+ def increment_time(filename, time)
31
+ @stats[filename][:time] += time
32
+ end
33
+
34
+ def increment_count(filename)
35
+ @stats[filename][:count] += 1
36
+ end
37
+
38
+ def stats_table(num_of_rows = 50)
39
+ LiquidRenderer::Table.new(@stats).to_s(num_of_rows)
40
+ end
41
+
42
+ def self.format_error(error, path)
43
+ "#{error.message} in #{path}"
44
+ end
45
+
46
+ # A persistent cache to store and retrieve parsed templates based on the filename
47
+ # via `LiquidRenderer::File#parse`
48
+ #
49
+ # It is emptied when `self.reset` is called.
50
+ def cache
51
+ @cache ||= {}
52
+ end
53
+
54
+ private
55
+
56
+ def normalize_path(filename)
57
+ @normalize_path ||= {}
58
+ @normalize_path[filename] ||= begin
59
+ theme_dir = @site.theme&.root
60
+ case filename
61
+ when %r!\A(#{Regexp.escape(@site.source)}/)(?<rest>.*)!io
62
+ Regexp.last_match(:rest)
63
+ when %r!(/gems/.*)*/gems/(?<dirname>[^/]+)(?<rest>.*)!,
64
+ %r!(?<dirname>[^/]+/lib)(?<rest>.*)!
65
+ "#{Regexp.last_match(:dirname)}#{Regexp.last_match(:rest)}"
66
+ when theme_dir && %r!\A#{Regexp.escape(theme_dir)}/(?<rest>.*)!io
67
+ PathManager.join(@site.theme.basename, Regexp.last_match(:rest))
68
+ when %r!\A/(.*)!
69
+ Regexp.last_match(1)
70
+ else
71
+ filename
72
+ end
73
+ end
74
+ end
75
+
76
+ def new_profile_hash
77
+ Hash.new { |hash, key| hash[key] = 0 }
78
+ end
79
+ end
80
+ end
@@ -1,151 +1,151 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- class LogAdapter
5
- attr_reader :writer, :messages, :level
6
-
7
- LOG_LEVELS = {
8
- :debug => ::Logger::DEBUG,
9
- :info => ::Logger::INFO,
10
- :warn => ::Logger::WARN,
11
- :error => ::Logger::ERROR,
12
- }.freeze
13
-
14
- # Public: Create a new instance of a log writer
15
- #
16
- # writer - Logger compatible instance
17
- # log_level - (optional, symbol) the log level
18
- #
19
- # Returns nothing
20
- def initialize(writer, level = :info)
21
- @messages = []
22
- @writer = writer
23
- self.log_level = level
24
- end
25
-
26
- # Public: Set the log level on the writer
27
- #
28
- # level - (symbol) the log level
29
- #
30
- # Returns nothing
31
- def log_level=(level)
32
- writer.level = level if level.is_a?(Integer) && level.between?(0, 3)
33
- writer.level = LOG_LEVELS[level] ||
34
- raise(ArgumentError, "unknown log level")
35
- @level = level
36
- end
37
-
38
- def adjust_verbosity(options = {})
39
- # Quiet always wins.
40
- if options[:quiet]
41
- self.log_level = :error
42
- elsif options[:verbose]
43
- self.log_level = :debug
44
- end
45
- debug "Logging at level:", LOG_LEVELS.key(writer.level).to_s
46
- debug "Jekyll Version:", Jekyll::VERSION
47
- end
48
-
49
- # Public: Print a debug message
50
- #
51
- # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
52
- # message - the message detail
53
- #
54
- # Returns nothing
55
- def debug(topic, message = nil, &block)
56
- write(:debug, topic, message, &block)
57
- end
58
-
59
- # Public: Print a message
60
- #
61
- # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
62
- # message - the message detail
63
- #
64
- # Returns nothing
65
- def info(topic, message = nil, &block)
66
- write(:info, topic, message, &block)
67
- end
68
-
69
- # Public: Print a message
70
- #
71
- # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
72
- # message - the message detail
73
- #
74
- # Returns nothing
75
- def warn(topic, message = nil, &block)
76
- write(:warn, topic, message, &block)
77
- end
78
-
79
- # Public: Print an error message
80
- #
81
- # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
82
- # message - the message detail
83
- #
84
- # Returns nothing
85
- def error(topic, message = nil, &block)
86
- write(:error, topic, message, &block)
87
- end
88
-
89
- # Public: Print an error message and immediately abort the process
90
- #
91
- # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
92
- # message - the message detail (can be omitted)
93
- #
94
- # Returns nothing
95
- def abort_with(topic, message = nil, &block)
96
- error(topic, message, &block)
97
- abort
98
- end
99
-
100
- # Internal: Build a topic method
101
- #
102
- # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
103
- # message - the message detail
104
- #
105
- # Returns the formatted message
106
- def message(topic, message = nil)
107
- raise ArgumentError, "block or message, not both" if block_given? && message
108
-
109
- message = yield if block_given?
110
- message = message.to_s.gsub(%r!\s+!, " ")
111
- topic = formatted_topic(topic, block_given?)
112
- out = topic + message
113
- messages << out
114
- out
115
- end
116
-
117
- # Internal: Format the topic
118
- #
119
- # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
120
- # colon -
121
- #
122
- # Returns the formatted topic statement
123
- def formatted_topic(topic, colon = false)
124
- "#{topic}#{colon ? ": " : " "}".rjust(20)
125
- end
126
-
127
- # Internal: Check if the message should be written given the log level.
128
- #
129
- # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error
130
- #
131
- # Returns whether the message should be written.
132
- def write_message?(level_of_message)
133
- LOG_LEVELS.fetch(level) <= LOG_LEVELS.fetch(level_of_message)
134
- end
135
-
136
- # Internal: Log a message.
137
- #
138
- # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error
139
- # topic - the String topic or full message
140
- # message - the String message (optional)
141
- # block - a block containing the message (optional)
142
- #
143
- # Returns false if the message was not written, otherwise returns the value of calling
144
- # the appropriate writer method, e.g. writer.info.
145
- def write(level_of_message, topic, message = nil, &block)
146
- return false unless write_message?(level_of_message)
147
-
148
- writer.public_send(level_of_message, message(topic, message, &block))
149
- end
150
- end
151
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class LogAdapter
5
+ attr_reader :writer, :messages, :level
6
+
7
+ LOG_LEVELS = {
8
+ :debug => ::Logger::DEBUG,
9
+ :info => ::Logger::INFO,
10
+ :warn => ::Logger::WARN,
11
+ :error => ::Logger::ERROR,
12
+ }.freeze
13
+
14
+ # Public: Create a new instance of a log writer
15
+ #
16
+ # writer - Logger compatible instance
17
+ # log_level - (optional, symbol) the log level
18
+ #
19
+ # Returns nothing
20
+ def initialize(writer, level = :info)
21
+ @messages = []
22
+ @writer = writer
23
+ self.log_level = level
24
+ end
25
+
26
+ # Public: Set the log level on the writer
27
+ #
28
+ # level - (symbol) the log level
29
+ #
30
+ # Returns nothing
31
+ def log_level=(level)
32
+ writer.level = level if level.is_a?(Integer) && level.between?(0, 3)
33
+ writer.level = LOG_LEVELS[level] ||
34
+ raise(ArgumentError, "unknown log level")
35
+ @level = level
36
+ end
37
+
38
+ def adjust_verbosity(options = {})
39
+ # Quiet always wins.
40
+ if options[:quiet]
41
+ self.log_level = :error
42
+ elsif options[:verbose]
43
+ self.log_level = :debug
44
+ end
45
+ debug "Logging at level:", LOG_LEVELS.key(writer.level).to_s
46
+ debug "Jekyll Version:", Jekyll::VERSION
47
+ end
48
+
49
+ # Public: Print a debug message
50
+ #
51
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
52
+ # message - the message detail
53
+ #
54
+ # Returns nothing
55
+ def debug(topic, message = nil, &block)
56
+ write(:debug, topic, message, &block)
57
+ end
58
+
59
+ # Public: Print a message
60
+ #
61
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
62
+ # message - the message detail
63
+ #
64
+ # Returns nothing
65
+ def info(topic, message = nil, &block)
66
+ write(:info, topic, message, &block)
67
+ end
68
+
69
+ # Public: Print a message
70
+ #
71
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
72
+ # message - the message detail
73
+ #
74
+ # Returns nothing
75
+ def warn(topic, message = nil, &block)
76
+ write(:warn, topic, message, &block)
77
+ end
78
+
79
+ # Public: Print an error message
80
+ #
81
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
82
+ # message - the message detail
83
+ #
84
+ # Returns nothing
85
+ def error(topic, message = nil, &block)
86
+ write(:error, topic, message, &block)
87
+ end
88
+
89
+ # Public: Print an error message and immediately abort the process
90
+ #
91
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
92
+ # message - the message detail (can be omitted)
93
+ #
94
+ # Returns nothing
95
+ def abort_with(topic, message = nil, &block)
96
+ error(topic, message, &block)
97
+ abort
98
+ end
99
+
100
+ # Internal: Build a topic method
101
+ #
102
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
103
+ # message - the message detail
104
+ #
105
+ # Returns the formatted message
106
+ def message(topic, message = nil)
107
+ raise ArgumentError, "block or message, not both" if block_given? && message
108
+
109
+ message = yield if block_given?
110
+ message = message.to_s.gsub(%r!\s+!, " ")
111
+ topic = formatted_topic(topic, block_given?)
112
+ out = topic + message
113
+ messages << out
114
+ out
115
+ end
116
+
117
+ # Internal: Format the topic
118
+ #
119
+ # topic - the topic of the message, e.g. "Configuration file", "Deprecation", etc.
120
+ # colon -
121
+ #
122
+ # Returns the formatted topic statement
123
+ def formatted_topic(topic, colon = false)
124
+ "#{topic}#{colon ? ": " : " "}".rjust(20)
125
+ end
126
+
127
+ # Internal: Check if the message should be written given the log level.
128
+ #
129
+ # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error
130
+ #
131
+ # Returns whether the message should be written.
132
+ def write_message?(level_of_message)
133
+ LOG_LEVELS.fetch(level) <= LOG_LEVELS.fetch(level_of_message)
134
+ end
135
+
136
+ # Internal: Log a message.
137
+ #
138
+ # level_of_message - the Symbol level of message, one of :debug, :info, :warn, :error
139
+ # topic - the String topic or full message
140
+ # message - the String message (optional)
141
+ # block - a block containing the message (optional)
142
+ #
143
+ # Returns false if the message was not written, otherwise returns the value of calling
144
+ # the appropriate writer method, e.g. writer.info.
145
+ def write(level_of_message, topic, message = nil, &block)
146
+ return false unless write_message?(level_of_message)
147
+
148
+ writer.public_send(level_of_message, message(topic, message, &block))
149
+ end
150
+ end
151
+ end