simplecsv 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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