csp 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.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ csp.gemspec
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.test_files = Dir.glob("test/*_test.rb")
6
+ end
7
+
8
+ begin
9
+ require 'jeweler'
10
+ Jeweler::Tasks.new do |gemspec|
11
+ gemspec.name = "csp"
12
+ gemspec.summary = "Concurrent Sequential Processes"
13
+ gemspec.description = "Massive concurrency with message-passing and stuff."
14
+ gemspec.email = "daniel.schierbeck@gmail.com"
15
+ gemspec.homepage = "http://github.com/dasch/ruby-csp"
16
+ gemspec.authors = ["Daniel Schierbeck"]
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler not available. Install it with: gem install jeweler"
21
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/lib/csp.rb ADDED
@@ -0,0 +1,38 @@
1
+
2
+ require "csp/scheduler"
3
+ require "csp/channel"
4
+ require "csp/process"
5
+ require "csp/choice"
6
+ require "csp/skip"
7
+
8
+ module CSP
9
+
10
+ class << self
11
+
12
+ def scheduler
13
+ @scheduler ||= CSP::Scheduler.new
14
+ end
15
+
16
+ def start(*processes)
17
+ processes.each do |process|
18
+ process.start
19
+ end
20
+
21
+ CSP.run
22
+ end
23
+
24
+ def yield
25
+ scheduler.yield
26
+ end
27
+
28
+ def run
29
+ scheduler.run
30
+ end
31
+
32
+ def enqueue(cont)
33
+ scheduler.enqueue(cont)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,60 @@
1
+
2
+ module CSP
3
+
4
+ class Channel
5
+
6
+ include Enumerable
7
+
8
+ def initialize
9
+ @readers = []
10
+ @writers = []
11
+ end
12
+
13
+ def read(options = {})
14
+ message = callcc do |cont|
15
+ @readers << cont
16
+
17
+ if @writers.empty?
18
+ if options[:callback]
19
+ return
20
+ else
21
+ CSP.run
22
+ end
23
+ else
24
+ @writers.shift.call
25
+ end
26
+ end
27
+
28
+ if options[:callback]
29
+ options[:callback].call(message)
30
+ else
31
+ return message
32
+ end
33
+ end
34
+
35
+ def write(message)
36
+ if @readers.empty?
37
+ callcc do |cont|
38
+ @writers << cont
39
+ CSP.run
40
+ end
41
+ end
42
+
43
+ callcc do |cont|
44
+ CSP.enqueue(cont)
45
+ @readers.shift.call(message)
46
+ end
47
+ end
48
+
49
+ def << message
50
+ write(message)
51
+ return self
52
+ end
53
+
54
+ def each
55
+ yield read while true
56
+ end
57
+
58
+ end
59
+
60
+ end
data/lib/csp/choice.rb ADDED
@@ -0,0 +1,13 @@
1
+
2
+ module CSP
3
+
4
+ def self.select(*options)
5
+ callcc do |cont|
6
+ options.each do |option|
7
+ option.read(:callback => cont)
8
+ end
9
+ CSP.run
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,24 @@
1
+
2
+
3
+ module CSP
4
+
5
+ class Process
6
+
7
+ def initialize(&block)
8
+ @block = block
9
+ end
10
+
11
+ def call
12
+ @block.call
13
+ end
14
+
15
+ def start
16
+ callcc do |cont|
17
+ CSP.enqueue(cont)
18
+ @block.call
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,32 @@
1
+
2
+ module CSP
3
+
4
+ class Scheduler
5
+
6
+ def initialize
7
+ @ready = []
8
+ end
9
+
10
+ def enqueue(cont)
11
+ @ready << cont
12
+ end
13
+
14
+ def run
15
+ schedule until @ready.empty?
16
+ end
17
+
18
+ def yield
19
+ callcc do |cont|
20
+ enqueue(cont)
21
+ run
22
+ end
23
+ end
24
+
25
+ def schedule
26
+ raise RuntimeError.new("Cannot yield; ready queue is empty") if @ready.empty?
27
+ @ready.shift.call
28
+ end
29
+
30
+ end
31
+
32
+ end
data/lib/csp/skip.rb ADDED
@@ -0,0 +1,16 @@
1
+
2
+ module CSP
3
+
4
+ class SKIP
5
+
6
+ class << self
7
+
8
+ def read(options = {})
9
+ options[:callback] && options[:callback].call
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,51 @@
1
+
2
+ require 'rubygems'
3
+ require 'test/unit'
4
+ require 'shoulda'
5
+ require 'lib/csp'
6
+
7
+
8
+ class ChannelTest < Test::Unit::TestCase
9
+
10
+ context "A CSP channel" do
11
+
12
+ setup do
13
+ @channel = CSP::Channel.new
14
+ end
15
+
16
+ should "send over channels" do
17
+ p1 = CSP::Process.new { @channel.write(42) }
18
+ p2 = CSP::Process.new { assert_equal 42, @channel.read }
19
+
20
+ CSP.start(p2, p1)
21
+ CSP.start(p1, p2)
22
+ end
23
+
24
+ should "send multiple values over channels" do
25
+ p1 = CSP::Process.new { [1, 2, 3].each {|i| @channel.write(i) } }
26
+ p2 = CSP::Process.new { [1, 2, 3].each {|i| assert_equal i, @channel.read } }
27
+
28
+ CSP.start(p2, p1)
29
+ end
30
+
31
+ should "iterate over received values" do
32
+ count = 0
33
+
34
+ p1 = CSP::Process.new { @channel.each {|msg| count += 1; assert_equal 42, msg } }
35
+ p2 = CSP::Process.new { 2.times { @channel.write(42) } }
36
+
37
+ CSP.start(p1, p2)
38
+
39
+ assert_equal 2, count
40
+ end
41
+
42
+ should "send multiple messages with the << operator" do
43
+ p1 = CSP::Process.new { @channel << 42 << 19 }
44
+ p2 = CSP::Process.new { [42, 19].each {|msg| assert_equal msg, @channel.read } }
45
+
46
+ CSP.start(p1, p2)
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,48 @@
1
+
2
+ require 'rubygems'
3
+ require 'test/unit'
4
+ require 'shoulda'
5
+ require 'lib/csp'
6
+
7
+
8
+ class ProcessTest < Test::Unit::TestCase
9
+
10
+ context "A choice of guards" do
11
+
12
+ should "select between multiple channels" do
13
+ c1 = CSP::Channel.new
14
+ c2 = CSP::Channel.new
15
+
16
+ p1 = CSP::Process.new { c1.write(42) while true }
17
+
18
+ CSP.start(p1)
19
+
20
+ assert_equal 42, CSP.select(c1, c2)
21
+ assert_equal 42, CSP.select(c2, c1)
22
+ end
23
+
24
+ should "select between multiple channels with decreasing priority" do
25
+ c1 = CSP::Channel.new
26
+ c2 = CSP::Channel.new
27
+
28
+ p1 = CSP::Process.new { c1.write(42) while true }
29
+ p2 = CSP::Process.new { c2.write(19) while true }
30
+
31
+ CSP.start(p1, p2)
32
+
33
+ assert_equal 42, CSP.select(c1, c2)
34
+ assert_equal 19, CSP.select(c2, c1)
35
+ end
36
+
37
+ should "skip if no previous guards was ready" do
38
+ c1 = CSP::Channel.new
39
+ c2 = CSP::Channel.new
40
+
41
+ CSP.select(c1, c2, CSP::SKIP)
42
+
43
+ assert true
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,19 @@
1
+
2
+ require 'rubygems'
3
+ require 'test/unit'
4
+ require 'shoulda'
5
+ require 'lib/csp'
6
+
7
+
8
+ class ProcessTest < Test::Unit::TestCase
9
+
10
+ should "create a process" do
11
+ a = []
12
+ p = CSP::Process.new { a << 42 }
13
+
14
+ CSP.start(p)
15
+
16
+ assert_equal [42], a
17
+ end
18
+
19
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: csp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Schierbeck
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-31 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Massive concurrency with message-passing and stuff.
17
+ email: daniel.schierbeck@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - .gitignore
26
+ - Rakefile
27
+ - VERSION
28
+ - lib/csp.rb
29
+ - lib/csp/channel.rb
30
+ - lib/csp/choice.rb
31
+ - lib/csp/process.rb
32
+ - lib/csp/scheduler.rb
33
+ - lib/csp/skip.rb
34
+ - test/channel_test.rb
35
+ - test/choice_test.rb
36
+ - test/process_test.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/dasch/ruby-csp
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --charset=UTF-8
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.3.5
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Concurrent Sequential Processes
65
+ test_files:
66
+ - test/choice_test.rb
67
+ - test/channel_test.rb
68
+ - test/process_test.rb