docxtor 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.coveralls.yml +1 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +4 -0
  6. data/.wrong +1 -0
  7. data/Gemfile +18 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +117 -0
  10. data/Rakefile +7 -0
  11. data/TODO.md +5 -0
  12. data/docxtor.gemspec +32 -0
  13. data/lib/docxtor.rb +30 -0
  14. data/lib/docxtor/document/builder.rb +32 -0
  15. data/lib/docxtor/document/element.rb +96 -0
  16. data/lib/docxtor/document/heading.rb +13 -0
  17. data/lib/docxtor/document/page_break.rb +14 -0
  18. data/lib/docxtor/document/paragraph.rb +125 -0
  19. data/lib/docxtor/document/root.rb +17 -0
  20. data/lib/docxtor/document/table_of_contents.rb +95 -0
  21. data/lib/docxtor/generator.rb +13 -0
  22. data/lib/docxtor/package/builder.rb +35 -0
  23. data/lib/docxtor/package/part.rb +12 -0
  24. data/lib/docxtor/template_parser.rb +38 -0
  25. data/lib/docxtor/version.rb +3 -0
  26. data/spec/docxtor/document/builder_spec.rb +16 -0
  27. data/spec/docxtor/document/heading_spec.rb +9 -0
  28. data/spec/docxtor/document/paragraph_spec.rb +56 -0
  29. data/spec/docxtor/document/root_spec.rb +20 -0
  30. data/spec/docxtor/document/table_of_contents_spec.rb +18 -0
  31. data/spec/docxtor/docxtor_spec.rb +13 -0
  32. data/spec/docxtor/package/builder_spec.rb +37 -0
  33. data/spec/docxtor/package/part_spec.rb +16 -0
  34. data/spec/docxtor/prerequisites_spec.rb +9 -0
  35. data/spec/docxtor/support/contexts/integration_context.rb +6 -0
  36. data/spec/docxtor/support/contexts/xml_builder_context.rb +11 -0
  37. data/spec/docxtor/support/examples/.gitkeep +0 -0
  38. data/spec/docxtor/support/matchers/wordprocessingml_matchers.rb +42 -0
  39. data/spec/docxtor/support/matchers/xpath_matchers.rb +46 -0
  40. data/spec/docxtor/template_parser_spec.rb +18 -0
  41. data/spec/spec_helper.rb +35 -0
  42. data/templates/.gitkeep +0 -0
  43. data/templates/default/[Content_Types].xml +16 -0
  44. data/templates/default/_rels/.rels +4 -0
  45. data/templates/default/word/_rels/document.xml.rels +13 -0
  46. data/templates/default/word/endnotes.xml +17 -0
  47. data/templates/default/word/fontTable.xml +31 -0
  48. data/templates/default/word/footer1.xml +35 -0
  49. data/templates/default/word/footer2.xml +48 -0
  50. data/templates/default/word/footnotes.xml +17 -0
  51. data/templates/default/word/numbering.xml +212 -0
  52. data/templates/default/word/settings.xml +107 -0
  53. data/templates/default/word/styles.xml +368 -0
  54. data/templates/default/word/theme/theme1.xml +2 -0
  55. data/templates/default/word/websettings.xml +4 -0
  56. metadata +265 -0
@@ -0,0 +1 @@
1
+ repo_token: 4wdVJp9RHu5gRyn96RakitmhAHQri6OFe
@@ -0,0 +1,21 @@
1
+ ~*
2
+ .DS_Store
3
+ *.swp
4
+
5
+ *.gem
6
+ *.rbc
7
+ .bundle
8
+ .config
9
+ .yardoc
10
+ Gemfile.lock
11
+ InstalledFiles
12
+ _yardoc
13
+ coverage
14
+ doc/
15
+ lib/bundler/man
16
+ pkg
17
+ rdoc
18
+ spec/reports
19
+ test/tmp
20
+ test/version_tmp
21
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1 @@
1
+ ree-1.8.7-2012.02
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - ree-1.8.7-2012.02
4
+ - 1.8.7
data/.wrong ADDED
@@ -0,0 +1 @@
1
+ color
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test, :development do
6
+ gem 'pre-commit'
7
+ end
8
+
9
+ group :test do
10
+ gem 'coveralls', :require => false
11
+ gem 'simplecov', :require => false
12
+ gem 'tconsole'
13
+ gem 'turn'
14
+ end
15
+
16
+ group :development do
17
+ gem "pry"
18
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Vasiliy Yorkin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,117 @@
1
+ docxtor
2
+ ========
3
+
4
+ [![Build Status](https://travis-ci.org/docxtor/docxtor.png?branch=master)](https://travis-ci.org/docxtor/docxtor)
5
+ [![Coverage Status](https://coveralls.io/repos/docxtor/docxtor/badge.png)](https://coveralls.io/r/docxtor/docxtor)
6
+ [![Dependency Status](https://gemnasium.com/docxtor/docxtor.png)](https://gemnasium.com/docxtor/docxtor)
7
+ [![Gem Version](http://stillmaintained.com/docxtor/docxtor.png)](http://stillmaintained.com/docxtor/docxtor)
8
+
9
+ ## Summary
10
+
11
+ Ruby docx generator.
12
+ Supported ruby versions: ree-1.8.7, mri 1.8.7
13
+
14
+ ## Features
15
+
16
+ 1. Paragraphs and headings: bold, italic, custom style id, line breaks, page breaks, spacing
17
+ 2. Table of contents
18
+
19
+ More to come, stay tuned!
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ gem 'docxtor'
26
+
27
+ And then execute:
28
+
29
+ $ bundle
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install 'docxtor'
34
+
35
+ ## Usage
36
+
37
+ ```
38
+ package = Docxtor.generate do
39
+ table_of_contents "Contents"
40
+ h 1, "heading1"
41
+
42
+ p "text1", :b => true do
43
+ style 'p1'
44
+ spacing :before => 80, :after => 240
45
+ italic; u
46
+
47
+ w "text2"
48
+ br
49
+ write "text3"
50
+ end
51
+
52
+ h 2 do
53
+ w "heading2"
54
+ line_break
55
+ write "some text"
56
+ br
57
+ write "another text"
58
+ end
59
+
60
+ p "content", :style => 'p2', :i => true, :align => 'center'
61
+ end
62
+
63
+ package.save('test.docx')
64
+ ```
65
+
66
+ more usage examples:
67
+
68
+ ```
69
+ # Usage sample:
70
+ # elements - any collection of your elements, so in this example i have:
71
+ # class Element
72
+ # attr_reader :title1, :title2, :content
73
+ # end
74
+ # elements = Array.new(5, Element)
75
+
76
+ # Somewhere in your controller:
77
+
78
+ def action_method
79
+ @stream = Docxtor.generate do
80
+ p 'Paragraph text', :align => 'center', :b => true
81
+ table_of_contents 'Table of contents'
82
+ page_break
83
+
84
+ elements.each do |el|
85
+ h 1, el.title do
86
+ spacing :before => 120, :after => 120
87
+
88
+ write el.title1
89
+ write ", blahblah "
90
+ br
91
+ write el.title2
92
+ end
93
+
94
+ p do
95
+ el.content.lines.map(&:chomp).each do |line|
96
+ write line; br
97
+ end
98
+ end
99
+
100
+ end
101
+ end
102
+
103
+ send_data(
104
+ @stream.read,
105
+ :filename => 'yourfilename.docx',
106
+ :type =>'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
107
+ )
108
+ end
109
+ ```
110
+
111
+ ## Contributing
112
+
113
+ 1. Fork it
114
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
115
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
116
+ 4. Push to the branch (`git push origin my-new-feature`)
117
+ 5. Create new Pull Request
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+ task :test => :spec
data/TODO.md ADDED
@@ -0,0 +1,5 @@
1
+ 1) Paragraph spacing support [Done]
2
+ 2) Dynamic style generation
3
+ 3) Tables
4
+ 4) Lists
5
+ 5) Images
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'docxtor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "docxtor"
8
+ spec.version = Docxtor::VERSION
9
+ spec.authors = ["Irina Bednova, Vasiliy Yorkin"]
10
+ spec.email = ["howeveririna@gmail.com, vasiliy.yorkin@gmail.com"]
11
+ spec.description = %q{Ruby docx generator, provides simple DSL for building word documents}
12
+ spec.summary = %q{Ruby docx generator}
13
+ spec.homepage = "http://github.com/docxtor/docxtor"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ # HINT: Version lock is required for ruby ree-1.8.7
24
+ spec.add_development_dependency "nokogiri", "~> 1.4.0"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "rspec-xml"
27
+ spec.add_development_dependency "wrong"
28
+
29
+ spec.add_runtime_dependency "builder"
30
+ spec.add_runtime_dependency "rubytree"
31
+ spec.add_runtime_dependency "rubyzip", "0.9.9"
32
+ end
@@ -0,0 +1,30 @@
1
+ require "builder"
2
+ require "zip/zip"
3
+
4
+ require "docxtor/version"
5
+
6
+ module Docxtor
7
+ autoload :Generator, 'docxtor/generator'
8
+ autoload :TemplateParser, 'docxtor/template_parser'
9
+
10
+ module Document
11
+ autoload :Builder, 'docxtor/document/builder'
12
+ autoload :Element, 'docxtor/document/element'
13
+ autoload :Root, 'docxtor/document/root'
14
+ autoload :Run, 'docxtor/document/run'
15
+ autoload :Text, 'docxtor/document/text'
16
+ autoload :TableOfContents, 'docxtor/document/table_of_contents'
17
+ autoload :Paragraph, 'docxtor/document/paragraph'
18
+ autoload :Heading, 'docxtor/document/heading'
19
+ autoload :PageBreak, 'docxtor/document/page_break'
20
+ end
21
+
22
+ module Package
23
+ autoload :Part, 'docxtor/package/part'
24
+ autoload :Builder, "docxtor/package/builder"
25
+ end
26
+
27
+ def self.generate(template = nil, &block)
28
+ Generator.generate(template, &block)
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ module Docxtor
2
+ module Document
3
+ class Builder
4
+ attr_accessor :content
5
+
6
+ def initialize(&block)
7
+ @content = render(&block)
8
+ end
9
+
10
+ def render(&block)
11
+ xml = ::Builder::XmlMarkup.new
12
+
13
+ xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8", :standalone => "yes"
14
+ xml.w :document, "xmlns:ve" => "http://schemas.openxmlformats.org/markup-compatibility/2006",
15
+ "xmlns:o" => "urn:schemas-microsoft-com:office:office",
16
+ "xmlns:r" => "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
17
+ "xmlns:m" => "http://schemas.openxmlformats.org/officeDocument/2006/math",
18
+ "xmlns:v" => "urn:schemas-microsoft-com:vml",
19
+ "xmlns:wp" => "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
20
+ "xmlns:w10" => "urn:schemas-microsoft-com:office:word",
21
+ "xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
22
+ "xmlns:wne" => "http://schemas.microsoft.com/office/word/2006/wordml" do
23
+ xml.w :body do
24
+ xml << Document::Root.new(&block).render(xml)
25
+ end
26
+ end
27
+
28
+ xml.target!
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,96 @@
1
+ module Docxtor
2
+ module Document
3
+ class Element
4
+ attr_accessor :elements, :xml
5
+
6
+ def self.map(mappings)
7
+ mappings.each do |name, klass|
8
+ define_method(name) do |*args, &block|
9
+ elements << klass.new(*args, &block)
10
+ end
11
+ end
12
+ end
13
+
14
+ def initialize(*args, &block)
15
+ @elements = []
16
+
17
+ # FIXME You have to call #create_params in this hook
18
+ after_initialize(*args)
19
+
20
+ instance_eval &block if block_given?
21
+ end
22
+
23
+ def render(xml)
24
+ @xml = xml
25
+ end
26
+
27
+ protected
28
+
29
+ def after_initialize *args; end
30
+
31
+ def properties
32
+ {}
33
+ end
34
+
35
+ def aliases
36
+ {}
37
+ end
38
+
39
+ def write_elements
40
+ @elements.each { |el| el.render(@xml) }
41
+ end
42
+
43
+ def write_element(name, &block)
44
+ xml.tag!("w:#{name}") do
45
+ write_properties(name)
46
+ instance_eval &block if block_given?
47
+ write_elements
48
+ end
49
+ end
50
+
51
+ def write_properties(el)
52
+ @properties = get_properties_for(el)
53
+ if @properties
54
+ xml.tag!("w:#{el}Pr") do
55
+ @properties.each { |k, v| write_property(k, v) }
56
+ end
57
+ end
58
+ end
59
+
60
+ def write_property(key, val)
61
+ if self_closing? val
62
+ xml.tag!("w:#{key}")
63
+ elsif val
64
+ if val.is_a?(Hash) && !val.empty?
65
+ xml.tag!("w:#{key}", prefixize(val))
66
+ else
67
+ xml.tag!("w:#{key}", 'w:val' => val)
68
+ end
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ def create_params(options)
75
+ @params = Hash[options.map {|k,v| [aliases[k] || k, v]}]
76
+ end
77
+
78
+ def self_closing?(val)
79
+ val == true
80
+ end
81
+
82
+ def get_properties_for(el)
83
+ props = properties[el]
84
+ if props
85
+ pairs = @params.
86
+ map { |k, v| props[k] && [props[k][:name] || props[k], v] }
87
+ Hash[pairs]
88
+ end
89
+ end
90
+
91
+ def prefixize(attrs)
92
+ Hash[attrs.map { |k, v| ["w:#{k}", v] }]
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,13 @@
1
+ module Docxtor
2
+ module Document
3
+ class Heading < Paragraph
4
+ H1 = 1
5
+ H2 = 2
6
+
7
+ def after_initialize(nesting = H1, *args)
8
+ super(*args)
9
+ @params[:style] ||= nesting
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Docxtor
2
+ module Document
3
+ class PageBreak < Element
4
+ def render(xml)
5
+ super
6
+ write_element(:p) do
7
+ write_element(:r) do
8
+ xml.w :br, 'w:type' => 'page'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,125 @@
1
+ module Docxtor
2
+ module Document
3
+ class Paragraph < Element
4
+ STYLE = 'a5'
5
+
6
+ PROPERTIES =
7
+ {
8
+ :p => {
9
+ :style => 'pStyle',
10
+ :align => 'jc',
11
+ :font_size => 'sz',
12
+ :font_size_complex => 'szCs',
13
+ :spacing => {
14
+ :name => 'spacing',
15
+ :before => 'before',
16
+ :after => 'after'
17
+ },
18
+ :indent => {
19
+ :name => 'ind',
20
+ :start => 'start',
21
+ :end => 'end',
22
+ :hanging => 'hanging'
23
+ }
24
+ },
25
+ :r => {
26
+ :bold => 'b',
27
+ :italic => 'i',
28
+ :underline => 'u'
29
+ }
30
+ }
31
+
32
+ PLAIN_PROPERTIES =
33
+ PROPERTIES[:p].reject {|k,v| v.is_a? Hash}
34
+
35
+ NESTED_PROPERTIES =
36
+ PROPERTIES[:p].reject {|k,v| !v.is_a? Hash}
37
+
38
+ def after_initialize(*args)
39
+ @contents = []
40
+ @contents << args.shift if args.first.is_a? String
41
+
42
+ create_params(args.shift || {})
43
+
44
+ NESTED_PROPERTIES.each do |name, element|
45
+ @params[name] ||= {}
46
+ end
47
+ @params[:space] ||= 'default'
48
+ end
49
+
50
+ def render(xml)
51
+ super
52
+ write_element(:p) do
53
+ write_element(:r) do
54
+ write_contents
55
+ end
56
+ end
57
+ end
58
+
59
+ PLAIN_PROPERTIES.each do |name, element|
60
+ define_method(name) { |val| @params[name] = val }
61
+ end
62
+
63
+ PROPERTIES[:r].each do |name, element|
64
+ define_method(name) { @params[name] = true }
65
+ end
66
+
67
+ NESTED_PROPERTIES.each do |name, element|
68
+ define_method(name) { |attrs| @params[name].merge!(attrs) }
69
+ end
70
+
71
+ def properties
72
+ PROPERTIES
73
+ end
74
+
75
+ def line_break
76
+ @contents << :br
77
+ end
78
+
79
+ def preserve_whitespace
80
+ @params[:space] = 'preserve'
81
+ end
82
+
83
+ def write(text)
84
+ @contents << text
85
+ end
86
+
87
+ def aliases
88
+ {
89
+ :b => :bold,
90
+ :i => :italic,
91
+ :u => :underline
92
+ }
93
+ end
94
+
95
+ private
96
+
97
+ def write_contents
98
+ @contents.each { |c| write_content(c) }
99
+ end
100
+
101
+ def write_content(content)
102
+ content == :br ?
103
+ write_line_break :
104
+ write_text(content)
105
+ end
106
+
107
+ def write_line_break
108
+ @xml.w :br
109
+ end
110
+
111
+ def write_text(text)
112
+ @xml.w :t, 'xml:space' => @params[:space] do
113
+ @xml.text! text
114
+ end
115
+ end
116
+
117
+ alias_method :b, :bold
118
+ alias_method :i, :italic
119
+ alias_method :u, :underline
120
+ alias_method :br, :line_break
121
+ alias_method :w, :write
122
+ alias_method :ind, :indent
123
+ end
124
+ end
125
+ end