ntl-actor 0.3.1 → 0.4.0.pre1

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