caxlsx 4.2.0 → 4.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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +17 -8
- data/Rakefile +2 -9
- data/lib/axlsx/drawing/bar_3D_chart.rb +11 -1
- data/lib/axlsx/drawing/bar_chart.rb +11 -1
- data/lib/axlsx/drawing/chart.rb +1 -0
- data/lib/axlsx/drawing/d_lbls.rb +1 -0
- data/lib/axlsx/drawing/vml_shape.rb +1 -1
- data/lib/axlsx/package.rb +43 -10
- data/lib/axlsx/stylesheet/border_pr.rb +1 -0
- data/lib/axlsx/stylesheet/pattern_fill.rb +1 -0
- data/lib/axlsx/stylesheet/styles.rb +1 -0
- data/lib/axlsx/stylesheet/theme.rb +163 -0
- data/lib/axlsx/stylesheet/xf.rb +1 -0
- data/lib/axlsx/util/buffered_zip_output_stream.rb +2 -2
- data/lib/axlsx/util/constants.rb +12 -0
- data/lib/axlsx/util/mime_type_utils.rb +72 -13
- data/lib/axlsx/util/simple_typed_list.rb +1 -2
- data/lib/axlsx/util/uri_utils.rb +70 -0
- data/lib/axlsx/util/validators.rb +5 -5
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/defined_name.rb +1 -0
- data/lib/axlsx/workbook/workbook.rb +7 -0
- data/lib/axlsx/workbook/workbook_view.rb +1 -1
- data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +1 -1
- data/lib/axlsx/workbook/worksheet/cell.rb +3 -3
- data/lib/axlsx/workbook/worksheet/col.rb +1 -0
- data/lib/axlsx/workbook/worksheet/header_footer.rb +1 -1
- data/lib/axlsx/workbook/worksheet/pane.rb +1 -0
- data/lib/axlsx/workbook/worksheet/pivot_table.rb +1 -1
- data/lib/axlsx/workbook/worksheet/print_options.rb +1 -0
- data/lib/axlsx/workbook/worksheet/sheet_calc_pr.rb +1 -0
- data/lib/axlsx/workbook/worksheet/table_style_info.rb +1 -0
- data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +1 -1
- data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +1 -1
- data/lib/axlsx/workbook/worksheet/worksheet_hyperlink.rb +1 -0
- data/lib/axlsx.rb +2 -0
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97d26d1c2165080987473b430781c434b27f62510950ce0c27792058ab493bbf
|
4
|
+
data.tar.gz: 6d9f1f55b9b6602d86e2f6e30ce5e0589ac811bf49f8991f7dbc7f8fec42e6e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd8f19deac0273ac8f59aca129190fc395b23077e34bfaafaa50dc48b9e6565430b94c7bbac8f19fd7272edacf0cac04438a2dc464b22670a575be75259cb2fe
|
7
|
+
data.tar.gz: 92ef32593a1ba1132b2b53ae08ecd82eb7e538edfdbb5e764fb325c57f6a2c66b56de6b67e04a48aa3dde5b663468a06d876292103f22fcf456b0da6563df967
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,22 @@ CHANGELOG
|
|
2
2
|
---------
|
3
3
|
- **Unreleased**
|
4
4
|
|
5
|
+
- **September.01.25**: 4.4.0
|
6
|
+
- [PR #477](https://github.com/caxlsx/caxlsx/pull/477) Add package-level encryption and password protection.
|
7
|
+
- [PR #476](https://github.com/caxlsx/caxlsx/pull/476) Add Excel for Windows integration testing.
|
8
|
+
- [PR #476](https://github.com/caxlsx/caxlsx/pull/476) Add Excel for MacOS integration testing.
|
9
|
+
- [PR #469](https://github.com/caxlsx/caxlsx/pull/469) Add default theme file to Excel package.
|
10
|
+
- [PR #475](https://github.com/caxlsx/caxlsx/pull/475) Use timecop to fix transient time failure in tests
|
11
|
+
- [PR #474](https://github.com/caxlsx/caxlsx/pull/474) Add Windows and MacOS to the CI.
|
12
|
+
- [PR #474](https://github.com/caxlsx/caxlsx/pull/474) Fix local image file MIME type detection on Windows.
|
13
|
+
- [PR #474](https://github.com/caxlsx/caxlsx/pull/474) Load only HTTP headers when determining remote file MIME type.
|
14
|
+
|
15
|
+
- **August.16.25**: 4.3.0
|
16
|
+
- [PR #421](https://github.com/caxlsx/caxlsx/pull/421) Add Rubyzip >= 2.4 support
|
17
|
+
- [PR #448](https://github.com/caxlsx/caxlsx/pull/448) Fix Bar Chart: set axis position for Apple Numbers compatibility
|
18
|
+
- [PR #466](https://github.com/caxlsx/caxlsx/pull/466) Use RubyGem's trusted publishing
|
19
|
+
- [PR #467](https://github.com/caxlsx/caxlsx/pull/467) Add JRuby 10.0 to the CI
|
20
|
+
|
5
21
|
- **December.15.24**: 4.2.0
|
6
22
|
- [PR #359](https://github.com/caxlsx/caxlsx/pull/359) Add `PivotTable#grand_totals` option to remove grand totals row/col
|
7
23
|
- [PR #362](https://github.com/caxlsx/caxlsx/pull/362) Use widest width even if provided as fixed value
|
data/README.md
CHANGED
@@ -51,20 +51,21 @@ cell level input data validation.
|
|
51
51
|
|
52
52
|
15. Support for page margins and print options
|
53
53
|
|
54
|
-
16. Support for
|
54
|
+
16. Support for workbook-level encryption and password protection (requires [ooxml_crypt](https://github.com/teamsimplepay/ooxml_crypt) gem which only supports MRI Ruby.)
|
55
55
|
|
56
|
-
17.
|
57
|
-
and Numbers
|
56
|
+
17. Support for sheet-level password and non-password protection.
|
58
57
|
|
59
|
-
18.
|
58
|
+
18. First stage interoperability support for GoogleDocs, LibreOffice, and Numbers.
|
60
59
|
|
61
|
-
19.
|
60
|
+
19. Support for defined names, which gives you repeated header rows for printing.
|
62
61
|
|
63
|
-
20.
|
62
|
+
20. Data labels for charts as well as series color customization.
|
64
63
|
|
65
|
-
21.
|
64
|
+
21. Support for sheet headers and footers
|
66
65
|
|
67
|
-
22.
|
66
|
+
22. Pivot Tables
|
67
|
+
|
68
|
+
23. Page Breaks
|
68
69
|
|
69
70
|
|
70
71
|
## Install
|
@@ -107,6 +108,12 @@ Additional documentation is listed below:
|
|
107
108
|
- [Style Reference](https://github.com/caxlsx/caxlsx/blob/master/docs/style_reference.md)
|
108
109
|
- [Header and Footer Codes](https://github.com/caxlsx/caxlsx/blob/master/docs/header_and_footer_codes.md)
|
109
110
|
|
111
|
+
You can run the documentation on your local by running the following:
|
112
|
+
```sh
|
113
|
+
gem install webrick
|
114
|
+
yard server
|
115
|
+
```
|
116
|
+
|
110
117
|
⚠ Please __do not create issues__ for questions regarding the usage of axlsx / caxlsx. Look through this README, the [examples folder](https://github.com/caxlsx/caxlsx/tree/master/examples), and the [FAQ](https://github.com/caxlsx/caxlsx/wiki/FAQ), and also check [questions tagged `axlsx` on Stack Overflow](https://stackoverflow.com/questions/tagged/axlsx).
|
111
118
|
|
112
119
|
Feel free to add your question (including an answer!) to the FAQ if you think it is of general interest.
|
@@ -121,6 +128,8 @@ Currently the following additional gems are available:
|
|
121
128
|
* Provides a `.axlsx` renderer to Rails so you can move all your spreadsheet code from your controller into view files.
|
122
129
|
- [activeadmin-caxlsx](https://github.com/caxlsx/activeadmin-caxlsx)
|
123
130
|
* An Active Admin plugin that includes DSL to create downloadable reports.
|
131
|
+
- [ooxml_crypt](https://github.com/teamsimplepay/ooxml_crypt)
|
132
|
+
* Required to enable workbook encryption and password protection.
|
124
133
|
|
125
134
|
## Security
|
126
135
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
task build: :gendoc do
|
6
|
-
system "gem build axlsx.gemspec"
|
7
|
-
end
|
3
|
+
require 'bundler'
|
4
|
+
Bundler::GemHelper.install_tasks
|
8
5
|
|
9
6
|
task :benchmark do
|
10
7
|
require File.expand_path("#{File.dirname(__FILE__)}/test/benchmark.rb")
|
@@ -23,8 +20,4 @@ Rake::TestTask.new do |t|
|
|
23
20
|
t.warning = true
|
24
21
|
end
|
25
22
|
|
26
|
-
task release: :build do
|
27
|
-
system "gem push caxlsx-#{Axlsx::VERSION}.gem"
|
28
|
-
end
|
29
|
-
|
30
23
|
task default: :test
|
@@ -141,7 +141,17 @@ module Axlsx
|
|
141
141
|
# category axes specified via axes[:val_axes] and axes[:cat_axis]
|
142
142
|
# @return [Axes]
|
143
143
|
def axes
|
144
|
-
@axes ||=
|
144
|
+
@axes ||= begin
|
145
|
+
a = Axes.new(cat_axis: CatAxis, val_axis: ValAxis)
|
146
|
+
|
147
|
+
if bar_dir == :col
|
148
|
+
a[:val_axis].ax_pos = :l
|
149
|
+
else
|
150
|
+
a[:cat_axis].ax_pos = :l
|
151
|
+
end
|
152
|
+
|
153
|
+
a
|
154
|
+
end
|
145
155
|
end
|
146
156
|
end
|
147
157
|
end
|
@@ -131,7 +131,17 @@ module Axlsx
|
|
131
131
|
# category axes specified via axes[:val_axes] and axes[:cat_axis]
|
132
132
|
# @return [Axes]
|
133
133
|
def axes
|
134
|
-
@axes ||=
|
134
|
+
@axes ||= begin
|
135
|
+
a = Axes.new(cat_axis: CatAxis, val_axis: ValAxis)
|
136
|
+
|
137
|
+
if bar_dir == :col
|
138
|
+
a[:val_axis].ax_pos = :l
|
139
|
+
else
|
140
|
+
a[:cat_axis].ax_pos = :l
|
141
|
+
end
|
142
|
+
|
143
|
+
a
|
144
|
+
end
|
135
145
|
end
|
136
146
|
end
|
137
147
|
end
|
data/lib/axlsx/drawing/chart.rb
CHANGED
data/lib/axlsx/drawing/d_lbls.rb
CHANGED
@@ -9,6 +9,7 @@ module Axlsx
|
|
9
9
|
class DLbls
|
10
10
|
include Axlsx::Accessors
|
11
11
|
include Axlsx::OptionsParser
|
12
|
+
|
12
13
|
# creates a new DLbls object
|
13
14
|
def initialize(chart_type, options = {})
|
14
15
|
raise ArgumentError, 'chart_type must inherit from Chart' unless [Chart, LineChart].include?(chart_type.superclass)
|
data/lib/axlsx/package.rb
CHANGED
@@ -82,6 +82,8 @@ module Axlsx
|
|
82
82
|
# @option options [String] :zip_command When `nil`, `#serialize` with RubyZip to
|
83
83
|
# zip the XLSX file contents. When a String, the provided zip command (e.g.,
|
84
84
|
# "zip") is used to zip the file contents (may be faster for large files)
|
85
|
+
# @option options [String] :password When specified, the serialized packaged will be
|
86
|
+
# encrypted with the password. Requires ooxml_crypt gem.
|
85
87
|
# @return [Boolean] False if confirm_valid and validation errors exist. True if the package was serialized
|
86
88
|
# @note A tremendous amount of effort has gone into ensuring that you cannot create invalid xlsx documents.
|
87
89
|
# options[:confirm_valid] should be used in the rare case that you cannot open the serialized file.
|
@@ -108,7 +110,7 @@ module Axlsx
|
|
108
110
|
workbook.apply_styles
|
109
111
|
end
|
110
112
|
|
111
|
-
confirm_valid, zip_command = parse_serialize_options(options, secondary_options)
|
113
|
+
confirm_valid, zip_command, password = parse_serialize_options(options, secondary_options)
|
112
114
|
return false unless !confirm_valid || validate.empty?
|
113
115
|
|
114
116
|
zip_provider = if zip_command
|
@@ -120,15 +122,31 @@ module Axlsx
|
|
120
122
|
zip_provider.open(output) do |zip|
|
121
123
|
write_parts(zip)
|
122
124
|
end
|
125
|
+
|
126
|
+
if password && !password.empty?
|
127
|
+
require_ooxml_crypt!
|
128
|
+
OoxmlCrypt.encrypt_file(output, password, output)
|
129
|
+
end
|
130
|
+
|
123
131
|
true
|
124
132
|
ensure
|
125
133
|
Relationship.clear_ids_cache
|
126
134
|
end
|
127
135
|
|
128
136
|
# Serialize your workbook to a StringIO instance
|
129
|
-
# @param [Boolean]
|
130
|
-
#
|
131
|
-
|
137
|
+
# @param [Boolean] old_confirm_valid (Deprecated) Validate the package prior to serialization.
|
138
|
+
# Use :confirm_valid keyword arg instead.
|
139
|
+
# @option kwargs [Boolean] :confirm_valid Validate the package prior to serialization.
|
140
|
+
# @option kwargs [String] :password When specified, the serialized packaged will be
|
141
|
+
# encrypted with the password. Requires ooxml_crypt gem.
|
142
|
+
# @return [StringIO|Boolean] False if confirm_valid and validation errors exist. Rewound string IO if not.
|
143
|
+
def to_stream(old_confirm_valid = nil, confirm_valid: false, password: nil)
|
144
|
+
unless old_confirm_valid.nil?
|
145
|
+
warn "[DEPRECATION] Axlsx::Package#to_stream with confirm_valid as a non-keyword arg is deprecated. " \
|
146
|
+
"Use keyword arg instead e.g., package.to_stream(confirm_valid: false)"
|
147
|
+
confirm_valid ||= old_confirm_valid
|
148
|
+
end
|
149
|
+
|
132
150
|
unless workbook.styles_applied
|
133
151
|
workbook.apply_styles
|
134
152
|
end
|
@@ -140,6 +158,12 @@ module Axlsx
|
|
140
158
|
write_parts(zip)
|
141
159
|
end
|
142
160
|
stream.rewind
|
161
|
+
|
162
|
+
if password && !password.empty?
|
163
|
+
require_ooxml_crypt!
|
164
|
+
stream = StringIO.new(OoxmlCrypt.encrypt(stream.read, password))
|
165
|
+
end
|
166
|
+
|
143
167
|
stream
|
144
168
|
ensure
|
145
169
|
Relationship.clear_ids_cache
|
@@ -147,7 +171,7 @@ module Axlsx
|
|
147
171
|
|
148
172
|
# Encrypt the package into a CFB using the password provided
|
149
173
|
# This is not ready yet
|
150
|
-
def encrypt(file_name, password)
|
174
|
+
def encrypt(file_name, password) # rubocop:disable Naming/PredicateMethod
|
151
175
|
false
|
152
176
|
# moc = MsOffCrypto.new(file_name, password)
|
153
177
|
# moc.save
|
@@ -211,7 +235,8 @@ module Axlsx
|
|
211
235
|
# @return [Zip::Entry]
|
212
236
|
def zip_entry_for_part(part)
|
213
237
|
timestamp = Zip::DOSTime.at(@core.created.to_i)
|
214
|
-
|
238
|
+
|
239
|
+
Zip::Entry.new("", part[:entry], time: timestamp)
|
215
240
|
end
|
216
241
|
|
217
242
|
# The parts of a package
|
@@ -220,6 +245,7 @@ module Axlsx
|
|
220
245
|
def parts
|
221
246
|
parts = [
|
222
247
|
{ entry: "xl/#{STYLES_PN}", doc: workbook.styles, schema: SML_XSD },
|
248
|
+
{ entry: "xl/#{THEME_PN}", doc: workbook.theme, schema: THEME_XSD },
|
223
249
|
{ entry: CORE_PN, doc: @core, schema: CORE_XSD },
|
224
250
|
{ entry: APP_PN, doc: @app, schema: APP_XSD },
|
225
251
|
{ entry: WORKBOOK_RELS_PN, doc: workbook.relationships, schema: RELS_XSD },
|
@@ -356,6 +382,7 @@ module Axlsx
|
|
356
382
|
c_types << Override.new(PartName: "/#{APP_PN}", ContentType: APP_CT)
|
357
383
|
c_types << Override.new(PartName: "/#{CORE_PN}", ContentType: CORE_CT)
|
358
384
|
c_types << Override.new(PartName: "/xl/#{STYLES_PN}", ContentType: STYLES_CT)
|
385
|
+
c_types << Override.new(PartName: "/xl/#{THEME_PN}", ContentType: THEME_CT)
|
359
386
|
c_types << Axlsx::Override.new(PartName: "/#{WORKBOOK_PN}", ContentType: WORKBOOK_CT)
|
360
387
|
c_types.lock
|
361
388
|
c_types
|
@@ -374,8 +401,8 @@ module Axlsx
|
|
374
401
|
end
|
375
402
|
|
376
403
|
# Parse the arguments of `#serialize`
|
377
|
-
# @return [Boolean, (String or nil)] Returns
|
378
|
-
# `confirm_valid` and
|
404
|
+
# @return [Boolean, (String or nil), (String or nil)] Returns a 3-tuple where values are
|
405
|
+
# `confirm_valid`, `zip_command`, and `password`.
|
379
406
|
# @private
|
380
407
|
def parse_serialize_options(options, secondary_options)
|
381
408
|
if secondary_options
|
@@ -384,17 +411,23 @@ module Axlsx
|
|
384
411
|
end
|
385
412
|
if options.is_a?(Hash)
|
386
413
|
options.merge!(secondary_options || {})
|
387
|
-
invalid_keys = options.keys - [:confirm_valid, :zip_command]
|
414
|
+
invalid_keys = options.keys - [:confirm_valid, :zip_command, :password]
|
388
415
|
if invalid_keys.any?
|
389
416
|
raise ArgumentError, "Invalid keyword arguments: #{invalid_keys}"
|
390
417
|
end
|
391
418
|
|
392
|
-
[options.fetch(:confirm_valid, false), options.fetch(:zip_command, nil)]
|
419
|
+
[options.fetch(:confirm_valid, false), options.fetch(:zip_command, nil), options.fetch(:password, nil)]
|
393
420
|
else
|
394
421
|
warn "[DEPRECATION] Axlsx::Package#serialize with confirm_valid as a boolean is deprecated. " \
|
395
422
|
"Use keyword args instead e.g., package.serialize(output, confirm_valid: false)"
|
396
423
|
parse_serialize_options((secondary_options || {}).merge(confirm_valid: options), nil)
|
397
424
|
end
|
398
425
|
end
|
426
|
+
|
427
|
+
def require_ooxml_crypt!
|
428
|
+
return if defined?(OoxmlCrypt)
|
429
|
+
|
430
|
+
raise 'Axlsx encryption requires ooxml_crypt gem'
|
431
|
+
end
|
399
432
|
end
|
400
433
|
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Axlsx
|
4
|
+
# Theme represents the theme part of the package and is responsible for
|
5
|
+
# generating the default Office theme that is required for encryption compatibility
|
6
|
+
class Theme
|
7
|
+
# The part name of this theme
|
8
|
+
# @return [String]
|
9
|
+
def pn
|
10
|
+
THEME_PN
|
11
|
+
end
|
12
|
+
|
13
|
+
# Serializes the default theme to XML
|
14
|
+
# @param [String] str
|
15
|
+
# @return [String]
|
16
|
+
def to_xml_string(str = +'')
|
17
|
+
str << <<~XML.delete("\n")
|
18
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
19
|
+
<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">
|
20
|
+
<a:themeElements>
|
21
|
+
<a:clrScheme name="Office">
|
22
|
+
<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>
|
23
|
+
<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>
|
24
|
+
<a:dk2><a:srgbClr val="1F497D"/></a:dk2>
|
25
|
+
<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>
|
26
|
+
<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>
|
27
|
+
<a:accent2><a:srgbClr val="C0504D"/></a:accent2>
|
28
|
+
<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>
|
29
|
+
<a:accent4><a:srgbClr val="8064A2"/></a:accent4>
|
30
|
+
<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>
|
31
|
+
<a:accent6><a:srgbClr val="F79646"/></a:accent6>
|
32
|
+
<a:hlink><a:srgbClr val="0000FF"/></a:hlink>
|
33
|
+
<a:folHlink><a:srgbClr val="800080"/></a:folHlink>
|
34
|
+
</a:clrScheme>
|
35
|
+
|
36
|
+
<a:fontScheme name="Office">
|
37
|
+
<a:majorFont>
|
38
|
+
<a:latin typeface="Cambria"/>
|
39
|
+
<a:ea typeface=""/>
|
40
|
+
<a:cs typeface=""/>
|
41
|
+
</a:majorFont>
|
42
|
+
<a:minorFont>
|
43
|
+
<a:latin typeface="Calibri"/>
|
44
|
+
<a:ea typeface=""/>
|
45
|
+
<a:cs typeface=""/>
|
46
|
+
</a:minorFont>
|
47
|
+
</a:fontScheme>
|
48
|
+
|
49
|
+
<a:fmtScheme name="Office">
|
50
|
+
<a:fillStyleLst>
|
51
|
+
<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
|
52
|
+
<a:gradFill rotWithShape="1">
|
53
|
+
<a:gsLst>
|
54
|
+
<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>
|
55
|
+
<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>
|
56
|
+
<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>
|
57
|
+
</a:gsLst>
|
58
|
+
<a:lin ang="16200000" scaled="1"/>
|
59
|
+
</a:gradFill>
|
60
|
+
<a:gradFill rotWithShape="1">
|
61
|
+
<a:gsLst>
|
62
|
+
<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="100000"/><a:shade val="100000"/><a:satMod val="130000"/></a:schemeClr></a:gs>
|
63
|
+
<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="50000"/><a:shade val="100000"/><a:satMod val="350000"/></a:schemeClr></a:gs>
|
64
|
+
</a:gsLst>
|
65
|
+
<a:lin ang="16200000" scaled="false"/>
|
66
|
+
</a:gradFill>
|
67
|
+
</a:fillStyleLst>
|
68
|
+
|
69
|
+
<a:lnStyleLst>
|
70
|
+
<a:ln w="9525" cap="flat" cmpd="sng" algn="ctr">
|
71
|
+
<a:solidFill><a:schemeClr val="phClr"><a:shade val="95000"/><a:satMod val="105000"/></a:schemeClr></a:solidFill>
|
72
|
+
<a:prstDash val="solid"/>
|
73
|
+
</a:ln>
|
74
|
+
<a:ln w="25400" cap="flat" cmpd="sng" algn="ctr">
|
75
|
+
<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
|
76
|
+
<a:prstDash val="solid"/>
|
77
|
+
</a:ln>
|
78
|
+
<a:ln w="38100" cap="flat" cmpd="sng" algn="ctr">
|
79
|
+
<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
|
80
|
+
<a:prstDash val="solid"/>
|
81
|
+
</a:ln>
|
82
|
+
</a:lnStyleLst>
|
83
|
+
|
84
|
+
<a:effectStyleLst>
|
85
|
+
<a:effectStyle>
|
86
|
+
<a:effectLst>
|
87
|
+
<a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="false">
|
88
|
+
<a:srgbClr val="000000"><a:alpha val="38000"/></a:srgbClr>
|
89
|
+
</a:outerShdw>
|
90
|
+
</a:effectLst>
|
91
|
+
</a:effectStyle>
|
92
|
+
<a:effectStyle>
|
93
|
+
<a:effectLst>
|
94
|
+
<a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="false">
|
95
|
+
<a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr>
|
96
|
+
</a:outerShdw>
|
97
|
+
</a:effectLst>
|
98
|
+
</a:effectStyle>
|
99
|
+
<a:effectStyle>
|
100
|
+
<a:effectLst>
|
101
|
+
<a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="false">
|
102
|
+
<a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr>
|
103
|
+
</a:outerShdw>
|
104
|
+
</a:effectLst>
|
105
|
+
<a:scene3d>
|
106
|
+
<a:camera prst="orthographicFront"><a:rot lat="0" lon="0" rev="0"/></a:camera>
|
107
|
+
<a:lightRig rig="threePt" dir="t"><a:rot lat="0" lon="0" rev="1200000"/></a:lightRig>
|
108
|
+
</a:scene3d>
|
109
|
+
<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>
|
110
|
+
</a:effectStyle>
|
111
|
+
</a:effectStyleLst>
|
112
|
+
|
113
|
+
<a:bgFillStyleLst>
|
114
|
+
<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>
|
115
|
+
<a:gradFill rotWithShape="1">
|
116
|
+
<a:gsLst>
|
117
|
+
<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>
|
118
|
+
<a:gs pos="40000"><a:schemeClr val="phClr"><a:tint val="45000"/><a:shade val="99000"/><a:satMod val="350000"/></a:schemeClr></a:gs>
|
119
|
+
<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>
|
120
|
+
</a:gsLst>
|
121
|
+
<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>
|
122
|
+
</a:gradFill>
|
123
|
+
<a:gradFill rotWithShape="1">
|
124
|
+
<a:gsLst>
|
125
|
+
<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>
|
126
|
+
<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>
|
127
|
+
</a:gsLst>
|
128
|
+
<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>
|
129
|
+
</a:gradFill>
|
130
|
+
</a:bgFillStyleLst>
|
131
|
+
</a:fmtScheme>
|
132
|
+
</a:themeElements>
|
133
|
+
|
134
|
+
<a:objectDefaults>
|
135
|
+
<a:spDef>
|
136
|
+
<a:spPr/>
|
137
|
+
<a:bodyPr/>
|
138
|
+
<a:lstStyle/>
|
139
|
+
<a:style>
|
140
|
+
<a:lnRef idx="1"><a:schemeClr val="accent1"/></a:lnRef>
|
141
|
+
<a:fillRef idx="3"><a:schemeClr val="accent1"/></a:fillRef>
|
142
|
+
<a:effectRef idx="2"><a:schemeClr val="accent1"/></a:effectRef>
|
143
|
+
<a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef>
|
144
|
+
</a:style>
|
145
|
+
</a:spDef>
|
146
|
+
<a:lnDef>
|
147
|
+
<a:spPr/>
|
148
|
+
<a:bodyPr/>
|
149
|
+
<a:lstStyle/>
|
150
|
+
<a:style>
|
151
|
+
<a:lnRef idx="2"><a:schemeClr val="accent1"/></a:lnRef>
|
152
|
+
<a:fillRef idx="0"><a:schemeClr val="accent1"/></a:fillRef>
|
153
|
+
<a:effectRef idx="1"><a:schemeClr val="accent1"/></a:effectRef>
|
154
|
+
<a:fontRef idx="minor"><a:schemeClr val="tx1"/></a:fontRef>
|
155
|
+
</a:style>
|
156
|
+
</a:lnDef>
|
157
|
+
</a:objectDefaults>
|
158
|
+
<a:extraClrSchemeLst/>
|
159
|
+
</a:theme>
|
160
|
+
XML
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/lib/axlsx/stylesheet/xf.rb
CHANGED
@@ -19,7 +19,7 @@ module Axlsx
|
|
19
19
|
#
|
20
20
|
# The directory and its contents are removed at the end of the block.
|
21
21
|
def self.open(file_name, encrypter = nil)
|
22
|
-
Zip::OutputStream.open(file_name, encrypter) do |zos|
|
22
|
+
Zip::OutputStream.open(file_name, encrypter: encrypter) do |zos|
|
23
23
|
bzos = new(zos)
|
24
24
|
yield(bzos)
|
25
25
|
ensure
|
@@ -28,7 +28,7 @@ module Axlsx
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.write_buffer(io = ::StringIO.new, encrypter = nil)
|
31
|
-
Zip::OutputStream.write_buffer(io, encrypter) do |zos|
|
31
|
+
Zip::OutputStream.write_buffer(io, encrypter: encrypter) do |zos|
|
32
32
|
bzos = new(zos)
|
33
33
|
yield(bzos)
|
34
34
|
ensure
|
data/lib/axlsx/util/constants.rb
CHANGED
@@ -79,6 +79,9 @@ module Axlsx
|
|
79
79
|
# shared strings namespace
|
80
80
|
SHARED_STRINGS_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
|
81
81
|
|
82
|
+
# theme rels namespace
|
83
|
+
THEME_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
|
84
|
+
|
82
85
|
# drawing rels namespace
|
83
86
|
DRAWING_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
|
84
87
|
|
@@ -133,6 +136,9 @@ module Axlsx
|
|
133
136
|
# shared strings content type
|
134
137
|
SHARED_STRINGS_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"
|
135
138
|
|
139
|
+
# theme content type
|
140
|
+
THEME_CT = "application/vnd.openxmlformats-officedocument.theme+xml"
|
141
|
+
|
136
142
|
# core content type
|
137
143
|
CORE_CT = "application/vnd.openxmlformats-package.core-properties+xml"
|
138
144
|
|
@@ -187,6 +193,9 @@ module Axlsx
|
|
187
193
|
# shared_strings part
|
188
194
|
SHARED_STRINGS_PN = "sharedStrings.xml"
|
189
195
|
|
196
|
+
# theme part
|
197
|
+
THEME_PN = "theme/theme1.xml"
|
198
|
+
|
190
199
|
# app part
|
191
200
|
APP_PN = "docProps/app.xml"
|
192
201
|
|
@@ -259,6 +268,9 @@ module Axlsx
|
|
259
268
|
# drawing validation schema
|
260
269
|
DRAWING_XSD = "#{SCHEMA_BASE}dml-spreadsheetDrawing.xsd"
|
261
270
|
|
271
|
+
# theme validation schema
|
272
|
+
THEME_XSD = "#{SCHEMA_BASE}dml-main.xsd"
|
273
|
+
|
262
274
|
# number format id for percentage formatting using the default formatting id.
|
263
275
|
NUM_FMT_PERCENT = 9
|
264
276
|
|
@@ -1,22 +1,81 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'open-uri'
|
4
|
-
|
5
3
|
module Axlsx
|
6
4
|
# This module defines some utils related with mime type detection
|
7
5
|
module MimeTypeUtils
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
# Extension to MIME type mapping for Windows fallback
|
7
|
+
EXTENSION_FALLBACKS = {
|
8
|
+
'.jpg' => 'image/jpeg',
|
9
|
+
'.jpeg' => 'image/jpeg',
|
10
|
+
'.png' => 'image/png',
|
11
|
+
'.gif' => 'image/gif'
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# Detect a file mime type
|
16
|
+
# @param [String] v File path
|
17
|
+
# @return [String] File mime type
|
18
|
+
def get_mime_type(v)
|
19
|
+
mime_type = Marcel::MimeType.for(Pathname.new(v))
|
20
|
+
|
21
|
+
# Windows fallback: Marcel sometimes returns application/octet-stream for valid image files
|
22
|
+
if mime_type == 'application/octet-stream' && windows_platform?
|
23
|
+
extension = File.extname(v).downcase
|
24
|
+
# Verify it's actually an image by checking the file header
|
25
|
+
if EXTENSION_FALLBACKS.key?(extension) && File.exist?(v) && valid_image_file?(v, extension)
|
26
|
+
mime_type = EXTENSION_FALLBACKS[extension]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
mime_type
|
31
|
+
end
|
32
|
+
|
33
|
+
# Detect a file mime type from URI
|
34
|
+
# @param [String] v URI
|
35
|
+
# @return [String] File mime type
|
36
|
+
def get_mime_type_from_uri(v)
|
37
|
+
uri = URI.parse(v)
|
38
|
+
|
39
|
+
unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
|
40
|
+
raise URI::InvalidURIError, "Only HTTP/HTTPS URIs are supported"
|
41
|
+
end
|
42
|
+
|
43
|
+
response = UriUtils.fetch_headers(uri)
|
44
|
+
mime_type = response&.[]('content-type')&.split(';')&.first&.strip
|
45
|
+
|
46
|
+
if mime_type.nil? || mime_type.empty?
|
47
|
+
raise ArgumentError, "Unable to determine MIME type from response"
|
48
|
+
end
|
49
|
+
|
50
|
+
mime_type
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def windows_platform?
|
56
|
+
RUBY_PLATFORM =~ /mswin|mingw|cygwin/
|
57
|
+
end
|
58
|
+
|
59
|
+
def valid_image_file?(file_path, extension)
|
60
|
+
return false unless File.exist?(file_path)
|
14
61
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
62
|
+
# Check magic bytes for common image formats
|
63
|
+
begin
|
64
|
+
header = File.binread(file_path, 10)
|
65
|
+
case extension
|
66
|
+
when '.jpg', '.jpeg'
|
67
|
+
header[0..2].bytes == [0xFF, 0xD8, 0xFF] # JPEG magic bytes
|
68
|
+
when '.png'
|
69
|
+
header[0..7].bytes == [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A] # PNG magic bytes
|
70
|
+
when '.gif'
|
71
|
+
header[0..2] == 'GIF' # GIF magic bytes
|
72
|
+
else
|
73
|
+
false
|
74
|
+
end
|
75
|
+
rescue StandardError
|
76
|
+
false
|
77
|
+
end
|
78
|
+
end
|
20
79
|
end
|
21
80
|
end
|
22
81
|
end
|
@@ -183,8 +183,7 @@ module Axlsx
|
|
183
183
|
end
|
184
184
|
|
185
185
|
def to_xml_string(str = +'')
|
186
|
-
|
187
|
-
el_name = serialize_as.to_s || (classname[0, 1].downcase + classname[1..])
|
186
|
+
el_name = serialize_as.to_s
|
188
187
|
str << '<' << el_name << ' count="' << size.to_s << '">'
|
189
188
|
each { |item| item.to_xml_string(str) }
|
190
189
|
str << '</' << el_name << '>'
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Axlsx
|
7
|
+
# This module defines some utils related to mime type detection
|
8
|
+
module UriUtils
|
9
|
+
class << self
|
10
|
+
# Performs an HTTP GeT request fetching only headers
|
11
|
+
def fetch_headers(uri, redirect_limit = 5)
|
12
|
+
redirect_count = 0
|
13
|
+
use_get = false
|
14
|
+
|
15
|
+
while redirect_count < redirect_limit
|
16
|
+
case (response = fetch_headers_request(uri, use_get: use_get))
|
17
|
+
when Net::HTTPSuccess
|
18
|
+
return response
|
19
|
+
when Net::HTTPMethodNotAllowed, Net::HTTPNotImplemented
|
20
|
+
fail_response(response) if use_get
|
21
|
+
use_get = true
|
22
|
+
next # Retry current URL with GET
|
23
|
+
when Net::HTTPRedirection
|
24
|
+
uri = follow_redirect(uri, response)
|
25
|
+
redirect_count += 1
|
26
|
+
else
|
27
|
+
fail_response(response)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
raise ArgumentError, "Too many redirects (exceeded #{redirect_limit})"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def fetch_headers_request(uri, use_get: false)
|
37
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
38
|
+
path = build_path(uri)
|
39
|
+
if use_get
|
40
|
+
http.request_get(path) { |response| break(response) } # Exit early with just headers
|
41
|
+
else
|
42
|
+
http.head(path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_path(uri)
|
48
|
+
"#{uri.path.empty? ? '/' : uri.path}#{"?#{uri.query}" if uri.query}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def follow_redirect(original_uri, response)
|
52
|
+
location = response['location']
|
53
|
+
|
54
|
+
if location.nil? || location.empty?
|
55
|
+
raise ArgumentError, "Redirect response missing Location header"
|
56
|
+
end
|
57
|
+
|
58
|
+
if location.start_with?('http://', 'https://')
|
59
|
+
URI.parse(location)
|
60
|
+
else
|
61
|
+
URI.join(original_uri, location)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def fail_response(response)
|
66
|
+
raise ArgumentError, "Failed to fetch resource: #{response.code} #{response.message}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -9,7 +9,7 @@ module Axlsx
|
|
9
9
|
# @param [Any] v The value to be validated
|
10
10
|
# @raise [ArgumentError] Raised if the value provided is not in the list of choices.
|
11
11
|
# @return [Boolean] true if validation succeeds.
|
12
|
-
def self.validate(name, choices, v)
|
12
|
+
def self.validate(name, choices, v) # rubocop:disable Naming/PredicateMethod
|
13
13
|
raise ArgumentError, format(ERR_RESTRICTION, v.to_s, name, choices.inspect) unless choices.include?(v)
|
14
14
|
|
15
15
|
true
|
@@ -268,19 +268,19 @@ module Axlsx
|
|
268
268
|
RestrictionValidator.validate :vertical_alignment, VALID_VERTICAL_ALIGNMENT_VALUES, v
|
269
269
|
end
|
270
270
|
|
271
|
-
VALID_CONTENT_TYPE_VALUES = [TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, JPEG_CT, GIF_CT, PNG_CT, DRAWING_CT, COMMENT_CT, VML_DRAWING_CT, PIVOT_TABLE_CT, PIVOT_TABLE_CACHE_DEFINITION_CT].freeze
|
271
|
+
VALID_CONTENT_TYPE_VALUES = [TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, THEME_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, JPEG_CT, GIF_CT, PNG_CT, DRAWING_CT, COMMENT_CT, VML_DRAWING_CT, PIVOT_TABLE_CT, PIVOT_TABLE_CACHE_DEFINITION_CT].freeze
|
272
272
|
|
273
273
|
# Requires that the value is a valid content_type
|
274
|
-
# TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, DRAWING_CT, COMMENT_CT are allowed
|
274
|
+
# TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, THEME_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, DRAWING_CT, COMMENT_CT are allowed
|
275
275
|
# @param [Any] v The value validated
|
276
276
|
def self.validate_content_type(v)
|
277
277
|
RestrictionValidator.validate :content_type, VALID_CONTENT_TYPE_VALUES, v
|
278
278
|
end
|
279
279
|
|
280
|
-
VALID_RELATIONSHIP_TYPE_VALUES = [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, SHARED_STRINGS_R, COMMENT_R, VML_DRAWING_R, COMMENT_R_NULL, PIVOT_TABLE_R, PIVOT_TABLE_CACHE_DEFINITION_R].freeze
|
280
|
+
VALID_RELATIONSHIP_TYPE_VALUES = [XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, THEME_R, CHART_R, DRAWING_R, IMAGE_R, HYPERLINK_R, SHARED_STRINGS_R, COMMENT_R, VML_DRAWING_R, COMMENT_R_NULL, PIVOT_TABLE_R, PIVOT_TABLE_CACHE_DEFINITION_R].freeze
|
281
281
|
|
282
282
|
# Requires that the value is a valid relationship_type
|
283
|
-
# 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, SHARED_STRINGS_R are allowed
|
283
|
+
# XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, THEME_R, CHART_R, DRAWING_R, IMAGE_R, HYPERLINK_R, SHARED_STRINGS_R are allowed
|
284
284
|
# @param [Any] v The value validated
|
285
285
|
def self.validate_relationship_type(v)
|
286
286
|
RestrictionValidator.validate :relationship_type, VALID_RELATIONSHIP_TYPE_VALUES, v
|
data/lib/axlsx/version.rb
CHANGED
@@ -54,6 +54,7 @@ module Axlsx
|
|
54
54
|
include Axlsx::SerializedAttributes
|
55
55
|
include Axlsx::OptionsParser
|
56
56
|
include Axlsx::Accessors
|
57
|
+
|
57
58
|
# creates a new DefinedName.
|
58
59
|
# @param [String] formula - the formula the defined name references
|
59
60
|
# @param [Hash] options - A hash of key/value pairs that will be mapped to this instances attributes.
|
@@ -184,6 +184,12 @@ module Axlsx
|
|
184
184
|
@styles
|
185
185
|
end
|
186
186
|
|
187
|
+
# The theme associated with this workbook
|
188
|
+
# @return [Theme]
|
189
|
+
def theme
|
190
|
+
@theme ||= Theme.new
|
191
|
+
end
|
192
|
+
|
187
193
|
# An array that holds all cells with styles
|
188
194
|
# @return Set
|
189
195
|
def styled_cells
|
@@ -373,6 +379,7 @@ module Axlsx
|
|
373
379
|
r << Relationship.new(pivot_table.cache_definition, PIVOT_TABLE_CACHE_DEFINITION_R, format(PIVOT_TABLE_CACHE_DEFINITION_PN, index + 1))
|
374
380
|
end
|
375
381
|
r << Relationship.new(self, STYLES_R, STYLES_PN)
|
382
|
+
r << Relationship.new(self, THEME_R, THEME_PN)
|
376
383
|
if use_shared_strings
|
377
384
|
r << Relationship.new(self, SHARED_STRINGS_R, SHARED_STRINGS_PN)
|
378
385
|
end
|
@@ -38,7 +38,7 @@ module Axlsx
|
|
38
38
|
# @option [Boolean] show_horizontal_scroll Specifies a boolean value that indicates whether to display the horizontal scroll bar in the user interface.
|
39
39
|
# @option [Boolean] show_vertical_scroll Specifies a boolean value that indicates whether to display the vertical scroll bar.
|
40
40
|
# @option [Boolean] show_sheet_tabs Specifies a boolean value that indicates whether to display the sheet tabs in the user interface.
|
41
|
-
# @option [Integer] tab_ratio Specifies ratio between the workbook tabs bar and the horizontal scroll bar.
|
41
|
+
# @option [Integer] tab_ratio Specifies the ratio between the workbook tabs bar and the horizontal scroll bar (from 0 to 1000, higher values mean more space for tabs). May only be supported on some clients.
|
42
42
|
# @option [Integer] first_sheet Specifies the index to the first sheet in this book view.
|
43
43
|
# @option [Integer] active_tab Specifies an unsignedInt that contains the index to the active sheet in this book view.
|
44
44
|
# @option [Integer] x_window Specifies the X coordinate for the upper left corner of the workbook window. The unit of measurement for this value is twips.
|
@@ -41,7 +41,7 @@ module Axlsx
|
|
41
41
|
# date_group_items restrictions.
|
42
42
|
# @param [Cell] cell The cell to test against items
|
43
43
|
# TODO implement this for date filters as well!
|
44
|
-
def apply(cell)
|
44
|
+
def apply(cell) # rubocop:disable Naming/PredicateMethod
|
45
45
|
return false unless cell
|
46
46
|
|
47
47
|
filter_items.each do |filter|
|
@@ -166,7 +166,7 @@ module Axlsx
|
|
166
166
|
|
167
167
|
# Indicates that the cell has one or more of the custom cell styles applied.
|
168
168
|
# @return [Boolean]
|
169
|
-
def is_text_run? # rubocop:disable Naming/
|
169
|
+
def is_text_run? # rubocop:disable Naming/PredicatePrefix
|
170
170
|
defined?(@is_text_run) && @is_text_run && !contains_rich_text?
|
171
171
|
end
|
172
172
|
|
@@ -410,13 +410,13 @@ module Axlsx
|
|
410
410
|
CellSerializer.to_xml_string r_index, c_index, self, str
|
411
411
|
end
|
412
412
|
|
413
|
-
def is_formula? # rubocop:disable Naming/
|
413
|
+
def is_formula? # rubocop:disable Naming/PredicatePrefix
|
414
414
|
return false if escape_formulas
|
415
415
|
|
416
416
|
type == :string && @value.to_s.start_with?(FORMULA_PREFIX)
|
417
417
|
end
|
418
418
|
|
419
|
-
def is_array_formula? # rubocop:disable Naming/
|
419
|
+
def is_array_formula? # rubocop:disable Naming/PredicatePrefix
|
420
420
|
return false if escape_formulas
|
421
421
|
|
422
422
|
type == :string &&
|
@@ -7,7 +7,7 @@ module Axlsx
|
|
7
7
|
# of plain text and control characters. A fairly comprehensive list of control
|
8
8
|
# characters can be found here:
|
9
9
|
# https://github.com/randym/axlsx/blob/master/notes_on_header_footer.md
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# @note The recommended way of managing header/footers is via Worksheet#header_footer
|
12
12
|
# @see Worksheet#initialize
|
13
13
|
class HeaderFooter
|
@@ -343,7 +343,7 @@ module Axlsx
|
|
343
343
|
attributes << 'dataField="1"'
|
344
344
|
end
|
345
345
|
|
346
|
-
"<pivotField #{attributes.join(' ')}>#{
|
346
|
+
"<pivotField #{attributes.join(' ')}>#{items_tag if include_items_tag}</pivotField>"
|
347
347
|
end
|
348
348
|
|
349
349
|
def data_refs
|
@@ -10,6 +10,7 @@ module Axlsx
|
|
10
10
|
include Axlsx::OptionsParser
|
11
11
|
include Axlsx::SerializedAttributes
|
12
12
|
include Axlsx::Accessors
|
13
|
+
|
13
14
|
# Creates a new PrintOptions object
|
14
15
|
# @option options [Boolean] grid_lines Whether grid lines should be printed
|
15
16
|
# @option options [Boolean] headings Whether row and column headings should be printed
|
@@ -37,7 +37,7 @@ module Axlsx
|
|
37
37
|
|
38
38
|
# Helper method to tell us if there are comments in the comments collection
|
39
39
|
# @return [Boolean]
|
40
|
-
def has_comments? # rubocop:disable Naming/
|
40
|
+
def has_comments? # rubocop:disable Naming/PredicatePrefix
|
41
41
|
!comments.empty?
|
42
42
|
end
|
43
43
|
|
@@ -42,7 +42,7 @@ module Axlsx
|
|
42
42
|
|
43
43
|
# helper method to tell us if the drawing has something in it or not
|
44
44
|
# @return [Boolean]
|
45
|
-
def has_drawing? # rubocop:disable Naming/
|
45
|
+
def has_drawing? # rubocop:disable Naming/PredicatePrefix
|
46
46
|
@drawing.is_a? Drawing
|
47
47
|
end
|
48
48
|
|
@@ -6,6 +6,7 @@ module Axlsx
|
|
6
6
|
include Axlsx::OptionsParser
|
7
7
|
include Axlsx::Accessors
|
8
8
|
include Axlsx::SerializedAttributes
|
9
|
+
|
9
10
|
# Creates a new hyperlink object.
|
10
11
|
# @note the preferred way to add hyperlinks to your worksheet is the Worksheet#add_hyperlink method
|
11
12
|
# @param [Worksheet] worksheet the Worksheet that owns this hyperlink
|
data/lib/axlsx.rb
CHANGED
@@ -13,6 +13,7 @@ require 'cgi'
|
|
13
13
|
require 'set'
|
14
14
|
require 'time'
|
15
15
|
require 'uri'
|
16
|
+
require 'net/http'
|
16
17
|
|
17
18
|
require_relative 'axlsx/util/simple_typed_list'
|
18
19
|
require_relative 'axlsx/util/constants'
|
@@ -20,6 +21,7 @@ require_relative 'axlsx/util/validators'
|
|
20
21
|
require_relative 'axlsx/util/accessors'
|
21
22
|
require_relative 'axlsx/util/serialized_attributes'
|
22
23
|
require_relative 'axlsx/util/options_parser'
|
24
|
+
require_relative 'axlsx/util/uri_utils'
|
23
25
|
require_relative 'axlsx/util/mime_type_utils'
|
24
26
|
require_relative 'axlsx/util/buffered_zip_output_stream'
|
25
27
|
require_relative 'axlsx/util/zip_command'
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: caxlsx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Randy Morgan
|
8
8
|
- Jurriaan Pruis
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: htmlentities
|
@@ -71,20 +70,20 @@ dependencies:
|
|
71
70
|
requirements:
|
72
71
|
- - ">="
|
73
72
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
73
|
+
version: '2.4'
|
75
74
|
- - "<"
|
76
75
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
76
|
+
version: '4'
|
78
77
|
type: :runtime
|
79
78
|
prerelease: false
|
80
79
|
version_requirements: !ruby/object:Gem::Requirement
|
81
80
|
requirements:
|
82
81
|
- - ">="
|
83
82
|
- !ruby/object:Gem::Version
|
84
|
-
version:
|
83
|
+
version: '2.4'
|
85
84
|
- - "<"
|
86
85
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
86
|
+
version: '4'
|
88
87
|
description: 'xlsx spreadsheet generation with charts, images, automated column width,
|
89
88
|
customizable styles and full schema validation. Axlsx helps you create beautiful
|
90
89
|
Office Open XML Spreadsheet documents (Excel, Google Spreadsheets, Numbers, LibreOffice)
|
@@ -177,6 +176,7 @@ files:
|
|
177
176
|
- lib/axlsx/stylesheet/table_style.rb
|
178
177
|
- lib/axlsx/stylesheet/table_style_element.rb
|
179
178
|
- lib/axlsx/stylesheet/table_styles.rb
|
179
|
+
- lib/axlsx/stylesheet/theme.rb
|
180
180
|
- lib/axlsx/stylesheet/xf.rb
|
181
181
|
- lib/axlsx/util/accessors.rb
|
182
182
|
- lib/axlsx/util/buffered_zip_output_stream.rb
|
@@ -186,6 +186,7 @@ files:
|
|
186
186
|
- lib/axlsx/util/serialized_attributes.rb
|
187
187
|
- lib/axlsx/util/simple_typed_list.rb
|
188
188
|
- lib/axlsx/util/storage.rb
|
189
|
+
- lib/axlsx/util/uri_utils.rb
|
189
190
|
- lib/axlsx/util/validators.rb
|
190
191
|
- lib/axlsx/util/zip_command.rb
|
191
192
|
- lib/axlsx/version.rb
|
@@ -297,7 +298,6 @@ metadata:
|
|
297
298
|
changelog_uri: https://github.com/caxlsx/caxlsx/blob/master/CHANGELOG.md
|
298
299
|
source_code_uri: https://github.com/caxlsx/caxlsx
|
299
300
|
rubygems_mfa_required: 'true'
|
300
|
-
post_install_message:
|
301
301
|
rdoc_options: []
|
302
302
|
require_paths:
|
303
303
|
- lib
|
@@ -312,8 +312,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
312
312
|
- !ruby/object:Gem::Version
|
313
313
|
version: '0'
|
314
314
|
requirements: []
|
315
|
-
rubygems_version: 3.
|
316
|
-
signing_key:
|
315
|
+
rubygems_version: 3.6.9
|
317
316
|
specification_version: 4
|
318
317
|
summary: Excel OOXML (xlsx) with charts, styles, images and autowidth columns.
|
319
318
|
test_files: []
|