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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +10 -1
  3. data/.rubocop_todo.yml +5 -4
  4. data/Appraisals +20 -22
  5. data/Gemfile.lock +1 -1
  6. data/README.md +75 -3
  7. data/gemfiles/{active6.0.6.gemfile → active7.1.6.gemfile} +2 -2
  8. data/gemfiles/{active7.1.3.gemfile.lock → active7.1.6.gemfile.lock} +79 -43
  9. data/gemfiles/{active7.0.8.gemfile → active7.2.3.2.gemfile} +2 -2
  10. data/gemfiles/active7.2.3.2.gemfile.lock +182 -0
  11. data/gemfiles/{active6.1.7.6.gemfile → active8.0.5.1.gemfile} +2 -2
  12. data/gemfiles/{active6.1.7.6.gemfile.lock → active8.0.5.1.gemfile.lock} +87 -47
  13. data/gemfiles/{active7.1.3.gemfile → active8.1.3.1.gemfile} +2 -2
  14. data/gemfiles/{active7.0.8.gemfile.lock → active8.1.3.1.gemfile.lock} +87 -45
  15. data/gemfiles/{rails7.0.8.gemfile → rails7.1.6.gemfile} +1 -1
  16. data/gemfiles/{rails7.1.3.gemfile.lock → rails7.1.6.gemfile.lock} +155 -126
  17. data/gemfiles/{rails7.1.3.gemfile → rails7.2.3.2.gemfile} +1 -1
  18. data/gemfiles/rails7.2.3.2.gemfile.lock +321 -0
  19. data/gemfiles/{rails6.0.6.gemfile → rails8.0.5.1.gemfile} +1 -2
  20. data/gemfiles/rails8.0.5.1.gemfile.lock +319 -0
  21. data/gemfiles/{rails6.1.7.6.gemfile → rails8.1.3.1.gemfile} +1 -2
  22. data/gemfiles/rails8.1.3.1.gemfile.lock +322 -0
  23. data/lib/comma/array.rb +1 -3
  24. data/lib/comma/collection_export.rb +9 -0
  25. data/lib/comma/data_extractor.rb +16 -20
  26. data/lib/comma/data_mapper_collection.rb +1 -3
  27. data/lib/comma/extractor.rb +33 -2
  28. data/lib/comma/generator.rb +4 -8
  29. data/lib/comma/header_extractor.rb +10 -19
  30. data/lib/comma/mongoid.rb +1 -3
  31. data/lib/comma/object.rb +37 -11
  32. data/lib/comma/options.rb +18 -0
  33. data/lib/comma/rails/renderer.rb +21 -0
  34. data/lib/comma/rails.rb +16 -0
  35. data/lib/comma/version.rb +1 -1
  36. data/lib/comma.rb +4 -43
  37. data/spec/comma/comma_spec.rb +93 -34
  38. data/spec/comma/data_extractor_spec.rb +3 -3
  39. data/spec/comma/header_extractor_spec.rb +1 -1
  40. data/spec/comma/options_spec.rb +63 -0
  41. data/spec/comma/rails/active_record_spec.rb +0 -1
  42. data/spec/controllers/users_controller_spec.rb +13 -28
  43. data/spec/support/comma_class_helper.rb +12 -0
  44. data/spec/support/csv_expectation_helper.rb +14 -0
  45. metadata +28 -18
  46. data/gemfiles/active6.0.6.gemfile.lock +0 -144
  47. data/gemfiles/rails6.0.6.gemfile.lock +0 -276
  48. data/gemfiles/rails6.1.7.6.gemfile.lock +0 -279
  49. data/gemfiles/rails7.0.8.gemfile.lock +0 -274
@@ -0,0 +1,322 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ comma (5.1.0)
5
+ activesupport (>= 4.2.0)
6
+ csv (>= 3.3)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ action_text-trix (2.1.19)
12
+ railties
13
+ actioncable (8.1.3.1)
14
+ actionpack (= 8.1.3.1)
15
+ activesupport (= 8.1.3.1)
16
+ nio4r (~> 2.0)
17
+ websocket-driver (>= 0.6.1)
18
+ zeitwerk (~> 2.6)
19
+ actionmailbox (8.1.3.1)
20
+ actionpack (= 8.1.3.1)
21
+ activejob (= 8.1.3.1)
22
+ activerecord (= 8.1.3.1)
23
+ activestorage (= 8.1.3.1)
24
+ activesupport (= 8.1.3.1)
25
+ mail (>= 2.8.0)
26
+ actionmailer (8.1.3.1)
27
+ actionpack (= 8.1.3.1)
28
+ actionview (= 8.1.3.1)
29
+ activejob (= 8.1.3.1)
30
+ activesupport (= 8.1.3.1)
31
+ mail (>= 2.8.0)
32
+ rails-dom-testing (~> 2.2)
33
+ actionpack (8.1.3.1)
34
+ actionview (= 8.1.3.1)
35
+ activesupport (= 8.1.3.1)
36
+ nokogiri (>= 1.8.5)
37
+ rack (>= 2.2.4)
38
+ rack-session (>= 1.0.1)
39
+ rack-test (>= 0.6.3)
40
+ rails-dom-testing (~> 2.2)
41
+ rails-html-sanitizer (~> 1.6)
42
+ useragent (~> 0.16)
43
+ actiontext (8.1.3.1)
44
+ action_text-trix (~> 2.1.15)
45
+ actionpack (= 8.1.3.1)
46
+ activerecord (= 8.1.3.1)
47
+ activestorage (= 8.1.3.1)
48
+ activesupport (= 8.1.3.1)
49
+ globalid (>= 0.6.0)
50
+ nokogiri (>= 1.8.5)
51
+ actionview (8.1.3.1)
52
+ activesupport (= 8.1.3.1)
53
+ builder (~> 3.1)
54
+ erubi (~> 1.11)
55
+ rails-dom-testing (~> 2.2)
56
+ rails-html-sanitizer (~> 1.6)
57
+ activejob (8.1.3.1)
58
+ activesupport (= 8.1.3.1)
59
+ globalid (>= 0.3.6)
60
+ activemodel (8.1.3.1)
61
+ activesupport (= 8.1.3.1)
62
+ activerecord (8.1.3.1)
63
+ activemodel (= 8.1.3.1)
64
+ activesupport (= 8.1.3.1)
65
+ timeout (>= 0.4.0)
66
+ activestorage (8.1.3.1)
67
+ actionpack (= 8.1.3.1)
68
+ activejob (= 8.1.3.1)
69
+ activerecord (= 8.1.3.1)
70
+ activesupport (= 8.1.3.1)
71
+ marcel (~> 1.0)
72
+ activesupport (8.1.3.1)
73
+ base64
74
+ bigdecimal
75
+ concurrent-ruby (~> 1.0, >= 1.3.1)
76
+ connection_pool (>= 2.2.5)
77
+ drb
78
+ i18n (>= 1.6, < 2)
79
+ json
80
+ logger (>= 1.4.2)
81
+ minitest (>= 5.1)
82
+ securerandom (>= 0.3)
83
+ tzinfo (~> 2.0, >= 2.0.5)
84
+ uri (>= 0.13.1)
85
+ appraisal (1.0.3)
86
+ bundler
87
+ rake
88
+ thor (>= 0.14.0)
89
+ ast (2.4.3)
90
+ base64 (0.3.0)
91
+ benchmark (0.5.0)
92
+ bigdecimal (4.1.2)
93
+ builder (3.3.0)
94
+ cgi (0.5.2)
95
+ concurrent-ruby (1.3.8)
96
+ connection_pool (3.0.2)
97
+ coveralls (0.8.23)
98
+ json (>= 1.8, < 3)
99
+ simplecov (~> 0.16.1)
100
+ term-ansicolor (~> 1.3)
101
+ thor (>= 0.19.4, < 2.0)
102
+ tins (~> 1.6)
103
+ crass (1.0.7)
104
+ csv (3.3.6)
105
+ date (3.5.1)
106
+ diff-lcs (1.6.2)
107
+ docile (1.4.1)
108
+ drb (2.2.3)
109
+ erb (6.0.7)
110
+ erubi (1.13.1)
111
+ globalid (1.4.0)
112
+ activesupport (>= 6.1)
113
+ i18n (1.15.2)
114
+ concurrent-ruby (~> 1.0)
115
+ io-console (0.9.2)
116
+ irb (1.18.0)
117
+ pp (>= 0.6.0)
118
+ prism (>= 1.3.0)
119
+ rdoc (>= 4.0.0)
120
+ reline (>= 0.4.2)
121
+ json (2.21.2)
122
+ logger (1.7.0)
123
+ loofah (2.25.2)
124
+ crass (~> 1.0.2)
125
+ nokogiri (>= 1.12.0)
126
+ mail (2.9.1)
127
+ logger
128
+ mini_mime (>= 0.1.1)
129
+ net-imap
130
+ net-pop
131
+ net-smtp
132
+ marcel (1.2.1)
133
+ mini_mime (1.1.5)
134
+ mini_portile2 (2.8.9)
135
+ minitest (5.27.0)
136
+ mize (0.6.1)
137
+ mutex_m (0.3.0)
138
+ net-imap (0.6.6)
139
+ date
140
+ net-protocol
141
+ net-pop (0.1.2)
142
+ net-protocol
143
+ net-protocol (0.3.0)
144
+ timeout
145
+ net-smtp (0.5.1)
146
+ net-protocol
147
+ nio4r (2.7.5)
148
+ nokogiri (1.19.4)
149
+ mini_portile2 (~> 2.8.2)
150
+ racc (~> 1.4)
151
+ nokogiri (1.19.4-x86_64-linux-gnu)
152
+ racc (~> 1.4)
153
+ ostruct (0.6.3)
154
+ parallel (1.28.0)
155
+ parser (3.3.12.0)
156
+ ast (~> 2.4.1)
157
+ racc
158
+ pp (0.6.4)
159
+ prettyprint
160
+ prettyprint (0.2.0)
161
+ prism (1.9.0)
162
+ racc (1.8.1)
163
+ rack (3.2.7)
164
+ rack-session (2.1.2)
165
+ base64 (>= 0.1.0)
166
+ rack (>= 3.0.0)
167
+ rack-test (2.2.0)
168
+ rack (>= 1.3)
169
+ rackup (2.3.1)
170
+ rack (>= 3)
171
+ rails (8.1.3.1)
172
+ actioncable (= 8.1.3.1)
173
+ actionmailbox (= 8.1.3.1)
174
+ actionmailer (= 8.1.3.1)
175
+ actionpack (= 8.1.3.1)
176
+ actiontext (= 8.1.3.1)
177
+ actionview (= 8.1.3.1)
178
+ activejob (= 8.1.3.1)
179
+ activemodel (= 8.1.3.1)
180
+ activerecord (= 8.1.3.1)
181
+ activestorage (= 8.1.3.1)
182
+ activesupport (= 8.1.3.1)
183
+ bundler (>= 1.15.0)
184
+ railties (= 8.1.3.1)
185
+ rails-dom-testing (2.3.0)
186
+ activesupport (>= 5.0.0)
187
+ minitest
188
+ nokogiri (>= 1.6)
189
+ rails-html-sanitizer (1.7.1)
190
+ loofah (~> 2.25, >= 2.25.2)
191
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
192
+ railties (8.1.3.1)
193
+ actionpack (= 8.1.3.1)
194
+ activesupport (= 8.1.3.1)
195
+ irb (~> 1.13)
196
+ rackup (>= 1.0.0)
197
+ rake (>= 12.2)
198
+ thor (~> 1.0, >= 1.2.2)
199
+ tsort (>= 0.2)
200
+ zeitwerk (~> 2.6)
201
+ rainbow (3.1.1)
202
+ rake (13.0.6)
203
+ rbs (4.1.3)
204
+ logger
205
+ prism (>= 1.6.0)
206
+ tsort
207
+ rdoc (8.0.0)
208
+ erb
209
+ prism (>= 1.6.0)
210
+ rbs (>= 4.0.0)
211
+ tsort
212
+ readline (0.0.4)
213
+ reline
214
+ regexp_parser (2.12.0)
215
+ reline (0.7.0)
216
+ io-console (~> 0.5)
217
+ rexml (3.4.4)
218
+ rspec (3.13.2)
219
+ rspec-core (~> 3.13.0)
220
+ rspec-expectations (~> 3.13.0)
221
+ rspec-mocks (~> 3.13.0)
222
+ rspec-activemodel-mocks (1.3.0)
223
+ activemodel (>= 3.0)
224
+ activesupport (>= 3.0)
225
+ rspec-mocks (>= 2.99, < 4.0)
226
+ rspec-core (3.13.6)
227
+ rspec-support (~> 3.13.0)
228
+ rspec-expectations (3.13.5)
229
+ diff-lcs (>= 1.2.0, < 2.0)
230
+ rspec-support (~> 3.13.0)
231
+ rspec-its (2.0.0)
232
+ rspec-core (>= 3.13.0)
233
+ rspec-expectations (>= 3.13.0)
234
+ rspec-mocks (3.13.8)
235
+ diff-lcs (>= 1.2.0, < 2.0)
236
+ rspec-support (~> 3.13.0)
237
+ rspec-rails (8.0.4)
238
+ actionpack (>= 7.2)
239
+ activesupport (>= 7.2)
240
+ railties (>= 7.2)
241
+ rspec-core (>= 3.13.0, < 5.0.0)
242
+ rspec-expectations (>= 3.13.0, < 5.0.0)
243
+ rspec-mocks (>= 3.13.0, < 5.0.0)
244
+ rspec-support (>= 3.13.0, < 5.0.0)
245
+ rspec-support (3.13.7)
246
+ rubocop (1.30.1)
247
+ parallel (~> 1.10)
248
+ parser (>= 3.1.0.0)
249
+ rainbow (>= 2.2.2, < 4.0)
250
+ regexp_parser (>= 1.8, < 3.0)
251
+ rexml (>= 3.2.5, < 4.0)
252
+ rubocop-ast (>= 1.18.0, < 2.0)
253
+ ruby-progressbar (~> 1.7)
254
+ unicode-display_width (>= 1.4.0, < 3.0)
255
+ rubocop-ast (1.50.0)
256
+ parser (>= 3.3.7.2)
257
+ prism (~> 1.7)
258
+ rubocop-performance (1.19.1)
259
+ rubocop (>= 1.7.0, < 2.0)
260
+ rubocop-ast (>= 0.4.0)
261
+ ruby-progressbar (1.13.0)
262
+ securerandom (0.4.1)
263
+ simplecov (0.16.1)
264
+ docile (~> 1.1)
265
+ json (>= 1.8, < 3)
266
+ simplecov-html (~> 0.10.0)
267
+ simplecov-html (0.10.2)
268
+ sqlite3 (2.9.6)
269
+ mini_portile2 (~> 2.8.0)
270
+ sqlite3 (2.9.6-x86_64-linux-gnu)
271
+ sync (0.5.0)
272
+ term-ansicolor (1.11.3)
273
+ tins (~> 1)
274
+ thor (1.5.0)
275
+ timeout (0.6.1)
276
+ tins (1.56.0)
277
+ bigdecimal
278
+ irb
279
+ mize (~> 0.6)
280
+ readline
281
+ sync
282
+ tsort (0.2.0)
283
+ tzinfo (2.0.6)
284
+ concurrent-ruby (~> 1.0)
285
+ unicode-display_width (2.6.0)
286
+ uri (1.1.1)
287
+ useragent (0.16.11)
288
+ websocket-driver (0.8.2)
289
+ base64
290
+ websocket-extensions (>= 0.1.0)
291
+ websocket-extensions (0.1.5)
292
+ zeitwerk (2.8.3)
293
+
294
+ PLATFORMS
295
+ ruby
296
+ x86_64-linux
297
+
298
+ DEPENDENCIES
299
+ appraisal (~> 1.0.0)
300
+ base64
301
+ benchmark
302
+ bigdecimal
303
+ cgi
304
+ comma!
305
+ coveralls
306
+ drb
307
+ logger
308
+ minitest (= 5.27.0)
309
+ mutex_m
310
+ ostruct
311
+ rails (= 8.1.3.1)
312
+ rake (~> 13.0.1)
313
+ rspec (~> 3.13)
314
+ rspec-activemodel-mocks
315
+ rspec-its
316
+ rspec-rails
317
+ rubocop (~> 1.30.0)
318
+ rubocop-performance
319
+ sqlite3
320
+
321
+ BUNDLED WITH
322
+ 2.5.5
data/lib/comma/array.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Array
4
- def to_comma(style = :default)
5
- Comma::Generator.new(self, style).run(:each)
6
- end
4
+ include Comma::CollectionExport
7
5
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Comma
4
+ module CollectionExport
5
+ def to_comma(style = :default)
6
+ Comma::Generator.new(self, style).run(:each)
7
+ end
8
+ end
9
+ end
@@ -49,28 +49,24 @@ module Comma
49
49
  end
50
50
  end
51
51
 
52
- def method_missing(sym, *args, &block)
53
- @results << ExtractValueFromInstance.new(@instance).extract(sym, &block) if
54
- args.blank?
55
-
56
- args.each do |arg|
57
- case arg
58
- when Hash
59
- arg.each do |k, _v|
60
- @results << ExtractValueFromAssociationOfInstance.new(@instance, sym).extract(k, &block)
61
- end
62
- when Symbol
63
- @results << ExtractValueFromAssociationOfInstance.new(@instance, sym).extract(arg, &block)
64
- when String
65
- @results << ExtractValueFromInstance.new(@instance).extract(sym, &block)
66
- else
67
- raise "Unknown data symbol #{arg.inspect}"
68
- end
69
- end
70
- end
71
-
72
52
  def __static_column__(_header = nil, &block)
73
53
  @results << (block ? yield(@instance) : nil)
74
54
  end
55
+
56
+ private
57
+
58
+ def extract_column(method, association: nil, **, &block)
59
+ value_extractor(association).extract(method, &block)
60
+ end
61
+
62
+ def value_extractor(association)
63
+ return ExtractValueFromInstance.new(@instance) unless association
64
+
65
+ ExtractValueFromAssociationOfInstance.new(@instance, association)
66
+ end
67
+
68
+ def column_kind
69
+ 'data'
70
+ end
75
71
  end
76
72
  end
@@ -3,9 +3,7 @@
3
3
  if defined?(DataMapper)
4
4
  module DataMapper
5
5
  class Collection
6
- def to_comma(style = :default)
7
- Comma::Generator.new(self, style).run(:each)
8
- end
6
+ include Comma::CollectionExport
9
7
  end
10
8
  end
11
9
  end
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Comma
4
+ class CircularStyleReference < StandardError; end
5
+
4
6
  class Extractor
5
7
  def initialize(instance, style, formats)
6
8
  @instance = instance
7
9
  @style = style
8
10
  @formats = formats
9
11
  @results = []
12
+ @style_stack = [style]
10
13
  end
11
14
 
12
15
  def results
@@ -19,8 +22,36 @@ module Comma
19
22
  end
20
23
 
21
24
  def __use__(style)
22
- # TODO: prevent infinite recursion
23
- instance_eval(&@formats[style])
25
+ if @style_stack.include?(style)
26
+ chain = (@style_stack + [style]).join(' -> ')
27
+ raise Comma::CircularStyleReference, "Circular __use__ reference detected: #{chain}"
28
+ end
29
+
30
+ format = @formats.fetch(style) { raise "No comma format defined for style #{style}" }
31
+
32
+ @style_stack.push(style)
33
+ begin
34
+ instance_eval(&format)
35
+ ensure
36
+ @style_stack.pop
37
+ end
38
+ end
39
+
40
+ def method_missing(sym, *args, &block)
41
+ @results << extract_column(sym, &block) if args.empty?
42
+
43
+ args.each do |arg|
44
+ case arg
45
+ when Hash
46
+ arg.each { |k, v| @results << extract_column(k, association: sym, label: v, &block) }
47
+ when Symbol
48
+ @results << extract_column(arg, association: sym, label: arg, &block)
49
+ when String
50
+ @results << extract_column(sym, label: arg, &block)
51
+ else
52
+ raise "Unknown #{column_kind} symbol #{arg.inspect}"
53
+ end
54
+ end
24
55
  end
25
56
 
26
57
  private
@@ -4,14 +4,10 @@ module Comma
4
4
  class Generator
5
5
  def initialize(instance, style)
6
6
  @instance = instance
7
- @style = style
8
- @options = {}
9
-
10
- return unless @style.is_a?(Hash)
11
-
12
- @options = @style.clone
13
- @style = @options.delete(:style) || Comma::DEFAULT_OPTIONS[:style]
14
- @filename = @options.delete(:filename)
7
+ parsed = Comma::Options.parse(style)
8
+ @style = parsed[:style]
9
+ @filename = parsed[:filename]
10
+ @options = parsed[:csv]
15
11
  end
16
12
 
17
13
  def run(iterator_method)
@@ -16,31 +16,22 @@ module Comma
16
16
  end
17
17
  self.value_humanizer = DEFAULT_VALUE_HUMANIZER
18
18
 
19
- def method_missing(sym, *args, &_block)
20
- model_class = @instance.class
21
- @results << value_humanizer.call(sym, model_class) if args.blank?
22
- args.each do |arg|
23
- case arg
24
- when Hash
25
- arg.each do |_k, v|
26
- @results << value_humanizer.call(v, get_association_class(model_class, sym))
27
- end
28
- when Symbol
29
- @results << value_humanizer.call(arg, get_association_class(model_class, sym))
30
- when String
31
- @results << value_humanizer.call(arg, model_class)
32
- else
33
- raise "Unknown header symbol #{arg.inspect}"
34
- end
35
- end
36
- end
37
-
38
19
  def __static_column__(header = '', &_block)
39
20
  @results << header
40
21
  end
41
22
 
42
23
  private
43
24
 
25
+ def extract_column(method, association: nil, label: nil, **)
26
+ model_class = @instance.class
27
+ target_class = association ? get_association_class(model_class, association) : model_class
28
+ value_humanizer.call(label || method, target_class)
29
+ end
30
+
31
+ def column_kind
32
+ 'header'
33
+ end
34
+
44
35
  def get_association_class(model_class, association)
45
36
  return unless model_class.respond_to?(:reflect_on_association)
46
37
 
data/lib/comma/mongoid.rb CHANGED
@@ -6,9 +6,7 @@ begin
6
6
 
7
7
  module Mongoid
8
8
  class Criteria
9
- def to_comma(style = :default)
10
- Comma::Generator.new(self, style).run(:each)
11
- end
9
+ include Comma::CollectionExport
12
10
  end
13
11
  end
14
12
  rescue LoadError => e
data/lib/comma/object.rb CHANGED
@@ -4,19 +4,43 @@ require 'comma/data_extractor'
4
4
  require 'comma/header_extractor'
5
5
 
6
6
  class Object
7
- class_attribute :comma_formats
8
-
9
7
  class << self
10
8
  def comma(style = :default, &block)
11
- (self.comma_formats ||= {})[style] = block
9
+ own_comma_formats[style] = block
10
+ end
11
+
12
+ def comma_formats
13
+ classes_with_own_formats.reverse_each.each_with_object({}) do |klass, formats|
14
+ formats.merge!(klass.instance_variable_get(:@own_comma_formats))
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def own_comma_formats
21
+ @own_comma_formats ||= {}
12
22
  end
13
23
 
14
- def inherited(subclass)
15
- super
16
- subclass.comma_formats = self.comma_formats ? self.comma_formats.dup : {}
24
+ # `self` here is always a Class: `comma`/`comma_formats` live on Object's
25
+ # singleton class, which only plain Class objects mirror, so a bare
26
+ # Module can never reach this method to begin with. `Class#superclass`
27
+ # in turn only ever yields another Class or nil, so `klass` stays a
28
+ # Class for the whole walk.
29
+ def classes_with_own_formats
30
+ classes = []
31
+ klass = self
32
+ while klass
33
+ classes << klass if klass.instance_variable_defined?(:@own_comma_formats)
34
+ klass = klass.superclass
35
+ end
36
+ classes
17
37
  end
18
38
  end
19
39
 
40
+ def comma_formats
41
+ self.class.comma_formats
42
+ end
43
+
20
44
  def to_comma(style = :default)
21
45
  extract_with(Comma::DataExtractor, style)
22
46
  end
@@ -28,13 +52,15 @@ class Object
28
52
  private
29
53
 
30
54
  def extract_with(extractor_class, style = :default)
31
- raise_unless_style_exists(style)
32
- extractor_class.new(self, style, self.comma_formats).results
55
+ formats = comma_formats
56
+ raise_unless_style_exists(formats, style)
57
+ extractor_class.new(self, style, formats).results
33
58
  end
34
59
 
35
- def raise_unless_style_exists(style)
36
- return if self.comma_formats && self.comma_formats[style]
60
+ def raise_unless_style_exists(formats, style)
61
+ return if formats[style]
37
62
 
38
- raise "No comma format for class #{self.class} defined for style #{style}"
63
+ receiver = is_a?(Module) ? self : self.class
64
+ raise "No comma format for class #{receiver} defined for style #{style}"
39
65
  end
40
66
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Comma
4
+ module Options
5
+ module_function
6
+
7
+ def parse(input)
8
+ return { style: input, filename: nil, csv: {} } unless input.is_a?(Hash)
9
+
10
+ csv = input.dup
11
+ style = csv.delete(:style) || Comma::DEFAULT_OPTIONS[:style]
12
+ filename = csv.delete(:filename)
13
+ csv[:write_headers] = csv[:write_headers] != 'false' if csv[:write_headers].is_a?(String)
14
+
15
+ { style: style, filename: filename, csv: csv }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(ActionController::Renderers) && ActionController::Renderers.respond_to?(:add)
4
+ ActionController::Renderers.add :csv do |obj, options|
5
+ filename = options[:filename] || 'data'
6
+ extension = options[:extension] || 'csv'
7
+ mime_type = if Rails.gem_version >= Gem::Version.new('5.0.0')
8
+ options[:mime_type] || Mime[:csv]
9
+ else
10
+ options[:mime_type] || Mime::CSV
11
+ end
12
+ with_bom = options.delete(:with_bom) || false
13
+
14
+ # Capture any CSV optional settings passed to comma or comma specific options
15
+ csv_options = options.slice(*CSV_HANDLER::DEFAULT_OPTIONS.merge(Comma::DEFAULT_OPTIONS).keys)
16
+ data = obj.to_comma(csv_options)
17
+ data = "\xEF\xBB\xBF#{data}" if with_bom
18
+ disposition = "attachment; filename=\"#{filename}.#{extension}\""
19
+ send_data data, type: mime_type, disposition: disposition
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/lazy_load_hooks'
5
+
6
+ ActiveSupport.on_load(:active_record) do
7
+ require 'comma/relation' if defined?(ActiveRecord::Relation)
8
+ end
9
+
10
+ ActiveSupport.on_load(:mongoid) do
11
+ require 'comma/mongoid'
12
+ end
13
+
14
+ ActiveSupport.on_load(:action_controller) do
15
+ require 'comma/rails/renderer'
16
+ end
data/lib/comma/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Comma
4
- VERSION = '5.0.0'
4
+ VERSION = '5.1.0'
5
5
  end