goroutine 0.0.1

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.
@@ -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: