revactor 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ #--
2
+ # Copyright (C)2007 Tony Arcieri
3
+ # You can redistribute this under the terms of the Ruby license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ require File.dirname(__FILE__) + '/../lib/revactor'
8
+
9
+ describe Actor::Delegator do
10
+ before :each do
11
+ @obj = mock(:obj)
12
+ @delegator = Actor::Delegator.new(@obj)
13
+ end
14
+
15
+ it "delegates calls to the given object" do
16
+ @obj.should_receive(:foo).with(1)
17
+ @obj.should_receive(:bar).with(2)
18
+ @obj.should_receive(:baz).with(3)
19
+
20
+ @delegator.foo(1)
21
+ @delegator.bar(2)
22
+ @delegator.baz(3)
23
+ end
24
+
25
+ it "returns the value from calls to the delegate object" do
26
+ input_value = 42
27
+ output_value = 420
28
+
29
+ @obj.should_receive(:spiffy).with(input_value).and_return(input_value * 10)
30
+ @delegator.spiffy(input_value).should == output_value
31
+ end
32
+
33
+ it "captures exceptions in the delegate and raises them for the caller" do
34
+ ex = "crash!"
35
+
36
+ @obj.should_receive(:crashy_method).and_raise(ex)
37
+ proc { @delegator.crashy_method }.should raise_error(ex)
38
+ end
39
+
40
+ it "passes blocks along to the delegate" do
41
+ prc = proc { "yay" }
42
+
43
+ @obj.should_receive(:blocky).with(&prc)
44
+ @delegator.blocky(&prc)
45
+ end
46
+ end
@@ -22,63 +22,43 @@ describe Revactor::TCP do
22
22
  end
23
23
 
24
24
  it "connects to remote servers" do
25
- Actor.start do
26
- sock = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
27
- sock.should be_an_instance_of(Revactor::TCP::Socket)
28
- @server.accept.should be_an_instance_of(TCPSocket)
29
-
30
- sock.close
31
- @actor_run = true
32
- end
25
+ sock = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
26
+ sock.should be_an_instance_of(Revactor::TCP::Socket)
27
+ @server.accept.should be_an_instance_of(TCPSocket)
33
28
 
34
- @actor_run.should be_true
29
+ sock.close
35
30
  end
36
31
 
37
32
  it "listens for remote connections" do
38
- @server.close # Don't use it for this one...
33
+ @server.close # Don't use their server for this one...
39
34
 
40
- Actor.start do
41
- server = Revactor::TCP.listen(TEST_HOST, RANDOM_PORT)
42
- server.should be_an_instance_of(Revactor::TCP::Listener)
43
-
44
- s1 = TCPSocket.open(TEST_HOST, RANDOM_PORT)
45
- s2 = server.accept
46
-
47
- server.close
48
- s2.close
49
- @actor_run = true
50
- end
35
+ server = Revactor::TCP.listen(TEST_HOST, RANDOM_PORT)
36
+ server.should be_an_instance_of(Revactor::TCP::Listener)
51
37
 
52
- @actor_run.should be_true
38
+ s1 = TCPSocket.open(TEST_HOST, RANDOM_PORT)
39
+ s2 = server.accept
40
+
41
+ server.close
42
+ s2.close
53
43
  end
54
44
 
55
45
  it "reads data" do
56
- Actor.start do
57
- s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
58
- s2 = @server.accept
59
-
60
- s2.write 'foobar'
61
- s1.read(6).should == 'foobar'
62
-
63
- s1.close
64
- @actor_run = true
65
- end
46
+ s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
47
+ s2 = @server.accept
66
48
 
67
- @actor_run.should be_true
49
+ s2.write 'foobar'
50
+ s1.read(6).should == 'foobar'
51
+
52
+ s1.close
68
53
  end
69
54
 
70
55
  it "writes data" do
71
- Actor.start do
72
- s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
73
- s2 = @server.accept
74
-
75
- s1.write 'foobar'
76
- s2.read(6).should == 'foobar'
77
-
78
- s1.close
79
- @actor_run = true
80
- end
56
+ s1 = Revactor::TCP.connect(TEST_HOST, RANDOM_PORT)
57
+ s2 = @server.accept
58
+
59
+ s1.write 'foobar'
60
+ s2.read(6).should == 'foobar'
81
61
 
82
- @actor_run.should be_true
62
+ s1.close
83
63
  end
84
64
  end
@@ -6,24 +6,22 @@ begin_time = Time.now
6
6
 
7
7
  puts "#{begin_time.strftime('%H:%M:%S')} -- Sending #{NTIMES} messages"
8
8
 
9
- Actor.start do
10
- parent = Actor.current
11
- child = Actor.spawn do
12
- (NTIMES / 2).times do
13
- Actor.receive do |f|
14
- f.when(:foo) { parent << :bar }
15
- end
16
- end
17
- end
18
-
19
- child << :foo
9
+ parent = Actor.current
10
+ child = Actor.spawn do
20
11
  (NTIMES / 2).times do
21
12
  Actor.receive do |f|
22
- f.when(:bar) { child << :foo }
13
+ f.when(:foo) { parent << :bar }
23
14
  end
24
15
  end
25
16
  end
26
17
 
18
+ child << :foo
19
+ (NTIMES / 2).times do
20
+ Actor.receive do |f|
21
+ f.when(:bar) { child << :foo }
22
+ end
23
+ end
24
+
27
25
  end_time = Time.now
28
26
  duration = end_time - begin_time
29
27
  throughput = NTIMES / duration
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: revactor
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2008-01-15 00:00:00 -07:00
6
+ version: 0.1.1
7
+ date: 2008-01-28 00:00:00 -07:00
8
8
  summary: Revactor is an Actor implementation for writing high performance concurrent programs
9
9
  require_paths:
10
10
  - lib
@@ -31,13 +31,13 @@ authors:
31
31
  files:
32
32
  - lib/revactor
33
33
  - lib/revactor/actor.rb
34
- - lib/revactor/behaviors
35
- - lib/revactor/behaviors/server.rb
34
+ - lib/revactor/delegator.rb
36
35
  - lib/revactor/filters
37
36
  - lib/revactor/filters/line.rb
38
37
  - lib/revactor/filters/packet.rb
38
+ - lib/revactor/mailbox.rb
39
39
  - lib/revactor/mongrel.rb
40
- - lib/revactor/server.rb
40
+ - lib/revactor/scheduler.rb
41
41
  - lib/revactor/tcp.rb
42
42
  - lib/revactor.rb
43
43
  - examples/echo_server.rb
@@ -45,6 +45,7 @@ files:
45
45
  - examples/mongrel.rb
46
46
  - tools/messaging_throughput.rb
47
47
  - spec/actor_spec.rb
48
+ - spec/delegator_spec.rb
48
49
  - spec/line_filter_spec.rb
49
50
  - spec/packet_filter_spec.rb
50
51
  - spec/tcp_spec.rb
@@ -79,7 +80,7 @@ dependencies:
79
80
  requirements:
80
81
  - - ">="
81
82
  - !ruby/object:Gem::Version
82
- version: 0.1.3
83
+ version: 0.1.4
83
84
  version:
84
85
  - !ruby/object:Gem::Dependency
85
86
  name: case
@@ -88,5 +89,5 @@ dependencies:
88
89
  requirements:
89
90
  - - ">="
90
91
  - !ruby/object:Gem::Version
91
- version: "0.3"
92
+ version: "0.4"
92
93
  version:
@@ -1,87 +0,0 @@
1
- #--
2
- # Copyright (C)2007 Tony Arcieri
3
- # You can redistribute this under the terms of the Ruby license
4
- # See file LICENSE for details
5
- #++
6
-
7
- module Revactor
8
- module Behavior
9
- # The Server behavior provides a callback-driven class which eases the
10
- # creation of standard synchronous "blocking" calls by abstracting away
11
- # inter-Actor communication and also providing baked-in state management.
12
- #
13
- # This behavior module provides the base set of callbacks necessary
14
- # to implement the behavior. It also provides descriptions for what
15
- # certain callback methods should do.
16
- #
17
- # When used properly, the server behavior can implement transactional
18
- # semantics, ensuring only successful calls mutate the previous state
19
- # and erroneous/exception-raising ones do not.
20
- #
21
- # The design is modeled off Erlang/OTP's gen_server
22
- module Server
23
- # Initialize the server state. Can return:
24
- #
25
- # start(*args)
26
- # -> [:ok, state]
27
- # -> [:ok, state, timeout]
28
- # -> [:stop, reason]
29
- #
30
- # The state variable allows you to provide a set of state whose mutation
31
- # can be controlled a lot more closely than is possible with standard
32
- # object oriented behavior. The latest version of state is passed
33
- # to all Revactor::Server callbacks and is only mutated upon a
34
- # successful return (unless an exception was raised)
35
- #
36
- def start(*args)
37
- return :ok
38
- end
39
-
40
- # Handle any calls made to a Reactor::Server object, which are captured
41
- # via method_missing and dispatched here. Calls provide synchronous
42
- # behavior: the callee will block until this method completss and a
43
- # reply is sent back to them. Can return:
44
- #
45
- # handle_call(message, from, state)
46
- # -> [:reply, reply, new_state]
47
- # -> [:reply, reply, new_state, timeout]
48
- # -> [:noreply, new_state]
49
- # -> [:noreply, new_state, timeout]
50
- # -> [:stop, reason, reply, new_state]
51
- #
52
- def handle_call(message, from, state)
53
- return :reply, :ok, state
54
- end
55
-
56
- # Handle calls without return values
57
- #
58
- # handle_cast(message, state)
59
- # -> [:noreply, new_state]
60
- # -> [:noreply, new_state, timeout]
61
- # -> [:stop, reason, new_state]
62
- #
63
- def handle_cast(message, state)
64
- return :noreply, state
65
- end
66
-
67
- # Handle any spontaneous messages to the server which are not calls
68
- # or casts made from Rev::Server. Can return:
69
- #
70
- # handle_info(info, state)
71
- # -> [:noreply, new_state]
72
- # -> [:noreply, new_state, timeout]
73
- # -> [:stop, reason, new_state]
74
- #
75
- def handle_info(info, state)
76
- return :noreply, state
77
- end
78
-
79
- # Method called when the server is about to terminate, for example when
80
- # any of the handle_* routines above return :stop. The return value of
81
- # terminate is discarded.
82
- #
83
- def terminate(reason, state)
84
- end
85
- end
86
- end
87
- end
@@ -1,153 +0,0 @@
1
- #--
2
- # Copyright (C)2007 Tony Arcieri
3
- # You can redistribute this under the terms of the Ruby license
4
- # See file LICENSE for details
5
- #++
6
-
7
- require File.dirname(__FILE__) + '/../revactor'
8
-
9
- module Revactor
10
- # Revactor::Server wraps an Actor's receive loop and issues callbacks to
11
- # a class which implements Revactor::Behaviors::Server. It eases the
12
- # creation of standard synchronous "blocking" calls by abstracting away
13
- # inter-Actor communication and also providing baked-in state management.
14
- #
15
- # When used properly, Revactor::Server can implement transactional
16
- # semantics, ensuring only successful calls mutate the previous state
17
- # and erroneous/exception-raising ones do not.
18
- #
19
- # The design is modeled off Erlang/OTP's gen_server
20
- class Server
21
- # How long to wait for a response to a call before timing out
22
- # This value also borrowed from Erlang. More cargo culting!
23
- DEFAULT_CALL_TIMEOUT = 5
24
-
25
- # Create a new server. Accepts the following options:
26
- #
27
- # register: Register the Actor in the Actor registry under
28
- # the given term
29
- #
30
- # Any options passed after the options hash are passed to the
31
- # start method of the given object.
32
- #
33
- def initialize(obj, options = {}, *args)
34
- @obj = obj
35
- @timeout = nil
36
- @state = obj.start(*args)
37
- @actor = Actor.new(&method(:start).to_proc)
38
-
39
- Actor[options[:register]] = @actor if options[:register]
40
- end
41
-
42
- # Call the server with the given message
43
- def call(message, options = {})
44
- options[:timeout] ||= DEFAULT_CALL_TIMEOUT
45
-
46
- @actor << T[:call, Actor.current, message]
47
- Actor.receive do |filter|
48
- filter.when(Case[:call_reply, @actor, Object]) { |_, _, reply| reply }
49
- filter.when(Case[:call_error, @actor, Object]) { |_, _, ex| raise ex }
50
- filter.after(options[:timeout]) { raise 'timeout' }
51
- end
52
- end
53
-
54
- # Send a cast to the server
55
- def cast(message)
56
- @actor << T[:cast, message]
57
- message
58
- end
59
-
60
- #########
61
- protected
62
- #########
63
-
64
- # Start the server
65
- def start
66
- @running = true
67
- while @running do
68
- Actor.receive do |filter|
69
- filter.when(Object) { |message| handle_message(message) }
70
- filter.after(@timeout) { stop(:timeout) } if @timeout
71
- end
72
- end
73
- end
74
-
75
- # Dispatch the incoming message to the appropriate handler
76
- def handle_message(message)
77
- case message.first
78
- when :call then handle_call(message)
79
- when :cast then handle_cast(message)
80
- else handle_info(message)
81
- end
82
- end
83
-
84
- # Wrapper for calling the provided object's handle_call method
85
- def handle_call(message)
86
- _, from, body = message
87
-
88
- begin
89
- result = @obj.handle_call(body, from, @state)
90
- case result.first
91
- when :reply
92
- _, reply, @state, @timeout = result
93
- from << T[:call_reply, Actor.current, reply]
94
- when :noreply
95
- _, @state, @timeout = result
96
- when :stop
97
- _, reason, @state = result
98
- stop(reason)
99
- end
100
- rescue Exception => ex
101
- log_exception(ex)
102
- from << T[:call_error, Actor.current, ex]
103
- end
104
- end
105
-
106
- # Wrapper for calling the provided object's handle_cast method
107
- def handle_cast(message)
108
- _, body = message
109
-
110
- begin
111
- result = @obj.handle_cast(body, @state)
112
- case result.first
113
- when :noreply
114
- _, @state, @timeout = result
115
- when :stop
116
- _, reason, @state = result
117
- stop(reason)
118
- end
119
- rescue Exception => e
120
- log_exception(e)
121
- end
122
- end
123
-
124
- # Wrapper for calling the provided object's handle_info method
125
- def handle_info(message)
126
- begin
127
- result = @obj.handle_info(message, @state)
128
- case result.first
129
- when :noreply
130
- _, @state, @timeout = result
131
- when :stop
132
- _, reason, @state = result
133
- stop(reason)
134
- end
135
- rescue Exception => e
136
- log_exception(e)
137
- end
138
- end
139
-
140
- # Stop the server
141
- def stop(reason)
142
- @running = false
143
- @obj.terminate(reason, @state)
144
- end
145
-
146
- # Log an exception
147
- def log_exception(exception)
148
- # FIXME this should really go to a logger, not STDERR
149
- STDERR.puts "Rev::Server exception: #{exception}"
150
- STDERR.puts exception.backtrace
151
- end
152
- end
153
- end