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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- YzhiYWE2MTU5OTRjZWQ2NGExZDc1ZDRjMGUzM2ZlZWU1ZWY4ZWUwNg==
5
- data.tar.gz: !binary |-
6
- YTBkNGEzZjE1NmNkMjc3MTdiNjdmNjZhMDI4ZjAzYjg5NTU0NjJjZA==
2
+ SHA1:
3
+ metadata.gz: 639774f385b52ff5939a37b9e5d46f0ef32883fa
4
+ data.tar.gz: 518447cce1c1ccae65960ffd0d75b617f3bb48bf
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZjU1YzA0ZjY5YmRlMmJhZTE4YmM0NjY5MDQ0MDkyNGFlYjU1MGYzOTM1NTk0
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
@@ -3,4 +3,5 @@ pckg
3
3
  doc
4
4
  *.gem
5
5
  test/result
6
+ spec/result
6
7
  Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
4
+ --format documentation
@@ -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) do { |item| "==> #{item.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 don't suppose to type this.
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'd mention it ;-)
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 be created one row for each item in the collection, and the replacement will take place accordingly.
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
@@ -1 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'launchy'
3
+ task :test do
4
+ Dir.glob('./test/*_test.rb').each { |file| require file}
5
+ end
6
+
7
+ task :open do
8
+ Dir.glob('./test/result/*.odt').each { |file| Launchy.open(file) }
9
+ end
@@ -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__)
@@ -1,56 +1,88 @@
1
1
  module ODFReport
2
+ class Field
2
3
 
3
- class Field
4
+ DELIMITERS = %w([ ])
4
5
 
5
- DELIMITERS = ['[', ']']
6
+ def initialize(opts, &block)
7
+ @name = opts[:name]
8
+ @data_field = opts[:data_field]
6
9
 
7
- def initialize(opts, &block)
8
- @name = opts[:name]
9
- @data_field = opts[:data_field]
10
+ unless @value = opts[:value]
10
11
 
11
- unless @value = opts[:value]
12
+ if block_given?
13
+ @block = block
12
14
 
13
- if block_given?
14
- @block = block
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
- end
23
+ def replace!(content, data_item = nil)
23
24
 
24
- def get_value(data_item = nil)
25
- @value || @block.call(data_item) || ''
26
- end
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
- def extract_value(data_item)
37
- return unless data_item
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
- key = @data_field || @name
42
+ key = @data_field || @name
40
43
 
41
- if data_item.is_a?(Hash)
42
- data_item[key] || data_item[key.to_s.downcase] || data_item[key.to_s.upcase] || data_item[key.to_s.downcase.to_sym]
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
- elsif data_item.respond_to?(key.to_s.downcase.to_sym)
45
- data_item.send(key.to_s.downcase.to_sym)
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
- else
48
- raise "Can't find field [#{key}] in this #{data_item.class}"
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
- end
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 = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
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
- end
86
+
87
+ end
88
+ end
@@ -1,10 +1,10 @@
1
1
  module ODFReport
2
2
  class File
3
3
 
4
- attr_accessor :data, :output_stream
4
+ attr_accessor :output_stream
5
5
 
6
6
  def initialize(template)
7
- raise "Template [#{template}] not found." unless ::File.exists? template
7
+ raise "Template [#{template}] not found." unless ::File.exist? template
8
8
  @template = template
9
9
  end
10
10
 
@@ -2,10 +2,38 @@ module ODFReport
2
2
 
3
3
  module Nested
4
4
 
5
- def replace_fields!(new_section, data_item)
6
- field_replace!(new_section, data_item)
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>(.+?)<\/strong>/) { "<text:span text:style-name=\"bold\">#{$1}<\/text:span>" }
63
- text.gsub!(/<em>(.+?)<\/em>/) { "<text:span text:style-name=\"italic\">#{$1}<\/text:span>" }
64
- text.gsub!(/<u>(.+?)<\/u>/) { "<text:span text:style-name=\"underline\">#{$1}<\/text:span>" }
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
@@ -1,9 +1,7 @@
1
1
  module ODFReport
2
2
 
3
3
  class Report
4
- include Fields, Images
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='', &block)
21
+ def add_field(field_tag, value='')
24
22
  opts = {:name => field_tag, :value => value}
25
- field = Field.new(opts, &block)
23
+ field = Field.new(opts)
26
24
  @fields << field
27
25
  end
28
26
 
29
- def add_text(field_tag, value='', &block)
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={}, &block)
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={}, &block)
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
- replace_texts!(doc)
64
- replace_fields!(doc)
61
+ @sections.each { |s| s.replace!(doc) }
62
+ @tables.each { |t| t.replace!(doc) }
65
63
 
66
- replace_sections!(doc)
67
- replace_tables!(doc)
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
@@ -1,87 +1,43 @@
1
1
  module ODFReport
2
2
 
3
3
  class Section
4
- include Fields, Nested
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 section = find_section_node(doc)
20
+ return unless @section_node = find_section_node(doc)
58
21
 
59
- template = section.dup
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
- @texts.each do |t|
67
- t.replace!(new_section, data_item)
68
- end
26
+ new_section = get_section_node
27
+
28
+ @tables.each { |t| t.replace!(new_section, data_item) }
69
29
 
70
- @tables.each do |t|
71
- t.replace!(new_section, data_item)
72
- end
30
+ @sections.each { |s| s.replace!(new_section, data_item) }
73
31
 
74
- @sections.each do |s|
75
- s.replace!(new_section, data_item)
76
- end
32
+ @texts.each { |t| t.replace!(new_section, data_item) }
77
33
 
78
- replace_fields!(new_section, data_item)
34
+ @fields.each { |f| f.replace!(new_section, data_item) }
79
35
 
80
- section.before(new_section)
36
+ @section_node.before(new_section)
81
37
 
82
38
  end
83
39
 
84
- section.remove
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
- end
54
+ def get_section_node
55
+ node = @section_node.dup
99
56
 
100
- end
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