Skip to content

Commit

Permalink
resolves #2535 replace ostruct with internal implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mojavelinux committed Sep 7, 2024
1 parent 3cd22b0 commit c275af9
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 33 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co

== Unreleased

_No changes since previous release._
Improvements::

* replace OpenStruct with internal ThemeData class for storing theme data (#2535)

== 2.3.18 (2024-07-27) - @mojavelinux

Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ gem 'asciidoctor', ENV['ASCIIDOCTOR_VERSION'], require: false if ENV.key? 'ASCII
gem 'asciidoctor-diagram', ENV['ASCIIDOCTOR_DIAGRAM_VERSION'], require: false if ENV.key? 'ASCIIDOCTOR_DIAGRAM_VERSION'
gem 'asciidoctor-kroki', ENV['ASCIIDOCTOR_KROKI_VERSION'], require: false if ENV.key? 'ASCIIDOCTOR_KROKI_VERSION'
gem 'coderay', '~> 1.1.0', require: false
gem 'logger', require: false if (Gem::Version.new RUBY_VERSION) > (Gem::Version.new '3.3.4')
gem 'open-uri-cached', '~> 1.0.0', require: false
gem 'prawn-gmagick', ENV['PRAWN_GMAGICK_VERSION'], require: false if (ENV.key? 'PRAWN_GMAGICK_VERSION') && RUBY_ENGINE == 'ruby'
gem 'pygments.rb', ENV['PYGMENTS_VERSION'], require: false if ENV.key? 'PYGMENTS_VERSION'
Expand All @@ -35,5 +36,6 @@ end

group :coverage do
gem 'deep-cover-core', '~> 1.1.0', require: false
gem 'json', '~> 2.7', require: false if (Gem::Version.new RUBY_VERSION) > (Gem::Version.new '3.3.4')
gem 'simplecov', '~> 0.22.0', require: false
end
57 changes: 57 additions & 0 deletions lib/asciidoctor/pdf/theme_data.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module Asciidoctor
module PDF
class ThemeData
attr_reader :table

def initialize data = nil
@table = (data || {}).transform_keys(&:to_sym)
end

def [] name
@table[name.to_sym]
end

def []= name, value
@table[name.to_sym] = value
end

def each_pair &block
@table.each_pair(&block)
end

def eql? other
@table.to_h.eql? other.to_h
end

def delete_field name
@table.delete name
end

def dup
ThemeData.new @table
end

def method_missing name, *args
if (name_str = name.to_s).end_with? '='
@table[name_str.chop.to_sym] = args[0]
else
@table[name]
end
end

def respond_to? name, _include_all = false
@table.key? name.to_sym
end

def respond_to_missing? name, _include_all = false
@table.key? name.to_sym
end

def to_h
@table
end
end
end
end
12 changes: 6 additions & 6 deletions lib/asciidoctor/pdf/theme_loader.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require 'ostruct'
require_relative 'theme_data'
require_relative 'measurements'

module Asciidoctor
Expand Down Expand Up @@ -69,7 +69,7 @@ def self.resolve_theme_asset asset_path, theme_dir = nil
# NOTE: base theme is loaded "as is" (no post-processing)
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 }
(ThemeData.new ::YAML.safe_load io, filename: BaseThemePath).tap {|theme| theme.__dir__ = ThemesDir }
end
end

Expand All @@ -78,7 +78,7 @@ def self.load_theme theme_name = nil, theme_dir = nil
if theme_path == BaseThemePath
load_base_theme
else
theme_data = load_file theme_path, (::OpenStruct.new base_font_size: 12), theme_dir
theme_data = load_file theme_path, (ThemeData.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
Expand All @@ -102,12 +102,12 @@ def self.load_file filename, theme_data = nil, theme_dir = nil
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
(loaded = (theme_data ||= ThemeData.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
theme_data = ThemeData.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
Expand All @@ -123,7 +123,7 @@ def self.load_file filename, theme_data = nil, theme_dir = nil
end

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)
::Hash === hash ? hash.reduce(theme_data || ThemeData.new) {|data, (key, val)| process_entry key, val, data, true } : (theme_data || ThemeData.new)
end

private
Expand Down
52 changes: 26 additions & 26 deletions spec/theme_loader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@
it 'should not fail if theme data is empty' do
theme = subject.new.load ''
(expect theme).not_to be_nil
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.to_h).to be_empty
end

it 'should not fail if theme data is falsy' do
theme = subject.new.load false
(expect theme).not_to be_nil
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.to_h).to be_empty
end

# NOTE: this API is not used by the converter
it 'should use specified theme data if raw theme data is nil' do
theme_data = OpenStruct.new
theme_data = Asciidoctor::PDF::ThemeData.new
theme_data.base_font_color = '222222'
theme = subject.new.load nil, theme_data
(expect theme).to be theme_data
end

it 'should store flattened keys in OpenStruct' do
it 'should store flattened keys in Asciidoctor::PDF::ThemeData' do
theme_data = YAML.safe_load <<~'EOS'
page:
size: A4
Expand All @@ -41,7 +41,7 @@
font_style: bold
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme).to respond_to :page_size
(expect theme).to respond_to :base_font_family
(expect theme).to respond_to :base_border_width
Expand All @@ -62,7 +62,7 @@
size: 24
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.admonition_icon_tip).to be_a Hash
(expect theme.admonition_icon_tip).to eql name: 'far-lightbulb', stroke_color: 'FFFF00', size: 24
(expect theme.admonition_icon_note).to be_a Hash
Expand All @@ -76,7 +76,7 @@
advice: ~
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.admonition_icon_advice).to be_nil
end

Expand All @@ -93,7 +93,7 @@
stroke-color: FFFF00
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme).to respond_to :page_size
(expect theme).to respond_to :base_font_family
(expect theme).to respond_to :abstract_title_font_size
Expand All @@ -112,7 +112,7 @@
color: 0000ff
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme).to respond_to 'role_flaming-red_font_color'
(expect theme['role_flaming-red_font_color']).to eql 'FF0000'
(expect theme).to respond_to 'role_so-very-blue_font_color'
Expand All @@ -126,7 +126,7 @@
font-style: bold
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme).to respond_to 'role_BOLD_font_style'
(expect theme['role_BOLD_font_style']).to eql 'bold'
end
Expand All @@ -148,7 +148,7 @@
content: 2 * 2
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.menu_caret_content).to eql '[">"]'
(expect theme.ulist_marker_disc_content).to eql '0'
(expect theme.footer_recto_left_content).to eql 'true'
Expand All @@ -172,7 +172,7 @@
text-align: $heading-align
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.base_align).to be_nil
(expect theme.base_text_align).to eql 'center'
(expect theme.heading_align).to be_nil
Expand All @@ -197,7 +197,7 @@
end: $table-caption-side
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.table_caption_side).to be_nil
(expect theme.table_caption_end).to eql 'bottom'
(expect theme.image_caption_end).to eql 'bottom'
Expand All @@ -214,7 +214,7 @@
item-spacing: $outline_list_item_spacing / 2
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.outline_list_item_spacing).to be_nil
(expect theme.list_item_spacing).to eql 6
(expect theme.footnotes_margin_top).to eql theme.list_item_spacing
Expand All @@ -232,7 +232,7 @@
font-color: $blockquote-font-color
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.blockquote_font_color).to be_nil
(expect theme.quote_font_color).to eql '4A4A4A'
(expect theme.quote_border_color).to eql theme.quote_font_color
Expand All @@ -249,7 +249,7 @@
font-color: $key-border-color
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.key_border_color).to be_nil
(expect theme.kbd_border_color).to eql 'CCCCCC'
(expect theme.kbd_font_color).to eql theme.kbd_border_color
Expand All @@ -265,7 +265,7 @@
font-family: $literal-font-family
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.literal_font_family).to be_nil
(expect theme.codespan_font_family).to eql 'M+ 1mn'
(expect theme.verse_font_family).to eql 'M+ 1mn'
Expand All @@ -284,7 +284,7 @@
padding: [6, 12, -6, 14]
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.example_padding).to eql [12, 12, 12, 12]
(expect theme.quote_padding).to eql [0, 12, 0, 14]
(expect theme.sidebar_padding).to eql [12, 12, 12, 12]
Expand All @@ -297,7 +297,7 @@
padding: [-3, 12, -3, 14]
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.quote_padding).to eql [-3, 12, -3, 14]
end

Expand All @@ -315,7 +315,7 @@
content: $page_size
EOS
theme = subject.new.load theme_data
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.footer_verso_left_content).to eql '2 * 12'
(expect theme.footer_verso_right_content).to eql 'A4'
end
Expand Down Expand Up @@ -477,16 +477,16 @@
describe '.load_file' do
it 'should not fail if theme file is empty' do
theme = subject.load_file fixture_file 'empty-theme.yml'
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
theme.delete_field :__loaded__
(expect theme).to eql OpenStruct.new
(expect theme).to eql Asciidoctor::PDF::ThemeData.new
end

it 'should not fail if theme file resolves to nil' do
theme = subject.load_file fixture_file 'nil-theme.yml'
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
theme.delete_field :__loaded__
(expect theme).to eql OpenStruct.new
(expect theme).to eql Asciidoctor::PDF::ThemeData.new
end

it 'should throw error that includes filename and reason if theme is indented using tabs' do
Expand Down Expand Up @@ -726,7 +726,7 @@
it 'should load base theme if theme name is base' do
theme = subject.load_theme 'base'
(expect theme).not_to be_nil
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.base_font_family).to eql 'Helvetica'
(expect theme.codespan_font_family).to eql 'Courier'
(expect theme).to eql subject.load_base_theme
Expand All @@ -735,7 +735,7 @@
it 'should load default theme if no arguments are given' do
theme = subject.load_theme
(expect theme).not_to be_nil
(expect theme).to be_an OpenStruct
(expect theme).to be_an Asciidoctor::PDF::ThemeData
(expect theme.base_font_family).to eql 'Noto Serif'
(expect theme.link_font_color).to eql '428BCA'
end
Expand Down

0 comments on commit c275af9

Please sign in to comment.