This commit is contained in:
162
lib/notare/builder.rb
Normal file
162
lib/notare/builder.rb
Normal file
@@ -0,0 +1,162 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Notare
|
||||
module Builder
|
||||
def p(text = nil, style: nil, &block)
|
||||
para = Nodes::Paragraph.new(style: resolve_style(style))
|
||||
if block
|
||||
with_target(para, &block)
|
||||
elsif text
|
||||
para.add_run(Nodes::Run.new(text, **current_formatting))
|
||||
end
|
||||
@nodes << para
|
||||
end
|
||||
|
||||
def text(value, style: nil)
|
||||
formatting = current_formatting.merge(style: resolve_style(style))
|
||||
@current_target.add_run(Nodes::Run.new(value, **formatting))
|
||||
end
|
||||
|
||||
# Heading shortcuts
|
||||
def h1(text = nil, &block)
|
||||
p(text, style: :heading1, &block)
|
||||
end
|
||||
|
||||
def h2(text = nil, &block)
|
||||
p(text, style: :heading2, &block)
|
||||
end
|
||||
|
||||
def h3(text = nil, &block)
|
||||
p(text, style: :heading3, &block)
|
||||
end
|
||||
|
||||
def h4(text = nil, &block)
|
||||
p(text, style: :heading4, &block)
|
||||
end
|
||||
|
||||
def h5(text = nil, &block)
|
||||
p(text, style: :heading5, &block)
|
||||
end
|
||||
|
||||
def h6(text = nil, &block)
|
||||
p(text, style: :heading6, &block)
|
||||
end
|
||||
|
||||
def image(path, width: nil, height: nil)
|
||||
validate_image_path!(path)
|
||||
img = register_image(path, width: width, height: height)
|
||||
@current_target.add_run(img)
|
||||
end
|
||||
|
||||
def b(&block)
|
||||
with_format(:bold, &block)
|
||||
end
|
||||
|
||||
def i(&block)
|
||||
with_format(:italic, &block)
|
||||
end
|
||||
|
||||
def u(&block)
|
||||
with_format(:underline, &block)
|
||||
end
|
||||
|
||||
def ul(&block)
|
||||
list(:bullet, &block)
|
||||
end
|
||||
|
||||
def ol(&block)
|
||||
list(:number, &block)
|
||||
end
|
||||
|
||||
def li(text = nil, &block)
|
||||
item = Nodes::ListItem.new([], list_type: @current_list.type, num_id: @current_list.num_id)
|
||||
if block
|
||||
with_target(item, &block)
|
||||
elsif text
|
||||
item.add_run(Nodes::Run.new(text, **current_formatting))
|
||||
end
|
||||
@current_list.add_item(item)
|
||||
end
|
||||
|
||||
def table(&block)
|
||||
tbl = Nodes::Table.new
|
||||
previous_table = @current_table
|
||||
@current_table = tbl
|
||||
block.call
|
||||
@current_table = previous_table
|
||||
@nodes << tbl
|
||||
end
|
||||
|
||||
def tr(&block)
|
||||
row = Nodes::TableRow.new
|
||||
previous_row = @current_row
|
||||
@current_row = row
|
||||
block.call
|
||||
@current_row = previous_row
|
||||
@current_table.add_row(row)
|
||||
end
|
||||
|
||||
def td(text = nil, &block)
|
||||
cell = Nodes::TableCell.new
|
||||
if block
|
||||
with_target(cell, &block)
|
||||
elsif text
|
||||
cell.add_run(Nodes::Run.new(text, **current_formatting))
|
||||
end
|
||||
@current_row.add_cell(cell)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def list(type, &block)
|
||||
@num_id_counter ||= 0
|
||||
@num_id_counter += 1
|
||||
|
||||
list_node = Nodes::List.new(type: type, num_id: @num_id_counter)
|
||||
previous_list = @current_list
|
||||
@current_list = list_node
|
||||
block.call
|
||||
@current_list = previous_list
|
||||
@nodes << list_node
|
||||
end
|
||||
|
||||
def with_format(format, &block)
|
||||
@format_stack ||= []
|
||||
@format_stack.push(format)
|
||||
block.call
|
||||
@format_stack.pop
|
||||
end
|
||||
|
||||
def with_target(target, &block)
|
||||
previous_target = @current_target
|
||||
@current_target = target
|
||||
block.call
|
||||
@current_target = previous_target
|
||||
end
|
||||
|
||||
def current_formatting
|
||||
@format_stack ||= []
|
||||
{
|
||||
bold: @format_stack.include?(:bold),
|
||||
italic: @format_stack.include?(:italic),
|
||||
underline: @format_stack.include?(:underline)
|
||||
}
|
||||
end
|
||||
|
||||
def validate_image_path!(path)
|
||||
raise ArgumentError, "Image file not found: #{path}" unless File.exist?(path)
|
||||
|
||||
ext = File.extname(path).downcase
|
||||
return if %w[.png .jpg .jpeg].include?(ext)
|
||||
|
||||
raise ArgumentError, "Unsupported image format: #{ext}. Use PNG or JPEG."
|
||||
end
|
||||
|
||||
def resolve_style(style_or_name)
|
||||
return nil if style_or_name.nil?
|
||||
return style_or_name if style_or_name.is_a?(Style)
|
||||
|
||||
style(style_or_name) || raise(ArgumentError, "Unknown style: #{style_or_name}")
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user