serenity-odt-patched 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 20fefb8225508044218e19271f67eb58a4abe1c5
4
+ data.tar.gz: 97371f993fa1494e7851f9a4e7dd42da477be5dd
5
+ SHA512:
6
+ metadata.gz: 74a2fd49d0d3b709a542e95bc1c23ab2200f1e323b8d1d96b3901ece332055e02ea5f71d80f63d2377dc4b7495081f38274be51747b1749f482e37809c62e9fc
7
+ data.tar.gz: 19c3b6374a777b05189e59c05097fe88b3f0546815892c0888b8ea8fbd5a97056070fdce3fca356c663a4672e0796d677f19a3c11c55be2cbe5d5c1f85762e06
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2010 Tomas Kramar
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Patch
2
+ Forked to make small tweaks. The original is at https://github.com/kremso/serenity/tree/master/showcase
3
+
4
+ ## Changes
5
+ 1. changed all require 'zip/zip' to require 'zip' to patch bug with rubyzip gem
6
+
7
+ ## Todo
8
+ 1. add paramiter to change output of file for render_odt function instead of name_of_template_output.odt
9
+
10
+ Serenity is an embedded ruby for OpenOffice documents (.odt files). You provide an .odt template with ruby code inside a special markup and the data and Serenity generates the document. If you know erb all of this should sound familiar.
11
+
12
+ Important Changes
13
+ =================
14
+
15
+ As of version 0.2.0 serenity is using instance variables in the templates. In previous versions, your instance variables would be converted to local before passing to the template, so while in the code you had `@title = 'Serenity'`, you had to put `{%= title }` in the template to get serenity to work. This has now changed and you need to use instance variables in the templates: `{%= @title }`. Honestly, I don't know why I did it this way in the first place, considering that people are used to instance variables in templates from rails.
16
+
17
+ Usage
18
+ ======
19
+
20
+ Serenity is best demonstrated with an example. The first picture shows the template with the ruby code, next image shows the generated document. The template, output and the sample script can be found in the showcase directory.
21
+
22
+ ![Serenity template](http://github.com/kremso/serenity/blob/master/showcase/imgs/serenity_template.png?raw=true)
23
+
24
+ The image above is a screenshot of showcase.odt from the [showcase](http://github.com/kremso/serenity/blob/master/showcase) directory. It's a regular OpenOffice document with ruby code embedded inside a special markup. That ruby code drives the document creation. You can use conditionals, loops, blocks — in fact, the whole ruby language and you can apply any OpenOffice formatting to the outputted variables or static text.
25
+
26
+ The second line in the template is `{%= @title%}` what means: output the value of variable title. It's bold and big, in fact, it's has the 'Heading 1' style applied. That variable will be replaced in the generated document, but it will still be a 'Heading 1'.
27
+
28
+ You can now take that template, provide the data and generate the final document:
29
+
30
+ require 'rubygems'
31
+ require 'serenity'
32
+
33
+ class Showcase
34
+ include Serenity::Generator
35
+
36
+ Person = Struct.new(:name, :items)
37
+ Item = Struct.new(:name, :usage)
38
+
39
+ def generate_showcase
40
+ @title = 'Serenity inventory'
41
+
42
+ mals_items = [Item.new('Moses Brothers Self-Defense Engine Frontier Model B', 'Lock and load')]
43
+ mal = Person.new('Malcolm Reynolds', mals_items)
44
+
45
+ jaynes_items = [Item.new('Vera', 'Callahan full-bore auto-lock with a customized trigger, double cartridge and thorough gauge'),
46
+ Item.new('Lux', 'Ratatata'),
47
+ Item.new('Knife', 'Cut-throat')]
48
+ jayne = Person.new('Jayne Cobb', jaynes_items)
49
+
50
+ @crew = [mal, jayne]
51
+
52
+ render_odt 'showcase.odt'
53
+ end
54
+ end
55
+
56
+ The key parts are `include Serenity::Generator` and `render_odt`. The data for the template must be provided as instance variables.
57
+
58
+ Following picture shows the generated document. It's a screenshot of the showcase_output.odt document from the [showcase](http://github.com/kremso/serenity/blob/master/showcase) directory.
59
+
60
+ ![Generated document](http://github.com/kremso/serenity/blob/master/showcase/imgs/serenity_output.png?raw=true)
61
+
62
+ Installation
63
+ ============
64
+
65
+ gem install serenity-odt
66
+
67
+ Yeah, serenity is already taken on gemcutter.
68
+
69
+ Creating templates
70
+ ===================
71
+
72
+ Templates are created directly in OpenOffice. Ruby code is enclosed in special markup:
73
+
74
+ + `{%= %}` is for ruby code which should be output to the final document. `to_s` is applied to anything found inside this markup
75
+ + `{% %}` is for everything else — loops, ifs, ends and any other non-outputting code
76
+
77
+ Any special formatting should by applied directly on the markup. E.g. if you need to ouput the value of variable title in bold font, write `{%= title %}`, select in in OpenOffice and make it bold. See the showcase.odt for more examples.
78
+
79
+ Contact
80
+ =======
81
+
82
+ kramar[dot]tomas[at]gmail.com
83
+
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+ require 'rake/gempackagetask'
4
+
5
+ task :default => [:spec]
6
+
7
+ Spec::Rake::SpecTask.new("spec")
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.name = %q{serenity-odt}
11
+ s.version = "0.2.2"
12
+
13
+ s.authors = ["Tomas Kramar"]
14
+ s.description = <<-EOF
15
+ Embedded ruby for OpenOffice Text Document (.odt) files. You provide an .odt template
16
+ with ruby code in a special markup and the data, and Serenity generates the document.
17
+ Very similar to .erb files.
18
+ EOF
19
+ s.email = %q{kramar.tomas@gmail.com}
20
+ s.files = Dir.glob('lib/**/*.rb') + %w{README.md Rakefile LICENSE}
21
+ s.has_rdoc = false
22
+ s.require_paths = ["lib"]
23
+ s.rubygems_version = %q{1.3.5}
24
+ s.summary = %q{Embedded ruby for OpenOffice Text Document (.odt) files}
25
+ s.test_files = Dir.glob('spec/**/*.rb') + Dir.glob('fixtures/*.odt')
26
+ s.add_dependency('rubyzip', '>= 0.9.1')
27
+ s.add_dependency('nokogiri', '>= 1.0')
28
+ s.add_development_dependency('rspec', '>= 1.2.9')
29
+ end
30
+
31
+ Rake::GemPackageTask.new(spec) do |p|
32
+ p.gem_spec = spec
33
+ end
@@ -0,0 +1,19 @@
1
+ module Serenity
2
+ module Debug
3
+ def debug?
4
+ false
5
+ end
6
+
7
+ def debug_file_path
8
+ File.join(debug_dir, debug_file_name)
9
+ end
10
+
11
+ def debug_file_name
12
+ "serenity_debug_#{rand(100)}.rb"
13
+ end
14
+
15
+ def debug_dir
16
+ File.join(File.dirname(__FILE__), '..', '..', 'debug')
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ class String
2
+ def escape_xml
3
+ mgsub!([[/&/, '&amp;'], [/</, '&lt;'], [/>/, '&gt;']])
4
+ end
5
+
6
+ def convert_newlines
7
+ gsub!("\n", '<text:line-break/>')
8
+ self
9
+ end
10
+
11
+ def mgsub!(key_value_pairs=[].freeze)
12
+ regexp_fragments = key_value_pairs.collect { |k,v| k }
13
+ gsub!(Regexp.union(*regexp_fragments)) do |match|
14
+ key_value_pairs.detect{|k,v| k =~ match}[1]
15
+ end
16
+ self
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Serenity
2
+ module Generator
3
+ def render_odt template_path, output_path = output_name(template_path)
4
+ template = Template.new template_path, output_path
5
+ template.process binding
6
+ end
7
+
8
+ private
9
+
10
+ def output_name input
11
+ if input =~ /(.+)\.odt\Z/
12
+ "#{$1}_output.odt"
13
+ else
14
+ "#{input}_output.odt"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ module Serenity
2
+ class ImagesProcessor
3
+ include Debug
4
+
5
+ IMAGE_DIR_NAME = "Pictures"
6
+
7
+ def initialize(xml_content, context)
8
+ @replacements = []
9
+ @images = eval('@images', context)
10
+ @xml_content = xml_content
11
+ end
12
+
13
+ def generate_replacements
14
+ require 'nokogiri'
15
+
16
+ if @images && @images.kind_of?(Hash)
17
+ xml_data = Nokogiri::XML(@xml_content)
18
+
19
+ @images.each do |image_name, replacement_path|
20
+ if node = xml_data.xpath("//draw:frame[@draw:name='#{image_name}']/draw:image").first
21
+ placeholder_path = node.attribute('href').value
22
+ odt_image_path = ::File.join(IMAGE_DIR_NAME, ::File.basename(placeholder_path))
23
+
24
+ @replacements << [odt_image_path, replacement_path]
25
+ end
26
+ end
27
+ end
28
+
29
+ @replacements
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,68 @@
1
+ module Serenity
2
+ class Line
3
+ attr_reader :text
4
+
5
+ def initialize text
6
+ @text = text
7
+ end
8
+
9
+ def to_s
10
+ @text
11
+ end
12
+
13
+ def self.text txt
14
+ TextLine.new txt
15
+ end
16
+
17
+ def self.code txt
18
+ CodeLine.new txt
19
+ end
20
+
21
+ def self.string txt
22
+ StringLine.new txt
23
+ end
24
+
25
+ def self.literal txt
26
+ LiteralLine.new txt
27
+ end
28
+
29
+ end
30
+
31
+ class TextLine < Line
32
+ def to_buf
33
+ " _buf << '" << escape_text(@text) << "';"
34
+ end
35
+
36
+ def escape_text text
37
+ text.gsub(/['\\]/, '\\\\\&')
38
+ end
39
+ end
40
+
41
+ class CodeLine < Line
42
+ def to_buf
43
+ escape_code(@text) << ';'
44
+ end
45
+
46
+ def escape_code code
47
+ code.mgsub! [[/&apos;/, "'"], [/&gt;/, '>'], [/&lt/, '<'], [/&quot;/, '"'], [/&amp;/, '&']]
48
+ end
49
+ end
50
+
51
+ class StringLine < CodeLine
52
+ def to_buf
53
+ " _buf << (" << escape_code(@text) << ").to_s.escape_xml.convert_newlines;"
54
+ end
55
+
56
+ def convert_newlines text
57
+ text.gsub("First line", '<text:line-break>')
58
+ end
59
+ end
60
+
61
+ class LiteralLine < CodeLine
62
+ def to_buf
63
+ " _buf << (" << escape_code(@text) << ").to_s;"
64
+ end
65
+ end
66
+
67
+ end
68
+
@@ -0,0 +1,7 @@
1
+ module Serenity
2
+ class NodeType
3
+ TAG = 1
4
+ CONTROL = 2
5
+ TEMPLATE = 3
6
+ end
7
+ end
@@ -0,0 +1,91 @@
1
+ module Serenity
2
+ class OdtEruby
3
+ include Debug
4
+
5
+ EMBEDDED_PATTERN = /\{%([=%]+)?(.*?)-?%\}/m
6
+
7
+ def initialize template
8
+ @src = convert template
9
+ if debug?
10
+ File.open(debug_file_path, 'w') do |f|
11
+ f << @src
12
+ end
13
+ end
14
+ end
15
+
16
+ def evaluate context
17
+ @src = @src.force_encoding Encoding.default_external
18
+ eval(@src, context)
19
+ end
20
+
21
+ private
22
+
23
+ def convert template
24
+ src = "_buf = '';"
25
+ buffer = []
26
+ buffer_next = []
27
+
28
+ template.each_node do |node, type|
29
+ if !buffer_next.empty?
30
+ if is_matching_pair?(buffer.last, node)
31
+ buffer.pop
32
+ next
33
+ elsif is_nonpair_tag? node
34
+ next
35
+ else
36
+ buffer << buffer_next
37
+ buffer.flatten!
38
+ buffer_next = []
39
+ end
40
+ end
41
+
42
+ if type == NodeType::CONTROL
43
+ buffer_next = process_instruction(node)
44
+ else
45
+ buffer << process_instruction(node)
46
+ buffer.flatten!
47
+ end
48
+ end
49
+
50
+ buffer.each { |line| src << line.to_buf }
51
+ src << "\n_buf.to_s\n"
52
+ end
53
+
54
+ def process_instruction text
55
+ #text = text.strip
56
+ pos = 0
57
+ src = []
58
+
59
+ text.scan(EMBEDDED_PATTERN) do |indicator, code|
60
+ m = Regexp.last_match
61
+ middle = text[pos...m.begin(0)]
62
+ pos = m.end(0)
63
+ src << Line.text(middle) unless middle.empty?
64
+
65
+ if !indicator # <% %>
66
+ src << Line.code(code)
67
+ elsif indicator == '=' # <%= %>
68
+ src << Line.string(code)
69
+ elsif indicator == '%' # <%% %>
70
+ src << Line.literal(code)
71
+ end
72
+ end
73
+
74
+ rest = pos == 0 ? text : text[pos..-1]
75
+
76
+ src << Line.text(rest) unless rest.nil? or rest.empty?
77
+ src
78
+ end
79
+
80
+ def is_nonpair_tag? tag
81
+ tag =~ /<.+?\/>/
82
+ end
83
+
84
+ def is_matching_pair? open, close
85
+ open = open.to_s.strip
86
+ close = close.to_s.strip
87
+
88
+ close == "</#{open[1, close.length - 3]}>"
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,38 @@
1
+ require 'zip'
2
+ require 'fileutils'
3
+
4
+ module Serenity
5
+ class Template
6
+ attr_accessor :template
7
+
8
+ def initialize(template, output)
9
+ FileUtils.cp(template, output)
10
+ @template = output
11
+ end
12
+
13
+ def process context
14
+ tmpfiles = []
15
+ Zip::ZipFile.open(@template) do |zipfile|
16
+ %w(content.xml styles.xml).each do |xml_file|
17
+ content = zipfile.read(xml_file)
18
+
19
+ # Images replacement
20
+ images_replacements = ImagesProcessor.new(content, context).generate_replacements
21
+ images_replacements.each do |r|
22
+ zipfile.replace(r.first, r.last)
23
+ end
24
+
25
+ odteruby = OdtEruby.new(XmlReader.new(content))
26
+ out = odteruby.evaluate(context)
27
+ out.force_encoding Encoding.default_external
28
+
29
+ tmpfiles << (file = Tempfile.new("serenity"))
30
+ file << out
31
+ file.close
32
+
33
+ zipfile.replace(xml_file, file.path)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ module Serenity
2
+ class XmlReader
3
+
4
+ def initialize src
5
+ @src = src.force_encoding("UTF-8")
6
+ end
7
+
8
+ def each_node
9
+ last_match_pos = 0
10
+
11
+ @src.scan(/<.*?>/) do |node|
12
+ m = Regexp.last_match
13
+ if m.begin(0) > last_match_pos
14
+ text = @src[last_match_pos...m.begin(0)]
15
+ yield text, node_type(text) if text.gsub(/\s+/, '') != ''
16
+ end
17
+
18
+ last_match_pos = m.end(0)
19
+ yield node, NodeType::TAG
20
+ end
21
+ end
22
+
23
+ def node_type text
24
+ if text =~ /\s*\{%[^=#].+?%\}\s*/
25
+ NodeType::CONTROL
26
+ else
27
+ NodeType::TEMPLATE
28
+ end
29
+ end
30
+ end
31
+ end
data/lib/serenity.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'serenity/line'
3
+ require 'serenity/debug'
4
+ require 'serenity/node_type'
5
+ require 'serenity/escape_xml'
6
+ require 'serenity/odteruby'
7
+ require 'serenity/images_processor'
8
+ require 'serenity/template'
9
+ require 'serenity/xml_reader'
10
+ require 'serenity/generator'
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: serenity-odt-patched
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - kremso, Tyrel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubyzip
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.2.9
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.9
55
+ description: Embedded ruby for OpenOffice/LibreOffice Text Document (.odt) files.
56
+ You provide an .odt template with ruby code in a special markup and the data, and
57
+ Serenity generates the document. Very similar to .erb files.
58
+ email: ''
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - lib/serenity.rb
67
+ - lib/serenity/debug.rb
68
+ - lib/serenity/escape_xml.rb
69
+ - lib/serenity/generator.rb
70
+ - lib/serenity/images_processor.rb
71
+ - lib/serenity/line.rb
72
+ - lib/serenity/node_type.rb
73
+ - lib/serenity/odteruby.rb
74
+ - lib/serenity/template.rb
75
+ - lib/serenity/xml_reader.rb
76
+ homepage: https://github.com/MuTechIndustries/serenity
77
+ licenses: []
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.5.1
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Parse ODT file and substitutes placeholders like ERb. With small tweeks
99
+ test_files: []