Code Monkey home page Code Monkey logo

caracal's Introduction

Caracal

Gem Version

Overview

Caracal is a ruby library for dynamically creating professional-quality Microsoft Word documents using an HTML-style syntax.

Caracal is not a magical HTML to Word translator. Instead, it is a markup language for generating Office Open XML (OOXML). Programmers create Word documents by issuing a series of simple commands against a document object. When the document is rendered, Caracal takes care of translating those Ruby commands into the requisite OOXML. At its core, the library is essentially a templating engine for the :docx format.

Or, said differently, if you use Prawn for PDF generation, you'll probably like Caracal. Only you'll probably like it better. :)

Please see the caracal-example repository for a working demonstration of the library's capabilities.

Teaser

How would you like to make a Word document like this?

Caracal::Document.save 'example.docx' do |docx|
  # page 1
  docx.h1 'Page 1 Header'
  docx.hr
  docx.p
  docx.h2 'Section 1'
  docx.p  'Lorem ipsum dolor....'
  docx.p
  docx.table @my_data, border_size: 4 do
    cell_style rows[0], background: 'cccccc', bold: true
  end

  # page 2
  docx.page
  docx.h1 'Page 2 Header'
  docx.hr
  docx.p
  docx.h2 'Section 2'
  docx.p  'Lorem ipsum dolor....'
  docx.ul do
    li 'Item 1'
    li 'Item 2'
  end
  docx.p
  docx.img 'https://www.example.com/logo.png', width: 500, height: 300
end

You can! Read on.

Why is Caracal Needed?

We created Caracal to satisfy a genuine business requirement. We were working on a system that produced a periodic PDF report and our clients asked if the report could instead be generated as a Word document, which would allow them to perform edits before passing the report along to their clients.

Now, as you may have noticed, the Ruby community has never exactly been known for its enthusiastic support of Microsoft standards. So it might not surprise you to learn that the existing options on Rubygems for Word document generation were limited. Those libraries, by and large, fell into a couple of categories:

  • HTML to Word Convertors We understand the motivating idea here (two output streams from one set of instructions), but the reality is the number of possible permutations of nested HTML tags is simply too great for this strategy to ever work for anything other than the simplest kinds of documents. Most of these libraries rely on a number of undocumented assumptions about the structure of your HTML (which undermines the whole value proposition of a convertor) and fail to support basic features of a professional-quality Word document (e.g., images, lists, tables, etc). The remaining libraries simply did not work at all.

  • Weekend Projects We also found a number of inactive projects that appeared to be experiments in the space. Obviously, these libraries were out of the question for a commercial product.

What we wanted was a Prawn-style library for the :docx format. In the absence of an active project organized along those lines, we decided to write one.

Design

Caracal is designed to separate the process of parsing and collecting rendering instructions from the process of rendering itself.

First, the library consumes all programmer instructions and organizes several collections of data models that capture those instructions. These collections are ordered and nested exactly as the instructions we given. Each model contains all the data required to render it and is responsible for declaring itself valid or invalid.

Note: Some instructions create more than one model. For example, the img method both appends an ImageModel to the main contents collection and determines whether or not a new RelationshipModel should be added to the relationships collection.

Only after all the programmer instructions have been parsed does the document attempt to render the data to XML. This strategy gives the rendering process a tremendous amount of flexibility in the rare cases where renderers combine data from more than one collection.

File Structure

You may not know that .docx files are simply a zipped collection of XML documents that follow the OOXML standard. (We didn't, in any event.) This means constructing a .docx file from scratch actually requires the creation of several files. Caracal abstracts users from this process entirely.

For each Caracal request, the following document structure will be created and zipped into the final output file:

    example.docx
      |- _rels
      	|- .rels
      |- docProps
        |- app.xml
        |- core.xml
        |- custom.xml
      |- word
        |- _rels
          |- document.xml.rels
        |- media
          |- image001.png
          |- image002.png
          ...
        |- document.xml
        |- fontTable.xml
        |- footer.xml
        |- numbering.xml
        |- settings.xml
        |- styles.xml
      |- [Content_Types].xml

File Descriptions

The following provides a brief description for each component of the final document:

_rels/.rels Defines an internal identifier and type for global content items. This file is generated automatically by the library based on other user directives.

docProps/app.xml Specifies the name of the application that generated the document. This file is generated automatically by the library based on other user directives.

docProps/core.xml Specifies the title of the document. This file is generated automatically by the library based on other user directives.

docProps/custom.xml Specifies the custom document properties. This file is generated automatically by the library based on other user directives.

word/_rels/document.xml.rels Defines an internal identifier and type with all external content items (images, links, etc). This file is generated automatically by the library based on other user directives.

word/media/ A collection of media assets (each of which should have an entry in document.xml.rels).

word/document.xml The main content file for the document.

word/fontTable.xml Specifies the fonts used in the document.

word/footer.xml Defines the formatting of the document footer.

word/numbering.xml Defines ordered and unordered list styles.

word/settings.xml Defines global directives for the document (e.g., whether to show background images, tab widths, etc). Also, establishes compatibility with older versions on Word.

word/styles.xml Defines all paragraph and table styles used through the document. Caracal adds a default set of styles to match its HTML-like content syntax. These defaults can be overridden.

[Content_Types].xml Pairs extensions and XML files with schema content types so Word can parse them correctly. This file is generated automatically by the library based on other user directives.

Units

OpenXML properties are specified in several different units, depending on which attribute is being set.

Points Most spacing declarations are measured in full points.

Half Points All font sizes are measure in half points. A font size of 24 is equivalent to 12pt.

Eighth Points Borders are measured in 1/8 points. A border size of 4 is equivalent to 0.5pt.

Twips A twip is 1/20 of a point. Word documents are printed at 72dpi. 1in == 72pt == 1440 twips.

Pixels In Word documents, pixels are equivalent to points.

EMUs (English Metric Unit) EMUs are a virtual unit designed to facilitate the smooth conversion between inches, millimeters, and pixels for images and vector graphics. 1in == 914400 EMUs == 72dpi x 100 x 254.

At present, Caracal expects values to be specified in whichever unit OOXML requires. This is admittedly difficult for new Caracal users. Eventually, we'll probably implement a utility object under the hood to convert user-specified units into the format expected by OOXML.

Syntax Flexibility

Generally speaking, Caracal commands will accept instructions via any combination of a parameters hash and/or a block. For example, all of the following commands are equivalent.

docx.style id: 'special', name: 'Special', size: 24, bold: true

docx.style id: 'special', size: 24 do
  name 'Special'
  bold true
end

docx.style do
  id   'special'
  name 'Special'
  size 24
  bold true
end

Parameter options are always evaluated before block options. This means if the same option is provided in the parameter hash and in the block, the value in the block will overwrite the value from the parameter hash. Tread carefully.

Validations

All Caracal models perform basic validations on their attributes, but this is, without question, the least sophisticated part of the library at present.

In forthcoming versions of Caracal, we'll be looking to expand the InvalidModelError class to provide broader error reporting abilities across the entire library.

Installation

Add this line to your application's Gemfile:

gem 'caracal'

Then execute:

bundle install

Commands

In the following examples, the variable docx is assumed to be an instance of Caracal::Document.

docx = Caracal::Document.new('example_document.docx')

Most code examples show optional values being passed in a block. As noted above, you may also pass these options as a parameter hash or as a combination of a parameter hash and a block.

File Name

The final output document's title can be set at initialization or via the file_name method.

docx = Caracal::Document.new('example_document.docx')

docx.file_name 'different_name.docx'

The current document name can be returned by invoking the name method:

docx.name    # => 'example_document.docx'

The default file name is caracal.docx.

Page Size

Page dimensions can be set using the page_size method. The method accepts two parameters for controlling the width and height of the document. It also accepts a third parameter for setting the page orientation. If you want landscape orientation, you need to change both the page dimensions and the orientation explicitly.

Page size defaults to United States standard A4, portrait dimensions (8.5in x 11in).

docx.page_size do
  width       15840       # sets the page width. units in twips.
  height      12240       # sets the page height. units in twips.
  orientation :landscape  # sets the printer orientation. accepts :portrait and :landscape.
end

Both the width and height attributes require positive integer values.

Page Margins

Page margins can be set using the page_margins method. The method accepts four parameters for controlling the margins of the document.

Margins default to 1.0in for all sides.

docx.page_margins do
  left    720     # sets the left margin. units in twips.
  right   720     # sets the right margin. units in twips.
  top     1440    # sets the top margin. units in twips.
  bottom  1440    # sets the bottom margin. units in twips.
end

All attributes require positive integer values. Additionally, the combined size of the margins on either axis cannot exceed the page size on that axis (e.g., the sum of the left and right values must be less than the page_width).

Page Breaks

Page breaks can be added via the page method. The method accepts no parameters.

docx.page     # starts a new page.

Page Numbers

Page numbers can be added to the footer via the page_numbers method. The method accepts optional parameters for controlling the alignment, label and size of the text.

Page numbers are turned off by default.

docx.page_numbers true do
  align        :right  # sets the alignment. accepts :left, :center, and :right.
  label        'Page'  # sets the text that will go to the left of the page number. Defaults to nil.
  size:        24      # sets the label and number size simultaneously. units in half points.
  label_size:  24      # sets the label size only. units in half points.
  number_size: 20      # sets the number size only. units in half points.
end

The size option and the label_size and number_size options are mutually exclusive.

Fonts

Fonts are added to the font table file by calling the font method and passing the name of the font.

At present, Caracal only supports declaring the primary font name.

docx.font do
  name 'Droid Serif'
end

Styles

Paragraph style classes can be defined using the style method. The method accepts several optional parameters to control the rendering of text using the style.

docx.style do
  id              'Heading1'  # sets the internal identifier for the style.
  name            'heading 1' # sets the friendly name of the style.
  type            'paragraph' # sets the style type. accepts `paragraph` or `character`
  font            'Palantino' # sets the font family.
  color           '333333'    # sets the text color. accepts hex RGB.
  size            28          # sets the font size. units in half points.
  bold            false       # sets the font weight.
  italic          false       # sets the font style.
  underline       false       # sets whether or not to underline the text.
  caps            false       # sets whether or not text should be rendered in all capital letters.
  align           :left       # sets the alignment. accepts :left, :center, :right, and :both.
  line            360         # sets the line height. units in twips.
  top             100         # sets the spacing above the paragraph. units in twips.
  bottom          0           # sets the spacing below the paragraph. units in twips.
  indent_left     360         # sets the left indent. units in twips.
  indent_right    360         # sets the rights indent. units in twips.
  indent_first    720         # sets the first line indent. units in twips.
end

Caracal establishes a standard set of default styles for every document. Default styles can be overridden by issuing a style command referencing an existing id. Default style ids are:

  • Normal
  • Title
  • Subtitle
  • Heading1
  • Heading2
  • Heading3
  • Heading4
  • Heading5
  • Heading6

Styles are declared as paragraph by default. If you need to adjust inline text styles repeatedly, you might benefit from defining a character style. Paragraph styles affects all text runs within a paragraph; character styles are used to style individual runs within a larger text block.

One-off inline text styling can also be accomplished by passing the text command override arguments (see below).

Custom Properties

Custom document properties can be defined using the custom_property method. The method accepts a few required parameters to control the definition of the custom property.

docx.custom_property do
  name      'property name 1' # sets the name of the custom property.
  value     'test'            # sets the value of the custom property.
  type      :text             # sets the property type. accepts :text, :number, :date, :boolean.
end

The name, value, and height attributes are required. If any of the attributes are missing, the custom property will not be created.

A document may have zero or many custom properties. Each custom property's name should be unique with its type.

Paragraphs

Paragraph text can be added using the p method. The method accepts several optional parameters for controlling the style and behavior of the paragraph.

In its simple form, a paragraph accepts a text string and formatting options.

docx.p 'Sample text.'

docx.p 'Sample text.', style: 'custom_style'

docx.p 'Sample text.' do
  style           'custom_style'    # sets the paragraph style. generally used at the exclusion of other attributes.
  align           :left             # sets the alignment. accepts :left, :center, :right, and :both.
  color           '333333'          # sets the font color.
  size            32                # sets the font size. units in 1/2 points.
  bold            true              # sets whether or not to render the text with a bold weight.
  italic          false             # sets whether or not render the text in italic style.
  underline       false             # sets whether or not to underline the text.
  bgcolor         'cccccc'          # sets the background color.
  highlight_color 'yellow'          # sets the highlight color. only accepts OOXML enumerations. see http://www.datypic.com/sc/ooxml/t-w_ST_HighlightColor.html.
  vertical_align  'superscript'     # sets the vertical alignment.
end

More complex paragraph runs can be accomplished by using the text method instead the paragraph's block.

docx.p do
  text 'Here is a sentence with a '
  link 'link', 'https://www.example.com'
  text ' to something awesome', font: 'Courier New', color: '555555', size: 32, bold: true, italic: true, underline: true, bgcolor: 'cccccc'
  text '.'
  br
  text 'This text follows a line break and uses a character style instead of overrides.', style: 'MyCharStyle'
  page
end

Links

Links can be added inside paragraphs using the link method. The method accepts several optional parameters for controlling the style and behavior of the rule.

p do
  link 'Example Text', 'https://wwww.example.com' do
    internal        false             # sets whether or not the link references an external url. defaults to false.
    font            'Courier New'     # sets the font name to use. defaults to nil.
    color           '0000ff'          # sets the color of the text. defaults to 1155cc.
    size            24                # sets the font size. units in half-points. defaults to nil.
    bold            false             # sets whether or not the text will be bold. defaults to false.
    italic          false             # sets whether or not the text will be italic. defaults to false.
    underline       true              # sets whether or not the text will be underlined. defaults to true.
    bgcolor         'cccccc'          # sets the background color.
    highlight_color 'yellow'          # sets the highlight color. only accepts OOXML enumerations. see http://www.datypic.com/sc/ooxml/t-w_ST_HighlightColor.html.
  end
end

Bookmarks

Bookmarks can be added directly to the document or inside paragraph blocks using the bookmark_start and bookmark_end methods. Bookmarks can be inserted at the document-level to describe section headings, etc. or inside of a paragraph block for fine-grained linking.

# document-level bookmark
dox.bookmark_start id: 's1', name: 'section1'
docx.h2 'Section Heading'
docx.bookmark_end id: 's1'
docx.p  'Section content.'

# pargraph-level bookmark
docx.h2 'Section Heading'
docx.p do
  text 'Pretend this paragraph has a lot of text and we want to bookmark '
  bookmark_start id: 'p1', name: 'phrase1'
  text 'a single phrase'
  bookmark_end id: 'p1'
  text ' inside the larger block.'
end

Bookmarks work in conjunction with internal links. Please see above.

Headings

Headings can be added using the h1, h2, h3, h4, h5, and h6 methods. Headings are simply paragraph commands with a specific style set, so anything you can do with a paragraph is available to a heading.

docx.h1 'Heading'

docx.h2 do
  text 'Heading with a '
  link 'Link', 'http://www.google.com'
  text '.'
end

Rules

Horizontal rules can be added using the hr method. The method accepts several optional parameters for controlling the style of the rule.

docx.hr do
  color   '333333'   # sets the color of the line. defaults to auto.
  line    :double    # sets the line style (single or double). defaults to single.
  size    8          # sets the thickness of the line. units in 1/8 points. defaults to 4.
  spacing 4          # sets the spacing around the line. units in 1/8 points. defaults to 1.
end

Line Breaks

Line breaks can be added via the br method inside paragraphs.

docx.p do
  text 'This sentence precedes the line break.'
  br
  text 'This sentence follows the line break.'
end

Line breaks only work instead paragraph-like commands. If you want to create an empty line between two paragraphs, use an empty paragraph instead.

docx.p

Lists

Ordered lists can be added using the ol and li methods. The li method substantially follows the same rules as the the p method.

docx.ol do
  li 'First item'
  li do
    text 'Second item with a '
    link 'link', 'http://www.google.com'
    text '.'
    br
    text 'This sentence follows a line break.'
  end
end

Similarly, unordered lists can be added using the ul and li methods.

docx.ul do
  li 'First item'
  li do
    text 'Second item with a '
    link 'link', 'http://www.google.com'
    text '.'
    br
    text 'This sentence follows a line break.'
  end
end

Lists can nested as many levels deep as you wish and mixed in any combination.

docx.ul do
  li 'First item'
  li 'Second item' do
    ol do
      li 'SubItem 1'
      li 'SubItem 2' do
        ol do
          li 'SubSubItem'
        end
      end
    end
  end
end

List Styles

List styles can be defined using the list_style command. The method accepts several optional parameters to control the rendering of list items using the style.

Caracal will automatically define 9 levels of default styles for both ordered and unordered lists.

docx.list_style do
  type    :ordered    # sets the type of list. accepts :ordered or :unordered.
  level   2           # sets the nesting level. 0-based index.
  format  'decimal'   # sets the list style. see OOXML docs for details.
  value   '%3.'       # sets the value of the list item marker. see OOXML docs for details.
  align   :left       # sets the alignment. accepts :left, :center: and :right. defaults to :left.
  indent  400         # sets the indention of the marker from the margin. units in twips.
  left    800         # sets the indention of the text from the margin. units in twips.
  start   2           # sets the number at which item counts begin. defaults to 1.
  restart 1           # sets the level that triggers a reset of numbers at this level. 1-based index. 0 means numbers never reset. defaults to 1.
end

Images

Images can be added by using the img method. The method accepts several optional parameters for controlling the style and placement of the asset.

Caracal will automatically embed the image in the Word document.

docx.img 'https://www.example.com/logo.png' do
  data    raw_data  # sets the file data directly instead of opening the url
  width   396       # sets the image width. units specified in pixels.
  height  216       # sets the image height. units specified in pixels.
  align   :right    # controls the justification of the image. default is :left.
  top     10        # sets the top margin. units specified in pixels.
  bottom  10        # sets the bottom margin. units specified in pixels.
  left    10        # sets the left margin. units specified in pixels.
  right   10        # sets the right margin. units specified in pixels.
end

Note: If you provide the image data, you should still supply a URL. I know this is a bit hacky, but it allows the library to key the image more effectively and Caracal needs a file extension to apply to the renamed media file. This seemed the simplest solution to both problems.

Tables

Release v1.4.0 deprecated the behaviour of automatically adding an empty paragraph tag after every table. If you are upgrading from an older version of the library, you will need to control such spacing in your own code.

Tables can be added using the table method. The method accepts several optional paramters to control the layout and style of the table cells.

The table command accepts data in the form of a two-dimensional arrays. This corresponds to rows and column cells within those rows. Each array item can be a string, a Hash of options, a Proc (which will be passed as a block), or a TableCellModel. The command will normalize all array contents into a two-dimensional array of TableCellModel instances.

docx.table [['Header 1','Header 2'],['Cell 1', 'Cell 2']] do
  border_color   '666666'   # sets the border color. defaults to 'auto'.
  border_line    :single    # sets the border style. defaults to :single. see OOXML docs for details.
  border_size    4          # sets the border width. defaults to 0. units in twips.
  border_spacing 4          # sets the spacing around the border. defaults to 0. units in twips.
end

Table borders can be further styled with position-specific options. Caracal supports styling the top, bottom, left, right, inside horizontal, and inside vertical borders with the border_top, border_bottom, border_left, border_right, border_horizontal, and border_vertical, respectively. Options have the same meaning as those set at the table level.

docx.table data, border_size: 4 do
  border_top do
    color   '000000'
    line    :double
    size    8
    spacing 2
  end
end

Table cells can be styles using the cell_style method inside the table's block. The method will attempt to apply any specified options against the collection of TableModelCell instances provided in the first argument. Any improper options will fail silently.

As a convenience, the table provides the methods rows, cols, and cells to facilitate building the first argument.

The example will style the first row as a header and establish a fixed width for the first column.

docx.table [['Header 1','Header 2'],['Cell 1', 'Cell 2']], border_size: 4 do
  cell_style rows[0], background: '3366cc', color: 'ffffff', bold: true
  cell_style cols[0], width: 6000
end

It is possible to merge cells vertically and horizontally using the rowspan and colspan options in cell_style method e.g.

docx.table [['11', '1213', '14'], ['21', '22', '23', '24']] do
  cell_style rows[0][0], rowspan: 2
  cell_style rows[0][1], colspan: 2
  cell_style rows[0][2], rowspan: 2
end

Note: content of cells 21 and 24 will disappear

Table Cells

If your table contains more complex data (multiple paragraphs, images, lists, etc.), you will probably want to instantiate your TableCellModel instances directly. With the exception of page breaks, table cells can contain anything the document can contain, including another table.

c1 = Caracal::Core::Models::TableCellModel.new do
  background 'cccccc'    # sets the background color. defaults to 'ffffff'.
  margins do
    top                  # sets the top margin. defaults to 100. units in twips.
    bottom               # sets the bottom margin. defaults to 100. units in twips.
    left                 # sets the left margin. defaults to 100. units in twips.
    right                # sets the right margin. defaults to 100. units in twips.
  end

  p 'This is a sentence above an image.'
  p
  img 'https://www.example.com/logo.png', width: 200, height: 100
end

Nested Tables

Because table cells can contain anything that can be added to the document, tables can be nested to achieve whatever layout goals you want to achieve.

row1 = ['Header 1', 'Header 2', 'Header 3']
row2 = ['Cell 1', 'Cell 2', 'Cell 3']
row3 = ['Cell 4', 'Cell 5', 'Cell 6']
row4 = ['Footer 1', 'Footer 2', 'Footer 3']
c1 = Caracal::Core::Models::TableCellModel.new margins: { top: 0, bottom: 100, left: 0, right: 200 } do
  table [row1, row2, row3, row4], border_size: 4 do
    cell_style rows[0],  bold: true, background: '3366cc', color: 'ffffff'
    cell_style rows[-1], bold: true,   background: 'dddddd'
    cell_style cells[3], italic: true, color: 'cc0000'
    cell_style cells,    size: 18, margins: { top: 100, bottom: 0, left: 100, right: 100 }
  end
end
c2 = Caracal::Core::Models::TableCellModel.new margins: { top: 0, bottom: 100, left: 0, right: 200 } do
  p 'This layout uses nested tables (the outer table has no border) to provide a caption to the table data.'
end

docx.table [[c1,c2]] do
  cell_style cols[0], width: 6000
end

Experimental Features

IFrames

You can include an external Word document into your working Caracal document by specifying a URL or by supplying the data directly.

It should be noted that the metaphor here is imperfect. Caracal fully includes the external file at the time of insertion. Further changes to the external file will not be reflected in your Caracal output.

# this example loads the file from the internet
docx.iframe url: 'http://www.some-website.org/snippet.docx'

# this example loads the data directly
docx.iframe data: File.read('my/path/to/snippet.docx')

Caracal is pretty smart about including the external document, at least as it relates to images. As long as the external document only uses the feature set Caracal supports natively, you should be okay.

But if the external document uses more advanced Word features, the iframe directive may or may not work. Again, a Word document is really just a dozen or so XML files zipped up with the extension .docx. Most of the commands you issue in a Word document only add OOXML to one of these internal files. But some commands--like inserting an image--modify several of the internal files. So, when you include an external file, what Caracal is doing under the hood is grabbing the contents of the main internal XML file and copying that OOXML into the Caracal document's main internal file. Caracal is smart enough to look for any images in the external file and make the corresponding entries in its own internal files, but if other advanced features of Word require similar adjustments, Caracal won't know to do that. Probably those advanced features will not operate as expected in the parent Caracal document.

Again, this feature is considered experimental. Use at your own risk/discretion.

Template Rendering

Caracal includes Tilt integration to facilitate its inclusion in other frameworks.

Rails integration can be added via the Caracal-Rails gem.

Using Variables

Lexical scope is a pretty big challenge for Caracal and it often confuses new users. This closed issue covers the discussion both from the user and library persepctive.

Filing an Issue

Caracal was written for and tested against Word 2010, 2013, and Office365. It should also open in LibreOffice with high fidelity.

Older Versions

If you are using a version of Word that predates 2010, Caracal may or may not work for you. (Probably it won't.) We don't ever plan to support versions before 2010, but if you choose to embark on that endeavor, we'd be happy to answer questions and provide what guidance we can. We just won't write any code in that direction.

Newer Versions

For those using reasonably current versions of Word, please consider the following:

  • Before you file an issue, please run the example Caracal project caracal-example in your development environment and check the output. This project implements nearly every feature Caracal supports and renders the expected output correctly. It can be thought of as a canonical implementation of the library.

  • If you don't see your issue in the example project's implementation of the same feature, chances are you made a mistake in your document's syntax or have an environment-specific, non-caracal problem.

  • If you do see the same behavior in the example project, you've probably uncovered a variance in the way your particular permutation of Windows/Word interprets the OOXML.

How to Work on a Problem

Caracal is essentially an exercise in reverse engineering OOXML output. When developing features, we typically start by building the simplest Word document we can that includes the desired behavior. Then, we change the document extension to .zip, extract the archive, and inspect the resulting OOXML. Finally, we teach the corresponding renderer to output that OOXML.

It's a tedious process, but it's not nearly as tedious as learning the entire OOXML specification.

The downside is Word changes its expectations about OOXML format with each version, so it can be a bit of a balancing act to get the OOXML structured for acceptance by all supported versions.

Ultimately, we'll probably need to implement version-specific renderers (i.e., a set of renderers for 2010/2013, a set for 2016, etc.).

Contributing

  1. Fork it ( https://github.com/trade-informatics/caracal/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Why is It Called Caracal?

Because my son likes caracals. :)

Inspiration

A tip of the hat to the wonderful PDF generation library Prawn.

License

Copyright (c) 2014 Trade Informatics, Inc

MIT License

caracal's People

Contributors

alnoroid avatar avolochnev avatar davidtolsma avatar gh4me avatar henrychung avatar jdugan avatar jdugan-plia avatar jensljungblad avatar joshwlewis avatar linuus avatar martinsp avatar ykonovets avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

caracal's Issues

How can i create a complex table like this

Hi,
First, thanks for your great work. It is very useful for me, i like it very much.
Now, i want to create a table likes this, but there are some questions for me.
qq 20151209181636
My question is:
1, How can i insert a picture in a cell.
2, How can i split a cell like row 2
many thanks

Document is corrupted

When opening the document in word it is reported as corrupted. The automatic recovery dialog is able to repair it, but it reports an error with "Styles 1".

I've tried both with contents and empty documents.

As an aside; when unzipping the document with 'unzip', I get the following warning:

test % unzip 10.docx 
Archive:  10.docx
warning [10.docx]:  34710 extra bytes at beginning or within zipfile
  (attempting to process anyway)

I did try to downgrade RubyZip from 1.1.7 to 1.1.0, with no success.

Ruby 2.2.2, Rails 4.2, Caracal 1.3.0

How to create new lines inside a paragraph

How can I insert a line break in a paragraph?

I tried the following but it didn't work:

docx.p do
  text "some text"
  br
  text "some more text"
end

Also tried the following:

docx.p do
  text "some text"
  docx.br
  text "some more text"
end

Also, it seems that line breaks are not actually line breaks but empty paragraphs? When doing this:

docx.br
docx.p "some text"

I get this:

ยถ
some textยถ

I would expect:

โŽ
some textยถ

Add table of contents

Is there a way to generate a Table of Contents as well as a page header that is repeated on each page?

Crashes on JRuby 9.1.8.0 with NAMESPACE_ERR

I tried to get the example project to run on JRuby 9.1.8.0 with Rails 4.2.8, but it fails with the following exception:

Started GET "/" for 0:0:0:0:0:0:0:1 at 2017-04-21 12:27:18 +0200
Processing by ExamplesController#show as DOCX
  Rendered examples/show.docx.caracal (381.4ms)
Completed 500 Internal Server Error in 418ms (ActiveRecord: 0.0ms)

ActionView::Template::Error (NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.):
  org.apache.xerces.dom.ElementNSImpl.setName(Unknown Source)
  org.apache.xerces.dom.ElementNSImpl.<init>(Unknown Source)
  org.apache.xerces.dom.CoreDocumentImpl.createElementNS(Unknown Source)
  nokogiri.XmlNode.init(XmlNode.java:340)
  nokogiri.XmlNode.rbNew(XmlNode.java:298)
  nokogiri.XmlNode$INVOKER$s$0$0$rbNew.call(XmlNode$INVOKER$s$0$0$rbNew.gen)
  org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
  ...

After that there are 992 more lines of org.jruby... stacktrace. Any idea on how to get it to work? I like and use prawn in my project and caracal seems perfect to generate Word documents.

Template rendering example

The README hints that caracal can be used to render DOCX templates. My use case is e.g. to take an existing template .docx file that contains placeholders like $FIRST_NAME$ and replace those placeholders with either text or image data.

How is this done?

Helper methods not supported?

Hi,

the following raises undefined method formatted_question' for #Caracal::Core::Models::ParagraphModel:0x007fa98558e018`

docx.p do
    text formatted_question('AAA')
    text ' : '
end

my formatted_question comes from helper. I'm using caracal-rails. Any idea?

Unable to open document in Word or Winzip

I produced a sample doc, using the following commands, in irb:

docx = Caracal::Document.new("fred.docx")
para2 = "fooz"
docx.p para2
buffer = docx.render
File.open("./#{docx.name}", 'w') { |f| f.write(buffer.string) }

but the document doesn't open in Word or Winzip. Winzip gives the error: Error: Central Directory not found . I tried 7zip, which opens the file, but then it I get an "unsupported compression method" error when I try to extract a file.

How to insert a page break after each li?

I have code like below:-
docx.ol do
li 'first'
li 'second'
end
I need to insert a page break after each li.
I tried with docx.page after li but that didn't worked.

Add ability to use partials

Hi,
is there a way of using partials? I see integration to Tilt, which supports it as far as I've checked (not sure entirely). But if I try something like this in show.docx.caracal:
render partial: 'template'
docx.p 'blabla'
and partial _template.docx.caracal has:
docx.p 'tralala'
It generates .docx file, but it has only "blabla", and not content of partial, as it was ignored.
If I'm wrong, could you show me the correct way?
p.s.: I'm using rails wrapper gem caracal-rails

Compability mode

Hello,
I'm working on generating an invoice using 'caracal'. Everything seems fine, except when it gets generated and I open it the bottom borders of the tables are not showing. Well they are showing when the zoom level is above 100%, but when I try to print them out they are not showing again..

Perhaps it somehow related to being in "compatibility mode". Because when I convert it out of compatibility mode using Word, the issue is gone.

My first thought was that is was only me, but then I tried generating tables with different templates and tried opening them on another PC.. The result was that the bottom borders were still not showing on some of the tables, but as I have mentioned, when I convert them, then everything is fine.

Any thoughts on this?

Paragraph styling

Some questions regarding styling.

  1. Is it possible to change the default font, without having to override all styles? This doesn't seem to do that, at least:
docx.font do
  name "Times New Roman"
end
  1. It seems like the normal style is the one assigned to text by default, i.e. paragraphs. It seems to correlate to the Word/Pages "body text". It also seems to be possible to set the font size of the normal style using:
docx.style { id: "Normal",  name: "normal", size: 360 }

However, it's not possible to set other attributes, such as bottom:

docx.style { id: "Normal",  name: "normal", bottom: 200 }

If I want to style all my paragraphs with a bottom value, is that how I'm supposed to do it, or should I create my own style and set bottom on that? When I tried that I got a problem: "keep lines on same page" and "keep with next paragraphs" are both set for the paragraph as well. They are not when using the normal style.

Tables look strange

screen shot 2015-06-18 at 19 42 29

Tried with and without text, Word for Mac beta 2015.

This may or may not be related to issue #12

Adding a Footer

How can I go about adding a static footer to each page, such as a copyright?

I see that you have the ability to add page numbers, I was wondering if you had something similar for content?

Is there a way to highlight ?

Hello,
First, thank you form your work it's amazing !

I want to know if there is a way to hightlight text. I mean like the in HTML. Moreover this function is already developped in Word.

Thank you in advance :)

Variables to Model

I want to use variables in a TableCellModel. Is it possible to do something like this?

c2 = Caracal::Core::Models::TableCellModel.new margins: { top: 0, bottom: 100, left: 0, right: 200 } do
  ul do
    @minisite_publication.course.work_flow.each do |stage|
      li "#{stage[:name]}"
    end
  end
end

I am getting undefined method course' for nil:NilClass. So, @minisite_publication` variable is nil, I don't know how to pass it.

Breaks and multiple paragraphs in table cells

I've not fully investigated yet, but it appears there is a problem with line breaks in table cells. The following code illustrates this:

#!/usr/bin/env ruby
#encoding: UTF-8

require 'rubygems'
require 'caracal'

Caracal::Document.save('table-cell-br-test.docx') do |docx|

  # Only the second line of text shows
  broken_cell_br = Caracal::Core::Models::TableCellModel.new do |c|
    c.p do |para| 
      para.text'First line'
      para.br
      para.text'Second line'
    end
  end

  # Both pieces of text show
  working_cell = Caracal::Core::Models::TableCellModel.new do |c|
    c.p do |para| 
      para.text'First line '
      para.text'Second line'
    end
  end

  # Only the second paragraph shows
  broken_cell_para = Caracal::Core::Models::TableCellModel.new do |c|
    c.p "first para"
    c.p "second para"
  end  

  docx.table [ [broken_cell_br, working_cell, broken_cell_para] ] do
  end
end

When I've tried putting a line break in a paragraph within a table cell I only see part of the output in the rendered .docx. The data is present in the .docx however. If I do an autoformat of the resulting table from within MS Word (2008 - Mac) I see all the expected text with the expected line breaks.

I'll try to investigate further, but thought I'd at least open a ticket in case I'm missing something obvious.

bgcolor Attribute Doesn't Work on Styles

If I try to specify a bgcolor attribute for a font style, it does not apply, but if I apply the same attribute to the individual paragraphs within the document, it works fine.

Example: This applies the font size and font face properly, but not the background:

docx.style id: 'code', name: 'Code Excerpt', size: 20, font: 'Consolas', bgcolor: 'eaeaea'
...
docx.p  'Lorem ipsum dolor....', style: 'code'

And this applies everything correctly:

docx.style id: 'code', name: 'Code Excerpt', size: 20, font: 'Consolas'
...
docx.p  'Lorem ipsum dolor....', style: 'code', bgcolor: 'eaeaea'

Titles & subtitles

Hi,

Is it possible to generate titles and subtitles? I noticed they are mentioned in the default style ids list, but I'm unsure how to use them. Am I supposed to generate a docx.h1 and attach a style? That doesn't seem to work.

Want to ask

Can you make ul li nested in table column becasue i'm keep getting error when try to iterate from data model in table and can this gem generate page header beacause i want to give image logo in my docx header?

Dynamic Images

Hi there! I've been trying to echo out dynamic images in a generated doc using Caracal-Rails. I tried doing this like so:

docx.img image_url('#{@customer.main_photo}'), width: 300, height: 200, align: 'right'

and got the error: "bad URI(is not URI?): http://localhost:3000/images/#{customer.main_photo}"

I tried this:

docx.img image_tag(@customer.main_photo), width: 300, height: 200, align: 'right'

& got this error:
No such file or directory @ rb_sysopen - <img src="/system/customers/main_photos/000/000/013/original/Main.jpg?1476818582" alt="Main" />

Finally tried:

docx.img image_url(@customer.main_photo), width: 300, height: 200, align: 'right'

and got: "Net::ReadTimeout in Customers#onesheet_doc"

Allow text to wrap around images (i.e., support image floating)

Is there any way to switch from inline image to wrapping text around the image? It seems that images are hardcoded as inline images, is this correct or is there any way of changing it?

I tried to figure out how to change the xml, but i can't find any good documentation on how to make text wrap around the image.

Ruby question: using params within list block?

Apologies for the question more related to ruby scoping, but wondering if you or anyone has come across this in caracal and has a better way of solving it:

In a list block (i.e., the block that gets passed to the list to provide the contents of the list), I cannot use instance variables or local variables that are defined in the scope of the view (e.g., the params[] hash). Hence, I can't easily customize the text that goes into the list blocks.

Example (doesn't work):

docx.ol do
  li do
    text "here is a param from the form: #{ params[:name_field] }"
  end
end

I'm working around it by defining a global hash containing the customized text outside the list block, then referencing the global hash within the list block. It's an ugly hack but it works.

Example (works but ugly):

$gp = {
  :txt => params[:name_field]
}
docx.ol do
  li do
    text "here is a param from the form: #{ $gp[:txt] }"
  end
end

I didn't see this addressed in caracal-example. Any other options for something like this?

Pass through option?

I'm working on taking a text area that renders html, and want to pass it through to my docx file. I can't seem to find a way to render my converted html text that i've already converted to docx format (example: <w:br/>) and have it show up in the file.

Is there a pass through option that takes takes docx formatted string and drops it into the document? or is there another option available?

Is there any way to display text with Rich Text Format?

Is there any way to display text with Rich Text Format with proper stylings?
eg.

"<em><strong><span style=\"color:#0000FF\">Hello</span></strong> <strong><span style=\"color:#008000\">World</span></strong></em>"

Thanks!

Image Links

Does Caracal have the ability to display images as links?
I've tried writing this a number of ways and my best guess so far has been:

`soundcloud_image = image_url('soundcloud-icon.png')
c3 = Caracal::Core::Models::TableCellModel.new do
img soundcloud_image, width: 60, height: 60
docx.p do
link (soundcloud_image), 'https://www.soundcloud.com'
end
end

docx.table [[c3]] do
end`

I haven't been able to find anything in the documentation on it. Thanks in advance for your help!

Paragraph bold true doesn't seem to work while styles work

I have a tabel cell that looks like this:

docx.style { id 'NormalBold'; name 'NormalBold'; font 'Arial'; bold true }
cell = Caracal::Core::Models::TableCellModel.new do
  p('This is bold') { style 'NormalBold' }
  p('This is not bold') { bold true }
end

i.e the the style works, but setting bold on the paragraph does not.

docx.img hangs on docx.render

I'm using the following code:

docx.img image_url('logo-256.png'), width: 256, height: 256

Which according to byebug causes docx.render to hang infinitely. I've tried with several URLs and multiple settings.

Caracal 0.3.0, Caracal-rails 0.2.0, Ruby 2.2.2, Rails 4.2.1.

Any ideas?

EDIT: Confirmed to hang on Ruby 2.1.4 as well

Table with no borders not working

docx.table [['Header 1','Header 2'],['Cell 1', 'Cell 2']] do
  border_size    0          # sets the border width. defaults to 0. units in twips.
end

dependency on tilt conflict with sass-rails

I'm getting this when i try to bundle caracal:

Bundler could not find compatible versions for gem "tilt":
  In Gemfile:
    caracal (>= 0) ruby depends on
      tilt (~> 1.4) ruby

    sass-rails (~> 5.0) ruby depends on
      tilt (2.0.1)

My temporary solution was to add gem 'tilt', '~> 1.4' to my gem file and then bundle update tilt, but it might be better if caracal could handle tilt 2.0 and above?

Image cannot be displayed

Hi, I have an issue with displaying images. This works:

docx.img 'http://www.anexternalwebsite.co.uk/images/logo.gif', width: 200, height: 60

however this doesn't:

docx.img 'app/assets/images/logo.gif', width: 200, height: 60

The path is recognised, and the doc is generated, but the image is displayed in the doc with a cross and "This image cannot currently be displayed."

Any help much appreciated! Great gem by the way!

Omar

Unable to change font in the middle of a paragraph

I would like to change the font of one word in the middle of a paragraph, that is in a table cell. Here is the code I wrote, but it seems to have no effect.

docx.font do
name 'Courier New'
end

docx.style(id: 'UML', name: 'UML', font:'Courier New', size: 12 * 2)

   row[3] = 
      Caracal::Core::Models::TableCellModel.new do
        p do 
          text "The " 
          text e.name, style: 'UML'
          text " property "
          text e.documentation
        end
      end

I had previously tried something similar, with this code instead, but that didn't work either

text e.name, font: 'Courier New'

list_style not working?

I'm trying to replicate an existing Word template, and I'm having trouble making list_style work. I run the following code at the top of my view:

docx.list_style do
    type    :ordered
    level   0
    format  'decimal'
    value   '%1.'
    align   :both
    indent  1440
    left    720
end

But it seems to get messed up somewhere in the middle. The document it produces has the line wrap correct (the "marker" seems to go at 0.5" from the margin while the first line of the list item begins at 1" from the margin; subsequent lines of text wrap to 0" from the margin), but the marker itself does not appear in the generated document.

The relevant section of the numbering.xml document reads:

    <w:abstractNum w:abstractNumId="0">
        <w:nsid w:val="58A1624D"/>
        <w:multiLevelType w:val="multilevel"/>
        <w:tmpl w:val="5F7E016C"/>
        <w:lvl w:ilvl="0">
            <w:numFmt w:val="none"/>
            <w:lvlText w:val=""/>
            <w:lvlJc w:val="left"/>
            <w:pPr>
                <w:tabs>
                    <w:tab w:val="num" w:pos="360"/>
                </w:tabs>
            </w:pPr>
        </w:lvl>

As you can see, the numFmt element gets defined as "none" and the lvlText gets a blank string. I'm not an expert at Ruby but looking through the caracal code, it seems that maybe the data structure isn't being filled properly with the list_styles command I entered?

(Also, curious to note that the documentation suggests 'left' should be > 'indent' but when I set it as above, the indentation seems correct as I've described.... It's a good bit different than the numbering.xml produced by Word, which has a w:ind element with a w:left and w:hanging option that seem to specify the right twips values, so maybe this is just a fluke that Word renders it OK.)

I'll continue to dig, but am I missing something basic here? Any thoughts on how to get this to work?

Carriage returns

Hi

I have a text area with carriage returns. However these do not show on the caracal output. How can I get the text area to be displayed as entered pls including carriage returns?

Thanks!

Omar

Page Orientation

Hello!

I absolutely love the Caracal gem, it is truly awesome!

I have a request. While I can produce a Word document that "looks like" it is in landscape orientation, it still tries to print out as portrait. This means the end users have to make sure they set the printer page orientation manually before printing, which they tend to forget.

Is there any way of setting the page orientation to landscape "properly", rather than the current fiddle I use as follows:

landscape

docx.page_size do
width 16837 # sets the page width. units in twips = 297 mm
height 11905 # sets the page height. units in twips = 210 mm
end

portrait

docx.page_size do
width 11905 # sets the page width. units in twips = 210 mm
height 16837 # sets the page height. units in twips = 297 mm
end

It would also be great to tell Word that the document to be printed is A4, letter etc.

I'd have a go at this myself, but this is way beyond my competency level! :)

Cheers,

Michael

ActionView::Template::Error (undefined method `image_url')

Hello,
It seem the method 'image_url' is not implemented in a cell table like in your example.

when I put like in your example:

c1 = Caracal::Core::Models::TableCellModel.new do
img image_url('http://sweetclipart.com/multisite/sweetclipart/files/big_gold_star.png'), width: 120, height: 60
end

docx.table [[c1]] do
cell_style cols[0], width: 120
end

It return me this error :
ActionView::Template::Error (undefined method `image_url' for #Caracal::Core::Models::TableCellModel:0x007f5f53f465c8):

when I simply put :
docx.img image_url('http://sweetclipart.com/multisite/sweetclipart/files/big_gold_star.png'), width: 120, height: 60
My image is printed correctly.

I don't know if it's an issue or anything else?

PS : I have two column in my table but I have simplified to one.

Change list rendering to support nicer output when alignment is :both

I can include a new line break within a list (so that a given list item looks like it spans multiple paragraphs) like so:

Example

docx.ol do
  li do
    text "This is the first list item."
    br
    br
    text "This is the same first list item, but a new 'paragraph.'"
    br
  end
  li do
    text "This is the second list item."
  end
end

With this code, Caracal creates a document.xml that looks something like (for the first list item):

...
        <w:p w:rsidP="00000000" w:rsidRDefault="00000000" w:rsidR="00000000" w:rsidRPr="00000000" w:rsidDel="00000000">
            <w:pPr>
                <w:numPr>
                    <w:ilvl w:val="0"/>
                    <w:numId w:val="1"/>
                </w:numPr>
                <w:ind w:left="1440" w:hanging="719"/>
                <w:contextualSpacing w:val="1"/>
                <w:rPr>
                    <w:u w:val="none"/>
                </w:rPr>
            </w:pPr>
            <w:r w:rsidR="00000000" w:rsidRPr="00000000" w:rsidDel="00000000">
                <w:rPr>
                    <w:rtl w:val="0"/>
                </w:rPr>
                <w:t xml:space="preserve"/>
            </w:r>
            <w:r w:rsidR="00000000" w:rsidRPr="00000000" w:rsidDel="00000000">
                <w:rPr>
                    <w:rtl w:val="0"/>
                </w:rPr>
                <w:t xml:space="preserve">This is the first list item.</w:t>
            </w:r>
            <w:r>
                <w:br/>
            </w:r>
            <w:r>
                <w:br/>
            </w:r>
            <w:r w:rsidR="00000000" w:rsidRPr="00000000" w:rsidDel="00000000">
                <w:rPr>
                    <w:rtl w:val="0"/>
                </w:rPr>
                <w:t xml:space="preserve">This is the same first list item, but a new 'paragraph.'</w:t>
            </w:r>
            <w:r>
                <w:br/>
            </w:r>
        </w:p>
...

But when my Normal text style includes "align: :both", the text is "Justified" in such a way that Word wraps the last line of each "paragraph" that comprises a list item by padding spaces between the words with an ugly amount of space. See screenshot:

bad-justify

Within Word itself, you can get around this by entering a carriage return at the end of the first list item and removing the blank list that gets created. What Word does in the generated XML is something like (Word 2010 for Windows):

...
        <w:p w:rsidR="00666E17" w:rsidRDefault="00666E17">
            <w:pPr>
                <w:numPr>
                    <w:ilvl w:val="0"/>
                    <w:numId w:val="1"/>
                </w:numPr>
                <w:ind w:hanging="719"/>
                <w:contextualSpacing/>
            </w:pPr>
            <w:r>
                <w:t>This is the first list item.</w:t>
            </w:r>
        </w:p>
        <w:p w:rsidR="00666E17" w:rsidRDefault="00666E17" w:rsidP="00666E17">
            <w:pPr>
                <w:ind w:left="1440"/>
                <w:contextualSpacing/>
            </w:pPr>
            <w:r>
                <w:br/>
            </w:r>
            <w:bookmarkStart w:id="0" w:name="_GoBack"/>
            <w:bookmarkEnd w:id="0"/>
            <w:r>
                <w:t>This is the same first list item, but a new 'paragraph.'</w:t>
            </w:r>
        </w:p>
...

Essentially, Word starts a w:p with the list property for the first paragraph of the first list item, then starts a new w:p with no list property for the second paragraph of the first list item.

Does Caracal currently support something like this? If not, I'm willing to try adding it.

Possible to use dynamic images in tables?

I've been building out a table in order to float some elements next to each other. In row5 I'm trying to display a model object's image:

row1 = ['Sounds Like'] row2 = ["#{@customer.sounds_like1}"] row3 = ["#{@customer.sounds_like2}"] row4 = ["#{@customer.sounds_like3}"] row5 = [@customer.live_photo] docx.table [row1.dup, row2.dup, row3.dup, row4.dup, row5.dup] do cell_style rows[0], bold: true, width: 100 cell_style rows, align: 'center', width: 100 end

Which just outputs the photo's path:

/system/customers/live_photos/000/000/015/original/o-FKA-TWIGS-facebook.jpg?1478194510

Not sure what I'm doing wrong here. Also, I have the Paperclip gem handling the images (incase that helps).

Thanks!

Columns

Hi. First, thanks for the work you have put on this!

Is there a way to change the number of columns in parts of the text? Suppose I wanted the first paragraph as 2 columns and the rest of the text normal. I am able to achieve a similar effect putting my text inside a table without borders with the desired number of columns, but it isn't quite the same thing.

undefined method `new' for :TableCellModel:Symbol

Hello,

There is an issue with the table cell.
When I create a cell separately I have this error :
undefined method `new' for :TableCellModel:Symbol

I create a cell like that :

c1 = Caracal::Core::Models:TableCellModel.new do
docx.h1 'hello'
end

Do you know what is the problem?

Thank in advance.

Cannot include images

Whenever i try to include an image in the template the server crashes due to ThreadError.

I'm trying to call this in show.docx.caracal:
docx.img project.thumbnail_url(:cv), width: 300, height: 300, align: :left

Where project.thumbnail_url(:cv) is http://localhost:3000/assets/cv_default-34ff320be9c011ccaef4b564c308a0518b07329df2f62055e00738f4593577fd.png (the file is delivered correctly)

Any idea why this might be happening?

Here is the error if i let the server time out:

Completed 500 Internal Server Error in 120097ms (ActiveRecord: 3.9ms)

ActionView::Template::Error (Net::ReadTimeout):
    1: docx.style do
    2:   id 'Normal'
    3:   name 'Normal'
    4:   font   'Calibri'
  app/views/cv_exports/show.docx.caracal:1:in `block in singleton class'
  app/views/cv_exports/show.docx.caracal:-2:in `instance_eval'
  app/views/cv_exports/show.docx.caracal:-2:in `singleton class'
  app/views/cv_exports/show.docx.caracal:-4:in `__tilt_70195351606480'
  app/views/cv_exports/show.docx.caracal:1:in `_app_views_cv_exports_show_docx_caracal___2175006984916252707_70195432268340'


  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_source.erb (7.3ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (2.6ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (0.9ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb within rescues/layout (73.9ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_markup.html.erb (0.3ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_inner_console_markup.html.erb within layouts/inlined_string (0.4ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/_prompt_box_markup.html.erb within layouts/inlined_string (0.4ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/style.css.erb within layouts/inlined_string (0.3ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/console.js.erb within layouts/javascript (61.0ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/main.js.erb within layouts/javascript (0.5ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/error_page.js.erb within layouts/javascript (0.4ms)
  Rendered /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.2.1/lib/web_console/templates/index.html.erb (129.1ms)


Started GET "/assets/cv_default-34ff320be9c011ccaef4b564c308a0518b07329df2f62055e00738f4593577fd.png" for ::1 at 2016-02-18 15:20:32 +0100


Started GET "/assets/cv_default-34ff320be9c011ccaef4b564c308a0518b07329df2f62055e00738f4593577fd.png" for ::1 at 2016-02-18 15:20:32 +0100
[2016-02-18 15:20:32] ERROR Errno::ECONNRESET: Connection reset by peer @ io_fillbuf - fd:18
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/httpserver.rb:80:in `eof?'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/httpserver.rb:80:in `run'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread'

Here is my entire stack trace (after i manually kill the server):

  Rendered cv_exports/show.docx.caracal (2272.8ms)
Completed 401 Unauthorized in 2340ms (ActiveRecord: 13.2ms)
[2016-02-18 15:12:54] ERROR ThreadError: Attempt to unlock a mutex which is locked by another thread
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/lock.rb:22:in `unlock'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/lock.rb:22:in `ensure in call'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/lock.rb:23:in `call'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/content_length.rb:15:in `call'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/handler/webrick.rb:88:in `service'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/httpserver.rb:138:in `service'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/httpserver.rb:94:in `run'
    /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:294:in `block in start_thread'
/Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/handler/webrick.rb:48:in `shutdown': undefined method `shutdown' for nil:NilClass (NoMethodError)
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:280:in `block in start'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:206:in `call'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:206:in `join'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:206:in `block (2 levels) in start'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:206:in `each'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:206:in `block in start'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:32:in `start'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/webrick/server.rb:162:in `start'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/handler/webrick.rb:34:in `run'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:286:in `start'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/railties-4.2.5/lib/rails/commands/server.rb:80:in `start'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:80:in `block in server'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:75:in `tap'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:75:in `server'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/railties-4.2.5/lib/rails/commands.rb:17:in `<top (required)>'
    from /Users/ohenrik/Sites/menon_projects/bin/rails:9:in `require'
    from /Users/ohenrik/Sites/menon_projects/bin/rails:9:in `<top (required)>'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/spring-1.5.0/lib/spring/client/rails.rb:28:in `load'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/spring-1.5.0/lib/spring/client/rails.rb:28:in `call'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/spring-1.5.0/lib/spring/client/command.rb:7:in `call'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/spring-1.5.0/lib/spring/client.rb:28:in `run'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/spring-1.5.0/bin/spring:49:in `<top (required)>'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/spring-1.5.0/lib/spring/binstub.rb:11:in `load'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/spring-1.5.0/lib/spring/binstub.rb:11:in `<top (required)>'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
    from /Users/ohenrik/.rbenv/versions/2.2.1/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require'
    from /Users/ohenrik/Sites/menon_projects/bin/spring:13:in `<top (required)>'
    from bin/rails:3:in `load'
    from bin/rails:3:in `<main>'
zlib(finalizer): the stream was freed prematurely.

How to display image with original size

Is there any way to display the image with it's original height and width ?
eg:
docx.img image_url('https://www.example.com/logo.png')

Currently we have to always pass the height and width options manually, otherwise it throws error.
Caracal::Errors::InvalidModelError: Images require an URL and positive size/margin values.

Thanks!

README example document should actually run

Great library! The first thing I tried to do was to copy and paste the following snippet to try caracal for myself:

screen shot 2016-06-10 at 11 59 42

It didn't work. Two things stopped me from getting this really simple example to work:

  • @mydata. I had no idea what it should look like
  • /Users/fushunpoon/.rvm/rubies/ruby-2.2.4/lib/ruby/2.2.0/open-uri.rb:358:inopen_http': 404 Not Found (OpenURI::HTTPError)` โ€”ย I presume this is because of the network image.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.