Reviewed-on: #8
Notare
A Ruby gem for creating docx files with a simple DSL
Installation
Add this line to your application's Gemfile:
gem 'notare'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install notare
Usage
Basic Example
require 'notare'
Notare::Document.create("output.docx") do |doc|
doc.p "Hello World"
end
Paragraphs
Notare::Document.create("output.docx") do |doc|
# Simple paragraph
doc.p "This is a paragraph."
# Paragraph with multiple text runs
doc.p do
doc.text "First part. "
doc.text "Second part."
end
end
Text Formatting
Formatting uses nested blocks. Nesting combines formatting styles.
Notare::Document.create("output.docx") do |doc|
doc.p do
doc.text "Normal text "
doc.b { doc.text "bold" }
doc.text " and "
doc.i { doc.text "italic" }
doc.text " and "
doc.u { doc.text "underlined" }
doc.text " and "
doc.s { doc.text "strikethrough" }
end
# Nested formatting (bold + italic)
doc.p do
doc.b do
doc.i { doc.text "bold and italic" }
end
end
# Show edits (strikethrough old, bold new)
doc.p do
doc.s { doc.text "old text" }
doc.text " "
doc.b { doc.text "new text" }
end
end
Headings
Use h1 through h6 for document headings:
Notare::Document.create("output.docx") do |doc|
doc.h1 "Document Title"
doc.h2 "Chapter 1"
doc.h3 "Section 1.1"
doc.h4 "Subsection"
doc.h5 "Minor heading"
doc.h6 "Smallest heading"
# Headings with formatted content
doc.h2 do
doc.text "Chapter with "
doc.i { doc.text "emphasis" }
end
end
Styles
Notare includes built-in styles and supports custom style definitions.
Built-in Styles
| Style | Properties |
|---|---|
:title |
26pt, bold, centered |
:subtitle |
15pt, italic, gray (#666666) |
:quote |
italic, gray (#666666), indented |
:code |
Courier New, 10pt |
:heading1 |
24pt, bold |
:heading2 |
18pt, bold |
:heading3 |
14pt, bold |
:heading4 |
12pt, bold |
:heading5 |
11pt, bold, italic |
:heading6 |
10pt, bold, italic |
Note: h1 through h6 methods use the corresponding heading styles automatically.
Notare::Document.create("output.docx") do |doc|
doc.p "This is a title", style: :title
doc.p "A subtitle", style: :subtitle
doc.p "A quotation", style: :quote
doc.p "puts 'code'", style: :code
end
Custom Styles
Define your own styles with text and paragraph properties:
Notare::Document.create("output.docx") do |doc|
# Define custom styles
doc.define_style :warning,
bold: true,
color: "FF0000",
size: 14
doc.define_style :note,
italic: true,
color: "0066CC",
font: "Georgia"
doc.define_style :centered,
align: :center,
size: 12
# Apply to paragraphs
doc.p "Warning message!", style: :warning
doc.p "Centered text", style: :centered
# Apply to text runs
doc.p do
doc.text "Normal text, "
doc.text "important!", style: :warning
doc.text ", and "
doc.text "a note", style: :note
end
end
Style Properties
Text properties:
bold: true/falseitalic: true/falseunderline: true/falsestrike: true/false- strikethroughhighlight: "yellow"- text highlight (see colors below)color: "FF0000"(hex RGB)size: 14(points)font: "Arial"(font family)
Highlight colors: black, blue, cyan, darkBlue, darkCyan, darkGray, darkGreen, darkMagenta, darkRed, darkYellow, green, lightGray, magenta, red, white, yellow
Paragraph properties:
align: :left / :center / :right / :justifyindent: 720(twips, 1 inch = 1440 twips)spacing_before: 240(twips)spacing_after: 240(twips)
Lists
Bullet Lists
Notare::Document.create("output.docx") do |doc|
doc.ul do
doc.li "First item"
doc.li "Second item"
doc.li { doc.b { doc.text "Bold item" } }
end
end
Numbered Lists
Notare::Document.create("output.docx") do |doc|
doc.ol do
doc.li "First"
doc.li "Second"
doc.li "Third"
end
end
Nested Lists
Lists can be nested inside list items. Mixed types (bullets inside numbered or vice versa) are supported.
Notare::Document.create("output.docx") do |doc|
doc.ol do
doc.li "First item"
doc.li "Second item" do
doc.ul do
doc.li "Nested bullet A"
doc.li "Nested bullet B"
end
end
doc.li "Third item"
end
# Deeply nested
doc.ul do
doc.li "Level 0"
doc.li "Has children" do
doc.ul do
doc.li "Level 1"
doc.li "Goes deeper" do
doc.ul do
doc.li "Level 2"
end
end
end
end
end
end
Tables
Notare::Document.create("output.docx") do |doc|
doc.table do
doc.tr do
doc.td "Header 1"
doc.td "Header 2"
end
doc.tr do
doc.td "Cell 1"
doc.td { doc.b { doc.text "Bold cell" } }
end
end
end
Table Styles
Define reusable table styles with borders, shading, cell margins, and alignment:
Notare::Document.create("output.docx") do |doc|
# Define a custom table style
doc.define_table_style :fancy,
borders: { style: "double", color: "0066CC", size: 6 },
shading: "E6F2FF",
cell_margins: 100,
align: :center
# Apply the style to a table
doc.table(style: :fancy) do
doc.tr do
doc.td "Product"
doc.td "Price"
end
doc.tr do
doc.td "Widget"
doc.td "$10.00"
end
end
end
Table Style Properties
| Property | Description | Example |
|---|---|---|
borders |
Border configuration | { style: "single", color: "000000", size: 4 } |
shading |
Background color (hex) | "EEEEEE" |
cell_margins |
Cell padding (twips) | 100 or { top: 50, bottom: 50, left: 100, right: 100 } |
align |
Table alignment | :left, :center, :right |
Border styles: single, double, dotted, dashed, triple, none
Border configuration options:
# All borders the same
borders: { style: "single", color: "000000", size: 4 }
# Per-edge borders
borders: {
top: { style: "double", color: "FF0000", size: 8 },
bottom: { style: "single", color: "000000", size: 4 },
left: { style: "none" },
right: { style: "none" },
insideH: { style: "dotted", color: "CCCCCC", size: 2 },
insideV: { style: "dotted", color: "CCCCCC", size: 2 }
}
# No borders
borders: :none
Built-in Table Styles
| Style | Description |
|---|---|
:grid |
Standard black single-line borders |
:borderless |
No borders |
doc.table(style: :borderless) do
doc.tr { doc.td "No borders here" }
end
Images
Images can be added to paragraphs, table cells, and list items. Supports PNG and JPEG formats.
Notare::Document.create("output.docx") do |doc|
# Simple image (uses native dimensions)
doc.p do
doc.image "photo.png"
end
# Image with explicit dimensions (inches, cm, or pixels)
doc.p do
doc.image "logo.png", width: "2in", height: "1in"
end
# Specify only width (height auto-calculated to maintain aspect ratio)
doc.p do
doc.image "banner.jpg", width: "5cm"
end
# Image with text in the same paragraph
doc.p do
doc.text "Company Logo: "
doc.image "logo.png", width: "0.5in", height: "0.5in"
end
# Image in a table cell
doc.table do
doc.tr do
doc.td "Product"
doc.td do
doc.image "product.jpg", width: "1in", height: "1in"
end
end
end
# Image in a list item
doc.ul do
doc.li do
doc.image "icon.png", width: "16px", height: "16px"
doc.text " List item with icon"
end
end
end
Line Breaks
Use br for soft line breaks within a paragraph (text continues in the same paragraph but on a new line):
Notare::Document.create("output.docx") do |doc|
doc.p do
doc.text "Line one"
doc.br
doc.text "Line two (same paragraph)"
doc.br
doc.text "Line three"
end
# Useful for addresses
doc.p do
doc.b { doc.text "Address:" }
doc.br
doc.text "123 Main Street"
doc.br
doc.text "Anytown, ST 12345"
end
end
Page Breaks
Use page_break to force content to start on a new page:
Notare::Document.create("output.docx") do |doc|
doc.h1 "Chapter 1"
doc.p "Content of chapter 1..."
doc.page_break
doc.h1 "Chapter 2"
doc.p "This starts on a new page."
end
Hyperlinks
Add clickable links with link:
Notare::Document.create("output.docx") do |doc|
# Link with custom text
doc.p do
doc.text "Visit "
doc.link "https://example.com", "our website"
doc.text " for more info."
end
# Link showing the URL as text
doc.p do
doc.text "URL: "
doc.link "https://example.com"
end
# Link with formatted content
doc.p do
doc.link "https://github.com" do
doc.b { doc.text "GitHub" }
end
end
# Links in lists
doc.ul do
doc.li do
doc.link "https://ruby-lang.org", "Ruby"
end
doc.li do
doc.link "https://rubyonrails.org", "Rails"
end
end
# Email links
doc.p do
doc.text "Contact: "
doc.link "mailto:hello@example.com", "hello@example.com"
end
end
Complete Example
Notare::Document.create("report.docx") do |doc|
doc.p "Monthly Report"
doc.p do
doc.text "This report contains "
doc.b { doc.text "important" }
doc.text " information."
end
doc.p "Key Points:"
doc.ul do
doc.li "Revenue increased by 15%"
doc.li "Customer satisfaction improved"
doc.li { doc.i { doc.text "See appendix for details" } }
end
doc.p "Summary Table:"
doc.table do
doc.tr do
doc.td "Metric"
doc.td "Value"
end
doc.tr do
doc.td "Revenue"
doc.td "$1.2M"
end
doc.tr do
doc.td "Growth"
doc.td { doc.b { doc.text "15%" } }
end
end
end
API Reference
| Method | Description |
|---|---|
p(text, style:) |
Create a paragraph with text and optional style |
p(style:) { } |
Create a paragraph with block content and optional style |
text(value, style:) |
Add text with optional style to the current context |
h1(text) - h6(text) |
Create headings (level 1-6) |
b { } |
Bold formatting |
i { } |
Italic formatting |
u { } |
Underline formatting |
s { } |
Strikethrough formatting |
br |
Line break (soft break within paragraph) |
page_break |
Page break (force new page) |
link(url, text) |
Hyperlink with custom text |
link(url) { } |
Hyperlink with block content |
define_style(name, **props) |
Define a custom style |
define_table_style(name, **props) |
Define a custom table style |
ul { } |
Bullet list (can be nested) |
ol { } |
Numbered list (can be nested) |
li(text) |
List item with text |
li { } |
List item with block content |
li(text) { } |
List item with text and nested content |
table(style:) { } |
Table with optional style |
tr { } |
Table row |
td(text) |
Table cell with text |
td { } |
Table cell with block content |
image(path, width:, height:) |
Insert image (PNG/JPEG). Dimensions: "2in", "5cm", "100px", or integer pixels |
Development
After checking out the repo, run bundle install to install dependencies. Then, run rake test to run the tests.
bundle install
bundle exec rake test # Run tests
bundle exec rake rubocop # Run linter
bundle exec rake # Run both
License
The gem is available as open source under the terms of the MIT License.