sheng 0.3.4 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20f74c4e33aa2c6d02047cba5d9939aae549a4d6
4
- data.tar.gz: 9e5f6b49e52c00e894d799fb9e000d7fb070efad
3
+ metadata.gz: ea5e2737e44d4a27d5d268bdfcefe21e1a3ff51b
4
+ data.tar.gz: 3245c5ef173eb186beaf1fb78acd487bfd42e04e
5
5
  SHA512:
6
- metadata.gz: 98a4c1d780fb682610f7745dee718bad9b9d2ada521e8ac92f62b86e36ade25cc87f125a47fc2e701228d997b06d6d468eceda32e77d08a6554ddb9026f7875c
7
- data.tar.gz: 4540354d8578d52ca6d26a9f4b186ec1eeaa051c74857ec13b189bb642673cf554d88c8f95b88f2c08efd55d8df73783c718e732ab700934b72d5ea07c2a1b33
6
+ metadata.gz: bd6309f22f7c16ddb93dc94d79fe8dbe4cb34c7ec4eb835883fe8afb1127271f8380c70dc79c262ff8da3f7c8d3bb442bd3e6f9b22fcbc3496b17ae4366f532c
7
+ data.tar.gz: 513affc5751aa7de19dc060c13e99974605d9e30afc57ae1711b8666fcd23294493d1c7790e8df6968fba145bd574d520d11a437e9e185ec3c3d1bcce15bc780
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.1.1
1
+ 2.1.
Binary file
@@ -223,6 +223,20 @@ Filters can also be chained, and will be applied in which they appear (from left
223
223
 
224
224
  «a_basic_integer|downcase»
225
225
 
226
+ ## Basic Arithmetic Operations
227
+
228
+ You can perform basic arithmetic operations within a mergefield, using either hardcoded numeric values or variable names. The operators allowed are + (addition), - (subtraction), * (multiplication), and / (division). The usual order of precedence applies with these operators, and you can use parenthesis to control that precedence.
229
+
230
+ ### Examples:
231
+
232
+ «25 * 6»
233
+
234
+ «8.3 + 5.232»
235
+
236
+ «(2.1 + 5) * 18»
237
+
238
+ «(hair.length * 2) + head.height»
239
+
226
240
  # Checkboxes
227
241
 
228
242
  To create a checkbox:
@@ -1,8 +1,14 @@
1
+ require "dentaku"
2
+
1
3
  module Sheng
2
4
  class MergeField
3
- AllowedFilters = [:upcase, :downcase, :capitalize, :titleize, :reverse]
4
- InstructionTextRegex = /^\s*MERGEFIELD(.*)\\\* MERGEFORMAT\s*$/
5
- KeyRegex = /^(start:|end:|if:|end_if:|unless:|end_unless:)?\s*([^\|\s]+)\s*\|?(.*)?/
5
+ MATH_TOKENS = %w[+ - / * ( )]
6
+ REGEXES = {
7
+ instruction_text: /^\s*MERGEFIELD(.*)\\\* MERGEFORMAT\s*$/,
8
+ key_string: /^(?<prefix>start:|end:|if:|end_if:|unless:|end_unless:)?\s*(?<key>[^\|]+)\s*\|?(?<filters>.*)?/,
9
+ numeric_string: /^[-+]?[0-9]*\.?[0-9]+$/
10
+ }
11
+ ALLOWED_FILTERS = [:upcase, :downcase, :capitalize, :titleize, :reverse]
6
12
 
7
13
  class NotAMergeFieldError < StandardError; end
8
14
 
@@ -31,16 +37,16 @@ module Sheng
31
37
  end
32
38
 
33
39
  def key
34
- raw_key.gsub(KeyRegex, '\2')
40
+ raw_key.match(REGEXES[:key_string])[:key].strip
35
41
  end
36
42
 
37
43
  def filters
38
- match = raw_key.match(KeyRegex)
39
- match.captures[2].split("|").map(&:strip)
44
+ match = raw_key.match(REGEXES[:key_string])
45
+ match[:filters].split("|").map(&:strip)
40
46
  end
41
47
 
42
48
  def raw_key
43
- @raw_key ||= mergefield_instruction_text.gsub(InstructionTextRegex, '\1').strip
49
+ @raw_key ||= mergefield_instruction_text.gsub(REGEXES[:instruction_text], '\1').strip
44
50
  end
45
51
 
46
52
  def mergefield_instruction_text
@@ -84,7 +90,7 @@ module Sheng
84
90
 
85
91
  def block_prefix
86
92
  @potential_prefix ||= begin
87
- potential_prefix = raw_key.match(KeyRegex).captures[0]
93
+ potential_prefix = raw_key.match(REGEXES[:key_string])[:prefix]
88
94
  potential_prefix && potential_prefix.gsub(/\:$/, '')
89
95
  end
90
96
  end
@@ -185,10 +191,55 @@ module Sheng
185
191
  xml.remove
186
192
  end
187
193
 
194
+ def key_parts
195
+ @key_parts ||= key.gsub(".", "_DOTSEPARATOR_").
196
+ split(/\b|\s/).
197
+ map(&:strip).
198
+ reject(&:empty?).
199
+ map { |token|
200
+ token.gsub("_DOTSEPARATOR_", ".")
201
+ }
202
+ end
203
+
204
+ def required_variables
205
+ key_parts.reject { |token|
206
+ REGEXES[:numeric_string].match(token) || MATH_TOKENS.include?(token)
207
+ }
208
+ end
209
+
210
+ def required_hash(placeholder: nil)
211
+ required_variables.inject({}) { |assembled, variable|
212
+ parts = variable.split(/\./)
213
+ last_key = parts.pop
214
+ hash = parts.reverse.inject(last_key => placeholder) do |memo, key|
215
+ memo = { key => memo }; memo
216
+ end
217
+ Sheng::Support.merge_required_hashes(assembled, hash)
218
+ }
219
+ end
220
+
221
+ def key_has_math?
222
+ !(MATH_TOKENS & key_parts).empty?
223
+ end
224
+
225
+ def get_value(data_set)
226
+ interpolated_string = key_parts.map { |token|
227
+ if REGEXES[:numeric_string].match(token) || MATH_TOKENS.include?(token)
228
+ token
229
+ else
230
+ data_set.fetch(token)
231
+ end
232
+ }.join(" ")
233
+
234
+ return interpolated_string unless key_has_math?
235
+
236
+ Dentaku::Calculator.new.evaluate!(interpolated_string)
237
+ end
238
+
188
239
  def interpolate(data_set)
189
- value = data_set.fetch(key)
240
+ value = get_value(data_set)
190
241
  replace_mergefield(filter_value(value))
191
- rescue DataSet::KeyNotFound
242
+ rescue DataSet::KeyNotFound, Dentaku::UnboundVariableError
192
243
  # Ignore this error; we'll collect all uninterpolated fields later and
193
244
  # raise a new exception, so we can list all the fields in an error
194
245
  # message.
@@ -197,7 +248,7 @@ module Sheng
197
248
 
198
249
  def filter_value(value)
199
250
  filters.inject(value) { |val, filter|
200
- if AllowedFilters.include?(filter.to_sym) && val.respond_to?(filter.to_sym)
251
+ if ALLOWED_FILTERS.include?(filter.to_sym) && val.respond_to?(filter.to_sym)
201
252
  val.send(filter)
202
253
  else
203
254
  val
@@ -36,6 +36,8 @@ module Sheng
36
36
  nodes.inject({}) do |node_list, node|
37
37
  hsh = if node.is_a?(ConditionalBlock)
38
38
  node.required_hash(placeholder)
39
+ elsif node.is_a?(MergeField)
40
+ node.required_hash(placeholder: placeholder)
39
41
  else
40
42
  value = node.is_a?(Block) ? [node.required_hash(placeholder)].compact : placeholder
41
43
  key_parts = node.key.split(/\./)
data/lib/sheng/support.rb CHANGED
@@ -47,7 +47,7 @@ module Sheng
47
47
  label << label_part.text
48
48
  end
49
49
  end
50
- unless label.match(MergeField::InstructionTextRegex)
50
+ unless label.match(MergeField::REGEXES[:instruction_text])
51
51
  raise MergeField::NotAMergeFieldError.new(label)
52
52
  end
53
53
  label
data/lib/sheng/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sheng
2
- VERSION = "0.3.4"
2
+ VERSION = "0.4.0"
3
3
  end
data/sheng.gemspec CHANGED
@@ -28,4 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency "nokogiri", "~> 1.6"
29
29
  spec.add_dependency "rubyzip", "~> 1.1.1"
30
30
  spec.add_dependency "activesupport", "~> 4.0"
31
+ spec.add_dependency "dentaku", "~> 2.0"
31
32
  end
@@ -10,6 +10,10 @@
10
10
  :key: color
11
11
  - :type: merge_field
12
12
  :key: size
13
+ - :type: merge_field
14
+ :key: dimensions.width * dimensions.height
15
+ - :type: merge_field
16
+ :key: (dimensions.width * 2) + (dimensions.height * 2)
13
17
  - :type: check_box
14
18
  :key: veggies.green.spinach
15
19
  - :type: merge_field
@@ -0,0 +1,14 @@
1
+ <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
2
+ <w:p>
3
+ <w:fldSimple w:instr=" MERGEFIELD baskets.count * (3 + origami) \* MERGEFORMAT ">
4
+ <w:r>
5
+ <w:rPr>
6
+ <w:b/>
7
+ <w:i/>
8
+ <w:noProof/>
9
+ </w:rPr>
10
+ <w:t>«baskets.count * (3 + origami)»</w:t>
11
+ </w:r>
12
+ </w:fldSimple>
13
+ </w:p>
14
+ </w:document>
@@ -54,6 +54,32 @@
54
54
  </w:r>
55
55
  </w:fldSimple>
56
56
  </w:p>
57
+ <w:p>
58
+ <w:r>
59
+ <w:t xml:space="preserve">Sock Area: </w:t>
60
+ </w:r>
61
+ <w:fldSimple w:instr=" MERGEFIELD dimensions.width * dimensions.height \* MERGEFORMAT ">
62
+ <w:r>
63
+ <w:rPr>
64
+ <w:noProof/>
65
+ </w:rPr>
66
+ <w:t>«dimensions.width * dimensions.height»</w:t>
67
+ </w:r>
68
+ </w:fldSimple>
69
+ </w:p>
70
+ <w:p>
71
+ <w:r>
72
+ <w:t xml:space="preserve">Sock Circumference: </w:t>
73
+ </w:r>
74
+ <w:fldSimple w:instr=" MERGEFIELD (dimensions.width * 2) + (dimensions.height * 2) \* MERGEFORMAT ">
75
+ <w:r>
76
+ <w:rPr>
77
+ <w:noProof/>
78
+ </w:rPr>
79
+ <w:t>«(dimensions.width * 2) + (dimensions.height * 2)»</w:t>
80
+ </w:r>
81
+ </w:fldSimple>
82
+ </w:p>
57
83
  <w:p>
58
84
  <w:fldSimple w:instr=" MERGEFIELD end:person.socks \* MERGEFORMAT ">
59
85
  <w:r w:rsidR="00455C8A">
@@ -0,0 +1,12 @@
1
+ <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
2
+ <w:p>
3
+ <w:r>
4
+ <w:rPr>
5
+ <w:b/>
6
+ <w:i/>
7
+ <w:noProof/>
8
+ </w:rPr>
9
+ <w:t>22</w:t>
10
+ </w:r>
11
+ </w:p>
12
+ </w:document>
@@ -36,6 +36,28 @@
36
36
  <w:t>Stumungous</w:t>
37
37
  </w:r>
38
38
  </w:p>
39
+ <w:p>
40
+ <w:r>
41
+ <w:t xml:space="preserve">Sock Area: </w:t>
42
+ </w:r>
43
+ <w:r>
44
+ <w:rPr>
45
+ <w:noProof/>
46
+ </w:rPr>
47
+ <w:t>70</w:t>
48
+ </w:r>
49
+ </w:p>
50
+ <w:p>
51
+ <w:r>
52
+ <w:t xml:space="preserve">Sock Circumference: </w:t>
53
+ </w:r>
54
+ <w:r>
55
+ <w:rPr>
56
+ <w:noProof/>
57
+ </w:rPr>
58
+ <w:t>38</w:t>
59
+ </w:r>
60
+ </w:p>
39
61
  <w:p>
40
62
  <w:r>
41
63
  <w:rPr>
@@ -52,6 +74,28 @@
52
74
  <w:t>Teensy</w:t>
53
75
  </w:r>
54
76
  </w:p>
77
+ <w:p>
78
+ <w:r>
79
+ <w:t xml:space="preserve">Sock Area: </w:t>
80
+ </w:r>
81
+ <w:r>
82
+ <w:rPr>
83
+ <w:noProof/>
84
+ </w:rPr>
85
+ <w:t>364</w:t>
86
+ </w:r>
87
+ </w:p>
88
+ <w:p>
89
+ <w:r>
90
+ <w:t xml:space="preserve">Sock Circumference: </w:t>
91
+ </w:r>
92
+ <w:r>
93
+ <w:rPr>
94
+ <w:noProof/>
95
+ </w:rPr>
96
+ <w:t>82</w:t>
97
+ </w:r>
98
+ </w:p>
55
99
  <w:ffData>
56
100
  <w:name w:val="veggies.green.spinach"/>
57
101
  <w:enabled/>
@@ -28,8 +28,8 @@ describe Sheng::MergeFieldSet do
28
28
  :first_name => 'Brad',
29
29
  :last_name => 'Tucklemoof',
30
30
  :socks => [
31
- { :color => 'Green', :size => 'Stumungous' },
32
- { :color => 'Whitish', :size => 'Teensy' }
31
+ { :color => 'Green', :size => 'Stumungous', :dimensions => { :width => 14, :height => 5 } },
32
+ { :color => 'Whitish', :size => 'Teensy', :dimensions => { :width => 28, :height => 13 } }
33
33
  ]
34
34
  },
35
35
  :veggies => { :green => { :spinach => true } }
@@ -117,15 +117,49 @@ describe Sheng::MergeFieldSet do
117
117
  describe '#required_hash' do
118
118
  it 'returns skeleton hash demonstrating required data for interpolation' do
119
119
  expect(subject.required_hash).to eq({
120
- "person" => { "first_name" => nil, "last_name" => nil, "socks" => [{"color"=>nil, "size"=>nil}] },
121
- "veggies"=> { "green" => { "spinach" => nil } }
120
+ "person" => {
121
+ "first_name" => nil,
122
+ "last_name" => nil,
123
+ "socks" => [
124
+ {
125
+ "color" => nil,
126
+ "size" => nil,
127
+ "dimensions" => {
128
+ "width" => nil,
129
+ "height" => nil
130
+ }
131
+ }
132
+ ]
133
+ },
134
+ "veggies"=> {
135
+ "green" => {
136
+ "spinach" => nil
137
+ }
138
+ }
122
139
  })
123
140
  end
124
141
 
125
142
  it 'uses given value as placeholder for mergefields/checkboxes' do
126
143
  expect(subject.required_hash(:foo)).to eq({
127
- "person" => { "first_name" => :foo, "last_name" => :foo, "socks" => [{"color"=>:foo, "size"=>:foo}] },
128
- "veggies"=> { "green" => { "spinach" => :foo } }
144
+ "person" => {
145
+ "first_name" => :foo,
146
+ "last_name" => :foo,
147
+ "socks" => [
148
+ {
149
+ "color" => :foo,
150
+ "size" => :foo,
151
+ "dimensions" => {
152
+ "width" => :foo,
153
+ "height" => :foo
154
+ }
155
+ }
156
+ ]
157
+ },
158
+ "veggies"=> {
159
+ "green" => {
160
+ "spinach" => :foo
161
+ }
162
+ }
129
163
  })
130
164
  end
131
165
 
@@ -27,6 +27,25 @@ describe Sheng::MergeField do
27
27
  end
28
28
  end
29
29
 
30
+ describe "mergefield with math operations" do
31
+ let(:fragment) { xml_fragment('input/merge_field/math_merge_field') }
32
+ let(:element) { fragment.xpath("//w:fldSimple[contains(@w:instr, 'MERGEFIELD')]").first }
33
+
34
+ describe '#interpolate' do
35
+ it 'interpolates values from dataset into mergefield' do
36
+ dataset = Sheng::DataSet.new({
37
+ :baskets => {
38
+ :count => 2
39
+ },
40
+ :origami => 8
41
+ })
42
+
43
+ subject.interpolate(dataset)
44
+ expect(subject.xml_document).to be_equivalent_to xml_fragment('output/merge_field/math_merge_field')
45
+ end
46
+ end
47
+ end
48
+
30
49
  describe "new style merge field" do
31
50
  let(:fragment) { xml_fragment('input/merge_field/new_merge_field') }
32
51
  let(:element) { fragment.xpath("//w:fldChar[contains(@w:fldCharType, 'begin')]").first }
@@ -124,16 +143,70 @@ describe Sheng::MergeField do
124
143
  end
125
144
  end
126
145
 
127
- describe '#interpolate' do
128
- it 'interpolates filtered values from dataset into mergefield' do
129
- dataset = Sheng::DataSet.new({
130
- :ocean => { :fishy => "scrumblefish" }
146
+ describe "#get_value" do
147
+ let(:dataset) {
148
+ Sheng::DataSet.new({
149
+ :ocean => { :fishy => "scrumblefish" },
150
+ :numbers => { :first => 23, :second => 8 }
131
151
  })
152
+ }
153
+
154
+ it "returns value from dataset when given simple lookup" do
155
+ allow(subject).to receive(:key).and_return("ocean.fishy")
156
+ expect(subject.get_value(dataset)).to eq("scrumblefish")
157
+ end
158
+
159
+ it "performs math operations on values from dataset" do
160
+ allow(subject).to receive(:key).and_return("(numbers.first * numbers.second) + 5")
161
+ expect(subject.get_value(dataset)).to eq(189)
162
+ end
163
+
164
+ it "performs math operations with no dataset lookup" do
165
+ allow(subject).to receive(:key).and_return("2 + (3*5)")
166
+ expect(subject.get_value(dataset)).to eq(17)
167
+ end
168
+
169
+ it "raises exception if key not found in simple lookup" do
170
+ allow(subject).to receive(:key).and_return("oliver.twist")
171
+ expect {
172
+ subject.get_value(dataset)
173
+ }.to raise_error(Sheng::DataSet::KeyNotFound)
174
+ end
175
+
176
+ it "raises exception if key not found in math formula" do
177
+ allow(subject).to receive(:key).and_return("oliver.twist * 15")
178
+ expect {
179
+ subject.get_value(dataset)
180
+ }.to raise_error(Sheng::DataSet::KeyNotFound)
181
+ end
182
+
183
+ it "raises exception if interpolated math formula includes invalid symbols" do
184
+ allow(subject).to receive(:key).and_return("ocean.fishy * 15")
185
+ expect {
186
+ subject.get_value(dataset)
187
+ }.to raise_error(Dentaku::UnboundVariableError)
188
+ end
189
+ end
132
190
 
191
+ describe '#interpolate' do
192
+ it 'interpolates filtered values from dataset into mergefield' do
193
+ allow(subject).to receive(:get_value).with(:a_dataset).and_return("scrumblefish")
133
194
  allow(subject).to receive(:filter_value).with("scrumblefish").and_return("l33tphish")
134
- subject.interpolate(dataset)
195
+ subject.interpolate(:a_dataset)
135
196
  expect(subject.xml_document).to be_equivalent_to xml_fragment('output/merge_field/merge_field')
136
197
  end
198
+
199
+ it "does not replace and returns nil if any keys not found" do
200
+ allow(subject).to receive(:get_value).with(:a_dataset).and_raise(Sheng::DataSet::KeyNotFound)
201
+ expect(subject).to receive(:replace_mergefield).never
202
+ expect(subject.interpolate(:a_dataset)).to be_nil
203
+ end
204
+
205
+ it "does not replace and returns nil if calculation error encountered" do
206
+ allow(subject).to receive(:get_value).with(:a_dataset).and_raise(Dentaku::UnboundVariableError.new([]))
207
+ expect(subject).to receive(:replace_mergefield).never
208
+ expect(subject.interpolate(:a_dataset)).to be_nil
209
+ end
137
210
  end
138
211
 
139
212
  describe "#xml" do
@@ -148,6 +221,20 @@ describe Sheng::MergeField do
148
221
  end
149
222
  end
150
223
 
224
+ describe "#required_variables" do
225
+ it "returns key parts that are not operators or numeric" do
226
+ allow(subject).to receive(:key).and_return("cat.toes * 15 + (yawns / 2.0)")
227
+ expect(subject.required_variables).to eq(["cat.toes", "yawns"])
228
+ end
229
+ end
230
+
231
+ describe "#key_parts" do
232
+ it "returns key split on all word boundaries except dot separators" do
233
+ allow(subject).to receive(:key).and_return("cat.toes * 15 + (yawns / 2.0)")
234
+ expect(subject.key_parts).to eq(["cat.toes", "*", "15", "+", "(", "yawns", "/", "2.0", ")"])
235
+ end
236
+ end
237
+
151
238
  describe '#key' do
152
239
  it 'returns the raw key with start/end metadata stripped off' do
153
240
  allow(subject).to receive(:raw_key).and_return('start:whipple.dooter')
@@ -160,6 +247,11 @@ describe Sheng::MergeField do
160
247
  allow(subject).to receive(:raw_key).and_return("whumpies | cook | dress(frock)")
161
248
  expect(subject.key).to eq 'whumpies'
162
249
  end
250
+
251
+ it 'returns key even if it contains math operations' do
252
+ allow(subject).to receive(:raw_key).and_return("whumpies * 3 | cook | dress(frock)")
253
+ expect(subject.key).to eq 'whumpies * 3'
254
+ end
163
255
  end
164
256
 
165
257
  describe "#filters" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sheng
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ravi Gadad
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-05-21 00:00:00.000000000 Z
12
+ date: 2016-01-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -137,6 +137,20 @@ dependencies:
137
137
  - - "~>"
138
138
  - !ruby/object:Gem::Version
139
139
  version: '4.0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: dentaku
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - "~>"
145
+ - !ruby/object:Gem::Version
146
+ version: '2.0'
147
+ type: :runtime
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '2.0'
140
154
  description: A Ruby gem for data merging Word documents.
141
155
  email:
142
156
  - ravi@renewfund.com
@@ -194,6 +208,7 @@ files:
194
208
  - spec/fixtures/xml_fragments/input/merge_field/bad/not_a_real_mergefield_old.xml
195
209
  - spec/fixtures/xml_fragments/input/merge_field/bad/unclosed_merge_field.xml
196
210
  - spec/fixtures/xml_fragments/input/merge_field/inline_merge_field.xml
211
+ - spec/fixtures/xml_fragments/input/merge_field/math_merge_field.xml
197
212
  - spec/fixtures/xml_fragments/input/merge_field/merge_field.xml
198
213
  - spec/fixtures/xml_fragments/input/merge_field/new_merge_field.xml
199
214
  - spec/fixtures/xml_fragments/input/merge_field/split_merge_field.xml
@@ -224,6 +239,7 @@ files:
224
239
  - spec/fixtures/xml_fragments/output/conditional_block/unless_does_not_exist.xml
225
240
  - spec/fixtures/xml_fragments/output/conditional_block/unless_exists.xml
226
241
  - spec/fixtures/xml_fragments/output/merge_field/inline_merge_field.xml
242
+ - spec/fixtures/xml_fragments/output/merge_field/math_merge_field.xml
227
243
  - spec/fixtures/xml_fragments/output/merge_field/merge_field.xml
228
244
  - spec/fixtures/xml_fragments/output/merge_field/split_merge_field.xml
229
245
  - spec/fixtures/xml_fragments/output/merge_field_set/complex_nesting_and_reuse.xml
@@ -270,7 +286,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
270
286
  version: '0'
271
287
  requirements: []
272
288
  rubyforge_project:
273
- rubygems_version: 2.2.2
289
+ rubygems_version: 2.2.5
274
290
  signing_key:
275
291
  specification_version: 4
276
292
  summary: A Ruby gem for data merging Word documents, using native MergeFields as placeholders
@@ -301,6 +317,7 @@ test_files:
301
317
  - spec/fixtures/xml_fragments/input/merge_field/bad/not_a_real_mergefield_old.xml
302
318
  - spec/fixtures/xml_fragments/input/merge_field/bad/unclosed_merge_field.xml
303
319
  - spec/fixtures/xml_fragments/input/merge_field/inline_merge_field.xml
320
+ - spec/fixtures/xml_fragments/input/merge_field/math_merge_field.xml
304
321
  - spec/fixtures/xml_fragments/input/merge_field/merge_field.xml
305
322
  - spec/fixtures/xml_fragments/input/merge_field/new_merge_field.xml
306
323
  - spec/fixtures/xml_fragments/input/merge_field/split_merge_field.xml
@@ -331,6 +348,7 @@ test_files:
331
348
  - spec/fixtures/xml_fragments/output/conditional_block/unless_does_not_exist.xml
332
349
  - spec/fixtures/xml_fragments/output/conditional_block/unless_exists.xml
333
350
  - spec/fixtures/xml_fragments/output/merge_field/inline_merge_field.xml
351
+ - spec/fixtures/xml_fragments/output/merge_field/math_merge_field.xml
334
352
  - spec/fixtures/xml_fragments/output/merge_field/merge_field.xml
335
353
  - spec/fixtures/xml_fragments/output/merge_field/split_merge_field.xml
336
354
  - spec/fixtures/xml_fragments/output/merge_field_set/complex_nesting_and_reuse.xml