strptime 0.1.9-x64-mingw32 → 0.2.1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87b7e4d6f0044905e518c093138d21e538af7f23
4
- data.tar.gz: 772e0fbc7837a84fbee99fd598ace9b64b31e622
3
+ metadata.gz: da9b5b737ae895af93e98cc6a5d267e134e36cef
4
+ data.tar.gz: ff65ec6bdc06e6f0b202bb8a91594e50f83d6483
5
5
  SHA512:
6
- metadata.gz: 152d8f0198b22f65929cc6fd3503bde2898758ea5eb21d932d9fc8d8a183b3f9520222a30ce055dc7eab68ac93703c963d76c22eed5b701d31c84c1feb769f6f
7
- data.tar.gz: 306be2bad64761df3f8d4345b319d20cbb129c1d454ac8a6fee04f38809fa20f95b4f250457d1fbf83f4b1224ba562967708edebe39996cbd8b4440911924a68
6
+ metadata.gz: 9a16feb8a8146c3d0ae99880f6b9be74fad1049de1413446faa81072bba597d61c9dd15afdf73625f792f49cadbd2a57b9a52515d2c03a2984429477eb7484d5
7
+ data.tar.gz: 149c4fdc38c93bf6389d2cb4733c4745eb422b70a46dcc0b767bb61cf7ff14ab0f2018abbe916d4e572f08d26ed497841e4c024cea61cacd2aac6f8b98d215ed
@@ -2,5 +2,6 @@ require "mkmf"
2
2
 
3
3
  have_func('rb_timespec_now')
4
4
  have_func('rb_time_timespec_new')
5
+ have_func('rb_time_utc_offset')
5
6
 
6
7
  create_makefile("strptime/strptime")
@@ -147,7 +147,7 @@ rb_localtime_r(const time_t *t, struct tm *result)
147
147
  }
148
148
  #define LOCALTIME(tm, result) (tzset(),rb_localtime_r((tm), &(result)))
149
149
 
150
- static struct tm *
150
+ struct tm *
151
151
  rb_gmtime_r(const time_t *t, struct tm *result)
152
152
  {
153
153
  #ifdef HAVE_GMTIME_R
@@ -0,0 +1,495 @@
1
+ #include "../strptime/strptime.h"
2
+ #include "ruby/encoding.h"
3
+ #include <time.h>
4
+
5
+ VALUE rb_cStrftime;
6
+ #ifndef HAVE_RB_TIME_UTC_OFFSET
7
+ static ID id_gmtoff;
8
+ #endif
9
+
10
+ #define GetStrftimeval(obj, tobj) ((tobj) = get_strftimeval(obj))
11
+ #define GetNewStrftimeval(obj, tobj) ((tobj) = get_new_strftimeval(obj))
12
+ #define StrfTIME_INIT_P(tobj) ((tobj)->isns)
13
+
14
+ #define LIKELY(x) (__builtin_expect((x), 1))
15
+ #define UNLIKELY(x) (__builtin_expect((x), 0))
16
+
17
+ #define REG_PC (pc)
18
+ #define GET_PC() REG_PC
19
+ #define SET_PC(x) (REG_PC = (x))
20
+ #define GET_CURRENT_INSN() (*GET_PC())
21
+ #define GET_OPERAND(n) (GET_PC()[(n)])
22
+ #define ADD_PC(n) (SET_PC(REG_PC + (n)))
23
+
24
+ #define JUMP(dst) (REG_PC += (dst))
25
+
26
+ #define LABEL(x) INSN_LABEL_##x
27
+ #define ELABEL(x) INSN_ELABEL_##x
28
+ #define LABEL_PTR(x) &&LABEL(x)
29
+
30
+ #define INSN_ENTRY(insn) LABEL(insn) :
31
+
32
+ #define TC_DISPATCH(insn) \
33
+ goto *(void const *)GET_CURRENT_INSN(); \
34
+ ;
35
+ #define END_INSN(insn) TC_DISPATCH(insn);
36
+
37
+ #define INSN_DISPATCH() \
38
+ TC_DISPATCH(__START__) \
39
+ {
40
+
41
+ #define END_INSNS_DISPATCH() \
42
+ rb_bug("strptime: unknown insn: %p", GET_CURRENT_INSN()); \
43
+ } /* end of while loop */
44
+
45
+ #define NEXT_INSN() TC_DISPATCH(__NEXT_INSN__)
46
+
47
+
48
+
49
+ static VALUE
50
+ strftime_exec0(void **pc, VALUE fmt, struct timespec *tsp, int gmtoff, size_t result_length)
51
+ {
52
+ VALUE result;
53
+ struct tm tm;
54
+ char *p;
55
+ if (UNLIKELY(tsp == NULL)) {
56
+ static const void *const insns_address_table[] = {
57
+ NULL, NULL, NULL, NULL,
58
+ NULL, NULL, NULL, LABEL_PTR(H),
59
+ NULL, NULL, NULL, LABEL_PTR(L),
60
+ LABEL_PTR(M), LABEL_PTR(N), NULL, NULL,
61
+ NULL, NULL, LABEL_PTR(S), NULL,
62
+ NULL, NULL, NULL, NULL,
63
+ LABEL_PTR(Y), NULL, NULL, NULL,
64
+ NULL, NULL, LABEL_PTR(_5f), LABEL_PTR(_60),
65
+ NULL, NULL, NULL, LABEL_PTR(d),
66
+ LABEL_PTR(d), NULL, NULL, NULL,
67
+ NULL, NULL, NULL, NULL,
68
+ LABEL_PTR(m), NULL, NULL, NULL,
69
+ NULL, NULL, NULL, NULL,
70
+ NULL, NULL, NULL, NULL,
71
+ LABEL_PTR(y), LABEL_PTR(z),
72
+ };
73
+ *pc = (void *)insns_address_table;
74
+ return Qnil;
75
+ }
76
+
77
+ result = rb_str_new(NULL, result_length);
78
+ p = RSTRING_PTR(result);
79
+
80
+ tsp->tv_sec += gmtoff;
81
+ rb_gmtime_r(&tsp->tv_sec, &tm);
82
+
83
+ INSN_DISPATCH();
84
+ INSN_ENTRY(H)
85
+ {
86
+ *p++ = '0' + (tm.tm_hour / 10);
87
+ *p++ = '0' + (tm.tm_hour % 10);
88
+ ADD_PC(1);
89
+ END_INSN(H)
90
+ }
91
+ INSN_ENTRY(L)
92
+ {
93
+ int msec = tsp->tv_nsec / 1000000;
94
+ p[2] = '0' + (msec % 10);
95
+ msec /= 10;
96
+ p[1] = '0' + (msec % 10);
97
+ p[0] = '0' + (msec / 10);
98
+ p += 3;
99
+ ADD_PC(1);
100
+ END_INSN(L)
101
+ }
102
+ INSN_ENTRY(M)
103
+ {
104
+ *p++ = '0' + (tm.tm_min / 10);
105
+ *p++ = '0' + (tm.tm_min % 10);
106
+ ADD_PC(1);
107
+ END_INSN(M)
108
+ }
109
+ INSN_ENTRY(N)
110
+ {
111
+ int len = 9;
112
+ int i;
113
+ int base = 1;
114
+ int subsec = tsp->tv_nsec;
115
+ for (i=0; i < 9-len; i++) {
116
+ base *= 10;
117
+ }
118
+ subsec /= base;
119
+ for (i=0; i < len; i++) {
120
+ p[len-i-1] = '0' + subsec % 10;
121
+ subsec /= 10;
122
+ }
123
+ p += len;
124
+ ADD_PC(1);
125
+ END_INSN(N)
126
+ }
127
+ INSN_ENTRY(S)
128
+ {
129
+ *p++ = '0' + (tm.tm_sec / 10);
130
+ *p++ = '0' + (tm.tm_sec % 10);
131
+ ADD_PC(1);
132
+ END_INSN(S)
133
+ }
134
+ INSN_ENTRY(Y)
135
+ {
136
+ // TODO: Y10K
137
+ int i, y = tm.tm_year;
138
+ y += y < 69 ? 2000 : 1900;
139
+ for (i = 0; i < 4; i++) {
140
+ p[3-i] = '0' + y % 10;
141
+ y /= 10;
142
+ }
143
+ p += 4;
144
+ ADD_PC(1);
145
+ END_INSN(Y)
146
+ }
147
+ INSN_ENTRY(d)
148
+ {
149
+ *p++ = '0' + (tm.tm_mday / 10);
150
+ *p++ = '0' + (tm.tm_mday % 10);
151
+ ADD_PC(1);
152
+ END_INSN(d)
153
+ }
154
+ INSN_ENTRY(m)
155
+ {
156
+ int mon = tm.tm_mon + 1;
157
+ *p++ = '0' + (mon / 10);
158
+ *p++ = '0' + (mon % 10);
159
+ ADD_PC(1);
160
+ END_INSN(m)
161
+ }
162
+ INSN_ENTRY(y)
163
+ {
164
+ int y = tm.tm_year % 100;
165
+ *p++ = '0' + (y / 10);
166
+ *p++ = '0' + (y % 10);
167
+ ADD_PC(1);
168
+ END_INSN(y)
169
+ }
170
+ INSN_ENTRY(z)
171
+ {
172
+ int h, m, tmp=gmtoff;
173
+ if (gmtoff >= 0) {
174
+ *p++ = '+';
175
+ } else {
176
+ *p++ = '-';
177
+ tmp = -tmp;
178
+ }
179
+ tmp /= 60;
180
+ h = (tmp / 60)&15; /* ignore too large offset */
181
+ m = tmp % 60;
182
+ *p++ = '0' + (h / 10);
183
+ *p++ = '0' + (h % 10);
184
+ *p++ = '0' + (m / 10);
185
+ *p++ = '0' + (m % 10);
186
+ ADD_PC(1);
187
+ END_INSN(y)
188
+ }
189
+ INSN_ENTRY(_60)
190
+ {
191
+ size_t v = (size_t)GET_OPERAND(1);
192
+ size_t off = v & 0xFFFF;
193
+ size_t len = v >> 16;
194
+ memcpy(p, RSTRING_PTR(fmt) + off, len);
195
+ p += len;
196
+ pc += 2;
197
+ END_INSN(_60)
198
+ }
199
+ INSN_ENTRY(_5f)
200
+ {
201
+ return result;
202
+ END_INSN(_5f)
203
+ }
204
+ END_INSNS_DISPATCH();
205
+
206
+ /* unreachable */
207
+ rb_bug("strftime_exec0: unreachable");
208
+ UNREACHABLE;
209
+ }
210
+
211
+ static void **
212
+ strftime_compile(const char *fmt, size_t flen, size_t *rlenp)
213
+ {
214
+ size_t fi = 0, rlen = 0;
215
+ char c;
216
+ void **isns0, **isns;
217
+ void **insns_address_table;
218
+ void *tmp;
219
+ strftime_exec0((void **)&insns_address_table, Qnil, NULL, 0, 0);
220
+
221
+ if (flen > 65535) {
222
+ rb_raise(rb_eArgError, "too long format string (>65335)");
223
+ }
224
+ isns0 = ALLOC_N(void *, flen + 2);
225
+ isns = isns0;
226
+
227
+ while (fi < flen) {
228
+ switch (fmt[fi]) {
229
+ case '%':
230
+ fi++;
231
+ c = fmt[fi];
232
+ switch (c) {
233
+ case 'H':
234
+ rlen += 2;
235
+ goto accept_format;
236
+ case 'L':
237
+ rlen += 3;
238
+ goto accept_format;
239
+ case 'M':
240
+ rlen += 2;
241
+ goto accept_format;
242
+ case 'N':
243
+ rlen += 9;
244
+ goto accept_format;
245
+ case 'S':
246
+ rlen += 2;
247
+ goto accept_format;
248
+ case 'Y':
249
+ rlen += 4;
250
+ goto accept_format;
251
+ case 'd':
252
+ rlen += 2;
253
+ goto accept_format;
254
+ case 'm':
255
+ rlen += 2;
256
+ goto accept_format;
257
+ case 'y':
258
+ rlen += 2;
259
+ goto accept_format;
260
+ case 'z':
261
+ rlen += 5;
262
+ goto accept_format;
263
+ accept_format:
264
+ tmp = insns_address_table[c - 'A'];
265
+ if (tmp) {
266
+ *isns++ = tmp;
267
+ fi++;
268
+ continue;
269
+ }
270
+ default:
271
+ xfree(isns0);
272
+ rb_raise(rb_eArgError, "invalid format");
273
+ break;
274
+ }
275
+ default: {
276
+ const char *p0 = fmt + fi, *p = p0, *pe = fmt + flen;
277
+ size_t v = fi;
278
+ while (p < pe && *p != '%')
279
+ p++;
280
+ v += (p - p0) << 16;
281
+ fi += p - p0;
282
+ rlen += p - p0;
283
+ *isns++ = insns_address_table['`' - 'A'];
284
+ *isns++ = (void *)v;
285
+ } break;
286
+ }
287
+ }
288
+ *isns++ = insns_address_table['_' - 'A'];
289
+ REALLOC_N(isns0, void *, isns - isns0);
290
+ *rlenp = rlen;
291
+ return isns0;
292
+ }
293
+
294
+ struct strftime_object {
295
+ void **isns;
296
+ size_t result_length;
297
+ VALUE fmt;
298
+ };
299
+
300
+ static void
301
+ strftime_mark(void *ptr)
302
+ {
303
+ struct strftime_object *tobj = ptr;
304
+ rb_gc_mark(tobj->fmt);
305
+ }
306
+
307
+ static void
308
+ strftime_free(void *ptr)
309
+ {
310
+ struct strftime_object *tobj = ptr;
311
+ if (tobj->isns) ruby_xfree(tobj->isns);
312
+ }
313
+
314
+ static size_t
315
+ strftime_memsize(const void *tobj)
316
+ {
317
+ return sizeof(struct strftime_object);
318
+ }
319
+
320
+ static const rb_data_type_t strftime_data_type = {
321
+ "strftime",
322
+ {
323
+ strftime_mark, strftime_free, strftime_memsize,
324
+ },
325
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
326
+ 0,
327
+ 0,
328
+ RUBY_TYPED_FREE_IMMEDIATELY
329
+ #endif
330
+ };
331
+
332
+ static VALUE
333
+ strftime_s_alloc(VALUE klass)
334
+ {
335
+ VALUE obj;
336
+ struct strftime_object *tobj;
337
+
338
+ obj = TypedData_Make_Struct(klass, struct strftime_object,
339
+ &strftime_data_type, tobj);
340
+
341
+ return obj;
342
+ }
343
+
344
+ static struct strftime_object *
345
+ get_strftimeval(VALUE obj)
346
+ {
347
+ struct strftime_object *tobj;
348
+ TypedData_Get_Struct(obj, struct strftime_object, &strftime_data_type,
349
+ tobj);
350
+ if (!StrfTIME_INIT_P(tobj)) {
351
+ rb_raise(rb_eTypeError, "uninitialized %" PRIsVALUE, rb_obj_class(obj));
352
+ }
353
+ return tobj;
354
+ }
355
+
356
+ static struct strftime_object *
357
+ get_new_strftimeval(VALUE obj)
358
+ {
359
+ struct strftime_object *tobj;
360
+ TypedData_Get_Struct(obj, struct strftime_object, &strftime_data_type,
361
+ tobj);
362
+ if (StrfTIME_INIT_P(tobj)) {
363
+ rb_raise(rb_eTypeError, "already initialized %" PRIsVALUE,
364
+ rb_obj_class(obj));
365
+ }
366
+ return tobj;
367
+ }
368
+
369
+ /*
370
+ * @overload new(format)
371
+ * @param format [String] strftime(3) style format string.
372
+ *
373
+ * returns generator object
374
+ */
375
+ static VALUE
376
+ strftime_init(VALUE self, VALUE fmt)
377
+ {
378
+ struct strftime_object *tobj;
379
+ void **isns;
380
+ size_t rlen;
381
+ StringValueCStr(fmt);
382
+ TypedData_Get_Struct(self, struct strftime_object, &strftime_data_type,
383
+ tobj);
384
+ isns = strftime_compile(RSTRING_PTR(fmt), RSTRING_LEN(fmt), &rlen);
385
+ tobj->isns = isns;
386
+ tobj->fmt = rb_str_new_frozen(fmt);
387
+ tobj->result_length = rlen;
388
+ return self;
389
+ }
390
+
391
+ /* @api private
392
+ * For Ruby VM internal.
393
+ */
394
+ static VALUE
395
+ strftime_init_copy(VALUE copy, VALUE self)
396
+ {
397
+ struct strftime_object *tobj, *tcopy;
398
+
399
+ if (!OBJ_INIT_COPY(copy, self)) return copy;
400
+ GetStrftimeval(self, tobj);
401
+ GetNewStrftimeval(copy, tcopy);
402
+ MEMCPY(tcopy, tobj, struct strftime_object, 1);
403
+
404
+ return copy;
405
+ }
406
+
407
+ /*
408
+ * @overload exec(str)
409
+ * @param str [String] string to parse
410
+ * @return [Time] the time object given string means
411
+ *
412
+ * Return a formatted datetime string
413
+ *
414
+ */
415
+ static VALUE
416
+ strftime_exec(VALUE self, VALUE time)
417
+ {
418
+ struct strftime_object *sobj;
419
+ struct timespec ts = rb_time_timespec(time);
420
+ #ifdef HAVE_RB_TIME_UTC_OFFSET
421
+ int gmtoff = FIX2INT(rb_time_utc_offset(time));
422
+ #else
423
+ int gmtoff = NUM2INT(rb_funcall(time, id_gmtoff, 0));
424
+ #endif
425
+ GetStrftimeval(self, sobj);
426
+
427
+ return strftime_exec0(sobj->isns, sobj->fmt, &ts, gmtoff, sobj->result_length);
428
+ }
429
+
430
+ /*
431
+ * @overload execi(epoch)
432
+ * @param epoch [Integer] Unix epoch
433
+ * @return [String] the formatted datetime string
434
+ *
435
+ * Return a formatted datetime string
436
+ *
437
+ */
438
+ static VALUE
439
+ strftime_execi(VALUE self, VALUE epoch)
440
+ {
441
+ struct strftime_object *tobj;
442
+ struct timespec ts;
443
+ GetStrftimeval(self, tobj);
444
+
445
+ if (RB_INTEGER_TYPE_P(epoch)) {
446
+ ts.tv_sec = NUM2TIMET(epoch);
447
+ ts.tv_nsec = 0;
448
+ } else if (RB_FLOAT_TYPE_P(epoch)) {
449
+ double d = NUM2DBL(epoch);
450
+ ts.tv_sec = (time_t)d;
451
+ ts.tv_nsec = (int)((int64_t)(d * 1000000000) % 1000000000);
452
+ } else if (RB_TYPE_P(epoch, T_RATIONAL)) {
453
+ ts.tv_sec = NUM2TIMET(epoch);
454
+ ts.tv_nsec = NUM2INT(rb_funcall(rb_funcall(epoch, '*', 1, INT2FIX(1000000000)), '%', 1, INT2FIX(1000000000)));
455
+ }
456
+
457
+ return strftime_exec0(tobj->isns, tobj->fmt, &ts, 0, tobj->result_length);
458
+ }
459
+
460
+ /*
461
+ * @overload source
462
+ * @return [String] source format string
463
+ */
464
+ static VALUE
465
+ strftime_source(VALUE self)
466
+ {
467
+ struct strftime_object *tobj;
468
+ GetStrftimeval(self, tobj);
469
+
470
+ return tobj->fmt;
471
+ }
472
+
473
+
474
+ /*
475
+ * Document-class: Strftime
476
+ *
477
+ * Strftime is a faster way to format time string like strftime(3).
478
+ *
479
+ * @example
480
+ * generator = Strftime.new('%Y-%m-%dT%H:%M:%S%z')
481
+ * generator.source #=> "%Y-%m-%dT%H:%M:%S%z"
482
+ * generator.exec(Time.now) #=> 2017-12-25T12:34:56+09:00
483
+ */
484
+ void
485
+ Init_strftime(void)
486
+ {
487
+ rb_cStrftime = rb_define_class("Strftime", rb_cObject);
488
+ rb_define_alloc_func(rb_cStrftime, strftime_s_alloc);
489
+ rb_define_method(rb_cStrftime, "initialize", strftime_init, 1);
490
+ rb_define_method(rb_cStrftime, "initialize_copy", strftime_init_copy, 1);
491
+ rb_define_method(rb_cStrftime, "exec", strftime_exec, 1);
492
+ rb_define_method(rb_cStrftime, "execi", strftime_execi, 1);
493
+ rb_define_method(rb_cStrftime, "source", strftime_source, 0);
494
+ id_gmtoff = rb_intern("gmtoff");
495
+ }
@@ -481,7 +481,7 @@ strptime_exec0(void **pc, const char *fmt, const char *str, size_t slen,
481
481
  UNREACHABLE;
482
482
  }
483
483
 
484
- void **
484
+ static void **
485
485
  strptime_compile(const char *fmt, size_t flen)
486
486
  {
487
487
  size_t fi = 0;
@@ -518,7 +518,10 @@ strptime_compile(const char *fmt, size_t flen)
518
518
  fi++;
519
519
  continue;
520
520
  }
521
- default: rb_raise(rb_eArgError, "invalid format"); break;
521
+ default:
522
+ xfree(isns0);
523
+ rb_raise(rb_eArgError, "invalid format");
524
+ break;
522
525
  }
523
526
  case ' ':
524
527
  case '\t':
@@ -562,7 +565,7 @@ static void
562
565
  strptime_free(void *ptr)
563
566
  {
564
567
  struct strptime_object *tobj = ptr;
565
- ruby_xfree(tobj->isns);
568
+ if (tobj->isns) ruby_xfree(tobj->isns);
566
569
  }
567
570
 
568
571
  static size_t
@@ -735,4 +738,5 @@ Init_strptime(void)
735
738
  rb_define_method(rb_cStrptime, "exec", strptime_exec, 1);
736
739
  rb_define_method(rb_cStrptime, "execi", strptime_execi, 1);
737
740
  rb_define_method(rb_cStrptime, "source", strptime_source, 0);
741
+ Init_strftime();
738
742
  }
@@ -12,5 +12,18 @@ void rb_timespec_now(struct timespec *ts);
12
12
  time_t timegm_noleapsecond(struct tm *tm);
13
13
  const char *find_time_t(struct tm *tptr, int utc_p, time_t *tp);
14
14
  void tm_add_offset(struct tm *tm, long diff);
15
+ struct tm *rb_gmtime_r(const time_t *t, struct tm *result);
16
+ void Init_strftime(void);
17
+
18
+ #ifndef RB_INTEGER_TYPE_P
19
+ #define RB_INTEGER_TYPE_P(obj) rb_integer_type_p(obj)
20
+ static inline int
21
+ rb_integer_type_p(VALUE obj)
22
+ {
23
+ return (FIXNUM_P(obj) ||
24
+ (!SPECIAL_CONST_P(obj) &&
25
+ BUILTIN_TYPE(obj) == RUBY_T_BIGNUM));
26
+ }
27
+ #endif
15
28
 
16
29
  #endif /* STRPTIME_H */
@@ -1,3 +1,3 @@
1
1
  class Strptime
2
- VERSION = "0.1.9"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["NARUSE, Yui"]
10
10
  spec.email = ["naruse@airemix.jp"]
11
11
 
12
- spec.summary = %q{a fast strptime engine.}
13
- spec.description = %q{a fast strptime engine which uses VM.}
12
+ spec.summary = %q{a fast strptime/strftime engine.}
13
+ spec.description = %q{a fast strptime/strftime engine which uses VM.}
14
14
  spec.homepage = "https://github.com/nurse/strptime"
15
15
  spec.license = "BSD-2-Clause"
16
16
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strptime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.1
5
5
  platform: x64-mingw32
6
6
  authors:
7
7
  - NARUSE, Yui
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-01-11 00:00:00.000000000 Z
11
+ date: 2017-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- description: a fast strptime engine which uses VM.
97
+ description: a fast strptime/strftime engine which uses VM.
98
98
  email:
99
99
  - naruse@airemix.jp
100
100
  executables: []
@@ -114,6 +114,7 @@ files:
114
114
  - bin/setup
115
115
  - ext/strptime/extconf.rb
116
116
  - ext/strptime/ruby_time.c
117
+ - ext/strptime/strftime.c
117
118
  - ext/strptime/strptime.c
118
119
  - ext/strptime/strptime.h
119
120
  - lib/strptime.rb
@@ -150,5 +151,5 @@ rubyforge_project:
150
151
  rubygems_version: 2.6.8
151
152
  signing_key:
152
153
  specification_version: 4
153
- summary: a fast strptime engine.
154
+ summary: a fast strptime/strftime engine.
154
155
  test_files: []