spreadsheet_architect 3.3.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +46 -58
- data/lib/spreadsheet_architect/axlsx_string_width_patch.rb +21 -0
- data/lib/spreadsheet_architect/class_methods/xlsx.rb +49 -1
- data/lib/spreadsheet_architect/utils.rb +41 -2
- data/lib/spreadsheet_architect/utils/xlsx.rb +2 -13
- data/lib/spreadsheet_architect/version.rb +1 -1
- data/test/dummy_app/config/application.rb +1 -4
- data/test/dummy_app/db/test.sqlite3 +0 -0
- data/test/dummy_app/log/test.log +107293 -8605
- data/test/dummy_app/tmp/2.0.1/integration/alt_xlsx.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/integration/csv.csv +6 -0
- data/test/dummy_app/tmp/2.0.1/integration/ods.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/integration/xlsx.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/kitchen_sink.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/kitchen_sink.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/data.csv +3 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/data.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/empty.csv +1 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/empty.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/instances.csv +6 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/instances.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/data.csv +3 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/data.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/data.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/empty.csv +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/empty.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/empty.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/instances.csv +6 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/instances.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/instances.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/data.csv +3 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/data.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/data.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/empty.csv +1 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/empty.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/empty.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/instances.csv +6 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/instances.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/CustomPost/instances.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/data.csv +3 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/data.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/empty.csv +1 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/empty.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/instances.csv +6 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/instances.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/data.csv +3 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/data.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/empty.csv +1 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/empty.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/instances.csv +6 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/instances.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/data.csv +3 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/data.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/data.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/empty.csv +0 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/empty.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/empty.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/instances.csv +6 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/instances.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/models/Post/instances.xlsx +0 -0
- data/test/dummy_app/tmp/2.0.1/multi_sheet.ods +0 -0
- data/test/dummy_app/tmp/2.0.1/multi_sheet.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/integration/alt_xlsx.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/integration/csv.csv +5 -5
- data/test/dummy_app/tmp/3.0.0.pre/integration/ods.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/integration/xlsx.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/kitchen_sink.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/kitchen_sink.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/data.csv +1 -1
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/data.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/empty.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/instances.csv +5 -5
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/instances.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/data.csv +1 -1
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/data.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/data.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/empty.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/empty.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/instances.csv +5 -5
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/instances.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/instances.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/data.csv +1 -1
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/data.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/data.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/empty.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/empty.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/instances.csv +5 -5
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/instances.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/instances.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/data.csv +1 -1
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/data.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/empty.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/instances.csv +5 -5
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/instances.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/data.csv +1 -1
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/data.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/empty.csv +0 -1
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/empty.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/instances.csv +5 -5
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/instances.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/data.csv +1 -1
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/data.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/data.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/empty.csv +1 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/empty.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/empty.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/instances.csv +5 -5
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/instances.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/models/Post/instances.xlsx +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/multi_sheet.ods +0 -0
- data/test/dummy_app/tmp/3.0.0.pre/multi_sheet.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/integration/alt_xlsx.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/integration/csv.csv +6 -0
- data/test/dummy_app/tmp/axlsx-master/integration/ods.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/integration/xlsx.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/kitchen_sink.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/kitchen_sink.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/data.csv +4 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/data.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/empty.csv +1 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/empty.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/instances.csv +6 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/instances.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/data.csv +4 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/data.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/data.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/empty.csv +1 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/empty.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/empty.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/instances.csv +6 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/instances.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/instances.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/data.csv +4 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/data.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/data.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/empty.csv +1 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/empty.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/empty.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/instances.csv +6 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/instances.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/CustomPost/instances.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/data.csv +4 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/data.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/empty.csv +1 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/empty.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/instances.csv +6 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/instances.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/data.csv +4 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/data.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/data.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/empty.csv +1 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/empty.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/empty.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/instances.csv +6 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/instances.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/instances.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/data.csv +4 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/data.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/data.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/empty.csv +1 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/empty.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/empty.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/instances.csv +6 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/instances.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/models/Post/instances.xlsx +0 -0
- data/test/dummy_app/tmp/axlsx-master/multi_sheet.ods +0 -0
- data/test/dummy_app/tmp/axlsx-master/multi_sheet.xlsx +0 -0
- data/test/test_helper.rb +5 -7
- data/test/unit/exceptions_test.rb +4 -0
- data/test/unit/kitchen_sink_test.rb +6 -5
- data/test/unit/utils_test.rb +33 -2
- data/test/unit/xlsx_freeze_test.rb +44 -0
- data/test/unit/xlsx_utils_test.rb +0 -21
- metadata +354 -106
- data/lib/spreadsheet_architect/monkey_patches/axlsx_column_width.rb +0 -56
- data/test/custom_assertions.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64bcbae2181e3941b235d571b72bc217c5161c558075b2839376590e88e1ff74
|
4
|
+
data.tar.gz: 3c1d88c58d960945e7ca89266e57cf39bfc1b50259133dd4b31064398cba24a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ef5eff17a279f7235617000780bf6c1fae69f8c4a7a034567821cb836a9417a20716f38aa4632720d32d1f461f503fca0f5c4563566f5fe23ccb49b1e676dcd
|
7
|
+
data.tar.gz: 41e889c83d74da214d9eddc7c7eafb00d9c170e391be1ad6aa1cc3000c06b3c804e28c80c15d957b57639036cd5c37cdefcf86d9703074405378276654bf0c9b
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,15 @@ CHANGELOG
|
|
2
2
|
---------
|
3
3
|
|
4
4
|
- **Unreleased**
|
5
|
-
- Nothing
|
5
|
+
- Nothing yet
|
6
|
+
- **4.0.0**
|
7
|
+
- Switch to the `caxlsx` gem (Community Axlsx) from the legacy unmaintained `axlsx` gem. Axlsx has had a long history of being poorly maintained so this community gem improves the situation.
|
8
|
+
- Require Ruby 2.3+
|
9
|
+
- Ensure all options using Hash are automatically converted to symbol only hashes
|
10
|
+
- Add XLSX option `:freeze` to freeze custom sections of your spreadsheet
|
11
|
+
- Add XLSX option `:freeze_headers` to freeze the headers of your spreadsheet
|
12
|
+
- Remove old Axlsx patch for column width
|
13
|
+
- Backport new code for `string_width` calculations to Axlsx 3.0.1 and below.
|
6
14
|
- **3.3.1**
|
7
15
|
- [Issue #30](https://github.com/westonganger/spreadsheet_architect/issues/30) - Fix duplicate constant warning for XLSX_COLUMN_TYPES
|
8
16
|
- **3.3.0**
|
data/README.md
CHANGED
@@ -26,6 +26,8 @@ gem 'spreadsheet_architect'
|
|
26
26
|
|
27
27
|
### Tabular (Array) Data
|
28
28
|
|
29
|
+
The simplest and preffered usage is to simply create the data array yourself.
|
30
|
+
|
29
31
|
```ruby
|
30
32
|
headers = ['Col 1','Col 2','Col 3']
|
31
33
|
data = [[1,2,3], [4,5,6], [7,8,9]]
|
@@ -34,50 +36,25 @@ SpreadsheetArchitect.to_ods(headers: headers, data: data)
|
|
34
36
|
SpreadsheetArchitect.to_csv(headers: headers, data: data)
|
35
37
|
```
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
```ruby
|
40
|
-
posts = Post.order(name: :asc).where(published: true)
|
41
|
-
# OR
|
42
|
-
posts = 10.times.map{|i| Post.new(number: i)}
|
39
|
+
Using this style will allow you to utilize any custom performance optimizations during your data generation process. This will come in handy when the spreadsheets get large and things start to get slow. One of my favourites for Rails is [light_record](https://github.com/Paxa/light_record)
|
43
40
|
|
44
|
-
|
45
|
-
SpreadsheetArchitect.to_ods(instances: posts)
|
46
|
-
SpreadsheetArchitect.to_csv(instances: posts)
|
47
|
-
```
|
41
|
+
### Rails Relations or an Array of plain Ruby object instances
|
48
42
|
|
49
|
-
|
43
|
+
If you would like to add the methods `to_xlsx`, `to_ods`, `to_csv`, `to_axlsx_package`, `to_rodf_spreadsheet` to some class, you can simply include the SpreadsheetArchitect module to whichever classes you choose. A good default strategy is to simply add it to the ApplicationRecord or another parent class to have it available on all appropriate classes. For example:
|
50
44
|
|
51
45
|
```ruby
|
52
|
-
class
|
46
|
+
class Post < ApplicationRecord
|
53
47
|
include SpreadsheetArchitect
|
54
48
|
end
|
55
49
|
```
|
56
50
|
|
57
|
-
|
58
|
-
|
59
|
-
```ruby
|
60
|
-
posts = Post.order(name: :asc).where(published: true)
|
61
|
-
posts.to_xlsx
|
62
|
-
posts.to_ods
|
63
|
-
posts.to_csv
|
64
|
-
|
65
|
-
# Plain Ruby Objects
|
66
|
-
posts_array = 10.times.map{|i| Post.new(number: i)}
|
67
|
-
Post.to_xlsx(instances: posts_array)
|
68
|
-
Post.to_ods(instances: posts_array)
|
69
|
-
Post.to_csv(instances: posts_array)
|
70
|
-
```
|
71
|
-
|
72
|
-
# Usage with Instances / ActiveRecord Relations
|
73
|
-
|
74
|
-
When NOT using the `:data` option, ie. on an AR Relation or using the `:instances` option, Spreadsheet Architect requires an instance method defined on the class to generate the data. It looks for the `spreadsheet_columns` method on the class. If you are using on an ActiveRecord model and that method is not defined, it would fallback to the models `column_names` method (not recommended). If using the `:data` option this is ignored.
|
51
|
+
When using on an AR Relation or using the `:instances` option, SpreadsheetArchitect requires an instance method to be defined on the class to generate the data. By default it looks for the `spreadsheet_columns` method on the class. If you are using on an ActiveRecord model and that method is not defined, it would fallback to the models `column_names` method. If using the `:data` option this is completely ignored.
|
75
52
|
|
76
53
|
```ruby
|
77
54
|
class Post
|
55
|
+
include SpreadsheetArchitect
|
78
56
|
|
79
57
|
def spreadsheet_columns
|
80
|
-
|
81
58
|
### Column format is: [Header, Cell Data / Method (if symbol) to Call on each Instance, (optional) Cell Type]
|
82
59
|
[
|
83
60
|
['Title', :title],
|
@@ -89,15 +66,30 @@ class Post
|
|
89
66
|
['Rating', :rating],
|
90
67
|
['Category/Tags', "#{category.name} - #{tags.collect(&:name).join(', ')}"]
|
91
68
|
]
|
69
|
+
end
|
70
|
+
|
92
71
|
end
|
72
|
+
```
|
73
|
+
|
74
|
+
Then use it on the class or ActiveRecord relations of the class
|
93
75
|
|
94
|
-
|
76
|
+
```ruby
|
77
|
+
posts = Post.order(name: :asc).where(published: true)
|
78
|
+
posts.to_xlsx
|
79
|
+
posts.to_ods
|
80
|
+
posts.to_csv
|
81
|
+
|
82
|
+
# Plain Ruby Objects
|
83
|
+
posts_array = 10.times.map{|i| Post.new(number: i)}
|
84
|
+
Post.to_xlsx(instances: posts_array)
|
85
|
+
Post.to_ods(instances: posts_array)
|
86
|
+
Post.to_csv(instances: posts_array)
|
95
87
|
```
|
96
88
|
|
97
|
-
If you want to use a different method name then `spreadsheet_columns` you can pass a method name
|
89
|
+
If you want to use a different method name then `spreadsheet_columns` you can pass a method name to the `:spreadsheet_columns` option.
|
98
90
|
|
99
91
|
```ruby
|
100
|
-
Post.to_xlsx(instances: posts, spreadsheet_columns: :
|
92
|
+
Post.to_xlsx(instances: posts, spreadsheet_columns: :my_special_method)
|
101
93
|
```
|
102
94
|
|
103
95
|
Alternatively, you can pass a Proc/lambda to the `spreadsheet_columns` option. For those purists that really dont want to define any extra `spreadsheet_columns` instance method on your model, this option can help you work with that methodology.
|
@@ -119,10 +111,19 @@ Post.to_xlsx(instances: posts, spreadsheet_columns: Proc.new{|instance|
|
|
119
111
|
|
120
112
|
# Sending & Saving Spreadsheets
|
121
113
|
|
122
|
-
### Method 1:
|
114
|
+
### Method 1: Save to a file manually
|
123
115
|
|
124
116
|
```ruby
|
117
|
+
file_data = SpreadsheetArchitect.to_xlsx(headers: headers, data: data)
|
125
118
|
|
119
|
+
File.open('path/to/file.xlsx', 'w+b') do |f|
|
120
|
+
f.write file_data
|
121
|
+
end
|
122
|
+
```
|
123
|
+
|
124
|
+
### Method 2: Send Data via Rails Controller
|
125
|
+
|
126
|
+
```ruby
|
126
127
|
class PostsController < ActionController::Base
|
127
128
|
respond_to :html, :xlsx, :ods, :csv
|
128
129
|
|
@@ -176,44 +177,27 @@ class PostsController < ActionController::Base
|
|
176
177
|
end
|
177
178
|
```
|
178
179
|
|
179
|
-
|
180
|
+
# Multi Sheet Spreadsheets
|
180
181
|
|
181
|
-
|
182
|
-
### Ex. with ActiveRecord relation
|
183
|
-
file_data = Post.order(published_at: :asc).to_xlsx
|
184
|
-
File.open('path/to/file.xlsx', 'w+b') do |f|
|
185
|
-
f.write file_data
|
186
|
-
end
|
182
|
+
### XLSX
|
187
183
|
|
188
|
-
file_data = Post.order(published_at: :asc).to_ods
|
189
|
-
File.open('path/to/file.ods', 'w+b') do |f|
|
190
|
-
f.write file_data
|
191
|
-
end
|
192
|
-
|
193
|
-
file_data = Post.order(published_at: :asc).to_csv
|
194
|
-
File.open('path/to/file.csv', 'w+b') do |f|
|
195
|
-
f.write file_data
|
196
|
-
end
|
197
|
-
```
|
198
|
-
|
199
|
-
# Multi Sheet XLSX Spreadsheets
|
200
184
|
```ruby
|
201
185
|
axlsx_package = SpreadsheetArchitect.to_axlsx_package({headers: headers, data: data})
|
202
186
|
axlsx_package = SpreadsheetArchitect.to_axlsx_package({headers: headers, data: data}, package)
|
203
187
|
|
204
|
-
File.open('path/to/
|
188
|
+
File.open('path/to/multi_sheet_file.xlsx', 'w+b') do |f|
|
205
189
|
f.write axlsx_package.to_stream.read
|
206
190
|
end
|
207
191
|
```
|
208
192
|
|
209
193
|
See this file for more details: https://github.com/westonganger/spreadsheet_architect/blob/master/test/spreadsheet_architect/multi_sheet_test.rb
|
210
194
|
|
211
|
-
###
|
195
|
+
### ODS
|
212
196
|
```ruby
|
213
197
|
ods_spreadsheet = SpreadsheetArchitect.to_rodf_spreadsheet({headers: headers, data: data})
|
214
198
|
ods_spreadsheet = SpreadsheetArchitect.to_rodf_spreadsheet({headers: headers, data: data}, spreadsheet)
|
215
199
|
|
216
|
-
File.open('path/to/
|
200
|
+
File.open('path/to/multi_sheet_file.ods', 'w+b') do |f|
|
217
201
|
f.write ods_spreadsheet
|
218
202
|
end
|
219
203
|
```
|
@@ -240,6 +224,8 @@ See this file for more details: https://github.com/westonganger/spreadsheet_arch
|
|
240
224
|
|**borders**<br>*Array*||[See this example for usage](https://github.com/westonganger/spreadsheet_architect/blob/master/test/unit/kitchen_sink_test.rb)|
|
241
225
|
|**column_types**<br>*Array*||Valid types for XLSX are :string, :integer, :float, :date, :time, :boolean, nil = auto determine.|
|
242
226
|
|**column_widths**<br>*Array*||Sometimes you may want explicit column widths. Use nil if you want a column to autofit again.|
|
227
|
+
|**freeze_headers**<br>*Boolean*||Make all header rows frozen/fixed so they do not scroll.|
|
228
|
+
|**freeze**<br>* Hash*|`{rows: (1..4), columns: :all}`|Make all specified rows and columns frozen/fixed so they do not scroll.|
|
243
229
|
|
244
230
|
## `to_axlsx_spreadsheet(options={}, axlsx_package_to_join=nil)`
|
245
231
|
Same options as `to_xlsx`
|
@@ -273,7 +259,9 @@ Same options as `to_ods`
|
|
273
259
|
# Change class-wide default method options
|
274
260
|
|
275
261
|
```ruby
|
276
|
-
class Post
|
262
|
+
class Post < ApplicationRecord
|
263
|
+
include SpreadsheetArchitect
|
264
|
+
|
277
265
|
def spreadsheet_columns
|
278
266
|
[:name, :content]
|
279
267
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
if Axlsx::VERSION.to_f < 3.1
|
2
|
+
|
3
|
+
Axlsx::Cell.class_eval do
|
4
|
+
private
|
5
|
+
|
6
|
+
def string_width(string, font_size)
|
7
|
+
font_scale = font_size / 10.0
|
8
|
+
(string.to_s.size + 3) * font_scale
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Axlsx::RichTextRun.class_eval do
|
13
|
+
private
|
14
|
+
|
15
|
+
def string_width(string, font_size)
|
16
|
+
font_scale = font_size / 10.0
|
17
|
+
string.to_s.size * font_scale
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'axlsx'
|
2
2
|
require 'axlsx_styler'
|
3
3
|
|
4
|
-
require 'spreadsheet_architect/
|
4
|
+
require 'spreadsheet_architect/axlsx_string_width_patch'
|
5
5
|
|
6
6
|
module SpreadsheetArchitect
|
7
7
|
module ClassMethods
|
@@ -107,6 +107,8 @@ module SpreadsheetArchitect
|
|
107
107
|
sheet.add_row row_data, style: styles, types: types
|
108
108
|
|
109
109
|
if options[:conditional_row_styles]
|
110
|
+
options[:conditional_row_styles] = SpreadsheetArchitect::Utils.hash_array_symbolize_keys(options[:conditional_row_styles])
|
111
|
+
|
110
112
|
conditional_styles_for_row = SpreadsheetArchitect::Utils::XLSX.conditional_styles_for_row(options[:conditional_row_styles], row_index, row_data)
|
111
113
|
|
112
114
|
unless conditional_styles_for_row.empty?
|
@@ -127,6 +129,8 @@ module SpreadsheetArchitect
|
|
127
129
|
end
|
128
130
|
|
129
131
|
if options[:borders]
|
132
|
+
options[:borders] = SpreadsheetArchitect::Utils.hash_array_symbolize_keys(options[:borders])
|
133
|
+
|
130
134
|
options[:borders].each do |x|
|
131
135
|
if x[:range].is_a?(Hash)
|
132
136
|
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows)
|
@@ -139,6 +143,8 @@ module SpreadsheetArchitect
|
|
139
143
|
end
|
140
144
|
|
141
145
|
if options[:column_styles]
|
146
|
+
options[:column_styles] = SpreadsheetArchitect::Utils.hash_array_symbolize_keys(options[:column_styles])
|
147
|
+
|
142
148
|
options[:column_styles].each do |x|
|
143
149
|
start_row = (options[:headers] ? options[:headers].count : 0) + 1
|
144
150
|
|
@@ -170,6 +176,8 @@ module SpreadsheetArchitect
|
|
170
176
|
end
|
171
177
|
|
172
178
|
if options[:range_styles]
|
179
|
+
options[:range_styles] = SpreadsheetArchitect::Utils.hash_array_symbolize_keys(options[:range_styles])
|
180
|
+
|
173
181
|
options[:range_styles].each do |x|
|
174
182
|
styles = SpreadsheetArchitect::Utils::XLSX.convert_styles_to_axlsx(x[:styles])
|
175
183
|
|
@@ -184,6 +192,8 @@ module SpreadsheetArchitect
|
|
184
192
|
end
|
185
193
|
|
186
194
|
if options[:merges]
|
195
|
+
options[:merges] = SpreadsheetArchitect::Utils.hash_array_symbolize_keys(options[:merges])
|
196
|
+
|
187
197
|
options[:merges].each do |x|
|
188
198
|
if x[:range].is_a?(Hash)
|
189
199
|
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows)
|
@@ -194,6 +204,44 @@ module SpreadsheetArchitect
|
|
194
204
|
sheet.merge_cells x[:range]
|
195
205
|
end
|
196
206
|
end
|
207
|
+
|
208
|
+
if options[:freeze_headers]
|
209
|
+
sheet.sheet_view.pane do |pane|
|
210
|
+
pane.state = :frozen
|
211
|
+
pane.y_split = options[:headers].count
|
212
|
+
end
|
213
|
+
|
214
|
+
elsif options[:freeze]
|
215
|
+
options[:freeze] = SpreadsheetArchitect::Utils.symbolize_keys(options[:freeze])
|
216
|
+
|
217
|
+
sheet.sheet_view.pane do |pane|
|
218
|
+
pane.state = :frozen
|
219
|
+
|
220
|
+
### Currently not working
|
221
|
+
#if options[:freeze][:active_pane]
|
222
|
+
# Axlsx.validate_pane_type(options[:freeze][:active_pane])
|
223
|
+
# pane.active_pane = options[:freeze][:active_pane]
|
224
|
+
#else
|
225
|
+
# pane.active_pane = :bottom_right
|
226
|
+
#end
|
227
|
+
|
228
|
+
if !options[:freeze][:rows]
|
229
|
+
raise SpreadsheetArchitect::Exceptions::ArgumentError.new("The :rows key must be specified in the :freeze option hash")
|
230
|
+
elsif options[:freeze][:rows].is_a?(Range)
|
231
|
+
pane.y_split = options[:freeze][:rows].count
|
232
|
+
else
|
233
|
+
pane.y_split = 1
|
234
|
+
end
|
235
|
+
|
236
|
+
if options[:freeze][:columns] && options[:freeze][:columns] != :all
|
237
|
+
if options[:freeze][:columns].is_a?(Range)
|
238
|
+
pane.x_split = options[:freeze][:columns].count
|
239
|
+
else
|
240
|
+
pane.x_split = 1
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
197
245
|
end
|
198
246
|
|
199
247
|
return package
|
@@ -13,7 +13,7 @@ module SpreadsheetArchitect
|
|
13
13
|
elsif options[:headers].is_a?(Array)
|
14
14
|
headers = options[:headers]
|
15
15
|
else
|
16
|
-
headers =
|
16
|
+
headers = []
|
17
17
|
end
|
18
18
|
|
19
19
|
if options[:column_types]
|
@@ -109,6 +109,10 @@ module SpreadsheetArchitect
|
|
109
109
|
def self.get_options(options, klass)
|
110
110
|
verify_option_types(options)
|
111
111
|
|
112
|
+
if options[:freeze] && options[:freeze_headers]
|
113
|
+
raise SpreadsheetArchitect::Exceptions::ArgumentError.new('Cannot use both :freeze and :freeze_headers options at the same time')
|
114
|
+
end
|
115
|
+
|
112
116
|
if defined?(klass::SPREADSHEET_OPTIONS)
|
113
117
|
if klass::SPREADSHEET_OPTIONS.is_a?(Hash)
|
114
118
|
options = SpreadsheetArchitect.default_options.merge(
|
@@ -137,6 +141,10 @@ module SpreadsheetArchitect
|
|
137
141
|
end
|
138
142
|
end
|
139
143
|
|
144
|
+
if options[:freeze] && options[:freeze].is_a?(Hash) && !options[:freeze][:rows]
|
145
|
+
raise SpreadsheetArchitect::Exceptions::ArgumentError.new('Must provide a :rows key when passing a hash to the :freeze option')
|
146
|
+
end
|
147
|
+
|
140
148
|
return options
|
141
149
|
end
|
142
150
|
|
@@ -208,6 +216,8 @@ module SpreadsheetArchitect
|
|
208
216
|
end
|
209
217
|
|
210
218
|
def self.verify_option_types(options)
|
219
|
+
options = self.symbolize_keys(options, shallow: true)
|
220
|
+
|
211
221
|
check_option_type(options, :spreadsheet_columns, [Proc, Symbol, String])
|
212
222
|
check_option_type(options, :data, Array)
|
213
223
|
check_option_type(options, :instances, Array)
|
@@ -221,10 +231,13 @@ module SpreadsheetArchitect
|
|
221
231
|
check_option_type(options, :borders, Array)
|
222
232
|
check_option_type(options, :column_widths, Array)
|
223
233
|
check_option_type(options, :column_types, Array)
|
234
|
+
check_option_type(options, :freeze_headers, [TrueClass, FalseClass])
|
235
|
+
check_option_type(options, :freeze, Hash)
|
224
236
|
end
|
225
237
|
|
226
|
-
def self.stringify_keys(hash
|
238
|
+
def self.stringify_keys(hash)
|
227
239
|
new_hash = {}
|
240
|
+
|
228
241
|
hash.each do |k,v|
|
229
242
|
if v.is_a?(Hash)
|
230
243
|
new_hash[k.to_s] = self.stringify_keys(v)
|
@@ -232,7 +245,33 @@ module SpreadsheetArchitect
|
|
232
245
|
new_hash[k.to_s] = v
|
233
246
|
end
|
234
247
|
end
|
248
|
+
|
235
249
|
return new_hash
|
236
250
|
end
|
251
|
+
|
252
|
+
def self.symbolize_keys(hash, shallow: false)
|
253
|
+
new_hash = {}
|
254
|
+
|
255
|
+
hash.each do |k,v|
|
256
|
+
if v.is_a?(Hash)
|
257
|
+
new_hash[k.to_sym] = shallow ? v : self.symbolize_keys(v)
|
258
|
+
else
|
259
|
+
new_hash[k.to_sym] = v
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
return new_hash
|
264
|
+
end
|
265
|
+
|
266
|
+
def self.hash_array_symbolize_keys(array)
|
267
|
+
new_array = []
|
268
|
+
|
269
|
+
array.each_with_index do |x,i|
|
270
|
+
new_array[i] = x.is_a?(Hash) ? self.symbolize_keys(x) : x
|
271
|
+
end
|
272
|
+
|
273
|
+
return new_array
|
274
|
+
end
|
275
|
+
|
237
276
|
end
|
238
277
|
end
|
@@ -26,7 +26,8 @@ module SpreadsheetArchitect
|
|
26
26
|
|
27
27
|
def self.convert_styles_to_axlsx(styles={})
|
28
28
|
styles = {} unless styles.is_a?(Hash)
|
29
|
-
|
29
|
+
|
30
|
+
styles = SpreadsheetArchitect::Utils.symbolize_keys(styles)
|
30
31
|
|
31
32
|
if styles[:fg_color].nil? && styles[:color] && styles[:color].respond_to?(:sub) && !styles[:color].empty?
|
32
33
|
styles[:fg_color] = styles.delete(:color).sub('#','')
|
@@ -176,18 +177,6 @@ module SpreadsheetArchitect
|
|
176
177
|
|
177
178
|
private
|
178
179
|
|
179
|
-
def self.symbolize_keys(hash={})
|
180
|
-
new_hash = {}
|
181
|
-
hash.each do |k, v|
|
182
|
-
if v.is_a?(Hash)
|
183
|
-
new_hash[k.to_sym] = self.symbolize_keys(v)
|
184
|
-
else
|
185
|
-
new_hash[k.to_sym] = v
|
186
|
-
end
|
187
|
-
end
|
188
|
-
new_hash
|
189
|
-
end
|
190
|
-
|
191
180
|
### Limit of 16384 columns as per Excel limitations
|
192
181
|
COL_NAMES = Array('A'..'XFD').freeze
|
193
182
|
|