serenity-odt 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -19
- data/Rakefile +1 -1
- data/fixtures/advanced.odt +0 -0
- data/fixtures/header.odt +0 -0
- data/fixtures/loop.odt +0 -0
- data/fixtures/loop_table.odt +0 -0
- data/fixtures/table_rows.odt +0 -0
- data/fixtures/variables.odt +0 -0
- data/lib/serenity/escape_xml.rb +0 -1
- data/lib/serenity/generator.rb +0 -11
- data/lib/serenity/line.rb +11 -0
- data/lib/serenity/odteruby.rb +5 -3
- data/lib/serenity/template.rb +10 -7
- data/spec/generator_spec.rb +1 -1
- data/spec/odteruby_spec.rb +1 -1
- data/spec/support/matchers/contain_in.rb +20 -0
- data/spec/template_spec.rb +14 -6
- metadata +53 -13
data/README.md
CHANGED
@@ -1,29 +1,22 @@
|
|
1
1
|
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.
|
2
2
|
|
3
|
-
|
3
|
+
Important Changes
|
4
|
+
=================
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
![Generated document](http://github.com/kremso/serenity/blob/master/showcase/imgs/serenity_output.png?raw=true)
|
8
|
-
|
9
|
-
Installation
|
10
|
-
============
|
6
|
+
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.
|
11
7
|
|
12
|
-
|
8
|
+
Usage
|
9
|
+
======
|
13
10
|
|
14
|
-
|
11
|
+
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.
|
15
12
|
|
16
|
-
|
17
|
-
===================
|
13
|
+
![Serenity template](http://github.com/kremso/serenity/blob/master/showcase/imgs/serenity_template.png?raw=true)
|
18
14
|
|
19
|
-
|
20
|
-
* `{%= %}` is for ruby code which should be output to the final document. `to_s` is applied to anything found inside this markup
|
21
|
-
* `{% %}` is for everything else — loops, ifs, ends and any other non-outputting code
|
15
|
+
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.
|
22
16
|
|
23
|
-
|
17
|
+
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'.
|
24
18
|
|
25
|
-
|
26
|
-
====================
|
19
|
+
You can now take that template, provide the data and generate the final document:
|
27
20
|
|
28
21
|
require 'rubygems'
|
29
22
|
require 'serenity'
|
@@ -51,10 +44,31 @@ Generating documents
|
|
51
44
|
end
|
52
45
|
end
|
53
46
|
|
54
|
-
The key parts are `include Serenity::Generator` and render_odt
|
47
|
+
The key parts are `include Serenity::Generator` and `render_odt`. The data for the template must be provided as instance variables.
|
48
|
+
|
49
|
+
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.
|
50
|
+
|
51
|
+
![Generated document](http://github.com/kremso/serenity/blob/master/showcase/imgs/serenity_output.png?raw=true)
|
52
|
+
|
53
|
+
Installation
|
54
|
+
============
|
55
|
+
|
56
|
+
gem install serenity-odt
|
57
|
+
|
58
|
+
Yeah, serenity is already taken on gemcutter.
|
59
|
+
|
60
|
+
Creating templates
|
61
|
+
===================
|
62
|
+
|
63
|
+
Templates are created directly in OpenOffice. Ruby code is enclosed in special markup:
|
64
|
+
|
65
|
+
+ `{%= %}` is for ruby code which should be output to the final document. `to_s` is applied to anything found inside this markup
|
66
|
+
+ `{% %}` is for everything else — loops, ifs, ends and any other non-outputting code
|
67
|
+
|
68
|
+
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.
|
55
69
|
|
56
70
|
Contact
|
57
71
|
=======
|
58
72
|
|
59
|
-
kramar[dot]tomas[at]gmail.com
|
73
|
+
kramar[dot]tomas[at]gmail.com
|
60
74
|
|
data/Rakefile
CHANGED
data/fixtures/advanced.odt
CHANGED
Binary file
|
data/fixtures/header.odt
ADDED
Binary file
|
data/fixtures/loop.odt
CHANGED
Binary file
|
data/fixtures/loop_table.odt
CHANGED
Binary file
|
data/fixtures/table_rows.odt
CHANGED
Binary file
|
data/fixtures/variables.odt
CHANGED
Binary file
|
data/lib/serenity/escape_xml.rb
CHANGED
data/lib/serenity/generator.rb
CHANGED
@@ -1,23 +1,12 @@
|
|
1
1
|
module Serenity
|
2
2
|
module Generator
|
3
3
|
def render_odt template_path, output_path = output_name(template_path)
|
4
|
-
|
5
|
-
local_variables = {}
|
6
|
-
instance_variables.each { |name| local_variables[name] = instance_variable_get(name) }
|
7
|
-
|
8
|
-
locals = instance_variables.map { |name| "#{ival_name_to_local(name)} = local_variables['#{name}'];" }.join
|
9
|
-
eval locals
|
10
|
-
|
11
4
|
template = Template.new template_path, output_path
|
12
5
|
template.process binding
|
13
6
|
end
|
14
7
|
|
15
8
|
private
|
16
9
|
|
17
|
-
def ival_name_to_local ival_name
|
18
|
-
ival_name[1, ival_name.length]
|
19
|
-
end
|
20
|
-
|
21
10
|
def output_name input
|
22
11
|
if input =~ /(.+)\.odt\Z/
|
23
12
|
"#{$1}_output.odt"
|
data/lib/serenity/line.rb
CHANGED
@@ -22,6 +22,10 @@ module Serenity
|
|
22
22
|
StringLine.new txt
|
23
23
|
end
|
24
24
|
|
25
|
+
def self.literal txt
|
26
|
+
LiteralLine.new txt
|
27
|
+
end
|
28
|
+
|
25
29
|
end
|
26
30
|
|
27
31
|
class TextLine < Line
|
@@ -49,5 +53,12 @@ module Serenity
|
|
49
53
|
" _buf << (" << escape_code(@text) << ").to_s.escape_xml;"
|
50
54
|
end
|
51
55
|
end
|
56
|
+
|
57
|
+
class LiteralLine < CodeLine
|
58
|
+
def to_buf
|
59
|
+
" _buf << (" << escape_code(@text) << ").to_s;"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
52
63
|
end
|
53
64
|
|
data/lib/serenity/odteruby.rb
CHANGED
@@ -2,7 +2,7 @@ module Serenity
|
|
2
2
|
class OdtEruby
|
3
3
|
include Debug
|
4
4
|
|
5
|
-
EMBEDDED_PATTERN = /\{%(
|
5
|
+
EMBEDDED_PATTERN = /\{%([=%]+)?(.*?)-?%\}/m
|
6
6
|
|
7
7
|
def initialize template
|
8
8
|
@src = convert template
|
@@ -61,10 +61,12 @@ module Serenity
|
|
61
61
|
pos = m.end(0)
|
62
62
|
src << Line.text(middle) unless middle.empty?
|
63
63
|
|
64
|
-
if !indicator
|
64
|
+
if !indicator # <% %>
|
65
65
|
src << Line.code(code)
|
66
|
-
|
66
|
+
elsif indicator == '=' # <%= %>
|
67
67
|
src << Line.string(code)
|
68
|
+
elsif indicator == '%' # <%% %>
|
69
|
+
src << Line.literal(code)
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
data/lib/serenity/template.rb
CHANGED
@@ -11,16 +11,19 @@ module Serenity
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def process context
|
14
|
+
tmpfiles = []
|
14
15
|
Zip::ZipFile.open(@template) do |zipfile|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
%w(content.xml styles.xml).each do |xml_file|
|
17
|
+
content = zipfile.read(xml_file)
|
18
|
+
odteruby = OdtEruby.new(XmlReader.new(content))
|
19
|
+
out = odteruby.evaluate(context)
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
tmpfiles << (file = Tempfile.new("serenity"))
|
22
|
+
file << out
|
23
|
+
file.close
|
22
24
|
|
23
|
-
|
25
|
+
zipfile.replace(xml_file, file.path)
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
data/spec/generator_spec.rb
CHANGED
data/spec/odteruby_spec.rb
CHANGED
@@ -13,7 +13,7 @@ module Serenity
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def squeeze text
|
16
|
-
text.inject('') { |memo, line| memo += line.strip } unless text.nil?
|
16
|
+
text.each_char.inject('') { |memo, line| memo += line.strip } unless text.nil?
|
17
17
|
end
|
18
18
|
|
19
19
|
def run_spec template, expected, context=@context
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "zip/zip"
|
2
|
+
|
3
|
+
module Serenity
|
4
|
+
Spec::Matchers.define :contain_in do |xml_file, expected|
|
5
|
+
|
6
|
+
match do |actual|
|
7
|
+
content = Zip::ZipFile.open(actual) { |zip_file| zip_file.read(xml_file) }
|
8
|
+
content =~ Regexp.new(".*#{Regexp.escape(expected)}.*")
|
9
|
+
end
|
10
|
+
|
11
|
+
failure_message_for_should do |actual|
|
12
|
+
"expected #{actual} to contain the text #{expected}"
|
13
|
+
end
|
14
|
+
|
15
|
+
failure_message_for_should_not do |actual|
|
16
|
+
"expected #{actual} to not contain the text #{expected}"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/spec/template_spec.rb
CHANGED
@@ -10,39 +10,47 @@ module Serenity
|
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should process a document with simple variable substitution" do
|
13
|
-
name = 'Malcolm Reynolds'
|
14
|
-
title = 'captain'
|
13
|
+
@name = 'Malcolm Reynolds'
|
14
|
+
@title = 'captain'
|
15
15
|
|
16
16
|
template = Template.new(fixture('variables.odt'), 'output_variables.odt')
|
17
17
|
lambda {template.process binding}.should_not raise_error
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should unroll a simple for loop" do
|
21
|
-
crew = %w{'River', 'Jayne', 'Wash'}
|
21
|
+
@crew = %w{'River', 'Jayne', 'Wash'}
|
22
22
|
|
23
23
|
template = Template.new(fixture('loop.odt'), 'output_loop.odt')
|
24
24
|
lambda {template.process binding}.should_not raise_error
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should unroll an advanced loop with tables" do
|
28
|
-
ships = [Ship.new('Firefly', 'transport'), Ship.new('Colonial', 'battle')]
|
28
|
+
@ships = [Ship.new('Firefly', 'transport'), Ship.new('Colonial', 'battle')]
|
29
29
|
|
30
30
|
template = Template.new(fixture('loop_table.odt'), 'output_loop_table.odt')
|
31
31
|
lambda {template.process binding}.should_not raise_error
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should process an advanced document" do
|
35
|
-
persons = [Person.new('Malcolm', 'captain'), Person.new('River', 'psychic'), Person.new('Jay', 'gunslinger')]
|
35
|
+
@persons = [Person.new('Malcolm', 'captain'), Person.new('River', 'psychic'), Person.new('Jay', 'gunslinger')]
|
36
36
|
|
37
37
|
template = Template.new(fixture('advanced.odt'), 'output_advanced.odt')
|
38
38
|
lambda {template.process binding}.should_not raise_error
|
39
39
|
end
|
40
40
|
|
41
41
|
it "should loop and generate table rows" do
|
42
|
-
ships = [Ship.new('Firefly', 'transport'), Ship.new('Colonial', 'battle')]
|
42
|
+
@ships = [Ship.new('Firefly', 'transport'), Ship.new('Colonial', 'battle')]
|
43
43
|
|
44
44
|
template = Template.new(fixture('table_rows.odt'), 'output_table_rows.odt')
|
45
45
|
lambda {template.process binding}.should_not raise_error
|
46
46
|
end
|
47
|
+
|
48
|
+
it "should parse the header" do
|
49
|
+
@title = 'captain'
|
50
|
+
|
51
|
+
template = Template.new(fixture('header.odt'), 'output_header.odt')
|
52
|
+
template.process(binding)
|
53
|
+
'output_header.odt'.should contain_in('styles.xml', 'captain')
|
54
|
+
end
|
47
55
|
end
|
48
56
|
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serenity-odt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Tomas Kramar
|
@@ -9,29 +15,41 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2010-
|
18
|
+
date: 2010-09-23 00:00:00 +02:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
22
|
name: rubyzip
|
17
|
-
|
18
|
-
|
19
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - ">="
|
22
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 57
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 9
|
33
|
+
- 1
|
23
34
|
version: 0.9.1
|
24
|
-
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
25
37
|
- !ruby/object:Gem::Dependency
|
26
38
|
name: rspec
|
27
|
-
|
28
|
-
|
29
|
-
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
30
42
|
requirements:
|
31
43
|
- - ">="
|
32
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 13
|
46
|
+
segments:
|
47
|
+
- 1
|
48
|
+
- 2
|
49
|
+
- 9
|
33
50
|
version: 1.2.9
|
34
|
-
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
35
53
|
description: " Embedded ruby for OpenOffice Text Document (.odt) files. You provide an .odt template\n with ruby code in a special markup and the data, and Serenity generates the document.\n Very similar to .erb files.\n"
|
36
54
|
email: kramar.tomas@gmail.com
|
37
55
|
executables: []
|
@@ -53,6 +71,20 @@ files:
|
|
53
71
|
- README.md
|
54
72
|
- Rakefile
|
55
73
|
- LICENSE
|
74
|
+
- spec/escape_xml_spec.rb
|
75
|
+
- spec/generator_spec.rb
|
76
|
+
- spec/odteruby_spec.rb
|
77
|
+
- spec/spec_helper.rb
|
78
|
+
- spec/support/matchers/be_a_document.rb
|
79
|
+
- spec/support/matchers/contain_in.rb
|
80
|
+
- spec/template_spec.rb
|
81
|
+
- spec/xml_reader_spec.rb
|
82
|
+
- fixtures/advanced.odt
|
83
|
+
- fixtures/header.odt
|
84
|
+
- fixtures/loop.odt
|
85
|
+
- fixtures/loop_table.odt
|
86
|
+
- fixtures/table_rows.odt
|
87
|
+
- fixtures/variables.odt
|
56
88
|
has_rdoc: true
|
57
89
|
homepage:
|
58
90
|
licenses: []
|
@@ -63,21 +95,27 @@ rdoc_options: []
|
|
63
95
|
require_paths:
|
64
96
|
- lib
|
65
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
66
99
|
requirements:
|
67
100
|
- - ">="
|
68
101
|
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
69
105
|
version: "0"
|
70
|
-
version:
|
71
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
72
108
|
requirements:
|
73
109
|
- - ">="
|
74
110
|
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
112
|
+
segments:
|
113
|
+
- 0
|
75
114
|
version: "0"
|
76
|
-
version:
|
77
115
|
requirements: []
|
78
116
|
|
79
117
|
rubyforge_project:
|
80
|
-
rubygems_version: 1.3.
|
118
|
+
rubygems_version: 1.3.7
|
81
119
|
signing_key:
|
82
120
|
specification_version: 3
|
83
121
|
summary: Embedded ruby for OpenOffice Text Document (.odt) files
|
@@ -87,9 +125,11 @@ test_files:
|
|
87
125
|
- spec/odteruby_spec.rb
|
88
126
|
- spec/spec_helper.rb
|
89
127
|
- spec/support/matchers/be_a_document.rb
|
128
|
+
- spec/support/matchers/contain_in.rb
|
90
129
|
- spec/template_spec.rb
|
91
130
|
- spec/xml_reader_spec.rb
|
92
131
|
- fixtures/advanced.odt
|
132
|
+
- fixtures/header.odt
|
93
133
|
- fixtures/loop.odt
|
94
134
|
- fixtures/loop_table.odt
|
95
135
|
- fixtures/table_rows.odt
|