docxtor2 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +21 -0
  4. data/.rspec +2 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +6 -0
  7. data/.wrong +1 -0
  8. data/Gemfile +18 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +71 -0
  11. data/Rakefile +7 -0
  12. data/TODO.md +2 -0
  13. data/docxtor2.gemspec +32 -0
  14. data/lib/docxtor2.rb +39 -0
  15. data/lib/docxtor2/block_evaluator.rb +13 -0
  16. data/lib/docxtor2/constants.rb +4 -0
  17. data/lib/docxtor2/content_builder.rb +29 -0
  18. data/lib/docxtor2/document_builder.rb +19 -0
  19. data/lib/docxtor2/element_list.rb +26 -0
  20. data/lib/docxtor2/generator.rb +12 -0
  21. data/lib/docxtor2/known/aliases.rb +11 -0
  22. data/lib/docxtor2/known/mappings.rb +31 -0
  23. data/lib/docxtor2/known/parts.rb +9 -0
  24. data/lib/docxtor2/known/path.rb +11 -0
  25. data/lib/docxtor2/known/styles.rb +10 -0
  26. data/lib/docxtor2/known/templates.rb +7 -0
  27. data/lib/docxtor2/object_utils.rb +7 -0
  28. data/lib/docxtor2/package.rb +33 -0
  29. data/lib/docxtor2/package/document.rb +28 -0
  30. data/lib/docxtor2/package/document/element.rb +89 -0
  31. data/lib/docxtor2/package/document/heading.rb +11 -0
  32. data/lib/docxtor2/package/document/page_break.rb +16 -0
  33. data/lib/docxtor2/package/document/paragraph.rb +90 -0
  34. data/lib/docxtor2/package/document/table_of_contents.rb +90 -0
  35. data/lib/docxtor2/package/part.rb +10 -0
  36. data/lib/docxtor2/template_parser.rb +42 -0
  37. data/lib/docxtor2/version.rb +3 -0
  38. data/spec/docxtor2/content_builder_spec.rb +24 -0
  39. data/spec/docxtor2/docxtor2_spec.rb +13 -0
  40. data/spec/docxtor2/package/document/element_spec.rb +20 -0
  41. data/spec/docxtor2/package/document/heading_spec.rb +9 -0
  42. data/spec/docxtor2/package/document/paragraph_spec.rb +56 -0
  43. data/spec/docxtor2/package/document/table_of_contents_spec.rb +18 -0
  44. data/spec/docxtor2/package/document_spec.rb +13 -0
  45. data/spec/docxtor2/package/part_spec.rb +16 -0
  46. data/spec/docxtor2/package_spec.rb +37 -0
  47. data/spec/docxtor2/prerequisites_spec.rb +9 -0
  48. data/spec/docxtor2/support/contexts/integration_context.rb +6 -0
  49. data/spec/docxtor2/support/contexts/xml_builder_context.rb +11 -0
  50. data/spec/docxtor2/support/examples/.gitkeep +0 -0
  51. data/spec/docxtor2/support/matchers/wordprocessingml_matchers.rb +42 -0
  52. data/spec/docxtor2/support/matchers/xpath_matchers.rb +46 -0
  53. data/spec/docxtor2/template_parser_spec.rb +18 -0
  54. data/spec/spec_helper.rb +35 -0
  55. data/templates/.gitkeep +0 -0
  56. data/templates/default/[Content_Types].xml +16 -0
  57. data/templates/default/_rels/.rels +4 -0
  58. data/templates/default/word/_rels/document.xml.rels +13 -0
  59. data/templates/default/word/endnotes.xml +17 -0
  60. data/templates/default/word/fontTable.xml +31 -0
  61. data/templates/default/word/footer1.xml +35 -0
  62. data/templates/default/word/footer2.xml +48 -0
  63. data/templates/default/word/footnotes.xml +17 -0
  64. data/templates/default/word/numbering.xml +212 -0
  65. data/templates/default/word/settings.xml +107 -0
  66. data/templates/default/word/styles.xml +368 -0
  67. data/templates/default/word/theme/theme1.xml +2 -0
  68. data/templates/default/word/websettings.xml +4 -0
  69. metadata +212 -0
@@ -0,0 +1,7 @@
1
+ module Docxtor2
2
+ module Known
3
+ module Templates
4
+ DEFAULT = File.join(Path::TEMPLATES, 'default')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Docxtor2
2
+ module ObjectUtils
3
+ def find_argument(args, klass, default = nil)
4
+ args.find { |arg| arg.is_a? klass } || default
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Docxtor2
2
+ class Package
3
+ attr_reader :parts
4
+
5
+ def initialize(parts, document)
6
+ @parts = parts
7
+ @parts[Known::Parts::DOCUMENT] = document
8
+ end
9
+
10
+ def save(filepath)
11
+ Zip::ZipOutputStream.open(filepath) do |ostream|
12
+ write_parts(ostream)
13
+ end
14
+ end
15
+
16
+ def to_stream
17
+ ostream = Zip::ZipOutputStream.new("streamed", true)
18
+ write_parts(ostream)
19
+ string_io = ostream.close_buffer
20
+ string_io.rewind
21
+ string_io
22
+ end
23
+
24
+ private
25
+
26
+ def write_parts(ostream)
27
+ @parts.each do |name, part|
28
+ ostream.put_next_entry(part.filename)
29
+ ostream.puts part.content
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module Docxtor2
2
+ class Package::Document < Package::Part
3
+ def initialize(content, filepath = DOCUMENT_XML_PATH)
4
+ super(filepath, self.class.render(content))
5
+ end
6
+
7
+ def self.render(content)
8
+ xml = Builder::XmlMarkup.new
9
+
10
+ xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8", :standalone => "yes"
11
+ xml.w :document, "xmlns:ve" => "http://schemas.openxmlformats.org/markup-compatibility/2006",
12
+ "xmlns:o" => "urn:schemas-microsoft-com:office:office",
13
+ "xmlns:r" => "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
14
+ "xmlns:m" => "http://schemas.openxmlformats.org/officeDocument/2006/math",
15
+ "xmlns:v" => "urn:schemas-microsoft-com:vml",
16
+ "xmlns:wp" => "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
17
+ "xmlns:w10" => "urn:schemas-microsoft-com:office:word",
18
+ "xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
19
+ "xmlns:wne" => "http://schemas.microsoft.com/office/word/2006/wordml" do
20
+ xml.w :body do
21
+ xml << content
22
+ end
23
+ end
24
+
25
+ xml.target!
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,89 @@
1
+ module Docxtor2
2
+ class Package::Document::Element < ElementList
3
+ include BlockEvaluator
4
+ include ObjectUtils
5
+
6
+ def initialize(*args, &block)
7
+ @params = create_attributes(args)
8
+ @block = block
9
+ super()
10
+ end
11
+
12
+ def render(xml)
13
+ @xml = xml
14
+ evaluate &@block
15
+ end
16
+
17
+ protected
18
+
19
+ def mappings
20
+ {}
21
+ end
22
+
23
+ def aliases
24
+ {}
25
+ end
26
+
27
+ def write_element(name, &block)
28
+ @xml.tag!("w:#{name}") do
29
+ write_properties(name)
30
+ evaluate &block
31
+ write_elements(@xml)
32
+ end
33
+ end
34
+
35
+ def write_properties(el)
36
+ @properties = get_properties_for(el)
37
+ unless @properties.nil?
38
+ @xml.tag!("w:#{el}Pr") do
39
+ @properties.each { |k, v| write_property(k, v) }
40
+ end
41
+ end
42
+ end
43
+
44
+ def write_property(key, val)
45
+ if self_closing? val
46
+ @xml.tag!("w:#{key}")
47
+ elsif !val.nil?
48
+ if val.is_a?(Hash) && !val.empty?
49
+ @xml.tag!("w:#{key}", prefixize(val))
50
+ elsif !val.to_s.empty?
51
+ @xml.tag!("w:#{key}", 'w:val' => val)
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def create_attributes(args)
59
+ hash = find_argument(args, Hash, {})
60
+ pairs = hash.map do |k, v|
61
+ aliases.key?(k) ? [aliases[k], v] : [k, v]
62
+ end
63
+ Hash[pairs]
64
+ end
65
+
66
+ def self_closing?(val)
67
+ !!val == val && val
68
+ end
69
+
70
+ def get_properties_for(el)
71
+ map = mappings[el]
72
+ unless map.nil?
73
+ pairs = @params.
74
+ reject { |k, v| !map.key?(k) }.
75
+ map { |k, v|
76
+ element = map[k]
77
+ element.is_a?(Hash) ?
78
+ [element[:name], v] :
79
+ [element, v]
80
+ }
81
+ Hash[pairs]
82
+ end
83
+ end
84
+
85
+ def prefixize(attrs)
86
+ Hash[attrs.map { |k, v| ["w:#{k}", v] }]
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,11 @@
1
+ module Docxtor2
2
+ class Package::Document::Heading < Package::Document::Paragraph
3
+ H1 = 1
4
+ H2 = 2
5
+
6
+ def initialize(nesting = H1, *args, &block)
7
+ super(*args, &block)
8
+ @params[:style] ||= nesting
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Docxtor2
2
+ class Package::Document::PageBreak < Package::Document::Element
3
+ def initialize(*args, &block)
4
+ super(*args, &block)
5
+ end
6
+
7
+ def render(xml)
8
+ super(xml)
9
+ write_element(:p) do
10
+ write_element(:r) do
11
+ @xml.w :br, 'w:type' => 'page'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,90 @@
1
+ module Docxtor2
2
+ class Package::Document::Paragraph < Package::Document::Element
3
+ def initialize(*args, &block)
4
+ super(*args, &block)
5
+ Known::Mappings::PARAGRAPH_COMPLEX.each do |name, element|
6
+ @params[name] ||= {}
7
+ end
8
+ @params[:space] ||= 'default'
9
+ @contents = create_contents(args)
10
+ end
11
+
12
+ def render(xml)
13
+ super(xml)
14
+ write_element(:p) do
15
+ write_element(:r) do
16
+ write_contents
17
+ end
18
+ end
19
+ end
20
+
21
+ Known::Mappings::PARAGRAPH_SIMPLE.each do |name, element|
22
+ define_method(name) { |val| @params[name] = val }
23
+ end
24
+ Known::Mappings::RUN.each do |name, element|
25
+ define_method(name) { @params[name] = true }
26
+ end
27
+ Known::Mappings::PARAGRAPH_COMPLEX.each do |name, element|
28
+ define_method(name) { |attrs| @params[name].merge!(attrs) }
29
+ end
30
+
31
+ def line_break
32
+ @contents << :br
33
+ end
34
+
35
+ def preserve_whitespace
36
+ @params[:space] = 'preserve'
37
+ end
38
+
39
+ def write(text)
40
+ @contents << text
41
+ end
42
+
43
+ protected
44
+
45
+ def mappings
46
+ super.merge({
47
+ :p => Known::Mappings::PARAGRAPH,
48
+ :r => Known::Mappings::RUN
49
+ })
50
+ end
51
+
52
+ def aliases
53
+ super.merge(Known::Aliases::PARAGRAPH)
54
+ end
55
+
56
+ private
57
+
58
+ def write_contents
59
+ @contents.each { |c| write_content(c) }
60
+ end
61
+
62
+ def write_content(content)
63
+ content == :br ?
64
+ write_line_break :
65
+ write_text(content)
66
+ end
67
+
68
+ def write_line_break
69
+ @xml.w :br
70
+ end
71
+
72
+ def write_text(text)
73
+ @xml.w :t, 'xml:space' => @params[:space] do
74
+ @xml.text! text
75
+ end
76
+ end
77
+
78
+ def create_contents(args)
79
+ str = find_argument(args, String)
80
+ str.nil? ? [] : [str]
81
+ end
82
+
83
+ alias_method :b, :bold
84
+ alias_method :i, :italic
85
+ alias_method :u, :underline
86
+ alias_method :br, :line_break
87
+ alias_method :w, :write
88
+ alias_method :ind, :indent
89
+ end
90
+ end
@@ -0,0 +1,90 @@
1
+ module Docxtor2
2
+ class Package::Document::TableOfContents < Package::Document::Element
3
+ def initialize(text, &block)
4
+ super({ :style => Known::Styles::TOC }, &block)
5
+ @text = text
6
+ end
7
+
8
+ # TODO: Add support for extended styling & properties
9
+
10
+ def render(xml)
11
+ super(xml)
12
+
13
+ @xml.w :sdt, "xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main" do
14
+
15
+ write_properties
16
+
17
+ @xml.w :sdtContent do
18
+
19
+ write_heading
20
+
21
+ @xml.w :p do
22
+ @xml.w :pPr do
23
+ @xml.w :pStyle, "w:val" => Known::Styles::TOC_PARAGRAPH
24
+ @xml.w :tabs do
25
+ @xml.w :tab, "w:val" => "right", "w:leader" => "dot", "w:pos" => 9350
26
+ end
27
+ @xml.w :rPr do
28
+ @xml.w :noProof
29
+ end
30
+ end
31
+ @xml.w :r do
32
+ @xml.w :fldChar, "w:fldCharType" => "begin", "w:dirty" => true
33
+ end
34
+
35
+ write_instruct
36
+
37
+ @xml.w :r do
38
+ @xml.w :fldChar, "w:fldCharType" => "separate"
39
+ end
40
+ end
41
+
42
+ @xml.w :p do
43
+ @xml.w :r do
44
+ # @xml.w :rPr do
45
+ # @xml.w :b
46
+ # @xml.w :bCs
47
+ # @xml.w :noProof
48
+ # end
49
+ @xml.w :fldChar, "w:fldCharType" => "end"
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def write_properties
60
+ @xml.w :sdtPr do
61
+ @xml.w :docPartObj do
62
+ @xml.w :docPartGallery, "w:val" => "Table of Contents"
63
+ @xml.w :docPartUnique
64
+ end
65
+ end
66
+ end
67
+
68
+ def write_heading
69
+ @xml.w :p do
70
+ @xml.w :pPr do
71
+ @xml.w :pStyle, "w:val" => @params[:style]
72
+ end
73
+ @xml.w :r do
74
+ @xml.w :t do
75
+ @xml.text! @text
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def write_instruct
82
+ @xml.w :r do
83
+ @xml.w :instrText, "xml:space" => "preserve" do
84
+ @xml.text! " TOC \\o '1-3' \\h \\z \\u "
85
+ end
86
+ end
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,10 @@
1
+ module Docxtor2
2
+ class Package::Part
3
+ attr_reader :filename, :content
4
+
5
+ def initialize(filename, content)
6
+ @filename = filename
7
+ @content = content
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ module Docxtor2
2
+ class TemplateParser
3
+
4
+ class << self
5
+ def parse(template)
6
+ instance = new(template)
7
+ instance.parts
8
+ end
9
+ end
10
+
11
+ def initialize(template)
12
+ @parts = parse(template)
13
+ end
14
+
15
+ def parts
16
+ @parts
17
+ end
18
+
19
+ private
20
+
21
+ def parse(template)
22
+ Dir.chdir(template) do
23
+ Hash[create_parts]
24
+ end
25
+ end
26
+
27
+ def create_parts
28
+ Dir[SEARCH_PATTERN].
29
+ delete_if { |file| File.directory?(file) }.
30
+ map { |file| create_part(file) }
31
+ end
32
+
33
+ def create_part(file)
34
+ content = File.read(file)
35
+ part = Package::Part.new(file, content)
36
+ key = File.basename(file, '.xml')
37
+
38
+ [key, part]
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module Docxtor2
2
+ VERSION = "0.0.9"
3
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Docxtor2
4
+ describe ContentBuilder do
5
+ include WordprocessingMLMatchers
6
+
7
+ subject {
8
+ ContentBuilder.build do
9
+ table_of_contents 'Contents'
10
+ p :style => 3 do
11
+ write "content 1"
12
+ line_break
13
+ write "content 2"
14
+ end
15
+ end
16
+ }
17
+
18
+ it 'renders given DSL instructions' do
19
+ subject.should contain_paragraph_text
20
+ subject.should contain_element_style(:p)
21
+ subject.should contain_table_of_contents
22
+ end
23
+ end
24
+ end