comma 5.0.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +10 -1
- data/.rubocop_todo.yml +5 -4
- data/Appraisals +20 -22
- data/Gemfile.lock +1 -1
- data/README.md +75 -3
- data/gemfiles/{active6.0.6.gemfile → active7.1.6.gemfile} +2 -2
- data/gemfiles/{active7.1.3.gemfile.lock → active7.1.6.gemfile.lock} +79 -43
- data/gemfiles/{active7.0.8.gemfile → active7.2.3.2.gemfile} +2 -2
- data/gemfiles/active7.2.3.2.gemfile.lock +182 -0
- data/gemfiles/{active6.1.7.6.gemfile → active8.0.5.1.gemfile} +2 -2
- data/gemfiles/{active6.1.7.6.gemfile.lock → active8.0.5.1.gemfile.lock} +87 -47
- data/gemfiles/{active7.1.3.gemfile → active8.1.3.1.gemfile} +2 -2
- data/gemfiles/{active7.0.8.gemfile.lock → active8.1.3.1.gemfile.lock} +87 -45
- data/gemfiles/{rails7.0.8.gemfile → rails7.1.6.gemfile} +1 -1
- data/gemfiles/{rails7.1.3.gemfile.lock → rails7.1.6.gemfile.lock} +155 -126
- data/gemfiles/{rails7.1.3.gemfile → rails7.2.3.2.gemfile} +1 -1
- data/gemfiles/rails7.2.3.2.gemfile.lock +321 -0
- data/gemfiles/{rails6.0.6.gemfile → rails8.0.5.1.gemfile} +1 -2
- data/gemfiles/rails8.0.5.1.gemfile.lock +319 -0
- data/gemfiles/{rails6.1.7.6.gemfile → rails8.1.3.1.gemfile} +1 -2
- data/gemfiles/rails8.1.3.1.gemfile.lock +322 -0
- data/lib/comma/array.rb +1 -3
- data/lib/comma/collection_export.rb +9 -0
- data/lib/comma/data_extractor.rb +16 -20
- data/lib/comma/data_mapper_collection.rb +1 -3
- data/lib/comma/extractor.rb +33 -2
- data/lib/comma/generator.rb +4 -8
- data/lib/comma/header_extractor.rb +10 -19
- data/lib/comma/mongoid.rb +1 -3
- data/lib/comma/object.rb +37 -11
- data/lib/comma/options.rb +18 -0
- data/lib/comma/rails/renderer.rb +21 -0
- data/lib/comma/rails.rb +16 -0
- data/lib/comma/version.rb +1 -1
- data/lib/comma.rb +4 -43
- data/spec/comma/comma_spec.rb +93 -34
- data/spec/comma/data_extractor_spec.rb +3 -3
- data/spec/comma/header_extractor_spec.rb +1 -1
- data/spec/comma/options_spec.rb +63 -0
- data/spec/comma/rails/active_record_spec.rb +0 -1
- data/spec/controllers/users_controller_spec.rb +13 -28
- data/spec/support/comma_class_helper.rb +12 -0
- data/spec/support/csv_expectation_helper.rb +14 -0
- metadata +28 -18
- data/gemfiles/active6.0.6.gemfile.lock +0 -144
- data/gemfiles/rails6.0.6.gemfile.lock +0 -276
- data/gemfiles/rails6.1.7.6.gemfile.lock +0 -279
- data/gemfiles/rails7.0.8.gemfile.lock +0 -274
data/lib/comma.rb
CHANGED
|
@@ -11,50 +11,11 @@ module Comma
|
|
|
11
11
|
}.freeze
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
require '
|
|
15
|
-
require 'active_support/lazy_load_hooks'
|
|
16
|
-
ActiveSupport.on_load(:active_record) do
|
|
17
|
-
require 'comma/relation' if defined?(ActiveRecord::Relation)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
ActiveSupport.on_load(:mongoid) do
|
|
21
|
-
require 'comma/mongoid'
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
require 'comma/data_mapper_collection' if defined? DataMapper
|
|
25
|
-
|
|
14
|
+
require 'comma/options'
|
|
26
15
|
require 'comma/generator'
|
|
16
|
+
require 'comma/collection_export'
|
|
17
|
+
require 'comma/data_mapper_collection' if defined? DataMapper
|
|
27
18
|
require 'comma/array'
|
|
28
19
|
require 'comma/object'
|
|
29
20
|
|
|
30
|
-
|
|
31
|
-
ActiveSupport.on_load(:action_controller) do
|
|
32
|
-
if defined?(ActionController::Renderers) && ActionController::Renderers.respond_to?(:add)
|
|
33
|
-
ActionController::Renderers.add :csv do |obj, options|
|
|
34
|
-
filename = options[:filename] || 'data'
|
|
35
|
-
extension = options[:extension] || 'csv'
|
|
36
|
-
mime_type = if Rails.version >= '5.0.0'
|
|
37
|
-
options[:mime_type] || Mime[:csv]
|
|
38
|
-
else
|
|
39
|
-
options[:mime_type] || Mime::CSV
|
|
40
|
-
end
|
|
41
|
-
with_bom = options.delete(:with_bom) || false
|
|
42
|
-
|
|
43
|
-
# Capture any CSV optional settings passed to comma or comma specific options
|
|
44
|
-
csv_options = options.slice(*CSV_HANDLER::DEFAULT_OPTIONS.merge(Comma::DEFAULT_OPTIONS).keys)
|
|
45
|
-
csv_options = csv_options.each_with_object({}) do |(k, v), h|
|
|
46
|
-
# XXX: Convert string to boolean
|
|
47
|
-
h[k] = case k
|
|
48
|
-
when :write_headers
|
|
49
|
-
(v != 'false') if v.is_a?(String)
|
|
50
|
-
else
|
|
51
|
-
v
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
data = obj.to_comma(csv_options)
|
|
55
|
-
data = "\xEF\xBB\xBF#{data}" if with_bom
|
|
56
|
-
disposition = "attachment; filename=\"#{filename}.#{extension}\""
|
|
57
|
-
send_data data, type: mime_type, disposition: disposition
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
21
|
+
require 'comma/rails'
|
data/spec/comma/comma_spec.rb
CHANGED
|
@@ -40,8 +40,9 @@ describe Comma, 'generating CSV' do # rubocop:disable Metrics/BlockLength
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
it 'should extend Array to add a #to_comma method which will return CSV content for objects within the array' do
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
expect_csv(@books.to_comma,
|
|
44
|
+
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
|
|
45
|
+
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']])
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
it 'should return an empty string when generating CSV from an empty array' do
|
|
@@ -49,7 +50,9 @@ describe Comma, 'generating CSV' do # rubocop:disable Metrics/BlockLength
|
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
it 'should change the style when specified' do
|
|
52
|
-
|
|
53
|
+
expect_csv(@books.to_comma(:brief),
|
|
54
|
+
headers: %w[Name Description],
|
|
55
|
+
rows: [['Smalltalk-80', 'Language and Implementation']])
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
describe 'with :filename specified' do
|
|
@@ -57,31 +60,39 @@ describe Comma, 'generating CSV' do # rubocop:disable Metrics/BlockLength
|
|
|
57
60
|
|
|
58
61
|
it 'should write to the file' do
|
|
59
62
|
@books.to_comma(filename: 'comma.csv')
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
expect_csv(File.read('comma.csv'),
|
|
64
|
+
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
|
|
65
|
+
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']])
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
it 'should accept FasterCSV options' do
|
|
65
69
|
@books.to_comma(filename: 'comma.csv', col_sep: ';', force_quotes: true)
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
expect_csv(File.read('comma.csv'),
|
|
71
|
+
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
|
|
72
|
+
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']],
|
|
73
|
+
col_sep: ';', force_quotes: true)
|
|
68
74
|
end
|
|
69
75
|
end
|
|
70
76
|
|
|
71
77
|
describe 'with FasterCSV options' do
|
|
72
78
|
it 'should not change when options are empty' do
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
expect_csv(@books.to_comma({}),
|
|
80
|
+
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
|
|
81
|
+
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']])
|
|
75
82
|
end
|
|
76
83
|
|
|
77
84
|
it 'should accept the options in #to_comma and generate the appropriate CSV' do
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
expect_csv(@books.to_comma(col_sep: ';', force_quotes: true),
|
|
86
|
+
headers: %w[Title Description Issuer ISBN-10 ISBN-13],
|
|
87
|
+
rows: [['Smalltalk-80', 'Language and Implementation', 'ISBN', '123123123', '321321321']],
|
|
88
|
+
col_sep: ';', force_quotes: true)
|
|
80
89
|
end
|
|
81
90
|
|
|
82
91
|
it 'should change the style when specified' do
|
|
83
|
-
|
|
84
|
-
|
|
92
|
+
expect_csv(@books.to_comma(style: :brief, col_sep: ';', force_quotes: true),
|
|
93
|
+
headers: %w[Name Description],
|
|
94
|
+
rows: [['Smalltalk-80', 'Language and Implementation']],
|
|
95
|
+
col_sep: ';', force_quotes: true)
|
|
85
96
|
end
|
|
86
97
|
end
|
|
87
98
|
end
|
|
@@ -89,29 +100,29 @@ end
|
|
|
89
100
|
describe Comma, 'defining CSV descriptions' do
|
|
90
101
|
describe 'with an unnamed description' do
|
|
91
102
|
before do
|
|
92
|
-
|
|
103
|
+
@foo_class = define_comma_class do
|
|
93
104
|
comma do; end
|
|
94
105
|
end
|
|
95
106
|
end
|
|
96
107
|
|
|
97
108
|
it 'should name the current description :default if no name has been provided' do
|
|
98
|
-
expect(
|
|
99
|
-
expect(
|
|
109
|
+
expect(@foo_class.comma_formats).not_to be_empty
|
|
110
|
+
expect(@foo_class.comma_formats[:default]).not_to be_nil
|
|
100
111
|
end
|
|
101
112
|
end
|
|
102
113
|
|
|
103
114
|
describe 'with a named description' do
|
|
104
115
|
before do
|
|
105
|
-
|
|
116
|
+
@bar_class = define_comma_class do
|
|
106
117
|
comma do; end
|
|
107
118
|
comma :detailed do; end
|
|
108
119
|
end
|
|
109
120
|
end
|
|
110
121
|
|
|
111
122
|
it 'should use the provided name to index the comma format' do
|
|
112
|
-
expect(
|
|
113
|
-
expect(
|
|
114
|
-
expect(
|
|
123
|
+
expect(@bar_class.comma_formats).not_to be_empty
|
|
124
|
+
expect(@bar_class.comma_formats[:default]).not_to be_nil
|
|
125
|
+
expect(@bar_class.comma_formats[:detailed]).not_to be_nil
|
|
115
126
|
end
|
|
116
127
|
end
|
|
117
128
|
end
|
|
@@ -119,7 +130,7 @@ end
|
|
|
119
130
|
describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable Metrics/BlockLength
|
|
120
131
|
describe 'with unnamed descriptions' do
|
|
121
132
|
before do
|
|
122
|
-
|
|
133
|
+
foo_class = define_comma_class do
|
|
123
134
|
attr_accessor :content
|
|
124
135
|
comma do; content; end
|
|
125
136
|
|
|
@@ -128,7 +139,7 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
128
139
|
end
|
|
129
140
|
end
|
|
130
141
|
|
|
131
|
-
@foo =
|
|
142
|
+
@foo = foo_class.new('content')
|
|
132
143
|
end
|
|
133
144
|
|
|
134
145
|
it 'should return and array of data content, using the :default CSV description if none requested' do
|
|
@@ -146,7 +157,7 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
146
157
|
|
|
147
158
|
describe 'with named descriptions' do
|
|
148
159
|
before do
|
|
149
|
-
|
|
160
|
+
foo_class = define_comma_class do
|
|
150
161
|
attr_accessor :content
|
|
151
162
|
comma :detailed do; content; end
|
|
152
163
|
|
|
@@ -155,7 +166,7 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
155
166
|
end
|
|
156
167
|
end
|
|
157
168
|
|
|
158
|
-
@foo =
|
|
169
|
+
@foo = foo_class.new('content')
|
|
159
170
|
end
|
|
160
171
|
|
|
161
172
|
it 'should return and array of data content, using the :default CSV description if none requested' do
|
|
@@ -179,7 +190,7 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
179
190
|
|
|
180
191
|
describe 'with block' do # rubocop:disable Metrics/BlockLength
|
|
181
192
|
before do
|
|
182
|
-
|
|
193
|
+
foo_class = define_comma_class do
|
|
183
194
|
attr_accessor :content, :created_at, :updated_at
|
|
184
195
|
comma do
|
|
185
196
|
content
|
|
@@ -199,7 +210,7 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
199
210
|
|
|
200
211
|
@time = Time.now
|
|
201
212
|
@content = 'content ' * 5
|
|
202
|
-
@foo =
|
|
213
|
+
@foo = foo_class.new @content, @time, @time
|
|
203
214
|
end
|
|
204
215
|
|
|
205
216
|
it 'should return yielded values by block' do
|
|
@@ -263,9 +274,9 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
263
274
|
end
|
|
264
275
|
end
|
|
265
276
|
|
|
266
|
-
describe 'on objects using Single Table Inheritance' do
|
|
277
|
+
describe 'on objects using Single Table Inheritance' do # rubocop:disable Metrics/BlockLength
|
|
267
278
|
before do
|
|
268
|
-
|
|
279
|
+
super_class = define_comma_class do
|
|
269
280
|
attr_accessor :content
|
|
270
281
|
comma do; content end
|
|
271
282
|
|
|
@@ -274,7 +285,7 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
274
285
|
end
|
|
275
286
|
end
|
|
276
287
|
|
|
277
|
-
|
|
288
|
+
child_class_comma = define_comma_class(super_class) do
|
|
278
289
|
comma do; content end
|
|
279
290
|
|
|
280
291
|
def initialize(content)
|
|
@@ -282,11 +293,10 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
282
293
|
end
|
|
283
294
|
end
|
|
284
295
|
|
|
285
|
-
|
|
286
|
-
end
|
|
296
|
+
child_class_no_comma = define_comma_class(super_class) {}
|
|
287
297
|
|
|
288
|
-
@childComma =
|
|
289
|
-
@childNoComma =
|
|
298
|
+
@childComma = child_class_comma.new('content')
|
|
299
|
+
@childNoComma = child_class_no_comma.new('content')
|
|
290
300
|
end
|
|
291
301
|
|
|
292
302
|
it 'should return and array of data content, as defined in comma block in child class' do
|
|
@@ -296,12 +306,34 @@ describe Comma, 'to_comma data/headers object extensions' do # rubocop:disable M
|
|
|
296
306
|
it 'should return and array of data content, as defined in comma block in super class, if not present in child' do
|
|
297
307
|
expect(@childNoComma.to_comma).to eq(%w[super-content])
|
|
298
308
|
end
|
|
309
|
+
|
|
310
|
+
it 'should reflect changes to the superclass format made after the subclass was defined' do
|
|
311
|
+
reopened_super_class = define_comma_class do
|
|
312
|
+
attr_accessor :content
|
|
313
|
+
comma do; content end
|
|
314
|
+
|
|
315
|
+
def initialize(content)
|
|
316
|
+
@content = 'super-' + content
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
reopened_child_no_comma = define_comma_class(reopened_super_class) {}
|
|
321
|
+
|
|
322
|
+
reopened_super_class.class_eval do
|
|
323
|
+
comma do
|
|
324
|
+
content(&:upcase)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
child = reopened_child_no_comma.new('content')
|
|
329
|
+
expect(child.to_comma).to eq(%w[SUPER-CONTENT])
|
|
330
|
+
end
|
|
299
331
|
end
|
|
300
332
|
end
|
|
301
333
|
|
|
302
334
|
describe Comma, '__use__ keyword' do
|
|
303
335
|
before(:all) do
|
|
304
|
-
@obj =
|
|
336
|
+
@obj = define_comma_class(Struct.new(:id, :title, :description)) do
|
|
305
337
|
comma do
|
|
306
338
|
title
|
|
307
339
|
__use__ :description
|
|
@@ -322,3 +354,30 @@ describe Comma, '__use__ keyword' do
|
|
|
322
354
|
its(:size) { should eq(3) }
|
|
323
355
|
it { should eq(['Programming Ruby', 'Foo, Inc.', 'The Pickaxe book']) }
|
|
324
356
|
end
|
|
357
|
+
|
|
358
|
+
describe Comma, '__use__ keyword with a circular reference' do
|
|
359
|
+
it 'should raise Comma::CircularStyleReference instead of overflowing the stack' do
|
|
360
|
+
obj = define_comma_class(Struct.new(:id, :title)) do
|
|
361
|
+
comma :a do
|
|
362
|
+
title
|
|
363
|
+
__use__ :b
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
comma :b do
|
|
367
|
+
__use__ :a
|
|
368
|
+
end
|
|
369
|
+
end.new(1, 'Programming Ruby')
|
|
370
|
+
|
|
371
|
+
expect { obj.to_comma(:a) }.to raise_error(Comma::CircularStyleReference, /a -> b -> a/)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
it 'should raise Comma::CircularStyleReference for direct self-reference' do
|
|
375
|
+
obj = define_comma_class(Struct.new(:id)) do
|
|
376
|
+
comma :a do
|
|
377
|
+
__use__ :a
|
|
378
|
+
end
|
|
379
|
+
end.new(1)
|
|
380
|
+
|
|
381
|
+
expect { obj.to_comma(:a) }.to raise_error(Comma::CircularStyleReference, /a -> a/)
|
|
382
|
+
end
|
|
383
|
+
end
|
|
@@ -45,7 +45,7 @@ end
|
|
|
45
45
|
|
|
46
46
|
describe Comma::DataExtractor, 'id attribute' do
|
|
47
47
|
before do
|
|
48
|
-
@data =
|
|
48
|
+
@data = define_comma_class(Struct.new(:id)) do
|
|
49
49
|
comma do
|
|
50
50
|
id 'ID' do |_id| '42' end
|
|
51
51
|
end
|
|
@@ -59,7 +59,7 @@ end
|
|
|
59
59
|
|
|
60
60
|
describe Comma::DataExtractor, 'with static column method' do
|
|
61
61
|
before do
|
|
62
|
-
@data =
|
|
62
|
+
@data = define_comma_class(Struct.new(:id, :name)) do
|
|
63
63
|
comma do
|
|
64
64
|
__static_column__
|
|
65
65
|
__static_column__ 'STATIC'
|
|
@@ -76,7 +76,7 @@ end
|
|
|
76
76
|
|
|
77
77
|
describe Comma::DataExtractor, 'nil value' do
|
|
78
78
|
before do
|
|
79
|
-
@data =
|
|
79
|
+
@data = define_comma_class(Struct.new(:id, :name)) do
|
|
80
80
|
comma do
|
|
81
81
|
name
|
|
82
82
|
name 'Name'
|
|
@@ -46,7 +46,7 @@ end
|
|
|
46
46
|
|
|
47
47
|
describe Comma::HeaderExtractor, 'with static column method' do
|
|
48
48
|
before do
|
|
49
|
-
@headers =
|
|
49
|
+
@headers = define_comma_class(Struct.new(:id, :name)) do
|
|
50
50
|
comma do
|
|
51
51
|
__static_column__
|
|
52
52
|
__static_column__ 'STATIC'
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe Comma::Options do # rubocop:disable Metrics/BlockLength
|
|
6
|
+
describe '.parse' do # rubocop:disable Metrics/BlockLength
|
|
7
|
+
it 'treats a bare symbol as the style, with no filename or csv options' do
|
|
8
|
+
expect(described_class.parse(:brief)).to eq(style: :brief, filename: nil, csv: {})
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'passes a bare nil through unchanged rather than defaulting it' do
|
|
12
|
+
expect(described_class.parse(nil)).to eq(style: nil, filename: nil, csv: {})
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'passes a bare false through unchanged rather than defaulting it' do
|
|
16
|
+
expect(described_class.parse(false)).to eq(style: false, filename: nil, csv: {})
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'extracts :style from a hash, defaulting to :default when absent' do
|
|
20
|
+
result = described_class.parse(col_sep: ';')
|
|
21
|
+
expect(result[:style]).to eq(:default)
|
|
22
|
+
expect(result[:csv]).to eq(col_sep: ';')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'extracts an explicit :style from a hash' do
|
|
26
|
+
result = described_class.parse(style: :brief, col_sep: ';')
|
|
27
|
+
expect(result[:style]).to eq(:brief)
|
|
28
|
+
expect(result[:csv]).to eq(col_sep: ';')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'extracts :filename from a hash and excludes it from :csv' do
|
|
32
|
+
result = described_class.parse(filename: 'export.csv', col_sep: ';')
|
|
33
|
+
expect(result[:filename]).to eq('export.csv')
|
|
34
|
+
expect(result[:csv]).to eq(col_sep: ';')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'passes through a real boolean write_headers unchanged' do
|
|
38
|
+
result = described_class.parse(write_headers: false)
|
|
39
|
+
expect(result[:csv]).to eq(write_headers: false)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'coerces the string "false" for write_headers to boolean false' do
|
|
43
|
+
result = described_class.parse(write_headers: 'false')
|
|
44
|
+
expect(result[:csv]).to eq(write_headers: false)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'coerces any other string for write_headers to boolean true' do
|
|
48
|
+
result = described_class.parse(write_headers: 'true')
|
|
49
|
+
expect(result[:csv]).to eq(write_headers: true)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'does not mutate the input hash' do
|
|
53
|
+
input = { style: :brief, filename: 'f.csv', col_sep: ';' }
|
|
54
|
+
described_class.parse(input)
|
|
55
|
+
expect(input).to eq(style: :brief, filename: 'f.csv', col_sep: ';')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'does not raise when given a frozen hash' do
|
|
59
|
+
input = { style: :brief, col_sep: ';' }.freeze
|
|
60
|
+
expect { described_class.parse(input) }.not_to raise_error
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -191,7 +191,6 @@ if defined? ActiveRecord
|
|
|
191
191
|
expect(@dog.to_comma).to eq %w[Dog-Rex]
|
|
192
192
|
end
|
|
193
193
|
|
|
194
|
-
# FIXME: this one is failing - the comma block from Dog is executed instead of the one from the super class
|
|
195
194
|
it 'should return and array of data content, as defined in comma block in super class, if not present in child' do
|
|
196
195
|
expect(@cat.to_comma).to eq %w[Super-Kitty]
|
|
197
196
|
end
|
|
@@ -37,13 +37,9 @@ if defined?(Rails)
|
|
|
37
37
|
expect(response.media_type).to eq 'text/csv'
|
|
38
38
|
expect(response.header['Content-Disposition']).to include('filename="data.csv"')
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Wilma,Flintstone,Wilma Flintstone
|
|
44
|
-
CSV
|
|
45
|
-
|
|
46
|
-
expect(response.body).to eq expected_content
|
|
40
|
+
expect_csv(response.body,
|
|
41
|
+
headers: ['First name', 'Last name', 'Name'],
|
|
42
|
+
rows: [['Fred', 'Flintstone', 'Fred Flintstone'], ['Wilma', 'Flintstone', 'Wilma Flintstone']])
|
|
47
43
|
end
|
|
48
44
|
|
|
49
45
|
describe 'with comma options' do
|
|
@@ -53,13 +49,9 @@ if defined?(Rails)
|
|
|
53
49
|
|
|
54
50
|
get :with_custom_style, format: :csv
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Wilma,Flintstone
|
|
60
|
-
CSV
|
|
61
|
-
|
|
62
|
-
expect(response.body).to eq expected_content
|
|
52
|
+
expect_csv(response.body,
|
|
53
|
+
headers: ['First name', 'Last name'],
|
|
54
|
+
rows: [%w[Fred Flintstone], %w[Wilma Flintstone]])
|
|
63
55
|
end
|
|
64
56
|
end
|
|
65
57
|
|
|
@@ -131,13 +123,9 @@ if defined?(Rails)
|
|
|
131
123
|
expect(response.status).to eq 200
|
|
132
124
|
expect(response.media_type).to eq 'text/csv'
|
|
133
125
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
Wilma,Flintstone,Wilma Flintstone
|
|
138
|
-
CSV
|
|
139
|
-
|
|
140
|
-
expect(response.body).to eq expected_content
|
|
126
|
+
expect_csv(response.body,
|
|
127
|
+
headers: ['First name', 'Last name', 'Name'],
|
|
128
|
+
rows: [['Fred', 'Flintstone', 'Fred Flintstone'], ['Wilma', 'Flintstone', 'Wilma Flintstone']])
|
|
141
129
|
end
|
|
142
130
|
|
|
143
131
|
it 'should allow toggling off' do
|
|
@@ -161,13 +149,10 @@ if defined?(Rails)
|
|
|
161
149
|
expect(response.status).to eq 200
|
|
162
150
|
expect(response.media_type).to eq 'text/csv'
|
|
163
151
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
CSV
|
|
169
|
-
|
|
170
|
-
expect(response.body).to eq expected_content
|
|
152
|
+
expect_csv(response.body,
|
|
153
|
+
headers: ['First name', 'Last name', 'Name'],
|
|
154
|
+
rows: [['Fred', 'Flintstone', 'Fred Flintstone'], ['Wilma', 'Flintstone', 'Wilma Flintstone']],
|
|
155
|
+
force_quotes: true)
|
|
171
156
|
end
|
|
172
157
|
|
|
173
158
|
it 'should allow combinations of options' do
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Defines an anonymous class for use in a single example, avoiding
|
|
4
|
+
# constants leaking into the global namespace across the spec suite.
|
|
5
|
+
# Pass `base` to build on a superclass (e.g. a Struct).
|
|
6
|
+
#
|
|
7
|
+
# book_class = define_comma_class(Struct.new(:title)) do
|
|
8
|
+
# comma { title }
|
|
9
|
+
# end
|
|
10
|
+
def define_comma_class(base = Object, &block)
|
|
11
|
+
Class.new(base, &block)
|
|
12
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Builds the expected CSV string from headers/rows so specs don't hand-roll
|
|
4
|
+
# comma-joined strings, then asserts it against the actual output.
|
|
5
|
+
# `csv_options` are forwarded to CSV.generate (e.g. col_sep:, force_quotes:).
|
|
6
|
+
#
|
|
7
|
+
# expect_csv(books.to_comma, headers: %w[Title Author], rows: [['Smalltalk-80', 'Kay']])
|
|
8
|
+
def expect_csv(output, headers:, rows:, **csv_options)
|
|
9
|
+
expected = CSV.generate(**csv_options) do |csv|
|
|
10
|
+
csv << headers
|
|
11
|
+
rows.each { |row| csv << row }
|
|
12
|
+
end
|
|
13
|
+
expect(output).to eq(expected)
|
|
14
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: comma
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marcus Crafter
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-
|
|
12
|
+
date: 2026-09-06 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activesupport
|
|
@@ -258,25 +258,26 @@ files:
|
|
|
258
258
|
- README.md
|
|
259
259
|
- Rakefile
|
|
260
260
|
- comma.gemspec
|
|
261
|
-
- gemfiles/
|
|
262
|
-
- gemfiles/
|
|
263
|
-
- gemfiles/
|
|
264
|
-
- gemfiles/
|
|
265
|
-
- gemfiles/
|
|
266
|
-
- gemfiles/
|
|
267
|
-
- gemfiles/
|
|
268
|
-
- gemfiles/
|
|
269
|
-
- gemfiles/
|
|
270
|
-
- gemfiles/
|
|
271
|
-
- gemfiles/
|
|
272
|
-
- gemfiles/
|
|
273
|
-
- gemfiles/
|
|
274
|
-
- gemfiles/
|
|
275
|
-
- gemfiles/
|
|
276
|
-
- gemfiles/
|
|
261
|
+
- gemfiles/active7.1.6.gemfile
|
|
262
|
+
- gemfiles/active7.1.6.gemfile.lock
|
|
263
|
+
- gemfiles/active7.2.3.2.gemfile
|
|
264
|
+
- gemfiles/active7.2.3.2.gemfile.lock
|
|
265
|
+
- gemfiles/active8.0.5.1.gemfile
|
|
266
|
+
- gemfiles/active8.0.5.1.gemfile.lock
|
|
267
|
+
- gemfiles/active8.1.3.1.gemfile
|
|
268
|
+
- gemfiles/active8.1.3.1.gemfile.lock
|
|
269
|
+
- gemfiles/rails7.1.6.gemfile
|
|
270
|
+
- gemfiles/rails7.1.6.gemfile.lock
|
|
271
|
+
- gemfiles/rails7.2.3.2.gemfile
|
|
272
|
+
- gemfiles/rails7.2.3.2.gemfile.lock
|
|
273
|
+
- gemfiles/rails8.0.5.1.gemfile
|
|
274
|
+
- gemfiles/rails8.0.5.1.gemfile.lock
|
|
275
|
+
- gemfiles/rails8.1.3.1.gemfile
|
|
276
|
+
- gemfiles/rails8.1.3.1.gemfile.lock
|
|
277
277
|
- init.rb
|
|
278
278
|
- lib/comma.rb
|
|
279
279
|
- lib/comma/array.rb
|
|
280
|
+
- lib/comma/collection_export.rb
|
|
280
281
|
- lib/comma/data_extractor.rb
|
|
281
282
|
- lib/comma/data_mapper_collection.rb
|
|
282
283
|
- lib/comma/extractor.rb
|
|
@@ -284,11 +285,15 @@ files:
|
|
|
284
285
|
- lib/comma/header_extractor.rb
|
|
285
286
|
- lib/comma/mongoid.rb
|
|
286
287
|
- lib/comma/object.rb
|
|
288
|
+
- lib/comma/options.rb
|
|
289
|
+
- lib/comma/rails.rb
|
|
290
|
+
- lib/comma/rails/renderer.rb
|
|
287
291
|
- lib/comma/relation.rb
|
|
288
292
|
- lib/comma/version.rb
|
|
289
293
|
- spec/comma/comma_spec.rb
|
|
290
294
|
- spec/comma/data_extractor_spec.rb
|
|
291
295
|
- spec/comma/header_extractor_spec.rb
|
|
296
|
+
- spec/comma/options_spec.rb
|
|
292
297
|
- spec/comma/rails/active_record_spec.rb
|
|
293
298
|
- spec/comma/rails/data_mapper_collection_spec.rb
|
|
294
299
|
- spec/comma/rails/mongoid_spec.rb
|
|
@@ -302,6 +307,8 @@ files:
|
|
|
302
307
|
- spec/rails_app/rails_app.rb
|
|
303
308
|
- spec/rails_app/tmp/.gitkeep
|
|
304
309
|
- spec/spec_helper.rb
|
|
310
|
+
- spec/support/comma_class_helper.rb
|
|
311
|
+
- spec/support/csv_expectation_helper.rb
|
|
305
312
|
homepage: http://github.com/comma-csv/comma
|
|
306
313
|
licenses:
|
|
307
314
|
- MIT
|
|
@@ -329,6 +336,7 @@ test_files:
|
|
|
329
336
|
- spec/comma/comma_spec.rb
|
|
330
337
|
- spec/comma/data_extractor_spec.rb
|
|
331
338
|
- spec/comma/header_extractor_spec.rb
|
|
339
|
+
- spec/comma/options_spec.rb
|
|
332
340
|
- spec/comma/rails/active_record_spec.rb
|
|
333
341
|
- spec/comma/rails/data_mapper_collection_spec.rb
|
|
334
342
|
- spec/comma/rails/mongoid_spec.rb
|
|
@@ -342,3 +350,5 @@ test_files:
|
|
|
342
350
|
- spec/rails_app/rails_app.rb
|
|
343
351
|
- spec/rails_app/tmp/.gitkeep
|
|
344
352
|
- spec/spec_helper.rb
|
|
353
|
+
- spec/support/comma_class_helper.rb
|
|
354
|
+
- spec/support/csv_expectation_helper.rb
|