Class: Asciidoctor::PDF::ThemeLoader

Inherits:
Object
  • Object
show all
Includes:
Logging, Measurements
Defined in:
lib/asciidoctor/pdf/theme_loader.rb

Defined Under Namespace

Modules: CMYKColorValue, ColorValue Classes: HexColorValue, TransparentColorValue

Constant Summary collapse

DataDir =
::File.absolute_path %(#{__dir__}/../../../data)
ThemesDir =
::File.join DataDir, 'themes'
FontsDir =
::File.join DataDir, 'fonts'
BaseThemePath =
::File.join ThemesDir, 'base-theme.yml'
BundledThemeNames =
(::Dir.children ThemesDir).map {|it| it.slice 0, it.length - 10 }
DeprecatedCategoryKeys =
{ 'blockquote' => 'quote', 'key' => 'kbd', 'literal' => 'codespan', 'outline_list' => 'list' }
DeprecatedKeys =
{ 'table_caption_side' => 'table_caption_end' }.tap {|accum| %w(base heading heading_h1 heading_h2 heading_h3 heading_h4 heading_h5 heading_h6 title_page abstract abstract_title admonition_label sidebar_title toc_title).each {|prefix| accum[%(#{prefix}_align)] = %(#{prefix}_text_align) } }
PaddingBottomHackKeys =
%w(example_padding quote_padding sidebar_padding verse_padding)
VariableRx =
/\$([a-z0-9_-]+)/
LoneVariableRx =
/^\$([a-z0-9_-]+)$/
HexColorEntryRx =
/^(?<k> *\p{Graph}+): +(?!null$)(?<q>["']?)(?<h>#)?(?<v>\h\h\h\h{0,3})\k<q> *(?:#.*)?$/
MultiplyDivideOpRx =
%r((-?\d+(?:\.\d+)?) +([*/^]) +(-?\d+(?:\.\d+)?))
AddSubtractOpRx =
/(-?\d+(?:\.\d+)?) +([+-]) +(-?\d+(?:\.\d+)?)/
PrecisionFuncRx =
/^(round|floor|ceil)\(/
RelativeUnitsRx =
/(?<=\d)(r?em)(?= )/
RoleAlignKeyRx =
/(?:_text)?_align$/

Constants included from Measurements

Measurements::InsetMeasurementValueRx, Measurements::MeasurementValueHintRx, Measurements::MeasurementValueRx

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Measurements

#resolve_measurement_values, #str_to_pt, #to_pt

Class Method Details

.load_base_themeObject

NOTE: base theme is loaded “as is” (no post-processing)



71
72
73
74
75
# File 'lib/asciidoctor/pdf/theme_loader.rb', line 71

def self.load_base_theme
  ::File.open BaseThemePath, mode: 'r:UTF-8' do |io|
    (::OpenStruct.new ::YAML.safe_load io, filename: BaseThemePath).tap {|theme| theme.__dir__ = ThemesDir }
  end
end

.load_file(filename, theme_data = nil, theme_dir = nil) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/asciidoctor/pdf/theme_loader.rb', line 100

def self.load_file filename, theme_data = nil, theme_dir = nil
  data = ::File.read filename, mode: 'r:UTF-8', newline: :universal
  data = data.each_line.map do |line|
    line.sub(HexColorEntryRx) { %(#{(m = $~)[:k]}: #{m[:h] || (m[:k].end_with? 'color') ? "'#{m[:v]}'" : m[:v]}) }
  end.join unless (::File.dirname filename) == ThemesDir
  yaml_data = ::YAML.safe_load data, aliases: true, filename: filename
  (loaded = (theme_data ||= ::OpenStruct.new).__loaded__ ||= ::Set.new).add filename
  if ::Hash === yaml_data && (extends = yaml_data.delete 'extends')
    (Array extends).each do |extend_path|
      extend_path = extend_path.slice 0, extend_path.length - 11 if (force = extend_path.end_with? ' !important')
      if extend_path == 'base'
        theme_data = ::OpenStruct.new theme_data.to_h.merge load_base_theme.to_h if (loaded.add? 'base') || force
        next
      elsif BundledThemeNames.include? extend_path
        extend_path, extend_theme_dir = resolve_theme_file extend_path, ThemesDir
      elsif extend_path.start_with? './'
        extend_path, extend_theme_dir = resolve_theme_file extend_path, (::File.dirname filename)
      else
        extend_path, extend_theme_dir = resolve_theme_file extend_path, theme_dir
      end
      theme_data = load_file extend_path, theme_data, extend_theme_dir if (loaded.add? extend_path) || force
    end
  end
  new.load yaml_data, theme_data
end

.load_theme(theme_name = nil, theme_dir = nil) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/asciidoctor/pdf/theme_loader.rb', line 77

def self.load_theme theme_name = nil, theme_dir = nil
  theme_path, theme_dir = resolve_theme_file theme_name, theme_dir
  if theme_path == BaseThemePath
    load_base_theme
  else
    theme_data = load_file theme_path, (::OpenStruct.new base_font_size: 12), theme_dir
    unless (::File.dirname theme_path) == ThemesDir
      theme_data.base_text_align ||= 'left'
      theme_data.base_line_height ||= 1
      theme_data.base_font_color ||= '000000'
      theme_data.code_font_family ||= (theme_data.codespan_font_family || 'Courier')
      theme_data.conum_font_family ||= (theme_data.codespan_font_family || 'Courier')
      if (heading_font_family = theme_data.heading_font_family)
        theme_data.abstract_title_font_family ||= heading_font_family
        theme_data.sidebar_title_font_family ||= heading_font_family
      end
    end
    theme_data.delete_field :__loaded__
    theme_data.__dir__ = theme_dir
    theme_data
  end
end

.resolve_theme_asset(asset_path, theme_dir = nil) ⇒ Object



66
67
68
# File 'lib/asciidoctor/pdf/theme_loader.rb', line 66

def self.resolve_theme_asset asset_path, theme_dir = nil
  ::File.absolute_path asset_path, (theme_dir || ThemesDir)
end

.resolve_theme_file(theme_name = nil, theme_dir = nil) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/asciidoctor/pdf/theme_loader.rb', line 49

def self.resolve_theme_file theme_name = nil, theme_dir = nil
  # NOTE: if .yml extension is given, assume it's a path (don't append -theme.yml)
  if theme_name&.end_with? '.yml'
    # FIXME: restrict to jail!
    if theme_dir
      theme_path = ::File.absolute_path theme_name, (theme_dir = ::File.expand_path theme_dir)
    else
      theme_path = ::File.expand_path theme_name
      theme_dir = ::File.dirname theme_path
    end
  else
    theme_dir = theme_dir ? (::File.expand_path theme_dir) : ThemesDir
    theme_path = ::File.absolute_path ::File.join theme_dir, %(#{theme_name || 'default'}-theme.yml)
  end
  [theme_path, theme_dir]
end

Instance Method Details

#load(hash, theme_data = nil) ⇒ Object



126
127
128
# File 'lib/asciidoctor/pdf/theme_loader.rb', line 126

def load hash, theme_data = nil
  ::Hash === hash ? hash.reduce(theme_data || ::OpenStruct.new) {|data, (key, val)| process_entry key, val, data, true } : (theme_data || ::OpenStruct.new)
end