axlsx 1.0.15 → 1.0.16

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.
@@ -47,7 +47,24 @@ module Axlsx
47
47
  yield self if block_given?
48
48
  @picture_locking = PictureLocking.new(options)
49
49
  end
50
+
51
+ attr_reader :hyperlink
50
52
 
53
+ # sets or updates a hyperlink for this image.
54
+ # @param [String] v The href value for the hyper link
55
+ # @option options @see Hyperlink#initialize All options available to the Hyperlink class apply - however href will be overridden with the v parameter value.
56
+ def hyperlink=(v, options={})
57
+ options[:href] = v
58
+ if @hyperlink.is_a?(Hyperlink)
59
+ options.each do |o|
60
+ @hyperlink.send("#{o[0]}=", o[1]) if @hyperlink.respond_to? "#{o[0]}="
61
+ end
62
+ else
63
+ @hyperlink = Hyperlink.new(self, options)
64
+ end
65
+ @hyperlink
66
+ end
67
+
51
68
  def image_src=(v)
52
69
  Axlsx::validate_string(v)
53
70
  RestrictionValidator.validate 'Pic.image_src', ALLOWED_EXTENSIONS, File.extname(v).delete('.')
@@ -75,7 +92,7 @@ module Axlsx
75
92
  end
76
93
 
77
94
  # The index of this image in the workbooks images collections
78
- # @return [Index]
95
+ # @return [Index]
79
96
  def index
80
97
  @anchor.drawing.worksheet.workbook.images.index(self)
81
98
  end
@@ -86,6 +103,11 @@ module Axlsx
86
103
  "#{IMAGE_PN % [(index+1), extname]}"
87
104
  end
88
105
 
106
+ # The relational id withing the drawing's relationships
107
+ def id
108
+ @anchor.drawing.charts.size + @anchor.drawing.images.index(self) + 1
109
+ end
110
+
89
111
  # providing access to the anchor's width attribute
90
112
  # @param [Integer] v
91
113
  # @see OneCellAnchor.width
@@ -127,13 +149,17 @@ module Axlsx
127
149
  def to_xml(xml)
128
150
  xml.pic {
129
151
  xml.nvPicPr {
130
- xml.cNvPr :id=>"2", :name=>name, :descr=>descr
152
+ xml.cNvPr(:id=>"2", :name=>name, :descr=>descr) {
153
+ if @hyperlink.is_a?(Hyperlink)
154
+ @hyperlink.to_xml(xml)
155
+ end
156
+ }
131
157
  xml.cNvPicPr {
132
158
  picture_locking.to_xml(xml)
133
159
  }
134
160
  }
135
161
  xml.blipFill {
136
- xml[:a].blip :'xmlns:r' => XML_NS_R, :'r:embed'=>"rId1"
162
+ xml[:a].blip :'xmlns:r' => XML_NS_R, :'r:embed'=>"rId#{id}"
137
163
  xml[:a].stretch {
138
164
  xml.fillRect
139
165
  }
@@ -89,10 +89,10 @@ module Axlsx
89
89
  end
90
90
 
91
91
  # Encrypt the package into a CFB using the password provided
92
- # def encrypt(file_name, password)
93
- # moc = MsOffCrypto.new(file_name, password)
94
- # moc.save
95
- # end
92
+ def encrypt(file_name, password)
93
+ moc = MsOffCrypto.new(file_name, password)
94
+ moc.save
95
+ end
96
96
 
97
97
  # Validate all parts of the package against xsd schema.
98
98
  # @return [Array] An array of all validation errors found.
@@ -21,9 +21,21 @@ module Axlsx
21
21
  # @see DRAWING_R
22
22
  # @return [String]
23
23
  attr_reader :Type
24
- def initialize(type, target)
24
+
25
+ # The target mode of the relationship
26
+ # used for hyperlink type relationships to mark the relationship to an external resource
27
+ # TargetMode can be specified during initialization by passing in a :target_mode option
28
+ # Target mode must be :external for now.
29
+ attr_reader :TargetMode
30
+
31
+ # creates a new relationship
32
+ # @param [String] Type The type of the relationship
33
+ # @param [String] Target The target for the relationship
34
+ # @option [Symbol] target_mode only accepts :external.
35
+ def initialize(type, target, options={})
25
36
  self.Target=target
26
37
  self.Type=type
38
+ self.TargetMode = options.delete(:target_mode) if options[:target_mode]
27
39
  end
28
40
 
29
41
  # @see Target
@@ -31,6 +43,9 @@ module Axlsx
31
43
  # @see Type
32
44
  def Type=(v) Axlsx::validate_relationship_type v; @Type = v end
33
45
 
46
+ # @see TargetMode
47
+ def TargetMode=(v) RestrictionValidator.validate 'Relationship.TargetMode', [:External, :Internal], v; @TargetMode = v; end
48
+
34
49
  # Serializes the relationship
35
50
  # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
36
51
  # @param [String] rId the reference id of the object.
@@ -18,7 +18,7 @@ require 'axlsx/rels/relationship.rb'
18
18
  each_with_index { |rel, index| rel.to_xml(xml, "rId#{index+1}") }
19
19
  }
20
20
  end
21
- builder.to_xml
21
+ builder.to_xml(:save_with => 0)
22
22
  end
23
23
 
24
24
  end
@@ -246,7 +246,7 @@ module Axlsx
246
246
  end
247
247
  }
248
248
  end
249
- builder.to_xml
249
+ builder.to_xml(:save_with => 0)
250
250
  end
251
251
 
252
252
  private
@@ -10,13 +10,13 @@ module Axlsx
10
10
  VERSION_PACKING = 'l s30 l3'
11
11
 
12
12
  # The serialization for the MS-OFF-CRYPTO dataspace map stream
13
- DATA_SPACE_MAP_PACKING = 'l6 s16 l s25'
13
+ DATA_SPACE_MAP_PACKING = 'l6 s16 l s25 x2'
14
14
 
15
15
  # The serialization for the MS-OFF-CRYPTO strong encrytion data space stream
16
- STRONG_ENCRYPTION_DATA_SPACE_PACKING = 'l3 s25'
16
+ STRONG_ENCRYPTION_DATA_SPACE_PACKING = 'l3 s26'
17
17
 
18
18
  # The serialization for the MS-OFF-CRYPTO primary stream
19
- PRIMARY_PACKING = 'l3 s38 l s39 l3 x12 l x2'
19
+ PRIMARY_PACKING = 'l3 s38 l s40 l3 x12 l'
20
20
 
21
21
  # The cutoff size that determines if a stream should be in the mini-fat or the fat
22
22
  MINI_CUTOFF = 4096
@@ -28,6 +28,7 @@ module Axlsx
28
28
  # @param [MsOffCrypto] ms_off_crypto
29
29
  def initialize(ms_off_crypto)
30
30
  @file_name = ms_off_crypto.file_name
31
+ @ms_off_crypto = ms_off_crypto
31
32
  create_storages
32
33
  mini_fat_stream
33
34
  mini_fat
@@ -95,6 +96,17 @@ module Axlsx
95
96
  @header ||= create_header
96
97
  end
97
98
 
99
+ # returns the encryption info from the ms_off_crypt object provided during intialization
100
+ # @return [String] encryption info
101
+ def encryption_info
102
+ @ms_off_crypto.encryption_info
103
+ end
104
+
105
+ # returns the encrypted package from the ms_off_crypt object provided during initalization
106
+ # @return [String] encrypted package
107
+ def encrypted_package
108
+ @ms_off_crypto.encrypted_package
109
+ end
98
110
 
99
111
  # writes the compound binary file to disk
100
112
  def save
@@ -114,12 +126,11 @@ module Axlsx
114
126
  # Generates the storages required for ms-office-cryptography cfb
115
127
  def create_storages
116
128
  @storages = []
117
- @encryption_info = ms_off_crypto.encryption_info
118
- @encrypted_package = ms_off_crypto.encrypted_package
119
- @storages << Storage.new('R', :type=>Storage::TYPES[:root], :color=>Storage::COLORS[:red], :child=>1, :modified=>129685612742510730)
120
- @storages.last.name_size = 2
121
- @storages << Storage.new('EncryptionInfo', :data=>@encryption_info, :left=>3, :size => @encryption_info.size) # example shows right child. do we need the summary info????
122
- @storages << Storage.new('EncryptedPackage', :data=>@encrypted_package, :color=>Storage::COLORS[:red], :size=>@encrypted_package.size)
129
+ @encryption_info = @ms_off_crypto.encryption_info
130
+ @encrypted_package = @ms_off_crypto.encrypted_package
131
+
132
+ @storages << Storage.new('EncryptionInfo', :data=>encryption_info, :left=>3, :right=>11) # example shows right child. do we need the summary info????
133
+ @storages << Storage.new('EncryptedPackage', :data=>encrypted_package, :color=>Storage::COLORS[:red])
123
134
  @storages << Storage.new([6].pack("c")+"DataSpaces", :child=>5, :modified =>129685612740945580, :created=>129685612740819979)
124
135
  @storages << version
125
136
  @storages << data_space_map
@@ -128,6 +139,12 @@ module Axlsx
128
139
  @storages << Storage.new('TransformInfo', :color => Storage::COLORS[:red], :child=>9, :created=>129685612740834130, :modified=>129685612740943959)
129
140
  @storages << Storage.new('StrongEncryptionTransform', :child=>10, :created=>129685612740834169, :modified=>129685612740942280)
130
141
  @storages << primary
142
+ # @storages << summary_information
143
+ # @storages << document_summary_information
144
+
145
+ # we do this at the end as we need to build the minifat stream to determine the size. #HOWEVER - it looks like the size should not include the padding?
146
+ @storages.unshift Storage.new('Root Entry', :type=>Storage::TYPES[:root], :color=>Storage::COLORS[:red], :child=>1, :data => mini_fat_stream)
147
+
131
148
  end
132
149
 
133
150
  # generates the mini fat stream
@@ -135,10 +152,11 @@ module Axlsx
135
152
  def create_mini_fat_stream
136
153
  mfs = []
137
154
  @storages.select{ |s| s.type == Storage::TYPES[:stream] && s.size < MINI_CUTOFF}.each_with_index do |stream, index|
155
+ puts "#{stream.name.pack('c*')}: #{stream.data.size}"
138
156
  mfs.concat stream.data
139
- mfs.concat Array.new(64 - (mfs.size % 64), 0) if mfs.size % 64
157
+ mfs.concat Array.new(64 - (mfs.size % 64), 0) if mfs.size % 64 > 0
158
+ puts "mini fat stream size: #{mfs.size}"
140
159
  end
141
- @storages[0].size = mfs.size
142
160
  mfs.concat(Array.new(512 - (mfs.size % 512), 0))
143
161
  mfs.pack 'c*'
144
162
  end
@@ -149,7 +167,7 @@ module Axlsx
149
167
  mfs = []
150
168
  @storages.select{ |s| s.type == Storage::TYPES[:stream] && s.size >= MINI_CUTOFF}.each_with_index do |stream, index|
151
169
  mfs.concat stream.data
152
- mfs.concat Array.new(512 - (mfs.size % 512), 0) if mfs.size % 512
170
+ mfs.concat Array.new(512 - (mfs.size % 512), 0) if mfs.size % 512 > 0
153
171
  end
154
172
  mfs.pack 'c*'
155
173
  end
@@ -214,7 +232,7 @@ module Axlsx
214
232
  # creates the stron encryption data space storage
215
233
  # @return [Storgae]
216
234
  def create_strong_encryption_data_space
217
- v_stream = [8,1,50,"StrongEncryptionTransform".bytes.to_a].flatten.pack STRONG_ENCRYPTION_DATA_SPACE_PACKING
235
+ v_stream = [8,1,50,"StrongEncryptionTransform".bytes.to_a,0].flatten.pack STRONG_ENCRYPTION_DATA_SPACE_PACKING
218
236
  Storage.new("StrongEncryptionDataSpace", :data=>v_stream, :size => v_stream.size)
219
237
  end
220
238
 
@@ -222,41 +240,58 @@ module Axlsx
222
240
  # @return [Storgae]
223
241
  def create_primary
224
242
  v_stream = [88,1,76,"{FF9A3F03-56EF-4613-BDD5-5A41C1D07246}".bytes.to_a].flatten
225
- v_stream.concat [78, "Microsoft.Container.EncryptionTransform".bytes.to_a,1,1,1,4].flatten
243
+ v_stream.concat [78, "Microsoft.Container.EncryptionTransform".bytes.to_a,0,1,1,1,4].flatten
226
244
  v_stream = v_stream.pack PRIMARY_PACKING
227
245
  Storage.new([6].pack("c")+"Primary", :data=>v_stream)
228
246
  end
229
247
 
230
248
 
231
- SUMMARY_INFORMATION_PACKING = ""
232
249
  # creates the summary information storage
233
250
  # @return [Storage]
234
251
  def create_summary_information
235
- # FEFF 0000 030A 0100 0000 0000 0000 0000
236
- # 0000 0000 0000 0000 0100 0000 E085 9FF2
237
- # F94F 6810 AB91 0800 2B27 B3D9 3000 0000
238
- # AC00 0000 0700 0000 0100 0000 4000 0000
239
- # 0400 0000 4800 0000 0800 0000 5800 0000
240
- # 1200 0000 6800 0000 0C00 0000 8C00 0000
241
- # 0D00 0000 9800 0000 1300 0000 A400 0000
242
- # 0200 0000 E9FD 0000 1E00 0000 0800 0000
243
- # 7261 6E64 796D 0000 1E00 0000 0800 0000
244
- # 7261 6E64 796D 0000 1E00 0000 1C00 0000
245
- # 4D69 6372 6F73 6F66 7420 4D61 6369 6E74
246
- # 6F73 6820 4578 6365 6C00 0000 4000 0000
247
- # 10AC 5396 60BC CC01 4000 0000 40F4 FDAF
248
- # 60BC CC01 0300 0000 0100 0000
249
252
  v_stream = []
250
- v_stream = v_stream.pack SUMMARY_INFORMATION_PACKING
251
- Storage.new([5].pack('c')+"SummaryInformation", :data=>v_stream)
253
+ v_stream.concat [0xFEFF, 0x0000, 0x030A, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000]
254
+ v_stream.concat [0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0xE085, 0x9FF2]
255
+ v_stream.concat [0xF94F, 0x6810, 0xAB91, 0x0800, 0x2B27, 0xB3D9, 0x3000, 0x0000]
256
+ v_stream.concat [0xAC00, 0x0000, 0x0700, 0x0000, 0x0100, 0x0000, 0x4000, 0x0000]
257
+ v_stream.concat [0x0400, 0x0000, 0x4800, 0x0000, 0x0800, 0x0000, 0x5800, 0x0000]
258
+ v_stream.concat [0x1200, 0x0000, 0x6800, 0x0000, 0x0C00, 0x0000, 0x8C00, 0x0000]
259
+ v_stream.concat [0x0D00, 0x0000, 0x9800, 0x0000, 0x1300, 0x0000, 0xA400, 0x0000]
260
+ v_stream.concat [0x0200, 0x0000, 0xE9FD, 0x0000, 0x1E00, 0x0000, 0x0800, 0x0000]
261
+ v_stream.concat [0x7261, 0x6E64, 0x796D, 0x0000, 0x1E00, 0x0000, 0x0800, 0x0000]
262
+ v_stream.concat [0x7261, 0x6E64, 0x796D, 0x0000, 0x1E00, 0x0000, 0x1C00, 0x0000]
263
+ v_stream.concat [0x4D69, 0x6372, 0x6F73, 0x6F66, 0x7420, 0x4D61, 0x6369, 0x6E74]
264
+ v_stream.concat [0x6F73, 0x6820, 0x4578, 0x6365, 0x6C00, 0x0000, 0x4000, 0x0000]
265
+ v_stream.concat [0x10AC, 0x5396, 0x60BC, 0xCC01, 0x4000, 0x0000, 0x40F4, 0xFDAF]
266
+ v_stream.concat [0x60BC, 0xCC01, 0x0300, 0x0000, 0x0100, 0x0000]
267
+
268
+ v_stream = v_stream.pack "s*"
269
+
270
+ Storage.new([5].pack('c')+"SummaryInformation", :data=>v_stream, :left => 2)
252
271
  end
253
272
 
254
- DOCUMENT_SUMMARY_INFORMATION_PACKING = ""
273
+
255
274
  # creates the document summary information storage
256
275
  # @return [Storage]
257
276
  def create_document_summary_information
258
277
  v_stream = []
259
- v_stream = v_stream.pack DOCUMENT_SUMMARY_INFORMATION_PACKING
278
+ v_stream.concat [0xFEFF, 0x0000, 0x030A, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000]
279
+ v_stream.concat [0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x02D5, 0xCDD5]
280
+ v_stream.concat [0x9C2E, 0x1B10, 0x9397, 0x0800, 0x2B2C, 0xF9AE, 0x3000, 0x0000]
281
+ v_stream.concat [0xCC00, 0x0000, 0x0900, 0x0000, 0x0100, 0x0000, 0x5000, 0x0000]
282
+ v_stream.concat [0x0F00, 0x0000, 0x5800, 0x0000, 0x1700, 0x0000, 0x6400, 0x0000]
283
+ v_stream.concat [0x0B00, 0x0000, 0x6C00, 0x0000, 0x1000, 0x0000, 0x7400, 0x0000]
284
+ v_stream.concat [0x1300, 0x0000, 0x7C00, 0x0000, 0x1600, 0x0000, 0x8400, 0x0000]
285
+ v_stream.concat [0x0D00, 0x0000, 0x8C00, 0x0000, 0x0C00, 0x0000, 0x9F00, 0x0000]
286
+ v_stream.concat [0x0200, 0x0000, 0xE9FD, 0x0000, 0x1E00, 0x0000, 0x0400, 0x0000]
287
+ v_stream.concat [0x0000, 0x0000, 0x0300, 0x0000, 0x0000, 0x0C00, 0x0B00, 0x0000]
288
+ v_stream.concat [0x0000, 0x0000, 0x0B00, 0x0000, 0x0000, 0x0000, 0x0B00, 0x0000]
289
+ v_stream.concat [0x0000, 0x0000, 0x0B00, 0x0000, 0x0000, 0x0000, 0x1E10, 0x0000]
290
+ v_stream.concat [0x0100, 0x0000, 0x0700, 0x0000, 0x5368, 0x6565, 0x7431, 0x000C]
291
+ v_stream.concat [0x1000, 0x0002, 0x0000, 0x001E, 0x0000, 0x0013, 0x0000, 0x00E3]
292
+ v_stream.concat [0x83AF, 0xE383, 0xBCE3, 0x82AF, 0xE382, 0xB7E3, 0x83BC, 0xE383]
293
+ v_stream.concat [0x8800, 0x0300, 0x0000, 0x0100, 0x0000, 0x0000]
294
+ v_stream = v_stream.pack 'c*'
260
295
  Storage.new([5].pack('c')+"DocumentSummaryInformation", :data=>v_stream)
261
296
  end
262
297
 
@@ -73,6 +73,9 @@ module Axlsx
73
73
  # image rels namespace
74
74
  IMAGE_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
75
75
 
76
+ # image rels namespace
77
+ HYPERLINK_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
78
+
76
79
  # table content type
77
80
  TABLE_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
78
81
 
@@ -169,23 +172,26 @@ module Axlsx
169
172
  # chart part
170
173
  IMAGE_PN = "media/image%d.%s"
171
174
 
175
+ # location of schema files for validation
176
+ SCHEMA_BASE = File.dirname(__FILE__)+'/../../schema/'
177
+
172
178
  # App validation schema
173
- APP_XSD = "lib/schema/shared-documentPropertiesExtended.xsd"
179
+ APP_XSD = SCHEMA_BASE + "shared-documentPropertiesExtended.xsd"
174
180
 
175
181
  # core validation schema
176
- CORE_XSD = "lib/schema/opc-coreProperties.xsd"
182
+ CORE_XSD = SCHEMA_BASE + "opc-coreProperties.xsd"
177
183
 
178
184
  # content types validation schema
179
- CONTENT_TYPES_XSD = "lib/schema/opc-contentTypes.xsd"
185
+ CONTENT_TYPES_XSD = SCHEMA_BASE + "opc-contentTypes.xsd"
180
186
 
181
187
  # rels validation schema
182
- RELS_XSD = "lib/schema/opc-relationships.xsd"
188
+ RELS_XSD = SCHEMA_BASE + "opc-relationships.xsd"
183
189
 
184
190
  # spreadsheetML validation schema
185
- SML_XSD = "lib/schema/sml.xsd"
191
+ SML_XSD = SCHEMA_BASE + "sml.xsd"
186
192
 
187
193
  # drawing validation schema
188
- DRAWING_XSD = "lib/schema/dml-spreadsheetDrawing.xsd"
194
+ DRAWING_XSD = SCHEMA_BASE + "dml-spreadsheetDrawing.xsd"
189
195
 
190
196
  # number format id for pecentage formatting using the default formatting id.
191
197
  NUM_FMT_PERCENT = 9
@@ -48,7 +48,7 @@ module Axlsx
48
48
  # encrypts and returns the package specified by the file name
49
49
  # @return [String]
50
50
  def encrypted_package
51
- @encrypted_package ||= encrypt_package(file_name, password)
51
+ @encrypted_package ||= encrypt_package(file_name)
52
52
  end
53
53
 
54
54
  # returns the encryption info for this instance of ms-off-crypto
@@ -94,10 +94,10 @@ module Axlsx
94
94
  end
95
95
 
96
96
  # size of unencrypted package? concated with encrypted package
97
- def encrypt_package(file_name, password)
97
+ def encrypt_package(file_name)
98
98
  package = File.open(file_name, 'r')
99
- package_text = package.read
100
- [package_text.bytes.to_a.size].pack('q') + encrypt(package_text)
99
+ crypt_pack = encrypt(package.read)
100
+ [crypt_pack.size].pack('q') + crypt_pack
101
101
  end
102
102
 
103
103
  # Generates an encryption info structure
@@ -106,18 +106,18 @@ module Axlsx
106
106
  header = [3, 0, 2, 0] # version
107
107
  # Header flags copy
108
108
  header.concat [0x24, 0, 0, 0] #flags -- VERY UNSURE ABOUT THIS STILL
109
- header.concat [0, 0, 0, 0] #unused
109
+ # header.concat [0, 0, 0, 0] #unused
110
110
  header.concat [0xA4, 0, 0, 0] #length
111
111
  # Header
112
112
  header.concat [0x24, 0, 0, 0] #flags again
113
- header.concat [0, 0, 0, 0] #unused again,
113
+ # header.concat [0, 0, 0, 0] #unused again,
114
114
  header.concat [0x0E, 0x66, 0, 0] #alg id
115
115
  header.concat [0x04, 0x80, 0, 0] #alg hash id
116
116
  header.concat [key.size, 0, 0, 0] #key size
117
117
  header.concat [0x18, 0, 0, 0] #provider type
118
- header.concat [0, 0, 0, 0] #reserved 1
119
- header.concat [0, 0, 0, 0] #reserved 2
120
- #header.concat [0xA0, 0xC7, 0xDC, 0x2, 0, 0, 0, 0]
118
+ # header.concat [0, 0, 0, 0] #reserved 1
119
+ # header.concat [0, 0, 0, 0] #reserved 2
120
+ header.concat [0xA0, 0xC7, 0xDC, 0x2, 0, 0, 0, 0]
121
121
  header.concat "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)".bytes.to_a.pack('s*').bytes.to_a
122
122
  header.concat [0, 0] #null terminator
123
123
 
@@ -28,7 +28,6 @@ module Axlsx
28
28
  @modified,
29
29
  @sector,
30
30
  @size].flatten
31
- puts data.inspect
32
31
  data.pack(PACKING)
33
32
  end
34
33
 
@@ -119,7 +119,7 @@ module Axlsx
119
119
  # XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R are allowed
120
120
  # @param [Any] v The value validated
121
121
  def self.validate_relationship_type(v)
122
- RestrictionValidator.validate :relationship_type, [XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R, IMAGE_R], v
122
+ RestrictionValidator.validate :relationship_type, [XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R, IMAGE_R, HYPERLINK_R], v
123
123
  end
124
124
 
125
125
  # Requires that the value is a valid table element type
@@ -1,7 +1,9 @@
1
1
  module Axlsx
2
- # version
2
+
3
+ # The version of the gem
3
4
  # When using bunle exec rake and referencing the gem on github or locally
4
5
  # it will use the gemspec, which preloads this constant for the gem's version.
5
6
  # We check to make sure that it has not already been loaded
6
- VERSION="1.0.15" unless Axlsx.const_defined? :VERSION
7
+ VERSION="1.0.16" unless Axlsx.const_defined? :VERSION
8
+
7
9
  end
@@ -82,17 +82,27 @@ require 'axlsx/workbook/worksheet/worksheet.rb'
82
82
  #end
83
83
 
84
84
  # Creates a new Workbook
85
- # @option options [Boolean] date1904
85
+ #
86
+ # @option options [Boolean] date1904. If this is not specified, we try to determine if the platform is bsd/darwin and set date1904 to true automatically.
87
+ #
86
88
  def initialize(options={})
87
89
  @styles = Styles.new
88
90
  @worksheets = SimpleTypedList.new Worksheet
89
91
  @drawings = SimpleTypedList.new Drawing
90
92
  @charts = SimpleTypedList.new Chart
91
93
  @images = SimpleTypedList.new Pic
92
- self.date1904= options[:date1904] unless options[:date1904].nil?
94
+ self.date1904= options[:date1904].nil? ? is_bsd? : options[:date1904]
93
95
  yield self if block_given?
94
96
  end
95
97
 
98
+ # Uses RUBY_PLATFORM constant to determine if the OS is freebsd or darwin
99
+ # based on this value we attempt to set date1904.
100
+ # @return [Boolean]
101
+ def is_bsd?
102
+ platform = RUBY_PLATFORM.downcase
103
+ platform.include?('freebsd') || platform.include?('darwin')
104
+ end
105
+
96
106
  # Instance level access to the class variable 1904
97
107
  # @return [Boolean]
98
108
  def date1904() @@date1904; end
@@ -144,7 +154,7 @@ require 'axlsx/workbook/worksheet/worksheet.rb'
144
154
  # @return [String]
145
155
  def to_xml()
146
156
  add_worksheet unless worksheets.size > 0
147
- builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
157
+ builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
148
158
  xml.workbook(:xmlns => XML_NS, :'xmlns:r' => XML_NS_R) {
149
159
  xml.workbookPr(:date1904=>@@date1904)
150
160
  #<x:workbookProtection workbookPassword="xsd:hexBinary data" lockStructure="1" lockWindows="1" />
@@ -155,7 +165,7 @@ require 'axlsx/workbook/worksheet/worksheet.rb'
155
165
  }
156
166
  }
157
167
  end
158
- builder.to_xml(:indent=>0)
168
+ builder.to_xml(:save_with => 0)
159
169
  end
160
170
  end
161
171
  end