spreadsheet_architect 4.2.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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