rubex 0.0.1 → 0.1
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/.gitignore +4 -0
- data/.travis.yml +14 -0
- data/CONTRIBUTING.md +101 -0
- data/HISTORY.md +3 -0
- data/README.md +112 -297
- data/REFERENCE.md +753 -0
- data/Rakefile +4 -1
- data/TUTORIAL.md +234 -0
- data/bin/rubex +1 -1
- data/docs/_config.yml +1 -0
- data/docs/index.html +1 -0
- data/examples/c_struct_interface/c_struct_interface.rb +6 -0
- data/examples/c_struct_interface/c_struct_interface.rubex +47 -0
- data/examples/linked_list/linked_list.rubex +39 -0
- data/examples/linked_list/rb_linked_list.rb +8 -0
- data/examples/rcsv wrapper/rcsv/README.md +1 -0
- data/examples/rcsv wrapper/rcsv/Rakefile +7 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/extconf.rb +3 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.c +302 -0
- data/examples/rcsv wrapper/rcsv/ext/rcsv/rcsv.rubex +124 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv.rb +8 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv.so +0 -0
- data/examples/rcsv wrapper/rcsv/lib/rcsv/version.rb +1 -0
- data/examples/rcsv wrapper/rcsv/rcsv.gemspec +27 -0
- data/examples/rcsv wrapper/rcsv/spec/rcsv.csv +5 -0
- data/examples/rcsv wrapper/rcsv/spec/rcsv_spec.rb +17 -0
- data/examples/rcsv wrapper/rcsv/spec/spec_helper.rb +6 -0
- data/{spec/fixtures/basic_ruby_method/Makefile → examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/Makefile } +20 -20
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.o +0 -0
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/rcsv/2.3.3/rcsv.so +0 -0
- data/examples/rcsv wrapper/rcsv/tmp/x86_64-linux/stage/lib/rcsv.so +0 -0
- data/lib/rubex.rb +6 -50
- data/lib/rubex/ast.rb +1 -3
- data/lib/rubex/ast/expression.rb +1257 -8
- data/lib/rubex/ast/node.rb +226 -28
- data/lib/rubex/ast/statement.rb +1162 -35
- data/lib/rubex/ast/top_statement.rb +815 -0
- data/lib/rubex/code_writer.rb +103 -26
- data/lib/rubex/compiler.rb +72 -0
- data/lib/rubex/compiler_config.rb +19 -0
- data/lib/rubex/constants.rb +145 -8
- data/lib/rubex/data_type.rb +667 -4
- data/lib/rubex/error.rb +15 -0
- data/lib/rubex/helpers.rb +154 -0
- data/lib/rubex/lexer.rex +186 -22
- data/lib/rubex/lexer.rex.rb +261 -35
- data/lib/rubex/parser.racc +876 -28
- data/lib/rubex/parser.racc.rb +2845 -90
- data/lib/rubex/rake_task.rb +34 -0
- data/lib/rubex/symbol_table/entry.rb +17 -3
- data/lib/rubex/symbol_table/scope.rb +298 -25
- data/lib/rubex/version.rb +1 -1
- data/rubex.gemspec +11 -3
- data/spec/basic_ruby_method_spec.rb +15 -21
- data/spec/binding_ptr_args_spec.rb +33 -0
- data/spec/bitwise_operators_spec.rb +40 -0
- data/spec/blocks_spec.rb +35 -0
- data/spec/c_bindings_spec.rb +36 -0
- data/spec/c_constants_spec.rb +33 -0
- data/spec/c_function_ptrs_spec.rb +38 -0
- data/spec/c_functions_spec.rb +35 -0
- data/spec/c_struct_interface_spec.rb +38 -0
- data/spec/call_by_reference_spec.rb +33 -0
- data/spec/class_methods_spec.rb +33 -0
- data/spec/class_spec.rb +40 -0
- data/spec/comments_spec.rb +33 -0
- data/spec/default_args_spec.rb +37 -0
- data/spec/error_handling_spec.rb +42 -0
- data/spec/examples_spec.rb +52 -0
- data/spec/expressions_spec.rb +33 -0
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.rubex +2 -0
- data/spec/fixtures/binding_ptr_args/binding_ptr_args.rubex +30 -0
- data/spec/fixtures/bitwise_operators/bitwise_operators.rubex +40 -0
- data/spec/fixtures/blocks/blocks.rubex +11 -0
- data/spec/fixtures/c_bindings/c_bindings.rubex +58 -0
- data/spec/fixtures/c_constants/c_constants.rubex +7 -0
- data/spec/fixtures/c_function_ptrs/c_function_ptrs.rubex +52 -0
- data/spec/fixtures/c_functions/c_functions.rubex +25 -0
- data/spec/fixtures/c_struct_interface/c_struct_interface.rubex +34 -0
- data/spec/fixtures/call_by_reference/call_by_reference.rubex +30 -0
- data/spec/fixtures/class/class.rubex +20 -0
- data/spec/fixtures/class_methods/class_methods.rubex +12 -0
- data/spec/fixtures/comments/comments.rubex +9 -0
- data/spec/fixtures/default_args/default_args.rubex +11 -0
- data/spec/fixtures/error_handling/error_handling.rubex +54 -0
- data/spec/fixtures/examples/array_to_hash.rubex +14 -0
- data/spec/fixtures/examples/rcsv.csv +5 -0
- data/spec/fixtures/examples/rcsv.rubex +329 -0
- data/spec/fixtures/expressions/expressions.rubex +10 -0
- data/spec/fixtures/if_else/if_else.rubex +77 -0
- data/spec/fixtures/implicit_lib_include/implicit_lib_include.rubex +15 -0
- data/spec/fixtures/init_ruby_objects_with_literal_syntax/init_ruby_objects_with_literal_syntax.rubex +17 -0
- data/spec/fixtures/loops/loops.rubex +33 -0
- data/spec/fixtures/recursion/recursion.rubex +9 -0
- data/spec/fixtures/ruby_constant_method_calls/ruby_constant_method_calls.rubex +17 -0
- data/spec/fixtures/ruby_operators/ruby_operators.rubex +29 -0
- data/spec/fixtures/ruby_raise/ruby_raise.rubex +13 -0
- data/spec/fixtures/ruby_strings/ruby_strings.rubex +19 -0
- data/spec/fixtures/ruby_strings/string_blank_bm.rb +37 -0
- data/spec/fixtures/ruby_symbols/ruby_symbols.rubex +12 -0
- data/spec/fixtures/ruby_types/ruby_types.rubex +15 -0
- data/spec/fixtures/statement_expression/statement_expression.rubex +23 -0
- data/spec/fixtures/static_array/static_array.rubex +20 -0
- data/spec/fixtures/string_literals/string_literals.rubex +15 -0
- data/spec/fixtures/struct/struct.rubex +82 -0
- data/spec/fixtures/typecasting/typecasting.rubex +23 -0
- data/spec/fixtures/var_declarations/var_declarations.rubex +39 -0
- data/spec/if_else_spec.rb +39 -0
- data/spec/implicit_lib_include_spec.rb +33 -0
- data/spec/init_ruby_objects_with_literal_syntax_spec.rb +39 -0
- data/spec/loops_spec.rb +34 -0
- data/spec/recursion_spec.rb +35 -0
- data/spec/ruby_constant_method_calls_spec.rb +35 -0
- data/spec/ruby_operators_spec.rb +40 -0
- data/spec/ruby_raise_spec.rb +35 -0
- data/spec/ruby_strings_spec.rb +33 -0
- data/spec/ruby_symbols_spec.rb +37 -0
- data/spec/ruby_types_spec.rb +35 -0
- data/spec/spec_helper.rb +54 -1
- data/spec/statement_expression_spec.rb +34 -0
- data/spec/static_array_spec.rb +33 -0
- data/spec/string_literals_spec.rb +34 -0
- data/spec/struct_spec.rb +36 -0
- data/spec/typecasting_spec.rb +38 -0
- data/spec/var_declarions_spec.rb +35 -0
- metadata +255 -29
- data/lib/rubex/ast/argument_list.rb +0 -20
- data/lib/rubex/ast/c_base_type.rb +0 -11
- data/lib/rubex/ast/ruby_method_def.rb +0 -84
- data/spec/fixtures/basic_ruby_method/basic.rb +0 -3
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.c +0 -16
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.o +0 -0
- data/spec/fixtures/basic_ruby_method/basic_ruby_method.so +0 -0
- data/spec/fixtures/basic_ruby_method/extconf.rb +0 -3
@@ -0,0 +1,30 @@
|
|
1
|
+
struct attribs
|
2
|
+
int a, b
|
3
|
+
float c
|
4
|
+
end
|
5
|
+
|
6
|
+
class CallByReference
|
7
|
+
def ref_call
|
8
|
+
attribs a
|
9
|
+
int b_flat = 1
|
10
|
+
int *i
|
11
|
+
a.a = 1
|
12
|
+
a.b = 1
|
13
|
+
|
14
|
+
i = &b_flat
|
15
|
+
c_function(&a, b_flat, i)
|
16
|
+
add(&a)
|
17
|
+
|
18
|
+
b_flat = a.c + i[0]
|
19
|
+
|
20
|
+
return b_flat
|
21
|
+
end
|
22
|
+
|
23
|
+
cfunc void c_function(attribs *a, int b, int *i)
|
24
|
+
a[0].a = b + i[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
cfunc void add(attribs *a)
|
28
|
+
a[0].c = a[0].a + a[0].b
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Kustom
|
2
|
+
def bye
|
3
|
+
prelude
|
4
|
+
return "Bye world!"
|
5
|
+
end
|
6
|
+
|
7
|
+
def prelude
|
8
|
+
return "This is a prelude."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Kustom2 < Kustom
|
13
|
+
def hello
|
14
|
+
a = prelude
|
15
|
+
return a.concat("Hello world!")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class RandomRubyError < StandardError
|
20
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Handler
|
2
|
+
def error_test(num)
|
3
|
+
int i = num
|
4
|
+
int j = 0
|
5
|
+
|
6
|
+
begin
|
7
|
+
raise(ArgumentError, "Horrible error.") if i == 1
|
8
|
+
raise(LoadError, "Bad error.") if i == 2
|
9
|
+
raise(SyntaxError, "Disgusting error.") if i == 3
|
10
|
+
rescue ArgumentError
|
11
|
+
j = 1
|
12
|
+
rescue LoadError
|
13
|
+
j = 2
|
14
|
+
rescue SyntaxError
|
15
|
+
j = 3
|
16
|
+
else
|
17
|
+
j = 4
|
18
|
+
ensure
|
19
|
+
j += 5
|
20
|
+
end
|
21
|
+
|
22
|
+
return j
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_uncaught_error
|
26
|
+
begin
|
27
|
+
raise ArgumentError
|
28
|
+
rescue SyntaxError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_without_rescue
|
33
|
+
int i = 1
|
34
|
+
begin
|
35
|
+
raise ArgumentError
|
36
|
+
ensure
|
37
|
+
return i
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_decl_inside_begin
|
42
|
+
int i
|
43
|
+
string = "hello world"
|
44
|
+
|
45
|
+
begin
|
46
|
+
char* s = string
|
47
|
+
raise(ArgumentError) if s[0] == 'h'
|
48
|
+
rescue ArgumentError
|
49
|
+
i = 44
|
50
|
+
end
|
51
|
+
|
52
|
+
return i
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
lib "rubex/ruby"; end
|
2
|
+
lib "rubex/ruby/encoding"; end
|
3
|
+
lib "rubex/stdlib"; end
|
4
|
+
|
5
|
+
lib "csv.h", link: "csv"
|
6
|
+
struct csv_parser
|
7
|
+
end
|
8
|
+
|
9
|
+
struct FILE
|
10
|
+
end
|
11
|
+
|
12
|
+
int CSV_STRICT_FINI
|
13
|
+
int CSV_APPEND_NULL
|
14
|
+
int CSV_EPARSE
|
15
|
+
int CSV_ENOMEM
|
16
|
+
int CSV_ETOOBIG
|
17
|
+
int CSV_EINVALID
|
18
|
+
int CSV_STRICT
|
19
|
+
int CSV_EMPTY_IS_NULL
|
20
|
+
|
21
|
+
int csv_init(csv_parser, unsigned char)
|
22
|
+
int csv_fini(csv_parser, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *)
|
23
|
+
void csv_free(csv_parser *)
|
24
|
+
int csv_error(csv_parser *)
|
25
|
+
char * csv_strerror(int)
|
26
|
+
size_t csv_parse(csv_parser *p, void *, size_t, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *)
|
27
|
+
size_t csv_write(void *, size_t, void *, size_t)
|
28
|
+
int csv_fwrite(FILE *, void *, size_t)
|
29
|
+
size_t csv_write2(void *, size_t, void *, size_t, unsigned char)
|
30
|
+
int csv_fwrite2(FILE *, void *, size_t, unsigned char)
|
31
|
+
int csv_get_opts(csv_parser *)
|
32
|
+
int csv_set_opts(csv_parser *, unsigned char)
|
33
|
+
void csv_set_delim(csv_parser *, unsigned char)
|
34
|
+
void csv_set_quote(csv_parser *, unsigned char)
|
35
|
+
unsigned char csv_get_delim(csv_parser *)
|
36
|
+
unsigned char csv_get_quote(csv_parser *)
|
37
|
+
void csv_set_space_func(csv_parser *, int (*f)(unsigned char))
|
38
|
+
void csv_set_term_func(csv_parser *, int (*f)(unsigned char))
|
39
|
+
void csv_set_realloc_func(csv_parser *, void *(*cb)(void *, size_t))
|
40
|
+
void csv_set_free_func(csv_parser *, void (*cb)(void *))
|
41
|
+
void csv_set_blk_size(csv_parser *, size_t)
|
42
|
+
size_t csv_get_buffer_size(csv_parser *)
|
43
|
+
end
|
44
|
+
|
45
|
+
struct rcsv_metadata
|
46
|
+
# Derived from user-specified options
|
47
|
+
bool row_as_hash # Used to return array of hashes rather than array of arrays
|
48
|
+
bool empty_field_is_nil # Do we convert empty fields to nils?
|
49
|
+
size_t offset_rows # Number of rows to skip before parsing
|
50
|
+
int encoding_index # If available, the encoding index of the original input
|
51
|
+
|
52
|
+
char * row_conversions # A pointer to string/array of row conversions char specifiers
|
53
|
+
object * only_rows # A pointer to array of row filters
|
54
|
+
object * except_rows # A pointer to array of negative row filters
|
55
|
+
object * row_defaults # A pointer to array of row defaults
|
56
|
+
object * column_names # A pointer to array of column names to be used with hashes
|
57
|
+
|
58
|
+
# Pointer options lengths
|
59
|
+
size_t num_row_conversions # Number of converter types in row_conversions array
|
60
|
+
size_t num_only_rows # Number of items in only_rows filter
|
61
|
+
size_t num_except_rows # Number of items in except_rows filter
|
62
|
+
size_t num_row_defaults # Number of default values in row_defaults array
|
63
|
+
size_t num_columns # Number of columns detected from column_names.size
|
64
|
+
|
65
|
+
# Internal state
|
66
|
+
bool skip_current_row # Used by only_rows and except_rows filters to skip parsing of the row remainder
|
67
|
+
size_t current_col # Current column's index
|
68
|
+
size_t current_row # Current row's index
|
69
|
+
|
70
|
+
object last_entry # A pointer to the last entry that's going to be appended to result
|
71
|
+
object result # A pointer to the parsed data
|
72
|
+
end
|
73
|
+
|
74
|
+
class RcsvParseError < StandardError
|
75
|
+
end
|
76
|
+
|
77
|
+
class Rcsv
|
78
|
+
cfunc object validate_filter_row(row)
|
79
|
+
if row == nil
|
80
|
+
return nil
|
81
|
+
elsif row.is_a?(Array)
|
82
|
+
size_t j
|
83
|
+
int r_size = row.size
|
84
|
+
int type
|
85
|
+
for (0 <= j < r_size) do
|
86
|
+
type = TYPE(row[i])
|
87
|
+
|
88
|
+
if type == T_NIL || type == T_TRUE || type == T_FALSE || type == T_FLOAT || type == T_FLOAT || type == T_FIXNUM || type == T_STRING
|
89
|
+
break
|
90
|
+
else
|
91
|
+
raise(RcsvParseError, "Wrong type passed.")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
return row
|
95
|
+
else
|
96
|
+
raise(RcsvParseError, "Wrong type passed.")
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
cfunc void end_of_field_callback(void* field, size_t field_size, void* data)
|
102
|
+
char* field_str = <char *>field
|
103
|
+
rcsv_metadata* meta_p = <rcsv_metadata*>data
|
104
|
+
rcsv_metadata meta = meta_p[0]
|
105
|
+
char row_conversion = 0
|
106
|
+
object parsed_field
|
107
|
+
|
108
|
+
# No need to parse anything until the end of the line if skip_current_row is set */
|
109
|
+
# return if meta.skip_current_row
|
110
|
+
|
111
|
+
# Skip the row if its position is less than specifed offset
|
112
|
+
if (meta.current_row < meta.offset_rows)
|
113
|
+
meta_p[0].skip_current_row = true
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
117
|
+
parsed_field = ENCODED_STR_NEW(field_str, field_size, meta.encoding_index)
|
118
|
+
|
119
|
+
# Filter by row values listed in meta->only_rows */
|
120
|
+
if ((meta.only_rows != NULL) && (meta.current_col < meta.num_only_rows) && (meta.only_rows[meta.current_col] != nil) && (!rb_ary_includes(meta.only_rows[meta.current_col], parsed_field)))
|
121
|
+
meta_p[0].skip_current_row = true
|
122
|
+
return
|
123
|
+
end
|
124
|
+
# Filter out by row values listed in meta->except_rows
|
125
|
+
if ((meta.except_rows != NULL) && (meta.current_col < meta.num_except_rows) && (meta.except_rows[meta.current_col] != nil) && (rb_ary_includes(meta.except_rows[meta.current_col], parsed_field)))
|
126
|
+
meta.skip_current_row = true
|
127
|
+
return
|
128
|
+
end
|
129
|
+
|
130
|
+
# Assign the value to appropriate hash key if parsing into Hash */
|
131
|
+
if meta.row_as_hash
|
132
|
+
if meta.current_col >= meta.num_columns
|
133
|
+
raise_with_location(meta.current_row, meta.current_col, field_str)
|
134
|
+
else
|
135
|
+
meta_p[0].last_entry[meta.column_names[meta.current_col]] = parsed_field
|
136
|
+
end
|
137
|
+
else # Parse into Array
|
138
|
+
meta_p[0].last_entry.push(parsed_field) # /* last_entry << field */
|
139
|
+
end
|
140
|
+
|
141
|
+
# Increment column counter */
|
142
|
+
meta_p[0].current_col += 1
|
143
|
+
return
|
144
|
+
end
|
145
|
+
|
146
|
+
cfunc void raise_with_location(size_t current_row, size_t current_col, char* string)
|
147
|
+
end
|
148
|
+
|
149
|
+
cfunc void end_of_line_callback(int last_char, void* data)
|
150
|
+
rcsv_metadata* meta_p = <rcsv_metadata *> data
|
151
|
+
rcsv_metadata meta = meta_p[0]
|
152
|
+
|
153
|
+
# If filters didn't match, current row parsing is reverted */
|
154
|
+
if meta.skip_current_row
|
155
|
+
meta.skip_current_row = false
|
156
|
+
else
|
157
|
+
if block_given? # STREAMING
|
158
|
+
yield(meta.last_entry)
|
159
|
+
else
|
160
|
+
meta_p[0].result.push(meta.last_entry)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# /* Re-initialize last_entry unless EOF reached */
|
165
|
+
if last_char != -1
|
166
|
+
if meta.row_as_hash
|
167
|
+
meta.last_entry = {}
|
168
|
+
else
|
169
|
+
meta_p[0].last_entry = []
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Resetting column counter
|
174
|
+
meta.current_col = 0
|
175
|
+
|
176
|
+
# Incrementing row counter
|
177
|
+
meta.current_row += 1
|
178
|
+
end
|
179
|
+
|
180
|
+
cfunc object ENCODED_STR_NEW(char* string, int length, int enc_index)
|
181
|
+
_string = rb_str_new(string, length)
|
182
|
+
if (enc_index != -1)
|
183
|
+
rb_enc_associate_index(_string, enc_index)
|
184
|
+
end
|
185
|
+
return _string
|
186
|
+
end
|
187
|
+
|
188
|
+
cfunc void free_all_memory(csv_parser *p_cp, rcsv_metadata *p_meta)
|
189
|
+
if p_cp
|
190
|
+
csv_free(p_cp)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
cfunc void setup_rcsv_metadata_defaults(rcsv_metadata *p_meta)
|
195
|
+
p_meta[0].row_as_hash = 0
|
196
|
+
p_meta[0].empty_field_is_nil = 0
|
197
|
+
p_meta[0].skip_current_row = 0
|
198
|
+
p_meta[0].encoding_index = -1
|
199
|
+
p_meta[0].num_columns = 0
|
200
|
+
p_meta[0].current_col = 0
|
201
|
+
p_meta[0].current_row = 0
|
202
|
+
p_meta[0].offset_rows = 0
|
203
|
+
p_meta[0].num_only_rows = 0
|
204
|
+
p_meta[0].num_except_rows = 0
|
205
|
+
p_meta[0].num_row_defaults = 0
|
206
|
+
p_meta[0].num_row_conversions = 0
|
207
|
+
p_meta[0].only_rows = NULL
|
208
|
+
p_meta[0].except_rows = NULL
|
209
|
+
p_meta[0].row_defaults = NULL
|
210
|
+
p_meta[0].row_conversions = NULL
|
211
|
+
p_meta[0].column_names = NULL
|
212
|
+
p_meta[0].result = []
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.parse(file_name, opts)
|
216
|
+
rcsv_metadata meta
|
217
|
+
object csvio, options, option
|
218
|
+
csv_parser cp
|
219
|
+
ensure_container = []
|
220
|
+
unsigned char csv_options = CSV_STRICT_FINI | CSV_APPEND_NULL
|
221
|
+
int csv_string_len
|
222
|
+
|
223
|
+
setup_rcsv_metadata_defaults(&meta)
|
224
|
+
csvio = StringIO.new(file_name)
|
225
|
+
|
226
|
+
if !opts[:nostrict]
|
227
|
+
csv_options |= CSV_STRICT
|
228
|
+
end
|
229
|
+
|
230
|
+
option = opts[:parse_empty_fields_as]
|
231
|
+
|
232
|
+
if option == nil || option == :nil_or_string
|
233
|
+
csv_options |= CSV_EMPTY_IS_NULL
|
234
|
+
elsif option.nil?
|
235
|
+
meta.empty_field_is_nil = 1
|
236
|
+
elsif option == :string
|
237
|
+
meta.empty_field_is_nil = 0
|
238
|
+
else
|
239
|
+
raise(RcsvParseError, "The only valid options for :parse_empty_fields_as are :nil, :string and :nil_or_string.")
|
240
|
+
end
|
241
|
+
|
242
|
+
if csv_init(&cp, csv_options) == -1
|
243
|
+
raise(RcsvParseError, "Failed to initialize libcsv.")
|
244
|
+
end
|
245
|
+
|
246
|
+
buffer_size = opts[:buffer_size]
|
247
|
+
meta.row_as_hash = 1 if opts[:row_as_hash]
|
248
|
+
|
249
|
+
csv_set_delim(&cp, col_sep) if opts[:col_sep]
|
250
|
+
csv_set_quote(&cp, quote_char) if opts[:quote_char]
|
251
|
+
|
252
|
+
meta.offset_rows = opts[:offset_rows] if opts[:offset_rows]
|
253
|
+
|
254
|
+
# Specify character encoding
|
255
|
+
option = opts[:output_encoding]
|
256
|
+
meta.encoding_index = rb_enc_find_index(<char*>option) if option != nil
|
257
|
+
|
258
|
+
# :only_rows is a list of values where row is only parsed
|
259
|
+
# if its fields match those in the passed array.
|
260
|
+
option = opts[:only_rows]
|
261
|
+
if option
|
262
|
+
meta.num_only_rows = option.size
|
263
|
+
meta.only_rows = <object*>xmalloc(meta.num_only_rows * sizeof(object))
|
264
|
+
|
265
|
+
int i = 0
|
266
|
+
|
267
|
+
for 0 <= i < meta.num_only_rows do
|
268
|
+
only_row = option[i]
|
269
|
+
meta.only_rows[i] = validate_filter_row(only_row)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
# TODO: row_defaults, row_conversions, column name declaration when parsing
|
273
|
+
# fields as Hashes,
|
274
|
+
|
275
|
+
# :row_conversions specifies Ruby types that CSV field values should be
|
276
|
+
# converted into. Each char of row_conversions string represents Ruby
|
277
|
+
# type for CSV field with matching position.
|
278
|
+
row_conversions = opts[:row_conversions]
|
279
|
+
if row_conversions
|
280
|
+
meta.num_row_conversions = row_conversions.size
|
281
|
+
meta.row_conversions = row_conversions
|
282
|
+
end
|
283
|
+
|
284
|
+
if meta.row_as_hash
|
285
|
+
column_names = opts[:column_names]
|
286
|
+
|
287
|
+
if column_names.nil?
|
288
|
+
# raise RcsvParseError, ":row_as_hash requires :column_names to be set."
|
289
|
+
else
|
290
|
+
meta.last_entry = {}
|
291
|
+
meta.num_columns = column_names.size
|
292
|
+
meta.column_names = column_names
|
293
|
+
end
|
294
|
+
else
|
295
|
+
meta.last_entry = []
|
296
|
+
end
|
297
|
+
|
298
|
+
while true do
|
299
|
+
csvstr = csvio.read
|
300
|
+
# print csvstr
|
301
|
+
if csvstr.nil? || csvstr.size == 0
|
302
|
+
break
|
303
|
+
end
|
304
|
+
|
305
|
+
char* csv_string = csvstr
|
306
|
+
csv_string_len = csvstr.size
|
307
|
+
|
308
|
+
if csv_string_len != csv_parse(&cp, csv_string, csv_string_len, &end_of_field_callback, &end_of_line_callback, &meta)
|
309
|
+
int error = csv_error(&cp)
|
310
|
+
|
311
|
+
if error == CSV_EPARSE
|
312
|
+
raise(RcsvParseError, "Error when parsing malformed data.")
|
313
|
+
elsif error == CSV_ENOMEM
|
314
|
+
raise(RcsvParseError, "No memory.")
|
315
|
+
elsif error == CSV_ETOOBIG
|
316
|
+
raise(RcsvParseError, "Field data data is too large.")
|
317
|
+
elsif error == CSV_EINVALID
|
318
|
+
raise(RcsvParseError, "#{csv_strerror(error)}")
|
319
|
+
else
|
320
|
+
raise(RcsvParseError, "Something went wrong.")
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
csv_fini(&cp, &end_of_field_callback, &end_of_line_callback, &meta)
|
326
|
+
free_all_memory(&cp, &meta)
|
327
|
+
return meta.result
|
328
|
+
end
|
329
|
+
end
|