ara 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.2"
12
+ gem "rcov", ">= 0"
13
+ end
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.6.2)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rake (0.9.2)
10
+ rcov (0.9.9)
11
+ shoulda (2.11.3)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ bundler (~> 1.0.0)
18
+ jeweler (~> 1.6.2)
19
+ rcov
20
+ shoulda
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Gregoire Lejeune
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,85 @@
1
+ = ara
2
+
3
+ \\
4
+ (o>
5
+ //\
6
+ ____V_/\____
7
+ //
8
+ //
9
+
10
+ Ara is a tiny class that's allow you to use actors[http://en.wikipedia.org/wiki/Actor_model] in Ruby
11
+
12
+ Documentation : http://rubydoc.info/github/glejeune/ara/master/frames
13
+
14
+ == Why "ara"
15
+
16
+ Because of akka[http://akka.io/] and my two parakeets ;)
17
+
18
+ == Synopsys
19
+
20
+ require 'ara'
21
+
22
+ # Define an actor
23
+ class MyActor < Actor
24
+ def receive(message)
25
+ puts "MyActor receive message : #{message}"
26
+ sleep rand(10)
27
+ reply "Thanks @ #{Time.now}!"
28
+ end
29
+ end
30
+
31
+ # This method will receive the actor' replies after sending it an asynchronous message
32
+ def actor_response(r)
33
+ puts "Actor reply : #{r}"
34
+ end
35
+
36
+ # Initialize and start the actor
37
+ myActor = Actor.actor_of(MyActor).start
38
+
39
+ # Send a simple message -- We do not expect any response
40
+ myActor | "Bonjour !"
41
+
42
+ # Send a synchronous message -- We wait for the response
43
+ response = myActor << "Hola !"
44
+
45
+ # Send an asynchronous message -- We don't wait for the response
46
+ myActor < "Hello !"
47
+
48
+ # main loop ;)
49
+ 12.times do |_|
50
+ puts "I'm the main... And I'm running"
51
+ sleep 1
52
+ end
53
+
54
+
55
+ == Changelog
56
+
57
+ === 0.0.1
58
+ * Initial version
59
+
60
+ == Contributing to ara
61
+
62
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
63
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
64
+ * Fork the project
65
+ * Start a feature/bugfix branch
66
+ * Commit and push until you are happy with your contribution
67
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
68
+ * 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.
69
+
70
+ == Copyright
71
+
72
+ Copyright (c) 2011 Gregoire Lejeune. See LICENSE.txt for
73
+ further details.
74
+
75
+ === binding_of_caller.rb
76
+
77
+ binding_of_caller.rb is part of the binding_of_caller[https://github.com/quix/binding_of_caller] project by James M. Lawrence
78
+
79
+ Copyright (c) 2011 James M. Lawrence. All rights reserved.
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
82
+
83
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
84
+
85
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "ara"
18
+ gem.homepage = "http://algorithmique.net"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A tiny Actor class}
21
+ gem.description = %Q{Ara is a tiny class that’s allow you to use actors in Ruby}
22
+ gem.email = "gregoire.lejeune@free.fr"
23
+ gem.authors = ["Gregoire Lejeune"]
24
+ gem.required_ruby_version = '>= 1.9.2'
25
+ # dependencies defined in Gemfile
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ test.rcov_opts << '--exclude "gems/*"'
42
+ end
43
+
44
+ task :default => :test
45
+
46
+ require 'rake/rdoctask'
47
+ Rake::RDocTask.new do |rdoc|
48
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "ara #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,78 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ara}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Gregoire Lejeune"]
12
+ s.date = %q{2011-07-14}
13
+ s.description = %q{Ara is a tiny class that’s allow you to use actors in Ruby}
14
+ s.email = %q{gregoire.lejeune@free.fr}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "ara.gemspec",
28
+ "examples/actor.erl",
29
+ "examples/actor.rb",
30
+ "examples/actor.scala",
31
+ "examples/async_actor.rb",
32
+ "examples/async_block.rb",
33
+ "examples/async_meth.rb",
34
+ "examples/logger_actor.rb",
35
+ "examples/simple_actor.rb",
36
+ "examples/simple_scheduler.rb",
37
+ "examples/sync_actor.rb",
38
+ "examples/test_actor.rb",
39
+ "lib/ara.rb",
40
+ "lib/ara/actor.rb",
41
+ "lib/ara/actors.rb",
42
+ "lib/ara/exception.rb",
43
+ "lib/ara/logger.rb",
44
+ "lib/ara/scheduler.rb",
45
+ "lib/ara/simple_actor.rb",
46
+ "lib/ext/binding_of_caller.rb",
47
+ "test/helper.rb",
48
+ "test/test_ara.rb"
49
+ ]
50
+ s.homepage = %q{http://algorithmique.net}
51
+ s.licenses = ["MIT"]
52
+ s.require_paths = ["lib"]
53
+ s.required_ruby_version = Gem::Requirement.new(">= 1.9.2")
54
+ s.rubygems_version = %q{1.6.2}
55
+ s.summary = %q{A tiny Actor class}
56
+
57
+ if s.respond_to? :specification_version then
58
+ s.specification_version = 3
59
+
60
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
61
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
62
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
63
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
64
+ s.add_development_dependency(%q<rcov>, [">= 0"])
65
+ else
66
+ s.add_dependency(%q<shoulda>, [">= 0"])
67
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
68
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
69
+ s.add_dependency(%q<rcov>, [">= 0"])
70
+ end
71
+ else
72
+ s.add_dependency(%q<shoulda>, [">= 0"])
73
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
74
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
75
+ s.add_dependency(%q<rcov>, [">= 0"])
76
+ end
77
+ end
78
+
@@ -0,0 +1,21 @@
1
+ %% Usage :
2
+ %%
3
+ %% c(actor).
4
+ %% Pid = spawn(fun actor:myActor/0).
5
+ %% Pid ! {mult, 4}.
6
+ %%
7
+ -module(actor).
8
+ -export([myActor/0]).
9
+
10
+ myActor() ->
11
+ receive
12
+ {mult, X} ->
13
+ io:format(standard_io, "~w * ~w = ~w~n", [X, X, X*X]),
14
+ myActor();
15
+ {add, X} ->
16
+ io:format(standard_io, "~w + ~w = ~w~n", [X, X, X+X]),
17
+ myActor();
18
+ Other ->
19
+ io:format(standard_io, "Don't know what to do with message : ~w~n", [Other]),
20
+ myActor()
21
+ end.
@@ -0,0 +1,27 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MyActor < Actor
5
+ def receive(message)
6
+ action = message[0]
7
+ value = message[1]
8
+ case action
9
+ when :mult then
10
+ puts "#{value} * #{value} = #{value * value}"
11
+ when :add then
12
+ puts "#{value} + #{value} = #{value + value}"
13
+ else
14
+ puts "Don't know what to do with message : #{message}"
15
+ end
16
+ end
17
+ end
18
+
19
+ myActor = Actors.actor_of(MyActor).start
20
+
21
+ myActor | [:mult, 4]
22
+ myActor | [:add, 4]
23
+ myActor | [:something, 4]
24
+
25
+ sleep 2
26
+
27
+ myActor.stop
@@ -0,0 +1,28 @@
1
+ import scala.actors.Actor
2
+
3
+ case class Mult(value: Int)
4
+ case class Add(value: Int)
5
+ case class Something(value: Int)
6
+ case object Stop
7
+
8
+ class MyActor extends Actor {
9
+ def act() {
10
+ loop {
11
+ receive {
12
+ case Mult(value) => println(value + " * " + value + " = " + value * value)
13
+ case Add(value) => println(value + " + " + value + " = " + (value + value))
14
+ case Stop => exit()
15
+ case msg => println("Don't know what to do with message :" + msg)
16
+ }
17
+ }
18
+ }
19
+ }
20
+
21
+ val myActor = new MyActor()
22
+ myActor.start
23
+
24
+ myActor ! Mult(4)
25
+ myActor ! Add(4)
26
+ myActor ! Something(4)
27
+
28
+ myActor ! Stop
@@ -0,0 +1,25 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MyASynchronizedActor < Actor
5
+ def receive(message)
6
+ puts "Actor #{self} receive message : #{message}"
7
+ sleep rand(10)
8
+ reply "Thanks @ #{Time.now}!"
9
+ end
10
+ end
11
+
12
+ def actor_response(r)
13
+ puts "Actor send me : #{r}"
14
+ end
15
+
16
+ myASynchromizedActor = Actors.actor_of(MyASynchronizedActor).start
17
+ myASynchromizedActor < "Hello !"
18
+
19
+ puts "Message send to actor, response will arrive ;)"
20
+
21
+ 12.times do |_|
22
+ puts "I'm the main... And I'm running"
23
+ sleep 1
24
+ end
25
+
@@ -0,0 +1,23 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MyASynchronizedActor < Actor
5
+ def receive(message)
6
+ puts "Actor #{self} receive message : #{message}"
7
+ sleep rand(10)
8
+ reply "Thanks @ #{Time.now}!"
9
+ end
10
+ end
11
+
12
+ myASynchromizedActor = Actors.actor_of(MyASynchronizedActor).start
13
+ myASynchromizedActor.async_message("Hello !") do |r|
14
+ puts "Actor send me : #{r}"
15
+ end
16
+
17
+ puts "Message send to actor, response will arrive ;)"
18
+
19
+ 12.times do |_|
20
+ puts "I'm the main... And I'm running"
21
+ sleep 1
22
+ end
23
+
@@ -0,0 +1,25 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MyASynchronizedActor < Actor
5
+ def receive(message)
6
+ puts "Actor #{self} receive message : #{message}"
7
+ sleep rand(10)
8
+ reply "Thanks @ #{Time.now}!"
9
+ end
10
+ end
11
+
12
+ def my_response(r)
13
+ puts "Actor send me : #{r}"
14
+ end
15
+
16
+ myASynchromizedActor = Actors.actor_of(MyASynchronizedActor).start
17
+ myASynchromizedActor.async_message("Hello !", :my_response)
18
+
19
+ puts "Message send to actor, response will arrive ;)"
20
+
21
+ 12.times do |_|
22
+ puts "I'm the main... And I'm running"
23
+ sleep 1
24
+ end
25
+
@@ -0,0 +1,34 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ Ara.logger = Logger.new("actor.log")
5
+ Ara.logger.debug "Starting..."
6
+
7
+ class MySimpleActor < SimpleActor
8
+ def receive( message )
9
+ Ara.logger.debug "Actor #{self} receive message : #{message}"
10
+ end
11
+ end
12
+
13
+ mySimpleActor = Actors.actor_of(MySimpleActor).start
14
+ mySimpleActor | "Bonjour le monde!"
15
+
16
+ sleep 1
17
+
18
+ mySimpleActor | "Hello World!"
19
+ mySimpleActor | "Ola Mundo!"
20
+
21
+ sleep 1
22
+
23
+ mySimpleActor.stop
24
+
25
+ sleep 1
26
+
27
+ Ara.logger.debug "Ending..."
28
+
29
+ # This will raise an exception
30
+ begin
31
+ mySimpleActor | "Hum..."
32
+ rescue DeadActor => e
33
+ puts e
34
+ end
@@ -0,0 +1,29 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MySimpleActor < SimpleActor
5
+ def receive( message )
6
+ puts "Actor #{self} receive message : #{message}"
7
+ end
8
+ end
9
+
10
+ mySimpleActor = Actors.actor_of(MySimpleActor).start
11
+ mySimpleActor | "Bonjour le monde!"
12
+
13
+ sleep 1
14
+
15
+ mySimpleActor | "Hello World!"
16
+ mySimpleActor | "Ola Mundo!"
17
+
18
+ sleep 1
19
+
20
+ mySimpleActor.stop
21
+
22
+ sleep 1
23
+
24
+ # This will raise an exception
25
+ begin
26
+ mySimpleActor | "Hum..."
27
+ rescue DeadActor => e
28
+ puts e
29
+ end
@@ -0,0 +1,22 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MySimpleActor < SimpleActor
5
+ def receive( message )
6
+ puts "Actor #{self} receive message : #{message}"
7
+ end
8
+ end
9
+
10
+ my_actor = Actors.actor_of(MySimpleActor).start
11
+
12
+ sched_one = Scheduler.schedule(my_actor, "Hello World! (every 1 second)", 1, 1, Scheduler::SECOND)
13
+ sched_two = Scheduler.schedule_once(my_actor, "Hello World! (once after 4 second)", 4, Scheduler::SECOND)
14
+
15
+ sleep 10
16
+
17
+ sched_one.shutdown
18
+ puts "-- Scheduler has been shutdown! We wait 5 second to be sure ;)"
19
+
20
+ sleep 5
21
+
22
+ my_actor.stop
@@ -0,0 +1,13 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MySynchronizedActor < Actor
5
+ def receive(message)
6
+ puts "Actor #{self} receive message : #{message}"
7
+ sleep rand(10)
8
+ reply "Thanks @ #{Time.now}!"
9
+ end
10
+ end
11
+
12
+ mySynchromizedActor = Actors.actor_of(MySynchronizedActor).start
13
+ puts mySynchromizedActor << "Hello !"
@@ -0,0 +1,28 @@
1
+ $:.unshift("../lib")
2
+ require 'ara'
3
+
4
+ class MySimpleActor < SimpleActor
5
+ def receive( message )
6
+ id = rand(10)
7
+ puts "I'm actor #{self} with ID##{id}"
8
+ if message.class == Fixnum
9
+ message.times do |i|
10
+ puts "#{id} : #{i}"
11
+ sleep 0.5
12
+ end
13
+ else
14
+ puts "Don't know what to do with your message : #{message}"
15
+ end
16
+ end
17
+ end
18
+
19
+ mySimpleActor = Actors.actor_of(MySimpleActor).start
20
+ mySimpleActor | 5
21
+ mySimpleActor | "Hello World!"
22
+ mySimpleActor | 7
23
+ mySimpleActor | 9
24
+
25
+ puts "Thanks actor!"
26
+ sleep 20
27
+
28
+ mySimpleActor.stop
@@ -0,0 +1,8 @@
1
+ require 'thread'
2
+
3
+ require 'ara/exception'
4
+ require 'ara/logger'
5
+ require 'ara/simple_actor'
6
+ require 'ara/actor'
7
+ require 'ara/actors'
8
+ require 'ara/scheduler'
@@ -0,0 +1,75 @@
1
+ require 'ara/exception'
2
+ require 'ara/simple_actor'
3
+
4
+ # Actor class
5
+ class Actor < SimpleActor
6
+ def initialize #:nodoc:
7
+ raise ActorInitializationError, "You can't initialize Actor directly, use Actors.actor_of" if self.class == ::Actor
8
+ super
9
+ @main = Queue.new
10
+ end
11
+
12
+ # Send a synchronous message
13
+ #
14
+ # myActor = Actors.actor_of(MyActor).start
15
+ # message = ...
16
+ # result = myActor << message
17
+ #
18
+ # All code after this call will be executed only when the actor has finished it's work
19
+ def <<(message)
20
+ if @thread.alive?
21
+ @actorQueue << message
22
+ @main.pop
23
+ else
24
+ raise DeadActor, "Actor is dead!"
25
+ end
26
+ end
27
+ alias :sync_message :<<
28
+
29
+ # Send an asynchronous message
30
+ #
31
+ # myActor = Actors.actor_of(MyActor).start
32
+ # message = ...
33
+ # myActor < message
34
+ #
35
+ # The code after this call will be executed without waiting the actor. You must add a <tt>result</tt> method to get the actor' reponse.
36
+ def <(message, response_method = nil)
37
+ if @thread.alive?
38
+ @actorQueue << message
39
+ BindingOfCaller.binding_of_caller do |bind|
40
+ self_of_caller = eval("self", bind)
41
+ Thread.new do
42
+ _result = @main.pop
43
+ begin
44
+ if block_given?
45
+ yield _result
46
+ elsif response_method != nil
47
+ self_of_caller.send( response_method.to_sym, _result )
48
+ else
49
+ self_of_caller.send( :actor_response, _result )
50
+ end
51
+ rescue => e
52
+ raise ActorResponseError, "Error while sending response : #{e}"
53
+ end
54
+ end
55
+ end
56
+ else
57
+ raise DeadActor, "Actor is dead!"
58
+ end
59
+ end
60
+ alias :async_message :<
61
+
62
+ private
63
+ # Method use by the actor to reply to his sender
64
+ #
65
+ # class MyActor < Actor
66
+ # def receive(message)
67
+ # ...
68
+ # something = ...
69
+ # reply( something )
70
+ # end
71
+ # end
72
+ def reply( r )
73
+ @main << r
74
+ end
75
+ end
@@ -0,0 +1,16 @@
1
+ # Actors class
2
+ class Actors
3
+ # Create a new Actor with class klass
4
+ #
5
+ # class MyActor < Actor
6
+ # def receive(message)
7
+ # ...
8
+ # end
9
+ # end
10
+ #
11
+ # myActor = Actors.actor_of(MyActor)
12
+ def self.actor_of(klass)
13
+ return klass.new()
14
+ end
15
+ end
16
+
@@ -0,0 +1,8 @@
1
+ class DeadActor < Exception #:nodoc:
2
+ end
3
+ class UndefinedResultMethod < Exception #:nodoc:
4
+ end
5
+ class ActorInitializationError < Exception #:nodoc:
6
+ end
7
+ class ActorResponseError < Exception #:nodoc:
8
+ end
@@ -0,0 +1,29 @@
1
+ require 'logger'
2
+ require 'singleton'
3
+
4
+ module Ara
5
+ def self.logger
6
+ return L.instance.logger
7
+ end
8
+
9
+ def self.logger=(l)
10
+ L.instance.logger=l
11
+ end
12
+
13
+ class L #:nodoc:
14
+ include Singleton
15
+
16
+ def initialize
17
+ @mutex = Mutex.new
18
+ @logger = Logger.new STDERR
19
+ end
20
+
21
+ def logger
22
+ @mutex.synchronize { @logger }
23
+ end
24
+
25
+ def logger=(l)
26
+ @mutex.synchronize { @logger=l }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,144 @@
1
+ require 'singleton'
2
+
3
+ module Scheduler
4
+ SECOND = 1
5
+ MINUTE = 60 * SECOND
6
+ HOUR = 60 * MINUTE
7
+ DAY = 25 * HOUR
8
+ WEEK = 7 * DAY
9
+ MONTH = (365 * DAY) / 12
10
+ YEAR = 365 * DAY
11
+
12
+ # Create a scheduler to send the message <tt>message</tt> to actor <tt>receiver_actor</tt> every <tt>delay_between_messages</tt> <tt>time_unit</tt>
13
+ # with an initial delay of <tt>initial_delay_before_send</tt> <tt>time_unit</tt>
14
+ def self.schedule(receiver_actor, message, initial_delay_before_send, delay_between_messages, time_unit)
15
+ action = Action.new(receiver_actor, message, initial_delay_before_send, delay_between_messages, time_unit)
16
+ actions.add(action)
17
+ action.start
18
+ yield action if block_given?
19
+ action
20
+ end
21
+
22
+ # Create a scheduler to send the message <tt>message</tt> to actor <tt>receiver_actor</tt> after <tt>delay_until_send</tt> <tt>time_unit</tt>
23
+ def self.schedule_once(receiver_actor, message, delay_until_send, time_unit)
24
+ action = Action.new(receiver_actor, message, delay_until_send, nil, time_unit)
25
+ actions.add(action)
26
+ action.start
27
+ yield action if block_given?
28
+ action
29
+ end
30
+
31
+ # Shutdown all scheduled actions
32
+ def self.shutdown
33
+ actions.each { |a| a.shutdown }
34
+ end
35
+
36
+ # Restart all scheduled actions
37
+ def self.restart
38
+ actions.each { |a| a.rstart }
39
+ end
40
+
41
+ # Stop all scheduled actions
42
+ def self.stop
43
+ actions.each { |a| a.stop }
44
+ end
45
+
46
+ # Pause all scheduled actions
47
+ def self.pause
48
+ actions.each { |a| a.pause }
49
+ end
50
+
51
+ # Return all actions
52
+ def self.actions
53
+ Scheduler::Actions.instance
54
+ end
55
+
56
+ class Actions #:nodoc:
57
+ include Singleton
58
+
59
+ def initialize
60
+ @mutex = Mutex.new
61
+ @actions = Array.new
62
+ end
63
+
64
+ def add(a)
65
+ @mutex.synchronize { @actions << a }
66
+ end
67
+
68
+ def remove(a)
69
+ @mutex.synchronize { @actions.delete(a) }
70
+ end
71
+
72
+ def remove_all
73
+ @mutex.synchronize { @actions.each { |a| @actions.delete(a) } }
74
+ end
75
+
76
+ def include?(a)
77
+ @mutex.synchronize { @actions.include?(a) }
78
+ end
79
+
80
+ def each(&b)
81
+ @mutex.synchronize { @actions.each { |a| yield a } }
82
+ end
83
+ end
84
+
85
+ class Action
86
+ def initialize(receiver_actor, message, initial_delay, delay, time_unit) #:nodoc:
87
+ @receiver_actor = receiver_actor
88
+ @message = message
89
+ @initial_delay = initial_delay
90
+ @delay = delay
91
+ @time_unit = time_unit
92
+
93
+ @once = delay == nil
94
+ @current_delay = @initial_delay
95
+
96
+ @thread = nil
97
+ end
98
+
99
+ # Start the action
100
+ def start
101
+ return unless Scheduler.actions.include?(self)
102
+ @thread = Thread.new {
103
+ while(true)
104
+ run
105
+ @current_delay = @delay
106
+ if @current_delay.nil?
107
+ break
108
+ end
109
+ end
110
+ shutdown
111
+ }
112
+ end
113
+
114
+ # Stop the action
115
+ def stop
116
+ @current_delay = @initial_delay
117
+ pause
118
+ end
119
+
120
+ # Pause the action
121
+ def pause
122
+ @thread.kill
123
+ @thread = nil
124
+ end
125
+
126
+ # Restart the action
127
+ def restart
128
+ stop unless @thread.nil?
129
+ start
130
+ end
131
+
132
+ # Shutdown the action
133
+ def shutdown
134
+ stop
135
+ Scheduler.actions.remove(self)
136
+ end
137
+
138
+ private
139
+ def run
140
+ sleep(1 * @current_delay * @time_unit)
141
+ @receiver_actor | @message
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,61 @@
1
+ require 'ext/binding_of_caller'
2
+ require 'ara/exception'
3
+
4
+ # This class allow you to create simple actors.
5
+ class SimpleActor
6
+ def initialize #:nodoc:
7
+ raise ActorInitializationError, "You can't initialize SimpleActor directly, use Actors.actor_of" if self.class == ::SimpleActor
8
+ @actorQueue = Queue.new
9
+ end
10
+
11
+ # Start actor and return it
12
+ #
13
+ # myActor = Actors.actor_of(MyActor)
14
+ # myActor.start
15
+ def start
16
+ @thread = Thread.new do
17
+ loop do
18
+ receive(@actorQueue.pop)
19
+ end
20
+ end
21
+
22
+ return self
23
+ end
24
+
25
+ # Stop actor
26
+ #
27
+ # myActor = Actors.actor_of(MyActor).start
28
+ # ...
29
+ # myActor.stop
30
+ def stop
31
+ @thread.kill
32
+ end
33
+
34
+ # Send a simple message without expecting any response
35
+ #
36
+ # myActor = Actors.actor_of(MyActor).start
37
+ # message = ...
38
+ # myActor | message
39
+ def |(message)
40
+ if @thread.alive?
41
+ @actorQueue << message
42
+ else
43
+ raise DeadActor, "Actor is dead!"
44
+ end
45
+ end
46
+ alias :message :|
47
+
48
+ private
49
+ # Method receiver for the actor
50
+ #
51
+ # When you create an actor (simple or not) you *must* define a <tt>receive</tt> method.
52
+ #
53
+ # class MyActor < Actor
54
+ # def receive(message)
55
+ # ...
56
+ # end
57
+ # end
58
+ def receive(message)
59
+ raise "Define me!"
60
+ end
61
+ end
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2011 James M. Lawrence. All rights reserved.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation files
5
+ # (the "Software"), to deal in the Software without restriction,
6
+ # including without limitation the rights to use, copy, modify, merge,
7
+ # publish, distribute, sublicense, and/or sell copies of the Software,
8
+ # and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18
+ # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19
+ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'continuation'
24
+
25
+ module BindingOfCaller
26
+ VERSION = "0.1.3"
27
+
28
+ module_function
29
+
30
+ def binding_of_caller
31
+ cont = nil
32
+ event_count = 0
33
+
34
+ tracer = lambda do |event, _, _, _, binding, _|
35
+ event_count += 1
36
+ if event_count == 4
37
+ Thread.current.set_trace_func(nil)
38
+ case event
39
+ when "return", "line", "end"
40
+ cont.call(nil, binding)
41
+ else
42
+ error_msg = "\n" <<
43
+ "Invalid use of binding_of_caller. One of the following:\n" <<
44
+ " (1) statements exist after the binding_of_caller block;\n" <<
45
+ " (2) the method using binding_of_caller appears inside\n" <<
46
+ " a method call;\n" <<
47
+ " (3) the method using binding_of_caller is called from the\n" <<
48
+ " last line of a block or global scope.\n" <<
49
+ "See the documentation for binding_of_caller.\n"
50
+ cont.call(nil, nil, lambda { raise(ScriptError, error_msg) })
51
+ end
52
+ end
53
+ end
54
+
55
+ cont, result, error = callcc { |cc| cc }
56
+ if cont
57
+ Thread.current.set_trace_func(tracer)
58
+ elsif result
59
+ yield result
60
+ else
61
+ error.call
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'ara'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,13 @@
1
+ require 'helper'
2
+
3
+ class MySimpleActor < SimpleActor
4
+ def receive(m)
5
+ end
6
+ end
7
+
8
+ class TestAra < Test::Unit::TestCase
9
+ should "create a simple actor" do
10
+ simple_actor = Actors.actor_of(MySimpleActor)
11
+ assert simple_actor != nil
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ara
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Gregoire Lejeune
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-14 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: shoulda
17
+ requirement: &2151807640 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2151807640
26
+ - !ruby/object:Gem::Dependency
27
+ name: bundler
28
+ requirement: &2151806340 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2151806340
37
+ - !ruby/object:Gem::Dependency
38
+ name: jeweler
39
+ requirement: &2151804400 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.6.2
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *2151804400
48
+ - !ruby/object:Gem::Dependency
49
+ name: rcov
50
+ requirement: &2151802760 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *2151802760
59
+ description: Ara is a tiny class that’s allow you to use actors in Ruby
60
+ email: gregoire.lejeune@free.fr
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - LICENSE.txt
65
+ - README.rdoc
66
+ files:
67
+ - .document
68
+ - Gemfile
69
+ - Gemfile.lock
70
+ - LICENSE.txt
71
+ - README.rdoc
72
+ - Rakefile
73
+ - VERSION
74
+ - ara.gemspec
75
+ - examples/actor.erl
76
+ - examples/actor.rb
77
+ - examples/actor.scala
78
+ - examples/async_actor.rb
79
+ - examples/async_block.rb
80
+ - examples/async_meth.rb
81
+ - examples/logger_actor.rb
82
+ - examples/simple_actor.rb
83
+ - examples/simple_scheduler.rb
84
+ - examples/sync_actor.rb
85
+ - examples/test_actor.rb
86
+ - lib/ara.rb
87
+ - lib/ara/actor.rb
88
+ - lib/ara/actors.rb
89
+ - lib/ara/exception.rb
90
+ - lib/ara/logger.rb
91
+ - lib/ara/scheduler.rb
92
+ - lib/ara/simple_actor.rb
93
+ - lib/ext/binding_of_caller.rb
94
+ - test/helper.rb
95
+ - test/test_ara.rb
96
+ has_rdoc: true
97
+ homepage: http://algorithmique.net
98
+ licenses:
99
+ - MIT
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 1.9.2
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 1.6.2
119
+ signing_key:
120
+ specification_version: 3
121
+ summary: A tiny Actor class
122
+ test_files: []