odf-report 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.gitignore +1 -0
- data/.rspec +4 -0
- data/README.textile +6 -8
- data/Rakefile +8 -0
- data/lib/odf-report.rb +0 -1
- data/lib/odf-report/field.rb +64 -32
- data/lib/odf-report/file.rb +2 -2
- data/lib/odf-report/nested.rb +31 -3
- data/lib/odf-report/parser/default.rb +5 -4
- data/lib/odf-report/report.rb +10 -34
- data/lib/odf-report/section.rb +21 -57
- data/lib/odf-report/table.rb +12 -36
- data/lib/odf-report/text.rb +1 -1
- data/lib/odf-report/version.rb +1 -1
- data/odf-report.gemspec +4 -1
- data/spec/fields_spec.rb +77 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/specs.odt +0 -0
- data/spec/tables_spec.rb +39 -0
- data/test/fields_inside_text_test.rb +38 -0
- data/test/nested_tables_test.rb +43 -0
- data/test/sections_test.rb +44 -0
- data/test/sub_sections_test.rb +58 -0
- data/test/table_headers_test.rb +41 -0
- data/test/tables_test.rb +67 -0
- data/test/{piriapolis.jpg → templates/piriapolis.jpg} +0 -0
- data/test/{rails.png → templates/rails.png} +0 -0
- data/test/templates/test_sub_sections.odt +0 -0
- data/test/templates/test_text.odt +0 -0
- data/test/text_test.rb +56 -0
- metadata +87 -36
- data/lib/odf-report/fields.rb +0 -40
- data/test/test_fields_inside_text.rb +0 -37
- data/test/test_nested_tables.rb +0 -39
- data/test/test_sections.rb +0 -39
- data/test/test_sub_sections.rb +0 -57
- data/test/test_table_headers.rb +0 -39
- data/test/test_tables.rb +0 -62
- data/test/test_text.rb +0 -48
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
YTBkNGEzZjE1NmNkMjc3MTdiNjdmNjZhMDI4ZjAzYjg5NTU0NjJjZA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 639774f385b52ff5939a37b9e5d46f0ef32883fa
|
4
|
+
data.tar.gz: 518447cce1c1ccae65960ffd0d75b617f3bb48bf
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
Y2IyODBlMmEwNWRiODgzZmViMDI1MGE1MmJhODUxYzc3MWY4NDdlNzZmYTEw
|
11
|
-
YzVmZDA5NDIwNTVlYTRjMTQ0YTM1ZTQ0N2JkOTE4MDIyYThkOTY=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MDNlY2U4ZTU2NTUxZTYzYTZlMWZkN2YxYjI1YTE0YTFlODBmMzFiOTdmMThk
|
14
|
-
YzYyMWQwN2QzZDcxZDhmZjE3ZmQ1ZjFhY2E0NTY5MzcxM2M4NWE3NmEzZTBk
|
15
|
-
ZTI1MjI2OGJmZGMzZGIzYTcwZDYxNjYzYzYyYTgzYjhkNDFmNDc=
|
6
|
+
metadata.gz: 823da1a19f5c7fa4d44d2f130fd208658fe38472ea252c71427e2a5580126f882c40ba5a3ccb0d4bcc55e93e54d739fd22142fc3cfb540696fa0d52539227fdd
|
7
|
+
data.tar.gz: ba034ba239cd822fccb1c08e2586d33aa3c7ffd9268dc372fbac54cdd5b7f2b09f63d7aa69e48b83bcc1056cd64d4e4ced757c226771eaf999428f5144f33518
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/README.textile
CHANGED
@@ -18,10 +18,8 @@ h2. USAGE
|
|
18
18
|
|
19
19
|
h3. Step 1 -- the template
|
20
20
|
|
21
|
-
First of all, you need to create a .odt file to serve as a template
|
22
|
-
|
23
|
-
Templates are normal .odt files with placeholders for Substitutions
|
24
|
-
|
21
|
+
First of all, you need to create a .odt file to serve as a template.
|
22
|
+
Templates are normal .odt files with placeholders for *substitutions*.
|
25
23
|
There are now *four* kinds of substitutions available: *fields*, *tables*, *images* and *sections*.
|
26
24
|
|
27
25
|
h3. Fields placeholders
|
@@ -62,7 +60,7 @@ report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
|
|
62
60
|
|
63
61
|
r.add_table("TABLE_1", @list_of_itens, :header=>true) do |t|
|
64
62
|
t.add_column(:item_id, :id)
|
65
|
-
t.add_column(:description)
|
63
|
+
t.add_column(:description) { |item| "==> #{item.description}" }
|
66
64
|
end
|
67
65
|
|
68
66
|
end
|
@@ -76,12 +74,12 @@ and considering you have a table like this in your template
|
|
76
74
|
---------------------------------
|
77
75
|
|
78
76
|
* this is my lame attempt to draw a table.
|
79
|
-
you
|
77
|
+
you are not supposed to type this.
|
80
78
|
you have to use an actual table.
|
81
|
-
i don't know... just thought I
|
79
|
+
i don't know... just thought I should mention it ;-)
|
82
80
|
</pre>
|
83
81
|
|
84
|
-
and a collection @list_of_itens, it will
|
82
|
+
and a collection @list_of_itens, it will create one row for each item in the collection, and the replacement will take place accordingly.
|
85
83
|
|
86
84
|
Any format applied to the fields in the template will be preserved.
|
87
85
|
|
data/Rakefile
CHANGED
data/lib/odf-report.rb
CHANGED
@@ -9,7 +9,6 @@ require File.expand_path('../odf-report/images', __FILE__)
|
|
9
9
|
require File.expand_path('../odf-report/field', __FILE__)
|
10
10
|
require File.expand_path('../odf-report/text', __FILE__)
|
11
11
|
require File.expand_path('../odf-report/file', __FILE__)
|
12
|
-
require File.expand_path('../odf-report/fields', __FILE__)
|
13
12
|
require File.expand_path('../odf-report/nested', __FILE__)
|
14
13
|
require File.expand_path('../odf-report/section', __FILE__)
|
15
14
|
require File.expand_path('../odf-report/table', __FILE__)
|
data/lib/odf-report/field.rb
CHANGED
@@ -1,56 +1,88 @@
|
|
1
1
|
module ODFReport
|
2
|
+
class Field
|
2
3
|
|
3
|
-
|
4
|
+
DELIMITERS = %w([ ])
|
4
5
|
|
5
|
-
|
6
|
+
def initialize(opts, &block)
|
7
|
+
@name = opts[:name]
|
8
|
+
@data_field = opts[:data_field]
|
6
9
|
|
7
|
-
|
8
|
-
@name = opts[:name]
|
9
|
-
@data_field = opts[:data_field]
|
10
|
+
unless @value = opts[:value]
|
10
11
|
|
11
|
-
|
12
|
+
if block_given?
|
13
|
+
@block = block
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
+
else
|
16
|
+
@block = lambda { |item| self.extract_value(item) }
|
17
|
+
end
|
15
18
|
|
16
|
-
else
|
17
|
-
@block = lambda { |item| self.extract_value(item) }
|
18
19
|
end
|
19
20
|
|
20
21
|
end
|
21
22
|
|
22
|
-
|
23
|
+
def replace!(content, data_item = nil)
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
txt = content.inner_html
|
26
|
+
|
27
|
+
val = get_value(data_item)
|
28
|
+
|
29
|
+
txt.gsub!(to_placeholder, sanitize(val))
|
30
|
+
|
31
|
+
content.inner_html = txt
|
27
32
|
|
28
|
-
def to_placeholder
|
29
|
-
if DELIMITERS.is_a?(Array)
|
30
|
-
"#{DELIMITERS[0]}#{@name.to_s.upcase}#{DELIMITERS[1]}"
|
31
|
-
else
|
32
|
-
"#{DELIMITERS}#{@name.to_s.upcase}#{DELIMITERS}"
|
33
33
|
end
|
34
|
-
end
|
35
34
|
|
36
|
-
|
37
|
-
|
35
|
+
def get_value(data_item = nil)
|
36
|
+
@value || @block.call(data_item) || ''
|
37
|
+
end
|
38
|
+
|
39
|
+
def extract_value(data_item)
|
40
|
+
return unless data_item
|
38
41
|
|
39
|
-
|
42
|
+
key = @data_field || @name
|
40
43
|
|
41
|
-
|
42
|
-
|
44
|
+
if data_item.is_a?(Hash)
|
45
|
+
data_item[key] || data_item[key.to_s.downcase] || data_item[key.to_s.upcase] || data_item[key.to_s.downcase.to_sym]
|
43
46
|
|
44
|
-
|
45
|
-
|
47
|
+
elsif data_item.respond_to?(key.to_s.downcase.to_sym)
|
48
|
+
data_item.send(key.to_s.downcase.to_sym)
|
46
49
|
|
47
|
-
|
48
|
-
|
50
|
+
else
|
51
|
+
raise "Can't find field [#{key}] in this #{data_item.class}"
|
52
|
+
|
53
|
+
end
|
49
54
|
|
50
55
|
end
|
51
56
|
|
52
|
-
|
57
|
+
private
|
58
|
+
|
59
|
+
def to_placeholder
|
60
|
+
if DELIMITERS.is_a?(Array)
|
61
|
+
"#{DELIMITERS[0]}#{@name.to_s.upcase}#{DELIMITERS[1]}"
|
62
|
+
else
|
63
|
+
"#{DELIMITERS}#{@name.to_s.upcase}#{DELIMITERS}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def sanitize(txt)
|
68
|
+
txt = html_escape(txt)
|
69
|
+
txt = odf_linebreak(txt)
|
70
|
+
txt
|
71
|
+
end
|
72
|
+
|
73
|
+
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
|
74
|
+
|
75
|
+
def html_escape(s)
|
76
|
+
return "" unless s
|
77
|
+
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
|
78
|
+
end
|
79
|
+
|
80
|
+
def odf_linebreak(s)
|
81
|
+
return "" unless s
|
82
|
+
s.to_s.gsub("\n", "<text:line-break/>")
|
83
|
+
end
|
53
84
|
|
54
|
-
end
|
55
85
|
|
56
|
-
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/lib/odf-report/file.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module ODFReport
|
2
2
|
class File
|
3
3
|
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :output_stream
|
5
5
|
|
6
6
|
def initialize(template)
|
7
|
-
raise "Template [#{template}] not found." unless ::File.
|
7
|
+
raise "Template [#{template}] not found." unless ::File.exist? template
|
8
8
|
@template = template
|
9
9
|
end
|
10
10
|
|
data/lib/odf-report/nested.rb
CHANGED
@@ -2,10 +2,38 @@ module ODFReport
|
|
2
2
|
|
3
3
|
module Nested
|
4
4
|
|
5
|
-
def
|
6
|
-
|
5
|
+
def add_field(name, data_field=nil, &block)
|
6
|
+
opts = {:name => name, :data_field => data_field}
|
7
|
+
field = Field.new(opts, &block)
|
8
|
+
@fields << field
|
9
|
+
|
10
|
+
end
|
11
|
+
alias_method :add_column, :add_field
|
12
|
+
|
13
|
+
def add_text(name, data_field=nil, &block)
|
14
|
+
opts = {:name => name, :data_field => data_field}
|
15
|
+
field = Text.new(opts, &block)
|
16
|
+
@texts << field
|
17
|
+
|
7
18
|
end
|
8
19
|
|
20
|
+
def add_table(table_name, collection_field, opts={})
|
21
|
+
opts.merge!(:name => table_name, :collection_field => collection_field)
|
22
|
+
tab = Table.new(opts)
|
23
|
+
@tables << tab
|
24
|
+
|
25
|
+
yield(tab)
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_section(section_name, collection_field, opts={})
|
29
|
+
opts.merge!(:name => section_name, :collection_field => collection_field)
|
30
|
+
sec = Section.new(opts)
|
31
|
+
@sections << sec
|
32
|
+
|
33
|
+
yield(sec)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
9
37
|
def get_collection_from_item(item, collection_field)
|
10
38
|
|
11
39
|
return item[collection_field] if item.is_a?(Hash)
|
@@ -31,4 +59,4 @@ module ODFReport
|
|
31
59
|
|
32
60
|
end
|
33
61
|
|
34
|
-
end
|
62
|
+
end
|
@@ -34,6 +34,7 @@ module Parser
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def parse
|
37
|
+
|
37
38
|
xml = @template_node.parse(@text)
|
38
39
|
|
39
40
|
xml.css("p", "h1", "h2").each do |p|
|
@@ -59,9 +60,9 @@ module Parser
|
|
59
60
|
|
60
61
|
def parse_formatting(text)
|
61
62
|
text.strip!
|
62
|
-
text.gsub!(/<strong
|
63
|
-
text.gsub!(/<em
|
64
|
-
text.gsub!(/<u
|
63
|
+
text.gsub!(/<strong.*?>(.+?)<\/strong>/) { "<text:span text:style-name=\"bold\">#{$1}<\/text:span>" }
|
64
|
+
text.gsub!(/<em.*?>(.+?)<\/em>/) { "<text:span text:style-name=\"italic\">#{$1}<\/text:span>" }
|
65
|
+
text.gsub!(/<u.*?>(.+?)<\/u>/) { "<text:span text:style-name=\"underline\">#{$1}<\/text:span>" }
|
65
66
|
text.gsub!("\n", "")
|
66
67
|
text
|
67
68
|
end
|
@@ -87,4 +88,4 @@ module Parser
|
|
87
88
|
|
88
89
|
end
|
89
90
|
|
90
|
-
end
|
91
|
+
end
|
data/lib/odf-report/report.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
module ODFReport
|
2
2
|
|
3
3
|
class Report
|
4
|
-
include
|
5
|
-
|
6
|
-
attr_accessor :fields, :tables, :images, :sections, :file, :texts
|
4
|
+
include Images
|
7
5
|
|
8
6
|
def initialize(template_name, &block)
|
9
7
|
|
@@ -20,19 +18,19 @@ class Report
|
|
20
18
|
|
21
19
|
end
|
22
20
|
|
23
|
-
def add_field(field_tag, value=''
|
21
|
+
def add_field(field_tag, value='')
|
24
22
|
opts = {:name => field_tag, :value => value}
|
25
|
-
field = Field.new(opts
|
23
|
+
field = Field.new(opts)
|
26
24
|
@fields << field
|
27
25
|
end
|
28
26
|
|
29
|
-
def add_text(field_tag, value=''
|
27
|
+
def add_text(field_tag, value='')
|
30
28
|
opts = {:name => field_tag, :value => value}
|
31
29
|
text = Text.new(opts)
|
32
30
|
@texts << text
|
33
31
|
end
|
34
32
|
|
35
|
-
def add_table(table_name, collection, opts={}
|
33
|
+
def add_table(table_name, collection, opts={})
|
36
34
|
opts.merge!(:name => table_name, :collection => collection)
|
37
35
|
tab = Table.new(opts)
|
38
36
|
@tables << tab
|
@@ -40,7 +38,7 @@ class Report
|
|
40
38
|
yield(tab)
|
41
39
|
end
|
42
40
|
|
43
|
-
def add_section(section_name, collection, opts={}
|
41
|
+
def add_section(section_name, collection, opts={})
|
44
42
|
opts.merge!(:name => section_name, :collection => collection)
|
45
43
|
sec = Section.new(opts)
|
46
44
|
@sections << sec
|
@@ -60,11 +58,11 @@ class Report
|
|
60
58
|
|
61
59
|
parse_document(txt) do |doc|
|
62
60
|
|
63
|
-
|
64
|
-
|
61
|
+
@sections.each { |s| s.replace!(doc) }
|
62
|
+
@tables.each { |t| t.replace!(doc) }
|
65
63
|
|
66
|
-
|
67
|
-
|
64
|
+
@texts.each { |t| t.replace!(doc) }
|
65
|
+
@fields.each { |f| f.replace!(doc) }
|
68
66
|
|
69
67
|
find_image_name_matches(doc)
|
70
68
|
avoid_duplicate_image_names(doc)
|
@@ -93,28 +91,6 @@ private
|
|
93
91
|
txt.replace(doc.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML))
|
94
92
|
end
|
95
93
|
|
96
|
-
def replace_fields!(content)
|
97
|
-
field_replace!(content)
|
98
|
-
end
|
99
|
-
|
100
|
-
def replace_texts!(content)
|
101
|
-
@texts.each do |text|
|
102
|
-
text.replace!(content)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def replace_tables!(content)
|
107
|
-
@tables.each do |table|
|
108
|
-
table.replace!(content)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def replace_sections!(content)
|
113
|
-
@sections.each do |section|
|
114
|
-
section.replace!(content)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
94
|
end
|
119
95
|
|
120
96
|
end
|
data/lib/odf-report/section.rb
CHANGED
@@ -1,87 +1,43 @@
|
|
1
1
|
module ODFReport
|
2
2
|
|
3
3
|
class Section
|
4
|
-
include
|
5
|
-
|
6
|
-
attr_accessor :fields, :tables, :data, :name, :collection_field, :parent
|
4
|
+
include Nested
|
7
5
|
|
8
6
|
def initialize(opts)
|
9
7
|
@name = opts[:name]
|
10
8
|
@collection_field = opts[:collection_field]
|
11
9
|
@collection = opts[:collection]
|
12
|
-
@parent = opts[:parent]
|
13
10
|
|
14
11
|
@fields = []
|
15
12
|
@texts = []
|
16
|
-
|
17
13
|
@tables = []
|
18
14
|
@sections = []
|
19
|
-
end
|
20
|
-
|
21
|
-
def add_field(name, data_field=nil, &block)
|
22
|
-
opts = {:name => name, :data_field => data_field}
|
23
|
-
field = Field.new(opts, &block)
|
24
|
-
@fields << field
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def add_text(name, data_field=nil, &block)
|
29
|
-
opts = {:name => name, :data_field => data_field}
|
30
|
-
field = Text.new(opts, &block)
|
31
|
-
@texts << field
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def add_table(table_name, collection_field, opts={}, &block)
|
36
|
-
opts.merge!(:name => table_name, :collection_field => collection_field, :parent => self)
|
37
|
-
tab = Table.new(opts)
|
38
|
-
@tables << tab
|
39
|
-
|
40
|
-
yield(tab)
|
41
|
-
end
|
42
|
-
|
43
|
-
def add_section(section_name, collection_field, opts={}, &block)
|
44
|
-
opts.merge!(:name => section_name, :collection_field => collection_field, :parent => self)
|
45
|
-
sec = Section.new(opts)
|
46
|
-
@sections << sec
|
47
15
|
|
48
|
-
yield(sec)
|
49
|
-
end
|
50
|
-
|
51
|
-
def populate!(row)
|
52
|
-
@collection = get_collection_from_item(row, @collection_field) if row
|
53
16
|
end
|
54
17
|
|
55
18
|
def replace!(doc, row = nil)
|
56
19
|
|
57
|
-
return unless
|
20
|
+
return unless @section_node = find_section_node(doc)
|
58
21
|
|
59
|
-
|
60
|
-
|
61
|
-
populate!(row)
|
22
|
+
@collection = get_collection_from_item(row, @collection_field) if row
|
62
23
|
|
63
24
|
@collection.each do |data_item|
|
64
|
-
new_section = template.dup
|
65
25
|
|
66
|
-
|
67
|
-
|
68
|
-
|
26
|
+
new_section = get_section_node
|
27
|
+
|
28
|
+
@tables.each { |t| t.replace!(new_section, data_item) }
|
69
29
|
|
70
|
-
@
|
71
|
-
t.replace!(new_section, data_item)
|
72
|
-
end
|
30
|
+
@sections.each { |s| s.replace!(new_section, data_item) }
|
73
31
|
|
74
|
-
@
|
75
|
-
s.replace!(new_section, data_item)
|
76
|
-
end
|
32
|
+
@texts.each { |t| t.replace!(new_section, data_item) }
|
77
33
|
|
78
|
-
|
34
|
+
@fields.each { |f| f.replace!(new_section, data_item) }
|
79
35
|
|
80
|
-
|
36
|
+
@section_node.before(new_section)
|
81
37
|
|
82
38
|
end
|
83
39
|
|
84
|
-
|
40
|
+
@section_node.remove
|
85
41
|
|
86
42
|
end # replace_section
|
87
43
|
|
@@ -95,8 +51,16 @@ module ODFReport
|
|
95
51
|
|
96
52
|
end
|
97
53
|
|
98
|
-
|
54
|
+
def get_section_node
|
55
|
+
node = @section_node.dup
|
99
56
|
|
100
|
-
|
57
|
+
name = node.get_attribute('text:name').to_s
|
58
|
+
@idx ||=0; @idx +=1
|
59
|
+
node.set_attribute('text:name', "#{name}_#{@idx}")
|
60
|
+
|
61
|
+
node
|
62
|
+
end
|
101
63
|
|
64
|
+
end
|
102
65
|
|
66
|
+
end
|