Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 8003ffe3aef9fc2c1cd994502d14facffbeea14c 0 parents
@bagilevi authored
12 .gitignore
@@ -0,0 +1,12 @@
+.DS_Store
+log/*
+tmp/**/*
+*.swp
+*.swo
+nbproject
+.project
+.idea
+.idea/**
+*~
+**/*~
+
45 README.textile
@@ -0,0 +1,45 @@
+h1. DocX Builder
+
+_DocX Builder_ is a small utility to help you compose a docx (Microsoft Word 2007) based on a template's XML.
+
+The @slice_template.rb@ can be used separately for non-docx applications.
+
+The steps:
+# Create a docx file with _Microsoft Word_ or _OpenOffice.org_
+# Unzip it (the docx file is actually a ZIP package)
+# Create your template from @word/document.xml@
+# Open the template and reformat it (I used RubyMine)
+# Find the parts you need to generate programmatically, and mark them up with <!-- BEGIN SOMETHING --> ... <!-- END SOMETHING -->, see @example/plan_report_template.xml@
+# Remove the formatting (compact the XML)
+# Create your builder, see @example.rb@
+
+h2. The example explained
+
+pre.
+ _____head______ _________area_______________________________________ _foot_
+ | | | |
+ | | ________goal________________________| |
+ | | | | |
+ | | | _______objective____| |
+ | | | | | |
+ | (Plan Name) | (Area Name) | (Goal Name) | (Objective Name) | |
+ _____________________________________________________________________________
+ XML DOCUMENT
+
+You can assign a text to a placeholder:
+
+pre.
+ template['head']['Plan Name'] = @plan.name
+
+Or you can replace a slice with a string, that can be composed by multiplying that slice:
+
+pre.
+ template['area'] =
+ @plan.areas.map do |area|
+
+ area_slice = template['area'].clone
+ area_slice['Area Name'] = area.description
+ area_slice['goal'] = '...'
+ end
+
+See @example.rb@
38 docx_builder.rb
@@ -0,0 +1,38 @@
+require 'slice_template'
+
+class DocxBuilder
+ def initialize(template_filename, template_dirname)
+ @template_filename = template_filename
+ @template_dirname = template_dirname
+ end
+
+ def build
+ template = SliceTemplate.new(@template_filename);
+ yield template
+ build_docx(template.render)
+ end
+
+ private
+
+ def build_docx(content)
+ docx_content = nil
+ in_temp_dir do |temp_dir|
+ system("cp -r #{@template_dirname} #{temp_dir}/plan_report")
+ open("#{temp_dir}/plan_report/word/document.xml", "w") do |file|
+ file.write(content)
+ end
+ system("cd #{temp_dir}/plan_report; zip -r ../plan_report.docx *")
+ docx_content = File.read("#{temp_dir}/plan_report.docx")
+ end
+ docx_content
+ end
+
+ def in_temp_dir
+ temp_dir = "/tmp/docx_#{Time.now.to_f.to_s}"
+ Dir.mkdir(temp_dir)
+ yield(temp_dir)
+ system("rm -Rf #{temp_dir}")
+ end
+end
+
+
BIN  example.docx
Binary file not shown
56 example.rb
@@ -0,0 +1,56 @@
+require 'docx_builder'
+
+
+plan_struct = Struct.new(:name, :areas, :goals_by_area, :objectives_by_goal)
+area_struct = Struct.new(:description, :id)
+goal_struct = Struct.new(:description, :id)
+objective_struct = Struct.new(:description)
+@plan = plan_struct.new
+@plan.name = 'Business Plan for 2011'
+@plan.areas = [area_struct.new('Software Development', 1), area_struct.new('Cooking', 2)]
+@plan.goals_by_area = {
+ 1 => [ goal_struct.new('Create a new app', 1), goal_struct.new('Create another app', 2)],
+ 2 => [ goal_struct.new('Make a new recipe', 3), goal_struct.new('Open a restaurant', 4)],
+}
+@plan.objectives_by_goal = {
+ 1 => [ objective_struct.new('It should be interesting'), objective_struct.new('It should be simple') ],
+ 2 => [ objective_struct.new('It should be revolutionary'), objective_struct.new('It should be unique') ],
+ 3 => [ objective_struct.new('Make a unique recipe'), objective_struct.new('Make a tasty recipe') ],
+ 4 => [ objective_struct.new('Serve high quality food'), objective_struct.new('Make it cheap') ],
+}
+
+
+file_path = "#{File.dirname(__FILE__)}/example/plan_report_template.xml"
+dir_path = "#{File.dirname(__FILE__)}/example/plan_report_template"
+
+report = DocxBuilder.new(file_path, dir_path).build do |template|
+
+ template['head']['Plan Name'] = @plan.name
+ template['area'] =
+ @plan.areas.map do |area|
+
+ area_slice = template['area'].clone
+ area_slice['Area Name'] = area.description
+ area_slice['goal'] =
+ @plan.goals_by_area[area.id].map do |goal|
+
+ goal_slice = template['goal'].clone
+ goal_slice['Goal Name'] = goal.description
+ goal_slice['objective'] =
+ @plan.objectives_by_goal[goal.id].map do |objective|
+ objective_slice = template['objective'].clone
+ objective_slice['Objective Name'] = objective.description
+ objective_slice
+ end
+ goal_slice
+ end
+ area_slice
+ end
+end
+
+
+open("example.docx", "w") { |file| file.write(report) }
+
+# ... or in a Rails controller:
+# response.headers['Content-disposition'] = 'attachment; filename=plan_report.docx'
+# render :text => report, :content_type => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
2  example/plan_report_template.xml
@@ -0,0 +1,2 @@
+<!-- BEGIN HEAD --><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><w:body><w:p><w:pPr><w:pStyle w:val="style1"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr><w:spacing w:after="120" w:before="240"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Strategic Plan: (Plan Name)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style0"/></w:pPr><w:r><w:rPr></w:rPr></w:r></w:p><!-- END HEAD --><!-- BEGIN AREA --><w:p><w:pPr><w:pStyle w:val="style2"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Area: (Area Name)</w:t></w:r></w:p><!-- BEGIN GOAL --><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal Name)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><!-- BEGIN OBJECTIVE --><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="0" w:name="__DdeLink__0_226207805"/><w:bookmarkEnd w:id="0"/><w:r><w:rPr></w:rPr><w:t>(Objective Name)</w:t></w:r></w:p><!-- END OBJECTIVE --><!-- END GOAL --><!-- END AREA --><!-- BEGIN FOOT --><w:p><w:pPr><w:pStyle w:val="style17"/><w:spacing w:after="120" w:before="0"/></w:pPr><w:r><w:rPr></w:rPr></w:r></w:p><w:sectPr><w:formProt w:val="off"/><w:pgSz w:h="16838" w:w="11906"/><w:textDirection w:val="lrTb"/><w:pgNumType w:fmt="decimal"/><w:type w:val="nextPage"/><w:pgMar w:bottom="1134" w:left="1134" w:right="1134" w:top="1134"/></w:sectPr></w:body></w:document><!-- END FOOT -->
3  example/plan_report_template/[Content_Types].xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/word/_rels/document.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/><Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"/><Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
+</Types>
3  example/plan_report_template/_rels/.rels
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
+</Relationships>
2  example/plan_report_template/docProps/app.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>0</TotalTime></Properties>
2  example/plan_report_template/docProps/core.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">2010-05-28T19:47:48.00Z</dcterms:created><dc:creator>Levente Bagi</dc:creator><cp:revision>0</cp:revision></cp:coreProperties>
3  example/plan_report_template/word/_rels/document.xml.rels
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/>
+</Relationships>
2  example/plan_report_template/word/document.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:document xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><w:body><w:p><w:pPr><w:pStyle w:val="style1"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr><w:spacing w:after="120" w:before="240"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Strategic Plan: (Strategic Plan Name)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style0"/></w:pPr><w:r><w:rPr></w:rPr></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style2"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Area: (Area 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="0" w:name="__DdeLink__0_226207805"/><w:bookmarkEnd w:id="0"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="1" w:name="__DdeLink__0_2262078051"/><w:bookmarkEnd w:id="1"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="2" w:name="__DdeLink__0_22620780511"/><w:bookmarkEnd w:id="2"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style2"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Area: (Area 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="3" w:name="__DdeLink__0_2262078052"/><w:bookmarkEnd w:id="3"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="4" w:name="__DdeLink__0_22620780512"/><w:bookmarkEnd w:id="4"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="5" w:name="__DdeLink__0_226207805111"/><w:bookmarkEnd w:id="5"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style2"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Area: (Area 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="6" w:name="__DdeLink__0_2262078053"/><w:bookmarkEnd w:id="6"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="7" w:name="__DdeLink__0_22620780513"/><w:bookmarkEnd w:id="7"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style3"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>Goal: (Goal 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/></w:pPr><w:r><w:rPr></w:rPr><w:t>Objectives:</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:bookmarkStart w:id="8" w:name="__DdeLink__0_226207805112"/><w:bookmarkEnd w:id="8"/><w:r><w:rPr></w:rPr><w:t>(Objective 1)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 2)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr></w:pPr><w:r><w:rPr></w:rPr><w:t>(Objective 3)</w:t></w:r></w:p><w:p><w:pPr><w:pStyle w:val="style17"/><w:spacing w:after="120" w:before="0"/></w:pPr><w:r><w:rPr></w:rPr></w:r></w:p><w:sectPr><w:formProt w:val="off"/><w:pgSz w:h="16838" w:w="11906"/><w:textDirection w:val="lrTb"/><w:pgNumType w:fmt="decimal"/><w:type w:val="nextPage"/><w:pgMar w:bottom="1134" w:left="1134" w:right="1134" w:top="1134"/></w:sectPr></w:body></w:document>
2  example/plan_report_template/word/fontTable.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:font w:name="Times New Roman"><w:charset w:val="00"/><w:family w:val="roman"/><w:pitch w:val="variable"/></w:font><w:font w:name="Symbol"><w:charset w:val="02"/><w:family w:val="roman"/><w:pitch w:val="variable"/></w:font><w:font w:name="Arial"><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/></w:font><w:font w:name="Liberation Serif"><w:altName w:val="Times New Roman"/><w:charset w:val="80"/><w:family w:val="roman"/><w:pitch w:val="variable"/></w:font></w:fonts>
2  example/plan_report_template/word/numbering.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:abstractNum w:abstractNumId="1"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="432" w:left="432"/></w:pPr></w:lvl><w:lvl w:ilvl="1"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="576" w:left="576"/></w:pPr></w:lvl><w:lvl w:ilvl="2"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="720" w:left="720"/></w:pPr></w:lvl><w:lvl w:ilvl="3"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="864" w:left="864"/></w:pPr></w:lvl><w:lvl w:ilvl="4"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="1008" w:left="1008"/></w:pPr></w:lvl><w:lvl w:ilvl="5"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="1152" w:left="1152"/></w:pPr></w:lvl><w:lvl w:ilvl="6"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="1296" w:left="1296"/></w:pPr></w:lvl><w:lvl w:ilvl="7"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="1440" w:left="1440"/></w:pPr></w:lvl><w:lvl w:ilvl="8"><w:start w:val="1"/><w:numFmt w:val="none"/><w:lvlJc w:val="left"/><w:suff w:val="nothing"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="1584" w:left="1584"/></w:pPr></w:lvl></w:abstractNum><w:abstractNum w:abstractNumId="2"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="720"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="1"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="1080"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="2"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="1440"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="3"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="1800"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="4"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="2160"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="5"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="2520"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="6"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="2880"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="7"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="3240"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl><w:lvl w:ilvl="8"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlJc w:val="left"/><w:lvlText w:val=""/><w:pPr><w:ind w:hanging="360" w:left="3600"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:cs="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl></w:abstractNum><w:num w:numId="1"><w:abstractNumId w:val="1"/></w:num><w:num w:numId="2"><w:abstractNumId w:val="2"/></w:num></w:numbering>
2  example/plan_report_template/word/styles.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:style w:styleId="style0" w:type="paragraph"><w:name w:val="Default"/><w:next w:val="style0"/><w:pPr><w:widowControl w:val="off"/><w:tabs><w:tab w:leader="none" w:pos="709" w:val="left"/></w:tabs><w:suppressAutoHyphens w:val="true"/></w:pPr><w:rPr><w:color w:val="auto"/><w:sz w:val="24"/><w:szCs w:val="24"/><w:rFonts w:ascii="Liberation Serif" w:cs="DejaVu Sans" w:eastAsia="DejaVu Sans" w:hAnsi="Liberation Serif"/><w:lang w:bidi="hi-IN" w:eastAsia="zh-CN" w:val="en-GB"/></w:rPr></w:style><w:style w:styleId="style1" w:type="paragraph"><w:name w:val="Heading 1"/><w:basedOn w:val="style16"/><w:next w:val="style17"/><w:pPr><w:outlineLvl w:val="0"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr></w:pPr><w:rPr><w:sz w:val="32"/><w:b/><w:szCs w:val="32"/><w:bCs/></w:rPr></w:style><w:style w:styleId="style2" w:type="paragraph"><w:name w:val="Heading 2"/><w:basedOn w:val="style16"/><w:next w:val="style17"/><w:pPr><w:outlineLvl w:val="1"/><w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr></w:pPr><w:rPr><w:sz w:val="28"/><w:i/><w:b/><w:szCs w:val="28"/><w:iCs/><w:bCs/></w:rPr></w:style><w:style w:styleId="style3" w:type="paragraph"><w:name w:val="Heading 3"/><w:basedOn w:val="style16"/><w:next w:val="style17"/><w:pPr><w:outlineLvl w:val="2"/><w:numPr><w:ilvl w:val="2"/><w:numId w:val="1"/></w:numPr></w:pPr><w:rPr><w:sz w:val="28"/><w:b/><w:szCs w:val="28"/><w:bCs/></w:rPr></w:style><w:style w:styleId="style15" w:type="character"><w:name w:val="Bullets"/><w:next w:val="style15"/><w:rPr><w:rFonts w:ascii="OpenSymbol" w:cs="OpenSymbol" w:eastAsia="OpenSymbol" w:hAnsi="OpenSymbol"/></w:rPr></w:style><w:style w:styleId="style16" w:type="paragraph"><w:name w:val="Heading"/><w:basedOn w:val="style0"/><w:next w:val="style17"/><w:pPr><w:keepNext/><w:spacing w:after="120" w:before="240"/></w:pPr><w:rPr><w:sz w:val="28"/><w:szCs w:val="28"/><w:rFonts w:ascii="Liberation Sans" w:cs="DejaVu Sans" w:eastAsia="DejaVu Sans" w:hAnsi="Liberation Sans"/></w:rPr></w:style><w:style w:styleId="style17" w:type="paragraph"><w:name w:val="Text body"/><w:basedOn w:val="style0"/><w:next w:val="style17"/><w:pPr><w:spacing w:after="120" w:before="0"/></w:pPr><w:rPr></w:rPr></w:style><w:style w:styleId="style18" w:type="paragraph"><w:name w:val="List"/><w:basedOn w:val="style17"/><w:next w:val="style18"/><w:pPr></w:pPr><w:rPr></w:rPr></w:style><w:style w:styleId="style19" w:type="paragraph"><w:name w:val="Caption"/><w:basedOn w:val="style0"/><w:next w:val="style19"/><w:pPr><w:suppressLineNumbers/><w:spacing w:after="120" w:before="120"/></w:pPr><w:rPr><w:sz w:val="24"/><w:i/><w:szCs w:val="24"/><w:iCs/></w:rPr></w:style><w:style w:styleId="style20" w:type="paragraph"><w:name w:val="Index"/><w:basedOn w:val="style0"/><w:next w:val="style20"/><w:pPr><w:suppressLineNumbers/></w:pPr><w:rPr></w:rPr></w:style></w:styles>
105 slice_template.rb
@@ -0,0 +1,105 @@
+class SliceTemplate
+
+ attr_reader :content
+ attr_accessor :slices
+
+
+ def initialize(filename)
+ @content = File.read(filename)
+ @slices = {}
+ parse
+ end
+
+ def initialize_copy(other)
+ @content = other.content.clone
+ @slices = other.slices.clone
+ end
+
+ def [](slice_name)
+ @slices[slice_name] = Slice.new(@slices[slice_name]) unless @slices[slice_name].instance_of?(Slice)
+ @slices[slice_name]
+ end
+
+ def []=(slice_name, value)
+ if value.instance_of?(Array)
+ @slices[slice_name] = value.map do |item|
+ item.instance_of?(Slice) ? item.render : item
+ end
+ else
+ @slices[slice_name] = value
+ end
+ end
+
+ def render
+ render_string(@content)
+ end
+
+ alias_method :to_s, :render
+
+
+ private
+
+
+ def parse
+ parse_string(@content)
+ end
+
+ def parse_string(s)
+ s.gsub!(/<\!-- BEGIN ([^>]+) -->(.+)<\!-- END \1 -->/m).each do |match|
+ slice_name, content = [$1.downcase, $2]
+ parse_string(content)
+ @slices[slice_name] = content
+ "(#{slice_name})"
+ end
+ end
+
+ def render_string(s)
+ return if s.nil?
+ s.gsub(/\(([\w\d _]+)\)/) do |match|
+ slot_name = $1
+ slice = @slices[slot_name]
+ slice.nil? ? match : render_string(slice.to_s)
+ end
+ end
+
+
+ class Slice
+ attr_reader :slots
+
+ def initialize(content)
+ @content = content
+ parse
+ end
+
+ def parse
+ @slots = Hash[@content.scan(/\(([\w\d _]+)\)/).map{|slot_name| [slot_name, "(#{slot_name})"] }]
+ end
+
+ def [](slot_name)
+ @slots[slot_name]
+ end
+
+ def []=(slot_name, value)
+ @slots[slot_name] = value
+ end
+
+ def set(slot_name, value)
+ @slots[slot_name] = value
+ self
+ end
+
+ def render
+ @content.gsub(/\(([\w\d _]+)\)/) do |match|
+ slot_name = $1
+ @slots[slot_name]
+ end
+ end
+
+ alias_method :to_s, :render
+
+ def initialize_copy(other)
+ @slots = other.slots.clone
+ end
+ end
+
+end
Please sign in to comment.
Something went wrong with that request. Please try again.