odf-report 0.7.3 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ff3d6495c26d851b5497d740ce9443d69957efa8b6f11e99c9287e68c339147
4
- data.tar.gz: 3ffaee2475b15b556c8bdf7f1e15697442c9603e2c8dc09643887c0170effb2c
3
+ metadata.gz: 65db96f6bec66147072afafb0d4193df34d188f4c0479361c7dfb34b36300930
4
+ data.tar.gz: c7f903e4fa5cb6a5fa811da28339fb3a27d0f9a7d9d2910107efb9cc941823e0
5
5
  SHA512:
6
- metadata.gz: 6eff87a548135805364a1a214687e3b949975184b71bd0ea1796351110e4e142e02e6fda65a45bd039a4825e7bd58f435e2267a040a7ee69c1f8983a956331ce
7
- data.tar.gz: 6638443f8259b7b2c8b1fcbee7efa83c935febacbf28141e2392dc2de4a1b67d31caea6726070fe85dfb7eeb1eefb23c39ee57527a8621694252b3a31130ced2
6
+ metadata.gz: 82b5cf956e054ed3eec7d93e3b1bcb2244a3922df1faa3d7145a00fbca4a79d7c0d0a7cbb0dd05916dcd020f38305aa33083564812eb1d2417050c26010dc4cd
7
+ data.tar.gz: f0850ee3d3fa433cc55d38136f78c269796159feb07307a39c996af80da6f2597fe6928ec0cdcb38174044ba3899c399e73e6f0fd714df518f316a618ca7b912
@@ -8,13 +8,16 @@ jobs:
8
8
  build:
9
9
  name: Build + Publish
10
10
  runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ packages: write
11
14
 
12
15
  steps:
13
- - uses: actions/checkout@v2
14
- - name: Set up Ruby 2.6
15
- uses: actions/setup-ruby@v1
16
+ - uses: actions/checkout@v4
17
+ - uses: ruby/setup-ruby@v1
16
18
  with:
17
- version: 2.6.x
19
+ ruby-version: '3.2'
20
+ bundler-cache: true
18
21
 
19
22
  # - name: Publish to GPR
20
23
  # run: |
data/CHANGELOG.md CHANGED
@@ -18,10 +18,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
18
18
 
19
19
  - None
20
20
 
21
+ ## 0.8.1
22
+
23
+ ### Fixed
24
+ - \<br\> replacement in default text parser #130
25
+
26
+ ## 0.8.0
27
+
28
+ ### Fixed
29
+ - Use Nokogiri HTML5 parser for text nodes parsing #129
30
+
31
+ ### Dependencies
32
+ - nokogiri >= 1.12.0 (was >= 1.10.0)
33
+
21
34
  ## 0.7.3
22
35
 
23
36
  ### Fixed
24
- - newer versions (> 1.3.0) of Nokogiri where presenting "Nokogiri::CSS::SyntaxError: unexpected '|'" #120
37
+ - newer versions (> 1.13.0) of Nokogiri where presenting "Nokogiri::CSS::SyntaxError: unexpected '|'" #120
25
38
  - prevent unnecessary memory expensive operations with missing placeholders #117
26
39
 
27
40
  ## 0.7.2
data/README.md CHANGED
@@ -56,7 +56,7 @@ report = ODFReport::Report.new("Users/john/my_template.odt") do |r|
56
56
  r.add_field "USER_NAME", @user.nome
57
57
  r.add_field "ADDRESS", @user.address
58
58
 
59
- r.add_table("TABLE_1", @list_of_itens, :header=>true) do |t|
59
+ r.add_table("TABLE_1", @list_of_items, :header=>true) do |t|
60
60
  t.add_column(:item_id, :id)
61
61
  t.add_column(:description) { |item| "==> #{item.description}" }
62
62
  end
@@ -71,7 +71,7 @@ and considering you have a table like this in your template
71
71
  | [ITEM_ID] | [DESCRIPTION] |
72
72
 
73
73
 
74
- and a collection `@list_of_itens`, it will create one row for each item in the collection, and the replacement will take place accordingly.
74
+ and a collection `@list_of_items`, it will create one row for each item in the collection, and the replacement will take place accordingly.
75
75
 
76
76
  Any format applied to the fields in the template will be preserved.
77
77
 
@@ -1,12 +1,11 @@
1
1
  module ODFReport
2
2
  class DataSource
3
-
4
3
  attr_reader :value
5
4
 
6
5
  def initialize(opts, &block)
7
- @value = opts[:value] || opts[:collection]
6
+ @value = opts[:value] || opts[:collection]
8
7
  @data_field = opts[:data_field] || opts[:collection_field] || opts[:name]
9
- @block = block
8
+ @block = block
10
9
  end
11
10
 
12
11
  def set_source(record)
@@ -25,7 +24,6 @@ module ODFReport
25
24
  private
26
25
 
27
26
  def extract_value_from_item(record)
28
-
29
27
  if @block
30
28
  @block.call(record)
31
29
 
@@ -43,23 +41,21 @@ module ODFReport
43
41
  record.send(@data_field)
44
42
 
45
43
  else
46
- raise "Can't find [#{@data_field.to_s}] in this #{record.class}"
44
+ raise "Can't find [#{@data_field}] in this #{record.class}"
47
45
 
48
46
  end
49
-
50
47
  end
51
48
 
52
49
  def execute_methods_on_item(record)
53
50
  tmp = record.dup
54
51
  @data_field.each do |f|
55
- if f.is_a?(Hash)
56
- tmp = tmp.send(f.keys[0], f.values[0])
52
+ tmp = if f.is_a?(Hash)
53
+ tmp.send(f.keys[0], f.values[0])
57
54
  else
58
- tmp = tmp.send(f)
55
+ tmp.send(f)
59
56
  end
60
57
  end
61
58
  tmp
62
59
  end
63
-
64
60
  end
65
61
  end
@@ -1,6 +1,5 @@
1
1
  module ODFReport
2
2
  class Field
3
-
4
3
  DELIMITERS = %w([ ])
5
4
 
6
5
  def initialize(opts, &block)
@@ -14,16 +13,14 @@ module ODFReport
14
13
  end
15
14
 
16
15
  def replace!(content, data_item = nil)
17
-
18
16
  txt = content.inner_html
19
17
 
20
18
  if txt.gsub!(to_placeholder, sanitize(@data_source.value))
21
19
  content.inner_html = txt
22
20
  end
23
-
24
21
  end
25
22
 
26
- private
23
+ private
27
24
 
28
25
  def to_placeholder
29
26
  if DELIMITERS.is_a?(Array)
@@ -35,11 +32,10 @@ module ODFReport
35
32
 
36
33
  def sanitize(txt)
37
34
  txt = html_escape(txt)
38
- txt = odf_linebreak(txt)
39
- txt
35
+ odf_linebreak(txt)
40
36
  end
41
37
 
42
- HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;' }
38
+ HTML_ESCAPE = {"&" => "&amp;", ">" => "&gt;", "<" => "&lt;", '"' => "&quot;"}
43
39
 
44
40
  def html_escape(s)
45
41
  return "" unless s
@@ -50,6 +46,5 @@ module ODFReport
50
46
  return "" unless s
51
47
  s.to_s.gsub("\n", "<text:line-break/>")
52
48
  end
53
-
54
49
  end
55
50
  end
@@ -1,6 +1,5 @@
1
1
  module ODFReport
2
2
  class Image < Field
3
-
4
3
  IMAGE_DIR_NAME = "Pictures"
5
4
 
6
5
  attr_reader :files
@@ -11,7 +10,6 @@ module ODFReport
11
10
  end
12
11
 
13
12
  def replace!(doc, data_item = nil)
14
-
15
13
  frame = doc.xpath("//draw:frame[@draw:name='#{@name}']").first
16
14
  image = doc.xpath("//draw:frame[@draw:name='#{@name}']/draw:image").first
17
15
 
@@ -20,14 +18,13 @@ module ODFReport
20
18
  file = @data_source.value
21
19
 
22
20
  if file
23
- image.attribute('href').content = File.join(IMAGE_DIR_NAME, File.basename(file))
24
- frame.attribute('name').content = SecureRandom.uuid
21
+ image.attribute("href").content = File.join(IMAGE_DIR_NAME, File.basename(file))
22
+ frame.attribute("name").content = SecureRandom.uuid
25
23
 
26
24
  @files << file
27
25
  else
28
26
  frame.remove
29
27
  end
30
-
31
28
  end
32
29
 
33
30
  def self.include_image_file(zip_file, image_file)
@@ -41,17 +38,15 @@ module ODFReport
41
38
  def self.include_manifest_entry(content, image_file)
42
39
  return unless image_file
43
40
 
44
- return unless root_node = content.at("//manifest:manifest")
41
+ return unless (root_node = content.at("//manifest:manifest"))
45
42
 
46
43
  href = File.join(IMAGE_DIR_NAME, File.basename(image_file))
47
44
 
48
- entry = content.create_element('manifest:file-entry')
49
- entry['manifest:full-path'] = href
50
- entry['manifest:media-type'] = MIME::Types.type_for(href)[0].content_type
45
+ entry = content.create_element("manifest:file-entry")
46
+ entry["manifest:full-path"] = href
47
+ entry["manifest:media-type"] = MIME::Types.type_for(href)[0].content_type
51
48
 
52
49
  root_node.add_child entry
53
-
54
50
  end
55
-
56
51
  end
57
52
  end
@@ -1,17 +1,15 @@
1
1
  module ODFReport
2
2
  class Nestable
3
-
4
3
  def initialize(opts)
5
4
  @name = opts[:name]
6
5
 
7
6
  @data_source = DataSource.new(opts)
8
7
 
9
- @fields = []
10
- @texts = []
11
- @tables = []
8
+ @fields = []
9
+ @texts = []
10
+ @tables = []
12
11
  @sections = []
13
- @images = []
14
-
12
+ @images = []
15
13
  end
16
14
 
17
15
  def set_source(data_item)
@@ -19,32 +17,36 @@ module ODFReport
19
17
  self
20
18
  end
21
19
 
22
- def add_field(name, data_field=nil, &block)
23
- opts = { name: name, data_field: data_field }
20
+ def add_field(name, data_field = nil, &block)
21
+ opts = {name: name, data_field: data_field}
24
22
  @fields << Field.new(opts, &block)
25
23
  end
26
24
  alias_method :add_column, :add_field
27
25
 
28
- def add_text(name, data_field=nil, &block)
26
+ def add_text(name, data_field = nil, &block)
29
27
  opts = {name: name, data_field: data_field}
30
28
  @texts << Text.new(opts, &block)
31
29
  end
32
30
 
33
- def add_image(name, data_field=nil, &block)
31
+ def add_image(name, data_field = nil, &block)
34
32
  opts = {name: name, data_field: data_field}
35
33
  @images << Image.new(opts, &block)
36
34
  end
37
35
 
38
- def add_table(table_name, collection_field, opts={})
39
- opts.merge!(name: table_name, collection_field: collection_field)
36
+ def add_table(table_name, collection_field, opts = {})
37
+ opts[:name] = table_name
38
+ opts[:collection_field] = collection_field
39
+
40
40
  tab = Table.new(opts)
41
41
  @tables << tab
42
42
 
43
43
  yield(tab)
44
44
  end
45
45
 
46
- def add_section(section_name, collection_field, opts={})
47
- opts.merge!(name: section_name, collection_field: collection_field)
46
+ def add_section(section_name, collection_field, opts = {})
47
+ opts[:name] = section_name
48
+ opts[:collection_field] = collection_field
49
+
48
50
  sec = Section.new(opts)
49
51
  @sections << sec
50
52
 
@@ -60,6 +62,5 @@ module ODFReport
60
62
  <root xmlns:draw="a" xmlns:xlink="b" xmlns:text="c" xmlns:table="d">#{node.to_xml}</root>
61
63
  XML
62
64
  end
63
-
64
65
  end
65
66
  end
@@ -1,91 +1,82 @@
1
1
  module ODFReport
2
+ module Parser
3
+ # Default HTML parser
4
+ #
5
+ # sample HTML
6
+ #
7
+ # <p> first paragraph </p>
8
+ # <p> second <strong>paragraph</strong> </p>
9
+ # <blockquote>
10
+ # <p> first <em>quote paragraph</em> </p>
11
+ # <p> first quote paragraph </p>
12
+ # <p> first quote paragraph </p>
13
+ # </blockquote>
14
+ # <p> third <strong>paragraph</strong> </p>
15
+ #
16
+ # <p style="margin: 100px"> fourth <em>paragraph</em> </p>
17
+ # <p style="margin: 120px"> fifth paragraph </p>
18
+ # <p> sixth <strong>paragraph</strong> </p>
19
+ #
20
+
21
+ class Default
22
+ attr_accessor :paragraphs
23
+
24
+ def initialize(text, template_node)
25
+ @text = text
26
+ @paragraphs = []
27
+ @template_node = template_node
28
+
29
+ parse
30
+ end
2
31
 
3
- module Parser
4
-
5
-
6
- # Default HTML parser
7
- #
8
- # sample HTML
9
- #
10
- # <p> first paragraph </p>
11
- # <p> second <strong>paragraph</strong> </p>
12
- # <blockquote>
13
- # <p> first <em>quote paragraph</em> </p>
14
- # <p> first quote paragraph </p>
15
- # <p> first quote paragraph </p>
16
- # </blockquote>
17
- # <p> third <strong>paragraph</strong> </p>
18
- #
19
- # <p style="margin: 100px"> fourth <em>paragraph</em> </p>
20
- # <p style="margin: 120px"> fifth paragraph </p>
21
- # <p> sixth <strong>paragraph</strong> </p>
22
- #
23
-
24
- class Default
25
-
26
- attr_accessor :paragraphs
27
-
28
- def initialize(text, template_node)
29
- @text = text
30
- @paragraphs = []
31
- @template_node = template_node
32
-
33
- parse
34
- end
35
-
36
- def parse
37
-
38
- xml = @template_node.parse(@text)
39
-
40
- xml.css("p", "h1", "h2").each do |p|
32
+ def parse
33
+ html = Nokogiri::HTML5.fragment(@text)
41
34
 
42
- style = check_style(p)
43
- text = parse_formatting(p.inner_html)
35
+ html.css("p", "h1", "h2").each do |p|
36
+ style = check_style(p)
37
+ text = parse_formatting(p.inner_html)
44
38
 
45
- add_paragraph(text, style)
39
+ add_paragraph(text, style)
40
+ end
46
41
  end
47
- end
48
42
 
49
- def add_paragraph(text, style)
43
+ def add_paragraph(text, style)
44
+ node = @template_node.dup
50
45
 
51
- node = @template_node.dup
46
+ node["text:style-name"] = style if style
47
+ node.children = text
52
48
 
53
- node['text:style-name'] = style if style
54
- node.children = text
49
+ @paragraphs << node
50
+ end
55
51
 
56
- @paragraphs << node
57
- end
52
+ private
58
53
 
59
- private
54
+ def parse_formatting(text)
55
+ text.strip!
56
+ text.gsub!(/<strong.*?>(.+?)<\/strong>/) { "<text:span text:style-name=\"bold\">#{$1}</text:span>" }
57
+ text.gsub!(/<em.*?>(.+?)<\/em>/) { "<text:span text:style-name=\"italic\">#{$1}</text:span>" }
58
+ text.gsub!(/<u.*?>(.+?)<\/u>/) { "<text:span text:style-name=\"underline\">#{$1}</text:span>" }
59
+ text.gsub!(/<br\/?>/, "<text:line-break/>")
60
+ text.delete!("\n")
61
+ text
62
+ end
60
63
 
61
- def parse_formatting(text)
62
- text.strip!
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>" }
66
- text.gsub!("\n", "")
67
- text
68
- end
64
+ def check_style(node)
65
+ style = nil
69
66
 
70
- def check_style(node)
71
- style = nil
67
+ if /h\d/i.match?(node.name)
68
+ style = "title"
72
69
 
73
- if node.name =~ /h\d/i
74
- style = "title"
70
+ elsif node.parent && node.parent.name == "blockquote"
71
+ style = "quote"
75
72
 
76
- elsif node.parent && node.parent.name == "blockquote"
77
- style = "quote"
73
+ elsif /margin/.match?(node["style"])
74
+ style = "quote"
78
75
 
79
- elsif node['style'] =~ /margin/
80
- style = "quote"
76
+ end
81
77
 
78
+ style
82
79
  end
83
-
84
- style
85
80
  end
86
-
87
81
  end
88
-
89
- end
90
-
91
82
  end
@@ -1,92 +1,84 @@
1
1
  module ODFReport
2
+ class Report
3
+ def initialize(template_name = nil, io: nil)
4
+ @template = ODFReport::Template.new(template_name, io: io)
2
5
 
3
- class Report
6
+ @texts = []
7
+ @fields = []
8
+ @tables = []
9
+ @sections = []
4
10
 
5
- def initialize(template_name = nil, io: nil)
11
+ @images = []
6
12
 
7
- @template = ODFReport::Template.new(template_name, io: io)
8
-
9
- @texts = []
10
- @fields = []
11
- @tables = []
12
- @sections = []
13
-
14
- @images = []
15
-
16
- yield(self) if block_given?
17
-
18
- end
13
+ yield(self) if block_given?
14
+ end
19
15
 
20
- def add_field(field_tag, value='')
21
- opts = {:name => field_tag, :value => value}
22
- field = Field.new(opts)
23
- @fields << field
24
- end
16
+ def add_field(field_tag, value = "")
17
+ opts = {name: field_tag, value: value}
18
+ field = Field.new(opts)
19
+ @fields << field
20
+ end
25
21
 
26
- def add_text(field_tag, value='')
27
- opts = {:name => field_tag, :value => value}
28
- text = Text.new(opts)
29
- @texts << text
30
- end
22
+ def add_text(field_tag, value = "")
23
+ opts = {name: field_tag, value: value}
24
+ text = Text.new(opts)
25
+ @texts << text
26
+ end
31
27
 
32
- def add_table(table_name, collection, opts={})
33
- opts.merge!(:name => table_name, :collection => collection)
34
- tab = Table.new(opts)
35
- @tables << tab
28
+ def add_table(table_name, collection, opts = {})
29
+ opts[:name] = table_name
30
+ opts[:collection] = collection
36
31
 
37
- yield(tab)
38
- end
32
+ tab = Table.new(opts)
33
+ @tables << tab
39
34
 
40
- def add_section(section_name, collection, opts={})
41
- opts.merge!(:name => section_name, :collection => collection)
42
- sec = Section.new(opts)
43
- @sections << sec
35
+ yield(tab)
36
+ end
44
37
 
45
- yield(sec)
46
- end
38
+ def add_section(section_name, collection, opts = {})
39
+ opts[:name] = section_name
40
+ opts[:collection] = collection
47
41
 
48
- def add_image(image_name, value=nil)
49
- opts = {:name => image_name, :value => value}
50
- image = Image.new(opts)
51
- @images << image
52
- end
42
+ sec = Section.new(opts)
43
+ @sections << sec
53
44
 
54
- def generate(dest = nil)
45
+ yield(sec)
46
+ end
55
47
 
56
- @template.update_content do |file|
48
+ def add_image(image_name, value = nil)
49
+ opts = {name: image_name, value: value}
50
+ image = Image.new(opts)
51
+ @images << image
52
+ end
57
53
 
58
- file.update_files do |doc|
54
+ def generate(dest = nil)
55
+ @template.update_content do |file|
56
+ file.update_files do |doc|
57
+ @sections.each { |c| c.replace!(doc) }
58
+ @tables.each { |c| c.replace!(doc) }
59
59
 
60
- @sections.each { |c| c.replace!(doc) }
61
- @tables.each { |c| c.replace!(doc) }
60
+ @texts.each { |c| c.replace!(doc) }
61
+ @fields.each { |c| c.replace!(doc) }
62
62
 
63
- @texts.each { |c| c.replace!(doc) }
64
- @fields.each { |c| c.replace!(doc) }
63
+ @images.each { |c| c.replace!(doc) }
64
+ end
65
65
 
66
- @images.each { |c| c.replace!(doc) }
66
+ all_images.each { |i| Image.include_image_file(file, i) }
67
67
 
68
+ file.update_manifest do |content|
69
+ all_images.each { |i| Image.include_manifest_entry(content, i) }
70
+ end
68
71
  end
69
72
 
70
- all_images.each { |i| Image.include_image_file(file, i) }
71
-
72
- file.update_manifest do |content|
73
- all_images.each { |i| Image.include_manifest_entry(content, i) }
73
+ if dest
74
+ File.binwrite(dest, @template.data)
75
+ else
76
+ @template.data
74
77
  end
75
-
76
78
  end
77
79
 
78
- if dest
79
- File.open(dest, "wb") { |f| f.write(@template.data) }
80
- else
81
- @template.data
80
+ def all_images
81
+ @all_images ||= (@images.map(&:files) + @sections.map(&:all_images) + @tables.map(&:all_images)).flatten.uniq
82
82
  end
83
-
84
- end
85
-
86
- def all_images
87
- @all_images ||= (@images.map(&:files) + @sections.map(&:all_images) + @tables.map(&:all_images)).flatten.uniq
88
83
  end
89
-
90
- end
91
-
92
84
  end
@@ -1,29 +1,24 @@
1
1
  module ODFReport
2
2
  class Section < Nestable
3
-
4
3
  def replace!(doc)
5
-
6
4
  return unless find_section_node(doc)
7
5
 
8
6
  @data_source.each do |record|
9
-
10
7
  new_section = deep_clone(@section_node)
11
8
 
12
- @tables.each { |t| t.set_source(record).replace!(new_section) }
13
- @sections.each { |s| s.set_source(record).replace!(new_section) }
14
- @texts.each { |t| t.set_source(record).replace!(new_section) }
15
- @fields.each { |f| f.set_source(record).replace!(new_section) }
16
- @images.each { |i| i.set_source(record).replace!(new_section) }
9
+ @tables.each { |t| t.set_source(record).replace!(new_section) }
10
+ @sections.each { |s| s.set_source(record).replace!(new_section) }
11
+ @texts.each { |t| t.set_source(record).replace!(new_section) }
12
+ @fields.each { |f| f.set_source(record).replace!(new_section) }
13
+ @images.each { |i| i.set_source(record).replace!(new_section) }
17
14
 
18
15
  @section_node.before(new_section.to_xml)
19
-
20
16
  end
21
17
 
22
18
  @section_node.remove
23
-
24
19
  end # replace_section
25
20
 
26
- private
21
+ private
27
22
 
28
23
  def find_section_node(doc)
29
24
  @section_node = doc.at_xpath("//text:section[@text:name='#{@name}']")
@@ -31,9 +26,7 @@ module ODFReport
31
26
 
32
27
  def deep_clone(node)
33
28
  Nokogiri::XML(wrap_with_ns(node)).at_xpath("//text:section")
34
- .tap { |n| n.attribute('name').content = SecureRandom.uuid }
35
-
29
+ .tap { |n| n.attribute("name").content = SecureRandom.uuid }
36
30
  end
37
-
38
31
  end
39
32
  end
@@ -1,16 +1,15 @@
1
1
  module ODFReport
2
2
  class Table < Nestable
3
-
4
3
  def initialize(opts)
5
4
  super(opts)
6
5
 
7
6
  @template_rows = []
8
- @header = opts[:header] || false
9
- @skip_if_empty = opts[:skip_if_empty] || false
7
+ @header = opts[:header] || false
8
+ @skip_if_empty = opts[:skip_if_empty] || false
10
9
  end
11
10
 
12
11
  def replace!(doc)
13
- return unless table = find_table_node(doc)
12
+ return unless (table = find_table_node(doc))
14
13
 
15
14
  @template_rows = table.xpath("table:table-row")
16
15
 
@@ -22,26 +21,23 @@ module ODFReport
22
21
  end
23
22
 
24
23
  @data_source.each do |record|
25
-
26
24
  new_node = get_next_row
27
25
 
28
- @tables.each { |n| n.set_source(record).replace!(new_node) }
29
- @sections.each { |n| n.set_source(record).replace!(new_node) }
30
- @texts.each { |n| n.set_source(record).replace!(new_node) }
31
- @fields.each { |n| n.set_source(record).replace!(new_node) }
32
- @images.each { |n| n.set_source(record).replace!(new_node) }
26
+ @tables.each { |n| n.set_source(record).replace!(new_node) }
27
+ @sections.each { |n| n.set_source(record).replace!(new_node) }
28
+ @texts.each { |n| n.set_source(record).replace!(new_node) }
29
+ @fields.each { |n| n.set_source(record).replace!(new_node) }
30
+ @images.each { |n| n.set_source(record).replace!(new_node) }
33
31
 
34
32
  table.add_child(new_node.to_xml)
35
-
36
33
  end
37
34
 
38
35
  @template_rows.each_with_index do |r, i|
39
36
  r.remove if (get_start_node..template_length) === i
40
37
  end
41
-
42
38
  end # replace
43
39
 
44
- private
40
+ private
45
41
 
46
42
  def get_next_row
47
43
  if @template_rows.size == 1
@@ -59,7 +55,7 @@ module ODFReport
59
55
  end
60
56
  end
61
57
 
62
- return deep_clone(ret)
58
+ deep_clone(ret)
63
59
  end
64
60
 
65
61
  def get_start_node
@@ -77,6 +73,5 @@ module ODFReport
77
73
  def deep_clone(node)
78
74
  Nokogiri::XML(wrap_with_ns(node)).at_xpath("//table:table-row")
79
75
  end
80
-
81
76
  end
82
77
  end
@@ -1,7 +1,6 @@
1
1
  module ODFReport
2
2
  class Template
3
-
4
- CONTENT_FILES = ['content.xml', 'styles.xml']
3
+ CONTENT_FILES = ["content.xml", "styles.xml"]
5
4
  MANIFEST_FILE = "META-INF/manifest.xml"
6
5
 
7
6
  attr_accessor :output_stream
@@ -22,13 +21,10 @@ module ODFReport
22
21
  end
23
22
 
24
23
  def update_files(&block)
25
-
26
24
  get_template_entries.each do |entry|
27
-
28
25
  next if entry.directory?
29
26
 
30
27
  entry.get_input_stream do |is|
31
-
32
28
  data = is.sysread
33
29
 
34
30
  if CONTENT_FILES.include?(entry.name)
@@ -36,25 +32,20 @@ module ODFReport
36
32
  end
37
33
 
38
34
  update_file(entry.name, data) unless entry.name == MANIFEST_FILE
39
-
40
35
  end
41
36
  end
42
-
43
37
  end
44
38
 
45
39
  def update_manifest(&block)
46
40
  entry = get_template_entries.find_entry(MANIFEST_FILE)
47
41
 
48
42
  entry.get_input_stream do |is|
49
-
50
43
  data = is.sysread
51
44
 
52
45
  process_entry(data, &block)
53
46
 
54
47
  update_file(MANIFEST_FILE, data)
55
-
56
48
  end
57
-
58
49
  end
59
50
 
60
51
  def data
@@ -69,13 +60,11 @@ module ODFReport
69
60
  private
70
61
 
71
62
  def get_template_entries
72
-
73
63
  if @template
74
64
  Zip::File.open(@template)
75
65
  else
76
66
  Zip::File.open_buffer(@io.force_encoding("ASCII-8BIT"))
77
67
  end
78
-
79
68
  end
80
69
 
81
70
  def process_entry(entry)
@@ -83,6 +72,5 @@ module ODFReport
83
72
  yield doc
84
73
  entry.replace(doc.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML))
85
74
  end
86
-
87
75
  end
88
76
  end
@@ -1,12 +1,9 @@
1
1
  module ODFReport
2
-
3
2
  class Text < Field
4
-
5
3
  attr_accessor :parser
6
4
 
7
5
  def replace!(doc, data_item = nil)
8
-
9
- return unless node = find_text_node(doc)
6
+ return unless (node = find_text_node(doc))
10
7
 
11
8
  @parser = Parser::Default.new(@data_source.value, node)
12
9
 
@@ -15,7 +12,6 @@ module ODFReport
15
12
  end
16
13
 
17
14
  node.remove
18
-
19
15
  end
20
16
 
21
17
  private
@@ -24,10 +20,10 @@ module ODFReport
24
20
  texts = doc.xpath(".//text:p[text()='#{to_placeholder}']")
25
21
  if texts.empty?
26
22
  texts = doc.xpath(".//text:p/text:span[text()='#{to_placeholder}']")
27
- if texts.empty?
28
- texts = nil
23
+ texts = if texts.empty?
24
+ nil
29
25
  else
30
- texts = texts.first.parent
26
+ texts.first.parent
31
27
  end
32
28
  else
33
29
  texts = texts.first
@@ -35,7 +31,5 @@ module ODFReport
35
31
 
36
32
  texts
37
33
  end
38
-
39
34
  end
40
-
41
35
  end
@@ -1,3 +1,3 @@
1
1
  module ODFReport
2
- VERSION = "0.7.3"
2
+ VERSION = "0.8.1"
3
3
  end
data/lib/odf-report.rb CHANGED
@@ -1,18 +1,18 @@
1
- require 'rubygems'
2
- require 'zip'
3
- require 'fileutils'
4
- require 'nokogiri'
5
- require 'mime/types'
6
- require 'securerandom'
1
+ require "rubygems"
2
+ require "zip"
3
+ require "fileutils"
4
+ require "nokogiri"
5
+ require "mime/types"
6
+ require "securerandom"
7
7
 
8
- require File.expand_path('../odf-report/parser/default', __FILE__)
8
+ require File.expand_path("../odf-report/parser/default", __FILE__)
9
9
 
10
- require File.expand_path('../odf-report/data_source', __FILE__)
11
- require File.expand_path('../odf-report/field', __FILE__)
12
- require File.expand_path('../odf-report/text', __FILE__)
13
- require File.expand_path('../odf-report/template', __FILE__)
14
- require File.expand_path('../odf-report/image', __FILE__)
15
- require File.expand_path('../odf-report/nestable', __FILE__)
16
- require File.expand_path('../odf-report/section', __FILE__)
17
- require File.expand_path('../odf-report/table', __FILE__)
18
- require File.expand_path('../odf-report/report', __FILE__)
10
+ require File.expand_path("../odf-report/data_source", __FILE__)
11
+ require File.expand_path("../odf-report/field", __FILE__)
12
+ require File.expand_path("../odf-report/text", __FILE__)
13
+ require File.expand_path("../odf-report/template", __FILE__)
14
+ require File.expand_path("../odf-report/image", __FILE__)
15
+ require File.expand_path("../odf-report/nestable", __FILE__)
16
+ require File.expand_path("../odf-report/section", __FILE__)
17
+ require File.expand_path("../odf-report/table", __FILE__)
18
+ require File.expand_path("../odf-report/report", __FILE__)
data/odf-report.gemspec CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_development_dependency "launchy"
26
26
 
27
27
  s.add_runtime_dependency('rubyzip', ">= 1.3.0")
28
- s.add_runtime_dependency('nokogiri', ">= 1.10.0")
28
+ s.add_runtime_dependency('nokogiri', ">= 1.12.0")
29
29
  s.add_runtime_dependency('mime-types')
30
30
 
31
31
  end
Binary file
@@ -0,0 +1,48 @@
1
+ RSpec.describe "Texts" do
2
+ before(:context) do
3
+
4
+ @text1 = <<-HTML
5
+ <p>This is some text in a paragraph</p>
6
+ HTML
7
+
8
+ @text2 = <<-HTML
9
+ <p>Text before line break <br> text after line break</p>
10
+ HTML
11
+
12
+ @text3 = <<-HTML
13
+ <p>Text before entities
14
+ Maur&iacute;cio
15
+ Text after entities</p>
16
+ HTML
17
+
18
+
19
+ report = ODFReport::Report.new("spec/templates/specs.odt") do |r|
20
+
21
+ r.add_text(:text1, @text1)
22
+ r.add_text(:text2, @text2)
23
+ r.add_text(:text3, @text3)
24
+
25
+ end
26
+
27
+ report.generate("spec/result/specs.odt")
28
+
29
+ @data = Inspector.new("spec/result/specs.odt")
30
+
31
+ end
32
+
33
+ it "simple text replacement" do
34
+ expect(@data.text).to include "This is some text in a paragraph"
35
+ end
36
+
37
+ it "text replacement with <br>" do
38
+ expect(@data.text).to include "Text before line break"
39
+ expect(@data.text).to include "text after line break"
40
+ end
41
+
42
+ it "text replacement with html entities" do
43
+ expect(@data.text).to include "Text before entities"
44
+ expect(@data.text).to include "Maurício"
45
+ expect(@data.text).to include "Text after entities"
46
+ end
47
+
48
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: odf-report
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Duarte
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-23 00:00:00.000000000 Z
11
+ date: 2024-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 1.10.0
103
+ version: 1.12.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: 1.10.0
110
+ version: 1.12.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: mime-types
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -169,6 +169,7 @@ files:
169
169
  - spec/template_spec.rb
170
170
  - spec/templates/images.odt
171
171
  - spec/templates/specs.odt
172
+ - spec/texts_spec.rb
172
173
  - test/fields_inside_text_test.rb
173
174
  - test/images_test.rb
174
175
  - test/nested_tables_test.rb
@@ -211,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
212
  - !ruby/object:Gem::Version
212
213
  version: '0'
213
214
  requirements: []
214
- rubygems_version: 3.2.32
215
+ rubygems_version: 3.4.19
215
216
  signing_key:
216
217
  specification_version: 4
217
218
  summary: Generates ODF files, given a template (.odt) and data, replacing tags
@@ -230,6 +231,7 @@ test_files:
230
231
  - spec/template_spec.rb
231
232
  - spec/templates/images.odt
232
233
  - spec/templates/specs.odt
234
+ - spec/texts_spec.rb
233
235
  - test/fields_inside_text_test.rb
234
236
  - test/images_test.rb
235
237
  - test/nested_tables_test.rb