csv_rb 0.5.2

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 (89) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile +24 -0
  4. data/Gemfile.lock +250 -0
  5. data/Guardfile +16 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +510 -0
  8. data/Rakefile +29 -0
  9. data/lib/csv_rb/action_controller.rb +66 -0
  10. data/lib/csv_rb/plain_builder.rb +27 -0
  11. data/lib/csv_rb/railtie.rb +16 -0
  12. data/lib/csv_rb/stream_csv_deflator.rb +25 -0
  13. data/lib/csv_rb/template_handler.rb +31 -0
  14. data/lib/csv_rb/version.rb +5 -0
  15. data/lib/csv_rb.rb +6 -0
  16. data/lib/tasks/csv_rb_tasks.rake +4 -0
  17. data/spec/ci.rb +4 -0
  18. data/spec/csv_rb_builder_spec.rb +39 -0
  19. data/spec/csv_rb_mailer_spec.rb +17 -0
  20. data/spec/csv_rb_renderer_spec.rb +18 -0
  21. data/spec/csv_rb_request_spec.rb +220 -0
  22. data/spec/dummy/Rakefile +6 -0
  23. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  24. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  25. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  26. data/spec/dummy/app/controllers/home_controller.rb +58 -0
  27. data/spec/dummy/app/controllers/likes_controller.rb +20 -0
  28. data/spec/dummy/app/controllers/users_controller.rb +39 -0
  29. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec/dummy/app/mailers/notifier.rb +14 -0
  31. data/spec/dummy/app/models/like.rb +3 -0
  32. data/spec/dummy/app/models/user.rb +24 -0
  33. data/spec/dummy/app/views/home/_cover_sheet.csv.csvrb +1 -0
  34. data/spec/dummy/app/views/home/index.csv.csvrb +2 -0
  35. data/spec/dummy/app/views/home/index.html.erb +4 -0
  36. data/spec/dummy/app/views/home/only_html.html.erb +2 -0
  37. data/spec/dummy/app/views/home/useheader.csv.csvrb +1 -0
  38. data/spec/dummy/app/views/home/withpartial.csv.csvrb +2 -0
  39. data/spec/dummy/app/views/layouts/application.html.erb +12 -0
  40. data/spec/dummy/app/views/layouts/users.html.erb +12 -0
  41. data/spec/dummy/app/views/likes/index.csv.csvrb +4 -0
  42. data/spec/dummy/app/views/likes/index.html.erb +17 -0
  43. data/spec/dummy/app/views/notifier/instructions.html.erb +14 -0
  44. data/spec/dummy/app/views/notifier/instructions.txt.erb +6 -0
  45. data/spec/dummy/app/views/users/export.csv.csvrb +1 -0
  46. data/spec/dummy/app/views/users/index.csv.csvrb +1 -0
  47. data/spec/dummy/app/views/users/index.html.erb +23 -0
  48. data/spec/dummy/app/views/users/noaction.csv.csvrb +1 -0
  49. data/spec/dummy/app/views/users/respond_with.csv.csvrb +1 -0
  50. data/spec/dummy/app/views/users/send_instructions.csv.csvrb +2 -0
  51. data/spec/dummy/bin/bundle +3 -0
  52. data/spec/dummy/bin/rails +4 -0
  53. data/spec/dummy/bin/rake +4 -0
  54. data/spec/dummy/config/application.rb +22 -0
  55. data/spec/dummy/config/boot.rb +5 -0
  56. data/spec/dummy/config/database.yml +25 -0
  57. data/spec/dummy/config/environment.rb +5 -0
  58. data/spec/dummy/config/environments/development.rb +37 -0
  59. data/spec/dummy/config/environments/production.rb +83 -0
  60. data/spec/dummy/config/environments/test.rb +40 -0
  61. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  62. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  63. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  64. data/spec/dummy/config/initializers/inflections.rb +16 -0
  65. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  66. data/spec/dummy/config/initializers/secret_token.rb +2 -0
  67. data/spec/dummy/config/initializers/session_store.rb +3 -0
  68. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  69. data/spec/dummy/config/locales/en.yml +23 -0
  70. data/spec/dummy/config/routes.rb +17 -0
  71. data/spec/dummy/config/secrets.yml +22 -0
  72. data/spec/dummy/config.ru +4 -0
  73. data/spec/dummy/db/development.sqlite3 +0 -0
  74. data/spec/dummy/db/migrate/20120717192452_create_users.rb +12 -0
  75. data/spec/dummy/db/migrate/20121206210955_create_likes.rb +10 -0
  76. data/spec/dummy/db/schema.rb +31 -0
  77. data/spec/dummy/db/test.sqlite3 +0 -0
  78. data/spec/dummy/log/development.log +257 -0
  79. data/spec/dummy/log/test.log +25347 -0
  80. data/spec/dummy/public/404.html +67 -0
  81. data/spec/dummy/public/422.html +67 -0
  82. data/spec/dummy/public/500.html +66 -0
  83. data/spec/dummy/public/favicon.ico +0 -0
  84. data/spec/reset_gems.sh +2 -0
  85. data/spec/spec_helper.rb +39 -0
  86. data/spec/test_5.2.sh +16 -0
  87. data/spec/test_all_rails.sh +4 -0
  88. data/spec/test_revert.sh +3 -0
  89. metadata +413 -0
data/README.md ADDED
@@ -0,0 +1,510 @@
1
+ csvrb-Rails — Spreadsheet templates for Rails
2
+ ===================================================
3
+
4
+ [![Build Status](https://secure.travis-ci.org/straydogstudio/csv_rb.svg?branch=master)](http://travis-ci.org/straydogstudio/csv_rb)
5
+ [![Gem
6
+ Version](https://badge.fury.io/rb/csv_rb.svg)](http://badge.fury.io/rb/csv_rb)
7
+ [![Dependency Status](https://gemnasium.com/straydogstudio/csv_rb.svg?branch=master)](https://gemnasium.com/straydogstudio/csv_rb)
8
+ [![Coverage
9
+ Status](https://coveralls.io/repos/straydogstudio/csv_rb/badge.svg)](https://coveralls.io/r/straydogstudio/csv_rb)
10
+
11
+ ![Total downloads](http://ruby-gem-downloads-badge.herokuapp.com/csv_rb?type=total)
12
+ ![Downloads for 0.4.0](http://ruby-gem-downloads-badge.herokuapp.com/csv_rb/0.4.0?label=0.4.0)
13
+ ![Downloads for 0.5.0](http://ruby-gem-downloads-badge.herokuapp.com/csv_rb/0.5.0?label=0.5.0)
14
+ ![Downloads for latest release](http://ruby-gem-downloads-badge.herokuapp.com/csv_rb/0.5.1?label=0.5.1)
15
+
16
+ ## Installation
17
+
18
+ In your Gemfile:
19
+
20
+ ```ruby
21
+ gem 'rubyzip', '>= 1.2.1'
22
+ gem 'csvrb', git: 'https://github.com/randym/csvrb.git', ref: 'c8ac844'
23
+ gem 'csv_rb'
24
+ ```
25
+
26
+ **NOTE:** csvrb has been pending release for a long time. You must specify the master on github to support Rubyzip 1.2.1.
27
+
28
+ If `rubyzip 1.0.0` is needed:
29
+
30
+ ```ruby
31
+ gem 'rubyzip', '= 1.0.0'
32
+ gem 'csvrb', '= 2.0.1'
33
+ gem 'csv_rb'
34
+ ```
35
+
36
+ If `rubyzip >= 1.1.0` is needed:
37
+
38
+ ```ruby
39
+ gem 'rubyzip', '~> 1.1.0'
40
+ gem 'csvrb', '2.1.0.pre'
41
+ gem 'csv_rb'
42
+ ```
43
+
44
+ ## Requirements
45
+
46
+ * Rails 4.2, 5.0 or 5.1 (tested)
47
+ * For Rails 3.1 or 3.2 use version 3.0
48
+ * **As of 0.5.0 requires csvrb 2.0.1, but strongly suggests 2.1.0.pre, which requires rubyzip 1.1.0**
49
+ * As of Rails 4.1 you must use `render_to_string` to render a mail attachment.
50
+
51
+ ## FYI
52
+
53
+ * This gem depends on [csvrb](https://github.com/randym/csvrb). See [the blog](http://csvrb.blog.randym.net/) or the [examples page](https://github.com/randym/csvrb/blob/master/examples/example.rb) for usage.
54
+ * Check out [csvrb_styler](https://github.com/sakovias/csvrb_styler) by [sakovias](https://github.com/sakovias) for easier styles and borders!
55
+
56
+ ## Usage
57
+
58
+ csvrb-Rails provides a renderer and a template handler. It adds the `:csv` format and parses `.csv.csvrb` templates. This lets you take all the [csvrb](https://github.com/randym/csvrb) code out of your controller or model and place it inside the template, where view code belongs! **See [this blog post](http://csvrb.blog.randym.net/2012/08/excel-on-rails-like-pro-with-CSVRb.html) for a more complete walkthrough.**
59
+
60
+ ### Controller
61
+
62
+ To use csvrb-Rails set your instance variables in your controller and configure the response if needed:
63
+
64
+ ```ruby
65
+ class ButtonController < ApplicationController
66
+ def action_name
67
+ @buttons = Button.all
68
+ respond_to do |format|
69
+ format.csv
70
+ end
71
+ end
72
+ end
73
+ ```
74
+
75
+ ### Template
76
+
77
+ Create the template with the `.csv.csvrb` extension (`action_name.csv.csvrb` for example.) [**Watch out for typos!**](#troubleshooting) In the template, use csv_package variable to create your spreadsheet:
78
+
79
+ ```ruby
80
+ wb = csv_package.workbook
81
+ wb.add_worksheet(name: "Buttons") do |sheet|
82
+ @buttons.each do |button|
83
+ sheet.add_row [button.name, button.category, button.price]
84
+ end
85
+ end
86
+ ```
87
+
88
+ This is where you place all your [csvrb](https://github.com/randym/csvrb) specific markup. Add worksheets, fill content, merge cells, add styles. See the [csvrb examples](https://github.com/randym/csvrb/tree/master/examples/example.rb) page to see what you can do.
89
+
90
+ Remember, like in `erb` templates, view helpers are available to use the `.csv.csvrb` template.
91
+
92
+ That's it. Call your action and your spreadsheet will be delivered.
93
+
94
+ ### Rendering Options
95
+
96
+ You can call render in any of the following ways:
97
+
98
+ ```ruby
99
+ # rendered, no disposition/filename header
100
+ render 'buttons'
101
+ # rendered from another controller, no disposition/filename header
102
+ render 'featured/latest'
103
+ # template and filename of 'buttons'
104
+ render csv: 'buttons'
105
+ # template from another controller, filename of 'latest_buttons'
106
+ render csv: 'latest_buttons', template: 'featured/latest'
107
+ ```
108
+
109
+ ### Disposition
110
+
111
+ To specify a disposition (such as `inline` so the spreadsheet is opened inside the browser), use the `disposition` option:
112
+
113
+ ```ruby
114
+ render csv: "buttons", disposition: 'inline'
115
+ ```
116
+
117
+ If `render csv:` is called, the disposition defaults to `attachment`.
118
+
119
+ ### File name
120
+
121
+ If Rails calls csvrb through default channels (because you use `format.csv {}` for example) you must set the filename using the response header:
122
+
123
+ ```ruby
124
+ format.csv {
125
+ response.headers['Content-Disposition'] = 'attachment; filename="my_new_filename.csv"'
126
+ }
127
+ ```
128
+
129
+ If you use `render csv:` the gem will try to guess the file name:
130
+
131
+ ```ruby
132
+ # filename of 'buttons'
133
+ render csv: 'buttons'
134
+ # filename of 'latest_buttons'
135
+ render csv: 'latest_buttons', template: 'featured/latest'
136
+ ```
137
+
138
+ If that fails, pass the `:filename` parameter:
139
+
140
+ ```ruby
141
+ render csv: "action_or_template", filename: "my_new_filename.csv"
142
+ ```
143
+
144
+ ### csv_rb Package Options
145
+
146
+ csv_rb provides three options for initializing a spreadsheet:
147
+
148
+ - **:csv_author** (String) - The author of the document
149
+ - **:csv_created_at** (Time) - Timestamp in the document properties (defaults to current time)
150
+ - **:csv_use_shared_strings** (Boolean) - This is passed to the workbook to specify that shared strings should be used when serializing the package.
151
+
152
+ To pass these to the new package, pass them to `render :csv` _or_ pass them as local variables.
153
+
154
+ For example, to set the author name, pass the `:csv_author` parameter to `render :csv` _or_ as a local variable:
155
+
156
+ ```ruby
157
+ render csv: "index", csv_author: "Elmer Fudd"
158
+ render "index", locals: {csv_author: "Elmer Fudd"}
159
+ ```
160
+
161
+ Other examples:
162
+
163
+ ```ruby
164
+ render csv: "index", csv_created_at: 3.days.ago
165
+ render "index", locals: {csv_use_shared_strings: true}
166
+ ```
167
+
168
+ ### Partials
169
+
170
+ Partials work as expected, but you must pass in relevant spreadsheet variables:
171
+
172
+ ```ruby
173
+ wb = csv_package.workbook
174
+ render :partial => 'cover_sheet', :locals => {:wb => wb}
175
+ wb.add_worksheet(name: "Content") do |sheet|
176
+ sheet.add_row ['Content']
177
+ end
178
+ ```
179
+
180
+ With the partial simply using the passed variables:
181
+
182
+ ```ruby
183
+ wb.add_worksheet(name: "Cover Sheet") do |sheet|
184
+ sheet.add_row ['Cover', 'Sheet']
185
+ end
186
+ ```
187
+
188
+ ### Mailers
189
+
190
+ To use an csv template to render a mail attachment, use the following syntax:
191
+
192
+ ```ruby
193
+ class UserMailer < ActionMailer::Base
194
+ def export(users)
195
+ csv = render_to_string layout: false, handlers: [:csvrb], formats: [:csv], template: "users/export", locals: {users: users}
196
+ attachment = Base64.encode64(csv)
197
+ attachments["Users.csv"] = {mime_type: Mime[:csv], content: attachment, encoding: 'base64'}
198
+ # For rails 4 use Mime::csv
199
+ # attachments["Users.csv"] = {mime_type: Mime::csv, content: attachment, encoding: 'base64'}
200
+ # self.instance_variable_set(:@_lookup_context, nil) # If attachments are rendered as content, try this and open an issue
201
+ ...
202
+ end
203
+ end
204
+ ```
205
+
206
+ * If the route specifies or suggests the `:csv` format you do not need to specify `formats` or `handlers`.
207
+ * If the template (`users/export`) can refer to only one file (the csv.csvrb template), you do not need to specify `handlers`, provided the `formats` includes `:csv`.
208
+ * Specifying the encoding as 'base64' can avoid UTF-8 errors.
209
+
210
+ ### Scripts
211
+
212
+ To generate a template within a script, you need to instantiate an ActionView context. Here are two gists showing how to perform this:
213
+
214
+ * [Using rails runner](https://gist.github.com/straydogstudio/323139591f2cc5d48fbc)
215
+ * [Without rails runner](https://gist.github.com/straydogstudio/dceb775ead81470cea70)
216
+
217
+ ### Testing
218
+
219
+ There is no built-in way to test your resulting workbooks / templates. But here is a piece of code that may help you to find a way.
220
+
221
+ #### First, create a shared context
222
+
223
+ ```ruby
224
+ RSpec.shared_context 'csvrb' do
225
+
226
+ # all csv specs describe must be normalized
227
+ # "folder/view_name.csv.csvrb"
228
+ # allow to infer the template path
229
+ template_name = description
230
+
231
+ let(:template_path) do
232
+ ['app', 'views', template_name]
233
+ end
234
+
235
+ # This helper will be used in tests
236
+ def render_template(locals = {})
237
+ csvrb_binding = Kernel.binding
238
+ locals.each do |key, value|
239
+ csvrb_binding.local_variable_set key, value
240
+ end
241
+ # define a default workbook and a default sheet useful when testing partial in isolation
242
+ wb = CSVRb::Package.new.workbook
243
+ csvrb_binding.local_variable_set(:wb, wb)
244
+ csvrb_binding.local_variable_set(:sheet, wb.add_worksheet)
245
+
246
+ # mimics an ActionView::Template class, presenting a 'source' method
247
+ # to retrieve the content of the template
248
+ csvrb_binding.eval(ActionView::Template::Handlers::CSVRbBuilder.call(Struct.new(:source).new(File.read(Rails.root.join(*template_path)))))
249
+ csvrb_binding.local_variable_get(:wb)
250
+ end
251
+ end
252
+ ```
253
+
254
+ #### Include it in your spec files:
255
+
256
+ ```ruby
257
+ require 'spec_helper'
258
+ require 'helpers/csvrb_context'
259
+
260
+ describe 'shared/_total_request.csv.csvrb' do
261
+ include_context 'csvrb'
262
+
263
+ before :each do
264
+ # all the instance variables here are the one used in 'shared/_total_request.csv.csvrb'
265
+ @widget = mock_model(Widget, name: 'My widget')
266
+ @message_counts = Struct.new(:count_all, :positives, :negatives, :neutrals).new(42, 23, 15, 25)
267
+ end
268
+
269
+ it 'has a title line mentioning the widget' do
270
+ wb = render_template
271
+ sheet = wb.sheet_by_name('Réf. Requête')
272
+ expect(sheet).to have_header_cells ['My widget : Messages de la requête']
273
+ end
274
+
275
+ it 'exports the message counts' do
276
+ wb = render_template
277
+ sheet = wb.sheet_by_name('Réf. Requête')
278
+ expect(sheet).to have_cells(['Toutes tonalités', 'Tonalité positive', 'Tonalité négative', 'Tonalité neutre']).in_row(2)
279
+ expect(sheet).to have_cells([42, 23, 15, 25]).in_row(3)
280
+ end
281
+
282
+ end
283
+ ```
284
+
285
+ #### Matchers used
286
+
287
+ ```ruby
288
+
289
+ # encoding: UTF-8
290
+
291
+ require 'rspec/expectations'
292
+
293
+ module XslsMatchers
294
+
295
+ RSpec::Matchers.define :have_header_cells do |cell_values|
296
+ match do |worksheet|
297
+ worksheet.rows[0].cells.map(&:value) == cell_values
298
+ end
299
+
300
+ failure_message do |actual|
301
+ "Expected #{actual.rows[0].cells.map(&:value)} to be #{expected}"
302
+ end
303
+ end
304
+
305
+ RSpec::Matchers.define :have_cells do |expected|
306
+ match do |worksheet|
307
+ worksheet.rows[@index].cells.map(&:value) == expected
308
+ end
309
+
310
+ chain :in_row do |index|
311
+ @index = index
312
+ end
313
+
314
+ failure_message do |actual|
315
+ "Expected #{actual.rows[@index].cells.map(&:value)} to include #{expected} at row #{@index}."
316
+ end
317
+ end
318
+ end
319
+
320
+ ```
321
+
322
+
323
+ ## Troubleshooting
324
+
325
+ ### Mispellings
326
+
327
+ **It is easy to get the spelling wrong in the extension name, the format.csv statement, or in a render call.** Here are some possibilities:
328
+
329
+ * If it says your template is missing, check that its extension is `.csv.csvrb`.
330
+ * If you get the error `uninitialized constant Mime::XSLX` you have used `format.xslx` instead of `format.csv`, or something similar.
331
+
332
+ ### Mailer Attachments: No content, cannot read, Invalid Byte Sequence in UTF-8
333
+
334
+ If you are having problems with rendering a template and attaching it to a template, try a few options:
335
+
336
+ * Make sure the attachment template does not have the same name as the mailer.
337
+ * After you have rendered the template to string, and before you call the mailer, execute `self.instance_variable_set(:@_lookup_context, nil)`. If you must do this, please open an issue.
338
+ * If you get Invalid Byte Sequence in UTF-8, pass `encoding: 'base64'` with the attachment:
339
+
340
+ ```ruby
341
+ class UserMailer < ActionMailer::Base
342
+ def export(users)
343
+ csv = render_to_string handlers: [:csvrb], formats: [:csv], template: "users/export", locals: {users: users}
344
+ attachments["Users.csv"] = {mime_type: Mime[:csv], content: csv, encoding: 'base64'}
345
+ # For Rails 4 use Mime::csv
346
+ # attachments["Users.csv"] = {mime_type: Mime::csv, content: csv, encoding: 'base64'}
347
+ # self.instance_variable_set(:@_lookup_context, nil) # If attachments are rendered as content, try this and open an issue
348
+ ...
349
+ end
350
+ end
351
+ ```
352
+
353
+ If you get these errors, please open an issue and share code so the bug can be isolated. Or comment on issue [#29](https://github.com/straydogstudio/csv_rb/issues/29) or [#25](https://github.com/straydogstudio/csv_rb/issues/25).
354
+
355
+ ### Generated Files Can't Be Opened or Invalid Byte Sequence in UTF-8
356
+
357
+ Both these errors *appear* to be caused by Rails applying a layout to the template. Passing `layout: false` to `render :csv` should fix this issue. Version 0.5.0 attempts to fix this issue.
358
+
359
+ If you get this error, please open an issue and share code so the bug can be isolated.
360
+
361
+ ### Rails 4.2 changes
362
+
363
+ Before Rails 4.2 you could call:
364
+
365
+ ```ruby
366
+ render csv: "users/index"
367
+ ```
368
+
369
+ And csv_rb could adjust the paths and make sure the template was loaded from the right directory. This is no longer possible because the paths are cached between requests for a given controller. As a result, to display a template in another directory you must use the `:template` parameter (which is normal Rails behavior anyway):
370
+
371
+ ```ruby
372
+ render csv: "index", template: "users/index"
373
+ ```
374
+
375
+ If the request format matches you should be able to call:
376
+
377
+ ```ruby
378
+ render "users/index"
379
+ ```
380
+
381
+ This is a breaking change if you have the old syntax!
382
+
383
+ ### Turbolinks
384
+
385
+ If you are using turbolinks, you may need to disable turbolinks when you link to your spreadsheet:
386
+
387
+ ```ruby
388
+ # turbolinks 5:
389
+ link_to 'Download spreadsheet', path_to_sheet, data: {turbolinks: false}
390
+ ```
391
+
392
+ ### What to do
393
+
394
+ If you are having problems, try to isolate the issue. Use the console or a script to make sure your data is good. Then create the spreadsheet line by line without csvrb-Rails to see if you are having csvrb problems. If you can manually create the spreadsheet, create an issue and we will work it out.
395
+
396
+ ## Dependencies
397
+
398
+ - [Rails](https://github.com/rails/rails)
399
+ - [csvrb](https://github.com/randym/csvrb)
400
+
401
+ ## Authors
402
+
403
+ * [Noel Peden](https://github.com/straydogstudio)
404
+
405
+ ## Contributors
406
+
407
+ Many thanks to [contributors](https://github.com/straydogstudio/csv_rb/graphs/contributors):
408
+
409
+ * [randym](https://github.com/randym)
410
+ * [sugi](https://github.com/sugi)
411
+ * [envek](https://github.com/envek)
412
+ * [engwan](https://github.com/engwan)
413
+ * [maxd](https://github.com/maxd)
414
+ * [firien](https://github.com/firien)
415
+ * [kaluzny](https://github.com/kaluznyo)
416
+ * [sly7-7](https://github.com/sly7-7)
417
+ * [kodram](https://github.com/kodram)
418
+ * [JohnSmall](https://github.com/JohnSmall)
419
+ * [BenoitHiller](https://github.com/BenoitHiller)
420
+
421
+ ## Donations
422
+
423
+ Say thanks for csvrb-Rails by donating! It makes it easier for me to provide to open
424
+ source:
425
+
426
+ [![Click here to lend your support to: csvrb-Rails!](http://www.pledgie.com/campaigns/27737.png?skin_name=chrome)](http://www.pledgie.com/campaigns/27737)
427
+
428
+ ## Change log
429
+
430
+ **May 1st, 2018**: 0.5.2 release
431
+
432
+ - Improved Rails 5 compatibility re MIME type
433
+
434
+ **March 29th, 2017**: 0.5.1 release
435
+
436
+ - Fix stack trace line numbers
437
+ - Thanks to [BenoitHiller](https://github.com/BenoitHiller)
438
+
439
+ **July 26st, 2016**: 0.5.0 release
440
+
441
+ - Support for Rails 5
442
+ - **Tested on on Rails 4.0, 4.1, 4.2, and 5.0**
443
+ - Bug fixes for unreadable files and UTF-8 errors
444
+
445
+ **July 13th, 2015**: 0.4.0 release
446
+
447
+ - Support for Rails 4.2
448
+ - **Removal of forced default_formats** (url format must match)
449
+ - **Tested only on Rails 4.1 and 4.2**
450
+ - **For Rails 3.2 or below, use 0.3.0**
451
+
452
+ **November 20th, 2014**: 0.3.0 release
453
+
454
+ - Support for Rails 4.2.beta4.
455
+ - **Removal of shorthand template syntax** (`render csv: 'another/directory'`)
456
+
457
+ **September 4, 2014**: 0.2.1 release
458
+
459
+ - Rails 4.2.beta1 no longer includes responder. This release checks for the existence of responder before configuring a default responder.
460
+ - Rails 4.2 testing, though not yet on Travis CI
461
+ - Author, created_at, and use_shared_strings parameters for CSVRb::Package.new
462
+
463
+ **April 9, 2014**: 0.2.0 release
464
+
465
+ - Require csvrb 2.0.1, which requires rubyzip 1.0.0
466
+ - Better render handling and testing, which might break former usage
467
+ - Rails 4.1 testing
468
+ - Mailer example update (**use render_to_string not render**)
469
+
470
+ **October 11, 2013**
471
+
472
+ - Handle (and test) respond_to override
473
+
474
+ **October 4, 2013**
475
+
476
+ - Added coveralls
477
+ - Raised testing to csvrb 2.0.1, roo 1.12.2, and rubyzip 1.0.0
478
+
479
+ **July 25, 2013**
480
+
481
+ - Documentation improved
482
+ - Testing for generating partial in mailer
483
+
484
+ **January 18, 2013**: 0.1.4 release
485
+
486
+ - Now supports Rails 4 (thanks [Envek](https://github.com/Envek))
487
+ - If you call render :csv on a request without :csv format, it should force the :csv format. Works on Rails 3.2+.
488
+
489
+ **December 6, 2012**: 0.1.3 release
490
+
491
+ - Fix for absolute template paths
492
+
493
+ **July 25, 2012**: 0.1.2 release
494
+
495
+ - Partials tested
496
+
497
+ **July 19, 2012**: 0.1.1 release
498
+
499
+ - Travis-ci added (thanks [randym](https://github.com/randym))
500
+ - render statements and filename tests fixes (thanks [engwan](https://github.com/engwan))
501
+
502
+ **July 17, 2012**: 0.1.0 release
503
+
504
+ - Tests completed
505
+ - Acts_as_csv tested, example in docs
506
+
507
+ **July 12, 2012**: 0.0.1 release
508
+
509
+ - Initial posting.
510
+ - It works, but there are no tests! Bad programmer!
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'CSVRb'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+ require "rspec/core/rake_task"
24
+ RSpec::Core::RakeTask.new('spec')
25
+
26
+ task :default => :spec
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_controller'
4
+ require 'csv_rb/stream_csv_deflator'
5
+ unless Mime[:csv]
6
+ Mime::Type.register 'text/csv', :csv
7
+ end
8
+
9
+ ActionController::Renderers.add :csv do |filename, options|
10
+ #
11
+ # You can always specify a template:
12
+ #
13
+ # def called_action
14
+ # render csv: 'filename', template: 'controller/diff_action'
15
+ # end
16
+ #
17
+ # And the normal use case works:
18
+ #
19
+ # def called_action
20
+ # render 'diff_action'
21
+ # # or
22
+ # render 'controller/diff_action'
23
+ # end
24
+ #
25
+ options[:template] = filename.gsub(/^.*\//,'') if options[:template] == action_name
26
+ options[:template] = "#{options[:template]}.csv.csvrb" unless options[:template] =~ /\.csvrb/
27
+ options[:layout] = false
28
+ options[:locals] ||= {}
29
+ file_name = "#{options.delete(:filename) || filename.gsub(/^.*\//,'')}#{options.delete(:with_time) ? "-#{Time.zone.now.to_s}" : ''}.csv".sub(/(\.csv)+$/, '.csv')
30
+
31
+
32
+ # if options.delete(:should_stream)
33
+ response.headers["X-Accel-Buffering"] = 'no'
34
+ response.headers["Content-Type"] = "text/csv; charset=utf-8"
35
+ response.headers["Content-Encoding"] = 'deflate'
36
+ response.headers["Content-Disposition"] = %(attachment; filename="#{file_name}")
37
+
38
+
39
+ return self.response_body = Enumerator.new do |y|
40
+ csv = CSVRb::StreamCSVDeflator.new(y)
41
+ instance_eval lookup_context.find_template(options[:template], options[:prefixes], options[:partial], options.dup.merge(formats: [:csv])).source
42
+ csv.close
43
+ end
44
+ # else
45
+ # disposition = options.delete(:disposition) || 'attachment'
46
+ #
47
+ # send_data render_to_string(options), filename: file_name, type: Mime[:csv], disposition: disposition
48
+ # end
49
+ end
50
+
51
+ # For respond_to default
52
+ begin
53
+ ActionController::Responder
54
+ rescue
55
+ else
56
+ class ActionController::Responder
57
+ def to_csv
58
+ @_action_has_layout = false
59
+ if @default_response
60
+ @default_response.call(options)
61
+ else
62
+ controller.render({csv: controller.action_name}.merge(options))
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,27 @@
1
+ module CSVRb
2
+ class PlainBuilder
3
+ def value
4
+ @value ||= "#{}"
5
+ end
6
+
7
+ def stream(row)
8
+ value << CSV.generate_line(row, force_quotes: true, encoding: 'utf-8')
9
+ end
10
+
11
+ def <<(row)
12
+ stream(row)
13
+ end
14
+
15
+ def close
16
+ to_s
17
+ end
18
+
19
+ def to_str
20
+ to_s
21
+ end
22
+
23
+ def to_s
24
+ value
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CSVRb
4
+ class Railtie < Rails::Railtie
5
+ initializer 'csv_rb.initialization' do
6
+ ActiveSupport.on_load(:action_view) do
7
+ require 'csv_rb/template_handler'
8
+ ActionView::Template.register_template_handler :csvrb, ActionView::Template::Handlers::CSVRbBuilder.new
9
+ end
10
+
11
+ ActiveSupport.on_load(:action_controller) do
12
+ require 'csv_rb/action_controller'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ module CSVRb
2
+ class StreamCSVDeflator
3
+ def initialize(enum)
4
+ @enum = enum
5
+ @deflator = Zlib::Deflate.new
6
+ end
7
+
8
+ def y
9
+ @enum
10
+ end
11
+
12
+ def stream(row)
13
+ v = CSV.generate_line(row, force_quotes: true, encoding: 'utf-8')
14
+ y << @deflator.deflate(v, Zlib::SYNC_FLUSH)
15
+ end
16
+
17
+ def <<(row)
18
+ stream(row)
19
+ end
20
+
21
+ def close
22
+ y << @deflator.flush(Zlib::FINISH)
23
+ end
24
+ end
25
+ end