tomlib 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/tomlib/toml.h ADDED
@@ -0,0 +1,175 @@
1
+ /*
2
+ MIT License
3
+
4
+ Copyright (c) CK Tan
5
+ https://github.com/cktan/tomlc99
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
24
+ */
25
+ #ifndef TOML_H
26
+ #define TOML_H
27
+
28
+ #ifdef _MSC_VER
29
+ #pragma warning(disable: 4996)
30
+ #endif
31
+
32
+ #include <stdint.h>
33
+ #include <stdio.h>
34
+
35
+ #ifdef __cplusplus
36
+ #define TOML_EXTERN extern "C"
37
+ #else
38
+ #define TOML_EXTERN extern
39
+ #endif
40
+
41
+ typedef struct toml_timestamp_t toml_timestamp_t;
42
+ typedef struct toml_table_t toml_table_t;
43
+ typedef struct toml_array_t toml_array_t;
44
+ typedef struct toml_datum_t toml_datum_t;
45
+
46
+ /* Parse a file. Return a table on success, or 0 otherwise.
47
+ * Caller must toml_free(the-return-value) after use.
48
+ */
49
+ TOML_EXTERN toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz);
50
+
51
+ /* Parse a string containing the full config.
52
+ * Return a table on success, or 0 otherwise.
53
+ * Caller must toml_free(the-return-value) after use.
54
+ */
55
+ TOML_EXTERN toml_table_t *toml_parse(char *conf, /* NUL terminated, please. */
56
+ char *errbuf, int errbufsz);
57
+
58
+ /* Free the table returned by toml_parse() or toml_parse_file(). Once
59
+ * this function is called, any handles accessed through this tab
60
+ * directly or indirectly are no longer valid.
61
+ */
62
+ TOML_EXTERN void toml_free(toml_table_t *tab);
63
+
64
+ /* Timestamp types. The year, month, day, hour, minute, second, z
65
+ * fields may be NULL if they are not relevant. e.g. In a DATE
66
+ * type, the hour, minute, second and z fields will be NULLs.
67
+ */
68
+ struct toml_timestamp_t {
69
+ struct { /* internal. do not use. */
70
+ int year, month, day;
71
+ int hour, minute, second, millisec;
72
+ char z[10];
73
+ } __buffer;
74
+ int *year, *month, *day;
75
+ int *hour, *minute, *second, *millisec;
76
+ char *z;
77
+ };
78
+
79
+ /*-----------------------------------------------------------------
80
+ * Enhanced access methods
81
+ */
82
+ struct toml_datum_t {
83
+ int ok;
84
+ union {
85
+ toml_timestamp_t *ts; /* ts must be freed after use */
86
+ char *s; /* string value. s must be freed after use */
87
+ int b; /* bool value */
88
+ int64_t i; /* int value */
89
+ double d; /* double value */
90
+ } u;
91
+ };
92
+
93
+ /* on arrays: */
94
+ /* ... retrieve size of array. */
95
+ TOML_EXTERN int toml_array_nelem(const toml_array_t *arr);
96
+ /* ... retrieve values using index. */
97
+ TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t *arr, int idx);
98
+ TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t *arr, int idx);
99
+ TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t *arr, int idx);
100
+ TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t *arr, int idx);
101
+ TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx);
102
+ /* ... retrieve array or table using index. */
103
+ TOML_EXTERN toml_array_t *toml_array_at(const toml_array_t *arr, int idx);
104
+ TOML_EXTERN toml_table_t *toml_table_at(const toml_array_t *arr, int idx);
105
+
106
+ /* on tables: */
107
+ /* ... retrieve the key in table at keyidx. Return 0 if out of range. */
108
+ TOML_EXTERN const char *toml_key_in(const toml_table_t *tab, int keyidx);
109
+ /* ... returns 1 if key exists in tab, 0 otherwise */
110
+ TOML_EXTERN int toml_key_exists(const toml_table_t *tab, const char *key);
111
+ /* ... retrieve values using key. */
112
+ TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t *arr,
113
+ const char *key);
114
+ TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key);
115
+ TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t *arr, const char *key);
116
+ TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t *arr,
117
+ const char *key);
118
+ TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t *arr,
119
+ const char *key);
120
+ /* .. retrieve array or table using key. */
121
+ TOML_EXTERN toml_array_t *toml_array_in(const toml_table_t *tab,
122
+ const char *key);
123
+ TOML_EXTERN toml_table_t *toml_table_in(const toml_table_t *tab,
124
+ const char *key);
125
+
126
+ /*-----------------------------------------------------------------
127
+ * lesser used
128
+ */
129
+ /* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */
130
+ TOML_EXTERN char toml_array_kind(const toml_array_t *arr);
131
+
132
+ /* For array kind 'v'alue, return the type of values
133
+ i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed
134
+ 0 if unknown
135
+ */
136
+ TOML_EXTERN char toml_array_type(const toml_array_t *arr);
137
+
138
+ /* Return the key of an array */
139
+ TOML_EXTERN const char *toml_array_key(const toml_array_t *arr);
140
+
141
+ /* Return the number of key-values in a table */
142
+ TOML_EXTERN int toml_table_nkval(const toml_table_t *tab);
143
+
144
+ /* Return the number of arrays in a table */
145
+ TOML_EXTERN int toml_table_narr(const toml_table_t *tab);
146
+
147
+ /* Return the number of sub-tables in a table */
148
+ TOML_EXTERN int toml_table_ntab(const toml_table_t *tab);
149
+
150
+ /* Return the key of a table*/
151
+ TOML_EXTERN const char *toml_table_key(const toml_table_t *tab);
152
+
153
+ /*--------------------------------------------------------------
154
+ * misc
155
+ */
156
+ TOML_EXTERN int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret);
157
+ TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
158
+ TOML_EXTERN void toml_set_memutil(void *(*xxmalloc)(size_t),
159
+ void (*xxfree)(void *));
160
+
161
+ /*--------------------------------------------------------------
162
+ * deprecated
163
+ */
164
+ /* A raw value, must be processed by toml_rto* before using. */
165
+ typedef const char *toml_raw_t;
166
+ TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key);
167
+ TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t *arr, int idx);
168
+ TOML_EXTERN int toml_rtos(toml_raw_t s, char **ret);
169
+ TOML_EXTERN int toml_rtob(toml_raw_t s, int *ret);
170
+ TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t *ret);
171
+ TOML_EXTERN int toml_rtod(toml_raw_t s, double *ret);
172
+ TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double *ret, char *buf, int buflen);
173
+ TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t *ret);
174
+
175
+ #endif /* TOML_H */
@@ -0,0 +1,359 @@
1
+ #include <stdbool.h>
2
+ #include <stdio.h>
3
+ #include <ruby.h>
4
+
5
+ #include "toml.h"
6
+
7
+ static ID id_new;
8
+
9
+ static VALUE mTomlib;
10
+ static VALUE cDumper;
11
+ static VALUE cParserError;
12
+
13
+ static VALUE sym_simple;
14
+ static VALUE sym_quoted;
15
+ static VALUE sym_escape;
16
+
17
+ static VALUE cDate;
18
+
19
+ static VALUE toml_table_key_to_rb_value(const toml_table_t *table, const char *key);
20
+ static VALUE toml_array_index_to_rb_value(const toml_array_t *array, int index);
21
+
22
+ /**
23
+ * Convert TOML table (aka hash) to Ruby hash
24
+ */
25
+ static VALUE toml_table_to_rb_hash(const toml_table_t *table) {
26
+ VALUE rb_hash = rb_hash_new();
27
+
28
+ for (int i = 0; ; i++) {
29
+ const char *key = toml_key_in(table, i);
30
+
31
+ if (!key) break;
32
+
33
+ VALUE rb_key = rb_utf8_str_new_cstr(key);
34
+ VALUE rb_value = toml_table_key_to_rb_value(table, key);
35
+
36
+ rb_hash_aset(rb_hash, rb_key, rb_value);
37
+ }
38
+
39
+ return rb_hash;
40
+ }
41
+
42
+ /**
43
+ * Convert TOML array to Ruby array
44
+ */
45
+ static VALUE toml_array_to_rb_array(const toml_array_t *array) {
46
+ int length = toml_array_nelem(array);
47
+
48
+ VALUE rb_array = rb_ary_new2(length);
49
+
50
+ for (int i = 0; i < length; i++) {
51
+ VALUE rb_value = toml_array_index_to_rb_value(array, i);
52
+ rb_ary_push(rb_array, rb_value);
53
+ }
54
+
55
+ return rb_array;
56
+ }
57
+
58
+ /**
59
+ * Convert TOML timestamp to Ruby Date/Time/String depending on timestamp format
60
+ */
61
+ static VALUE toml_timestamp_to_rb_value(const toml_timestamp_t *ts) {
62
+ if (ts->month && (*ts->month < 1 || *ts->month > 12)) {
63
+ rb_raise(cParserError, "invalid month: %d", *ts->month);
64
+ }
65
+
66
+ if (ts->day && (*ts->day < 1 || *ts->day > 31)) {
67
+ rb_raise(cParserError, "invalid day: %d", *ts->day);
68
+ }
69
+
70
+ if (ts->hour && (*ts->hour < 0 || *ts->hour > 23)) {
71
+ rb_raise(cParserError, "invalid hour: %d", *ts->hour);
72
+ }
73
+
74
+ if (ts->minute && (*ts->minute < 0 || *ts->minute > 59)) {
75
+ rb_raise(cParserError, "invalid minute: %d", *ts->minute);
76
+ }
77
+
78
+ if (ts->second && (*ts->second < 0 || *ts->second > 59)) {
79
+ rb_raise(cParserError, "invalid second: %d", *ts->second);
80
+ }
81
+
82
+ if (ts->year && ts->hour) {
83
+ double second = *ts->second * 1000;
84
+
85
+ if (ts->millisec) {
86
+ second += *ts->millisec;
87
+ }
88
+
89
+ VALUE rb_time;
90
+
91
+ VALUE rb_year = INT2FIX(*ts->year);
92
+ VALUE rb_month = INT2FIX(*ts->month);
93
+ VALUE rb_day = INT2FIX(*ts->day);
94
+ VALUE rb_hour = INT2FIX(*ts->hour);
95
+ VALUE rb_minute = INT2FIX(*ts->minute);
96
+ VALUE rb_second = rb_rational_raw(DBL2NUM(second), INT2FIX(1000));
97
+
98
+ if (ts->z) {
99
+ VALUE rb_tz = rb_str_new2(ts->z);
100
+ rb_time = rb_funcall(
101
+ rb_cTime,
102
+ id_new,
103
+ 7,
104
+ rb_year,
105
+ rb_month,
106
+ rb_day,
107
+ rb_hour,
108
+ rb_minute,
109
+ rb_second,
110
+ rb_tz
111
+ );
112
+ } else {
113
+ rb_time = rb_funcall(
114
+ rb_cTime,
115
+ id_new,
116
+ 6,
117
+ rb_year,
118
+ rb_month,
119
+ rb_day,
120
+ rb_hour,
121
+ rb_minute,
122
+ rb_second
123
+ );
124
+ }
125
+
126
+ return rb_time;
127
+ }
128
+
129
+ if (ts->year && !ts->hour) {
130
+ VALUE rb_year = INT2FIX(*ts->year);
131
+ VALUE rb_month = INT2FIX(*ts->month);
132
+ VALUE rb_day = INT2FIX(*ts->day);
133
+
134
+ return rb_funcall(cDate, id_new, 3, rb_year, rb_month, rb_day);
135
+ }
136
+
137
+ if (!ts->year && ts->hour) {
138
+ const char *str;
139
+
140
+ int hour = *ts->hour;
141
+ int minute = *ts->minute;
142
+ int second = *ts->second;
143
+
144
+ if (ts->millisec) {
145
+ char buf[13];
146
+ sprintf(buf, "%02d:%02d:%02d.%03d", hour, minute, second, *ts->millisec);
147
+ str = buf;
148
+ } else {
149
+ char buf[9];
150
+ sprintf(buf, "%02d:%02d:%02d", hour, minute, second);
151
+ str = buf;
152
+ }
153
+
154
+ return rb_str_new2(str);
155
+ }
156
+
157
+ return Qnil;
158
+ }
159
+
160
+ /**
161
+ * Convert TOML table's value to Ruby object
162
+ */
163
+ static VALUE toml_table_key_to_rb_value(const toml_table_t *table, const char *key) {
164
+ toml_datum_t datum;
165
+
166
+ datum = toml_string_in(table, key);
167
+
168
+ if (datum.ok) {
169
+ VALUE rb_value = rb_utf8_str_new_cstr(datum.u.s);
170
+ free(datum.u.s);
171
+ return rb_value;
172
+ }
173
+
174
+ datum = toml_int_in(table, key);
175
+
176
+ if (datum.ok) {
177
+ return LL2NUM(datum.u.i);
178
+ }
179
+
180
+ datum = toml_double_in(table, key);
181
+
182
+ if (datum.ok) {
183
+ return DBL2NUM(datum.u.d);
184
+ }
185
+
186
+ datum = toml_bool_in(table, key);
187
+
188
+ if (datum.ok) {
189
+ return datum.u.b ? Qtrue : Qfalse;
190
+ }
191
+
192
+ datum = toml_timestamp_in(table, key);
193
+
194
+ if (datum.ok) {
195
+ VALUE rb_value = toml_timestamp_to_rb_value(datum.u.ts);
196
+ free(datum.u.ts);
197
+ return rb_value;
198
+ }
199
+
200
+ toml_table_t *sub_table = toml_table_in(table, key);
201
+
202
+ if (sub_table) {
203
+ return toml_table_to_rb_hash(sub_table);
204
+ }
205
+
206
+ toml_array_t *array = toml_array_in(table, key);
207
+
208
+ if (array) {
209
+ return toml_array_to_rb_array(array);
210
+ }
211
+
212
+ rb_raise(cParserError, "invalid value");
213
+ }
214
+
215
+ /**
216
+ * Convert TOML array element to Ruby object
217
+ */
218
+ static VALUE toml_array_index_to_rb_value(const toml_array_t *array, int index) {
219
+ toml_datum_t datum;
220
+
221
+ datum = toml_string_at(array, index);
222
+
223
+ if (datum.ok) {
224
+ VALUE rb_value = rb_utf8_str_new_cstr(datum.u.s);
225
+ free(datum.u.s);
226
+ return rb_value;
227
+ }
228
+
229
+ datum = toml_int_at(array, index);
230
+
231
+ if (datum.ok) {
232
+ return INT2FIX(datum.u.i);
233
+ }
234
+
235
+ datum = toml_double_at(array, index);
236
+
237
+ if (datum.ok) {
238
+ return DBL2NUM(datum.u.d);
239
+ }
240
+
241
+ datum = toml_bool_at(array, index);
242
+
243
+ if (datum.ok) {
244
+ return datum.u.b ? Qtrue : Qfalse;
245
+ }
246
+
247
+ datum = toml_timestamp_at(array, index);
248
+
249
+ if (datum.ok) {
250
+ VALUE rb_value = toml_timestamp_to_rb_value(datum.u.ts);
251
+ free(datum.u.ts);
252
+ return rb_value;
253
+ }
254
+
255
+ toml_table_t *table = toml_table_at(array, index);
256
+
257
+ if (table) {
258
+ return toml_table_to_rb_hash(table);
259
+ }
260
+
261
+ toml_array_t *sub_array = toml_array_at(array, index);
262
+
263
+ if (sub_array) {
264
+ return toml_array_to_rb_array(sub_array);
265
+ }
266
+
267
+ rb_raise(cParserError, "invalid value");
268
+ }
269
+
270
+ /**
271
+ * Parse TOML string and convert it into Ruby hash
272
+ */
273
+ static VALUE tomlib_load_do(VALUE rb_str) {
274
+ char *str = StringValueCStr(rb_str);
275
+ char errbuf[200] = "";
276
+
277
+ toml_table_t *table = toml_parse(str, errbuf, sizeof(errbuf));
278
+
279
+ if (!table) {
280
+ rb_raise(cParserError, "%s", errbuf);
281
+ }
282
+
283
+ VALUE rb_value = toml_table_to_rb_hash(table);
284
+
285
+ toml_free(table);
286
+
287
+ return rb_value;
288
+ }
289
+
290
+ /**
291
+ * Rescue from argument errors
292
+ */
293
+ static VALUE tomlib_load_rescue(VALUE rb_arg, VALUE rb_error) {
294
+ rb_set_errinfo(Qnil);
295
+ rb_raise(cParserError, "string contains null byte");
296
+ return Qnil;
297
+ }
298
+
299
+ /**
300
+ * Function exposed to Ruby's world as Tomlib.load(data)
301
+ */
302
+ static VALUE tomlib_load(VALUE self, VALUE rb_str) {
303
+ return rb_rescue2(tomlib_load_do, rb_str, tomlib_load_rescue, Qnil, rb_eArgError, 0);
304
+ }
305
+
306
+ /**
307
+ * Function exposed to Ruby's world as Tomlib::Dumper#key_type(str)
308
+ */
309
+ static VALUE tomlib_key_type(VALUE self, VALUE rb_key) {
310
+ const long str_len = RSTRING_LEN(rb_key);
311
+ const char *str = RSTRING_PTR(rb_key);
312
+
313
+ if (str_len == 0) return sym_escape;
314
+
315
+ for(long i = 0; i < str_len; i++) {
316
+ const char c = *(str + i);
317
+
318
+ if (c == '\n') {
319
+ return sym_escape;
320
+ }
321
+
322
+ const bool is_upper_alpha = c >= 'A' && c <= 'Z';
323
+ const bool is_lower_alpha = c >= 'a' && c <= 'z';
324
+ const bool is_number = c >= '0' && c <= '9';
325
+ const bool is_dash = c == '-';
326
+ const bool is_underscore = c == '_';
327
+
328
+ if (!(is_upper_alpha || is_lower_alpha || is_number || is_dash || is_underscore)) {
329
+ return sym_quoted;
330
+ }
331
+ }
332
+
333
+ return sym_simple;
334
+ }
335
+
336
+ /**
337
+ * Ruby's extension entry point
338
+ */
339
+ void Init_tomlib(void) {
340
+ id_new = rb_intern("new");
341
+
342
+ sym_simple = ID2SYM(rb_intern("simple"));
343
+ rb_global_variable(&sym_simple);
344
+ sym_quoted = ID2SYM(rb_intern("quoted"));
345
+ rb_global_variable(&sym_quoted);
346
+ sym_escape = ID2SYM(rb_intern("escape"));
347
+ rb_global_variable(&sym_escape);
348
+
349
+ cDate = rb_const_get(rb_cObject, rb_intern("Date"));
350
+ rb_global_variable(&cDate);
351
+
352
+ mTomlib = rb_define_module("Tomlib");
353
+ rb_define_singleton_method(mTomlib, "load", tomlib_load, 1);
354
+
355
+ cDumper = rb_define_class_under(mTomlib, "Dumper", rb_cObject);
356
+ rb_define_private_method(cDumper, "key_type", tomlib_key_type, 1);
357
+
358
+ cParserError = rb_define_class_under(mTomlib, "ParseError", rb_eStandardError);
359
+ }
data/lib/tomlib/dumper.rb CHANGED
@@ -27,17 +27,37 @@ module Tomlib
27
27
  # @api private
28
28
  NAN = 'nan'.freeze
29
29
 
30
+ def initialize(use_indent: true)
31
+ @use_indent = use_indent
32
+ end
33
+
34
+ # Generate TOML string from ruby Hash
35
+ #
36
+ # @param [Hash] hash
37
+ #
38
+ # @return [String]
39
+ #
40
+ # @api private
41
+ def dump(hash)
42
+ result = dump_hash(hash)
43
+
44
+ result[0] = '' if result[0] == "\n"
45
+
46
+ result
47
+ end
48
+
49
+ private
50
+
30
51
  # Generate TOML string from ruby Hash
31
52
  #
32
53
  # @param [Hash] hash
33
54
  # @param [String, nil] base_key
34
- # @param [String] indent
35
- # @param [true, false] use_indent
55
+ # @param [Integer] indent_level
36
56
  #
37
57
  # @return [String]
38
58
  #
39
59
  # @api private
40
- def dump(hash, base_key = nil, indent = '', use_indent: true)
60
+ def dump_hash(hash, base_key = nil, indent_level = 0)
41
61
  header = ''
42
62
  footer = ''
43
63
 
@@ -45,34 +65,36 @@ module Tomlib
45
65
  toml_key = to_toml_key(key)
46
66
 
47
67
  if value.is_a?(Hash)
68
+ skip = !value.empty? && value.values.all? { |e| e.is_a?(Hash) }
48
69
  compound_key = to_toml_compound_key(base_key, toml_key)
49
- next_indent = use_indent && base_key ? indent + INDENT : indent
50
70
 
51
- footer << "\n".freeze << next_indent << '['.freeze << compound_key << "]\n".freeze
52
- footer << dump(value, compound_key, next_indent, use_indent: use_indent)
53
- elsif value.is_a?(Array) && value.all? { |e| e.is_a?(Hash) }
71
+ unless skip
72
+ indent = @use_indent ? INDENT * indent_level : ''.freeze
73
+ footer << "\n".freeze << indent << '['.freeze << compound_key << "]\n".freeze
74
+ end
75
+
76
+ footer << dump_hash(value, compound_key, skip ? indent_level : indent_level + 1)
77
+ elsif value.is_a?(Array) && !value.empty? && value.all? { |e| e.is_a?(Hash) }
54
78
  compound_key = to_toml_compound_key(base_key, toml_key)
55
- next_indent = use_indent && base_key ? indent + INDENT : indent
79
+ indent = @use_indent ? INDENT * indent_level : ''.freeze
56
80
 
57
81
  value.each do |el|
58
- footer << "\n".freeze << next_indent << '[['.freeze << compound_key << "]]\n".freeze
59
- footer << dump(el, compound_key, next_indent, use_indent: use_indent)
82
+ footer << "\n".freeze << indent << '[['.freeze << compound_key << "]]\n".freeze
83
+ footer << dump_hash(el, compound_key, indent_level + 1)
60
84
  end
61
85
  else
86
+ indent_length = indent_level > 0 ? indent_level - 1 : 0
87
+ indent = @use_indent ? INDENT * indent_length : ''.freeze
62
88
  header << indent << toml_key << ' = '.freeze << to_toml_value(value) << "\n".freeze
63
89
  end
64
90
  end
65
91
 
66
- footer.gsub!(/\A\n/, ''.freeze) if header.empty?
67
92
  header << footer
68
93
  end
69
94
 
70
- private
71
-
72
95
  # Generate TOML key from Hash key
73
96
  #
74
97
  # @param [String] key
75
- # @param [true, false] use_indent
76
98
  #
77
99
  # @return [String]
78
100
  #
@@ -126,7 +148,7 @@ module Tomlib
126
148
  when Hash
127
149
  "{ #{value.map { |k, v| "#{to_toml_key(k)} = #{to_toml_value(v)}" }.join(', ')} }"
128
150
  when Array
129
- "[ #{value.map { |e| to_toml_value(e) }.join(', ')} ]"
151
+ value.empty? ? '[]' : "[ #{value.map { |e| to_toml_value(e) }.join(', ')} ]"
130
152
  when nil
131
153
  '""'.freeze
132
154
  else
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Tomlib
4
4
  # @api private
5
- VERSION = '0.1.0'
5
+ VERSION = '0.4.0'
6
6
  end
data/lib/tomlib.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'date'
4
+
3
5
  require_relative 'tomlib/dumper'
4
6
  require_relative 'tomlib/tomlib'
5
7
  require_relative 'tomlib/version'
@@ -40,6 +42,6 @@ module Tomlib
40
42
  #
41
43
  # @api public
42
44
  def self.dump(hash, indent: true)
43
- Dumper.new.dump(hash, use_indent: indent)
45
+ Dumper.new(use_indent: indent).dump(hash)
44
46
  end
45
47
  end
data/tomlib.gemspec CHANGED
@@ -20,7 +20,14 @@ Gem::Specification.new do |spec|
20
20
  spec.metadata['changelog_uri'] = 'https://github.com/kgiszczak/tomlib/blob/master/CHANGELOG.md'
21
21
  spec.metadata['bug_tracker_uri'] = 'https://github.com/kgiszczak/tomlib/issues'
22
22
 
23
- spec.files = Dir['CHANGELOG.md', 'LICENSE.txt', 'README.md', 'tomlib.gemspec', 'lib/**/*']
23
+ spec.files = Dir[
24
+ 'CHANGELOG.md',
25
+ 'LICENSE.txt',
26
+ 'README.md',
27
+ 'tomlib.gemspec',
28
+ 'ext/**/*',
29
+ 'lib/**/*.rb',
30
+ ]
24
31
  spec.require_paths = ['lib']
25
32
 
26
33
  spec.extensions = ['ext/tomlib/extconf.rb']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tomlib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kamil Giszczak
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-02 00:00:00.000000000 Z
11
+ date: 2022-08-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Fast TOML parser and generator with native extension.
14
14
  email:
@@ -22,10 +22,12 @@ files:
22
22
  - LICENSE.txt
23
23
  - README.md
24
24
  - ext/tomlib/extconf.rb
25
+ - ext/tomlib/toml.c
26
+ - ext/tomlib/toml.h
27
+ - ext/tomlib/tomlib.c
25
28
  - lib/tomlib.rb
26
29
  - lib/tomlib/dumper.rb
27
30
  - lib/tomlib/error.rb
28
- - lib/tomlib/tomlib.bundle
29
31
  - lib/tomlib/version.rb
30
32
  - tomlib.gemspec
31
33
  homepage: https://github.com/kgiszczak/tomlib
Binary file