spreadsheet_architect 4.2.0 → 5.0.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 +12 -1
- data/README.md +10 -14
- data/lib/spreadsheet_architect/class_methods/ods.rb +18 -8
- data/lib/spreadsheet_architect/class_methods/xlsx.rb +76 -32
- data/lib/spreadsheet_architect/exceptions.rb +30 -13
- data/lib/spreadsheet_architect/utils/ods.rb +66 -0
- data/lib/spreadsheet_architect/utils/xlsx.rb +29 -8
- data/lib/spreadsheet_architect/utils.rb +13 -38
- data/lib/spreadsheet_architect/version.rb +1 -1
- data/lib/spreadsheet_architect.rb +3 -2
- data/test/dummy_app/app/controllers/spreadsheets_controller.rb +1 -1
- data/test/dummy_app/config/application.rb +4 -12
- data/test/dummy_app/config/routes.rb +1 -1
- data/test/dummy_app/db/test.sqlite3 +0 -0
- data/test/dummy_app/log/test.log +79842 -63691
- 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/integration/application_test.rb +8 -16
- data/test/models/all_models_test.rb +15 -19
- data/test/test_helper.rb +38 -9
- data/test/unit/ods/general_test.rb +121 -0
- data/test/unit/{formats_test.rb → rails/formats_test.rb} +1 -1
- data/test/unit/{exceptions_test.rb → spreadsheet_architect/exceptions_test.rb} +19 -15
- data/test/unit/{general_test.rb → spreadsheet_architect/spreadsheet_architect_test.rb} +3 -3
- data/test/unit/spreadsheet_architect/utils/ods_test.rb +58 -0
- data/test/unit/{xlsx_utils_test.rb → spreadsheet_architect/utils/xlsx_test.rb} +13 -21
- data/test/unit/{utils_test.rb → spreadsheet_architect/utils_test.rb} +12 -35
- data/test/unit/xlsx/freeze_test.rb +79 -0
- data/test/unit/xlsx/general_test.rb +199 -0
- metadata +381 -128
- data/test/dummy_app/config/environments/development.rb +0 -30
- data/test/dummy_app/config/environments/production.rb +0 -60
- data/test/unit/kitchen_sink_test.rb +0 -110
- data/test/unit/multi_sheet_test.rb +0 -29
- data/test/unit/options_test.rb +0 -9
- data/test/unit/xlsx_freeze_test.rb +0 -44
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c88ecaffa3abed6ef127dc13d42c612ebf224c6d8552590d68ae544af2713f93
|
|
4
|
+
data.tar.gz: d0e864c2f50e99040f932da595b7270dd0e9c0161fc1189e6d99cb43126f6b5a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfc0caea596d57bd5aa88cd3b5ff3cebfca8b1299d1660e9995ca93837746d21420a90e0f427df9b3f8e73c13914a24b137572c005ee16fafdeeb6ddaf18b95d
|
|
7
|
+
data.tar.gz: c31f408e271453d46454e4f85ad2437a2539e39973186a8889c917a338f9e5f57f9ef3f3f28797955d61f8daa6a7100ffb46624ab3974c4bfd9273cc5cacba29
|
data/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
---------
|
|
3
3
|
|
|
4
|
-
- **Unreleased** - [View Diff](https://github.com/westonganger/spreadsheet_architect/compare/
|
|
4
|
+
- **Unreleased** - [View Diff](https://github.com/westonganger/spreadsheet_architect/compare/v5.0.0...master)
|
|
5
5
|
- Nothing yet
|
|
6
6
|
|
|
7
|
+
- **5.0.0** - [View Diff](https://github.com/westonganger/spreadsheet_architect/compare/v4.2.0...v5.0.0)
|
|
8
|
+
- [#52](https://github.com/westonganger/spreadsheet_architect/pull/52) - Update to caxlsx v3.3.0+ which now contains the axlsx_styler code, so we drop the dependency on axlsx_styler
|
|
9
|
+
- [#38](https://github.com/westonganger/spreadsheet_architect/pull/38) - **Breaking Change** - Add `escape_formulas` option for xlsx spreadsheets. This is a breaking change because we default to `escape_formulas: true` whereas before there was no formula escaping at all. The reasoning for this breaking change is that creating spreadsheets where many of the fields contain direct user input are a large majority compared to use cases that involve formulas.
|
|
10
|
+
- [#39](https://github.com/westonganger/spreadsheet_architect/pull/39) - Add option `use_zero_based_row_index: true` (Default `false`) which allows you to use zero-based row indexes instead of the default 1-based row indexes. Recomended to set this option for the whole project. The original reason it was designed to be 1-based is because spreadsheet row numbers literally start with 1. However this tends to be unituitive for the developer because columns use zero based indexes because they use letter-based notation instead.
|
|
11
|
+
- [#40](https://github.com/westonganger/spreadsheet_architect/pull/40) - Improve argument handling for freeze option and add support for all Axlsx supported options for panes using the `:freeze` hash. See test case for example (./test/unit/xlsx_freeze_test.rb)
|
|
12
|
+
- [#42](https://github.com/westonganger/spreadsheet_architect/pull/42) - Improve exceptions and messages regarding invalid ranges
|
|
13
|
+
- [#45](https://github.com/westonganger/spreadsheet_architect/pull/45) - For `to_xlsx`, dont add empty header row when `header: true`
|
|
14
|
+
- [#44](https://github.com/westonganger/spreadsheet_architect/pull/44) - Add support for hyperlinks in XLSX and ODS
|
|
15
|
+
- [#49](https://github.com/westonganger/spreadsheet_architect/pulls/49) - Extracted some ODS methods from `SpreadsheetArchitect::Utils` to `SpreadsheetArchitect::Utils::ODS`
|
|
16
|
+
- [#51](https://github.com/westonganger/spreadsheet_architect/pulls/51) - Add Proc support to `:column_types`
|
|
17
|
+
|
|
7
18
|
- **4.2.0** - May 27, 2021 - [View Diff](https://github.com/westonganger/spreadsheet_architect/compare/v4.1.0...v4.2.0)
|
|
8
19
|
- Add option `:skip_defaults` which removes the defaults and default styles. Particularily useful for heavily customized spreadsheets where the default styles get in the way.
|
|
9
20
|
- Fix bug where styles werent being un-applied when using the `false` value.
|
data/README.md
CHANGED
|
@@ -91,7 +91,7 @@ If you want to use a different method name then `spreadsheet_columns` you can pa
|
|
|
91
91
|
Post.to_xlsx(instances: posts, spreadsheet_columns: :my_special_method)
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
Alternatively, you can pass a Proc
|
|
94
|
+
Alternatively, you can pass a Proc 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.
|
|
95
95
|
|
|
96
96
|
```ruby
|
|
97
97
|
Post.to_xlsx(instances: posts, spreadsheet_columns: Proc.new{|instance|
|
|
@@ -103,7 +103,8 @@ Post.to_xlsx(instances: posts, spreadsheet_columns: Proc.new{|instance|
|
|
|
103
103
|
:published_at, # uses the method name as header title Einstance. 'Published At'
|
|
104
104
|
['# of Views', :number_of_views, :float],
|
|
105
105
|
['Rating', :rating],
|
|
106
|
-
['Category/Tags', "#{instance.category.name} - #{instance.tags.collect(&:name).join(', ')}"]
|
|
106
|
+
['Category/Tags', "#{instance.category.name} - #{instance.tags.collect(&:name).join(', ')}"],
|
|
107
|
+
['URL', :url, (val.start_with?("http") ? :hyperlink : :string)],
|
|
107
108
|
]
|
|
108
109
|
})
|
|
109
110
|
```
|
|
@@ -189,20 +190,16 @@ File.open('path/to/multi_sheet_file.xlsx', 'w+b') do |f|
|
|
|
189
190
|
end
|
|
190
191
|
```
|
|
191
192
|
|
|
192
|
-
See this file for more details: [test/unit/multi_sheet_test.rb](./test/unit/multi_sheet_test.rb)
|
|
193
|
-
|
|
194
193
|
### ODS
|
|
195
194
|
```ruby
|
|
196
195
|
ods_spreadsheet = SpreadsheetArchitect.to_rodf_spreadsheet({headers: headers, data: data})
|
|
197
196
|
ods_spreadsheet = SpreadsheetArchitect.to_rodf_spreadsheet({headers: headers, data: data}, ods_spreadsheet)
|
|
198
197
|
|
|
199
198
|
File.open('path/to/multi_sheet_file.ods', 'w+b') do |f|
|
|
200
|
-
f.write ods_spreadsheet
|
|
199
|
+
f.write ods_spreadsheet.bytes
|
|
201
200
|
end
|
|
202
201
|
```
|
|
203
202
|
|
|
204
|
-
See this file for more details: [test/unit/multi_sheet_test.rb](./test/unit/multi_sheet_test.rb)
|
|
205
|
-
|
|
206
203
|
# Methods
|
|
207
204
|
|
|
208
205
|
## `to_xlsx(options={})`
|
|
@@ -221,11 +218,13 @@ See this file for more details: [test/unit/multi_sheet_test.rb](./test/unit/mult
|
|
|
221
218
|
|**conditional_row_styles**<br>*Array*||[See this example for usage](./test/unit/kitchen_sink_test.rb). The if/unless proc will called with the following args: `row_index`, `row_data`|
|
|
222
219
|
|**merges**<br>*Array*||Merge cells. [See this example for usage](./test/unit/kitchen_sink_test.rb). Warning merges cannot overlap eachother, if you attempt to do so Excel will claim your spreadsheet is corrupt and refuse to open your spreadsheet.|
|
|
223
220
|
|**borders**<br>*Array*||[See this example for usage](./test/unit/kitchen_sink_test.rb)|
|
|
224
|
-
|**column_types**<br>*Array*||Valid types for XLSX are :string, :integer, :float, :date, :time, :boolean, nil = auto determine
|
|
221
|
+
|**column_types**<br>*Array*||Valid types for XLSX are :string, :integer, :float, :date, :time, :boolean, :hyperlink, nil = auto determine. You may also pass a Proc which evaluates to any of the valid types, for example `->(cell_val){ cell_val.start_with?('http') ? :hyperlink : :string }`|
|
|
225
222
|
|**column_widths**<br>*Array*||Sometimes you may want explicit column widths. Use nil if you want a column to autofit again.|
|
|
226
223
|
|**freeze_headers**<br>*Boolean*||Make all header rows frozen/fixed so they do not scroll.|
|
|
227
|
-
|**freeze**<br>*Hash
|
|
224
|
+
|**freeze**<br>*Hash*||Make all specified row and/or column frozen/fixed so they do not scroll. See [example usage](./test/unit/xlsx_freeze_test.rb)|
|
|
228
225
|
|**skip_defaults**<br>*Boolean*|`false`|Removes defaults and default styles. Particularily useful for heavily customized spreadsheets where the default styles get in the way.|
|
|
226
|
+
|**escape_formulas**<br>*Boolean* or *Array*|`true`|Pass a single boolean to apply to all cells, or an array of booleans to control column-by-column. Advisable to be set true when involved with untrusted user input. See [an example of the underlying functionality](https://github.com/caxlsx/caxlsx/blob/master/examples/escape_formula_example.md). NOTE: Header row cells are not escaped. |
|
|
227
|
+
|**use_zero_based_row_index**<br>*Boolean*|`false`|Allows you to use zero-based row indexes when defining `range_styles`, `merges`, etc. Recomended to set this option for the whole project rather than per call. The original reason it was designed to be 1-based is because spreadsheet row numbers actually start with 1.|
|
|
229
228
|
|
|
230
229
|
## `to_axlsx_spreadsheet(options={}, axlsx_package_to_join=nil)`
|
|
231
230
|
Same options as `to_xlsx`
|
|
@@ -241,7 +240,7 @@ Same options as `to_xlsx`
|
|
|
241
240
|
|**sheet_name**<br>*String*|`Sheet1`||
|
|
242
241
|
|**header_style**<br>*Hash*|`{background_color: "AAAAAA", color: "FFFFFF", align: :center, font_size: 10, bold: true}`|Note: Currently ODS only supports these options|
|
|
243
242
|
|**row_style**<br>*Hash*|`{background_color: nil, color: "000000", align: :left, font_size: 10, bold: false}`|Styles for non-header rows. Currently ODS only supports these options|
|
|
244
|
-
|**column_types**<br>*Array*||Valid types for ODS are :string, :float, :date, :time, :boolean, nil = auto determine. Due to [RODF Issue #19](https://github.com/thiagoarrais/rodf/issues/19), :date/:time will be converted to :string |
|
|
243
|
+
|**column_types**<br>*Array*||Valid types for ODS are :string, :float, :date, :time, :boolean, :hyperlink, nil = auto determine. Due to [RODF Issue #19](https://github.com/thiagoarrais/rodf/issues/19), :date/:time will be converted to :string. You may also pass a Proc which evaluates to any of the valid types, for example `->(cell_val){ cell_val.start_with?('http') ? :hyperlink : :string }` |
|
|
245
244
|
|**skip_defaults**<br>*Boolean*|`false`|Skip defaults and default styles. Particularily useful for heavily customized spreadsheets where the default styles get in the way.|
|
|
246
245
|
|
|
247
246
|
## `to_rodf_spreadsheet(options={}, spreadsheet_to_join=nil)`
|
|
@@ -303,6 +302,7 @@ SpreadsheetArchitect.default_options = {
|
|
|
303
302
|
merges: [],
|
|
304
303
|
borders: [],
|
|
305
304
|
column_types: [],
|
|
305
|
+
use_zero_based_row_index: false,
|
|
306
306
|
}
|
|
307
307
|
```
|
|
308
308
|
|
|
@@ -329,7 +329,3 @@ At this time the spreadsheets generated by the test suite are manually inspected
|
|
|
329
329
|
# Credits
|
|
330
330
|
|
|
331
331
|
Created & Maintained by [Weston Ganger](https://westonganger.com) - [@westonganger](https://github.com/westonganger)
|
|
332
|
-
|
|
333
|
-
For any consulting or contract work please contact me via my company website: [Solid Foundation Web Development](https://solidfoundationwebdev.com)
|
|
334
|
-
|
|
335
|
-
[](https://solidfoundationwebdev.com)
|
|
@@ -11,7 +11,7 @@ module SpreadsheetArchitect
|
|
|
11
11
|
opts = SpreadsheetArchitect::Utils.get_options(opts, self)
|
|
12
12
|
options = SpreadsheetArchitect::Utils.get_cell_data(opts, self)
|
|
13
13
|
|
|
14
|
-
if options[:column_types] && !(options[:column_types].compact.collect(&:to_sym) - SpreadsheetArchitect::ODS_COLUMN_TYPES).empty?
|
|
14
|
+
if options[:column_types] && !(options[:column_types].compact.reject{|x| x.is_a?(Proc) }.collect(&:to_sym) - SpreadsheetArchitect::ODS_COLUMN_TYPES).empty?
|
|
15
15
|
raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid column type. Valid ODS values are #{SpreadsheetArchitect::ODS_COLUMN_TYPES}")
|
|
16
16
|
end
|
|
17
17
|
|
|
@@ -21,7 +21,7 @@ module SpreadsheetArchitect
|
|
|
21
21
|
|
|
22
22
|
spreadsheet.office_style :header_style, family: :cell do
|
|
23
23
|
if options[:header_style]
|
|
24
|
-
SpreadsheetArchitect::Utils.
|
|
24
|
+
SpreadsheetArchitect::Utils::ODS.convert_styles(options[:header_style]).each do |prop, styles|
|
|
25
25
|
styles.each do |k,v|
|
|
26
26
|
property prop.to_sym, k => v
|
|
27
27
|
end
|
|
@@ -31,7 +31,7 @@ module SpreadsheetArchitect
|
|
|
31
31
|
|
|
32
32
|
spreadsheet.office_style :row_style, family: :cell do
|
|
33
33
|
if options[:row_style]
|
|
34
|
-
SpreadsheetArchitect::Utils.
|
|
34
|
+
SpreadsheetArchitect::Utils::ODS.convert_styles(options[:row_style]).each do |prop, styles|
|
|
35
35
|
styles.each do |k,v|
|
|
36
36
|
property prop.to_sym, k => v
|
|
37
37
|
end
|
|
@@ -54,15 +54,25 @@ module SpreadsheetArchitect
|
|
|
54
54
|
row do
|
|
55
55
|
row_data.each_with_index do |val, i|
|
|
56
56
|
if options[:column_types]
|
|
57
|
-
|
|
57
|
+
provided_column_type = options[:column_types][i]
|
|
58
|
+
|
|
59
|
+
if provided_column_type.is_a?(Proc)
|
|
60
|
+
provided_column_type = provided_column_type.call(val)
|
|
61
|
+
end
|
|
58
62
|
end
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
type = SpreadsheetArchitect::Utils::ODS.get_cell_type(val, provided_column_type)
|
|
65
|
+
|
|
66
|
+
cell_opts = {
|
|
67
|
+
style: :row_style,
|
|
68
|
+
type: type,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if provided_column_type == :hyperlink
|
|
72
|
+
cell_opts[:url] = val
|
|
63
73
|
end
|
|
64
74
|
|
|
65
|
-
cell
|
|
75
|
+
cell(val, **cell_opts)
|
|
66
76
|
end
|
|
67
77
|
end
|
|
68
78
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'axlsx'
|
|
2
|
-
require 'axlsx_styler'
|
|
3
2
|
|
|
4
3
|
require 'spreadsheet_architect/axlsx_string_width_patch'
|
|
5
4
|
|
|
@@ -14,7 +13,7 @@ module SpreadsheetArchitect
|
|
|
14
13
|
opts = SpreadsheetArchitect::Utils.get_options(opts, self)
|
|
15
14
|
options = SpreadsheetArchitect::Utils.get_cell_data(opts, self)
|
|
16
15
|
|
|
17
|
-
if options[:column_types] && !(options[:column_types].compact.collect(&:to_sym) - SpreadsheetArchitect::XLSX_COLUMN_TYPES).empty?
|
|
16
|
+
if options[:column_types] && !(options[:column_types].compact.reject{|x| x.is_a?(Proc) }.collect(&:to_sym) - SpreadsheetArchitect::XLSX_COLUMN_TYPES).empty?
|
|
18
17
|
raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid column type. Valid XLSX values are #{SpreadsheetArchitect::XLSX_COLUMN_TYPES}")
|
|
19
18
|
end
|
|
20
19
|
|
|
@@ -79,16 +78,27 @@ module SpreadsheetArchitect
|
|
|
79
78
|
|
|
80
79
|
types = []
|
|
81
80
|
styles = []
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
hyperlink_cell_indexes = []
|
|
82
|
+
|
|
83
|
+
row_data.each_with_index do |val,i|
|
|
84
|
+
if (val.respond_to?(:empty) ? val.empty? : val.nil?)
|
|
84
85
|
types[i] = nil
|
|
85
86
|
styles[i] = row_style_index
|
|
86
87
|
else
|
|
87
88
|
if options[:column_types]
|
|
88
|
-
|
|
89
|
+
provided_column_type = options[:column_types][i]
|
|
90
|
+
|
|
91
|
+
if provided_column_type.is_a?(Proc)
|
|
92
|
+
provided_column_type = provided_column_type.call(val)
|
|
93
|
+
end
|
|
89
94
|
end
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
if provided_column_type == :hyperlink
|
|
97
|
+
hyperlink_cell_indexes << i
|
|
98
|
+
row_data[i] = val.to_s
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
types[i] = SpreadsheetArchitect::Utils::XLSX.get_type(val, provided_column_type)
|
|
92
102
|
|
|
93
103
|
if [:date, :time].include?(types[i])
|
|
94
104
|
if types[i] == :date
|
|
@@ -104,7 +114,12 @@ module SpreadsheetArchitect
|
|
|
104
114
|
end
|
|
105
115
|
end
|
|
106
116
|
|
|
107
|
-
sheet.add_row row_data, style: styles, types: types
|
|
117
|
+
sheet.add_row row_data, style: styles, types: types, escape_formulas: options[:escape_formulas]
|
|
118
|
+
|
|
119
|
+
hyperlink_cell_indexes.each do |cell_index|
|
|
120
|
+
cell_ref = "#{SpreadsheetArchitect::Utils::XLSX::COL_NAMES[cell_index]}#{row_index+1}"
|
|
121
|
+
sheet.add_hyperlink location: row_data[cell_index], ref: cell_ref
|
|
122
|
+
end
|
|
108
123
|
|
|
109
124
|
if options[:conditional_row_styles]
|
|
110
125
|
options[:conditional_row_styles] = SpreadsheetArchitect::Utils.hash_array_symbolize_keys(options[:conditional_row_styles])
|
|
@@ -133,12 +148,12 @@ module SpreadsheetArchitect
|
|
|
133
148
|
|
|
134
149
|
options[:borders].each do |x|
|
|
135
150
|
if x[:range].is_a?(Hash)
|
|
136
|
-
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows)
|
|
151
|
+
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows, use_zero_based_row_index: options[:use_zero_based_row_index])
|
|
137
152
|
else
|
|
138
153
|
SpreadsheetArchitect::Utils::XLSX.verify_range(x[:range], num_rows)
|
|
139
154
|
end
|
|
140
155
|
|
|
141
|
-
sheet.add_border x[:range], (x[:border_styles] || x[:styles])
|
|
156
|
+
sheet.add_border x[:range], (x[:border_styles] || x[:styles] || Axlsx::Border::EDGES)
|
|
142
157
|
end
|
|
143
158
|
end
|
|
144
159
|
|
|
@@ -182,7 +197,7 @@ module SpreadsheetArchitect
|
|
|
182
197
|
styles = SpreadsheetArchitect::Utils::XLSX.convert_styles_to_axlsx(x[:styles])
|
|
183
198
|
|
|
184
199
|
if x[:range].is_a?(Hash)
|
|
185
|
-
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows)
|
|
200
|
+
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows, use_zero_based_row_index: options[:use_zero_based_row_index])
|
|
186
201
|
else
|
|
187
202
|
SpreadsheetArchitect::Utils::XLSX.verify_range(x[:range], num_rows)
|
|
188
203
|
end
|
|
@@ -196,7 +211,7 @@ module SpreadsheetArchitect
|
|
|
196
211
|
|
|
197
212
|
options[:merges].each do |x|
|
|
198
213
|
if x[:range].is_a?(Hash)
|
|
199
|
-
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows)
|
|
214
|
+
x[:range] = SpreadsheetArchitect::Utils::XLSX.range_hash_to_str(x[:range], max_row_length, num_rows, use_zero_based_row_index: options[:use_zero_based_row_index])
|
|
200
215
|
else
|
|
201
216
|
SpreadsheetArchitect::Utils::XLSX.verify_range(x[:range], num_rows)
|
|
202
217
|
end
|
|
@@ -212,33 +227,62 @@ module SpreadsheetArchitect
|
|
|
212
227
|
end
|
|
213
228
|
|
|
214
229
|
elsif options[:freeze]
|
|
215
|
-
options[:freeze]
|
|
230
|
+
case options[:freeze][:type].to_s
|
|
231
|
+
when "split_panes"
|
|
232
|
+
options[:freeze][:state] == "split"
|
|
233
|
+
when "frozen", "freeze"
|
|
234
|
+
options[:freeze][:state] == "frozen"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
if options[:freeze][:rows]
|
|
238
|
+
options[:freeze][:row] ||= options[:freeze][:rows]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
if options[:freeze][:columns]
|
|
242
|
+
options[:freeze][:column] ||= options[:freeze][:columns]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
if options[:freeze][:row] == :all
|
|
246
|
+
options[:freeze][:row] = nil
|
|
247
|
+
elsif options[:freeze][:row].is_a?(Range)
|
|
248
|
+
options[:freeze][:row] = options[:freeze][:row].last
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
if options[:freeze][:column] == :all
|
|
252
|
+
options[:freeze][:column] = nil
|
|
253
|
+
elsif options[:freeze][:column].is_a?(Range)
|
|
254
|
+
options[:freeze][:column] = options[:freeze][:column].last
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
if !options[:freeze][:row] && !options[:freeze][:column]
|
|
258
|
+
raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Missing required :row or :column value in the :freeze option hash")
|
|
259
|
+
elsif options[:freeze][:row] && !options[:freeze][:row].is_a?(Integer)
|
|
260
|
+
raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid :row value provided for in :freeze option hash, must be an Integer")
|
|
261
|
+
elsif options[:freeze][:column] && !options[:freeze][:column].is_a?(Integer)
|
|
262
|
+
raise SpreadsheetArchitect::Exceptions::ArgumentError.new("Invalid :column value provided for in :freeze option hash, must be an Integer")
|
|
263
|
+
end
|
|
216
264
|
|
|
217
265
|
sheet.sheet_view.pane do |pane|
|
|
218
|
-
pane.state = :frozen
|
|
266
|
+
pane.state = (options[:freeze][:state] || :frozen).to_sym ### Other options are :split and :frozen_split
|
|
219
267
|
|
|
220
|
-
|
|
221
|
-
|
|
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
|
|
268
|
+
if options[:freeze][:active_pane]
|
|
269
|
+
pane.active_pane = options[:freeze][:active_pane].to_sym
|
|
234
270
|
end
|
|
235
271
|
|
|
236
|
-
if options[:freeze][:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
272
|
+
if options[:freeze][:top_left_cell]
|
|
273
|
+
pane.top_left_cell = options[:freeze][:top_left_cell]
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
if options[:freeze][:row]
|
|
277
|
+
if options[:use_zero_based_row_index]
|
|
278
|
+
options[:freeze][:row] += 1
|
|
241
279
|
end
|
|
280
|
+
|
|
281
|
+
pane.y_split = options[:freeze][:row]
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
if options[:freeze][:column]
|
|
285
|
+
pane.x_split = options[:freeze][:column]
|
|
242
286
|
end
|
|
243
287
|
end
|
|
244
288
|
end
|
|
@@ -14,17 +14,27 @@ module SpreadsheetArchitect
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
class InvalidRangeError < ArgumentError
|
|
17
|
-
def initialize(type, range)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
def initialize(type, range, message: nil)
|
|
18
|
+
default_msg = "Invalid range `#{range}` passed"
|
|
19
|
+
|
|
20
|
+
if message.nil?
|
|
21
|
+
case type
|
|
22
|
+
when :missing_range_keys
|
|
23
|
+
message = "Missing :rows or :columns key"
|
|
24
|
+
when :format
|
|
25
|
+
message = "Format must be as follows: A1:D4"
|
|
26
|
+
when :type
|
|
27
|
+
message = "Valid types are Hash and String"
|
|
28
|
+
end
|
|
27
29
|
end
|
|
30
|
+
|
|
31
|
+
super([default_msg, message].compact.join(". "))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class InvalidRangeValue < ArgumentError
|
|
36
|
+
def initialize(type, range)
|
|
37
|
+
super("Invalid range `#{range}` passed. Some of the :#{type} specified are either an invalid value or are greater than the total number of #{type}")
|
|
28
38
|
end
|
|
29
39
|
end
|
|
30
40
|
|
|
@@ -34,9 +44,16 @@ module SpreadsheetArchitect
|
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
46
|
|
|
37
|
-
class
|
|
38
|
-
def initialize(
|
|
39
|
-
|
|
47
|
+
class InvalidRangeOptionError < ArgumentError
|
|
48
|
+
def initialize(key, opt)
|
|
49
|
+
default_msg = "Invalid :#{key} option for `#{opt}`"
|
|
50
|
+
|
|
51
|
+
case key
|
|
52
|
+
when :columns, :rows
|
|
53
|
+
message = ":#{key} can be an integer, range, or :all"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
super([default_msg, message].compact.join(". "))
|
|
40
57
|
end
|
|
41
58
|
end
|
|
42
59
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module SpreadsheetArchitect
|
|
2
|
+
module Utils
|
|
3
|
+
module ODS
|
|
4
|
+
|
|
5
|
+
def self.get_cell_type(value, type=nil)
|
|
6
|
+
if type && !type.empty?
|
|
7
|
+
case type
|
|
8
|
+
when :hyperlink
|
|
9
|
+
return :string
|
|
10
|
+
when :date, :time
|
|
11
|
+
return :string
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
return type unless (type.respond_to?(:empty?) ? type.empty? : type.nil?)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
if value.is_a?(Numeric)
|
|
18
|
+
type = :float
|
|
19
|
+
elsif value.respond_to?(:strftime)
|
|
20
|
+
type = :string
|
|
21
|
+
else
|
|
22
|
+
type = :string
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return type
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.convert_styles(styles={})
|
|
29
|
+
styles = {} unless styles.is_a?(Hash)
|
|
30
|
+
styles = SpreadsheetArchitect::Utils.stringify_keys(styles)
|
|
31
|
+
|
|
32
|
+
property_styles = {}
|
|
33
|
+
|
|
34
|
+
text_styles = {}
|
|
35
|
+
text_styles['font-weight'] = styles.delete('bold') ? 'bold' : styles.delete('font-weight')
|
|
36
|
+
text_styles['font-size'] = styles.delete('font_size') || styles.delete('font-size')
|
|
37
|
+
text_styles['font-style'] = styles.delete('italic') ? 'italic' : styles.delete('font-style')
|
|
38
|
+
if styles['underline']
|
|
39
|
+
styles.delete('underline')
|
|
40
|
+
text_styles['text-underline-style'] = 'solid'
|
|
41
|
+
text_styles['text-underline-type'] = 'single'
|
|
42
|
+
end
|
|
43
|
+
if styles['align']
|
|
44
|
+
text_styles['align'] = true
|
|
45
|
+
end
|
|
46
|
+
if styles['color'].respond_to?(:sub) && !styles['color'].empty?
|
|
47
|
+
text_styles['color'] = "##{styles.delete('color').sub('#','')}"
|
|
48
|
+
end
|
|
49
|
+
text_styles.delete_if{|_,v| v.nil?}
|
|
50
|
+
property_styles['text'] = text_styles
|
|
51
|
+
|
|
52
|
+
cell_styles = {}
|
|
53
|
+
styles['background_color'] ||= styles.delete('background-color')
|
|
54
|
+
if styles['background_color'].respond_to?(:sub) && !styles['background_color'].empty?
|
|
55
|
+
cell_styles['background-color'] = "##{styles.delete('background_color').sub('#','')}"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
cell_styles.delete_if{|_,v| v.nil?}
|
|
59
|
+
property_styles['cell'] = cell_styles
|
|
60
|
+
|
|
61
|
+
return property_styles
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -3,7 +3,14 @@ module SpreadsheetArchitect
|
|
|
3
3
|
module XLSX
|
|
4
4
|
|
|
5
5
|
def self.get_type(value, type=nil)
|
|
6
|
-
|
|
6
|
+
if type && !type.empty?
|
|
7
|
+
case type
|
|
8
|
+
when :hyperlink
|
|
9
|
+
return :string
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
return type unless (type.respond_to?(:empty?) ? type.empty? : type.nil?)
|
|
13
|
+
end
|
|
7
14
|
|
|
8
15
|
if value.is_a?(Numeric)
|
|
9
16
|
if value.is_a?(Float) || value.is_a?(BigDecimal)
|
|
@@ -83,7 +90,11 @@ module SpreadsheetArchitect
|
|
|
83
90
|
return styles
|
|
84
91
|
end
|
|
85
92
|
|
|
86
|
-
def self.range_hash_to_str(hash, num_columns, num_rows)
|
|
93
|
+
def self.range_hash_to_str(hash, num_columns, num_rows, use_zero_based_row_index: false)
|
|
94
|
+
if !hash.has_key?(:rows) && !hash.has_key?(:columns)
|
|
95
|
+
raise SpreadsheetArchitect::Exceptions::InvalidRangeError.new(:missing_range_keys, hash)
|
|
96
|
+
end
|
|
97
|
+
|
|
87
98
|
case hash[:columns]
|
|
88
99
|
when Integer
|
|
89
100
|
start_col = end_col = COL_NAMES[hash[:columns]]
|
|
@@ -100,24 +111,34 @@ module SpreadsheetArchitect
|
|
|
100
111
|
unless end_col.is_a?(String)
|
|
101
112
|
end_col = COL_NAMES[end_col]
|
|
102
113
|
end
|
|
103
|
-
when :all
|
|
114
|
+
when :all, nil
|
|
104
115
|
start_col = 'A'
|
|
105
116
|
end_col = COL_NAMES[num_columns-1]
|
|
106
117
|
else
|
|
107
|
-
raise SpreadsheetArchitect::Exceptions::
|
|
118
|
+
raise SpreadsheetArchitect::Exceptions::InvalidRangeOptionError.new(:columns, hash)
|
|
108
119
|
end
|
|
109
120
|
|
|
110
121
|
case hash[:rows]
|
|
111
122
|
when Integer
|
|
112
123
|
start_row = end_row = hash[:rows]
|
|
124
|
+
|
|
125
|
+
if use_zero_based_row_index
|
|
126
|
+
start_row += 1
|
|
127
|
+
end_row += 1
|
|
128
|
+
end
|
|
113
129
|
when Range
|
|
114
130
|
start_row = hash[:rows].first
|
|
115
131
|
end_row = hash[:rows].last
|
|
116
|
-
|
|
132
|
+
|
|
133
|
+
if use_zero_based_row_index
|
|
134
|
+
start_row += 1
|
|
135
|
+
end_row += 1
|
|
136
|
+
end
|
|
137
|
+
when :all, nil
|
|
117
138
|
start_row = 1
|
|
118
139
|
end_row = num_rows
|
|
119
140
|
else
|
|
120
|
-
raise SpreadsheetArchitect::Exceptions::
|
|
141
|
+
raise SpreadsheetArchitect::Exceptions::InvalidRangeOptionError.new(:rows, hash)
|
|
121
142
|
end
|
|
122
143
|
|
|
123
144
|
range_str = "#{start_col}#{start_row}:#{end_col}#{end_row}"
|
|
@@ -137,11 +158,11 @@ module SpreadsheetArchitect
|
|
|
137
158
|
end_col, end_row = back.scan(/\d+|\D+/)
|
|
138
159
|
|
|
139
160
|
unless COL_NAMES.include?(start_col) && COL_NAMES.include?(end_col)
|
|
140
|
-
raise SpreadsheetArchitect::Exceptions::
|
|
161
|
+
raise SpreadsheetArchitect::Exceptions::InvalidRangeValue.new(:columns, range)
|
|
141
162
|
end
|
|
142
163
|
|
|
143
164
|
unless start_row.to_i <= num_rows && end_row.to_i <= num_rows
|
|
144
|
-
raise SpreadsheetArchitect::Exceptions::
|
|
165
|
+
raise SpreadsheetArchitect::Exceptions::InvalidRangeValue.new(:rows, range)
|
|
145
166
|
end
|
|
146
167
|
else
|
|
147
168
|
raise SpreadsheetArchitect::Exceptions::InvalidRangeError.new(:format, range)
|
|
@@ -10,7 +10,9 @@ module SpreadsheetArchitect
|
|
|
10
10
|
if options[:headers] == true
|
|
11
11
|
headers = []
|
|
12
12
|
|
|
13
|
-
if
|
|
13
|
+
if options[:data]
|
|
14
|
+
headers = false
|
|
15
|
+
else
|
|
14
16
|
needs_headers = true
|
|
15
17
|
end
|
|
16
18
|
elsif options[:headers].is_a?(Array)
|
|
@@ -143,50 +145,22 @@ module SpreadsheetArchitect
|
|
|
143
145
|
end
|
|
144
146
|
|
|
145
147
|
if options[:freeze]
|
|
148
|
+
options[:freeze] = SpreadsheetArchitect::Utils.symbolize_keys(options[:freeze])
|
|
149
|
+
|
|
146
150
|
if options[:freeze_headers]
|
|
147
151
|
raise SpreadsheetArchitect::Exceptions::ArgumentError.new('Cannot use both :freeze and :freeze_headers options at the same time')
|
|
148
|
-
elsif options[:freeze].is_a?(Hash) && !options[:freeze][:rows]
|
|
149
|
-
raise SpreadsheetArchitect::Exceptions::ArgumentError.new('Must provide a :rows key when passing a hash to the :freeze option')
|
|
150
152
|
end
|
|
151
153
|
end
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def self.convert_styles_to_ods(styles={})
|
|
157
|
-
styles = {} unless styles.is_a?(Hash)
|
|
158
|
-
styles = stringify_keys(styles)
|
|
159
|
-
|
|
160
|
-
property_styles = {}
|
|
161
|
-
|
|
162
|
-
text_styles = {}
|
|
163
|
-
text_styles['font-weight'] = styles.delete('bold') ? 'bold' : styles.delete('font-weight')
|
|
164
|
-
text_styles['font-size'] = styles.delete('font_size') || styles.delete('font-size')
|
|
165
|
-
text_styles['font-style'] = styles.delete('italic') ? 'italic' : styles.delete('font-style')
|
|
166
|
-
if styles['underline']
|
|
167
|
-
styles.delete('underline')
|
|
168
|
-
text_styles['text-underline-style'] = 'solid'
|
|
169
|
-
text_styles['text-underline-type'] = 'single'
|
|
170
|
-
end
|
|
171
|
-
if styles['align']
|
|
172
|
-
text_styles['align'] = true
|
|
173
|
-
end
|
|
174
|
-
if styles['color'].respond_to?(:sub) && !styles['color'].empty?
|
|
175
|
-
text_styles['color'] = "##{styles.delete('color').sub('#','')}"
|
|
176
|
-
end
|
|
177
|
-
text_styles.delete_if{|_,v| v.nil?}
|
|
178
|
-
property_styles['text'] = text_styles
|
|
179
|
-
|
|
180
|
-
cell_styles = {}
|
|
181
|
-
styles['background_color'] ||= styles.delete('background-color')
|
|
182
|
-
if styles['background_color'].respond_to?(:sub) && !styles['background_color'].empty?
|
|
183
|
-
cell_styles['background-color'] = "##{styles.delete('background_color').sub('#','')}"
|
|
155
|
+
if options[:escape_formulas].nil?
|
|
156
|
+
options[:escape_formulas] = true
|
|
184
157
|
end
|
|
185
158
|
|
|
186
|
-
|
|
187
|
-
|
|
159
|
+
if options[:use_zero_based_row_index].nil?
|
|
160
|
+
options[:use_zero_based_row_index] = false
|
|
161
|
+
end
|
|
188
162
|
|
|
189
|
-
return
|
|
163
|
+
return options
|
|
190
164
|
end
|
|
191
165
|
|
|
192
166
|
private
|
|
@@ -290,8 +264,9 @@ module SpreadsheetArchitect
|
|
|
290
264
|
row_style: Hash,
|
|
291
265
|
sheet_name: String,
|
|
292
266
|
spreadsheet_columns: [Proc, Symbol, String],
|
|
267
|
+
escape_formulas: [TrueClass, FalseClass, Array],
|
|
268
|
+
use_zero_based_row_index: [TrueClass, FalseClass],
|
|
293
269
|
}.freeze
|
|
294
270
|
|
|
295
|
-
|
|
296
271
|
end
|
|
297
272
|
end
|