goroutine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d6fcf2f3f6baec6422830dc4ce5ced26ee7d86ab
4
+ data.tar.gz: b325d312391f8b4379e85c554053a21be817a621
5
+ SHA512:
6
+ metadata.gz: 07d18c2fdbfa411ef1212f02f19cbee83a797377d5b8145dbebf360fc0cafa5f614639114639965fd2caf25a5c885e2dbbf301b0b3c258066142bc45ae32b653
7
+ data.tar.gz: 810f327cf6d4b4e95baf28a4de1a8c497a9344303e824c1f00ed361813a463adf1bc3b8f8035a9cccf04c40ab6fe9b2a138f43b640cc3a0acc4b43c18d3e799d
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in goroutine.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Davide D'Agostino
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,160 @@
1
+ # Goroutine
2
+
3
+ This is a very simple implementation of `channels` in pure ruby in like [40
4
+ lines](lib/goroutine.rb) of code and with the help of unix `pipes` and `IO.select`
5
+
6
+ It's composed by two components: `Queue` and `IO.pipe`, the `Queue` can be **buffered**.
7
+
8
+ This project is in a very **early stage**.
9
+
10
+ ## Usage
11
+
12
+ ![demo](http://fs.daddye.it/qKUU+)
13
+
14
+ Let's start with some examples:
15
+
16
+ ### GO and Channel
17
+
18
+ A very basic program could be:
19
+
20
+ ```rb
21
+ chan = Channel.new
22
+
23
+ go do
24
+ loop do
25
+ chan << :hello!
26
+ sleep 1
27
+ end
28
+ end
29
+
30
+ while chan.ready
31
+ p chan.pop
32
+ end
33
+ ```
34
+
35
+ [go](lib/goroutine/ext.rb) method is nothing more than a `Thread.new {}`, just shorter.
36
+
37
+ ### Select
38
+
39
+ You can use the `select` method to wait for one or **more** (the latter is
40
+ interesting) channels.
41
+
42
+ ```rb
43
+ channel = Channel.new
44
+
45
+ go do
46
+ 10.times { |i| channel << i; sleep 1 }
47
+ channel << :quit
48
+ end
49
+
50
+ select(channel) do |val|
51
+ break if val == :quit
52
+ p val
53
+ end
54
+ ```
55
+
56
+ You can use `break` to stop and exit from a `select` block.
57
+
58
+ However `select` becomes more interesting when using multiple channels:
59
+
60
+ ```rb
61
+ channels = 5.times.map { Channel.new }
62
+
63
+ # Simulating a long running worker
64
+ go(0) do |i|
65
+ while i += 1
66
+ channels.sample << i
67
+ sleep 1
68
+ end
69
+ end
70
+
71
+ # Reader
72
+ select(channels) do |val, i|
73
+ puts "<ch:#{i}, message: #{val}>"
74
+ break if val > 9
75
+ end
76
+ ```
77
+
78
+ The output will be like:
79
+
80
+ ```
81
+ <ch:1, message: 1>
82
+ <ch:2, message: 2>
83
+ <ch:1, message: 3>
84
+ <ch:0, message: 4>
85
+ <ch:4, message: 5>
86
+ <ch:3, message: 6>
87
+ <ch:2, message: 7>
88
+ ```
89
+
90
+ ### Buffered Channel
91
+
92
+ If necessary, you can have a buffered channel:
93
+
94
+ ```rb
95
+ channel = Channel::Buffered.new(5)
96
+ go do
97
+ 10.times { |i| channel << i; sleep 1 }
98
+ channel << :quit
99
+ end
100
+
101
+ # Subscribe a "completed" channel
102
+ select(channel) do |val|
103
+ break if val == :quit
104
+ p val
105
+ end
106
+ ```
107
+
108
+ ## Installation
109
+
110
+ Add this line to your application's Gemfile:
111
+
112
+ gem 'goroutine'
113
+
114
+ And then execute:
115
+
116
+ $ bundle
117
+
118
+ Or install it yourself as:
119
+
120
+ $ gem install goroutine
121
+
122
+ ## Inspirations and Mentions
123
+
124
+ It's worth to mention that if you are looking for a more sophisticated version of `goroutines` you
125
+ should checkout [agent](https://github.com/igrigorik/agent) by [Ilya
126
+ Grigorik](https://www.igvita.com)
127
+
128
+ Of course, this idea is yet another attempt to model [go
129
+ channels](http://golang.org/doc/effective_go.html#channels)
130
+
131
+ ## Contributing
132
+
133
+ 1. Fork it ( https://github.com/[my-github-username]/goroutine/fork )
134
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
135
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
136
+ 4. Push to the branch (`git push origin my-new-feature`)
137
+ 5. Create a new Pull Request
138
+
139
+
140
+ ## LICENSE
141
+
142
+ Copyright (C) 2014 Davide D'Agostino
143
+
144
+ Permission is hereby granted, free of charge, to any person obtaining
145
+ a copy of this software and associated documentation files (the "Software"),
146
+ to deal in the Software without restriction, including without limitation
147
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
148
+ and/or sell copies of the Software, and to permit persons to whom the
149
+ Software is furnished to do so, subject to the following conditions:
150
+
151
+ The above copyright notice and this permission notice shall be included
152
+ in all copies or substantial portions of the Software.
153
+
154
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
155
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
156
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
157
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
158
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
159
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
160
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,21 @@
1
+ require 'bundler/setup'
2
+ require 'goroutine'
3
+
4
+ room = Channel.new
5
+
6
+ go do
7
+ room << ['You', STDIN.gets] while true
8
+ end
9
+
10
+ go('Stan', 'Francine', 'Roger') do |*names|
11
+ names.each do |who|
12
+ room << [who, "hello!"]
13
+ sleep 1
14
+ end
15
+ room << ['Klaus', "how are you?"]
16
+ end
17
+
18
+ select(room) do |(who, text)|
19
+ puts "\e[01m#{who}\e[0m said:\t#{text}"
20
+ break if who == 'You'
21
+ end
@@ -0,0 +1,27 @@
1
+ require 'bundler/setup'
2
+ require 'goroutine'
3
+
4
+ file = File.open(__FILE__) # read myself
5
+ channels = 10.times.map { Channel.new }
6
+
7
+ # Simulate slow reading
8
+ puts 'Start a slow reading'
9
+ go do
10
+ while buf = file.read(16)
11
+ channels.sample << buf
12
+ sleep 0.5
13
+ end
14
+ channels.each { |chan| chan << :exit }
15
+ end
16
+
17
+ # Do something now
18
+ puts 'Doing something else'
19
+
20
+ # Okay, now, it's time to read
21
+ puts 'Waiting for lines'
22
+ select(channels) do |line|
23
+ break if line == :exit
24
+ print line
25
+ end
26
+
27
+ file.close
@@ -0,0 +1,16 @@
1
+ require 'bundler/setup'
2
+ require 'goroutine'
3
+
4
+ # Single buffered channel, it's immediate so the publisher will complete before he'll get any
5
+ # subscription (edge case)
6
+ channel = Channel::Buffered.new(5)
7
+ go do
8
+ 10.times { |i| channel << i }
9
+ channel << :quit
10
+ end
11
+
12
+ # Subscribe a "completed" channel
13
+ select(channel) do |val|
14
+ break if val == :quit
15
+ p val
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'bundler/setup'
2
+ require 'goroutine'
3
+
4
+ channels = 5.times.map { Channel.new }
5
+
6
+ # Simulating a long running worker
7
+ go(0) do |i|
8
+ while i += 1
9
+ channels.sample << i
10
+ sleep 1
11
+ end
12
+ end
13
+
14
+ # Reader
15
+ select(channels) do |val, i|
16
+ puts "<ch:#{i}, message: #{val}>"
17
+ break if val > 9
18
+ end
@@ -0,0 +1,15 @@
1
+ require 'bundler/setup'
2
+ require 'goroutine'
3
+
4
+ chan = Channel.new
5
+
6
+ go do
7
+ loop do
8
+ chan << :hello!
9
+ sleep 1
10
+ end
11
+ end
12
+
13
+ while chan.ready
14
+ p chan.pop
15
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'goroutine/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "goroutine"
8
+ spec.version = Goroutine::VERSION
9
+ spec.authors = ["Davide D'Agostino"]
10
+ spec.email = ["info@daddye.it"]
11
+ spec.summary = %q{A simple goroutine model for ruby.}
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/DAddYE/goroutine"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,41 @@
1
+ require 'goroutine/version'
2
+ require 'goroutine/channel'
3
+ require 'goroutine/ext'
4
+
5
+ module Goroutine
6
+ def initialize(*args)
7
+ super(*args)
8
+ @rd, wr = IO.pipe
9
+ rd, @wr = IO.pipe
10
+ go do
11
+ loop do
12
+ IO.select([rd])
13
+ rd.read(1)
14
+ wr.write('.')
15
+ end
16
+ end
17
+ end
18
+
19
+ def pop
20
+ @rd.read(1)
21
+ super
22
+ end
23
+ alias shift pop
24
+ alias deq pop
25
+
26
+ def push(val)
27
+ @wr.write('.')
28
+ super(val)
29
+ end
30
+ alias << push
31
+ alias enq push
32
+
33
+ def to_io
34
+ @rd
35
+ end
36
+
37
+ def wait
38
+ IO.select([self])[0]
39
+ end
40
+ alias :ready :wait
41
+ end
@@ -0,0 +1,7 @@
1
+ class Channel < Queue
2
+ include Goroutine
3
+ end
4
+
5
+ class Channel::Buffered < SizedQueue
6
+ include Goroutine
7
+ end
@@ -0,0 +1,14 @@
1
+ module Kernel
2
+ def select(channels, &block)
3
+ channels = Array(channels)
4
+ loop do
5
+ rs, _ = IO.select(channels)
6
+ rs.each { |ch| block[ch.pop, channels.index(ch)] }
7
+ end
8
+ end
9
+
10
+ def go(*args, &block)
11
+ Thread.abort_on_exception = true
12
+ Thread.new(*args, &block)
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Goroutine
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: goroutine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Davide D'Agostino
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-10 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
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
+ description: A simple goroutine model for ruby.
42
+ email:
43
+ - info@daddye.it
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE.txt
51
+ - README.md
52
+ - Rakefile
53
+ - example/chat.rb
54
+ - example/file.rb
55
+ - example/immediate.rb
56
+ - example/multi.rb
57
+ - example/simple.rb
58
+ - goroutine.gemspec
59
+ - lib/goroutine.rb
60
+ - lib/goroutine/channel.rb
61
+ - lib/goroutine/ext.rb
62
+ - lib/goroutine/version.rb
63
+ homepage: https://github.com/DAddYE/goroutine
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.2.2
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: A simple goroutine model for ruby.
87
+ test_files: []
88
+ has_rdoc: