to-csv 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,21 @@
1
- == 1.0.2 2010-01-04
2
-
3
- * Changed use of OpenStruct in favor of Struct, which supports any attribute name. Now a block yields a Struct and the object itself
4
- * Support for Rails scopes
5
- * Improved documentation
6
-
7
- == 1.0.1 2009-12-24
8
-
9
- * Now compatible with Ruby 1.9.1
10
- * Updated documentation to reflect Ruby 1.9.1 support
11
-
12
- == 1.0.0 2009-12-23
13
-
14
- * First release
15
-
1
+ == 1.0.3 2010-08-09
2
+ * Supported (tested) Ruby versions: 1.8.7-p299, 1.9.1-p378, 1.9.2-rc1
3
+ * Support for Ruby 1.8.6 has been dropped
4
+ * New +include+ option
5
+ * +csv_options+ has an +encoding+ option set with UTF-8
6
+
7
+ == 1.0.2 2010-01-04
8
+
9
+ * Changed use of OpenStruct in favor of Struct, which supports any attribute name. Now a block yields a Struct and the object itself
10
+ * Support for Rails scopes
11
+ * Improved documentation
12
+
13
+ == 1.0.1 2009-12-24
14
+
15
+ * Now compatible with Ruby 1.9.1
16
+ * Updated documentation to reflect Ruby 1.9.1 support
17
+
18
+ == 1.0.0 2009-12-23
19
+
20
+ * First release
21
+
@@ -1,20 +1,20 @@
1
- Copyright (c) 2009 Ícaro Leopoldino da Motta
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2009 Ícaro Leopoldino da Motta
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,212 +1,237 @@
1
- = ToCSV
2
-
3
-
4
- ToCSV is a gem for converting arrays or scopes (Rails) to CSV by calling +to_csv+.
5
- These arrays can contain different data structures, as long as they are homogeneous, like the ones
6
- described below:
7
-
8
- * A simple array of anything that responds to <tt>to_s</tt>: <tt>['Date', Time.now].to_csv</tt>
9
- * An array of hashes: <tt>[ {'Name' => 'Icaro', 'Age' => 23}, {'Name' => 'Gabriel', 'Age' => 16} ].to_csv</tt>
10
- * A matrix: <tt>[['Name', 'Age'], ['Icaro', 23], ['Gabriel', 16]].to_csv</tt>
11
- * A hash like array: <tt>[ [['Name', 'Icaro'], ['Age', 23]], [['Name', 'Gabriel'], ['Age', 16]] ].to_csv</tt>
12
- * An array of ActiveRecord objects: <tt>@users.to_csv(:except => [:password, :phone], :timestamps => true)</tt>
13
- * Scopes in Rails
14
-
15
-
16
- === Requirements
17
-
18
- ToCSV has been tested with Ruby 1.8.6/1.8.7/1.9.1.
19
-
20
- If you are using Ruby 1.9 the only dependency to use the basic features is +ActiveSupport+.
21
- Otherwise you will need +fastercsv+. You will receive a warning if you don't meet the requirements.
22
-
23
- # If you don't have Rails installed...
24
- $ sudo gem install activesupport
25
-
26
- # And if your Ruby version is lower than 1.9
27
- $ sudo gem install fastercsv
28
-
29
-
30
- === Configuration
31
-
32
- If you want to use this gem with Rails, put the following requirement in your environment.rb:
33
-
34
- config.gem 'to-csv', :lib => 'to_csv', :source => 'http://gemcutter.org'
35
-
36
- After that, if you need to globally configure the gem, just create a <i>to_csv.rb</i> file in <i>initializers</i>.
37
-
38
- ToCSV.byte_order_marker = true
39
- ToCSV.timestamps = true
40
- ToCSV.locale = 'en-US'
41
- ToCSV.primary_key = false
42
- ToCSV.csv_options = { :col_sep => ',', :row_sep => "\r\n" }
43
-
44
-
45
- == Examples
46
-
47
- Let's start with the most simple example.
48
-
49
- ['Alfred Hitchcock', 'Robert Mitchum', 'Lucille Ball'].to_csv
50
- #=> "Alfred Hitchcock;Robert Mitchum;Lucille Ball\n"
51
-
52
-
53
- Or, if we have an array of arrays (i.e. a matrix) we can create tabular data.
54
- [
55
- ['Name', 'Gender'],
56
- ['Alfred', 'M'],
57
- ['Robert', 'M'],
58
- ['Lucille', 'F']
59
- ].to_csv #=> "Name;Gender\nAlfred;M\nRobert;M\nLucille;F\n"
60
-
61
-
62
- Almost always, when we generate CSV files, we want it to have appropriate
63
- headers, so a better approach might be to use an array of hashes.
64
-
65
- [
66
- { 'Name' => 'Alfred', 'Gender' => 'M' },
67
- { 'Name' => 'Robert', 'Gender' => 'M' },
68
- { 'Name' => 'Lucille', 'Gender' => 'F' }
69
- ].to_csv #=> "Gender;Name\nM;Alfred\nM;Robert\nF;Lucille\n"
70
-
71
-
72
- Look carefully to the above output. You can see that when we use hashes we can
73
- no longer be sure of the headers' order (true for Ruby versions older than 1.9).
74
- When we are working with tabular data the headers' order can be very important,
75
- thus we can use a somewhat similar data structure:
76
-
77
- [
78
- [ ['Name', 'Alfred'], ['Gender', 'M'] ],
79
- [ ['Name', 'Robert'], ['Gender', 'M'] ],
80
- [ ['Name', 'Lucille'], ['Gender', 'F'] ]
81
- ].to_csv #=> "Name;Gender\nAlfred;M\nRobert;M\nLucille;F\n"
82
-
83
- That's a lot to type... The first example was much simpler...
84
-
85
- There is the <tt>headers</tt> option. You can use it in all the examples above
86
- to enable/disable headers from the output. Default is to show (true).
87
-
88
- users = [{ 'Name' => 'Alfred', 'Gender' => 'M' }]
89
- users.to_csv(:headers => false)
90
-
91
-
92
- ==== Active Record Objects
93
-
94
- When we're building our data like the previous examples we have very few options
95
- compared to what can be passed when converting an array of AR objects. Again,
96
- the easiest way:
97
-
98
- # Anywhere in your app.
99
- # By default, all available model attributes (DB columns) are going to be used
100
- # except timestamps and the primary key of the record
101
- @users = User.all
102
- File.open('path/to/file.csv', 'w') { |io| io.puts @users.to_csv }
103
-
104
-
105
- ==== Headers
106
-
107
- You can control the order and the text of any header. You can accomplish that
108
- in various ways.
109
-
110
- By default all attribute/method names will be sorted in alphabetical order. So
111
- imagine a person model have +name+, +age+ and +email+ as attributes, and you
112
- want to get the following output:
113
-
114
- Name | E-mail | Age
115
- ... | ... | ..
116
- ... | ... | ..
117
-
118
- You can tell <i>to-csv</i> to use a specific locale. If you don't, it uses
119
- your app current locale. It will try to translate attributes to a
120
- more friendly text by using the scope <tt>[:activerecord, :attributes, <model name>]</tt>.
121
- If the translation doesn't exist the header's text is going to be humanized.
122
-
123
- The order of columns can be changed with the option +headers+. The way this
124
- option works is very similar to the <tt>plugins</tt> method in your Rails
125
- <i>environment.rb</i> file.
126
-
127
- * If you pass +nil+ (default) then headers/columns will be in alphabetical order.
128
- * If you pass an empty array or +false+, no headers will be shown.
129
- * Instead, if you pass a non empty array, headers will be sorted in the order specified. <tt>:all</tt> can be used as a placeholder for all attributes not explicitly named.
130
-
131
- So, in our example above, we can say:
132
-
133
- @users.to_csv(:headers => [:name, :email, :age])
134
-
135
- Or, using the placeholder +all+, which is not very useful here:
136
-
137
- @users.to_csv(:headers => [:name, :email, :all])
138
-
139
- If you want a completely different result you could, for instance, map all
140
- users to a hash. Example:
141
-
142
- # This makes use of a hash to completely change the CSV output.
143
- @users.map do |user|
144
- {
145
- 'Name' => user.name,
146
- 'Age' => user.age,
147
- 'Total Comments' => user.comments.count
148
- }
149
- end.to_csv
150
-
151
-
152
- ===== Passing a Block
153
-
154
- Sometimes you may want to change just one value out of six for example. The best
155
- way to go is to pass a block so that you don't have to repeat yourself writing
156
- five headers and it's obvious values and also loosing I18n header translations.
157
-
158
- # The block yields a new Struct for each object in the list. By calling
159
- # methods on this struct you can change their default values.
160
- @users.to_csv do |row, user|
161
- row.date_of_birth = user.date_of_birth.to_s(:long)
162
- end
163
-
164
-
165
- ===== A More Complete Example
166
-
167
- # users/index.html.haml
168
- = link_to 'export (CSV)', users_url(:csv)
169
-
170
- # UsersController#index
171
- class UsersController < ApplicationController
172
- def index
173
- @users = User.most_active
174
- respond_to do |format|
175
- format.html
176
- format.csv do
177
- send_data User.csv(@users), :filename => 'users_report.csv'
178
- end
179
- end
180
- end
181
- end
182
-
183
- # User model
184
- class User < ActiveRecord::Base
185
- def self.csv(users)
186
- users.csv(:headers => [:id, :all], :primary_key => true, :except => :password) do |row, user|
187
- row.id = "%04d" % user.id
188
- row.created_at = I18n.l(user.created_at, :format => :default)
189
- end
190
- end
191
- end
192
-
193
- # locales/en-US.yml
194
- activerecord:
195
- attributes:
196
- user:
197
- id: Code
198
-
199
-
200
- ==== Full Customization
201
-
202
- You can always customize the output if you wish by building arrays of hashes,
203
- arrays of arrays of bidimensional arrays etc :). Or you can obviously mix
204
- anything you want and even use FasterCSV directly.
205
-
206
- @user.to_csv { :only => [:name, :email] }, :col_sep => ','
207
-
208
- There are other options for you to customize the output. Take a look at the
209
- <tt>to_csv</tt> method documentation.
210
-
211
- Copyright (c) 2009 Ícaro Leopoldino da Motta, released under the MIT license.
212
-
1
+ = ToCSV
2
+
3
+
4
+ ToCSV is a gem for converting arrays or scopes (Rails) to CSV by calling +to_csv+.
5
+ These arrays can contain different data structures, as long as they are homogeneous, like the ones
6
+ described below:
7
+
8
+ * A simple array of anything that responds to <tt>to_s</tt>: <tt>['Date', Time.now].to_csv</tt>
9
+ * An array of hashes: <tt>[ {'Name' => 'Icaro', 'Age' => 23}, {'Name' => 'Gabriel', 'Age' => 16} ].to_csv</tt>
10
+ * A matrix: <tt>[['Name', 'Age'], ['Icaro', 23], ['Gabriel', 16]].to_csv</tt>
11
+ * A hash like array: <tt>[ [['Name', 'Icaro'], ['Age', 23]], [['Name', 'Gabriel'], ['Age', 16]] ].to_csv</tt>
12
+ * An array of ActiveRecord objects: <tt>@users.to_csv(:except => [:password, :phone], :timestamps => true)</tt>
13
+ * Scopes in Rails
14
+
15
+
16
+ === Requirements
17
+
18
+ ToCSV has been tested with Ruby 1.8.7-p299/1.9.1-p378/1.9.2-rc1.
19
+
20
+ If you are using Ruby 1.9 the only dependency to use the basic features is +ActiveSupport+.
21
+ Otherwise you will need +fastercsv+. You will receive a warning if you don't meet the requirements.
22
+
23
+ # If you don't have Rails installed...
24
+ $ sudo gem install activesupport
25
+
26
+ # And if your Ruby version is lower than 1.9
27
+ $ sudo gem install fastercsv
28
+
29
+ Full compatibility with Rails 3 is on the way...as well as a new API, with new features.
30
+
31
+
32
+ === Configuration
33
+
34
+ If you want to use this gem with Rails, put the following requirement in your environment.rb:
35
+
36
+ config.gem 'to-csv', :lib => 'to_csv', :source => 'http://rubygems.org'
37
+
38
+ After that, if you need to globally configure the gem, just create a <i>to_csv.rb</i> file in <i>initializers</i>.
39
+
40
+ ToCSV.byte_order_marker = true
41
+ ToCSV.timestamps = true
42
+ ToCSV.locale = 'en-US'
43
+ ToCSV.primary_key = false
44
+ ToCSV.csv_options[:col_sep] = ','
45
+ ToCSV.csv_options[:row_sep] = "\r\n"
46
+
47
+
48
+ == Examples
49
+
50
+ Let's start with the most simple example.
51
+
52
+ ['Alfred Hitchcock', 'Robert Mitchum', 'Lucille Ball'].to_csv
53
+ #=> "Alfred Hitchcock;Robert Mitchum;Lucille Ball\n"
54
+
55
+
56
+ Or, if we have an array of arrays (i.e. a matrix) we can create tabular data.
57
+ [
58
+ ['Name', 'Gender'],
59
+ ['Alfred', 'M'],
60
+ ['Robert', 'M'],
61
+ ['Lucille', 'F']
62
+ ].to_csv #=> "Name;Gender\nAlfred;M\nRobert;M\nLucille;F\n"
63
+
64
+
65
+ Almost always, when we generate CSV files, we want it to have appropriate
66
+ headers, so a better approach might be to use an array of hashes.
67
+
68
+ [
69
+ { 'Name' => 'Alfred', 'Gender' => 'M' },
70
+ { 'Name' => 'Robert', 'Gender' => 'M' },
71
+ { 'Name' => 'Lucille', 'Gender' => 'F' }
72
+ ].to_csv #=> "Gender;Name\nM;Alfred\nM;Robert\nF;Lucille\n"
73
+
74
+
75
+ Look carefully to the above output. You can see that when we use hashes we can
76
+ no longer be sure of the headers' order (true for Ruby versions older than 1.9).
77
+ When we are working with tabular data the headers' order can be very important,
78
+ thus we can use a somewhat similar data structure:
79
+
80
+ [
81
+ [ ['Name', 'Alfred'], ['Gender', 'M'] ],
82
+ [ ['Name', 'Robert'], ['Gender', 'M'] ],
83
+ [ ['Name', 'Lucille'], ['Gender', 'F'] ]
84
+ ].to_csv #=> "Name;Gender\nAlfred;M\nRobert;M\nLucille;F\n"
85
+
86
+ That's a lot to type... The first example was much simpler...
87
+
88
+ There is the <tt>headers</tt> option. You can use it in all the examples above
89
+ to enable/disable headers from the output. Default is to show (true).
90
+
91
+ users = [{ 'Name' => 'Alfred', 'Gender' => 'M' }]
92
+ users.to_csv(:headers => false)
93
+
94
+
95
+ ==== Active Record Objects
96
+
97
+ When we're building our data like the previous examples we have very few options
98
+ compared to what can be passed when converting an array of AR objects. Again,
99
+ the easiest way:
100
+
101
+ # Anywhere in your app.
102
+ # By default, all available model attributes (DB columns) are going to be used
103
+ # except timestamps and the primary key of the record
104
+ @users = User.all
105
+ File.open('path/to/file.csv', 'w') { |io| io.puts @users.to_csv }
106
+
107
+
108
+ ==== Headers
109
+
110
+ You can control the order and the text of any header. You can accomplish that
111
+ in various ways.
112
+
113
+ By default all attribute/method names will be sorted in alphabetical order. So
114
+ imagine a person model have +name+, +age+ and +email+ as attributes, and you
115
+ want to get the following output:
116
+
117
+ Name | E-mail | Age
118
+ ... | ... | ..
119
+ ... | ... | ..
120
+
121
+ You can tell <i>to-csv</i> to use a specific locale. If you don't, it uses
122
+ your app current locale. It will try to translate attributes to a
123
+ more friendly text by using the scope <tt>activerecord.attributes.<model name></tt>.
124
+ If the translation doesn't exist the header's text is going to be humanized.
125
+
126
+ The order of columns can be changed with the option +headers+. The way this
127
+ option works is very similar to the <tt>plugins</tt> method in your Rails
128
+ <i>environment.rb</i> file.
129
+
130
+ * If you pass +nil+ (default) then headers/columns will be in alphabetical order.
131
+ * If you pass an empty array or +false+, no headers will be shown.
132
+ * Instead, if you pass a non empty array, headers will be sorted in the order specified. <tt>:all</tt> can be used as a placeholder for all attributes not explicitly named.
133
+
134
+ So, in our example above, we can say:
135
+
136
+ @users.to_csv(:headers => [:name, :email, :age])
137
+
138
+ Or, using the placeholder +all+, which is not very useful here:
139
+
140
+ @users.to_csv(:headers => [:name, :email, :all])
141
+
142
+ If you want a completely different result you could, for instance, map all
143
+ users to a hash. Example:
144
+
145
+ # This makes use of a hash to completely change the CSV output.
146
+ @users.map do |user|
147
+ {
148
+ 'Name' => user.name,
149
+ 'Age' => user.age,
150
+ 'Total Comments' => user.comments.count
151
+ }
152
+ end.to_csv
153
+
154
+
155
+ ==== Passing a Block
156
+
157
+ Sometimes you may want to change just one value out of six for example. The best
158
+ way to go is to pass a block so that you don't have to repeat yourself writing
159
+ five headers and it's obvious values and also loosing I18n header translations.
160
+
161
+ # The block yields a new Struct for each object in the list. By calling
162
+ # methods on this struct you can change their default values.
163
+ @users.to_csv do |row, user|
164
+ row.date_of_birth = user.date_of_birth.to_s(:long)
165
+ end
166
+
167
+ ==== Include Relationships
168
+
169
+ If you have an AR object with many relationships and you want to include these to
170
+ CSV results, you can use :include option.
171
+
172
+ Examples:
173
+
174
+ # If you want to include a <tt>has_many</tt> relationship, you can do the following:
175
+ User.all.to_csv(:include => :posts)
176
+
177
+ # If you want to include a <tt>belongs_to</tt> relationship:
178
+ User.all.to_csv(:include => :organization)
179
+
180
+ # Or you can use both in the same time.
181
+ User.all.to_csv(:include => [:organization, :posts])
182
+
183
+ ==== A More Complete Example
184
+
185
+ # users/index.html.haml
186
+ = link_to 'export (CSV)', users_url(:csv)
187
+
188
+ # UsersController#index
189
+ class UsersController < ApplicationController
190
+ def index
191
+ @users = User.most_active
192
+ respond_to do |format|
193
+ format.html
194
+ format.csv do
195
+ send_data User.csv(@users), :filename => 'users_report.csv'
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ # User model
202
+ class User < ActiveRecord::Base
203
+ def self.csv(users)
204
+ users.csv(:headers => [:id, :all], :primary_key => true, :except => :password) do |row, user|
205
+ row.id = "%04d" % user.id
206
+ row.created_at = I18n.l(user.created_at, :format => :default)
207
+ end
208
+ end
209
+ end
210
+
211
+ # locales/en-US.yml
212
+ activerecord:
213
+ attributes:
214
+ user:
215
+ id: Code
216
+
217
+ ==== Full Customization
218
+
219
+ You can always customize the output if you wish by building arrays of hashes,
220
+ arrays of arrays of bidimensional arrays etc :). Or you can obviously mix
221
+ anything you want and even use FasterCSV directly.
222
+
223
+ @user.to_csv { :only => [:name, :email] }, :col_sep => ','
224
+
225
+ There are other options for you to customize the output. Take a look at the
226
+ <tt>to_csv</tt> method documentation.
227
+
228
+ ==== Credits
229
+
230
+ Special thanks to these people for their contributions and/or ideas:
231
+
232
+ * {Kyle J. Ginavan}[http://github.com/kylejginavan]
233
+ * {Mauro Torres}[http://github.com/chebyte]
234
+ * {petRUShka}[http://github.com/petRUShka]
235
+
236
+ Copyright (c) 2010 Ícaro Leopoldino da Motta, released under the MIT license.
237
+