Files
Notare/README.md
mathias234 9a70d91fd5
All checks were successful
CI Pipeline / build (pull_request) Successful in 14s
Implement table styles
2025-12-03 12:14:31 +01:00

549 lines
12 KiB
Markdown

# Notare
A Ruby gem for creating docx files with a simple DSL
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'notare'
```
And then execute:
$ bundle install
Or install it yourself as:
$ gem install notare
## Usage
### Basic Example
```ruby
require 'notare'
Notare::Document.create("output.docx") do |doc|
doc.p "Hello World"
end
```
### Paragraphs
```ruby
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.
```ruby
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:
```ruby
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.
```ruby
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:
```ruby
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/false`
- `italic: true/false`
- `underline: true/false`
- `strike: true/false` - strikethrough
- `highlight: "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 / :justify`
- `indent: 720` (twips, 1 inch = 1440 twips)
- `spacing_before: 240` (twips)
- `spacing_after: 240` (twips)
### Lists
#### Bullet Lists
```ruby
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
```ruby
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.
```ruby
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
```ruby
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:
```ruby
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:**
```ruby
# 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 |
```ruby
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.
```ruby
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):
```ruby
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:
```ruby
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`:
```ruby
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
```ruby
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.
```bash
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](LICENSE.txt).