-
Notifications
You must be signed in to change notification settings - Fork 338
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enables many of the currently disabled rubocop checks and fixes them. The biggest change is in the `copy_images` extension which is now split into two classes, on that processes blocks looking for candidates to copy and one that does the actual copying. Beyond that I've converted many tests from blocks into guards. Rubocop seems to really like guards and I find them pretty readble, partially because they force you to create a new method in some cases and those methods can have nice names.
- Loading branch information
Showing
20 changed files
with
318 additions
and
294 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'csv' | ||
require 'fileutils' | ||
require 'set' | ||
|
||
module CopyImages | ||
## | ||
# Handles finding images, copying them, and *not* copying them if they have | ||
# already been copied. | ||
class Copier | ||
include Asciidoctor::Logging | ||
|
||
def initialize | ||
@copied = Set[] | ||
end | ||
|
||
def copy_image(block, uri) | ||
return unless @copied.add? uri # Skip images we've copied before | ||
|
||
source = find_source block, uri | ||
return unless source # Skip images we can't find | ||
|
||
logger.info message_with_context "copying #{source}", :source_location => block.source_location | ||
copy_image_proc = block.document.attr 'copy_image' | ||
if copy_image_proc | ||
# Delegate to a proc for copying if one is defined. Used for testing. | ||
copy_image_proc.call(uri, source) | ||
else | ||
destination = ::File.join block.document.options[:to_dir], uri | ||
destination_dir = ::File.dirname destination | ||
FileUtils.mkdir_p destination_dir | ||
FileUtils.cp source, destination | ||
end | ||
end | ||
|
||
## | ||
# Does a breadth first search starting at the base_dir of the document and | ||
# any referenced resources. This isn't super efficient but it is how a2x works | ||
# and we strive for compatibility. | ||
# | ||
def find_source(block, uri) | ||
to_check = [block.document.base_dir] | ||
checked = [] | ||
|
||
resources = block.document.attr 'resources' | ||
if resources && !resources.empty? | ||
begin | ||
to_check += CSV.parse_line(resources) | ||
rescue CSV::MalformedCSVError => error | ||
logger.error message_with_context "Error loading [resources]: #{error}", | ||
:source_location => block.source_location | ||
end | ||
end | ||
|
||
while (dir = to_check.shift) | ||
checked << block.normalize_system_path(uri, dir) | ||
return checked.last if File.readable? checked.last | ||
next unless Dir.exist?(dir) | ||
|
||
Dir.new(dir).each do |f| | ||
next if ['.', '..'].include? f | ||
|
||
f = File.join(dir, f) | ||
to_check << f if File.directory?(f) | ||
end | ||
end | ||
|
||
# We'll skip images we can't find but we should log something about it so | ||
# we can fix them. | ||
checked.sort! do |lhs, rhs| | ||
by_depth = lhs.scan(%r{/}).count <=> rhs.scan(%r{/}).count | ||
if by_depth != 0 | ||
by_depth | ||
else | ||
lhs <=> rhs | ||
end | ||
end | ||
logger.warn message_with_context "can't read image at any of #{checked}", :source_location => block.source_location | ||
nil | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,138 +1,92 @@ | ||
require 'csv' | ||
require 'fileutils' | ||
require 'set' | ||
# frozen_string_literal: true | ||
|
||
require_relative '../scaffold.rb' | ||
require_relative 'copier.rb' | ||
|
||
include Asciidoctor | ||
|
||
## | ||
# Copies images that are referenced into the same directory as the output files. | ||
# | ||
# It finds the images by looking in a comma separated list of directories | ||
# defined by the `resources` attribute. | ||
# | ||
# It can also be configured to copy the images that number callout lists by | ||
# setting `copy-callout-images` to the file extension of the images to copy. | ||
# | ||
class CopyImages < TreeProcessorScaffold | ||
include Logging | ||
ADMONITION_IMAGE_FOR_REVISION_FLAG = { | ||
'added' => 'note', | ||
'changed' => 'note', | ||
'deleted' => 'warning', | ||
} | ||
|
||
def initialize(name) | ||
super | ||
@copied = Set[] | ||
end | ||
module CopyImages | ||
## | ||
# Copies images that are referenced into the same directory as the output files. | ||
# | ||
# It finds the images by looking in a comma separated list of directories | ||
# defined by the `resources` attribute. | ||
# | ||
# It can also be configured to copy the images that number callout lists by | ||
# setting `copy-callout-images` to the file extension of the images to copy. | ||
# | ||
# It can also be configured to copy the that decoration admonitions by | ||
# setting `copy-admonition-images` to the file extension of the images | ||
# to copy. | ||
# | ||
class CopyImages < TreeProcessorScaffold | ||
include Asciidoctor::Logging | ||
|
||
def process_block(block) | ||
if block.context == :image | ||
uri = block.image_uri(block.attr 'target') | ||
return if Helpers.uriish? uri # Skip external images | ||
ADMONITION_IMAGE_FOR_REVISION_FLAG = { | ||
'added' => 'note', | ||
'changed' => 'note', | ||
'deleted' => 'warning', | ||
} | ||
|
||
copy_image block, uri | ||
return | ||
end | ||
callout_extension = block.document.attr 'copy-callout-images' | ||
if callout_extension | ||
if block.parent && block.parent.context == :colist | ||
coids = block.attr('coids') | ||
return unless coids | ||
|
||
coids.scan(/CO(?:\d+)-(\d+)/) { | ||
copy_image block, "images/icons/callouts/#{$1}.#{callout_extension}" | ||
} | ||
return | ||
end | ||
def initialize(name) | ||
super | ||
@copier = Copier.new | ||
end | ||
admonition_extension = block.document.attr 'copy-admonition-images' | ||
if admonition_extension | ||
if block.context == :admonition | ||
# The image for a standard admonition comes from the style | ||
style = block.attr 'style' | ||
return unless style | ||
|
||
copy_image block, "images/icons/#{style.downcase}.#{admonition_extension}" | ||
return | ||
end | ||
# The image for a change admonition comes from the revisionflag | ||
revisionflag = block.attr 'revisionflag' | ||
if revisionflag | ||
admonition_image = ADMONITION_IMAGE_FOR_REVISION_FLAG[revisionflag] | ||
if admonition_image | ||
copy_image block, "images/icons/#{admonition_image}.#{admonition_extension}" | ||
else | ||
logger.warn message_with_context "unknow revisionflag #{revisionflag}", :source_location => block.source_location | ||
end | ||
return | ||
end | ||
|
||
def process_block(block) | ||
process_image block | ||
process_callout block | ||
process_admonition block | ||
end | ||
end | ||
|
||
def copy_image(block, uri) | ||
return unless @copied.add? uri # Skip images we've copied before | ||
|
||
source = find_source block, uri | ||
return unless source # Skip images we can't find | ||
|
||
logger.info message_with_context "copying #{source}", :source_location => block.source_location | ||
copy_image_proc = block.document.attr 'copy_image' | ||
if copy_image_proc | ||
# Delegate to a proc for copying if one is defined. Used for testing. | ||
copy_image_proc.call(uri, source) | ||
else | ||
destination = ::File.join block.document.options[:to_dir], uri | ||
destination_dir = ::File.dirname destination | ||
FileUtils.mkdir_p destination_dir | ||
FileUtils.cp source, destination | ||
def process_image(block) | ||
return unless block.context == :image | ||
|
||
uri = block.image_uri(block.attr 'target') | ||
return if Asciidoctor::Helpers.uriish? uri # Skip external images | ||
|
||
@copier.copy_image block, uri | ||
end | ||
end | ||
|
||
## | ||
# Does a breadth first search starting at the base_dir of the document and | ||
# any referenced resources. This isn't super efficient but it is how a2x works | ||
# and we strive for compatibility. | ||
# | ||
def find_source(block, uri) | ||
to_check = [block.document.base_dir] | ||
checked = [] | ||
|
||
resources = block.document.attr 'resources' | ||
if resources && !resources.empty? | ||
begin | ||
to_check += CSV.parse_line(resources) | ||
rescue CSV::MalformedCSVError => error | ||
logger.error message_with_context "Error loading [resources]: #{error}", | ||
:source_location => block.source_location | ||
def process_callout(block) | ||
callout_extension = block.document.attr 'copy-callout-images' | ||
return unless callout_extension | ||
return unless block.parent && block.parent.context == :colist | ||
|
||
coids = block.attr('coids') | ||
return unless coids | ||
|
||
coids.scan(/CO(?:\d+)-(\d+)/) do | ||
@copier.copy_image block, "images/icons/callouts/#{$1}.#{callout_extension}" | ||
end | ||
end | ||
|
||
while (dir = to_check.shift) | ||
checked << block.normalize_system_path(uri, dir) | ||
return checked.last if File.readable? checked.last | ||
next unless Dir.exist?(dir) | ||
def process_admonition(block) | ||
admonition_extension = block.document.attr 'copy-admonition-images' | ||
return unless admonition_extension | ||
|
||
Dir.new(dir).each { |f| | ||
next if ['.', '..'].include? f | ||
process_standard_admonition admonition_extension, block | ||
process_change_admonition admonition_extension, block | ||
end | ||
|
||
def process_standard_admonition(admonition_extension, block) | ||
return unless block.context == :admonition | ||
|
||
f = File.join(dir, f) | ||
to_check << f if File.directory?(f) | ||
} | ||
# The image for a standard admonition comes from the style | ||
style = block.attr 'style' | ||
return unless style | ||
|
||
@copier.copy_image block, "images/icons/#{style.downcase}.#{admonition_extension}" | ||
end | ||
|
||
# We'll skip images we can't find but we should log something about it so | ||
# we can fix them. | ||
checked.sort! { |lhs, rhs| | ||
by_depth = lhs.scan(/\//).count <=> rhs.scan(/\//).count | ||
if by_depth != 0 | ||
by_depth | ||
def process_change_admonition(admonition_extension, block) | ||
revisionflag = block.attr 'revisionflag' | ||
return unless revisionflag | ||
|
||
admonition_image = ADMONITION_IMAGE_FOR_REVISION_FLAG[revisionflag] | ||
if admonition_image | ||
@copier.copy_image block, "images/icons/#{admonition_image}.#{admonition_extension}" | ||
else | ||
lhs <=> rhs | ||
logger.warn message_with_context "unknow revisionflag #{revisionflag}", :source_location => block.source_location | ||
end | ||
} | ||
logger.warn message_with_context "can't read image at any of #{checked}", :source_location => block.source_location | ||
nil | ||
end | ||
end | ||
end |
Oops, something went wrong.