sablon 0.0.19.beta3 → 0.0.19.beta4

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
  SHA1:
3
- metadata.gz: 43e4aa5cc44824e41d65481d0b32a1f97a94ea2c
4
- data.tar.gz: 9fb8f9890f54cd1169ade7b178a2f995bc12d37b
3
+ metadata.gz: ac235d2921b38ea77aa5aef274e73aa34e84ffcf
4
+ data.tar.gz: 9ce6a08012f8540e2a1998d35a177a9e6b95a909
5
5
  SHA512:
6
- metadata.gz: 04ed4067045f1067cf36f98bc9139b869e66179a75f009d774e547df9a138b029ca2d47266e2e5019c70592b1e3821a921e01d93dfc22e74a377fc7f14647c9f
7
- data.tar.gz: 40435b0860b374a75e07343793d55d66b6a880b9df3b0951206171cdc961146f79204c5e7fd0988655ad3867a46b26720bfc6874b7cc588ac7852c85ddeeae07
6
+ metadata.gz: 219cb0acb4fdbf3eedc347577dc4c42996e78eb792a51394261e60a48d7b8114cd6d3668d91bcd00f0bdeb6406d0e0f3a2fb4ff63f12e12454bb5682cdbe967d
7
+ data.tar.gz: 51128d4324f508395837d57cf8330dabed48729ebe8518bacafd18416fa502b0e2a8dfbf4e980ab763a93f5f49c50f5330739dde185780d8f02ac83f66776b59
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sablon (0.0.19.beta3)
4
+ sablon (0.0.19.beta4)
5
5
  nokogiri (>= 1.6.0)
6
6
  redcarpet (>= 3.2)
7
7
  rubyzip (>= 1.1)
@@ -26,18 +26,22 @@ module Sablon
26
26
  def to_docx
27
27
  nodes.map(&:to_docx).join
28
28
  end
29
- end
30
29
 
31
- class Root < Collection
32
- def to_a
33
- nodes
30
+ def inspect
31
+ "[#{nodes.map(&:inspect).join(', ')}]"
34
32
  end
33
+ end
35
34
 
35
+ class Root < Collection
36
36
  def grep(pattern)
37
37
  visitor = GrepVisitor.new(pattern)
38
38
  accept(visitor)
39
39
  visitor.result
40
40
  end
41
+
42
+ def inspect
43
+ "<Root: #{super}>"
44
+ end
41
45
  end
42
46
 
43
47
  class Paragraph < Node
@@ -65,6 +69,10 @@ XML
65
69
  runs.accept(visitor)
66
70
  end
67
71
 
72
+ def inspect
73
+ "<Paragraph{#{style}}: #{runs.inspect}>"
74
+ end
75
+
68
76
  private
69
77
  def ppr_docx
70
78
  end
@@ -90,34 +98,61 @@ XML
90
98
  end
91
99
  end
92
100
 
93
- class Text < Node
94
- attr_reader :string
95
- def initialize(string)
96
- @string = string
101
+ class TextFormat
102
+ def initialize(bold, italic)
103
+ @bold = bold
104
+ @italic = italic
105
+ end
106
+
107
+ def inspect
108
+ parts = []
109
+ parts << 'bold' if @bold
110
+ parts << 'italic' if @italic
111
+ parts.join('|')
97
112
  end
98
113
 
99
114
  def to_docx
100
- "<w:r>#{style_docx}<w:t xml:space=\"preserve\">#{normalized_string}</w:t></w:r>"
115
+ styles = []
116
+ styles << '<w:b />' if @bold
117
+ styles << '<w:i />' if @italic
118
+ if styles.any?
119
+ "<w:rPr>#{styles.join}</w:rPr>"
120
+ else
121
+ ''
122
+ end
101
123
  end
102
124
 
103
- private
104
- def style_docx
125
+ def self.default
126
+ @default ||= new(false, false)
105
127
  end
106
128
 
107
- def normalized_string
108
- string.tr("\u00A0", ' ')
129
+ def with_bold
130
+ TextFormat.new(true, @italic)
109
131
  end
110
- end
111
132
 
112
- class Bold < Text
113
- def style_docx
114
- '<w:rPr><w:b /></w:rPr>'
133
+ def with_italic
134
+ TextFormat.new(@bold, true)
115
135
  end
116
136
  end
117
137
 
118
- class Italic < Text
119
- def style_docx
120
- '<w:rPr><w:i /></w:rPr>'
138
+ class Text < Node
139
+ attr_reader :string
140
+ def initialize(string, format)
141
+ @string = string
142
+ @format = format
143
+ end
144
+
145
+ def to_docx
146
+ "<w:r>#{@format.to_docx}<w:t xml:space=\"preserve\">#{normalized_string}</w:t></w:r>"
147
+ end
148
+
149
+ def inspect
150
+ "<Text{#{@format.inspect}}: #{string}>"
151
+ end
152
+
153
+ private
154
+ def normalized_string
155
+ string.tr("\u00A0", ' ')
121
156
  end
122
157
  end
123
158
 
@@ -125,6 +160,10 @@ XML
125
160
  def to_docx
126
161
  "<w:r><w:br/></w:r>"
127
162
  end
163
+
164
+ def inspect
165
+ "<Newline>"
166
+ end
128
167
  end
129
168
  end
130
169
  end
@@ -88,10 +88,10 @@ module Sablon
88
88
  node = @builder.next
89
89
  if node.name == 'div'
90
90
  @builder.new_layer
91
- @builder.emit Paragraph.new('Normal', text(node.children))
91
+ @builder.emit Paragraph.new('Normal', ast_text(node.children))
92
92
  elsif node.name == 'p'
93
93
  @builder.new_layer
94
- @builder.emit Paragraph.new('Paragraph', text(node.children))
94
+ @builder.emit Paragraph.new('Paragraph', ast_text(node.children))
95
95
  elsif node.name == 'ul'
96
96
  @builder.new_layer ilvl: true
97
97
  unless @builder.nested?
@@ -106,7 +106,7 @@ module Sablon
106
106
  @builder.push_all(node.children)
107
107
  elsif node.name == 'li'
108
108
  @builder.new_layer
109
- @builder.emit ListParagraph.new(@definition.style, text(node.children), @definition.numid, @builder.ilvl)
109
+ @builder.emit ListParagraph.new(@definition.style, ast_text(node.children), @definition.numid, @builder.ilvl)
110
110
  elsif node.text?
111
111
  # SKIP?
112
112
  else
@@ -114,16 +114,16 @@ module Sablon
114
114
  end
115
115
  end
116
116
 
117
- def text(nodes)
118
- runs = nodes.map do |node|
117
+ def ast_text(nodes, format: TextFormat.default)
118
+ runs = nodes.flat_map do |node|
119
119
  if node.text?
120
- Text.new(node.text)
120
+ Text.new(node.text, format)
121
121
  elsif node.name == 'br'
122
122
  Newline.new
123
123
  elsif node.name == 'strong'
124
- Bold.new(node.text)
124
+ ast_text(node.children, format: format.with_bold).nodes
125
125
  elsif node.name == 'em'
126
- Italic.new(node.text)
126
+ ast_text(node.children, format: format.with_italic).nodes
127
127
  elsif ['ul', 'ol', 'p', 'div'].include?(node.name)
128
128
  @builder.push(node)
129
129
  nil
@@ -3,7 +3,11 @@ module Sablon
3
3
  module Statement
4
4
  class Insertion < Struct.new(:expr, :field)
5
5
  def evaluate(context)
6
- field.replace(Sablon::Content.wrap(expr.evaluate(context)))
6
+ if content = expr.evaluate(context)
7
+ field.replace(Sablon::Content.wrap(expr.evaluate(context)))
8
+ else
9
+ field.remove
10
+ end
7
11
  end
8
12
  end
9
13
 
@@ -1,3 +1,3 @@
1
1
  module Sablon
2
- VERSION = "0.0.19.beta3"
2
+ VERSION = "0.0.19.beta4"
3
3
  end
Binary file
@@ -83,6 +83,25 @@ DOCX
83
83
  assert_equal normalize_wordml(expected_output), @converter.process(input)
84
84
  end
85
85
 
86
+ def test_convert_br_tags_inside_strong
87
+ input = '<div><strong><br />Lorem ipsum<br />dolor sit amet</strong></div>'
88
+ expected_output = <<-DOCX
89
+ <w:p>
90
+ <w:pPr><w:pStyle w:val="Normal" /></w:pPr>
91
+ <w:r><w:br/></w:r>
92
+ <w:r>
93
+ <w:rPr><w:b /></w:rPr>
94
+ <w:t xml:space="preserve">Lorem ipsum</w:t></w:r>
95
+ <w:r><w:br/></w:r>
96
+ <w:r>
97
+ <w:rPr><w:b /></w:rPr>
98
+ <w:t xml:space="preserve">dolor sit amet</w:t>
99
+ </w:r>
100
+ </w:p>
101
+ DOCX
102
+ assert_equal normalize_wordml(expected_output), @converter.process(input)
103
+ end
104
+
86
105
  def test_unorderd_lists
87
106
  input = '<ul><li>Lorem</li><li>ipsum</li><li>dolor</li></ul>'
88
107
  expected_output = <<-DOCX.strip
@@ -263,42 +282,56 @@ class HTMLConverterASTTest < Sablon::TestCase
263
282
 
264
283
  def test_div
265
284
  input = '<div>Lorem ipsum dolor sit amet</div>'
266
- ast = @converter.processed_ast(input).to_a
267
- assert_equal [Sablon::HTMLConverter::Paragraph], ast.map(&:class)
268
- assert_equal ['Normal'], ast.map(&:style)
285
+ ast = @converter.processed_ast(input)
286
+ assert_equal '<Root: [<Paragraph{Normal}: [<Text{}: Lorem ipsum dolor sit amet>]>]>', ast.inspect
269
287
  end
270
288
 
271
289
  def test_p
272
290
  input = '<p>Lorem ipsum dolor sit amet</p>'
273
- ast = @converter.processed_ast(input).to_a
274
- assert_equal [Sablon::HTMLConverter::Paragraph], ast.map(&:class)
275
- assert_equal ['Paragraph'], ast.map(&:style)
291
+ ast = @converter.processed_ast(input)
292
+ assert_equal '<Root: [<Paragraph{Paragraph}: [<Text{}: Lorem ipsum dolor sit amet>]>]>', ast.inspect
293
+ end
294
+
295
+ def test_br_in_strong
296
+ input = '<div><strong>Lorem<br />ipsum<br />dolor</strong></div>'
297
+ par = @converter.processed_ast(input).grep(Sablon::HTMLConverter::Paragraph).first
298
+ assert_equal "[<Text{bold}: Lorem>, <Newline>, <Text{bold}: ipsum>, <Newline>, <Text{bold}: dolor>]", par.runs.inspect
299
+ end
300
+
301
+ def test_br_in_em
302
+ input = '<div><em>Lorem<br />ipsum<br />dolor</em></div>'
303
+ par = @converter.processed_ast(input).grep(Sablon::HTMLConverter::Paragraph).first
304
+ assert_equal "[<Text{italic}: Lorem>, <Newline>, <Text{italic}: ipsum>, <Newline>, <Text{italic}: dolor>]", par.runs.inspect
305
+ end
306
+
307
+ def test_nested_strong_and_em
308
+ input = '<div><strong>Lorem <em>ipsum</em> dolor</strong></div>'
309
+ par = @converter.processed_ast(input).grep(Sablon::HTMLConverter::Paragraph).first
310
+ assert_equal "[<Text{bold}: Lorem >, <Text{bold|italic}: ipsum>, <Text{bold}: dolor>]", par.runs.inspect
276
311
  end
277
312
 
278
313
  def test_ignore_last_br_in_div
279
314
  input = '<div>Lorem ipsum dolor sit amet<br /></div>'
280
- par = @converter.processed_ast(input).to_a.first
281
- assert_equal [Sablon::HTMLConverter::Text], par.runs.nodes.map(&:class)
315
+ par = @converter.processed_ast(input).grep(Sablon::HTMLConverter::Paragraph).first
316
+ assert_equal "[<Text{}: Lorem ipsum dolor sit amet>]", par.runs.inspect
282
317
  end
283
318
 
284
319
  def test_ignore_br_in_blank_div
285
320
  input = '<div><br /></div>'
286
- par = @converter.processed_ast(input).to_a.first
287
- assert_equal [], par.runs.nodes.map(&:class)
321
+ par = @converter.processed_ast(input).grep(Sablon::HTMLConverter::Paragraph).first
322
+ assert_equal "[]", par.runs.inspect
288
323
  end
289
324
 
290
325
  def test_ul
291
326
  input = '<ul><li>Lorem</li><li>ipsum</li></ul>'
292
- ast = @converter.processed_ast(input).to_a
293
- assert_equal [Sablon::HTMLConverter::ListParagraph, Sablon::HTMLConverter::ListParagraph], ast.map(&:class)
294
- assert_equal ["ListBullet", "ListBullet"], ast.map(&:style)
327
+ ast = @converter.processed_ast(input)
328
+ assert_equal "<Root: [<Paragraph{ListBullet}: [<Text{}: Lorem>]>, <Paragraph{ListBullet}: [<Text{}: ipsum>]>]>", ast.inspect
295
329
  end
296
330
 
297
331
  def test_ol
298
332
  input = '<ol><li>Lorem</li><li>ipsum</li></ol>'
299
- ast = @converter.processed_ast(input).to_a
300
- assert_equal [Sablon::HTMLConverter::ListParagraph, Sablon::HTMLConverter::ListParagraph], ast.map(&:class)
301
- assert_equal ["ListNumber", "ListNumber"], ast.map(&:style)
333
+ ast = @converter.processed_ast(input)
334
+ assert_equal "<Root: [<Paragraph{ListNumber}: [<Text{}: Lorem>]>, <Paragraph{ListNumber}: [<Text{}: ipsum>]>]>", ast.inspect
302
335
  end
303
336
 
304
337
  def test_num_id
data/test/html_test.rb CHANGED
@@ -39,7 +39,7 @@ class SablonHTMLTest < Sablon::TestCase
39
39
  private
40
40
  def content
41
41
  <<-HTML
42
- <div>Lorem&nbsp;<strong>ipsum</strong>&nbsp;<em>dolor</em>&nbsp;<strong>sit</strong>&nbsp;<em>amet</em>,&nbsp;<strong>consectetur adipiscing elit</strong>.&nbsp;<em>Suspendisse a tempus turpis</em>. Duis urna justo, vehicula vitae ultricies vel, congue at sem. Fusce turpis turpis, aliquet id pulvinar aliquam, iaculis non elit. Nulla feugiat lectus nulla, in dictum ipsum cursus ac. Quisque at odio neque. Sed ac tortor iaculis, bibendum leo ut, malesuada velit. Donec iaculis sed urna eget pharetra. Praesent ornare fermentum turpis, placerat iaculis urna bibendum vitae. Nunc in quam consequat, tristique tellus in, commodo turpis. Curabitur ullamcorper odio purus, lobortis egestas magna laoreet vitae. Nunc fringilla velit ante, eu aliquam nisi cursus vitae. Suspendisse sit amet dui egestas, volutpat nisi vel, mattis justo. Nullam pellentesque, ipsum eget blandit pharetra, augue elit aliquam mauris, vel mollis nisl augue ut ipsum.</div><ol><li>Vestibulum&nbsp;<ol><li>ante ipsum primis&nbsp;</li></ol></li><li>in faucibus orci luctus&nbsp;<ol><li>et ultrices posuere cubilia Curae;&nbsp;<ol><li>Aliquam vel dolor&nbsp;</li><li>sed sem maximus&nbsp;</li></ol></li><li>fermentum in non odio.&nbsp;<ol><li>Fusce hendrerit ornare mollis.&nbsp;</li></ol></li><li>Nunc scelerisque nibh nec turpis tempor pulvinar.&nbsp;</li></ol></li><li>Donec eros turpis,&nbsp;</li><li>aliquet vel volutpat sit amet,&nbsp;<ol><li>semper eu purus.&nbsp;</li><li>Proin ac erat nec urna efficitur vulputate.&nbsp;<ol><li>Quisque varius convallis ultricies.&nbsp;</li><li>Nullam vel fermentum eros.&nbsp;</li></ol></li></ol></li></ol><div>Pellentesque nulla leo, auctor ornare erat sed, rhoncus congue diam. Duis non porttitor nulla, ut eleifend enim. Pellentesque non tempor sem.</div><div>Mauris auctor egestas arcu,&nbsp;</div><ol><li>id venenatis nibh dignissim id.&nbsp;</li><li>In non placerat metus.&nbsp;</li></ol><ul><li>Nunc sed consequat metus.&nbsp;</li><li>Nulla consectetur lorem consequat,&nbsp;</li><li>malesuada dui at, lacinia lectus.&nbsp;</li></ul><ol><li>Aliquam efficitur&nbsp;</li><li>lorem a mauris feugiat,&nbsp;</li><li>at semper eros pellentesque.&nbsp;</li></ol><div>Nunc lacus diam, consectetur ut odio sit amet, placerat pharetra erat. Sed commodo ut sem id congue. Sed eget neque elit. Curabitur at erat tortor. Maecenas eget sapien vitae est sagittis accumsan et nec orci. Integer luctus at nisl eget venenatis. Nunc nunc eros, consectetur at tortor et, tristique ultrices elit. Nulla in turpis nibh.</div><ul><li>Nam consectetur&nbsp;<ul><li>venenatis tempor.&nbsp;</li></ul></li><li>Aenean&nbsp;<ul><li>blandit<ul><li>porttitor massa,&nbsp;<ul><li>non efficitur&nbsp;<ul><li>metus.&nbsp;</li></ul></li></ul></li></ul></li></ul></li><li>Duis faucibus nunc nec venenatis faucibus.&nbsp;</li><li>Aliquam erat volutpat.&nbsp;</li></ul><div><strong>Quisque non neque ut lacus eleifend volutpat quis sed lacus. Praesent ultrices purus eu quam elementum, sit amet faucibus elit interdum. In lectus orci, elementum quis dictum ac, porta ac ante. Fusce tempus ac mauris id cursus. Phasellus a erat nulla. Mauris dolor orci, malesuada auctor dignissim non, posuere nec odio. Etiam hendrerit justo nec diam ullamcorper, nec blandit elit sodales.</strong></div>
42
+ <div>Lorem&nbsp;<strong>ipsum</strong>&nbsp;<em>dolor</em>&nbsp;<strong>sit</strong>&nbsp;<em>amet</em>,&nbsp;<strong>consectetur adipiscing elit</strong>.&nbsp;<em>Suspendisse a tempus turpis</em>. Duis urna justo, vehicula vitae ultricies vel, congue at sem. Fusce turpis turpis, aliquet id pulvinar aliquam, iaculis non elit. Nulla feugiat lectus nulla, in dictum ipsum cursus ac. Quisque at odio neque. Sed ac tortor iaculis, bibendum leo ut, malesuada velit. Donec iaculis sed urna eget pharetra. Praesent ornare fermentum turpis, placerat iaculis urna bibendum vitae. Nunc in quam consequat, tristique tellus in, commodo turpis. Curabitur ullamcorper odio purus, lobortis egestas magna laoreet vitae. Nunc fringilla velit ante, eu aliquam nisi cursus vitae. Suspendisse sit amet dui egestas, volutpat nisi vel, mattis justo. Nullam pellentesque, ipsum eget blandit pharetra, augue elit aliquam mauris, vel mollis nisl augue ut ipsum.</div><ol><li>Vestibulum&nbsp;<ol><li>ante ipsum primis&nbsp;</li></ol></li><li>in faucibus orci luctus&nbsp;<ol><li>et ultrices posuere cubilia Curae;&nbsp;<ol><li>Aliquam vel dolor&nbsp;</li><li>sed sem maximus&nbsp;</li></ol></li><li>fermentum in non odio.&nbsp;<ol><li>Fusce hendrerit ornare mollis.&nbsp;</li></ol></li><li>Nunc scelerisque nibh nec turpis tempor pulvinar.&nbsp;</li></ol></li><li>Donec eros turpis,&nbsp;</li><li>aliquet vel volutpat sit amet,&nbsp;<ol><li>semper eu purus.&nbsp;</li><li>Proin ac erat nec urna efficitur vulputate.&nbsp;<ol><li>Quisque varius convallis ultricies.&nbsp;</li><li>Nullam vel fermentum eros.&nbsp;</li></ol></li></ol></li></ol><div>Pellentesque nulla leo, auctor ornare erat sed, rhoncus congue diam. Duis non porttitor nulla, ut eleifend enim. Pellentesque non tempor sem.</div><div>Mauris auctor egestas arcu,&nbsp;</div><ol><li>id venenatis nibh dignissim id.&nbsp;</li><li>In non placerat metus.&nbsp;</li></ol><ul><li>Nunc sed consequat metus.&nbsp;</li><li>Nulla consectetur lorem consequat,&nbsp;</li><li>malesuada dui at, lacinia lectus.&nbsp;</li></ul><ol><li>Aliquam efficitur&nbsp;</li><li>lorem a mauris feugiat,&nbsp;</li><li>at semper eros pellentesque.&nbsp;</li></ol><div>Nunc lacus diam, consectetur ut odio sit amet, placerat pharetra erat. Sed commodo ut sem id congue. Sed eget neque elit. Curabitur at erat tortor. Maecenas eget sapien vitae est sagittis accumsan et nec orci. Integer luctus at nisl eget venenatis. Nunc nunc eros, consectetur at tortor et, tristique ultrices elit. Nulla in turpis nibh.</div><ul><li>Nam consectetur&nbsp;<ul><li>venenatis tempor.&nbsp;</li></ul></li><li>Aenean&nbsp;<ul><li>blandit<ul><li>porttitor massa,&nbsp;<ul><li>non efficitur&nbsp;<ul><li>metus.&nbsp;</li></ul></li></ul></li></ul></li></ul></li><li>Duis faucibus nunc nec venenatis faucibus.&nbsp;</li><li>Aliquam erat volutpat.&nbsp;</li></ul><div><strong>Quisque non neque ut lacus eleifend volutpat quis sed lacus.<br />Praesent ultrices purus eu quam elementum, sit amet faucibus elit interdum. In lectus orci,<br /> elementum quis dictum ac, porta ac ante. Fusce tempus ac mauris id cursus. Phasellus a erat nulla. <em>Mauris dolor orci</em>, malesuada auctor dignissim non, posuere nec odio. Etiam hendrerit justo nec diam ullamcorper, nec blandit elit sodales.</strong></div>
43
43
  HTML
44
44
  end
45
45
  end
@@ -28,6 +28,18 @@ class ProcessorDocumentTest < Sablon::TestCase
28
28
  document
29
29
  end
30
30
 
31
+ def test_simple_field_replacement_with_nil
32
+ result = process(snippet("simple_field"), {"first_name" => nil})
33
+
34
+ assert_equal "Hello! My Name is , nice to meet you.", text(result)
35
+ assert_xml_equal <<-document, result
36
+ <w:p>
37
+ <w:r><w:t xml:space="preserve">Hello! My Name is </w:t></w:r>
38
+ <w:r w:rsidR="00BE47B1"><w:t xml:space="preserve">, nice to meet you.</w:t></w:r>
39
+ </w:p>
40
+ document
41
+ end
42
+
31
43
  def test_context_can_contain_string_and_symbol_keys
32
44
  result = process(snippet("simple_fields"), {"first_name" => "Jack", last_name: "Davis"})
33
45
  assert_equal "Jack Davis", text(result)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sablon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.19.beta3
4
+ version: 0.0.19.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yves Senn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-06 00:00:00.000000000 Z
11
+ date: 2016-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri