spreadsheet_architect 3.3.1 → 4.0.0

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