simplecsv 0.1.0 → 0.1.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.
@@ -1,3 +1,15 @@
1
+ 2007-03-18 DATE Ken <itacchi@gmail.com>
2
+
3
+ * fix bug: options parameter of SimpleCSV.new do not effect SimpleCSV#parser
4
+ * implements SimpleCSV#options and SimpleCSV#options=
5
+
6
+ 2007-03-15 DATE Ken <itacchi@gmail.com>
7
+
8
+ * change SimpleCSV from module to class
9
+ * implements SimpleCSV.new
10
+ * implements SimpleCSV#parse
11
+ * implements SimpleCSV#write
12
+
1
13
  2007-03-09 DATE Ken <itacchi@gmail.com>
2
14
 
3
15
  * libcsv 1.0.0 support
@@ -1,3 +1,8 @@
1
+ 2007-03-18
2
+
3
+ * 0.1.2
4
+ * SimpleCSV#parse
5
+
1
6
  2007-03-09
2
7
 
3
8
  * 0.1.0
data/README.txt CHANGED
@@ -1,4 +1,4 @@
1
- SimpleCSV README
1
+ SimpleCSV 0.1.2 README
2
2
 
3
3
  What is:
4
4
  SimpleCSV provides simple api to read/write csv.
data/TODO CHANGED
@@ -1,2 +1,4 @@
1
1
  * stream input
2
- * OO I/F
2
+ * refactoring (parse method)
3
+ * subclass sutomizing by template method pattern
4
+ * convenience method such as parse_file
@@ -1,28 +1,65 @@
1
1
  #include <ruby.h>
2
2
  #include "rb_simplecsv.h"
3
3
 
4
- VALUE mSimpleCSV;
4
+ VALUE cSimpleCSV;
5
5
  VALUE eCSVError;
6
6
  VALUE eCSVParseError;
7
7
  VALUE eCSVNoMemError;
8
8
  VALUE eCSVTooBigError;
9
9
  VALUE eCSVInvalid;
10
10
 
11
+ struct csv_parser_object {
12
+ struct csv_parser* _parser;
13
+ };
11
14
 
12
- static void field_callback(char* s, size_t i, void* data) {
15
+
16
+ #define Get_Parser(obj, parser_obj, parser) {\
17
+ Data_Get_Struct(obj, struct csv_parser_object, parser_obj);\
18
+ parser = parser_obj->_parser;\
19
+ }
20
+
21
+
22
+ #define Set_Options(opts, options) {\
23
+ switch (TYPE(opts)) {\
24
+ case T_NIL:\
25
+ options = 0;\
26
+ break;\
27
+ case T_FIXNUM:\
28
+ options = FIX2INT(opts);\
29
+ break;\
30
+ default:\
31
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum/nil)",\
32
+ rb_class2name(CLASS_OF(opts)));\
33
+ }\
34
+ }
35
+
36
+ static void free_parser_object(struct csv_parser_object* parser_object)
37
+ {
38
+ if (parser_object){
39
+ if (parser_object->_parser) {
40
+ csv_free(parser_object->_parser);
41
+ }
42
+ free(parser_object);
43
+ }
44
+ }
45
+
46
+
47
+ static void field_callback(char* s, size_t i, void* obj)
48
+ {
13
49
  VALUE row, str;
14
50
 
15
- row = rb_ivar_get(mSimpleCSV, rb_intern("'row'"));
51
+ row = rb_ivar_get((VALUE)obj, rb_intern("'row'"));
16
52
  str = rb_str_new(s, i);
17
53
  rb_ary_push(row, str);
18
54
  }
19
55
 
20
- static void row_callback(char c, void* data) {
56
+ static void row_callback(char c, void* obj)
57
+ {
21
58
  VALUE row;
22
59
 
23
- row = rb_ivar_get(mSimpleCSV, rb_intern("'row'"));
60
+ row = rb_ivar_get((VALUE)obj, rb_intern("'row'"));
24
61
  rb_yield(row);
25
- rb_ivar_set(mSimpleCSV, rb_intern("'row'"), rb_ary_new());
62
+ rb_ivar_set((VALUE)obj, rb_intern("'row'"), rb_ary_new());
26
63
  }
27
64
 
28
65
 
@@ -79,37 +116,26 @@ static void row_callback(char c, void* data) {
79
116
  *
80
117
  * ==== Parameters
81
118
  * [str] <code>String</code> : csv string.
82
- * [options] <code>Interger</code> : parser options. You can specify SimpleCSV::STRICT and/or SimpleCSVREPALL_NL.
119
+ * [options] <code>Interger</code> : parser options. You can specify SimpleCSV::STRICT and/or SimpleCSV::REPALL_NL.
83
120
  * [row] <code>Array</code> of <code>String</code>s : parsed data.
84
121
  *
85
122
  * ==== Exceptions
86
- * [TypeError] <i>options</i> isn't <code>Fixnum</code>/<code>nil</code>.
123
+ * [TypeError] <i>options</i> isn't <code>Fixnum</code> / <code>nil</code>.
87
124
  * [SimpleCSV::Error] failed to initialize csv parser.
88
125
  * [SimpleCSV::ParseError] failed to parse.
89
126
  * [LocalJumpError] You must call this method with block.
90
127
  */
91
- static VALUE simplecsv_parse(int argc, VALUE* argv, VALUE klass)
128
+ static VALUE simplecsv_s_parse(int argc, VALUE* argv, VALUE klass)
92
129
  {
93
130
  VALUE str, opts;
94
- struct csv_parser *parser;
131
+ struct csv_parser* parser;
95
132
  int options;
96
133
  int len;
97
134
 
98
135
  rb_scan_args(argc, argv, "11", &str, &opts);
99
136
 
100
137
  Check_Type(str, T_STRING);
101
-
102
- switch (TYPE(opts)) {
103
- case T_NIL:
104
- options = 0;
105
- break;
106
- case T_FIXNUM:
107
- options = FIX2INT(opts);
108
- break;
109
- default:
110
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum/nil)",
111
- rb_class2name(CLASS_OF(opts)));
112
- }
138
+ Set_Options(opts, options);
113
139
 
114
140
  if (csv_init(&parser, options) != 0) {
115
141
  rb_raise(eCSVError, "failed to initialize csv parser");
@@ -120,20 +146,20 @@ static VALUE simplecsv_parse(int argc, VALUE* argv, VALUE klass)
120
146
  len = RSTRING(str)->len;
121
147
  if (csv_parse(parser, StringValuePtr(str), len, field_callback, row_callback, (void*)klass) != len) {
122
148
  switch (csv_error(parser)) {
123
- case CSV_EPARSE:
124
- rb_raise(eCSVParseError, "error while parsing by malformed data");
125
- break;
126
- case CSV_ENOMEM:
127
- rb_raise(eCSVNoMemError, "no memory");
128
- break;
129
- case CSV_ETOOBIG:
130
- rb_raise(eCSVTooBigError, "too large field data");
131
- break;
132
- case CSV_EINVALID:
133
- rb_raise(eCSVInvalid, csv_strerror(csv_error(parser)));
134
- break;
135
- default:
136
- rb_raise(eCSVError, "failed to parse by unknown reason");
149
+ case CSV_EPARSE:
150
+ rb_raise(eCSVParseError, "error while parsing by malformed data");
151
+ break;
152
+ case CSV_ENOMEM:
153
+ rb_raise(eCSVNoMemError, "no memory");
154
+ break;
155
+ case CSV_ETOOBIG:
156
+ rb_raise(eCSVTooBigError, "too large field data");
157
+ break;
158
+ case CSV_EINVALID:
159
+ rb_raise(eCSVInvalid, csv_strerror(csv_error(parser)));
160
+ break;
161
+ default:
162
+ rb_raise(eCSVError, "failed to parse by unknown reason");
137
163
  }
138
164
  }
139
165
 
@@ -168,7 +194,7 @@ static VALUE simplecsv_parse(int argc, VALUE* argv, VALUE klass)
168
194
  * ==== Exceptions
169
195
  * [TypeError] <i>array</i> isn't <code>Array</code> or each content of array isn't <code>String</code>.
170
196
  */
171
- static VALUE simplecsv_write(VALUE klass, VALUE array)
197
+ static VALUE simplecsv_s_write(VALUE klass, VALUE array)
172
198
  {
173
199
  int i;
174
200
  VALUE ret, str;
@@ -204,18 +230,175 @@ static VALUE simplecsv_write(VALUE klass, VALUE array)
204
230
 
205
231
 
206
232
 
233
+ /*
234
+ * call-seq:
235
+ * new(options = nil)
236
+ *
237
+ * Create a SimpleCSV instance object.
238
+ *
239
+ * ==== Parameters
240
+ * [options] <code>Interger</code> : parser options. You can specify SimpleCSV::STRICT and/or SimpleCSV::REPALL_NL.
241
+ *
242
+ * ==== Exceptions
243
+ * [TypeError] <i>options</i> isn't <code>Fixnum</code> / <code>nil</code>.
244
+ * [SimpleCSV::Error] failed to initialize csv parser.
245
+ */
246
+ static VALUE simplecsv_s_new(int argc, VALUE* argv, VALUE klass)
247
+ {
248
+ VALUE new_obj;
249
+ VALUE opts;
250
+ struct csv_parser_object* parser_obj;
251
+ struct csv_parser* parser;
252
+ int options;
253
+
254
+ rb_scan_args(argc, argv, "01", &opts);
255
+
256
+ Set_Options(opts, options);
257
+
258
+ new_obj = Data_Make_Struct(klass, struct csv_parser_object, NULL, free_parser_object, parser_obj);
259
+
260
+ if (csv_init(&parser, options) != 0) {
261
+ rb_raise(eCSVError, "failed to initialize csv parser");
262
+ }
263
+
264
+ parser_obj->_parser = parser;
265
+
266
+ rb_obj_call_init(new_obj, argc, argv);
267
+
268
+ rb_ivar_set(new_obj, rb_intern("'row'"), rb_ary_new());
269
+
270
+ return new_obj;
271
+ }
272
+
273
+
274
+
275
+ /* :nodoc: */
276
+ static VALUE simplecsv_initialize(VALUE self)
277
+ {
278
+ return Qnil;
279
+ }
280
+
281
+
282
+
283
+ /*
284
+ * options -> options
285
+ *
286
+ * Get option values.
287
+ *
288
+ * === Returns
289
+ * [options] <code>Interger</code> : parser options. SimpleCSV::STRICT and/or SimpleCSVREPALL_NL.
290
+ */
291
+ static VALUE simplecsv_get_options(VALUE self)
292
+ {
293
+ struct csv_parser_object* parser_object;
294
+ struct csv_parser* parser;
295
+
296
+ Get_Parser(self, parser_object, parser);
297
+
298
+ return INT2FIX(parser->options);
299
+ }
300
+
301
+
302
+
303
+ /*
304
+ * call-seq:
305
+ * options = new_options
306
+ *
307
+ * Set option values.
308
+ *
309
+ * === Parameters
310
+ * [options] <code>Interger</code> : parser options. SimpleCSV::STRICT and/or SimpleCSVREPALL_NL. You can specify nil to clear options.
311
+ */
312
+ static VALUE simplecsv_set_options(VALUE self, VALUE opts)
313
+ {
314
+ struct csv_parser_object* parser_object;
315
+ struct csv_parser* parser;
316
+ int options;
317
+
318
+ Get_Parser(self, parser_object, parser);
319
+ Set_Options(opts, options);
320
+
321
+ csv_opts(parser, options);
322
+
323
+ return Qnil;
324
+ }
325
+
326
+
327
+
328
+ /*
329
+ * call-seq:
330
+ * parse(str, options = nil){|row| ...}
331
+ *
332
+ * Parse csv string.
333
+ * Same as SimpleCSV.parse.
334
+ *
335
+ * ==== Parameters
336
+ * [str] <code>String</code> : csv string.
337
+ * [options] <code>Interger</code> : parser options. You can specify SimpleCSV::STRICT and/or SimpleCSVREPALL_NL.
338
+ * [row] <code>Array</code> of <code>String</code>s : parsed data.
339
+ *
340
+ * ==== Exceptions
341
+ * [TypeError] <i>options</i> isn't <code>Fixnum</code>/<code>nil</code>.
342
+ * [SimpleCSV::Error] failed to initialize csv parser.
343
+ * [SimpleCSV::ParseError] failed to parse.
344
+ * [LocalJumpError] You must call this method with block.
345
+ */
346
+ static VALUE simplecsv_parse(VALUE self, VALUE str)
347
+ {
348
+ struct csv_parser_object* parser_object;
349
+ struct csv_parser* parser;
350
+ int len;
351
+
352
+ Check_Type(str, T_STRING);
353
+
354
+ Get_Parser(self, parser_object, parser);
355
+
356
+ len = RSTRING(str)->len;
357
+ if (csv_parse(parser, StringValuePtr(str), len, field_callback, row_callback, (void*)self) != len) {
358
+ switch (csv_error(parser)) {
359
+ case CSV_EPARSE:
360
+ rb_raise(eCSVParseError, "error while parsing by malformed data");
361
+ break;
362
+ case CSV_ENOMEM:
363
+ rb_raise(eCSVNoMemError, "no memory");
364
+ break;
365
+ case CSV_ETOOBIG:
366
+ rb_raise(eCSVTooBigError, "too large field data");
367
+ break;
368
+ case CSV_EINVALID:
369
+ rb_raise(eCSVInvalid, csv_strerror(csv_error(parser)));
370
+ break;
371
+ default:
372
+ rb_raise(eCSVError, "failed to parse by unknown reason");
373
+ }
374
+ }
375
+
376
+ csv_fini(parser, field_callback, row_callback, (void*)self);
377
+
378
+ return Qnil;
379
+ }
380
+
381
+
382
+
207
383
  void Init_simplecsv(void)
208
384
  {
209
- mSimpleCSV = rb_define_module("SimpleCSV");
210
- eCSVError = rb_define_class_under(mSimpleCSV, "Error", rb_eStandardError);
211
- eCSVParseError = rb_define_class_under(mSimpleCSV, "ParseError", rb_eStandardError);
212
- eCSVNoMemError = rb_define_class_under(mSimpleCSV, "NoMemoryError", rb_eStandardError);
213
- eCSVTooBigError = rb_define_class_under(mSimpleCSV, "TooBigError", rb_eStandardError);
214
- eCSVInvalid = rb_define_class_under(mSimpleCSV, "InvalidError", rb_eStandardError);
215
-
216
- rb_define_const(mSimpleCSV, "STRICT", INT2FIX(CSV_STRICT));
217
- rb_define_const(mSimpleCSV, "REPALL_NL", INT2FIX(CSV_REPALL_NL));
218
-
219
- rb_define_singleton_method(mSimpleCSV, "parse", simplecsv_parse, -1);
220
- rb_define_singleton_method(mSimpleCSV, "write", simplecsv_write, 1);
385
+ cSimpleCSV = rb_define_class("SimpleCSV", rb_cObject);
386
+ eCSVError = rb_define_class_under(cSimpleCSV, "Error", rb_eStandardError);
387
+ eCSVParseError = rb_define_class_under(cSimpleCSV, "ParseError", rb_eStandardError);
388
+ eCSVNoMemError = rb_define_class_under(cSimpleCSV, "NoMemoryError", rb_eStandardError);
389
+ eCSVTooBigError = rb_define_class_under(cSimpleCSV, "TooBigError", rb_eStandardError);
390
+ eCSVInvalid = rb_define_class_under(cSimpleCSV, "InvalidError", rb_eStandardError);
391
+
392
+ rb_define_const(cSimpleCSV, "STRICT", INT2FIX(CSV_STRICT));
393
+ rb_define_const(cSimpleCSV, "REPALL_NL", INT2FIX(CSV_REPALL_NL));
394
+
395
+ rb_define_singleton_method(cSimpleCSV, "parse", simplecsv_s_parse, -1);
396
+ rb_define_singleton_method(cSimpleCSV, "write", simplecsv_s_write, 1);
397
+ rb_define_singleton_method(cSimpleCSV, "new", simplecsv_s_new, -1);
398
+
399
+ rb_define_method(cSimpleCSV, "initialize", simplecsv_initialize, -1);
400
+ rb_define_method(cSimpleCSV, "options", simplecsv_get_options, 0);
401
+ rb_define_method(cSimpleCSV, "options=", simplecsv_set_options, 1);
402
+ rb_define_method(cSimpleCSV, "parse", simplecsv_parse, 1);
403
+ rb_define_method(cSimpleCSV, "write", simplecsv_s_write, 1);
221
404
  }
@@ -1,3 +1,3 @@
1
- Dir[File.join(File.dirname(__FILE__), 'simplecsv/**/*.rb')].sort.each { |lib| require lib }
2
-
3
1
  require 'simplecsv.so'
2
+
3
+ Dir[File.join(File.dirname(__FILE__), 'simplecsv/**/*.rb')].sort.each { |lib| require lib }
@@ -2,7 +2,7 @@ module SimpleCSV #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 0
5
+ TINY = 2
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -17,14 +17,20 @@ Try to type below.
17
17
  assert_equal('constant', defined? SimpleCSV::REPALL_NL)
18
18
  end
19
19
 
20
- def test_module
21
- assert_instance_of Module, SimpleCSV
22
- assert_raise(NoMethodError) do
20
+ def test_class
21
+ assert_instance_of Class, SimpleCSV
22
+ end
23
+
24
+ def test_instantiate
25
+ assert_nothing_raised(NoMethodError) do
23
26
  SimpleCSV.new
24
27
  end
28
+ assert_raise(TypeError) do
29
+ SimpleCSV.new("invalid")
30
+ end
25
31
  end
26
32
 
27
- def test_parse
33
+ def test_s_parse
28
34
  assert_raise(ArgumentError) do
29
35
  SimpleCSV.parse()
30
36
  end
@@ -146,7 +152,7 @@ _CSV_
146
152
  assert_equal 3, rows
147
153
  end
148
154
 
149
- def test_write
155
+ def test_s_write
150
156
  assert_equal '', SimpleCSV.write([])
151
157
 
152
158
  assert_equal '"1","2","3"', SimpleCSV.write(["1", "2", "3"])
@@ -168,4 +174,141 @@ _CSV_
168
174
  SimpleCSV.write([1, 2, 3])
169
175
  end
170
176
  end
177
+
178
+ def test_parse
179
+ simplecsv = SimpleCSV.new
180
+
181
+ assert_raise(ArgumentError) do
182
+ simplecsv.parse()
183
+ end
184
+
185
+ assert_raise(TypeError) do
186
+ simplecsv.parse(1)
187
+ end
188
+
189
+ assert_raise(LocalJumpError) do
190
+ simplecsv.parse('no block given')
191
+ end
192
+
193
+ assert_nothing_raised do
194
+ simplecsv.parse(''){}
195
+ end
196
+
197
+ assert_nil simplecsv.parse('')
198
+
199
+ simplecsv.parse(<<_CSV_) do |row|
200
+ test
201
+ _CSV_
202
+ assert_instance_of Array, row
203
+ assert_instance_of String, row.first
204
+ assert_equal 1, row.size
205
+ assert_equal ['test'], row
206
+ end
207
+
208
+ simplecsv.parse(<<_CSV_) do |row|
209
+ 1,2,3
210
+ _CSV_
211
+ assert_instance_of Array, row
212
+ assert_instance_of String, row.first
213
+ assert_equal 3, row.size
214
+ assert_equal ['1', '2', '3'], row
215
+ end
216
+
217
+ rows = 0
218
+ simplecsv.parse(<<_CSV_) do |row|
219
+ 1,2,3
220
+ 2,3,4
221
+ _CSV_
222
+ assert_instance_of Array, row
223
+ assert_instance_of String, row.first
224
+ assert_equal 3, row.size
225
+ rows += 1
226
+ end
227
+ assert_equal 2, rows
228
+
229
+ rows = 0
230
+ simplecsv.parse("1,2,3\r\n2,3,4\n") do |row|
231
+ rows += 1
232
+ end
233
+ assert_equal 2, rows
234
+
235
+ rows = 0
236
+ simplecsv.parse("1,2,3\r2,3,4\n") do |row|
237
+ rows += 1
238
+ end
239
+ assert_equal 2, rows
240
+
241
+ rows = 0
242
+ simplecsv.parse("1,2,3\n2,3,4\n \t\n") do |row|
243
+ rows += 1
244
+ end
245
+ assert_equal 2, rows
246
+
247
+ simplecsv.parse(" 1,2 , 3 ,\t4,5\t,\t6\t, 7\t,\t8 ") do |row|
248
+ assert_equal ['1', '2', '3', '4', '5', '6', '7', '8'], row
249
+ end
250
+
251
+ simplecsv.parse(<<_CSV_) do |row|
252
+ " 1 "
253
+ _CSV_
254
+ assert_equal [' 1 '], row
255
+ end
256
+
257
+ simplecsv.parse(<<_CSV_) do |row|
258
+ "1", "2", "3"
259
+ _CSV_
260
+ assert_equal ['1', '2', '3'], row
261
+ end
262
+
263
+ simplecsv.parse(<<_CSV_) do |row|
264
+ "1, 2, 3"
265
+ _CSV_
266
+ assert_equal ['1, 2, 3'], row
267
+ end
268
+
269
+ simplecsv.parse(<<_CSV_) do |row|
270
+ """1"
271
+ _CSV_
272
+ assert_equal ['"1'], row
273
+ end
274
+
275
+ simplecsv.parse(<<_CSV_) do |row|
276
+ "ab"c"
277
+ _CSV_
278
+ assert_equal ['ab"c'], row
279
+ end
280
+
281
+ simplecsv = SimpleCSV.new(SimpleCSV::STRICT)
282
+ assert_raise(SimpleCSV::ParseError) do
283
+ simplecsv.parse(<<_CSV_){}
284
+ "ab"c"
285
+ _CSV_
286
+ end
287
+
288
+ end
289
+
290
+ def test_write
291
+ simplecsv = SimpleCSV.new
292
+
293
+ assert_equal '', simplecsv.write([])
294
+
295
+ assert_equal '"1","2","3"', simplecsv.write(["1", "2", "3"])
296
+
297
+ assert_equal '""""', simplecsv.write(['"'])
298
+
299
+ assert_equal 256, simplecsv.write(['"'*127]).size
300
+ assert_equal '"' * 256, simplecsv.write(['"'*127])
301
+
302
+ assert_raise(ArgumentError) do
303
+ simplecsv.write()
304
+ end
305
+
306
+ assert_raise(TypeError) do
307
+ simplecsv.write(1)
308
+ end
309
+
310
+ assert_raise(TypeError) do
311
+ simplecsv.write([1, 2, 3])
312
+ end
313
+ end
171
314
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: simplecsv
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2007-03-09 00:00:00 +09:00
6
+ version: 0.1.2
7
+ date: 2007-03-18 00:00:00 +09:00
8
8
  summary: SimpleCSV privides simple csv reading/writing api.
9
9
  require_paths:
10
10
  - lib