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