caracal 1.0.9 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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