class Asciidoctor::PDF::ThemeLoader
Constants
- AddSubtractOpRx
- BaseThemePath
- DataDir
- DefaultThemePath
- FontsDir
- HexColorEntryRx
- LoneVariableRx
- MultiplyDivideOpRx
- PrecisionFuncRx
- ThemesDir
- VariableRx
Public Class Methods
load_base_theme()
click to toggle source
NOTE base theme is loaded “as is” (no post-processing)
# File lib/asciidoctor-pdf/theme_loader.rb, line 63 def self.load_base_theme ::OpenStruct.new(::SafeYAML.load_file BaseThemePath) end
load_file(filename, theme_data = nil, theme_path = nil)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 76 def self.load_file filename, theme_data = nil, theme_path = nil yaml_data = ::SafeYAML.load (::File.read filename, encoding: ::Encoding::UTF_8).each_line.map {|l| l.sub HexColorEntryRx, '\k<k>: \'\k<v>\'' }.join if ::Hash === yaml_data && (extend_files = yaml_data.delete 'extends') [*extend_files].each do |extend_file| if extend_file == 'default' extend_file = resolve_theme_file extend_file, (extend_theme_path = ThemesDir) elsif extend_file.start_with? './' extend_file = resolve_theme_file extend_file, (extend_theme_path = (::File.dirname ::File.absolute_path filename)) else extend_file = resolve_theme_file extend_file, (extend_theme_path = theme_path) end theme_data = load_file extend_file, theme_data, extend_theme_path end end self.new.load yaml_data, theme_data, theme_path end
load_theme(theme_name = nil, theme_path = nil, opts = {})
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 67 def self.load_theme theme_name = nil, theme_path = nil, opts = {} if (theme_file = resolve_theme_file theme_name, theme_path) == BaseThemePath || (theme_file != DefaultThemePath && (opts.fetch :apply_base_theme, true)) theme_data = load_base_theme end theme_file == BaseThemePath ? theme_data : (load_file theme_file, theme_data, theme_path) end
resolve_theme_asset(asset_path, theme_path = nil)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 58 def self.resolve_theme_asset asset_path, theme_path = nil ::File.expand_path asset_path, (theme_path || ThemesDir) end
resolve_theme_file(theme_name = nil, theme_path = nil)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 45 def self.resolve_theme_file theme_name = nil, theme_path = nil theme_name ||= 'default' # if .yml extension is given, don't append -theme.yml if (theme_name.end_with? '.yml') # FIXME restrict to jail! # QUESTION why are we not using expand_path in this case? theme_path ? (::File.join theme_path, theme_name) : theme_name else # QUESTION should we append '-theme.yml' or just '.yml'? ::File.expand_path %(#{theme_name}-theme.yml), (theme_path || ThemesDir) end end
Public Instance Methods
load(hash, theme_data = nil, theme_path = nil)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 93 def load hash, theme_data = nil, theme_path = nil theme_data ||= ::OpenStruct.new return theme_data unless ::Hash === hash base_code_font_family = theme_data.delete 'code_font_family' base_conum_font_family = theme_data.delete 'conum_font_family' hash.inject(theme_data) {|data, (key, val)| process_entry key, val, data } # NOTE remap legacy running content keys (e.g., header_recto_content_left => header_recto_left_content) %w(header_recto header_verso footer_recto footer_verso).each do |periphery_face| %w(left center right).each do |align| if (val = theme_data.delete %(#{periphery_face}_content_#{align})) theme_data[%(#{periphery_face}_#{align}_content)] = val end end end theme_data.base_align ||= 'left' theme_data.code_font_family ||= (theme_data.literal_font_family || base_code_font_family) theme_data.conum_font_family ||= (theme_data.literal_font_family || base_conum_font_family) # QUESTION should we do any other post-load calculations or defaults? theme_data end
Private Instance Methods
evaluate(expr, vars)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 138 def evaluate expr, vars case expr when ::String evaluate_math(expand_vars expr, vars) when ::Array expr.map {|e| evaluate e, vars } else expr end end
evaluate_math(expr)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 174 def evaluate_math expr return expr if !(::String === expr) || ColorValue === expr # resolve measurement values (e.g., 0.5in => 36) # QUESTION should we round the value? perhaps leave that to the precision functions # NOTE leave % as a string; handled by converter for now expr = resolve_measurement_values(original = expr) while true result = expr.gsub(MultiplyDivideOpRx) { $1.to_f.send $2.to_sym, $3.to_f } unchanged = (result == expr) expr = result break if unchanged end while true result = expr.gsub(AddSubtractOpRx) { $1.to_f.send $2.to_sym, $3.to_f } unchanged = (result == expr) expr = result break if unchanged end if (expr.end_with? ')') && expr =~ PrecisionFuncRx op = $1 offset = op.length + 1 expr = expr[offset...-1].to_f.send op.to_sym end if expr == original original else (int_val = expr.to_i) == (flt_val = expr.to_f) ? int_val : flt_val end end
expand_vars(expr, vars)
click to toggle source
NOTE we assume expr is a String
# File lib/asciidoctor-pdf/theme_loader.rb, line 150 def expand_vars expr, vars if (idx = (expr.index '$')) if idx == 0 && expr =~ LoneVariableRx if vars.respond_to? $1 vars[$1] else logger.warn %(unknown variable reference in PDF theme: $#{$1}) expr end else expr.gsub(VariableRx) { if vars.respond_to? $1 vars[$1] else logger.warn %(unknown variable reference in PDF theme: $#{$1}) $& end } end else expr end end
process_entry(key, val, data)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 116 def process_entry key, val, data if key.start_with? 'font_' data[key] = val elsif key.start_with? 'admonition_icon_' data[key] = (val || {}).map do |(key2, val2)| [key2.to_sym, (key2.end_with? '_color') ? to_color(evaluate val2, data) : (evaluate val2, data)] end.to_h elsif ::Hash === val val.each do |key2, val2| process_entry %(#{key}_#{key2.tr '-', '_'}), val2, data end elsif key.end_with? '_color' # QUESTION do we need to evaluate_math in this case? data[key] = to_color(evaluate val, data) elsif %(#{key.chomp '_'}_).include? '_content_' data[key] = (expand_vars val.to_s, data).to_s else data[key] = evaluate val, data end data end
to_color(value)
click to toggle source
# File lib/asciidoctor-pdf/theme_loader.rb, line 204 def to_color value case value when ColorValue # already converted return value when ::String if value == 'transparent' # FIXME should we have a TransparentColorValue class? return HexColorValue.new value elsif value.length == 6 return HexColorValue.new value.upcase end when ::Array case value.length # CMYK value when 4 value = value.map do |e| if ::Numeric === e e = e * 100.0 unless e > 1 else e = e.to_s.chomp('%').to_f end e == (int_e = e.to_i) ? int_e : e end case value when [0, 0, 0, 0] return HexColorValue.new 'FFFFFF' when [100, 100, 100, 100] return HexColorValue.new '000000' else value.extend CmykColorValue return value end # RGB value when 3 return HexColorValue.new value.map {|e| '%02X' % e }.join # Nonsense array value; flatten to string else value = value.join end else # Unknown type; coerce to a string value = value.to_s end value = case value.length when 6 value when 3 # expand hex shorthand (e.g., f00 -> ff0000) value.each_char.map {|c| c * 2 }.join else # truncate or pad with leading zeros (e.g., ff -> 0000ff) value[0..5].rjust 6, '0' end HexColorValue.new value.upcase end