uringmachine 0.11 → 0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8297cccb35ae1c8086889c2400db8bb884b0dfccdbef561caa0a4e9f80b21053
4
- data.tar.gz: 990e84bb2f975de00739150cff966bbf97a551ba135714eb92bc3b86cd14b5d0
3
+ metadata.gz: 1f8224da7817436bd74a52e650362c9b77d5dbc8877c0fa1cefd1c52e57ceb03
4
+ data.tar.gz: c7bb88c42bf59a9d1f105e2356c4f71f0fec49c7cbbe662744465ee3b34d5141
5
5
  SHA512:
6
- metadata.gz: f66149736c1cf58f8df65d387b81ff070fd890e99aa7c8aa806a5afcb04b8248b78c95c1673d30b7d3270c81e05bc0b84afdb025d2a0a2f02beca5977196b321
7
- data.tar.gz: 7b6e6c31193da3a1e3e9a6fa627c84ae0f4d35c36f5fa636595acf1a013b71cd419073bb78be04130333796bed05e0ce9d1bfa74ab195608346cd689ecf9abaf
6
+ metadata.gz: 39d930e9f4d8a17676c28e4bf24f38b585dbd0cd124316272778abb285391be4bb9ecf14452d19568ffa8f6a0144c6a98b2e3ee1f50d58ec7c5101333f5de5e7
7
+ data.tar.gz: 95468f71d402a2a8abf675dbbae6e94b4e1919c5552f0b831b7387016d3fb24271756585cf66283130ed3440818ccc94f504d73a46d2ab8f9faa4607b0cc822b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # 2025-06-03 Version 0.12
2
+
3
+ - Add buffer, maxlen params to `Stream#get_line`
4
+ - Add buffer param to `Stream#get_string`
5
+ - Remove `Stream#resp_get_line`, `Stream#resp_get_string` methods
6
+
7
+ # 2025-06-02 Version 0.11.1
8
+
9
+ - Fix `UM::Stream` behaviour on GC
10
+
1
11
  # 2025-06-02 Version 0.11
2
12
 
3
13
  - Implement `UM::Stream` class for read streams
data/TODO.md CHANGED
@@ -22,3 +22,27 @@
22
22
  When doing a `call`, we need to provide a mailbox for the response. can this be
23
23
  automatic?
24
24
 
25
+ # streams
26
+
27
+ We're still missing:
28
+
29
+ - limit on line length in `get_line`
30
+ - ability to supply buffer to `get_line` and `get_string`
31
+ - allow read to eof, maybe with `read_to_eof`
32
+
33
+ For the sake of performance, simplicity and explicitness, we change the API as follows:
34
+
35
+ ```ruby
36
+ stream.get_line(buf, limit)
37
+ # the defaults:
38
+ stream.get_line(nil, -1)
39
+
40
+ stream.get_string(len, buf)
41
+ # defaults:
42
+ stream.get_string(len, nil)
43
+
44
+ # and
45
+ stream.read_to_eof(buf)
46
+ # defaults:
47
+ stream.read_to_eof(nil)
48
+ ```
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/inline'
3
+ # require 'bundler/inline'
4
4
 
5
- gemfile do
6
- source 'https://rubygems.org'
7
- gem 'uringmachine', path: '..'
8
- gem 'benchmark-ips'
9
- gem 'http_parser.rb'
10
- end
5
+ # gemfile do
6
+ # source 'https://rubygems.org'
7
+ # gem 'uringmachine', path: '..'
8
+ # gem 'benchmark-ips'
9
+ # gem 'http_parser.rb'
10
+ # end
11
11
 
12
- require 'benchmark/ips'
12
+ require 'bundler/setup'
13
13
  require 'uringmachine'
14
+ require 'benchmark/ips'
14
15
  require 'http/parser'
15
16
 
16
17
  $machine = UM.new
@@ -19,6 +20,8 @@ HTTP_MSG = "GET /foo/bar HTTP/1.1\r\nServer: foobar.com\r\nFoo: bar\r\n\r\n"
19
20
 
20
21
  $count = 0
21
22
 
23
+ STDOUT.sync = true
24
+
22
25
  def parse_http_parser
23
26
  current_fiber = Fiber.current
24
27
  $count += 1
@@ -45,10 +48,16 @@ def parse_http_parser
45
48
  end
46
49
 
47
50
  $machine.write(w.fileno, HTTP_MSG)
48
- $machine.yield
51
+ ret = $machine.yield
52
+ ret
53
+ rescue Exception => e
54
+ p e: e
55
+ exit
49
56
  ensure
50
- $machine.close(r.fileno)
51
- $machine.close(w.fileno)
57
+ r.close rescue nil
58
+ w.close rescue nil
59
+ # $machine.close(r.fileno) rescue nil
60
+ # $machine.close(w.fileno) rescue nil
52
61
  end
53
62
 
54
63
  require 'stringio'
@@ -100,50 +109,116 @@ def parse_headers(fd)
100
109
  end
101
110
 
102
111
  def parse_http_stringio
103
- current_fiber = Fiber.current
104
- r, w = IO.pipe
112
+ rfd, wfd = UM.pipe
113
+ queue = UM::Queue.new
105
114
 
106
115
  $machine.spin do
107
- headers = parse_headers(r.fileno)
108
- $machine.schedule(current_fiber, headers)
116
+ headers = parse_headers(rfd)
117
+ $machine.push(queue, headers)
109
118
  rescue Exception => e
110
119
  p e
111
120
  puts e.backtrace.join("\n")
112
121
  exit!
113
122
  end
114
123
 
115
- $machine.write(w.fileno, HTTP_MSG)
116
- $machine.yield
124
+ $machine.write(wfd, HTTP_MSG)
125
+ $machine.close(wfd)
126
+ $machine.shift(queue)
117
127
  ensure
118
- $machine.close(r.fileno)
119
- $machine.close(w.fileno)
128
+ ($machine.close(rfd) rescue nil) if rfd
129
+ ($machine.close(wfd) rescue nil) if wfd
130
+ end
131
+
132
+ def stream_parse_headers(fd)
133
+ stream = UM::Stream.new($machine, fd)
134
+
135
+ buf = String.new(capacity: 65536)
136
+ headers = stream_get_request_line(stream, buf)
137
+ return nil if !headers
138
+
139
+ while true
140
+ line = stream.get_line(buf, 0)
141
+ break if line.empty?
142
+
143
+ m = line.match(RE_HEADER_LINE)
144
+ raise "Invalid header" if !m
145
+
146
+ headers[m[1]] = m[2]
147
+ end
148
+
149
+ headers
120
150
  end
121
151
 
122
- # p parse_http_parser
123
- # p parse_http_stringio
124
- # exit
152
+ def stream_get_request_line(stream, buf)
153
+ line = stream.get_line(buf, 0)
125
154
 
126
- GC.disable
155
+ m = line.match(RE_REQUEST_LINE)
156
+ return nil if !m
157
+
158
+ {
159
+ 'method' => m[1].downcase,
160
+ 'path' => m[2],
161
+ 'protocol' => m[3].downcase
162
+ }
163
+ end
164
+
165
+ def parse_http_stream
166
+ rfd, wfd = UM.pipe
167
+ queue = UM::Queue.new
168
+
169
+ $machine.spin do
170
+ headers = stream_parse_headers(rfd)
171
+ $machine.push(queue, headers)
172
+ rescue Exception => e
173
+ p e
174
+ puts e.backtrace.join("\n")
175
+ exit!
176
+ end
177
+
178
+ $machine.write(wfd, HTTP_MSG)
179
+ $machine.shift(queue)
180
+ ensure
181
+ ($machine.close(rfd) rescue nil) if rfd
182
+ ($machine.close(wfd) rescue nil) if wfd
183
+ end
184
+
185
+ def compare_allocs
186
+ GC.disable
187
+ x = 1000
188
+ p(
189
+ alloc_http_parser: alloc_count { x.times { parse_http_parser } },
190
+ alloc_stringio: alloc_count { x.times { parse_http_stringio } },
191
+ alloc_stream: alloc_count { x.times { parse_http_stream } }
192
+ )
193
+ ensure
194
+ GC.enable
195
+ end
196
+
197
+ def object_count
198
+ counts = ObjectSpace.count_objects
199
+ counts[:TOTAL] - counts[:FREE]
200
+ end
127
201
 
128
202
  def alloc_count
129
- count0 = ObjectSpace.count_objects[:TOTAL]
203
+ GC.start
204
+ count0 = object_count
130
205
  yield
131
- count1 = ObjectSpace.count_objects[:TOTAL]
206
+ # GC.start
207
+ count1 = object_count
132
208
  count1 - count0
133
209
  end
134
210
 
135
- X = 100
136
- p(
137
- alloc_http_parser: alloc_count { X.times { parse_http_parser } },
138
- alloc_stringio: alloc_count { X.times { parse_http_stringio } }
139
- )
140
- exit
211
+ def benchmark
212
+ Benchmark.ips do |x|
213
+ x.config(:time => 5, :warmup => 3)
141
214
 
142
- Benchmark.ips do |x|
143
- x.config(:time => 5, :warmup => 3)
215
+ x.report("http_parser") { parse_http_parser }
216
+ x.report("stringio") { parse_http_stringio }
217
+ x.report("stream") { parse_http_stream }
144
218
 
145
- x.report("http_parser") { parse_http_parser }
146
- x.report("homegrown") { parse_http_stringio }
147
-
148
- x.compare!
219
+ x.compare!
220
+ end
149
221
  end
222
+
223
+ compare_allocs
224
+ benchmark
data/ext/um/um.h CHANGED
@@ -270,10 +270,8 @@ VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
270
270
  VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
271
271
  VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
272
272
 
273
- int stream_read_more(struct um_stream *stream);
274
-
275
- VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer);
276
- VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer);
273
+ VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen);
274
+ VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len);
277
275
  VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
278
276
  void resp_encode(struct um_write_buffer *buf, VALUE obj);
279
277
 
data/ext/um/um_stream.c CHANGED
@@ -1,4 +1,5 @@
1
1
  #include "um.h"
2
+ #include <stdlib.h>
2
3
 
3
4
  static inline void stream_check_truncate_buffer(struct um_stream *stream) {
4
5
  if ((stream->pos == stream->len) && (stream->len >= 1 << 12)) {
@@ -40,10 +41,67 @@ int stream_read_more(struct um_stream *stream) {
40
41
  return 1;
41
42
  }
42
43
 
43
- // ensure string can hold at least len bytes
44
+ // ensures given string can hold at least given len bytes (+trailing null)
44
45
  static inline void str_expand(VALUE str, size_t len) {
45
- size_t capa = rb_str_capacity(str);
46
- if (capa < len + 1) rb_str_modify_expand(str, len + 1 - capa);
46
+ rb_str_resize(str, len);
47
+ }
48
+
49
+ static inline void str_copy_bytes(VALUE dest, const char *src, ssize_t len) {
50
+ str_expand(dest, len + 1);
51
+ char *dest_ptr = RSTRING_PTR(dest);
52
+ memcpy(dest_ptr, src, len);
53
+ dest_ptr[len] = 0;
54
+ rb_str_set_len(dest, len);
55
+ }
56
+
57
+ VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen) {
58
+ char *start = RSTRING_PTR(stream->buffer) + stream->pos;
59
+ while (true) {
60
+ ssize_t pending_len = stream->len - stream->pos;
61
+ ssize_t search_len = pending_len;
62
+ ssize_t absmax_len = labs(maxlen);
63
+ int should_limit_len = (absmax_len > 0) && (search_len > maxlen);
64
+ if (should_limit_len) search_len = absmax_len;
65
+
66
+ char * lf_ptr = memchr(start, '\n', search_len);
67
+ if (lf_ptr) {
68
+ ssize_t len = lf_ptr - start;
69
+ if (len && (start[len - 1] == '\r')) len -= 1;
70
+
71
+ stream->pos += lf_ptr - start + 1;
72
+ if (NIL_P(buf)) return rb_utf8_str_new(start, len);
73
+
74
+ str_copy_bytes(buf, start, len);
75
+ return buf;
76
+ }
77
+ else if (should_limit_len && pending_len > search_len)
78
+ // maxlen
79
+ return Qnil;
80
+
81
+ if (!stream_read_more(stream))
82
+ return Qnil;
83
+ else
84
+ // update start ptr (it might have changed after reading)
85
+ start = RSTRING_PTR(stream->buffer) + stream->pos;
86
+ }
87
+ }
88
+
89
+ VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len) {
90
+ size_t abslen = labs(len);
91
+ while (stream->len - stream->pos < abslen)
92
+ if (!stream_read_more(stream)) {
93
+ if (len > 0) return Qnil;
94
+
95
+ abslen = stream->len - stream->pos;
96
+ }
97
+
98
+ char *start = RSTRING_PTR(stream->buffer) + stream->pos;
99
+ stream->pos += abslen;
100
+
101
+ if (NIL_P(buf)) return rb_utf8_str_new(start, abslen);
102
+
103
+ str_copy_bytes(buf, start, len);
104
+ return buf;
47
105
  }
48
106
 
49
107
  VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
@@ -58,14 +116,11 @@ VALUE resp_get_line(struct um_stream *stream, VALUE out_buffer) {
58
116
  VALUE str = rb_str_new(start, len + 1);
59
117
  rb_str_set_len(str, len);
60
118
  RSTRING_PTR(str)[len] = 0;
119
+ RB_GC_GUARD(str);
61
120
  return str;
62
121
  }
63
122
 
64
- str_expand(out_buffer, len + 1);
65
- char *dest_ptr = RSTRING_PTR(out_buffer);
66
- memcpy(dest_ptr, start, len);
67
- dest_ptr[len] = 0; // add null at end
68
- rb_str_set_len(out_buffer, len);
123
+ str_copy_bytes(out_buffer, start, len);
69
124
  return out_buffer;
70
125
  }
71
126
 
@@ -88,11 +143,7 @@ VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
88
143
 
89
144
  if (NIL_P(out_buffer)) return rb_utf8_str_new(start, len);
90
145
 
91
- str_expand(out_buffer, len + 1);
92
- char *dest_ptr = RSTRING_PTR(out_buffer);
93
- memcpy(dest_ptr, start, len);
94
- dest_ptr[len] = 0; // add null at end
95
- rb_str_set_len(out_buffer, len);
146
+ str_copy_bytes(out_buffer, start, len);
96
147
  return out_buffer;
97
148
  }
98
149
 
@@ -37,6 +37,8 @@ static VALUE Stream_allocate(VALUE klass) {
37
37
  VALUE Stream_initialize(VALUE self, VALUE machine, VALUE fd) {
38
38
  struct um_stream *stream = RTYPEDDATA_DATA(self);
39
39
 
40
+ stream->self = self;
41
+
40
42
  stream->machine = RTYPEDDATA_DATA(machine);
41
43
  stream->fd = NUM2ULONG(fd);
42
44
  stream->buffer = rb_utf8_str_new_literal("");
@@ -50,57 +52,18 @@ VALUE Stream_initialize(VALUE self, VALUE machine, VALUE fd) {
50
52
  return self;
51
53
  }
52
54
 
53
- VALUE Stream_get_line(VALUE self) {
54
- struct um_stream *stream = RTYPEDDATA_DATA(self);
55
- if (unlikely(stream->eof)) return Qnil;
56
-
57
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
58
- while (true) {
59
- char * lf_ptr = memchr(start, '\n', stream->len - stream->pos);
60
- if (lf_ptr) {
61
- ulong len = lf_ptr - start;
62
- if (len && (start[len - 1] == '\r')) len -= 1;
63
-
64
- VALUE str = rb_str_new(start, len);
65
- stream->pos += lf_ptr - start + 1;
66
- return str;
67
- }
68
-
69
- if (!stream_read_more(stream)) return Qnil;
70
- }
71
- }
72
-
73
- VALUE Stream_get_string(VALUE self, VALUE len) {
74
- struct um_stream *stream = RTYPEDDATA_DATA(self);
75
- if (unlikely(stream->eof)) return Qnil;
76
-
77
- ulong ulen = NUM2ULONG(len);
78
-
79
- while (stream->len - stream->pos < ulen)
80
- if (!stream_read_more(stream)) return Qnil;
81
-
82
- char *start = RSTRING_PTR(stream->buffer) + stream->pos;
83
- VALUE str = rb_utf8_str_new(start, ulen);
84
- stream->pos += ulen;
85
- return str;
86
- }
87
-
88
- VALUE Stream_resp_get_line(VALUE self) {
55
+ VALUE Stream_get_line(VALUE self, VALUE buf, VALUE limit) {
89
56
  struct um_stream *stream = RTYPEDDATA_DATA(self);
90
57
  if (unlikely(stream->eof)) return Qnil;
91
58
 
92
- VALUE line = resp_get_line(stream, Qnil);
93
- RB_GC_GUARD(line);
94
- return line;
59
+ return stream_get_line(stream, buf, NUM2LONG(limit));
95
60
  }
96
61
 
97
- VALUE Stream_resp_get_string(VALUE self, VALUE len) {
62
+ VALUE Stream_get_string(VALUE self, VALUE buf, VALUE len) {
98
63
  struct um_stream *stream = RTYPEDDATA_DATA(self);
99
64
  if (unlikely(stream->eof)) return Qnil;
100
65
 
101
- VALUE str = resp_get_string(stream, NUM2ULONG(len), Qnil);
102
- RB_GC_GUARD(str);
103
- return str;
66
+ return stream_get_string(stream, buf, NUM2LONG(len));
104
67
  }
105
68
 
106
69
  VALUE Stream_resp_decode(VALUE self) {
@@ -128,11 +91,8 @@ void Init_Stream(void) {
128
91
 
129
92
  rb_define_method(cStream, "initialize", Stream_initialize, 2);
130
93
 
131
- rb_define_method(cStream, "get_line", Stream_get_line, 0);
132
- rb_define_method(cStream, "get_string", Stream_get_string, 1);
133
-
134
- rb_define_method(cStream, "resp_get_line", Stream_resp_get_line, 0);
135
- rb_define_method(cStream, "resp_get_string", Stream_resp_get_string, 1);
94
+ rb_define_method(cStream, "get_line", Stream_get_line, 2);
95
+ rb_define_method(cStream, "get_string", Stream_get_string, 2);
136
96
 
137
97
  rb_define_method(cStream, "resp_decode", Stream_resp_decode, 0);
138
98
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.11'
4
+ VERSION = '0.12'
5
5
  end
data/test/test_stream.rb CHANGED
@@ -15,41 +15,92 @@ class StreamTest < StreamBaseTest
15
15
  machine.write(@wfd, "foo\nbar\r\nbaz")
16
16
  machine.close(@wfd)
17
17
 
18
- assert_equal 'foo', @stream.get_line
19
- assert_equal 'bar', @stream.get_line
20
- assert_nil @stream.get_line
18
+ assert_equal 'foo', @stream.get_line(nil, 0)
19
+ assert_equal 'bar', @stream.get_line(nil, 0)
20
+ assert_nil @stream.get_line(nil, 0)
21
+ end
22
+
23
+ def test_get_line_with_buf
24
+ machine.write(@wfd, "foo\nbar\r\nbaz")
25
+ machine.close(@wfd)
26
+
27
+ buf = +''
28
+ ret = @stream.get_line(buf, 0)
29
+ assert_equal 'foo', buf
30
+ assert_equal ret, buf
31
+
32
+ ret = @stream.get_line(buf, 0)
33
+ assert_equal 'bar', buf
34
+ assert_equal ret, buf
35
+ end
36
+
37
+ def test_get_line_with_positive_maxlen
38
+ machine.write(@wfd, "foobar\r\n")
39
+ machine.close(@wfd)
40
+
41
+ buf = +''
42
+ ret = @stream.get_line(buf, 3)
43
+ assert_nil ret
44
+ assert_equal '', buf
45
+
46
+ # verify that stream pos has not changed
47
+ ret = @stream.get_line(buf, 0)
48
+ assert_equal 'foobar', buf
49
+ assert_equal ret, buf
50
+ end
51
+
52
+ def test_get_line_with_negative_maxlen
53
+ machine.write(@wfd, "foobar\r\n")
54
+ machine.close(@wfd)
55
+
56
+ buf = +''
57
+ ret = @stream.get_line(buf, -3)
58
+ assert_nil ret
59
+ assert_equal '', buf
60
+
61
+ # verify that stream pos has not changed
62
+ ret = @stream.get_line(buf, 0)
63
+ assert_equal 'foobar', buf
64
+ assert_equal ret, buf
21
65
  end
22
66
 
23
67
  def test_get_string
24
68
  machine.write(@wfd, "foobarbazblahzzz")
25
69
  machine.close(@wfd)
26
70
 
27
- assert_equal 'foobar', @stream.get_string(6)
28
- assert_equal 'baz', @stream.get_string(3)
29
- assert_equal 'blah', @stream.get_string(4)
30
- assert_nil @stream.get_string(4)
71
+ assert_equal 'foobar', @stream.get_string(nil, 6)
72
+ assert_equal 'baz', @stream.get_string(nil, 3)
73
+ assert_equal 'blah', @stream.get_string(nil, 4)
74
+ assert_nil @stream.get_string(nil, 4)
31
75
  end
32
- end
33
76
 
34
- class StreamRespTest < StreamBaseTest
35
- def test_trdp_get_line
36
- machine.write(@wfd, "foo\r\nbarbar\r\nbaz\n")
77
+ def test_get_string_with_buf
78
+ machine.write(@wfd, "foobarbazblahzzz")
37
79
  machine.close(@wfd)
38
-
39
- assert_equal 'foo', @stream.resp_get_line
40
- assert_equal 'barbar', @stream.resp_get_line
41
- assert_nil @stream.resp_get_line
80
+
81
+ buf = +''
82
+ ret = @stream.get_string(buf, 6)
83
+ assert_equal 'foobar', buf
84
+ assert_equal ret, buf
85
+
86
+ ret = @stream.get_string(buf, 3)
87
+ assert_equal 'baz', buf
88
+ assert_equal ret, buf
42
89
  end
43
90
 
44
- def test_resp_get_string
45
- machine.write(@wfd, "foo\r\nbarbar\r\nbaz\n")
91
+ def test_get_string_with_negative_len
92
+ machine.write(@wfd, "foobar")
46
93
  machine.close(@wfd)
47
94
 
48
- assert_equal 'foo', @stream.resp_get_string(3)
49
- assert_equal 'barbar', @stream.resp_get_string(6)
50
- assert_nil @stream.resp_get_string(3)
95
+ ret = @stream.get_string(nil, -12)
96
+ assert_equal 'foobar', ret
97
+
98
+ ret = @stream.get_string(nil, -4)
99
+ assert_nil ret
51
100
  end
101
+ end
52
102
 
103
+ class StreamRespTest < StreamBaseTest
53
104
  def test_resp_decode
54
105
  machine.write(@wfd, "+foo bar\r\n")
55
106
  assert_equal "foo bar", @stream.resp_decode
data/test/test_um.rb CHANGED
@@ -271,7 +271,7 @@ class PeriodicallyTest < UMBaseTest
271
271
  rescue Cancel
272
272
  cancel = 1
273
273
  end
274
- machine.snooze
274
+ 2.times { machine.snooze }
275
275
  assert_equal 0, machine.pending_count
276
276
  t1 = monotonic_clock
277
277
  assert_in_range 0.05..0.08, t1 - t0
data/uringmachine.gemspec CHANGED
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency 'rake-compiler', '1.2.9'
24
24
  s.add_development_dependency 'minitest', '5.25.4'
25
25
  s.add_development_dependency 'benchmark-ips', '2.14.0'
26
+ s.add_development_dependency 'http_parser.rb', '0.8.0'
26
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uringmachine
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.11'
4
+ version: '0.12'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -51,6 +51,20 @@ dependencies:
51
51
  - - '='
52
52
  - !ruby/object:Gem::Version
53
53
  version: 2.14.0
54
+ - !ruby/object:Gem::Dependency
55
+ name: http_parser.rb
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '='
59
+ - !ruby/object:Gem::Version
60
+ version: 0.8.0
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '='
66
+ - !ruby/object:Gem::Version
67
+ version: 0.8.0
54
68
  email: sharon@noteflakes.com
55
69
  executables: []
56
70
  extensions: