caracal 1.0.9 → 1.0.10

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.
@@ -1,15 +1,18 @@
1
1
  require 'open-uri'
2
2
  require 'zip'
3
3
 
4
+ require 'caracal/core/custom_properties'
4
5
  require 'caracal/core/file_name'
5
6
  require 'caracal/core/fonts'
7
+ require 'caracal/core/iframes'
8
+ require 'caracal/core/ignorables'
6
9
  require 'caracal/core/images'
7
10
  require 'caracal/core/list_styles'
8
11
  require 'caracal/core/lists'
12
+ require 'caracal/core/namespaces'
9
13
  require 'caracal/core/page_breaks'
10
14
  require 'caracal/core/page_numbers'
11
15
  require 'caracal/core/page_settings'
12
- require 'caracal/core/custom_properties'
13
16
  require 'caracal/core/relationships'
14
17
  require 'caracal/core/rules'
15
18
  require 'caracal/core/styles'
@@ -38,16 +41,19 @@ module Caracal
38
41
  #-------------------------------------------------------------
39
42
 
40
43
  # mixins (order is important)
41
- include Caracal::Core::FileName
42
44
  include Caracal::Core::CustomProperties
43
-
45
+ include Caracal::Core::FileName
46
+ include Caracal::Core::Ignorables
47
+ include Caracal::Core::Namespaces
44
48
  include Caracal::Core::Relationships
49
+
45
50
  include Caracal::Core::Fonts
46
51
  include Caracal::Core::PageSettings
47
52
  include Caracal::Core::PageNumbers
48
53
  include Caracal::Core::Styles
49
54
  include Caracal::Core::ListStyles
50
55
 
56
+ include Caracal::Core::IFrames
51
57
  include Caracal::Core::Images
52
58
  include Caracal::Core::Lists
53
59
  include Caracal::Core::PageBreaks
@@ -98,7 +104,7 @@ module Caracal
98
104
  page_margins top: 1440, bottom: 1440, left: 1440, right: 1440
99
105
  page_numbers
100
106
 
101
- [:relationship, :font, :style, :list_style].each do |method|
107
+ [:font, :list_style, :namespace, :relationship, :style].each do |method|
102
108
  collection = self.class.send("default_#{ method }s")
103
109
  collection.each do |item|
104
110
  send(method, item)
@@ -97,6 +97,40 @@ module Caracal
97
97
 
98
98
  #============= MODEL RENDERERS ===========================
99
99
 
100
+ def render_iframe(xml, model)
101
+ ::Zip::File.open(model.file) do |zip|
102
+ a_href = 'http://schemas.openxmlformats.org/drawingml/2006/main'
103
+ pic_href = 'http://schemas.openxmlformats.org/drawingml/2006/picture'
104
+ r_href = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
105
+
106
+ entry = zip.glob('word/document.xml').first
107
+ content = entry.get_input_stream.read
108
+ doc_xml = Nokogiri::XML(content)
109
+
110
+ fragment = doc_xml.xpath('//w:body').first.children
111
+ fragment.pop
112
+
113
+ model.relationships.each do |r_hash|
114
+ id = r_hash.delete(:id) # we can't update the fragment until
115
+ model = document.relationship(r_hash) # the parent document assigns the embedded
116
+ index = model.relationship_id # relationship an id.
117
+
118
+ r_node = fragment.at_xpath("//a:blip[@r:embed='#{ id }']", { a: a_href, r: r_href })
119
+ if r_attr = r_node.attributes['embed']
120
+ r_attr.value = "rId#{ index }"
121
+ end
122
+
123
+ p_parent = r_node.parent.parent
124
+ p_node = p_parent.children[0].children[0]
125
+ if p_attr = p_node.attributes['id']
126
+ p_attr.value = index.to_s
127
+ end
128
+ end
129
+
130
+ xml << fragment.to_s
131
+ end
132
+ end
133
+
100
134
  def render_image(xml, model)
101
135
  unless ds = document.default_style
102
136
  raise Caracal::Errors::NoDefaultStyleError 'Document must declare a default paragraph style.'
@@ -327,23 +361,32 @@ module Caracal
327
361
  #============= OPTIONS ===================================
328
362
 
329
363
  def root_options
330
- {
331
- 'xmlns:mc' => 'http://schemas.openxmlformats.org/markup-compatibility/2006',
332
- 'xmlns:o' => 'urn:schemas-microsoft-com:office:office',
333
- 'xmlns:r' => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
334
- 'xmlns:m' => 'http://schemas.openxmlformats.org/officeDocument/2006/math',
335
- 'xmlns:v' => 'urn:schemas-microsoft-com:vml',
336
- 'xmlns:wp' => 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
337
- 'xmlns:w10' => 'urn:schemas-microsoft-com:office:word',
338
- 'xmlns:w' => 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
339
- 'xmlns:wne' => 'http://schemas.microsoft.com/office/word/2006/wordml',
340
- 'xmlns:sl' => 'http://schemas.openxmlformats.org/schemaLibrary/2006/main',
341
- 'xmlns:a' => 'http://schemas.openxmlformats.org/drawingml/2006/main',
342
- 'xmlns:pic' => 'http://schemas.openxmlformats.org/drawingml/2006/picture',
343
- 'xmlns:c' => 'http://schemas.openxmlformats.org/drawingml/2006/chart',
344
- 'xmlns:lc' => 'http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas',
345
- 'xmlns:dgm' => 'http://schemas.openxmlformats.org/drawingml/2006/diagram'
346
- }
364
+ opts = {}
365
+ document.namespaces.each do |model|
366
+ opts[model.namespace_prefix] = model.namespace_href
367
+ end
368
+ unless document.ignorables.empty?
369
+ v = document.ignorables.join(' ')
370
+ opts['mc:Ignorable'] = v
371
+ end
372
+ opts
373
+ # {
374
+ # 'xmlns:mc' => 'http://schemas.openxmlformats.org/markup-compatibility/2006',
375
+ # 'xmlns:o' => 'urn:schemas-microsoft-com:office:office',
376
+ # 'xmlns:r' => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
377
+ # 'xmlns:m' => 'http://schemas.openxmlformats.org/officeDocument/2006/math',
378
+ # 'xmlns:v' => 'urn:schemas-microsoft-com:vml',
379
+ # 'xmlns:wp' => 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
380
+ # 'xmlns:w10' => 'urn:schemas-microsoft-com:office:word',
381
+ # 'xmlns:w' => 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
382
+ # 'xmlns:wne' => 'http://schemas.microsoft.com/office/word/2006/wordml',
383
+ # 'xmlns:sl' => 'http://schemas.openxmlformats.org/schemaLibrary/2006/main',
384
+ # 'xmlns:a' => 'http://schemas.openxmlformats.org/drawingml/2006/main',
385
+ # 'xmlns:pic' => 'http://schemas.openxmlformats.org/drawingml/2006/picture',
386
+ # 'xmlns:c' => 'http://schemas.openxmlformats.org/drawingml/2006/chart',
387
+ # 'xmlns:lc' => 'http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas',
388
+ # 'xmlns:dgm' => 'http://schemas.openxmlformats.org/drawingml/2006/diagram'
389
+ # }
347
390
  end
348
391
 
349
392
  def page_margin_options
@@ -359,7 +402,7 @@ module Caracal
359
402
  {
360
403
  'w:w' => document.page_width,
361
404
  'w:h' => document.page_height,
362
- 'w:orient' => document.page_orientation
405
+ 'w:orient' => document.page_orientation
363
406
  }
364
407
  end
365
408
 
@@ -1,3 +1,3 @@
1
1
  module Caracal
2
- VERSION = '1.0.9'
2
+ VERSION = '1.0.10'
3
3
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Caracal::Core::IFrames do
4
+ subject { Caracal::Document.new }
5
+
6
+
7
+ #-------------------------------------------------------------
8
+ # Public Methods
9
+ #-------------------------------------------------------------
10
+
11
+ describe 'public method tests' do
12
+
13
+ # .img
14
+ describe '.iframes' do
15
+ let!(:size) { subject.contents.size }
16
+
17
+ before do
18
+ path = File.join(Caracal.root, 'spec', 'support', '_fixtures', 'snippet.docx')
19
+ data = File.open(path).read
20
+ subject.iframe data: data
21
+ end
22
+
23
+ it { expect(subject.contents.size).to eq size + 1 }
24
+ it { expect(subject.contents.last).to be_a(Caracal::Core::Models::IFrameModel) }
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Caracal::Core::Ignorables do
4
+ subject { Caracal::Document.new }
5
+
6
+
7
+ #-------------------------------------------------------------
8
+ # Public Methods
9
+ #-------------------------------------------------------------
10
+
11
+ describe 'public method tests' do
12
+
13
+ #============== ATTRIBUTES =====================
14
+
15
+ # .ignorable
16
+ describe '.ignorable' do
17
+ it 'delegates to registration method' do
18
+ expect(subject).to receive(:register_ignorable)
19
+ subject.ignorable('dummy')
20
+ end
21
+ end
22
+
23
+
24
+ #============== GETTERS ========================
25
+
26
+ # .ignorables
27
+ describe '.ignorables' do
28
+ it { expect(subject.ignorables).to be_a(Array) }
29
+ end
30
+
31
+
32
+ #============== REGISTRATION ========================
33
+
34
+ # .register_ignorable
35
+ describe '.register_ignorable' do
36
+ let(:default_length) { 0 }
37
+
38
+ describe 'when not already registered' do
39
+ before do
40
+ subject.register_ignorable('dummy')
41
+ end
42
+
43
+ it { expect(subject.ignorables.size).to eq default_length + 1 }
44
+ end
45
+ describe 'when already registered' do
46
+ before do
47
+ subject.register_ignorable('dummy')
48
+ subject.register_ignorable('dummy')
49
+ end
50
+
51
+ it { expect(subject.ignorables.size).to eq default_length + 1 }
52
+ end
53
+ end
54
+
55
+ # .unregister_ignorable
56
+ describe '.unregister_ignorable' do
57
+ let(:default_length) { 0 }
58
+
59
+ describe 'when registered' do
60
+ before do
61
+ subject.register_ignorable('dummy')
62
+ subject.unregister_ignorable('dummy')
63
+ end
64
+
65
+ it { expect(subject.ignorables.size).to eq default_length }
66
+ end
67
+ describe 'when not registered' do
68
+ before do
69
+ subject.register_ignorable('dummy')
70
+ subject.unregister_ignorable('bogus')
71
+ end
72
+
73
+ it { expect(subject.ignorables.size).to eq default_length + 1 }
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe Caracal::Core::Models::IFrameModel do
4
+ subject do
5
+ described_class.new do
6
+ url 'https://www.example.com/snippet.docx'
7
+ end
8
+ end
9
+
10
+
11
+
12
+ #-------------------------------------------------------------
13
+ # Configuration
14
+ #-------------------------------------------------------------
15
+
16
+ describe 'configuration tests' do
17
+
18
+ # accessors
19
+ describe 'accessors' do
20
+ it { expect(subject.iframe_url).to eq 'https://www.example.com/snippet.docx' }
21
+ end
22
+
23
+ end
24
+
25
+
26
+ #-------------------------------------------------------------
27
+ # Public Methods
28
+ #-------------------------------------------------------------
29
+
30
+ describe 'public method tests' do
31
+
32
+ #=============== SETTERS ==========================
33
+
34
+ # .url
35
+ describe '.url' do
36
+ before { subject.url('https://www.example.com/sample.docx') }
37
+
38
+ it { expect(subject.iframe_url).to eq 'https://www.example.com/sample.docx' }
39
+ end
40
+
41
+ # .data
42
+ describe '.data' do
43
+ before { subject.data('DOCX data follows here') }
44
+
45
+ it { expect(subject.iframe_data).to eq 'DOCX data follows here' }
46
+ end
47
+
48
+
49
+ #=============== VALIDATION ===========================
50
+
51
+ describe '.valid?' do
52
+ describe 'when either value present' do
53
+ it { expect(subject.valid?).to eq true }
54
+ end
55
+ describe 'when neither value present' do
56
+ before do
57
+ subject.url(nil)
58
+ subject.data(nil)
59
+ end
60
+ it { expect(subject.valid?).to eq false }
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+
67
+ #-------------------------------------------------------------
68
+ # Private Methods
69
+ #-------------------------------------------------------------
70
+
71
+ describe 'private method tests' do
72
+
73
+ # .option_keys
74
+ describe '.option_keys' do
75
+ let(:actual) { subject.send(:option_keys).sort }
76
+ let(:expected) { [:url, :data].sort }
77
+
78
+ it { expect(actual).to eq expected }
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Caracal::Core::Models::ImageModel do
4
- subject do
4
+ subject do
5
5
  described_class.new do
6
6
  url 'https://www.google.com/images/srpr/logo11w.png'
7
7
  ppi 96
@@ -14,15 +14,15 @@ describe Caracal::Core::Models::ImageModel do
14
14
  right 15
15
15
  end
16
16
  end
17
-
18
-
19
-
17
+
18
+
19
+
20
20
  #-------------------------------------------------------------
21
21
  # Configuration
22
22
  #-------------------------------------------------------------
23
23
 
24
24
  describe 'configuration tests' do
25
-
25
+
26
26
  # constants
27
27
  describe 'constants' do
28
28
  it { expect(described_class::DEFAULT_IMAGE_PPI).to eq 72 }
@@ -34,7 +34,7 @@ describe Caracal::Core::Models::ImageModel do
34
34
  it { expect(described_class::DEFAULT_IMAGE_LEFT).to eq 8 }
35
35
  it { expect(described_class::DEFAULT_IMAGE_RIGHT).to eq 8 }
36
36
  end
37
-
37
+
38
38
  # accessors
39
39
  describe 'accessors' do
40
40
  it { expect(subject.image_url).to eq 'https://www.google.com/images/srpr/logo11w.png' }
@@ -48,122 +48,120 @@ describe Caracal::Core::Models::ImageModel do
48
48
  it { expect(subject.image_left).to eq 14 }
49
49
  it { expect(subject.image_right).to eq 15 }
50
50
  end
51
-
51
+
52
52
  end
53
-
54
-
53
+
54
+
55
55
  #-------------------------------------------------------------
56
56
  # Public Methods
57
57
  #-------------------------------------------------------------
58
-
58
+
59
59
  describe 'public method tests' do
60
-
60
+
61
61
  #=============== GETTERS ==========================
62
-
62
+
63
63
  # emu conversions (dimensions)
64
64
  [:width, :height].each do |m|
65
65
  describe ".formatted_#{ m }" do
66
66
  let(:actual) { subject.send("formatted_#{ m }") }
67
-
67
+
68
68
  before do
69
69
  allow(subject).to receive("image_#{ m }").and_return(540)
70
70
  allow(subject).to receive("image_ppi").and_return(96)
71
71
  end
72
-
72
+
73
73
  it { expect(actual).to eq 5143500 }
74
74
  end
75
75
  end
76
-
76
+
77
77
  # emu conversions (margins)
78
78
  [:top, :bottom, :left, :right].each do |m|
79
79
  describe ".formatted_#{ m }" do
80
80
  let(:actual) { subject.send("formatted_#{ m }") }
81
-
81
+
82
82
  before { allow(subject).to receive("image_#{ m }").and_return(9) }
83
-
83
+
84
84
  it { expect(actual).to eq 114300 }
85
85
  end
86
86
  end
87
-
88
- # .relationship_target
89
-
90
-
91
-
87
+
88
+
89
+
92
90
  #=============== SETTERS ==========================
93
-
91
+
94
92
  # .url
95
- describe '.color' do
93
+ describe '.url' do
96
94
  before { subject.url('https://www.google.com/images/dummy.png') }
97
-
95
+
98
96
  it { expect(subject.image_url).to eq 'https://www.google.com/images/dummy.png' }
99
97
  end
100
-
98
+
101
99
  # .data
102
100
  describe '.data' do
103
101
  before { subject.data('PNG Data follows here') }
104
-
102
+
105
103
  it { expect(subject.image_data).to eq 'PNG Data follows here' }
106
104
  end
107
-
105
+
108
106
  # .ppi
109
107
  describe '.ppi' do
110
108
  before { subject.ppi(108) }
111
-
109
+
112
110
  it { expect(subject.image_ppi).to eq 108 }
113
111
  end
114
-
112
+
115
113
  # .width
116
114
  describe '.width' do
117
115
  before { subject.width(300) }
118
-
116
+
119
117
  it { expect(subject.image_width).to eq 300 }
120
118
  end
121
-
119
+
122
120
  # .height
123
121
  describe '.height' do
124
122
  before { subject.height(400) }
125
-
123
+
126
124
  it { expect(subject.image_height).to eq 400 }
127
125
  end
128
-
126
+
129
127
  # .align
130
128
  describe '.align' do
131
129
  before { subject.align(:center) }
132
-
130
+
133
131
  it { expect(subject.image_align).to eq :center }
134
132
  end
135
-
133
+
136
134
  # .top
137
135
  describe '.top' do
138
136
  before { subject.top(12) }
139
-
137
+
140
138
  it { expect(subject.image_top).to eq 12 }
141
139
  end
142
-
140
+
143
141
  # .bottom
144
142
  describe '.bottom' do
145
143
  before { subject.bottom(12) }
146
-
144
+
147
145
  it { expect(subject.image_bottom).to eq 12 }
148
146
  end
149
-
147
+
150
148
  # .left
151
149
  describe '.left' do
152
150
  before { subject.left(12) }
153
-
151
+
154
152
  it { expect(subject.image_left).to eq 12 }
155
153
  end
156
-
154
+
157
155
  # .right
158
156
  describe '.right' do
159
157
  before { subject.right(12) }
160
-
158
+
161
159
  it { expect(subject.image_right).to eq 12 }
162
160
  end
163
-
164
-
161
+
162
+
165
163
  #=============== VALIDATION ===========================
166
-
164
+
167
165
  describe '.valid?' do
168
166
  describe 'when all values okay' do
169
167
  it { expect(subject.valid?).to eq true }
@@ -173,55 +171,55 @@ describe Caracal::Core::Models::ImageModel do
173
171
  before do
174
172
  allow(subject).to receive("image_#{ d }").and_return(0)
175
173
  end
176
-
174
+
177
175
  it { expect(subject.valid?).to eq false }
178
176
  end
179
177
  end
180
178
  end
181
-
179
+
182
180
  end
183
-
184
-
181
+
182
+
185
183
  #-------------------------------------------------------------
186
184
  # Private Methods
187
185
  #-------------------------------------------------------------
188
-
186
+
189
187
  describe 'private method tests' do
190
-
188
+
191
189
  # .option_keys
192
190
  describe '.option_keys' do
193
191
  let(:actual) { subject.send(:option_keys).sort }
194
192
  let(:expected) { [:url, :width, :height, :align, :top, :bottom, :left, :right].sort }
195
-
193
+
196
194
  it { expect(actual).to eq expected }
197
195
  end
198
-
196
+
199
197
  # .pixels_to_emus
200
198
  describe '.pixels_to_emus' do
201
199
  let(:actual) { subject.send(:pixels_to_emus, value, 72) }
202
-
200
+
203
201
  describe 'when argument is nil' do
204
202
  let(:value) { nil }
205
-
203
+
206
204
  it { expect(actual).to eq 0 }
207
205
  end
208
206
  describe 'when argument is NaN' do
209
207
  let(:value) { 'a' }
210
-
208
+
211
209
  it { expect(actual).to eq 0 }
212
210
  end
213
211
  describe 'when argument is rational' do
214
212
  let(:value) { 396.1 }
215
-
213
+
216
214
  it { expect(actual).to eq 5029200 }
217
215
  end
218
216
  describe 'when argument is integer' do
219
217
  let(:value) { 396 }
220
-
218
+
221
219
  it { expect(actual).to eq 5029200 }
222
220
  end
223
221
  end
224
-
222
+
225
223
  end
226
-
227
- end
224
+
225
+ end