bychar 2.0.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +2 -0
- data/Gemfile +3 -7
- data/README.md +60 -0
- data/bychar.gemspec +17 -13
- data/lib/bychar.rb +20 -6
- data/lib/impls/reader_bare.rb +2 -4
- data/lib/impls/reader_iobuf.rb +2 -2
- data/lib/impls/reader_strbuf.rb +3 -2
- data/test/test_ioreader.rb +12 -14
- data/test/test_reader.rb +6 -18
- data/test/test_strreader.rb +8 -19
- data/test/test_z_bench.rb +3 -3
- metadata +57 -60
- data/README.rdoc +0 -63
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4955440b9eff7331dd966ba6a381b032b24e8f1a
|
4
|
+
data.tar.gz: 345f1b882ce2aef85acf391dd55d8a8aa8db2a33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 96879e770df2a03d227834db03c6c64ec7b501bff447c01e25ccd9ecfead0be28408ef5d0f92b6eacfa3380a16b72c8e8d9ef3142e277601b5ecbe2f26462f89
|
7
|
+
data.tar.gz: 89a78a2e211f15cc54a0fe8e21b4ef21338ece9662d16aa27ba5d228f581cdc84a576f2e35cd9151261cbc0ffe889cb81d00df723ba29f842c835e9b29b65c10
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
|
-
# Add dependencies required to use your gem here.
|
3
|
-
# Example:
|
4
|
-
# gem "activesupport", ">= 2.3.5"
|
5
2
|
|
6
|
-
# Add dependencies to develop your gem here.
|
7
|
-
# Include everything needed to run rake, tests, features, etc.
|
8
3
|
group :development do
|
4
|
+
gem "rake"
|
9
5
|
gem "rdoc", "~> 3.12"
|
10
|
-
gem
|
11
|
-
gem "jeweler",
|
6
|
+
gem 'test-unit'
|
7
|
+
gem "jeweler", '1.8.7'
|
12
8
|
gem "flexmock", "~>0.8"
|
13
9
|
end
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# bychar
|
2
|
+
|
3
|
+
A simple IO wrapper for libraries that tend to read the IO in the following way:
|
4
|
+
|
5
|
+
* Only forward
|
6
|
+
* By a single character
|
7
|
+
* Without skipping
|
8
|
+
|
9
|
+
This is how most of recursive-descent parsers and stateful parsers would work. However,
|
10
|
+
reading a simple IO object byte by byte in Ruby is very slow. Orders slower in fact.
|
11
|
+
Therefore, this gem creates a simple wrapper that you can get like this:
|
12
|
+
|
13
|
+
wrapper = Bychar.wrap(io)
|
14
|
+
while c = wrapper.read_one_char
|
15
|
+
# Do your thang
|
16
|
+
end
|
17
|
+
|
18
|
+
The wrapper will cache some bytes from the passed IO object which will make parsing
|
19
|
+
faster when you advance your parser char by char.
|
20
|
+
|
21
|
+
## Performance
|
22
|
+
|
23
|
+
I told you reading char by char is not the best strategy. On Ruby 1.9:
|
24
|
+
|
25
|
+
Bare IO using read(1): 3.400000 1.900000 5.300000 ( 5.300798)
|
26
|
+
Bychar using StringIO: 1.790000 0.010000 1.800000 ( 1.795277)
|
27
|
+
Bychar using a String buffer: 1.760000 0.000000 1.760000 ( 1.760440)
|
28
|
+
Platform-picked Bychar.wrap(io) Bychar::ReaderStrbuf: 1.770000 0.010000 1.780000 ( 1.776339)
|
29
|
+
|
30
|
+
while on Ruby 1.8 it is kinda sad:
|
31
|
+
|
32
|
+
Bare IO using read(1): 2.380000 0.000000 2.380000 ( 2.393260)
|
33
|
+
Bychar using StringIO: 2.270000 0.010000 2.280000 ( 2.275631)
|
34
|
+
Bychar using a String buffer: 2.920000 0.000000 2.920000 ( 2.924574)
|
35
|
+
Platform-picked Bychar.wrap(io) Bychar::ReaderBare: 2.380000 0.010000 2.390000 ( 2.384414)
|
36
|
+
|
37
|
+
And on JRuby it's different still:
|
38
|
+
|
39
|
+
Bare IO using read(1): 1.610000 0.040000 1.650000 ( 1.180000)
|
40
|
+
Bychar using StringIO: 0.730000 0.020000 0.750000 ( 0.603000)
|
41
|
+
Bychar using a String buffer: 1.040000 0.040000 1.080000 ( 0.790000)
|
42
|
+
Platform-picked Bychar.wrap(io) Bychar::ReaderIOBuf: 0.560000 0.030000 0.590000 ( 0.546000)
|
43
|
+
|
44
|
+
As you can see, Bychar will do some work to pick an implementation that makes sense for your Ruby platform.
|
45
|
+
|
46
|
+
## Contributing to bychar
|
47
|
+
|
48
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
49
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
50
|
+
* Fork the project.
|
51
|
+
* Start a feature/bugfix branch.
|
52
|
+
* Commit and push until you are happy with your contribution.
|
53
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
54
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
55
|
+
|
56
|
+
## Copyright
|
57
|
+
|
58
|
+
Copyright (c) 2013 Julik Tarkhanov. See LICENSE.txt for
|
59
|
+
further details.
|
60
|
+
|
data/bychar.gemspec
CHANGED
@@ -2,26 +2,28 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: bychar 3.0.0 ruby lib
|
5
6
|
|
6
7
|
Gem::Specification.new do |s|
|
7
8
|
s.name = "bychar"
|
8
|
-
s.version = "
|
9
|
+
s.version = "3.0.0"
|
9
10
|
|
10
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
11
13
|
s.authors = ["Julik Tarkhanov"]
|
12
|
-
s.date = "
|
14
|
+
s.date = "2014-12-10"
|
13
15
|
s.description = " Helps parsing IO char by char "
|
14
16
|
s.email = "me@julik.nl"
|
15
17
|
s.extra_rdoc_files = [
|
16
18
|
"LICENSE.txt",
|
17
|
-
"README.
|
19
|
+
"README.md"
|
18
20
|
]
|
19
21
|
s.files = [
|
20
22
|
".document",
|
21
23
|
".travis.yml",
|
22
24
|
"Gemfile",
|
23
25
|
"LICENSE.txt",
|
24
|
-
"README.
|
26
|
+
"README.md",
|
25
27
|
"Rakefile",
|
26
28
|
"bychar.gemspec",
|
27
29
|
"lib/bychar.rb",
|
@@ -37,28 +39,30 @@ Gem::Specification.new do |s|
|
|
37
39
|
]
|
38
40
|
s.homepage = "http://github.com/julik/bychar"
|
39
41
|
s.licenses = ["MIT"]
|
40
|
-
s.
|
41
|
-
s.rubygems_version = "1.8.24"
|
42
|
+
s.rubygems_version = "2.2.2"
|
42
43
|
s.summary = "Helps parsing IO char by char"
|
43
44
|
|
44
45
|
if s.respond_to? :specification_version then
|
45
|
-
s.specification_version =
|
46
|
+
s.specification_version = 4
|
46
47
|
|
47
48
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
48
50
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
49
|
-
s.add_development_dependency(%q<
|
50
|
-
s.add_development_dependency(%q<jeweler>, ["
|
51
|
+
s.add_development_dependency(%q<test-unit>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<jeweler>, ["= 1.8.7"])
|
51
53
|
s.add_development_dependency(%q<flexmock>, ["~> 0.8"])
|
52
54
|
else
|
55
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
53
56
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
54
|
-
s.add_dependency(%q<
|
55
|
-
s.add_dependency(%q<jeweler>, ["
|
57
|
+
s.add_dependency(%q<test-unit>, [">= 0"])
|
58
|
+
s.add_dependency(%q<jeweler>, ["= 1.8.7"])
|
56
59
|
s.add_dependency(%q<flexmock>, ["~> 0.8"])
|
57
60
|
end
|
58
61
|
else
|
62
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
59
63
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
60
|
-
s.add_dependency(%q<
|
61
|
-
s.add_dependency(%q<jeweler>, ["
|
64
|
+
s.add_dependency(%q<test-unit>, [">= 0"])
|
65
|
+
s.add_dependency(%q<jeweler>, ["= 1.8.7"])
|
62
66
|
s.add_dependency(%q<flexmock>, ["~> 0.8"])
|
63
67
|
end
|
64
68
|
end
|
data/lib/bychar.rb
CHANGED
@@ -6,22 +6,36 @@ require File.dirname(__FILE__) + "/impls/reader_strbuf"
|
|
6
6
|
require File.dirname(__FILE__) + "/impls/reader_bare"
|
7
7
|
|
8
8
|
module Bychar
|
9
|
-
VERSION = '
|
9
|
+
VERSION = '3.0.0'
|
10
10
|
DEFAULT_BUFFER_SIZE = 512 * 1024
|
11
11
|
|
12
|
-
#
|
13
|
-
class
|
12
|
+
# The basic wrapper that you get from wrap()
|
13
|
+
class Wrapper
|
14
|
+
def initialize(io_to_wrap)
|
15
|
+
@io = io_to_wrap
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_one_char
|
19
|
+
@io.read_one_char
|
20
|
+
end
|
21
|
+
|
22
|
+
def each_char
|
23
|
+
while char = read_one_char do
|
24
|
+
yield char
|
25
|
+
end
|
26
|
+
end
|
14
27
|
end
|
15
28
|
|
16
|
-
# Returns a reader object that responds to read_one_char
|
17
|
-
# and
|
29
|
+
# Returns a reader object that responds to read_one_char
|
30
|
+
# and can be passed on to the actual parsers
|
18
31
|
def self.wrap(io)
|
19
|
-
if RUBY_PLATFORM == 'java'
|
32
|
+
reader = if RUBY_PLATFORM == 'java'
|
20
33
|
ReaderIOBuf.new(io)
|
21
34
|
elsif RUBY_VERSION < '1.9'
|
22
35
|
ReaderBare.new(io)
|
23
36
|
else
|
24
37
|
ReaderStrbuf.new(io)
|
25
38
|
end
|
39
|
+
Wrapper.new(reader)
|
26
40
|
end
|
27
41
|
end
|
data/lib/impls/reader_bare.rb
CHANGED
data/lib/impls/reader_iobuf.rb
CHANGED
@@ -10,9 +10,9 @@ module Bychar
|
|
10
10
|
# Since you parse char by char, you will be tempted to do it in a tight loop
|
11
11
|
# and to call eof? on each iteration. Don't. Instead. allow it to raise and do not check.
|
12
12
|
# This takes the profile time down from 36 seconds to 30 seconds for a large file.
|
13
|
-
def read_one_char
|
13
|
+
def read_one_char
|
14
14
|
cache if @buf.eos?
|
15
|
-
|
15
|
+
return nil if @buf.eos?
|
16
16
|
|
17
17
|
@buf.getch
|
18
18
|
end
|
data/lib/impls/reader_strbuf.rb
CHANGED
@@ -14,10 +14,11 @@ module Bychar
|
|
14
14
|
# Will transparently read one byte off the contained IO, maintaining the internal cache.
|
15
15
|
# If the cache has been depleted it will read a big chunk from the IO and cache it and then
|
16
16
|
# return the byte
|
17
|
-
def read_one_char
|
17
|
+
def read_one_char
|
18
18
|
if @pos_in_buf > @maximum_pos
|
19
19
|
@buf = @io.read(DEFAULT_BUFFER_SIZE)
|
20
|
-
|
20
|
+
|
21
|
+
return nil if @buf.nil?
|
21
22
|
|
22
23
|
@maximum_pos = @buf.length - 1
|
23
24
|
@pos_in_buf = 0
|
data/test/test_ioreader.rb
CHANGED
@@ -6,55 +6,53 @@ class TestBychar < Test::Unit::TestCase
|
|
6
6
|
s = StringIO.new("This is a string")
|
7
7
|
|
8
8
|
reader = Bychar::ReaderIOBuf.new(s)
|
9
|
-
assert_equal "T", reader.read_one_char
|
10
|
-
assert_equal "h", reader.read_one_char
|
9
|
+
assert_equal "T", reader.read_one_char
|
10
|
+
assert_equal "h", reader.read_one_char
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_reads_set_buffer_size
|
14
14
|
s = StringIO.new("abcd")
|
15
15
|
flexmock(s).should_receive(:read).with(4).once.and_return("abcd")
|
16
16
|
reader = Bychar::ReaderIOBuf.new(s, 4)
|
17
|
-
reader.read_one_char
|
17
|
+
reader.read_one_char
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_reads_in_64kb_chunks_by_default
|
21
21
|
s = StringIO.new("abcd")
|
22
22
|
flexmock(s).should_receive(:read).with(Bychar::DEFAULT_BUFFER_SIZE).once.and_return("abcd")
|
23
23
|
reader = Bychar::ReaderIOBuf.new(s)
|
24
|
-
reader.read_one_char
|
24
|
+
reader.read_one_char
|
25
25
|
end
|
26
26
|
|
27
27
|
def test_eof_with_empty
|
28
28
|
s = StringIO.new
|
29
29
|
reader = Bychar::ReaderIOBuf.new(s)
|
30
|
-
|
30
|
+
assert_nil reader.read_one_char
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_eof_with_io_at_eof
|
34
34
|
s = StringIO.new("foo")
|
35
35
|
s.read(3)
|
36
36
|
reader = Bychar::ReaderIOBuf.new(s)
|
37
|
-
|
37
|
+
assert_nil reader.read_one_char
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_eof_with_string_to_size
|
41
41
|
s = "Foobarboo another"
|
42
42
|
s = StringIO.new(s)
|
43
43
|
reader = Bychar::ReaderIOBuf.new(s, 1)
|
44
|
-
s.length.times { reader.read_one_char
|
45
|
-
|
44
|
+
s.length.times { reader.read_one_char }
|
45
|
+
assert_nil reader.read_one_char
|
46
46
|
end
|
47
47
|
|
48
|
-
def
|
48
|
+
def test_read_one_byte_and_nil_at_eof
|
49
49
|
str = "Frobobo"
|
50
50
|
|
51
51
|
bytes = []
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
s = Bychar::ReaderIOBuf.new(StringIO.new(str))
|
53
|
+
while c = s.read_one_char do
|
54
|
+
bytes << c
|
55
55
|
end
|
56
|
-
|
57
56
|
assert_equal %w( F r o b o b o ), bytes
|
58
57
|
end
|
59
|
-
|
60
58
|
end
|
data/test/test_reader.rb
CHANGED
@@ -6,40 +6,28 @@ class TestReader < Test::Unit::TestCase
|
|
6
6
|
s = StringIO.new("This is a string")
|
7
7
|
|
8
8
|
reader = Bychar.wrap(s)
|
9
|
-
assert_equal "T", reader.read_one_char
|
10
|
-
assert_equal "h", reader.read_one_char
|
9
|
+
assert_equal "T", reader.read_one_char
|
10
|
+
assert_equal "h", reader.read_one_char
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_eof_with_empty
|
14
14
|
s = StringIO.new
|
15
15
|
reader = Bychar.wrap(s)
|
16
|
-
|
16
|
+
assert_nil reader.read_one_char
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_eof_with_io_at_eof
|
20
20
|
s = StringIO.new("foo")
|
21
21
|
s.read(3)
|
22
22
|
reader = Bychar.wrap(s)
|
23
|
-
|
23
|
+
assert_nil reader.read_one_char
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_eof_with_string_to_size
|
27
27
|
s = "Foobarboo another"
|
28
28
|
s = StringIO.new(s)
|
29
29
|
reader = Bychar.wrap(s)
|
30
|
-
s.length.times { reader.read_one_char
|
31
|
-
|
30
|
+
s.length.times { reader.read_one_char }
|
31
|
+
assert_nil reader.read_one_char
|
32
32
|
end
|
33
|
-
|
34
|
-
def test_read_one_byte_and_raise_at_eof
|
35
|
-
str = "Frobobo"
|
36
|
-
bytes = []
|
37
|
-
assert_raise(Bychar::EOF) do
|
38
|
-
s = Bychar.wrap(StringIO.new(str))
|
39
|
-
loop { bytes << s.read_one_char! }
|
40
|
-
end
|
41
|
-
|
42
|
-
assert_equal %w( F r o b o b o ), bytes
|
43
|
-
end
|
44
|
-
|
45
33
|
end
|
data/test/test_strreader.rb
CHANGED
@@ -6,41 +6,30 @@ class TestStrReader < Test::Unit::TestCase
|
|
6
6
|
s = StringIO.new("This is a string")
|
7
7
|
|
8
8
|
reader = Bychar::ReaderIOBuf.new(s)
|
9
|
-
assert_equal "T", reader.read_one_char
|
10
|
-
assert_equal "h", reader.read_one_char
|
9
|
+
assert_equal "T", reader.read_one_char
|
10
|
+
assert_equal "h", reader.read_one_char
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_eof_with_empty
|
14
14
|
s = StringIO.new
|
15
15
|
reader = Bychar::ReaderStrbuf.new(s)
|
16
|
-
|
16
|
+
assert_nil reader.read_one_char
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_eof_with_io_at_eof
|
20
20
|
s = StringIO.new("foo")
|
21
21
|
s.read(3)
|
22
22
|
reader = Bychar::ReaderStrbuf.new(s)
|
23
|
-
|
23
|
+
assert_nil reader.read_one_char
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_eof_with_string_to_size
|
27
27
|
s = "Foobarboo another"
|
28
28
|
s = StringIO.new(s)
|
29
29
|
reader = Bychar::ReaderStrbuf.new(s)
|
30
|
-
s.length.times {
|
31
|
-
|
30
|
+
s.length.times {
|
31
|
+
assert reader.read_one_char
|
32
|
+
}
|
33
|
+
assert_nil reader.read_one_char
|
32
34
|
end
|
33
|
-
|
34
|
-
def test_read_one_byte_and_raise_at_eof
|
35
|
-
str = "Frobobo"
|
36
|
-
|
37
|
-
bytes = []
|
38
|
-
assert_raise(Bychar::EOF) do
|
39
|
-
s = Bychar::ReaderStrbuf.new(StringIO.new(str))
|
40
|
-
loop { bytes << s.read_one_char! }
|
41
|
-
end
|
42
|
-
|
43
|
-
assert_equal %w( F r o b o b o ), bytes
|
44
|
-
end
|
45
|
-
|
46
35
|
end
|
data/test/test_z_bench.rb
CHANGED
@@ -21,9 +21,9 @@ class BenchReader
|
|
21
21
|
def run
|
22
22
|
File.open(File.dirname(__FILE__) + "/huge_nuke_tcl.tcl") do | io |
|
23
23
|
reader = get_reader(io)
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
str = []
|
25
|
+
while c = reader.read_one_char
|
26
|
+
str << (c * 2)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
metadata
CHANGED
@@ -1,95 +1,98 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bychar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 3.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Julik Tarkhanov
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-12-10 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
16
22
|
version_requirements: !ruby/object:Gem::Requirement
|
17
23
|
requirements:
|
18
|
-
- -
|
24
|
+
- - ">="
|
19
25
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
21
|
-
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
22
29
|
requirement: !ruby/object:Gem::Requirement
|
23
30
|
requirements:
|
24
|
-
- - ~>
|
31
|
+
- - "~>"
|
25
32
|
- !ruby/object:Gem::Version
|
26
33
|
version: '3.12'
|
27
|
-
none: false
|
28
|
-
prerelease: false
|
29
34
|
type: :development
|
30
|
-
|
31
|
-
name: bundler
|
35
|
+
prerelease: false
|
32
36
|
version_requirements: !ruby/object:Gem::Requirement
|
33
37
|
requirements:
|
34
|
-
- -
|
38
|
+
- - "~>"
|
35
39
|
- !ruby/object:Gem::Version
|
36
|
-
version:
|
37
|
-
|
38
|
-
|
40
|
+
version: '3.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
39
43
|
requirement: !ruby/object:Gem::Requirement
|
40
44
|
requirements:
|
41
|
-
- -
|
45
|
+
- - ">="
|
42
46
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
44
|
-
MA==
|
45
|
-
none: false
|
46
|
-
prerelease: false
|
47
|
+
version: '0'
|
47
48
|
type: :development
|
48
|
-
|
49
|
-
name: jeweler
|
49
|
+
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
-
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jeweler
|
56
57
|
requirement: !ruby/object:Gem::Requirement
|
57
58
|
requirements:
|
58
|
-
- -
|
59
|
+
- - '='
|
59
60
|
- !ruby/object:Gem::Version
|
60
|
-
version: 1.8.
|
61
|
-
none: false
|
62
|
-
prerelease: false
|
61
|
+
version: 1.8.7
|
63
62
|
type: :development
|
64
|
-
|
65
|
-
name: flexmock
|
63
|
+
prerelease: false
|
66
64
|
version_requirements: !ruby/object:Gem::Requirement
|
67
65
|
requirements:
|
68
|
-
- -
|
66
|
+
- - '='
|
69
67
|
- !ruby/object:Gem::Version
|
70
|
-
version:
|
71
|
-
|
68
|
+
version: 1.8.7
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: flexmock
|
72
71
|
requirement: !ruby/object:Gem::Requirement
|
73
72
|
requirements:
|
74
|
-
- - ~>
|
73
|
+
- - "~>"
|
75
74
|
- !ruby/object:Gem::Version
|
76
75
|
version: '0.8'
|
77
|
-
none: false
|
78
|
-
prerelease: false
|
79
76
|
type: :development
|
80
|
-
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.8'
|
83
|
+
description: " Helps parsing IO char by char "
|
81
84
|
email: me@julik.nl
|
82
85
|
executables: []
|
83
86
|
extensions: []
|
84
87
|
extra_rdoc_files:
|
85
88
|
- LICENSE.txt
|
86
|
-
- README.
|
89
|
+
- README.md
|
87
90
|
files:
|
88
|
-
- .document
|
89
|
-
- .travis.yml
|
91
|
+
- ".document"
|
92
|
+
- ".travis.yml"
|
90
93
|
- Gemfile
|
91
94
|
- LICENSE.txt
|
92
|
-
- README.
|
95
|
+
- README.md
|
93
96
|
- Rakefile
|
94
97
|
- bychar.gemspec
|
95
98
|
- lib/bychar.rb
|
@@ -105,31 +108,25 @@ files:
|
|
105
108
|
homepage: http://github.com/julik/bychar
|
106
109
|
licenses:
|
107
110
|
- MIT
|
108
|
-
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
109
113
|
rdoc_options: []
|
110
114
|
require_paths:
|
111
115
|
- lib
|
112
116
|
required_ruby_version: !ruby/object:Gem::Requirement
|
113
117
|
requirements:
|
114
|
-
- -
|
118
|
+
- - ">="
|
115
119
|
- !ruby/object:Gem::Version
|
116
|
-
|
117
|
-
- 0
|
118
|
-
hash: 2
|
119
|
-
version: !binary |-
|
120
|
-
MA==
|
121
|
-
none: false
|
120
|
+
version: '0'
|
122
121
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
122
|
requirements:
|
124
|
-
- -
|
123
|
+
- - ">="
|
125
124
|
- !ruby/object:Gem::Version
|
126
|
-
version:
|
127
|
-
MA==
|
128
|
-
none: false
|
125
|
+
version: '0'
|
129
126
|
requirements: []
|
130
|
-
rubyforge_project:
|
131
|
-
rubygems_version:
|
132
|
-
signing_key:
|
133
|
-
specification_version:
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 2.2.2
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
134
131
|
summary: Helps parsing IO char by char
|
135
132
|
test_files: []
|
data/README.rdoc
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
= bychar
|
2
|
-
|
3
|
-
A simple IO wrapper for libraries that tend to read the IO in the following way:
|
4
|
-
|
5
|
-
* Only forward
|
6
|
-
* By a single character
|
7
|
-
* Without skipping
|
8
|
-
|
9
|
-
This is how most of recursive-descent parsers and stateful parsers would work. However,
|
10
|
-
reading a simple IO object byte by byte in Ruby is very slow. Orders slower in fact.
|
11
|
-
Therefore, this gem creates a simple wrapper that you can get like this:
|
12
|
-
|
13
|
-
wrapper = Bychar.wrap(io)
|
14
|
-
loop do
|
15
|
-
c = wrapper.read_one_char!
|
16
|
-
rescye Bychar::EOF
|
17
|
-
# Your IO ran out
|
18
|
-
end
|
19
|
-
|
20
|
-
The wrapper will cache some bytes from the passed IO object which will make parsing
|
21
|
-
faster when you advance your parser char by char. You should not do any checks on the returned char
|
22
|
-
since the reader will raise a Bychar::EOF once the IO is depleted. That exception inherits from EOFError.
|
23
|
-
|
24
|
-
== Performance
|
25
|
-
|
26
|
-
I told you reading char by char is not the best strategy. On Ruby 1.9:
|
27
|
-
|
28
|
-
Bare IO using read(1): 3.400000 1.900000 5.300000 ( 5.300798)
|
29
|
-
Bychar using StringIO: 1.790000 0.010000 1.800000 ( 1.795277)
|
30
|
-
Bychar using a String buffer: 1.760000 0.000000 1.760000 ( 1.760440)
|
31
|
-
Platform-picked Bychar.wrap(io) Bychar::ReaderStrbuf: 1.770000 0.010000 1.780000 ( 1.776339)
|
32
|
-
|
33
|
-
while on Ruby 1.8 it is kinda sad:
|
34
|
-
|
35
|
-
Bare IO using read(1): 2.380000 0.000000 2.380000 ( 2.393260)
|
36
|
-
Bychar using StringIO: 2.270000 0.010000 2.280000 ( 2.275631)
|
37
|
-
Bychar using a String buffer: 2.920000 0.000000 2.920000 ( 2.924574)
|
38
|
-
Platform-picked Bychar.wrap(io) Bychar::ReaderBare: 2.380000 0.010000 2.390000 ( 2.384414)
|
39
|
-
|
40
|
-
And on JRuby it's different still:
|
41
|
-
|
42
|
-
Bare IO using read(1): 1.610000 0.040000 1.650000 ( 1.180000)
|
43
|
-
Bychar using StringIO: 0.730000 0.020000 0.750000 ( 0.603000)
|
44
|
-
Bychar using a String buffer: 1.040000 0.040000 1.080000 ( 0.790000)
|
45
|
-
Platform-picked Bychar.wrap(io) Bychar::ReaderIOBuf: 0.560000 0.030000 0.590000 ( 0.546000)
|
46
|
-
|
47
|
-
As you can see, Bychar will do some work to pick an implementation that makes sense for your Ruby platform.
|
48
|
-
|
49
|
-
== Contributing to bychar
|
50
|
-
|
51
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
52
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
53
|
-
* Fork the project.
|
54
|
-
* Start a feature/bugfix branch.
|
55
|
-
* Commit and push until you are happy with your contribution.
|
56
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
57
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
58
|
-
|
59
|
-
== Copyright
|
60
|
-
|
61
|
-
Copyright (c) 2013 Julik Tarkhanov. See LICENSE.txt for
|
62
|
-
further details.
|
63
|
-
|