ntl-actor 0.3.1 → 0.4.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/actor/actor.rb +7 -147
  3. data/lib/actor/address.rb +18 -0
  4. data/lib/actor/controls/actor.rb +27 -40
  5. data/lib/actor/controls/address.rb +48 -0
  6. data/lib/actor/controls/error.rb +17 -0
  7. data/lib/actor/controls/message/attribute.rb +17 -0
  8. data/lib/actor/controls/message.rb +23 -1
  9. data/lib/actor/controls/thread.rb +9 -0
  10. data/lib/actor/controls/uuid.rb +15 -0
  11. data/lib/actor/controls.rb +6 -10
  12. data/lib/actor/destructure.rb +23 -0
  13. data/lib/actor/{time_unit.rb → duration.rb} +1 -1
  14. data/lib/actor/messages.rb +15 -0
  15. data/lib/actor/messaging/message.rb +5 -0
  16. data/lib/actor/messaging/{writer → read}/substitute.rb +13 -10
  17. data/lib/actor/messaging/read.rb +50 -0
  18. data/lib/actor/messaging/write/substitute.rb +39 -0
  19. data/lib/actor/messaging/write.rb +26 -0
  20. data/lib/actor/module/build.rb +20 -0
  21. data/lib/actor/module/handle_macro.rb +39 -0
  22. data/lib/actor/module/start.rb +19 -0
  23. data/lib/actor/module.rb +73 -0
  24. data/lib/actor/router.rb +79 -0
  25. data/lib/actor/start.rb +46 -0
  26. data/lib/actor/stream.rb +36 -0
  27. data/lib/actor/substitutes/kernel.rb +23 -0
  28. data/lib/actor/substitutes/thread.rb +39 -0
  29. data/lib/actor/substitutes/thread_group.rb +26 -0
  30. data/lib/actor/supervisor.rb +46 -52
  31. data/lib/actor.rb +22 -14
  32. metadata +29 -29
  33. data/lib/actor/controls/statistics/elapsed_time/average.rb +0 -21
  34. data/lib/actor/controls/statistics/elapsed_time/maximum.rb +0 -21
  35. data/lib/actor/controls/statistics/elapsed_time/minimum.rb +0 -21
  36. data/lib/actor/controls/statistics/elapsed_time/standard_deviation.rb +0 -38
  37. data/lib/actor/controls/statistics/elapsed_time.rb +0 -15
  38. data/lib/actor/controls/statistics/timer.rb +0 -19
  39. data/lib/actor/controls/statistics.rb +0 -21
  40. data/lib/actor/controls/time/clock.rb +0 -31
  41. data/lib/actor/controls/time.rb +0 -24
  42. data/lib/actor/message.rb +0 -23
  43. data/lib/actor/messaging/address.rb +0 -40
  44. data/lib/actor/messaging/reader/substitute.rb +0 -40
  45. data/lib/actor/messaging/reader.rb +0 -31
  46. data/lib/actor/messaging/writer.rb +0 -26
  47. data/lib/actor/queue/assertions.rb +0 -13
  48. data/lib/actor/queue/reader.rb +0 -57
  49. data/lib/actor/queue.rb +0 -122
  50. data/lib/actor/statistics/copy.rb +0 -19
  51. data/lib/actor/statistics/timer.rb +0 -26
  52. data/lib/actor/statistics.rb +0 -75
  53. data/lib/actor/test_fixtures/parallel_iteration.rb +0 -143
  54. data/lib/actor/test_fixtures/sample_actor_status.rb +0 -45
  55. data/lib/actor/test_fixtures.rb +0 -4
@@ -0,0 +1,39 @@
1
+ module Actor
2
+ module Module
3
+ module HandleMacro
4
+ def handle_macro pattern, &action
5
+ method_name = MethodName.get pattern
6
+
7
+ define_method method_name, &action
8
+ end
9
+ alias_method :handle, :handle_macro
10
+
11
+ module MethodName
12
+ PATTERN = %r{(?:\A|[a-z0-9])[A-Z]}
13
+
14
+ def self.get message_pattern
15
+ case message_pattern
16
+ when Class, String then
17
+ message_name = message_pattern.to_s
18
+
19
+ *, message_name = message_name.split '::'
20
+
21
+ message_name.gsub! PATTERN do |str|
22
+ str.downcase!
23
+ str.insert 1, '_' if str.length == 2
24
+ str
25
+ end
26
+
27
+ get message_name.to_sym
28
+
29
+ when Symbol then
30
+ :"handle_#{message_pattern}"
31
+
32
+ else
33
+ get message_pattern.class
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ module Actor
2
+ module Module
3
+ module Start
4
+ def start *positional_arguments, address: nil, supervisor_address: nil, include: nil, **keyword_arguments, &block
5
+ address ||= Address.build
6
+
7
+ instance = build address, *positional_arguments, **keyword_arguments, &block
8
+
9
+ thread = Actor::Start.(
10
+ instance,
11
+ address,
12
+ supervisor_address: supervisor_address
13
+ )
14
+
15
+ Destructure.(address, include, { :thread => thread, :actor => instance })
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,73 @@
1
+ module Actor
2
+ module Module
3
+ def self.included cls
4
+ cls.class_exec do
5
+ extend Build
6
+ extend HandleMacro
7
+ extend Start
8
+ end
9
+ end
10
+
11
+ attr_writer :reader
12
+ attr_writer :writer
13
+
14
+ def configure
15
+ end
16
+
17
+ def continuations
18
+ @continuations ||= []
19
+ end
20
+
21
+ def handle message
22
+ method = handle? message
23
+
24
+ return if method.nil?
25
+
26
+ if method.arity == 0
27
+ method.()
28
+ else
29
+ method.(message)
30
+ end
31
+ end
32
+
33
+ def handle_stop
34
+ raise StopIteration
35
+ end
36
+
37
+ def handle? message
38
+ method_name = HandleMacro::MethodName.get message
39
+
40
+ if respond_to? method_name
41
+ method method_name
42
+ end
43
+ end
44
+
45
+ def next
46
+ if continuations.empty?
47
+ message = reader.(wait: true)
48
+ else
49
+ message = reader.(wait: false)
50
+ message ||= continuations.shift
51
+ end
52
+
53
+ continuation_message = handle message
54
+
55
+ if continuation_message.is_a? Messaging::Message
56
+ continuations << continuation_message
57
+ end
58
+ end
59
+
60
+ def run_loop
61
+ loop do self.next end
62
+ end
63
+ alias_method :start, :run_loop
64
+
65
+ def reader
66
+ @reader ||= Messaging::Read::Substitute.new
67
+ end
68
+
69
+ def writer
70
+ @writer ||= Messaging::Write::Substitute.new
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,79 @@
1
+ module Actor
2
+ class Router
3
+ include Actor
4
+
5
+ attr_writer :kernel
6
+ attr_reader :routes
7
+
8
+ def initialize
9
+ @routes = Hash.new do |hash, input|
10
+ hash[input] = Set.new
11
+ end
12
+ end
13
+
14
+ handle :start do
15
+ :continue
16
+ end
17
+
18
+ handle :continue do
19
+ routed_messages = false
20
+
21
+ routes.each do |input_reader, outputs|
22
+ msg = input_reader.(wait: false)
23
+
24
+ next unless msg
25
+
26
+ routed_messages = true
27
+
28
+ outputs.each do |output|
29
+ writer.(msg, output)
30
+ end
31
+ end
32
+
33
+ unless routed_messages
34
+ kernel.sleep Duration.millisecond
35
+ end
36
+
37
+ :continue
38
+ end
39
+
40
+ handle :add_route do |message|
41
+ reader = message.reader
42
+ output_address = message.output_address
43
+
44
+ add reader, output_address
45
+ end
46
+
47
+ handle :remove_route do |message|
48
+ reader = message.reader
49
+ output_address = message.output_address
50
+
51
+ remove reader, output_address
52
+ end
53
+
54
+ def add reader, output_address
55
+ routes[reader] << output_address
56
+ end
57
+
58
+ def remove reader, output_address
59
+ routes[reader].delete output_address
60
+ end
61
+
62
+ def configure
63
+ self.kernel = Kernel
64
+ end
65
+
66
+ def kernel
67
+ @kernel ||= Substitutes::Kernel.new
68
+ end
69
+
70
+ AddRoute = Struct.new :reader, :output_address
71
+ RemoveRoute = Struct.new :reader, :output_address
72
+
73
+ module Assertions
74
+ def route? reader, output_address
75
+ routes[reader].include? output_address
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,46 @@
1
+ module Actor
2
+ class Start
3
+ attr_writer :supervisor_address
4
+ attr_writer :thread
5
+ attr_writer :writer
6
+
7
+ def self.build supervisor_address: nil
8
+ instance = new
9
+ instance.supervisor_address = supervisor_address
10
+ instance.thread = Thread
11
+ Messaging::Write.configure instance
12
+ instance
13
+ end
14
+
15
+ def self.call actor, address, supervisor_address: nil
16
+ instance = build supervisor_address: supervisor_address
17
+ instance.(actor, address)
18
+ end
19
+
20
+ def call actor, address
21
+ address ||= Address.build
22
+
23
+ start = Messages::Start.new
24
+ writer.(start, address)
25
+
26
+ actor_started = Messages::ActorStarted.new address
27
+ writer.(actor_started, supervisor_address)
28
+
29
+ self.thread.new do
30
+ actor.start
31
+ end
32
+ end
33
+
34
+ def supervisor_address
35
+ @supervisor_address ||= Address::None
36
+ end
37
+
38
+ def thread
39
+ @thread ||= Substitutes::Thread
40
+ end
41
+
42
+ def writer
43
+ @writer ||= Messaging::Write::Substitute.new
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,36 @@
1
+ module Actor
2
+ class Stream
3
+ attr_reader :queues
4
+
5
+ def initialize
6
+ @queues = Set.new
7
+ end
8
+
9
+ def add_queue queue
10
+ queues << queue
11
+ end
12
+
13
+ def remove_queue queue
14
+ queues.delete queue
15
+ end
16
+
17
+ def write message
18
+ queues.each do |queue|
19
+ queue.enq message
20
+ end
21
+ end
22
+
23
+ module Null
24
+ extend self
25
+
26
+ def add_queue queue
27
+ end
28
+
29
+ def remove_queue queue
30
+ end
31
+
32
+ def write message
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ module Actor
2
+ module Substitutes
3
+ class Kernel
4
+ def initialize
5
+ @sleep_duration = nil
6
+ end
7
+
8
+ def sleep duration=nil
9
+ @sleep_duration = duration
10
+ end
11
+
12
+ module Assertions
13
+ def slept? duration=nil
14
+ if duration.nil?
15
+ @sleep_duration ? true : false
16
+ else
17
+ @sleep_duration == duration
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ module Actor
2
+ module Substitutes
3
+ class Thread
4
+ attr_reader :block
5
+ attr_accessor :name
6
+ attr_accessor :priority
7
+ attr_accessor :status
8
+
9
+ def initialize &block
10
+ @status = 'run'
11
+ @priority = 0
12
+
13
+ @block = block
14
+ end
15
+
16
+ def join limit=nil
17
+ if limit
18
+ begin
19
+ Timeout.timeout limit, &block
20
+ rescue Timeout::Error
21
+ return nil
22
+ end
23
+ else
24
+ block.()
25
+ end
26
+
27
+ self
28
+ end
29
+
30
+ def alive?
31
+ %w(sleep run).include? status
32
+ end
33
+
34
+ def stop?
35
+ status != 'run'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module Actor
2
+ module Substitutes
3
+ class ThreadGroup
4
+ def initialize
5
+ @list = []
6
+ @enclosed = false
7
+ end
8
+
9
+ def add thread
10
+ @list << thread
11
+ end
12
+
13
+ def list
14
+ @list.dup
15
+ end
16
+
17
+ def enclose
18
+ @enclosed = true
19
+ end
20
+
21
+ def enclosed?
22
+ @enclosed
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,81 +1,75 @@
1
1
  module Actor
2
2
  class Supervisor
3
- attr_reader :actors
4
- attr_writer :exception_notifier
3
+ include Actor
5
4
 
6
- def initialize
7
- @actors = Set.new
8
- end
9
-
10
- def add address, thread
11
- actor = Actor.new address, thread
12
-
13
- actors << actor
5
+ attr_writer :broadcast_address
6
+ attr_accessor :error
7
+ attr_writer :thread_group
8
+ attr_writer :router_address
14
9
 
15
- actor
10
+ handle :start do
11
+ :continue
16
12
  end
17
13
 
18
- def remove address
19
- actors.delete_if do |actor|
20
- actor.address == address
14
+ handle :continue do |message|
15
+ if actor_threads.empty?
16
+ :stop
17
+ else
18
+ message
21
19
  end
22
20
  end
23
21
 
24
- def broadcast message
25
- addresses = actors.map &:address
22
+ handle :actor_started do |message|
23
+ reader = Messaging::Read.build broadcast_address
24
+ output_address = message.actor_address
26
25
 
27
- addresses.each do |address|
28
- Messaging::Writer.(message, address)
29
- end
30
- end
26
+ add_route = Router::AddRoute.new reader, output_address
31
27
 
32
- def pause
33
- broadcast Message::Pause.new
28
+ writer.(add_route, router_address)
34
29
  end
35
30
 
36
- def resume
37
- broadcast Message::Resume.new
38
- end
31
+ handle :actor_crashed do |message|
32
+ self.error ||= message.error
39
33
 
40
- def stop
41
- broadcast Message::Stop.new
34
+ :shutdown
42
35
  end
43
36
 
44
- def start &supplementary_action
45
- Signal.trap 'CONT' do resume end
46
- Signal.trap 'INT' do stop end
47
- Signal.trap 'TSTP' do pause end
37
+ handle :shutdown do
38
+ stop = Messages::Stop.new
48
39
 
49
- loop do
50
- supplementary_action.() if supplementary_action
40
+ writer.(stop, broadcast_address)
41
+ writer.(stop, router_address)
51
42
 
52
- actors.delete_if do |actor|
53
- thread = actor.thread
54
- thread.join TimeUnit.millisecond
55
- end
43
+ :continue
44
+ end
56
45
 
57
- break if actors.empty?
46
+ def actor_threads
47
+ list = thread_group.list
48
+ list.delete Thread.current
49
+ list
50
+ end
58
51
 
59
- Thread.pass
60
- end
52
+ def configure
53
+ thread_group = ThreadGroup.new
54
+ thread_group.add Thread.current
61
55
 
62
- rescue => error
63
- exception_notifier.(error)
64
- raise error
56
+ self.broadcast_address = Address.build
57
+ self.router_address = Router.start
58
+ self.thread_group = thread_group
65
59
  end
66
60
 
67
- def exception_notifier
68
- @exception_notifier ||= proc { }
61
+ def broadcast_address
62
+ @broadcast_address ||= Address::None
69
63
  end
70
64
 
71
- Actor = Struct.new :address, :thread
65
+ def router_address
66
+ @router_address ||= Address::None
67
+ end
72
68
 
73
- module Assertions
74
- def actor? actor_address
75
- actors.any? do |actor|
76
- actor.address == actor_address
77
- end
78
- end
69
+ def thread_group
70
+ @thread_group ||= Substitutes::ThreadGroup.new
79
71
  end
72
+
73
+ ActorCrashed = Struct.new :error
80
74
  end
81
75
  end
data/lib/actor.rb CHANGED
@@ -1,24 +1,32 @@
1
- require 'ostruct'
2
1
  require 'securerandom'
3
2
  require 'set'
3
+ require 'timeout'
4
4
 
5
- require 'actor/queue'
6
- require 'actor/queue/assertions'
7
- require 'actor/queue/reader'
5
+ require 'actor/substitutes/kernel'
6
+ require 'actor/substitutes/thread_group'
7
+ require 'actor/substitutes/thread'
8
8
 
9
- require 'actor/statistics'
10
- require 'actor/statistics/copy'
11
- require 'actor/statistics/timer'
9
+ require 'actor/destructure'
10
+ require 'actor/duration'
11
+ require 'actor/stream'
12
12
 
13
- require 'actor/messaging/address'
14
- require 'actor/messaging/reader'
15
- require 'actor/messaging/reader/substitute'
16
- require 'actor/messaging/writer'
17
- require 'actor/messaging/writer/substitute'
13
+ require 'actor/address'
14
+ require 'actor/messaging/message'
15
+ require 'actor/messaging/read'
16
+ require 'actor/messaging/read/substitute'
17
+ require 'actor/messaging/write'
18
+ require 'actor/messaging/write/substitute'
18
19
 
19
- require 'actor/message'
20
+ require 'actor/messages'
20
21
 
21
- require 'actor/time_unit'
22
+ require 'actor/module/build'
23
+ require 'actor/module/handle_macro'
24
+ require 'actor/module/start'
25
+ require 'actor/module'
26
+
27
+ require 'actor/start'
22
28
 
23
29
  require 'actor/actor'
30
+
31
+ require 'actor/router'
24
32
  require 'actor/supervisor'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ntl-actor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Ladd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-31 00:00:00.000000000 Z
11
+ date: 2016-09-14 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Implementation of actor pattern for ruby designed for simplicity and
14
14
  frugality
@@ -19,35 +19,34 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - lib/actor.rb
21
21
  - lib/actor/actor.rb
22
+ - lib/actor/address.rb
22
23
  - lib/actor/controls.rb
23
24
  - lib/actor/controls/actor.rb
25
+ - lib/actor/controls/address.rb
26
+ - lib/actor/controls/error.rb
24
27
  - lib/actor/controls/message.rb
25
- - lib/actor/controls/statistics.rb
26
- - lib/actor/controls/statistics/elapsed_time.rb
27
- - lib/actor/controls/statistics/elapsed_time/average.rb
28
- - lib/actor/controls/statistics/elapsed_time/maximum.rb
29
- - lib/actor/controls/statistics/elapsed_time/minimum.rb
30
- - lib/actor/controls/statistics/elapsed_time/standard_deviation.rb
31
- - lib/actor/controls/statistics/timer.rb
32
- - lib/actor/controls/time.rb
33
- - lib/actor/controls/time/clock.rb
34
- - lib/actor/message.rb
35
- - lib/actor/messaging/address.rb
36
- - lib/actor/messaging/reader.rb
37
- - lib/actor/messaging/reader/substitute.rb
38
- - lib/actor/messaging/writer.rb
39
- - lib/actor/messaging/writer/substitute.rb
40
- - lib/actor/queue.rb
41
- - lib/actor/queue/assertions.rb
42
- - lib/actor/queue/reader.rb
43
- - lib/actor/statistics.rb
44
- - lib/actor/statistics/copy.rb
45
- - lib/actor/statistics/timer.rb
28
+ - lib/actor/controls/message/attribute.rb
29
+ - lib/actor/controls/thread.rb
30
+ - lib/actor/controls/uuid.rb
31
+ - lib/actor/destructure.rb
32
+ - lib/actor/duration.rb
33
+ - lib/actor/messages.rb
34
+ - lib/actor/messaging/message.rb
35
+ - lib/actor/messaging/read.rb
36
+ - lib/actor/messaging/read/substitute.rb
37
+ - lib/actor/messaging/write.rb
38
+ - lib/actor/messaging/write/substitute.rb
39
+ - lib/actor/module.rb
40
+ - lib/actor/module/build.rb
41
+ - lib/actor/module/handle_macro.rb
42
+ - lib/actor/module/start.rb
43
+ - lib/actor/router.rb
44
+ - lib/actor/start.rb
45
+ - lib/actor/stream.rb
46
+ - lib/actor/substitutes/kernel.rb
47
+ - lib/actor/substitutes/thread.rb
48
+ - lib/actor/substitutes/thread_group.rb
46
49
  - lib/actor/supervisor.rb
47
- - lib/actor/test_fixtures.rb
48
- - lib/actor/test_fixtures/parallel_iteration.rb
49
- - lib/actor/test_fixtures/sample_actor_status.rb
50
- - lib/actor/time_unit.rb
51
50
  homepage: https://github.com/ntl/actor
52
51
  licenses:
53
52
  - MIT
@@ -56,6 +55,7 @@ post_install_message:
56
55
  rdoc_options: []
57
56
  require_paths:
58
57
  - lib
58
+ - src
59
59
  required_ruby_version: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - ">="
@@ -63,9 +63,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
63
63
  version: '0'
64
64
  required_rubygems_version: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - ">"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 1.3.1
69
69
  requirements: []
70
70
  rubyforge_project:
71
71
  rubygems_version: 2.6.6
@@ -1,21 +0,0 @@
1
- module Actor
2
- module Controls
3
- module Statistics
4
- module ElapsedTime
5
- module Average
6
- def self.configure_timer receiver
7
- ElapsedTime.configure_timer receiver, elapsed_times
8
- end
9
-
10
- def self.elapsed_times
11
- [1, 2, 6]
12
- end
13
-
14
- def self.value
15
- 3
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end