lm_docstache 2.1.0 → 3.0.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 +4 -4
- data/CHANGELOG.md +35 -0
- data/lib/lm_docstache/hide_custom_tags.rb +31 -15
- data/lib/lm_docstache/parser.rb +19 -14
- data/lib/lm_docstache/renderer.rb +2 -1
- data/lib/lm_docstache/version.rb +1 -1
- data/spec/example_input/docx-no-rpr.docx +0 -0
- data/spec/example_input/sample-signature-blue.docx +0 -0
- data/spec/example_input/sample-signature-with-tabs-spacing.docx +0 -0
- data/spec/hide_custom_tags_spec.rb +75 -13
- data/spec/integration_spec.rb +37 -9
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8db9e1f7f1a534059ed080bfd89005372b334cc203b66cfbb45323b8116b980
|
4
|
+
data.tar.gz: 4af011e633d34a62fcc0ed24fa639e04ce88937423b8570ae4f3a8fd4ff8fe70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3c0630c4472b5d5b8f2a479a7b201411a817069221026778f86581146f4ef797dd586d2a0b299df4281394edf7878f1536ceda0d59f766a737255960a07d450
|
7
|
+
data.tar.gz: df59e4c7c9750e75f976d47ee6d8d632c795702863cdb332627497f88026efa70a2eac2b01520c615a8faf042f677e547d3fec8ae09dc470d50383e1e5ed5548
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,40 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 3.0.2
|
4
|
+
|
5
|
+
### Bugfix
|
6
|
+
|
7
|
+
* Fix replacing tags related to hidden custom tags regexp formats. E.g. tab characters.
|
8
|
+
|
9
|
+
|
10
|
+
## 3.0.1
|
11
|
+
|
12
|
+
### Bugfix
|
13
|
+
|
14
|
+
* Fix Hide Custom Tag feature when document there is no text inside a w|r we
|
15
|
+
can't split content.
|
16
|
+
|
17
|
+
## 3.0.0
|
18
|
+
|
19
|
+
## Breaking Changes
|
20
|
+
* Replaced Renderer `hide_custom_tags` options to be a `Hash` instead of `Array`.
|
21
|
+
There are are edge cases which we want to replace the content on hide custom tags.
|
22
|
+
All documentations can be followed on `Renderer` and `HideCustomTag` classes.
|
23
|
+
|
24
|
+
## 2.1.2
|
25
|
+
|
26
|
+
### Bugfix
|
27
|
+
|
28
|
+
* Giving a document there is no *rPr* tag we should add new *rPr* tag before
|
29
|
+
*t* tag.
|
30
|
+
|
31
|
+
## 2.1.1
|
32
|
+
|
33
|
+
### Improvements
|
34
|
+
|
35
|
+
* Hidden custom tags now follow your document background color. If there is no background defined
|
36
|
+
we assume white font color.
|
37
|
+
|
3
38
|
## 2.1.0
|
4
39
|
|
5
40
|
#### Improvements
|
@@ -1,41 +1,52 @@
|
|
1
1
|
module LMDocstache
|
2
2
|
class HideCustomTags
|
3
|
-
HIDDEN_FONT_COLOR = 'FFFFFF'
|
4
|
-
|
5
3
|
attr_reader :document, :hide_custom_tags
|
6
4
|
|
7
|
-
# The +hide_custom_tags+ options is
|
8
|
-
# the pattern you expect to keep at the document but
|
5
|
+
# The +hide_custom_tags+ options is a +Hash+ of +Regexp+ or +String+ keys representing
|
6
|
+
# the pattern you expect to keep at the document but replacing the content to use
|
7
|
+
# font color equal to document background color or white.
|
8
|
+
# For the +Hash+ values we can have:
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
|
10
|
+
# * +false+ -> In this case we don't change the text content.
|
11
|
+
# * +Proc+ -> When a +Proc+ instance is provided, it's expected it to be
|
12
|
+
# able to receive the matched string and to return the string that will be
|
13
|
+
# used as replacement.
|
14
|
+
# * any other value that will be turned into a string -> in this case, this
|
15
|
+
# will be the value that will replace the matched string
|
16
|
+
def initialize(document:, hide_custom_tags: {})
|
14
17
|
@document = document
|
15
18
|
@hide_custom_tags = hide_custom_tags
|
16
19
|
end
|
17
20
|
|
18
21
|
# Find all run nodes matching hide custom tags +Regexp's+ options you defined, split it
|
19
|
-
# in multiple runs and replace font color to white in the matching tag run node.
|
22
|
+
# in multiple runs and replace font color to document background color or white in the matching tag run node.
|
23
|
+
# Replace content if you have defined any replacement value.
|
20
24
|
def hide_custom_tags!
|
21
|
-
hide_custom_tags.each do |full_pattern|
|
25
|
+
hide_custom_tags.each do |full_pattern, value|
|
22
26
|
paragraphs = document.css('w|p')
|
23
27
|
while paragraph = paragraphs.shift do
|
24
28
|
next unless paragraph.text =~ full_pattern
|
25
29
|
run_nodes = paragraph.css('w|r')
|
26
30
|
while run_node = run_nodes.shift
|
27
|
-
next
|
31
|
+
next unless run_node.at_css('w|t')
|
32
|
+
next unless run_node.text =~ full_pattern
|
28
33
|
remainder_run_node = run_node.clone
|
29
34
|
run_node.unlink
|
30
35
|
tag_contents = split_tag_content(remainder_run_node.text, full_pattern)
|
31
36
|
tag_contents[:content_list].each_with_index do |content, idx|
|
32
37
|
replace_content(remainder_run_node, content)
|
33
|
-
run_node_with_match = remainder_run_node.dup
|
34
38
|
matched_tag = tag_contents[:matched_tags][idx]
|
35
39
|
nodes_list = [remainder_run_node]
|
36
40
|
if matched_tag
|
41
|
+
run_node_with_match = remainder_run_node.dup
|
37
42
|
replace_style(run_node_with_match)
|
38
|
-
|
43
|
+
matched_content = matched_tag
|
44
|
+
if value
|
45
|
+
matched_content = value.is_a?(Proc) ?
|
46
|
+
value.call(matched_tag) :
|
47
|
+
value.to_s
|
48
|
+
end
|
49
|
+
replace_content(run_node_with_match, matched_content)
|
39
50
|
nodes_list << run_node_with_match
|
40
51
|
end
|
41
52
|
paragraph << Nokogiri::XML::NodeSet.new(document, nodes_list)
|
@@ -47,6 +58,11 @@ module LMDocstache
|
|
47
58
|
end
|
48
59
|
|
49
60
|
private
|
61
|
+
|
62
|
+
def font_color
|
63
|
+
@font_color ||= document.at_css('w|background')&.attr('w:color') || 'FFFFFF'
|
64
|
+
end
|
65
|
+
|
50
66
|
def split_tag_content(text, full_pattern)
|
51
67
|
content_list = text.split(full_pattern)
|
52
68
|
content_list = content_list.empty? ? [''] : content_list
|
@@ -59,9 +75,9 @@ module LMDocstache
|
|
59
75
|
if style
|
60
76
|
w_color = style.at_css('w|color')
|
61
77
|
w_color.unlink if w_color
|
62
|
-
style << "<w:color w:val=\"#{
|
78
|
+
style << "<w:color w:val=\"#{font_color}\"/>"
|
63
79
|
else
|
64
|
-
run_node
|
80
|
+
run_node.prepend_child("<w:rPr><w:color w:val=\"#{font_color}\"/></w:rPr>")
|
65
81
|
end
|
66
82
|
end
|
67
83
|
|
data/lib/lm_docstache/parser.rb
CHANGED
@@ -34,22 +34,30 @@ module LMDocstache
|
|
34
34
|
# * any other value that will be turned into a string -> in this case, this
|
35
35
|
# will be the value that will replace the matched string
|
36
36
|
#
|
37
|
-
# The +hide_custom_tags+ options is
|
38
|
-
# the pattern you expect to keep at the document but
|
37
|
+
# The +hide_custom_tags+ options is a +Hash+ of +Regexp+ or +String+ keys representing
|
38
|
+
# the pattern you expect to keep at the document but replacing the content to use
|
39
|
+
# font color equal to document background color or white.
|
40
|
+
# For the +Hash+ values we can have:
|
39
41
|
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
42
|
+
# * +false+ -> In this case we don't change the text content.
|
43
|
+
# * +Proc+ -> When a +Proc+ instance is provided, it's expected it to be
|
44
|
+
# able to receive the matched string and to return the string that will be
|
45
|
+
# used as replacement.
|
46
|
+
# * any other value that will be turned into a string -> in this case, this
|
47
|
+
# will be the value that will replace the matched string
|
43
48
|
def initialize(document, data, options = {})
|
44
49
|
@document = document
|
45
50
|
@data = data.transform_keys(&:to_s)
|
46
|
-
@special_variable_replacements = options.fetch(:special_variable_replacements, {})
|
47
|
-
@hide_custom_tags =
|
51
|
+
@special_variable_replacements = add_blocks_to_regexp(options.fetch(:special_variable_replacements, {}))
|
52
|
+
@hide_custom_tags = add_blocks_to_regexp(options.fetch(:hide_custom_tags, {}))
|
48
53
|
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
# Replace +Regepx+ or +String+ keys to have the enclosing blocks
|
56
|
+
def add_blocks_to_regexp(options)
|
57
|
+
options.inject({}) do |x, (regexp_str, value)|
|
58
|
+
key = regexp_str.is_a?(String) ? Regexp.new("{{#{regexp_str}}}") : /{{#{regexp_str.source}}/
|
59
|
+
x[key] = value
|
60
|
+
x
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
@@ -128,15 +136,13 @@ module LMDocstache
|
|
128
136
|
variable_replacement.call($1) :
|
129
137
|
variable_replacement.to_s
|
130
138
|
end
|
131
|
-
|
132
139
|
text_node.content = text
|
133
140
|
end
|
134
141
|
end
|
135
142
|
|
136
143
|
def has_skippable_variable?(text)
|
137
|
-
return true if hide_custom_tags.find { |pattern| text =~ pattern }
|
144
|
+
return true if hide_custom_tags.find { |(pattern, value)| text =~ pattern }
|
138
145
|
!!special_variable_replacements.find do |(pattern, value)|
|
139
|
-
pattern = pattern.is_a?(String) ? /{{#{pattern}}}/ : /{{#{pattern.source}}}/
|
140
146
|
text =~ pattern && value == false
|
141
147
|
end
|
142
148
|
end
|
@@ -144,7 +150,6 @@ module LMDocstache
|
|
144
150
|
def special_variable_replacement(text)
|
145
151
|
Array(
|
146
152
|
special_variable_replacements.find do |(pattern, value)|
|
147
|
-
pattern = pattern.is_a?(String) ? /{{#{pattern}}}/ : /{{#{pattern.source}}}/
|
148
153
|
text =~ pattern && !!value
|
149
154
|
end
|
150
155
|
).last
|
@@ -6,7 +6,8 @@ module LMDocstache
|
|
6
6
|
|
7
7
|
def initialize(xml, data, options = {})
|
8
8
|
@content = xml
|
9
|
-
|
9
|
+
option_types = [:special_variable_replacements, :hide_custom_tags]
|
10
|
+
@parser = Parser.new(xml, data, options.slice(*option_types))
|
10
11
|
end
|
11
12
|
|
12
13
|
def render
|
data/lib/lm_docstache/version.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe LMDocstache::HideCustomTags do
|
4
|
-
|
5
4
|
context '#example' do
|
6
5
|
let(:output_dir) { "#{base_path}/tmp/" }
|
7
6
|
let(:output_file) { File.new("#{output_dir}/BlankTestOutput.docx", 'w') }
|
7
|
+
|
8
8
|
before do
|
9
9
|
FileUtils.rm_rf(output_dir) if File.exist?(output_dir)
|
10
10
|
Dir.mkdir(output_dir)
|
@@ -15,22 +15,84 @@ describe LMDocstache::HideCustomTags do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
let(:base_path) { SPEC_BASE_PATH.join('example_input') }
|
18
|
-
let(:
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
let(:document) {
|
19
|
+
doc = LMDocstache::Document.new(input_file)
|
20
|
+
doc.fix_errors
|
21
|
+
doc.instance_variable_get(:@document)
|
22
|
+
}
|
23
|
+
let(:regexp_tag) { /(?:sig|sigfirm|date|text|initial)\|(?:req|noreq)\|.+?/ }
|
24
|
+
let(:regexp_for_replacement) { /(?:check)\|(?:req|noreq)\|.+?/ }
|
22
25
|
let(:hide_custom_tags) {
|
23
|
-
LMDocstache::HideCustomTags.new(document: document, hide_custom_tags:
|
26
|
+
LMDocstache::HideCustomTags.new(document: document, hide_custom_tags: {
|
27
|
+
/#{regexp_tag}/ => false,
|
28
|
+
/#{regexp_for_replacement}/ => 'replaced_content'
|
29
|
+
})
|
24
30
|
}
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
|
32
|
+
context "giving a document with blue background" do
|
33
|
+
let(:input_file) { "#{base_path}/sample-signature-blue.docx" }
|
34
|
+
|
35
|
+
it 'expect to have a white color on all hide custom tags matching and have first child node equal rPr tag' do
|
36
|
+
hide_custom_tags.hide_custom_tags!
|
37
|
+
d = hide_custom_tags.document
|
38
|
+
run_nodes = d.css('w|p w|r')
|
39
|
+
while run_node = run_nodes.shift
|
40
|
+
next unless run_node.text =~ regexp_tag
|
41
|
+
expect(run_node.at_css('w|rPr w|color').first[1]).to eq('4472C4')
|
42
|
+
expect(run_node.children.first.name).to eq('rPr')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'giving a document with white background' do
|
48
|
+
let(:input_file) { "#{base_path}/sample-signature.docx" }
|
49
|
+
|
50
|
+
it 'expect to have a white color on all hide custom tags matching and have first child node equal rPr tag' do
|
51
|
+
hide_custom_tags.hide_custom_tags!
|
52
|
+
d = hide_custom_tags.document
|
53
|
+
run_nodes = d.css('w|p w|r')
|
54
|
+
while run_node = run_nodes.shift
|
55
|
+
next unless run_node.text =~ regexp_tag
|
56
|
+
expect(run_node.at_css('w|rPr w|color').first[1]).to eq('FFFFFF')
|
57
|
+
expect(run_node.children.first.name).to eq('rPr')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
context 'giving a document without rpr and block tags on the left' do
|
62
|
+
let(:input_file) { "#{base_path}/docx-no-rpr.docx" }
|
63
|
+
|
64
|
+
it 'expect to have a white color on all hide custom tags matching and have first child node equal rPr tag' do
|
65
|
+
hide_custom_tags.hide_custom_tags!
|
66
|
+
d = hide_custom_tags.document
|
67
|
+
run_nodes = d.css('w|p w|r')
|
68
|
+
while run_node = run_nodes.shift
|
69
|
+
next unless run_node.text =~ regexp_tag
|
70
|
+
expect(run_node.at_css('w|rPr w|color').first[1]).to eq('FFFFFF')
|
71
|
+
expect(run_node.children.first.name).to eq('rPr')
|
32
72
|
end
|
33
73
|
end
|
74
|
+
it 'expect to have a white color on all replacement tags and content following replacement' do
|
75
|
+
hide_custom_tags.hide_custom_tags!
|
76
|
+
d = hide_custom_tags.document
|
77
|
+
run_nodes = d.css('w|p w|r')
|
78
|
+
total_replacement = 0
|
79
|
+
while run_node = run_nodes.shift
|
80
|
+
next unless run_node.text =~ /replaced_content/
|
81
|
+
total_replacement+=1
|
82
|
+
expect(run_node.at_css('w|rPr w|color').first[1]).to eq('FFFFFF')
|
83
|
+
expect(run_node.children.first.name).to eq('rPr')
|
84
|
+
end
|
85
|
+
expect(total_replacement).to eq(2)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'giving a document with tabs spacing in the middle of replacement tags' do
|
90
|
+
let(:input_file) { "#{base_path}/sample-signature-with-tabs-spacing.docx" }
|
91
|
+
it 'expect to not replace tabs' do
|
92
|
+
hide_custom_tags.hide_custom_tags!
|
93
|
+
d = hide_custom_tags.document
|
94
|
+
expect(d.css('w|p w|tab').size).to eq(11)
|
95
|
+
end
|
34
96
|
end
|
35
97
|
end
|
36
98
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -35,15 +35,18 @@ end
|
|
35
35
|
describe 'integration test', integration: true do
|
36
36
|
let(:base_path) { SPEC_BASE_PATH.join('example_input') }
|
37
37
|
let(:output_dir) { "#{base_path}/tmp" }
|
38
|
+
|
38
39
|
context 'should process that incoming docx' do
|
39
40
|
let(:data) { LMDocstache::TestData::DATA }
|
40
41
|
let(:input_file) { "#{base_path}/ExampleTemplate.docx" }
|
41
42
|
let(:output_file) { "#{output_dir}/IntegrationTestOutput.docx" }
|
42
43
|
let(:document) { LMDocstache::Document.new(input_file) }
|
44
|
+
|
43
45
|
before do
|
44
46
|
FileUtils.rm_rf(output_dir) if File.exist?(output_dir)
|
45
47
|
Dir.mkdir(output_dir)
|
46
48
|
end
|
49
|
+
|
47
50
|
it 'loads the input file' do
|
48
51
|
expect(document).to_not be_nil
|
49
52
|
end
|
@@ -89,19 +92,43 @@ describe 'integration test', integration: true do
|
|
89
92
|
Dir.mkdir(output_dir)
|
90
93
|
end
|
91
94
|
|
92
|
-
let(:input_file) { "#{base_path}/sample-signature.docx" }
|
93
95
|
let(:render_options) {
|
94
96
|
{
|
95
|
-
hide_custom_tags: ['(?:sig|sigfirm|date|check|text|initial)\|(?:req|noreq)
|
97
|
+
hide_custom_tags: ['(?:sig|sigfirm|date|check|text|initial)\|(?:req|noreq)\|.+?']
|
96
98
|
}
|
97
99
|
}
|
98
100
|
let(:document) { LMDocstache::Document.new(input_file) }
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
101
|
+
|
102
|
+
context "witth document with blue background" do
|
103
|
+
let(:input_file) { "#{base_path}/sample-signature-blue.docx" }
|
104
|
+
|
105
|
+
it 'should have content replacement aligned with hide custom tags' do
|
106
|
+
doc = document
|
107
|
+
doc.fix_errors
|
108
|
+
noko = doc.render_xml({}, render_options)
|
109
|
+
output = noko['word/document.xml'].to_xml
|
110
|
+
expect(output).to include('<w:r>
|
111
|
+
<w:rPr>
|
112
|
+
<w:rFonts w:cstheme="minorHAnsi"/>
|
113
|
+
<w:lang w:val="en-US"/>
|
114
|
+
<w:color w:val="4472C4"/>
|
115
|
+
</w:rPr>
|
116
|
+
<w:t xml:space="preserve">{{sig|req|client}}</w:t>
|
117
|
+
</w:r>')
|
118
|
+
expect(output).to include('<w:t xml:space="preserve">Test Multiple text in the same line </w:t>')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "with document without backgorund" do
|
123
|
+
let(:input_file) { "#{base_path}/sample-signature.docx" }
|
124
|
+
let(:document) { LMDocstache::Document.new(input_file) }
|
125
|
+
|
126
|
+
it 'should have content replacement aligned with hide custom tags' do
|
127
|
+
doc = document
|
128
|
+
doc.fix_errors
|
129
|
+
noko = doc.render_xml({}, render_options)
|
130
|
+
output = noko['word/document.xml'].to_xml
|
131
|
+
expect(output).to include('<w:r>
|
105
132
|
<w:rPr>
|
106
133
|
<w:rFonts w:cstheme="minorHAnsi"/>
|
107
134
|
<w:lang w:val="en-US"/>
|
@@ -109,7 +136,8 @@ describe 'integration test', integration: true do
|
|
109
136
|
</w:rPr>
|
110
137
|
<w:t xml:space="preserve">{{sig|req|client}}</w:t>
|
111
138
|
</w:r>')
|
112
|
-
|
139
|
+
expect(output).to include('<w:t xml:space="preserve">Test Multiple text in the same line </w:t>')
|
140
|
+
end
|
113
141
|
end
|
114
142
|
end
|
115
143
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lm_docstache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roey Chasman
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2021-
|
15
|
+
date: 2021-04-08 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: nokogiri
|
@@ -121,6 +121,9 @@ files:
|
|
121
121
|
- spec/conditional_block_spec.rb
|
122
122
|
- spec/example_input/ExampleTemplate.docx
|
123
123
|
- spec/example_input/blank.docx
|
124
|
+
- spec/example_input/docx-no-rpr.docx
|
125
|
+
- spec/example_input/sample-signature-blue.docx
|
126
|
+
- spec/example_input/sample-signature-with-tabs-spacing.docx
|
124
127
|
- spec/example_input/sample-signature.docx
|
125
128
|
- spec/hide_custom_tags_spec.rb
|
126
129
|
- spec/integration_spec.rb
|
@@ -153,6 +156,9 @@ test_files:
|
|
153
156
|
- spec/conditional_block_spec.rb
|
154
157
|
- spec/example_input/ExampleTemplate.docx
|
155
158
|
- spec/example_input/blank.docx
|
159
|
+
- spec/example_input/docx-no-rpr.docx
|
160
|
+
- spec/example_input/sample-signature-blue.docx
|
161
|
+
- spec/example_input/sample-signature-with-tabs-spacing.docx
|
156
162
|
- spec/example_input/sample-signature.docx
|
157
163
|
- spec/hide_custom_tags_spec.rb
|
158
164
|
- spec/integration_spec.rb
|