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.
Files changed (217) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -1
  3. data/README.md +10 -14
  4. data/lib/spreadsheet_architect/class_methods/ods.rb +18 -8
  5. data/lib/spreadsheet_architect/class_methods/xlsx.rb +76 -32
  6. data/lib/spreadsheet_architect/exceptions.rb +30 -13
  7. data/lib/spreadsheet_architect/utils/ods.rb +66 -0
  8. data/lib/spreadsheet_architect/utils/xlsx.rb +29 -8
  9. data/lib/spreadsheet_architect/utils.rb +13 -38
  10. data/lib/spreadsheet_architect/version.rb +1 -1
  11. data/lib/spreadsheet_architect.rb +3 -2
  12. data/test/dummy_app/app/controllers/spreadsheets_controller.rb +1 -1
  13. data/test/dummy_app/config/application.rb +4 -12
  14. data/test/dummy_app/config/routes.rb +1 -1
  15. data/test/dummy_app/db/test.sqlite3 +0 -0
  16. data/test/dummy_app/log/test.log +79842 -63691
  17. data/test/dummy_app/tmp/2.0.1/integration/alt_xlsx.xlsx +0 -0
  18. data/test/dummy_app/tmp/2.0.1/integration/csv.csv +6 -0
  19. data/test/dummy_app/tmp/2.0.1/integration/ods.ods +0 -0
  20. data/test/dummy_app/tmp/2.0.1/integration/xlsx.xlsx +0 -0
  21. data/test/dummy_app/tmp/2.0.1/kitchen_sink.ods +0 -0
  22. data/test/dummy_app/tmp/2.0.1/kitchen_sink.xlsx +0 -0
  23. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/data.csv +3 -0
  24. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/data.ods +0 -0
  25. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/data.xlsx +0 -0
  26. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/empty.csv +1 -0
  27. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/empty.ods +0 -0
  28. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/empty.xlsx +0 -0
  29. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/instances.csv +6 -0
  30. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/instances.ods +0 -0
  31. data/test/dummy_app/tmp/2.0.1/models/ActiveModelObject/instances.xlsx +0 -0
  32. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/data.csv +3 -0
  33. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/data.ods +0 -0
  34. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/data.xlsx +0 -0
  35. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/empty.csv +0 -0
  36. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/empty.ods +0 -0
  37. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/empty.xlsx +0 -0
  38. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/instances.csv +6 -0
  39. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/instances.ods +0 -0
  40. data/test/dummy_app/tmp/2.0.1/models/CustomColumnsMethodPost/instances.xlsx +0 -0
  41. data/test/dummy_app/tmp/2.0.1/models/CustomPost/data.csv +3 -0
  42. data/test/dummy_app/tmp/2.0.1/models/CustomPost/data.ods +0 -0
  43. data/test/dummy_app/tmp/2.0.1/models/CustomPost/data.xlsx +0 -0
  44. data/test/dummy_app/tmp/2.0.1/models/CustomPost/empty.csv +1 -0
  45. data/test/dummy_app/tmp/2.0.1/models/CustomPost/empty.ods +0 -0
  46. data/test/dummy_app/tmp/2.0.1/models/CustomPost/empty.xlsx +0 -0
  47. data/test/dummy_app/tmp/2.0.1/models/CustomPost/instances.csv +6 -0
  48. data/test/dummy_app/tmp/2.0.1/models/CustomPost/instances.ods +0 -0
  49. data/test/dummy_app/tmp/2.0.1/models/CustomPost/instances.xlsx +0 -0
  50. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/data.csv +3 -0
  51. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/data.ods +0 -0
  52. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/data.xlsx +0 -0
  53. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/empty.csv +1 -0
  54. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/empty.ods +0 -0
  55. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/empty.xlsx +0 -0
  56. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/instances.csv +6 -0
  57. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/instances.ods +0 -0
  58. data/test/dummy_app/tmp/2.0.1/models/LegacyPlainRubyObject/instances.xlsx +0 -0
  59. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/data.csv +3 -0
  60. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/data.ods +0 -0
  61. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/data.xlsx +0 -0
  62. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/empty.csv +1 -0
  63. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/empty.ods +0 -0
  64. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/empty.xlsx +0 -0
  65. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/instances.csv +6 -0
  66. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/instances.ods +0 -0
  67. data/test/dummy_app/tmp/2.0.1/models/PlainRubyObject/instances.xlsx +0 -0
  68. data/test/dummy_app/tmp/2.0.1/models/Post/data.csv +3 -0
  69. data/test/dummy_app/tmp/2.0.1/models/Post/data.ods +0 -0
  70. data/test/dummy_app/tmp/2.0.1/models/Post/data.xlsx +0 -0
  71. data/test/dummy_app/tmp/2.0.1/models/Post/empty.csv +0 -0
  72. data/test/dummy_app/tmp/2.0.1/models/Post/empty.ods +0 -0
  73. data/test/dummy_app/tmp/2.0.1/models/Post/empty.xlsx +0 -0
  74. data/test/dummy_app/tmp/2.0.1/models/Post/instances.csv +6 -0
  75. data/test/dummy_app/tmp/2.0.1/models/Post/instances.ods +0 -0
  76. data/test/dummy_app/tmp/2.0.1/models/Post/instances.xlsx +0 -0
  77. data/test/dummy_app/tmp/2.0.1/multi_sheet.ods +0 -0
  78. data/test/dummy_app/tmp/2.0.1/multi_sheet.xlsx +0 -0
  79. data/test/dummy_app/tmp/3.0.0.pre/integration/alt_xlsx.xlsx +0 -0
  80. data/test/dummy_app/tmp/3.0.0.pre/integration/csv.csv +5 -5
  81. data/test/dummy_app/tmp/3.0.0.pre/integration/ods.ods +0 -0
  82. data/test/dummy_app/tmp/3.0.0.pre/integration/xlsx.xlsx +0 -0
  83. data/test/dummy_app/tmp/3.0.0.pre/kitchen_sink.ods +0 -0
  84. data/test/dummy_app/tmp/3.0.0.pre/kitchen_sink.xlsx +0 -0
  85. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/data.csv +1 -1
  86. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/data.ods +0 -0
  87. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/data.xlsx +0 -0
  88. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/empty.ods +0 -0
  89. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/empty.xlsx +0 -0
  90. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/instances.csv +5 -5
  91. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/instances.ods +0 -0
  92. data/test/dummy_app/tmp/3.0.0.pre/models/ActiveModelObject/instances.xlsx +0 -0
  93. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/data.csv +1 -1
  94. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/data.ods +0 -0
  95. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/data.xlsx +0 -0
  96. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/empty.ods +0 -0
  97. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/empty.xlsx +0 -0
  98. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/instances.csv +5 -5
  99. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/instances.ods +0 -0
  100. data/test/dummy_app/tmp/3.0.0.pre/models/CustomColumnsMethodPost/instances.xlsx +0 -0
  101. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/data.csv +1 -1
  102. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/data.ods +0 -0
  103. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/data.xlsx +0 -0
  104. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/empty.ods +0 -0
  105. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/empty.xlsx +0 -0
  106. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/instances.csv +5 -5
  107. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/instances.ods +0 -0
  108. data/test/dummy_app/tmp/3.0.0.pre/models/CustomPost/instances.xlsx +0 -0
  109. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/data.csv +1 -1
  110. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/data.ods +0 -0
  111. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/data.xlsx +0 -0
  112. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/empty.ods +0 -0
  113. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/empty.xlsx +0 -0
  114. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/instances.csv +5 -5
  115. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/instances.ods +0 -0
  116. data/test/dummy_app/tmp/3.0.0.pre/models/LegacyPlainRubyObject/instances.xlsx +0 -0
  117. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/data.csv +1 -1
  118. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/data.ods +0 -0
  119. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/data.xlsx +0 -0
  120. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/empty.csv +0 -1
  121. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/empty.ods +0 -0
  122. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/empty.xlsx +0 -0
  123. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/instances.csv +5 -5
  124. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/instances.ods +0 -0
  125. data/test/dummy_app/tmp/3.0.0.pre/models/PlainRubyObject/instances.xlsx +0 -0
  126. data/test/dummy_app/tmp/3.0.0.pre/models/Post/data.csv +1 -1
  127. data/test/dummy_app/tmp/3.0.0.pre/models/Post/data.ods +0 -0
  128. data/test/dummy_app/tmp/3.0.0.pre/models/Post/data.xlsx +0 -0
  129. data/test/dummy_app/tmp/3.0.0.pre/models/Post/empty.csv +1 -0
  130. data/test/dummy_app/tmp/3.0.0.pre/models/Post/empty.ods +0 -0
  131. data/test/dummy_app/tmp/3.0.0.pre/models/Post/empty.xlsx +0 -0
  132. data/test/dummy_app/tmp/3.0.0.pre/models/Post/instances.csv +5 -5
  133. data/test/dummy_app/tmp/3.0.0.pre/models/Post/instances.ods +0 -0
  134. data/test/dummy_app/tmp/3.0.0.pre/models/Post/instances.xlsx +0 -0
  135. data/test/dummy_app/tmp/3.0.0.pre/multi_sheet.ods +0 -0
  136. data/test/dummy_app/tmp/3.0.0.pre/multi_sheet.xlsx +0 -0
  137. data/test/dummy_app/tmp/axlsx-master/integration/alt_xlsx.xlsx +0 -0
  138. data/test/dummy_app/tmp/axlsx-master/integration/csv.csv +6 -0
  139. data/test/dummy_app/tmp/axlsx-master/integration/ods.ods +0 -0
  140. data/test/dummy_app/tmp/axlsx-master/integration/xlsx.xlsx +0 -0
  141. data/test/dummy_app/tmp/axlsx-master/kitchen_sink.ods +0 -0
  142. data/test/dummy_app/tmp/axlsx-master/kitchen_sink.xlsx +0 -0
  143. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/data.csv +4 -0
  144. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/data.ods +0 -0
  145. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/data.xlsx +0 -0
  146. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/empty.csv +1 -0
  147. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/empty.ods +0 -0
  148. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/empty.xlsx +0 -0
  149. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/instances.csv +6 -0
  150. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/instances.ods +0 -0
  151. data/test/dummy_app/tmp/axlsx-master/models/ActiveModelObject/instances.xlsx +0 -0
  152. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/data.csv +4 -0
  153. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/data.ods +0 -0
  154. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/data.xlsx +0 -0
  155. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/empty.csv +1 -0
  156. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/empty.ods +0 -0
  157. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/empty.xlsx +0 -0
  158. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/instances.csv +6 -0
  159. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/instances.ods +0 -0
  160. data/test/dummy_app/tmp/axlsx-master/models/CustomColumnsMethodPost/instances.xlsx +0 -0
  161. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/data.csv +4 -0
  162. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/data.ods +0 -0
  163. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/data.xlsx +0 -0
  164. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/empty.csv +1 -0
  165. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/empty.ods +0 -0
  166. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/empty.xlsx +0 -0
  167. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/instances.csv +6 -0
  168. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/instances.ods +0 -0
  169. data/test/dummy_app/tmp/axlsx-master/models/CustomPost/instances.xlsx +0 -0
  170. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/data.csv +4 -0
  171. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/data.ods +0 -0
  172. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/data.xlsx +0 -0
  173. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/empty.csv +1 -0
  174. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/empty.ods +0 -0
  175. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/empty.xlsx +0 -0
  176. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/instances.csv +6 -0
  177. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/instances.ods +0 -0
  178. data/test/dummy_app/tmp/axlsx-master/models/LegacyPlainRubyObject/instances.xlsx +0 -0
  179. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/data.csv +4 -0
  180. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/data.ods +0 -0
  181. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/data.xlsx +0 -0
  182. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/empty.csv +1 -0
  183. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/empty.ods +0 -0
  184. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/empty.xlsx +0 -0
  185. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/instances.csv +6 -0
  186. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/instances.ods +0 -0
  187. data/test/dummy_app/tmp/axlsx-master/models/PlainRubyObject/instances.xlsx +0 -0
  188. data/test/dummy_app/tmp/axlsx-master/models/Post/data.csv +4 -0
  189. data/test/dummy_app/tmp/axlsx-master/models/Post/data.ods +0 -0
  190. data/test/dummy_app/tmp/axlsx-master/models/Post/data.xlsx +0 -0
  191. data/test/dummy_app/tmp/axlsx-master/models/Post/empty.csv +1 -0
  192. data/test/dummy_app/tmp/axlsx-master/models/Post/empty.ods +0 -0
  193. data/test/dummy_app/tmp/axlsx-master/models/Post/empty.xlsx +0 -0
  194. data/test/dummy_app/tmp/axlsx-master/models/Post/instances.csv +6 -0
  195. data/test/dummy_app/tmp/axlsx-master/models/Post/instances.ods +0 -0
  196. data/test/dummy_app/tmp/axlsx-master/models/Post/instances.xlsx +0 -0
  197. data/test/dummy_app/tmp/axlsx-master/multi_sheet.ods +0 -0
  198. data/test/dummy_app/tmp/axlsx-master/multi_sheet.xlsx +0 -0
  199. data/test/integration/application_test.rb +8 -16
  200. data/test/models/all_models_test.rb +15 -19
  201. data/test/test_helper.rb +38 -9
  202. data/test/unit/ods/general_test.rb +121 -0
  203. data/test/unit/{formats_test.rb → rails/formats_test.rb} +1 -1
  204. data/test/unit/{exceptions_test.rb → spreadsheet_architect/exceptions_test.rb} +19 -15
  205. data/test/unit/{general_test.rb → spreadsheet_architect/spreadsheet_architect_test.rb} +3 -3
  206. data/test/unit/spreadsheet_architect/utils/ods_test.rb +58 -0
  207. data/test/unit/{xlsx_utils_test.rb → spreadsheet_architect/utils/xlsx_test.rb} +13 -21
  208. data/test/unit/{utils_test.rb → spreadsheet_architect/utils_test.rb} +12 -35
  209. data/test/unit/xlsx/freeze_test.rb +79 -0
  210. data/test/unit/xlsx/general_test.rb +199 -0
  211. metadata +381 -128
  212. data/test/dummy_app/config/environments/development.rb +0 -30
  213. data/test/dummy_app/config/environments/production.rb +0 -60
  214. data/test/unit/kitchen_sink_test.rb +0 -110
  215. data/test/unit/multi_sheet_test.rb +0 -29
  216. data/test/unit/options_test.rb +0 -9
  217. data/test/unit/xlsx_freeze_test.rb +0 -44
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f453f3bd541db38744f93c7803a473dea7f8dee0c9c45ab86523992c78bd6317
4
- data.tar.gz: 5c92d3ac4e35db0c17bd4da1e4325d08700decf476546fde20a66aa6057dacdd
3
+ metadata.gz: c88ecaffa3abed6ef127dc13d42c612ebf224c6d8552590d68ae544af2713f93
4
+ data.tar.gz: d0e864c2f50e99040f932da595b7270dd0e9c0161fc1189e6d99cb43126f6b5a
5
5
  SHA512:
6
- metadata.gz: e89d0f1f1968275084495fdd420af039b61d7033606be0d9b63428fc3aab944baf82377103057fbf1ec43c91c02a7c48210bd81617ba55893ef998c3848265c0
7
- data.tar.gz: ddfdcd2c578a1aa10dd2839368cdf99b897a49abf1a888bae40dbd08ad310f4ee26a5bc93ce9fdd484092b5f32ee4d5195c7cb5bdb466fcdf5dec6250e79603e
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/v4.2.0...master)
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/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.
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*|`{rows: (1..4), columns: :all}`|Make all specified rows and columns frozen/fixed so they do not scroll.|
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
- [![Solid Foundation Web Development Logo](https://solidfoundationwebdev.com/logo-sm.png)](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.convert_styles_to_ods(options[:header_style]).each do |prop, styles|
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.convert_styles_to_ods(options[:row_style]).each do |prop, styles|
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
- type = options[:column_types][i]
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
- if (type && [:date, :time].include?(type)) || val.respond_to?(:strftime)
61
- type = :string
62
- val = val.to_s
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 val, style: :row_style, type: type
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
- row_data.each_with_index do |x,i|
83
- if (x.respond_to?(:empty) ? x.empty? : x.nil?)
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
- types[i] = options[:column_types][i]
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
- types[i] ||= SpreadsheetArchitect::Utils::XLSX.get_type(x)
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] = SpreadsheetArchitect::Utils.symbolize_keys(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
- ### 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
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][: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
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
- case type
19
- when :columns, :rows
20
- super("Invalid range `#{range}` passed. Some of the #{type} specified were greater than the total number of #{type}")
21
- when :format
22
- super("Invalid range `#{range}` passed. Format must be as follows: A1:D4")
23
- when :type
24
- super("Invalid range type `#{range}`. Valid types are String and Hash")
25
- else
26
- super("Invalid range `#{range}` passed.")
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 InvalidRangeStylesOptionError < ArgumentError
38
- def initialize(type, opt)
39
- super("Invalid or missing :#{type} option for `#{opt}`. :#{type} can be an integer, range, or :all")
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
- return type unless (type.respond_to?(:empty?) ? type.empty? : type.nil?)
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::InvalidRangeStylesOptionError.new(:columns, hash)
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
- when :all
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::InvalidRangeStylesOptionError.new(:rows, hash)
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::InvalidRangeError.new(:columns, range)
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::InvalidRangeError.new(:rows, range)
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 !options[:data]
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
- return options
154
- end
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
- cell_styles.delete_if{|_,v| v.nil?}
187
- property_styles['cell'] = cell_styles
159
+ if options[:use_zero_based_row_index].nil?
160
+ options[:use_zero_based_row_index] = false
161
+ end
188
162
 
189
- return property_styles
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
@@ -1,3 +1,3 @@
1
1
  module SpreadsheetArchitect
2
- VERSION = "4.2.0"
2
+ VERSION = "5.0.0"
3
3
  end