mmapscanner 0.1a → 0.2
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.
- data/README.md +2 -0
- data/ext/mmapscanner.c +102 -101
- data/spec/mmapscanner_spec.rb +148 -122
- metadata +5 -5
data/README.md
CHANGED
@@ -38,6 +38,8 @@ Usage
|
|
38
38
|
# ファイルの先頭 4096 バイト以降の 1234 バイト分を mmap
|
39
39
|
ms = MmapScanner.new(File.open("filename"), 4096, 1234)
|
40
40
|
|
41
|
+
* MmapScanner.new は文字列も受け付けます。文字列が途中で変更された時の動作は不定です。
|
42
|
+
|
41
43
|
* size, length は mmap(2) したサイズを返します。
|
42
44
|
* to_s は mmap(2) した領域を String で返します。Encoding は常に ASCII-8BIT です。
|
43
45
|
* slice は mmap(2) した領域の一部を新たな MmapScanner オブジェクトで返します。
|
data/ext/mmapscanner.c
CHANGED
@@ -6,11 +6,11 @@
|
|
6
6
|
#include <ruby/io.h>
|
7
7
|
|
8
8
|
static VALUE cMmapScanner;
|
9
|
+
static VALUE cMmap;
|
9
10
|
|
10
11
|
typedef struct {
|
11
12
|
char *ptr;
|
12
13
|
size_t size;
|
13
|
-
size_t pos;
|
14
14
|
} mmap_data_t;
|
15
15
|
|
16
16
|
static void mmap_free(mmap_data_t *data)
|
@@ -20,144 +20,148 @@ static void mmap_free(mmap_data_t *data)
|
|
20
20
|
free(data);
|
21
21
|
}
|
22
22
|
|
23
|
-
static VALUE
|
23
|
+
static VALUE create_mmap_object(int fd, size_t offset, size_t size)
|
24
24
|
{
|
25
|
-
VALUE obj;
|
26
25
|
mmap_data_t *data;
|
27
|
-
|
26
|
+
void *ptr;
|
27
|
+
if ((ptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset)) == MAP_FAILED) {
|
28
|
+
rb_exc_raise(rb_funcall(rb_eSystemCallError, rb_intern("new"), 1, INT2FIX(errno)));
|
29
|
+
}
|
28
30
|
data = xmalloc(sizeof(mmap_data_t));
|
29
|
-
data->ptr =
|
30
|
-
data->size =
|
31
|
-
|
32
|
-
obj = Data_Wrap_Struct(klass, 0, mmap_free, data);
|
33
|
-
rb_iv_set(obj, "parent", Qnil);
|
34
|
-
return obj;
|
31
|
+
data->ptr = ptr;
|
32
|
+
data->size = size;
|
33
|
+
return Data_Wrap_Struct(cMmap, 0, mmap_free, data);
|
35
34
|
}
|
36
35
|
|
37
36
|
static VALUE initialize(int argc, VALUE *argv, VALUE obj)
|
38
37
|
{
|
39
|
-
VALUE src,
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
if (
|
48
|
-
rb_raise(
|
49
|
-
|
50
|
-
if (pos != Qnil && NUM2LL(pos) < 0)
|
51
|
-
rb_raise(rb_eRangeError, "position out of range: %lld", NUM2LL(pos));
|
52
|
-
if (size != Qnil && NUM2LL(size) < 0)
|
53
|
-
rb_raise(rb_eRangeError, "length out of range: %lld", NUM2LL(size));
|
54
|
-
offset = pos == Qnil ? 0 : NUM2SIZET(pos);
|
38
|
+
VALUE src, voffset, vsize;
|
39
|
+
size_t offset, size;
|
40
|
+
size_t src_offset, src_size;
|
41
|
+
VALUE src_data;
|
42
|
+
|
43
|
+
rb_scan_args(argc, argv, "12", &src, &voffset, &vsize);
|
44
|
+
if (voffset != Qnil && NUM2LL(voffset) < 0)
|
45
|
+
rb_raise(rb_eRangeError, "offset out of range: %lld", NUM2LL(voffset));
|
46
|
+
if (vsize != Qnil && NUM2LL(vsize) < 0)
|
47
|
+
rb_raise(rb_eRangeError, "length out of range: %lld", NUM2LL(vsize));
|
48
|
+
offset = voffset == Qnil ? 0 : NUM2SIZET(voffset);
|
55
49
|
if (rb_obj_class(src) == cMmapScanner) {
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
50
|
+
src_offset = NUM2SIZET(rb_iv_get(src, "offset"));
|
51
|
+
src_size = NUM2SIZET(rb_iv_get(src, "size"));
|
52
|
+
src_data = rb_iv_get(src, "data");
|
53
|
+
} else if (TYPE(src) == T_FILE) {
|
54
|
+
int fd;
|
55
|
+
struct stat st;
|
56
|
+
fd = RFILE(src)->fptr->fd;
|
57
|
+
fstat(fd, &st);
|
58
|
+
src_offset = 0;
|
59
|
+
src_size = st.st_size;
|
60
|
+
size = vsize == Qnil ? src_size - offset : NUM2SIZET(vsize);
|
61
|
+
if (size > st.st_size - offset)
|
62
|
+
size = st.st_size - offset;
|
63
|
+
src_data = create_mmap_object(fd, offset, size);
|
64
|
+
} else if (TYPE(src) == T_STRING) {
|
65
|
+
src_offset = 0;
|
66
|
+
src_size = RSTRING_LEN(src);
|
67
|
+
src_data = src;
|
68
|
+
} else {
|
69
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected File/String/MmapScanner)", rb_obj_classname(src));
|
70
70
|
}
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
data->size = sz;
|
71
|
+
if (offset >= src_size)
|
72
|
+
rb_raise(rb_eRangeError, "length out of range: %zu >= %zu", offset, src_size);
|
73
|
+
size = vsize == Qnil ? src_size - offset : NUM2SIZET(vsize);
|
74
|
+
if (size > src_size - offset)
|
75
|
+
size = src_size - offset;
|
76
|
+
rb_iv_set(obj, "offset", SIZET2NUM(src_offset + offset));
|
77
|
+
rb_iv_set(obj, "size", SIZET2NUM(size));
|
78
|
+
rb_iv_set(obj, "data", src_data);
|
79
|
+
rb_iv_set(obj, "pos", INT2NUM(0));
|
80
|
+
return Qnil;
|
82
81
|
}
|
83
82
|
|
84
83
|
static VALUE size(VALUE obj)
|
85
84
|
{
|
86
|
-
|
87
|
-
|
88
|
-
Data_Get_Struct(obj, mmap_data_t, data);
|
89
|
-
return ULL2NUM(data->size);
|
85
|
+
return rb_iv_get(obj, "size");
|
90
86
|
}
|
91
87
|
|
92
88
|
static VALUE to_s(VALUE obj)
|
93
89
|
{
|
94
|
-
|
90
|
+
size_t offset = NUM2SIZET(rb_iv_get(obj, "offset"));
|
91
|
+
size_t size = NUM2SIZET(rb_iv_get(obj, "size"));
|
92
|
+
VALUE data = rb_iv_get(obj, "data");
|
93
|
+
mmap_data_t *mdata;
|
95
94
|
|
96
|
-
|
97
|
-
|
95
|
+
if (TYPE(data) == T_STRING)
|
96
|
+
return rb_str_new(RSTRING_PTR(data)+offset, size);
|
97
|
+
Data_Get_Struct(data, mmap_data_t, mdata);
|
98
|
+
return rb_str_new(mdata->ptr+offset, size);
|
98
99
|
}
|
99
100
|
|
100
101
|
static VALUE slice(VALUE obj, VALUE pos, VALUE len)
|
101
102
|
{
|
102
|
-
size_t offset;
|
103
|
-
size_t length;
|
104
|
-
mmap_data_t *data;
|
105
|
-
|
106
|
-
Data_Get_Struct(obj, mmap_data_t, data);
|
107
103
|
return rb_funcall(cMmapScanner, rb_intern("new"), 3, obj, pos, len);
|
108
104
|
}
|
109
105
|
|
110
106
|
static VALUE inspect(VALUE obj)
|
111
107
|
{
|
112
|
-
rb_str_new2("#<MmapScanner>");
|
108
|
+
return rb_str_new2("#<MmapScanner>");
|
113
109
|
}
|
114
110
|
|
115
111
|
static VALUE pos(VALUE obj)
|
116
112
|
{
|
117
|
-
|
118
|
-
|
119
|
-
Data_Get_Struct(obj, mmap_data_t, data);
|
120
|
-
return ULL2NUM(data->pos);
|
113
|
+
return rb_iv_get(obj, "pos");
|
121
114
|
}
|
122
115
|
|
123
116
|
static VALUE set_pos(VALUE obj, VALUE pos)
|
124
117
|
{
|
125
|
-
|
126
|
-
size_t p;
|
118
|
+
size_t p, size;
|
127
119
|
|
128
120
|
if (NUM2LL(pos) < 0)
|
129
121
|
rb_raise(rb_eRangeError, "out of range: %lld", NUM2LL(pos));
|
130
|
-
Data_Get_Struct(obj, mmap_data_t, data);
|
131
122
|
p = NUM2SIZET(pos);
|
132
|
-
|
133
|
-
|
134
|
-
|
123
|
+
size = NUM2SIZET(rb_iv_get(obj, "size"));
|
124
|
+
if (p > size)
|
125
|
+
rb_raise(rb_eRangeError, "out of range: %zu > %zu", p, size);
|
126
|
+
rb_iv_set(obj, "pos", pos);
|
135
127
|
return pos;
|
136
128
|
}
|
137
129
|
|
138
130
|
static VALUE scan_sub(VALUE obj, VALUE re, int forward)
|
139
131
|
{
|
140
132
|
regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
|
141
|
-
mmap_data_t *data;
|
142
133
|
regex_t *reg;
|
143
134
|
int tmpreg;
|
144
135
|
int result;
|
145
136
|
struct re_registers regs;
|
146
137
|
size_t old_pos, matched_len;
|
138
|
+
char *ptr;
|
139
|
+
size_t pos, size;
|
140
|
+
VALUE data;
|
141
|
+
mmap_data_t *mdata;
|
147
142
|
|
148
143
|
Check_Type(re, T_REGEXP);
|
149
|
-
|
150
|
-
|
144
|
+
pos = NUM2SIZET(rb_iv_get(obj, "pos"));
|
145
|
+
size = NUM2SIZET(rb_iv_get(obj, "size"));
|
146
|
+
if (pos >= size)
|
151
147
|
return Qnil;
|
148
|
+
data = rb_iv_get(obj, "data");
|
149
|
+
if (TYPE(data) == T_STRING)
|
150
|
+
ptr = RSTRING_PTR(data);
|
151
|
+
else {
|
152
|
+
Data_Get_Struct(data, mmap_data_t, mdata);
|
153
|
+
ptr = mdata->ptr;
|
154
|
+
}
|
155
|
+
ptr += NUM2SIZET(rb_iv_get(obj, "offset"));
|
152
156
|
|
153
157
|
reg = rb_reg_prepare_re(re, rb_str_new("", 0));
|
154
158
|
tmpreg = reg != RREGEXP(re)->ptr;
|
155
159
|
if (!tmpreg) RREGEXP(re)->usecnt++;
|
156
160
|
|
157
161
|
onig_region_init(®s);
|
158
|
-
result = onig_match(reg, (UChar* )(
|
159
|
-
(UChar* )(
|
160
|
-
(UChar* )(
|
162
|
+
result = onig_match(reg, (UChar* )(ptr+pos),
|
163
|
+
(UChar* )(ptr+size),
|
164
|
+
(UChar* )(ptr+pos),
|
161
165
|
®s, ONIG_OPTION_NONE);
|
162
166
|
if (!tmpreg) RREGEXP(re)->usecnt--;
|
163
167
|
if (tmpreg) {
|
@@ -170,10 +174,12 @@ static VALUE scan_sub(VALUE obj, VALUE re, int forward)
|
|
170
174
|
}
|
171
175
|
if (result < 0)
|
172
176
|
return Qnil;
|
173
|
-
old_pos =
|
177
|
+
old_pos = pos;
|
174
178
|
matched_len = regs.end[0];
|
175
|
-
if (forward)
|
176
|
-
|
179
|
+
if (forward) {
|
180
|
+
pos += matched_len;
|
181
|
+
rb_iv_set(obj, "pos", SIZET2NUM(pos));
|
182
|
+
}
|
177
183
|
return rb_funcall(cMmapScanner, rb_intern("new"), 3, obj, ULL2NUM(old_pos), ULL2NUM(matched_len));
|
178
184
|
}
|
179
185
|
|
@@ -189,52 +195,45 @@ static VALUE check(VALUE obj, VALUE re)
|
|
189
195
|
|
190
196
|
static VALUE skip(VALUE obj, VALUE re)
|
191
197
|
{
|
192
|
-
mmap_data_t *data;
|
193
198
|
VALUE ret = scan_sub(obj, re, 1);
|
194
199
|
if (ret == Qnil)
|
195
200
|
return ret;
|
196
|
-
|
197
|
-
return ULL2NUM(data->size);
|
201
|
+
return rb_iv_get(ret, "size");
|
198
202
|
}
|
199
203
|
|
200
204
|
static VALUE match_p(VALUE obj, VALUE re)
|
201
205
|
{
|
202
|
-
mmap_data_t *data;
|
203
206
|
VALUE ret = scan_sub(obj, re, 0);
|
204
207
|
if (ret == Qnil)
|
205
208
|
return ret;
|
206
|
-
|
207
|
-
return ULL2NUM(data->size);
|
209
|
+
return rb_iv_get(ret, "size");
|
208
210
|
}
|
209
211
|
|
210
212
|
static VALUE peek(VALUE obj, VALUE size)
|
211
213
|
{
|
212
214
|
size_t sz = NUM2SIZET(size);
|
213
|
-
|
214
|
-
|
215
|
-
if (sz >
|
216
|
-
sz =
|
217
|
-
return rb_funcall(cMmapScanner, rb_intern("new"), 3, obj, SIZET2NUM(
|
215
|
+
size_t data_pos = NUM2SIZET(rb_iv_get(obj, "pos"));
|
216
|
+
size_t data_size = NUM2SIZET(rb_iv_get(obj, "size"));
|
217
|
+
if (sz > data_size - data_pos)
|
218
|
+
sz = data_size - data_pos;
|
219
|
+
return rb_funcall(cMmapScanner, rb_intern("new"), 3, obj, SIZET2NUM(data_pos), SIZET2NUM(sz));
|
218
220
|
}
|
219
221
|
|
220
222
|
static VALUE eos_p(VALUE obj)
|
221
223
|
{
|
222
|
-
|
223
|
-
|
224
|
-
return
|
224
|
+
size_t data_pos = NUM2SIZET(rb_iv_get(obj, "pos"));
|
225
|
+
size_t data_size = NUM2SIZET(rb_iv_get(obj, "size"));
|
226
|
+
return data_pos >= data_size ? Qtrue : Qfalse;
|
225
227
|
}
|
226
228
|
|
227
229
|
static VALUE rest(VALUE obj)
|
228
230
|
{
|
229
|
-
|
230
|
-
Data_Get_Struct(obj, mmap_data_t, data);
|
231
|
-
return rb_funcall(cMmapScanner, rb_intern("new"), 2, obj, SIZET2NUM(data->pos));
|
231
|
+
return rb_funcall(cMmapScanner, rb_intern("new"), 2, obj, rb_iv_get(obj, "pos"));
|
232
232
|
}
|
233
233
|
|
234
234
|
void Init_mmapscanner(void)
|
235
235
|
{
|
236
236
|
cMmapScanner = rb_define_class("MmapScanner", rb_cObject);
|
237
|
-
rb_define_alloc_func(cMmapScanner, allocate);
|
238
237
|
rb_define_method(cMmapScanner, "initialize", initialize, -1);
|
239
238
|
rb_define_method(cMmapScanner, "size", size, 0);
|
240
239
|
rb_define_method(cMmapScanner, "length", size, 0);
|
@@ -251,4 +250,6 @@ void Init_mmapscanner(void)
|
|
251
250
|
rb_define_method(cMmapScanner, "peek", peek, 1);
|
252
251
|
rb_define_method(cMmapScanner, "eos?", eos_p, 0);
|
253
252
|
rb_define_method(cMmapScanner, "rest", rest, 0);
|
253
|
+
|
254
|
+
cMmap = rb_define_class_under(cMmapScanner, "Mmap", rb_cObject);
|
254
255
|
}
|
data/spec/mmapscanner_spec.rb
CHANGED
@@ -4,138 +4,164 @@ $LOAD_PATH.unshift "#{File.dirname __FILE__}/../ext"
|
|
4
4
|
require 'mmapscanner'
|
5
5
|
|
6
6
|
describe MmapScanner do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@file = File.open(tmpf.path)
|
11
|
-
end
|
12
|
-
subject{MmapScanner.new(@file)}
|
13
|
-
it '#size returns size of file' do
|
14
|
-
subject.size.should == 10000
|
15
|
-
end
|
16
|
-
it '#to_s returns contents of file' do
|
17
|
-
subject.to_s.should == '0123456789'*1000
|
18
|
-
end
|
19
|
-
describe '#slice' do
|
20
|
-
it 'returns MmapScanner' do
|
21
|
-
subject.slice(10, 100).should be_instance_of MmapScanner
|
22
|
-
end
|
23
|
-
end
|
24
|
-
it '#inspect returns "#<MmapScanner>"' do
|
25
|
-
subject.inspect.should == '#<MmapScanner>'
|
26
|
-
end
|
27
|
-
it '#pos returns current position' do
|
28
|
-
subject.pos.should == 0
|
29
|
-
subject.scan(/.../)
|
30
|
-
subject.pos.should == 3
|
31
|
-
end
|
32
|
-
describe '#pos=' do
|
33
|
-
it 'change current position' do
|
34
|
-
subject.pos = 100
|
35
|
-
subject.pos.should == 100
|
36
|
-
end
|
37
|
-
it 'raise error when negative value' do
|
38
|
-
expect{subject.pos = -1}.to raise_error(RangeError, 'out of range: -1')
|
39
|
-
end
|
40
|
-
it 'raise error when over size' do
|
41
|
-
expect{subject.pos = 10001}.to raise_error(RangeError, 'out of range: 10001 > 10000')
|
42
|
-
expect{subject.pos = 20000}.to raise_error(RangeError, 'out of range: 20000 > 10000')
|
7
|
+
shared_examples_for 'MmapScanner' do
|
8
|
+
it '#size returns size of file' do
|
9
|
+
subject.size.should == 10000
|
43
10
|
end
|
44
|
-
|
45
|
-
|
46
|
-
it 'returns matched data as MmapScanner' do
|
47
|
-
ret = subject.scan(/\d{10}/)
|
48
|
-
ret.class.should == MmapScanner
|
49
|
-
ret.to_s.should == '0123456789'
|
50
|
-
end
|
51
|
-
it 'returns nil if not matched' do
|
52
|
-
subject.scan(/123/).should be_nil
|
11
|
+
it '#to_s returns contents of file' do
|
12
|
+
subject.to_s.should == '0123456789'*1000
|
53
13
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
14
|
+
describe '#slice' do
|
15
|
+
it 'returns MmapScanner' do
|
16
|
+
subject.slice(10, 100).should be_instance_of MmapScanner
|
17
|
+
end
|
57
18
|
end
|
58
|
-
|
59
|
-
|
60
|
-
it 'returns matched data as MmapScanner' do
|
61
|
-
ret = subject.check(/\d{10}/)
|
62
|
-
ret.class.should == MmapScanner
|
63
|
-
ret.to_s.should == '0123456789'
|
19
|
+
it '#inspect returns "#<MmapScanner>"' do
|
20
|
+
subject.inspect.should == '#<MmapScanner>'
|
64
21
|
end
|
65
|
-
it 'returns
|
66
|
-
subject.check(/123/).should be_nil
|
67
|
-
end
|
68
|
-
it 'do not forward current position' do
|
69
|
-
ret = subject.check(/\d{10}/)
|
22
|
+
it '#pos returns current position' do
|
70
23
|
subject.pos.should == 0
|
24
|
+
subject.scan(/.../)
|
25
|
+
subject.pos.should == 3
|
26
|
+
end
|
27
|
+
describe '#pos=' do
|
28
|
+
it 'change current position' do
|
29
|
+
subject.pos = 100
|
30
|
+
subject.pos.should == 100
|
31
|
+
end
|
32
|
+
it 'raise error when negative value' do
|
33
|
+
expect{subject.pos = -1}.to raise_error(RangeError, 'out of range: -1')
|
34
|
+
end
|
35
|
+
it 'raise error when over size' do
|
36
|
+
expect{subject.pos = 10001}.to raise_error(RangeError, 'out of range: 10001 > 10000')
|
37
|
+
expect{subject.pos = 20000}.to raise_error(RangeError, 'out of range: 20000 > 10000')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
describe '#scan' do
|
41
|
+
it 'returns matched data as MmapScanner' do
|
42
|
+
ret = subject.scan(/\d{10}/)
|
43
|
+
ret.class.should == MmapScanner
|
44
|
+
ret.to_s.should == '0123456789'
|
45
|
+
end
|
46
|
+
it 'returns nil if not matched' do
|
47
|
+
subject.scan(/123/).should be_nil
|
48
|
+
end
|
49
|
+
it 'forward current position' do
|
50
|
+
subject.scan(/\d{10}/)
|
51
|
+
subject.pos.should == 10
|
52
|
+
end
|
53
|
+
end
|
54
|
+
describe '#check' do
|
55
|
+
it 'returns matched data as MmapScanner' do
|
56
|
+
ret = subject.check(/\d{10}/)
|
57
|
+
ret.class.should == MmapScanner
|
58
|
+
ret.to_s.should == '0123456789'
|
59
|
+
end
|
60
|
+
it 'returns nil if not matched' do
|
61
|
+
subject.check(/123/).should be_nil
|
62
|
+
end
|
63
|
+
it 'do not forward current position' do
|
64
|
+
ret = subject.check(/\d{10}/)
|
65
|
+
subject.pos.should == 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
describe '#skip' do
|
69
|
+
it 'returns length of matched data' do
|
70
|
+
subject.skip(/\d{10}/).should == 10
|
71
|
+
end
|
72
|
+
it 'returns nil if not matched' do
|
73
|
+
subject.skip(/123/).should be_nil
|
74
|
+
end
|
75
|
+
it 'forward current position' do
|
76
|
+
subject.skip(/\d{10}/)
|
77
|
+
subject.pos.should == 10
|
78
|
+
end
|
79
|
+
end
|
80
|
+
describe '#match?' do
|
81
|
+
it 'returns length of matched data' do
|
82
|
+
subject.match?(/\d{10}/).should == 10
|
83
|
+
end
|
84
|
+
it 'returns nil if not matched' do
|
85
|
+
subject.match?(/123/).should be_nil
|
86
|
+
end
|
87
|
+
it 'do not forward current position' do
|
88
|
+
subject.match?(/\d{10}/)
|
89
|
+
subject.pos.should == 0
|
90
|
+
end
|
91
|
+
end
|
92
|
+
describe '#peek' do
|
93
|
+
it 'returns MmapScanner' do
|
94
|
+
subject.peek(10).should be_instance_of MmapScanner
|
95
|
+
end
|
96
|
+
it 'do not forward current position' do
|
97
|
+
subject.peek(10)
|
98
|
+
subject.pos.should == 0
|
99
|
+
end
|
100
|
+
end
|
101
|
+
describe '#eos?' do
|
102
|
+
it 'returns true if eos' do
|
103
|
+
subject.pos = 10000
|
104
|
+
subject.eos?.should == true
|
105
|
+
end
|
106
|
+
it 'returns false if not eos' do
|
107
|
+
subject.pos = 9999
|
108
|
+
subject.eos?.should == false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
describe '#rest' do
|
112
|
+
it 'returns rest data as MmapScanner' do
|
113
|
+
subject.pos = 9997
|
114
|
+
ret = subject.rest
|
115
|
+
ret.should be_instance_of MmapScanner
|
116
|
+
ret.to_s.should == '789'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
describe '.new with position' do
|
120
|
+
it '#size is length of rest data' do
|
121
|
+
MmapScanner.new(src, 4096).size.should == src.size-4096
|
122
|
+
end
|
123
|
+
end
|
124
|
+
describe '.new with length' do
|
125
|
+
subject{MmapScanner.new(src, nil, 10)}
|
126
|
+
it '#size is specified size' do
|
127
|
+
subject.size.should == 10
|
128
|
+
end
|
129
|
+
it 'raise error when negative' do
|
130
|
+
expect{MmapScanner.new(src, nil, -1)}.to raise_error(RangeError, 'length out of range: -1')
|
131
|
+
end
|
71
132
|
end
|
72
133
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
it 'forward current position' do
|
81
|
-
subject.skip(/\d{10}/)
|
82
|
-
subject.pos.should == 10
|
83
|
-
end
|
84
|
-
end
|
85
|
-
describe '#match?' do
|
86
|
-
it 'returns length of matched data' do
|
87
|
-
subject.match?(/\d{10}/).should == 10
|
88
|
-
end
|
89
|
-
it 'returns nil if not matched' do
|
90
|
-
subject.match?(/123/).should be_nil
|
91
|
-
end
|
92
|
-
it 'do not forward current position' do
|
93
|
-
subject.match?(/\d{10}/)
|
94
|
-
subject.pos.should == 0
|
95
|
-
end
|
96
|
-
end
|
97
|
-
describe '#peek' do
|
98
|
-
it 'returns MmapScanner' do
|
99
|
-
subject.peek(10).should be_instance_of MmapScanner
|
100
|
-
end
|
101
|
-
it 'do not forward current position' do
|
102
|
-
subject.peek(10)
|
103
|
-
subject.pos.should == 0
|
104
|
-
end
|
105
|
-
end
|
106
|
-
describe '#eos?' do
|
107
|
-
it 'returns true if eos' do
|
108
|
-
subject.pos = 10000
|
109
|
-
subject.eos?.should == true
|
110
|
-
end
|
111
|
-
it 'returns false if not eos' do
|
112
|
-
subject.pos = 9999
|
113
|
-
subject.eos?.should == false
|
134
|
+
|
135
|
+
context 'with File' do
|
136
|
+
before do
|
137
|
+
tmpf = Tempfile.new 'mmapscanner'
|
138
|
+
tmpf.write '0123456789'*1000
|
139
|
+
@file = File.open(tmpf.path)
|
114
140
|
end
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
141
|
+
let(:src){@file}
|
142
|
+
subject{MmapScanner.new(src)}
|
143
|
+
it_should_behave_like 'MmapScanner'
|
144
|
+
describe '.new with position' do
|
145
|
+
it 'raise error when invalid position' do
|
146
|
+
expect{MmapScanner.new(@file, 4095)}.to raise_error(Errno::EINVAL)
|
147
|
+
end
|
122
148
|
end
|
123
149
|
end
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
expect{MmapScanner.new(@file, 4095)}.to raise_error(Errno::EINVAL)
|
130
|
-
end
|
150
|
+
|
151
|
+
context 'with String' do
|
152
|
+
let(:src){'0123456789'*1020}
|
153
|
+
subject{MmapScanner.new(src, 100, 10000)}
|
154
|
+
it_should_behave_like 'MmapScanner'
|
131
155
|
end
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
156
|
+
|
157
|
+
context 'with MmapScanner' do
|
158
|
+
before do
|
159
|
+
tmpf = Tempfile.new 'mmapscanner'
|
160
|
+
tmpf.write '0123456789'*1020
|
161
|
+
@file = File.open(tmpf.path)
|
162
|
+
end
|
163
|
+
let(:src){MmapScanner.new(@file)}
|
164
|
+
subject{MmapScanner.new(src, 100, 10000)}
|
165
|
+
it_should_behave_like 'MmapScanner'
|
140
166
|
end
|
141
167
|
end
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mmapscanner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.
|
4
|
+
prerelease:
|
5
|
+
version: "0.2"
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- TOMITA Masahiro
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-02
|
13
|
+
date: 2011-03-02 00:00:00 +09:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -45,9 +45,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
45
45
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
46
|
none: false
|
47
47
|
requirements:
|
48
|
-
- - "
|
48
|
+
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version:
|
50
|
+
version: "0"
|
51
51
|
requirements: []
|
52
52
|
|
53
53
|
rubyforge_project:
|