chan 0.0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +19 -0
- data/.travis.yml +31 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +31 -0
- data/Rakefile +38 -0
- data/chan.gemspec +27 -0
- data/lib/chan.rb +116 -0
- data/spec/chan_spec.rb +57 -0
- data/spec/spec_helper.rb +18 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bfca59accb24a6ffb6cdf1abb6800852694cff43
|
4
|
+
data.tar.gz: 3d83cfa26274fae11c30ca4069dece904acfec1a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d3804f17ef62273f6fd29bab3479e091b4ef7bbb1a548750ae67c16c93565778a72f8b680567976b24a7ec0ce819dcb10a9affae8173e355c3d80a69cb19841
|
7
|
+
data.tar.gz: 4c524ea1a700369e5e911cee292ef9ca12a01fe9722892613b66253fb69a79643eb360ef3e7793fe56e4f1941c1b196435471ad5311226ad9fa27292fe385786
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
language: ruby
|
2
|
+
before_install:
|
3
|
+
- gem update --system 2.1.11
|
4
|
+
- gem --version
|
5
|
+
rvm:
|
6
|
+
- 1.8.7
|
7
|
+
- ree
|
8
|
+
- 1.9.2
|
9
|
+
- 1.9.3
|
10
|
+
- 2.0.0
|
11
|
+
- 2.1.0
|
12
|
+
- 2.1.1
|
13
|
+
- 2.1.2
|
14
|
+
- ruby-head
|
15
|
+
- jruby-18mode
|
16
|
+
- jruby-19mode
|
17
|
+
- jruby-20mode
|
18
|
+
- jruby-21mode
|
19
|
+
- jruby-head
|
20
|
+
- rbx-2.1.1
|
21
|
+
- rbx-2.2.3
|
22
|
+
matrix:
|
23
|
+
allow_failures:
|
24
|
+
- rvm: ruby-head
|
25
|
+
- rvm: jruby-head
|
26
|
+
- rvm: jruby-18mode
|
27
|
+
- rvm: jruby-19mode
|
28
|
+
- rvm: jruby-20mode
|
29
|
+
- rvm: jruby-21mode
|
30
|
+
- rvm: rbx-2.1.1
|
31
|
+
- rvm: rbx-2.2.3
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
- Copyright (c) 2014, T. Yamada
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
7
|
+
list of conditions and the following disclaimer.
|
8
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
9
|
+
this list of conditions and the following disclaimer in the documentation
|
10
|
+
and/or other materials provided with the distribution.
|
11
|
+
|
12
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
13
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
14
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
15
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
16
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
17
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
18
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
19
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
20
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
21
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# chan
|
2
|
+
Bidirectional enumerator (channel) or the chan object like in Golang.
|
3
|
+
|
4
|
+
[![Build Status](https://travis-ci.org/cielavenir/ruby-chan.png)](https://travis-ci.org/cielavenir/ruby-chan) [![Code Climate](https://codeclimate.com/github/cielavenir/ruby-chan.png)](https://codeclimate.com/github/cielavenir/ruby-chan) [![Coverage Status](https://coveralls.io/repos/cielavenir/ruby-chan/badge.png)](https://coveralls.io/r/cielavenir/ruby-chan)
|
5
|
+
|
6
|
+
## Supported Ruby versions
|
7
|
+
* Ruby 1.8.7 or later
|
8
|
+
* jruby
|
9
|
+
* (Possibly) rubinius / ironruby / macruby / topaz etc
|
10
|
+
|
11
|
+
## Binary distribution
|
12
|
+
* https://rubygems.org/gems/chan
|
13
|
+
|
14
|
+
## Install
|
15
|
+
* gem install chan
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
* Please check spec/chan.spec as an example.
|
19
|
+
|
20
|
+
## Contributing to chan
|
21
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
22
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
23
|
+
* Fork the project.
|
24
|
+
* Start a feature/bugfix branch.
|
25
|
+
* Commit and push until you are happy with your contribution.
|
26
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
27
|
+
* 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.
|
28
|
+
|
29
|
+
## Copyright
|
30
|
+
Copyright (c) 2015 T. Yamada under Ruby License (2-clause BSDL or Artistic).
|
31
|
+
See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require './lib/chan'
|
3
|
+
|
4
|
+
### below are copied from jeweler ###
|
5
|
+
|
6
|
+
require 'rake'
|
7
|
+
# Clean up after gem building
|
8
|
+
require 'rake/clean'
|
9
|
+
CLEAN.include('pkg/*.gem')
|
10
|
+
CLOBBER.include('coverage')
|
11
|
+
|
12
|
+
require 'rspec/core'
|
13
|
+
require 'rspec/core/rake_task'
|
14
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
15
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
19
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
20
|
+
spec.rcov = true
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => :spec
|
24
|
+
|
25
|
+
begin
|
26
|
+
require 'rdoc/task'
|
27
|
+
Rake::RDocTask.new do |rdoc|
|
28
|
+
rdoc.rdoc_dir = 'rdoc'
|
29
|
+
rdoc.title = 'chan '+Chan::VERSION
|
30
|
+
rdoc.main = 'README.md'
|
31
|
+
rdoc.rdoc_files.include('README.*')
|
32
|
+
rdoc.rdoc_files.include('LICENSE.*')
|
33
|
+
rdoc.rdoc_files.include('CHANGELOG.*')
|
34
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
35
|
+
end
|
36
|
+
rescue Exception #LoadError # Thus rdoc generation is limited to Ruby 1.9.3+...
|
37
|
+
#Ruby 1.9.2 gives another Exception. I cannot limit to LoadError...
|
38
|
+
end
|
data/chan.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require './lib/chan'
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "chan"
|
6
|
+
spec.version = Chan::VERSION
|
7
|
+
spec.authors = ["cielavenir"]
|
8
|
+
spec.email = ["cielartisan@gmail.com"]
|
9
|
+
spec.description = "Bidirectional enumerator (channel) or the chan object like in Golang"
|
10
|
+
spec.summary = "Bidirectional channel like the Golang chan object"
|
11
|
+
spec.homepage = "http://github.com/cielavenir/chan"
|
12
|
+
spec.license = "Ruby License (2-clause BSDL or Artistic)"
|
13
|
+
|
14
|
+
spec.files = `git ls-files`.split($/) + [
|
15
|
+
"LICENSE.txt",
|
16
|
+
"README.md",
|
17
|
+
"CHANGELOG.md",
|
18
|
+
]
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", ">= 1.0"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
end
|
data/lib/chan.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# Chan: Bidirectional enumerator (channel) or the chan object like in Golang
|
2
|
+
#
|
3
|
+
# Copyright (c) 2015, T. Yamada under Ruby License (2-clause BSDL or Artistic).
|
4
|
+
#
|
5
|
+
# Check LICENSE terms.
|
6
|
+
#
|
7
|
+
# Note: MIT License is also applicable if that compresses LICENSE file.
|
8
|
+
|
9
|
+
class Chan
|
10
|
+
# VERSION string
|
11
|
+
VERSION='0.0.0.1'
|
12
|
+
|
13
|
+
# Channel handler inside block.
|
14
|
+
class Yielder
|
15
|
+
def initialize(parent_to_child,child_to_parent)
|
16
|
+
@parent_to_child=parent_to_child
|
17
|
+
@child_to_parent=child_to_parent
|
18
|
+
end
|
19
|
+
# Loops indefinitely while parent channel is empty.
|
20
|
+
def sync
|
21
|
+
while @parent_to_child.empty?
|
22
|
+
Fiber.yield(true)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
# Stops writing to parent queue.
|
26
|
+
def close
|
27
|
+
@parent_to_child.instance_eval{
|
28
|
+
def push(v)
|
29
|
+
raise RuntimeError.new('Pushing to closed Chan')
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
# Receives an object from parent without modifying the queue.
|
34
|
+
def peek
|
35
|
+
sync
|
36
|
+
@parent_to_child.first
|
37
|
+
end
|
38
|
+
# Receives an object from parent.
|
39
|
+
# aliased to next/succ.
|
40
|
+
def receive
|
41
|
+
sync
|
42
|
+
@parent_to_child.shift
|
43
|
+
end
|
44
|
+
alias_method :next,:receive
|
45
|
+
alias_method :succ,:receive
|
46
|
+
# Sends an object to parent.
|
47
|
+
# aliased to <<.
|
48
|
+
def send(v)
|
49
|
+
@child_to_parent.push(v)
|
50
|
+
Fiber.yield(false)
|
51
|
+
end
|
52
|
+
alias_method :<<,:send
|
53
|
+
end
|
54
|
+
|
55
|
+
# Constructor. you should pass a block like you do in Enumerator.
|
56
|
+
# Actually if you use Enumerator.new{} as external iterator,
|
57
|
+
# you can safely convert it to Chan.new{} in most cases.
|
58
|
+
def initialize(&blk)
|
59
|
+
@f=Fiber.new{|parent_to_child,child_to_parent,blk|
|
60
|
+
ch=Yielder.new(parent_to_child,child_to_parent)
|
61
|
+
blk.call(ch)
|
62
|
+
}
|
63
|
+
@parent_to_child=[]
|
64
|
+
@child_to_parent=[]
|
65
|
+
@f.resume(@parent_to_child,@child_to_parent,blk)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Tells if the channel has next element.
|
69
|
+
# If false, it means end of enumeration or you need to give more object.
|
70
|
+
def next?
|
71
|
+
while @child_to_parent.empty?
|
72
|
+
begin
|
73
|
+
flg=@f.resume
|
74
|
+
if flg&&@parent_to_child.empty?
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
rescue FiberError
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
true
|
82
|
+
end
|
83
|
+
# Receives an object from child without modifying the queue.
|
84
|
+
def peek
|
85
|
+
raise StopIteration.new('too many read requests') if !next?
|
86
|
+
@child_to_parent.first
|
87
|
+
end
|
88
|
+
# Receives an object from child.
|
89
|
+
# aliased to next/succ.
|
90
|
+
def receive
|
91
|
+
raise StopIteration.new('too many read requests') if !next?
|
92
|
+
@child_to_parent.shift
|
93
|
+
end
|
94
|
+
alias_method :next,:receive
|
95
|
+
alias_method :succ,:receive
|
96
|
+
# Sends an object to child.
|
97
|
+
def send(v)
|
98
|
+
@parent_to_child.push(v)
|
99
|
+
end
|
100
|
+
alias_method :<<,:send
|
101
|
+
|
102
|
+
# Builds an Enumerator using existing Enumerator.
|
103
|
+
def gen_enum(enum)
|
104
|
+
Enumerator.new{|y|
|
105
|
+
begin
|
106
|
+
loop{
|
107
|
+
self<<enum.next
|
108
|
+
y<<self.receive if self.next?
|
109
|
+
} # StopIteration is catched by Kernel#loop
|
110
|
+
rescue RuntimeError
|
111
|
+
# attempted to push to closed Chan
|
112
|
+
end
|
113
|
+
y<<self.receive while self.next?
|
114
|
+
}
|
115
|
+
end
|
116
|
+
end
|
data/spec/chan_spec.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+'/spec_helper')
|
2
|
+
|
3
|
+
describe "Chan" do
|
4
|
+
specify "skip elements" do
|
5
|
+
ch=Chan.new{|ch|
|
6
|
+
loop{
|
7
|
+
raise if ch.peek!=ch.receive
|
8
|
+
raise if ch.peek!=ch.receive
|
9
|
+
ch<<ch.receive*2
|
10
|
+
}
|
11
|
+
}
|
12
|
+
ch.next?.should be false
|
13
|
+
ch<<1
|
14
|
+
ch.next?.should be false
|
15
|
+
ch<<2
|
16
|
+
ch.next?.should be false
|
17
|
+
ch<<3
|
18
|
+
ch.next?.should be true
|
19
|
+
ch.peek.should eq 6
|
20
|
+
ch.next.should eq 6
|
21
|
+
end
|
22
|
+
specify "gen_enum (chan) with loop" do
|
23
|
+
Chan.new{|ch|
|
24
|
+
loop{
|
25
|
+
ch.receive
|
26
|
+
ch.receive
|
27
|
+
ch<<ch.receive*2
|
28
|
+
}
|
29
|
+
}.gen_enum(Chan.new{|y|
|
30
|
+
a=0
|
31
|
+
b=1
|
32
|
+
y<<a
|
33
|
+
20.times{
|
34
|
+
y<<b
|
35
|
+
a,b=b,a+b
|
36
|
+
}
|
37
|
+
}).take(10).should eq [2, 10, 42, 178, 754, 3194, 13530]
|
38
|
+
end
|
39
|
+
specify "gen_enum (enumerator) without loop" do
|
40
|
+
Chan.new{|ch|
|
41
|
+
#loop{
|
42
|
+
ch.next
|
43
|
+
ch.succ
|
44
|
+
ch.send ch.receive*2
|
45
|
+
#}
|
46
|
+
ch.close
|
47
|
+
}.gen_enum(Enumerator.new{|y|
|
48
|
+
a=0
|
49
|
+
b=1
|
50
|
+
y<<a
|
51
|
+
loop{
|
52
|
+
y<<b
|
53
|
+
a,b=b,a+b
|
54
|
+
}
|
55
|
+
}).take(10).should eq [2]
|
56
|
+
end
|
57
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
RSpec.configure{|config|
|
3
|
+
config.color=true
|
4
|
+
}
|
5
|
+
|
6
|
+
if !defined?(RUBY_ENGINE)||RUBY_ENGINE=='ruby'
|
7
|
+
require 'simplecov'
|
8
|
+
require 'coveralls'
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
10
|
+
SimpleCov::Formatter::HTMLFormatter,
|
11
|
+
Coveralls::SimpleCov::Formatter
|
12
|
+
]
|
13
|
+
SimpleCov.start do
|
14
|
+
add_filter 'spec'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require File.expand_path(File.dirname(__FILE__)+'/../lib/chan')
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- cielavenir
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Bidirectional enumerator (channel) or the chan object like in Golang
|
56
|
+
email:
|
57
|
+
- cielartisan@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .coveralls.yml
|
63
|
+
- .gitignore
|
64
|
+
- .travis.yml
|
65
|
+
- CHANGELOG.md
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- chan.gemspec
|
71
|
+
- lib/chan.rb
|
72
|
+
- spec/chan_spec.rb
|
73
|
+
- spec/spec_helper.rb
|
74
|
+
homepage: http://github.com/cielavenir/chan
|
75
|
+
licenses:
|
76
|
+
- Ruby License (2-clause BSDL or Artistic)
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 2.0.14
|
95
|
+
signing_key:
|
96
|
+
specification_version: 4
|
97
|
+
summary: Bidirectional channel like the Golang chan object
|
98
|
+
test_files:
|
99
|
+
- spec/chan_spec.rb
|
100
|
+
- spec/spec_helper.rb
|