docxtor2 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
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