odf-report 0.5.1 → 0.5.2
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 +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
|