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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0c88b4604c03bb629e693a7d72e274dfae3c2cc
4
- data.tar.gz: ec1392122225b29127297bfb32ad2e080276685a
3
+ metadata.gz: 8390670d6cdb63d966590bc7456a583e424b21aa
4
+ data.tar.gz: 71bc7ef3d159c05ada78869eff267f6e683ff7a9
5
5
  SHA512:
6
- metadata.gz: 3dc160915615a234617ad0a4880bcc9a5a07e88bb92ff6ce91ca5ab80743a2f7231599fe989783f50e433df6ff698faafe4745cc6de327127724e21ff1727e90
7
- data.tar.gz: ead037eba5b21614ba7169227906544e878e4c6470182d6362ebb6656420fb5803ece15fa4b2b62079ab8029aa7a447aecbabbdb01f4632e23220668222ea300
6
+ metadata.gz: d9bc1d1dd129fa2d4275a3bb57a051826c7808f6d426c68cde2a3e336f1d70301ac2456729516dc7203e6a30a7ac8c17523e27d453270fd3f87867fca4acbcbf
7
+ data.tar.gz: 7164e075114eec599f0233c386f6bf77335e03edd140e51d28159d379e8b5280fc5181ffdce386f80ce6b6a37cb89076bbecedeee081a9fd4b84f72d1be879da
data/lib/actor/actor.rb CHANGED
@@ -1,151 +1,11 @@
1
1
  module Actor
2
+ # It is possible to `include Actor' in the top-level namespace in order to
3
+ # bring this library's constants into focus (i.e. reference them without any
4
+ # leading `Actor' reference to qualify them). The test suite does this; see
5
+ # tests/test_init.rb. In that case, we take care not to attach any Actor
6
+ # behavior onto Object. This is achieved by placing the implementation of
7
+ # Actor in Actor::Module
2
8
  def self.included cls
3
- cls.class_exec do
4
- extend Destructure
5
- extend Spawn
6
- extend Start
7
-
8
- prepend UpdateStatistics
9
- end
10
- end
11
-
12
- attr_accessor :actor_address
13
- attr_accessor :actor_state
14
- attr_writer :reader
15
-
16
- def action
17
- end
18
-
19
- def actor_statistics
20
- @actor_statistics ||= Statistics.new
21
- end
22
-
23
- def handle _
24
- end
25
-
26
- def handle_system_message message
27
- case message
28
- when Message::Pause then
29
- self.actor_state = State::Paused
30
-
31
- when Message::Resume then
32
- self.actor_state = State::Running
33
-
34
- when Message::Stop then
35
- self.actor_state = State::Running
36
- raise StopIteration
37
-
38
- when Message::RecordStatus then
39
- status = message.status
40
-
41
- Statistics::Copy.(status, actor_statistics)
42
-
43
- status.state = actor_state
44
- status.actor_class = self.class.name
45
-
46
- Messaging::Writer.(status, message.reply_address)
47
- end
48
- end
49
-
50
- def reader
51
- @reader ||= Reader::Substitute.new
52
- end
53
-
54
- def run_loop
55
- loop do
56
- while message = reader.(wait: actor_state == State::Paused)
57
- handle message
58
-
59
- if message.is_a? Message
60
- handle_system_message message
61
- end
62
- end
63
-
64
- action if actor_state == State::Running
65
-
66
- Thread.pass
67
- end
68
-
69
- self.actor_state = State::Stopped
70
-
71
- rescue => error
72
- self.actor_state = State::Crashed
73
- raise error
74
- end
75
-
76
- module Destructure
77
- def destructure actor, address, thread, include: nil
78
- return address if include.nil?
79
-
80
- result = [address]
81
-
82
- include.each do |variable_name|
83
- value = binding.local_variable_get variable_name
84
-
85
- result << value
86
- end
87
-
88
- return *result
89
- end
90
- end
91
-
92
- module Spawn
93
- def spawn *positional_arguments, include: nil, **keyword_arguments, &block
94
- address = Messaging::Address.build
95
-
96
- method = if respond_to? :build then :build else :new end
97
-
98
- if keyword_arguments.empty?
99
- instance = __send__ method, *positional_arguments, &block
100
- else
101
- instance = __send__ method, *positional_arguments, **keyword_arguments, &block
102
- end
103
-
104
- reader = Messaging::Reader.build address
105
-
106
- instance.actor_address = address
107
- instance.actor_state = State::Paused
108
- instance.reader = reader
109
-
110
- thread = ::Thread.new do
111
- instance.run_loop
112
- end
113
-
114
- destructure instance, address, thread, include: include
115
- end
116
- end
117
-
118
- module Start
119
- def start *positional_arguments, include: nil, **keyword_arguments, &block
120
- address, instance, thread = spawn(
121
- *positional_arguments,
122
- include: %i(actor thread),
123
- **keyword_arguments,
124
- &block
125
- )
126
-
127
- Messaging::Writer.(Message::Resume.new, address)
128
-
129
- destructure instance, address, thread, include: include
130
- end
131
- end
132
-
133
- module State
134
- Crashed = :crashed
135
- Paused = :paused
136
- Running = :running
137
- Stopped = :stopped
138
- end
139
-
140
- module UpdateStatistics
141
- def action
142
- actor_statistics.executing_action
143
-
144
- result = super
145
-
146
- actor_statistics.action_executed
147
-
148
- result
149
- end
9
+ cls.include Module unless cls == Object
150
10
  end
151
11
  end
@@ -0,0 +1,18 @@
1
+ module Actor
2
+ Address = Struct.new :stream, :uuid do
3
+ def self.build stream=nil
4
+ stream ||= Stream.new
5
+
6
+ uuid = SecureRandom.uuid
7
+
8
+ instance = new stream, uuid
9
+ instance
10
+ end
11
+ end
12
+
13
+ class Address
14
+ NoneClass = Class.new Address
15
+
16
+ None = NoneClass.build Stream::Null
17
+ end
18
+ end
@@ -8,66 +8,53 @@ module Actor
8
8
  class Example
9
9
  include ::Actor
10
10
 
11
- def action
12
- @acted = true
11
+ def initialize
12
+ @messages = []
13
13
  end
14
14
 
15
- def action_executed?
16
- @acted == true
15
+ handle Message::Example do |message|
16
+ @messages << message
17
+ nil
17
18
  end
18
19
 
19
- def handle message
20
- handled_messages << message
21
- end
22
-
23
- def handled_messages
24
- @handled_messages ||= []
20
+ def handled? message
21
+ @messages.include? message
25
22
  end
23
+ end
26
24
 
27
- module Assertions
28
- def handled_message? expected_message
29
- expected_message ||= Message.example
25
+ class Continues
26
+ include ::Actor
30
27
 
31
- @handled_messages.include? expected_message
28
+ def handle message
29
+ if message == Message.example
30
+ Message::Other.example
31
+ else
32
+ Message.example
32
33
  end
33
34
  end
34
35
  end
35
36
 
36
- class CrashesImmediately < Example
37
- def action
38
- super
39
- raise Error, "Induced error"
40
- end
37
+ class Stops
38
+ include ::Actor
41
39
 
42
- Error = Class.new StandardError
43
- end
40
+ handle :start do
41
+ @stopped = true
44
42
 
45
- class StopsImmediately < Example
46
- def action
47
- super
48
43
  raise StopIteration
49
44
  end
50
- end
51
45
 
52
- class ConstructorArguments < StopsImmediately
53
- attr_reader :req, :opt, :keyreq, :key, :block
54
-
55
- def initialize req, opt=nil, keyreq:, key: nil, &block
56
- @req, @opt, @keyreq, @key, @block = req, opt, keyreq, key, block
46
+ def stopped?
47
+ @stopped ? true : false
57
48
  end
58
49
  end
59
50
 
60
- class FactoryMethod < ConstructorArguments
61
- def self.build req
62
- new req, keyreq: 'keyreq-value'
63
- end
64
-
65
- def argument_passed_in? value
66
- req == value
67
- end
51
+ class Singleton
52
+ include ::Actor
68
53
 
69
- def constructed_by_factory_method?
70
- keyreq == 'keyreq-value'
54
+ def self.define &block
55
+ cls = Class.new Singleton
56
+ cls.class_exec &block if block
57
+ cls.new
71
58
  end
72
59
  end
73
60
  end
@@ -0,0 +1,48 @@
1
+ module Actor
2
+ module Controls
3
+ module Address
4
+ def self.example id_offset=nil, stream: nil
5
+ stream ||= Stream.new
6
+
7
+ uuid = UUID.example id_offset
8
+
9
+ ::Actor::Address.new stream, uuid
10
+ end
11
+
12
+ def self.pair id_offset=nil
13
+ stream = Stream.new
14
+
15
+ queue = Queue.new
16
+ stream.add_queue queue
17
+
18
+ address = example id_offset, stream: stream
19
+
20
+ return address, queue
21
+ end
22
+
23
+ module Actor
24
+ def self.example
25
+ Address.example 0
26
+ end
27
+ end
28
+
29
+ module Supervisor
30
+ def self.example
31
+ Address.example 1
32
+ end
33
+
34
+ module Broadcast
35
+ def self.example
36
+ Address.example 2
37
+ end
38
+ end
39
+ end
40
+
41
+ module Router
42
+ def self.example
43
+ Address.example 3
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ module Actor
2
+ module Controls
3
+ module Error
4
+ def self.example
5
+ instance_eval <<~RUBY, '/path/to/some_file.rb', 1
6
+ def method_1; raise ::Actor::Controls::Error::Example; end
7
+ def method_2; method_1; end
8
+ method_2
9
+ RUBY
10
+ rescue Example => error
11
+ return error
12
+ end
13
+
14
+ Example = Class.new StandardError
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Actor
2
+ module Controls
3
+ module Message
4
+ module Attribute
5
+ def self.example
6
+ 'some-attribute'
7
+ end
8
+
9
+ module Other
10
+ def self.example
11
+ 'other-attribute'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,7 +2,29 @@ module Actor
2
2
  module Controls
3
3
  module Message
4
4
  def self.example
5
- 'some-message'
5
+ attribute = Attribute.example
6
+
7
+ Example.new attribute
8
+ end
9
+
10
+ module Other
11
+ def self.example
12
+ attribute = Attribute::Other.example
13
+
14
+ Example.new attribute
15
+ end
16
+ end
17
+
18
+ Example = Struct.new :some_attribute do
19
+ include Messaging::Message
20
+ end
21
+
22
+ module ActorStarted
23
+ def self.example
24
+ actor_address = Address::Actor.example
25
+
26
+ Messages::ActorStarted.new actor_address
27
+ end
6
28
  end
7
29
  end
8
30
  end
@@ -0,0 +1,9 @@
1
+ module Actor
2
+ module Controls
3
+ module Thread
4
+ def self.example
5
+ Substitutes::Thread.new
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module Actor
2
+ module Controls
3
+ module UUID
4
+ def self.example id_offset=nil
5
+ id_offset ||= 0
6
+
7
+ id_offset = id_offset.to_s 16
8
+
9
+ dword = id_offset.rjust 8, '0'
10
+
11
+ "#{dword}-0000-4000-8000-000000000000"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,11 +1,7 @@
1
- require 'actor/controls/actor'
1
+ require 'actor/controls/address'
2
+ require 'actor/controls/error'
2
3
  require 'actor/controls/message'
3
- require 'actor/controls/statistics'
4
- require 'actor/controls/statistics/elapsed_time'
5
- require 'actor/controls/statistics/elapsed_time/average'
6
- require 'actor/controls/statistics/elapsed_time/maximum'
7
- require 'actor/controls/statistics/elapsed_time/minimum'
8
- require 'actor/controls/statistics/elapsed_time/standard_deviation'
9
- require 'actor/controls/statistics/timer'
10
- require 'actor/controls/time'
11
- require 'actor/controls/time/clock'
4
+ require 'actor/controls/actor'
5
+ require 'actor/controls/message/attribute'
6
+ require 'actor/controls/uuid'
7
+ require 'actor/controls/thread'
@@ -0,0 +1,23 @@
1
+ module Actor
2
+ module Destructure
3
+ def self.call primary_return_value, include=nil, **values
4
+ include = Array(include)
5
+
6
+ if include.empty?
7
+ primary_return_value
8
+ else
9
+ return_values = include.map do |return_value_name|
10
+ begin
11
+ values.fetch return_value_name
12
+ rescue KeyError
13
+ raise Error, "Invalid return value to include `#{return_value_name.inspect}'"
14
+ end
15
+ end
16
+
17
+ return primary_return_value, *return_values
18
+ end
19
+ end
20
+
21
+ Error = Class.new StandardError
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  module Actor
2
- module TimeUnit
2
+ module Duration
3
3
  def self.millisecond
4
4
  0.001
5
5
  end
@@ -0,0 +1,15 @@
1
+ module Actor
2
+ module Messages
3
+ class Start
4
+ include Messaging::Message
5
+ end
6
+
7
+ ActorStarted = Struct.new :actor_address do
8
+ include Messaging::Message
9
+ end
10
+
11
+ class Stop
12
+ include Messaging::Message
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Actor
2
+ module Messaging
3
+ Message = Module.new
4
+ end
5
+ end
@@ -1,8 +1,18 @@
1
1
  module Actor
2
2
  module Messaging
3
- class Writer
3
+ class Read
4
4
  class Substitute
5
- def call message
5
+ def call wait: nil
6
+ message = messages.shift
7
+
8
+ if message.nil? and wait
9
+ raise WouldWait
10
+ end
11
+
12
+ message
13
+ end
14
+
15
+ def add_message message
6
16
  messages << message
7
17
  end
8
18
 
@@ -10,15 +20,8 @@ module Actor
10
20
  @messages ||= []
11
21
  end
12
22
 
13
- module Assertions
14
- def written? &block
15
- block ||= proc { true }
16
-
17
- messages.any? &block
18
- end
19
- end
23
+ WouldWait = Class.new StandardError
20
24
 
21
- # Eventide compatibility
22
25
  singleton_class.send :alias_method, :build, :new
23
26
  end
24
27
  end
@@ -0,0 +1,50 @@
1
+ module Actor
2
+ module Messaging
3
+ class Read
4
+ attr_reader :queue
5
+ attr_reader :stream
6
+
7
+ def initialize queue, stream
8
+ @queue = queue
9
+ @stream = stream
10
+ end
11
+
12
+ def self.build address
13
+ stream = address.stream
14
+
15
+ queue = Queue.new
16
+ stream.add_queue queue
17
+
18
+ instance = new queue, stream
19
+ instance
20
+ end
21
+
22
+ def self.call address, wait: nil
23
+ instance = build address
24
+ instance.(wait: wait)
25
+ end
26
+
27
+ def self.configure receiver, address, attr_name: nil
28
+ attr_name ||= :reader
29
+
30
+ instance = build address
31
+ receiver.public_send "#{attr_name}=", instance
32
+ instance
33
+ end
34
+
35
+ def call wait: nil
36
+ if wait
37
+ queue.deq
38
+ else
39
+ non_block = true
40
+
41
+ begin
42
+ queue.deq non_block
43
+ rescue ThreadError
44
+ nil
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ module Actor
2
+ module Messaging
3
+ class Write
4
+ class Substitute
5
+ attr_reader :records
6
+
7
+ def initialize
8
+ @records = []
9
+ end
10
+
11
+ def call message, address
12
+ record = Record.new message, address
13
+
14
+ records << record
15
+
16
+ record
17
+ end
18
+
19
+ Record = Struct.new :message, :address
20
+
21
+ singleton_class.send :alias_method, :build, :new
22
+
23
+ module Assertions
24
+ def written? message=nil, &block
25
+ if message.nil?
26
+ block ||= proc { true }
27
+ else
28
+ block ||= proc { |msg| msg == message }
29
+ end
30
+
31
+ records.any? do |record|
32
+ block.(record.message, record.address)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module Actor
2
+ module Messaging
3
+ class Write
4
+ def self.call message, address
5
+ instance = new
6
+ instance.(message, address)
7
+ end
8
+
9
+ def self.configure receiver, attr_name: nil
10
+ attr_name ||= :writer
11
+
12
+ instance = new
13
+ receiver.public_send "#{attr_name}=", instance
14
+ instance
15
+ end
16
+
17
+ def call message, address
18
+ stream = address.stream
19
+
20
+ stream.write message
21
+
22
+ nil
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,20 @@
1
+ module Actor
2
+ module Module
3
+ module Build
4
+ def build address, *positional_arguments, **keyword_arguments, &block
5
+ if keyword_arguments.empty?
6
+ instance = new *positional_arguments, &block
7
+ else
8
+ instance = new *positional_arguments, **keyword_arguments, &block
9
+ end
10
+
11
+ instance.reader = Messaging::Read.build address
12
+ instance.writer = Messaging::Write.new
13
+
14
+ instance.configure
15
+
16
+ instance
17
+ end
18
+ end
19
+ end
20
+ end