concurrent-ruby 0.1.1.pre.5 → 0.1.1

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -48
  3. data/lib/concurrent.rb +0 -6
  4. data/lib/concurrent/agent.rb +40 -19
  5. data/lib/concurrent/cached_thread_pool.rb +11 -10
  6. data/lib/concurrent/defer.rb +12 -8
  7. data/lib/concurrent/fixed_thread_pool.rb +6 -12
  8. data/lib/concurrent/future.rb +20 -8
  9. data/lib/concurrent/global_thread_pool.rb +0 -13
  10. data/lib/concurrent/goroutine.rb +1 -5
  11. data/lib/concurrent/obligation.rb +64 -10
  12. data/lib/concurrent/promise.rb +60 -38
  13. data/lib/concurrent/thread_pool.rb +5 -16
  14. data/lib/concurrent/utilities.rb +0 -8
  15. data/lib/concurrent/version.rb +1 -1
  16. data/md/defer.md +4 -4
  17. data/md/promise.md +0 -2
  18. data/md/thread_pool.md +0 -27
  19. data/spec/concurrent/agent_spec.rb +27 -8
  20. data/spec/concurrent/cached_thread_pool_spec.rb +1 -14
  21. data/spec/concurrent/defer_spec.rb +21 -17
  22. data/spec/concurrent/event_machine_defer_proxy_spec.rb +149 -159
  23. data/spec/concurrent/fixed_thread_pool_spec.rb +3 -2
  24. data/spec/concurrent/future_spec.rb +10 -3
  25. data/spec/concurrent/goroutine_spec.rb +0 -15
  26. data/spec/concurrent/obligation_shared.rb +2 -16
  27. data/spec/concurrent/promise_spec.rb +13 -15
  28. data/spec/concurrent/thread_pool_shared.rb +5 -5
  29. data/spec/concurrent/utilities_spec.rb +1 -30
  30. data/spec/spec_helper.rb +0 -25
  31. metadata +7 -28
  32. data/lib/concurrent/executor.rb +0 -95
  33. data/lib/concurrent/functions.rb +0 -120
  34. data/lib/concurrent/null_thread_pool.rb +0 -22
  35. data/lib/concurrent/reactor.rb +0 -161
  36. data/lib/concurrent/reactor/drb_async_demux.rb +0 -74
  37. data/lib/concurrent/reactor/tcp_sync_demux.rb +0 -98
  38. data/md/executor.md +0 -176
  39. data/spec/concurrent/executor_spec.rb +0 -200
  40. data/spec/concurrent/functions_spec.rb +0 -217
  41. data/spec/concurrent/global_thread_pool_spec.rb +0 -38
  42. data/spec/concurrent/null_thread_pool_spec.rb +0 -54
  43. data/spec/concurrent/reactor/drb_async_demux_spec.rb +0 -12
  44. data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +0 -12
  45. data/spec/concurrent/reactor_spec.rb +0 -351
@@ -1,120 +0,0 @@
1
- require 'concurrent/agent'
2
- require 'concurrent/defer'
3
- require 'concurrent/future'
4
- require 'concurrent/promise'
5
-
6
- module Kernel
7
-
8
- ## agent
9
-
10
- def agent(initial, timeout = Concurrent::Agent::TIMEOUT)
11
- return Concurrent::Agent.new(initial, timeout)
12
- end
13
- module_function :agent
14
-
15
- def post(object, &block)
16
- if object.respond_to?(:post)
17
- return object.post(&block)
18
- else
19
- raise ArgumentError.new('object does not support #post')
20
- end
21
- end
22
- module_function :post
23
-
24
- ## defer
25
-
26
- def defer(*args, &block)
27
- return Concurrent::Defer.new(*args, &block)
28
- end
29
- module_function :defer
30
-
31
- ## executor
32
-
33
- def executor(*args, &block)
34
- return Concurrent::Executor.run(*args, &block)
35
- end
36
- module_function :executor
37
-
38
- ## future
39
-
40
- def future(*args, &block)
41
- return Concurrent::Future.new(*args, &block)
42
- end
43
- module_function :future
44
-
45
- ## obligation
46
-
47
- def deref(object, timeout = nil)
48
- if object.respond_to?(:deref)
49
- return object.deref(timeout)
50
- elsif object.respond_to?(:value)
51
- return object.value(timeout)
52
- else
53
- raise ArgumentError.new('object does not support #deref')
54
- end
55
- end
56
- module_function :deref
57
-
58
- def pending?(object)
59
- if object.respond_to?(:pending?)
60
- return object.pending?
61
- else
62
- raise ArgumentError.new('object does not support #pending?')
63
- end
64
- end
65
- module_function :pending?
66
-
67
- def fulfilled?(object)
68
- if object.respond_to?(:fulfilled?)
69
- return object.fulfilled?
70
- elsif object.respond_to?(:realized?)
71
- return object.realized?
72
- else
73
- raise ArgumentError.new('object does not support #fulfilled?')
74
- end
75
- end
76
- module_function :fulfilled?
77
-
78
- def realized?(object)
79
- if object.respond_to?(:realized?)
80
- return object.realized?
81
- elsif object.respond_to?(:fulfilled?)
82
- return object.fulfilled?
83
- else
84
- raise ArgumentError.new('object does not support #realized?')
85
- end
86
- end
87
- module_function :realized?
88
-
89
- def rejected?(object)
90
- if object.respond_to?(:rejected?)
91
- return object.rejected?
92
- else
93
- raise ArgumentError.new('object does not support #rejected?')
94
- end
95
- end
96
- module_function :rejected?
97
-
98
- ## promise
99
-
100
- # Creates a new promise object. "A promise represents the eventual
101
- # value returned from the single completion of an operation."
102
- # Promises can be chained in a tree structure where each promise
103
- # has zero or more children. Promises are resolved asynchronously
104
- # in the order they are added to the tree. Parents are guaranteed
105
- # to be resolved before their children. The result of each promise
106
- # is passes to each of its children when the child resolves. When
107
- # a promise is rejected all its children will be summarily rejected.
108
- # A promise added to a rejected promise will immediately be rejected.
109
- # A promise that is neither resolved or rejected is pending.
110
- #
111
- # @param args [Array] zero or more arguments for the block
112
- # @param block [Proc] the block to call when attempting fulfillment
113
- #
114
- # @see Promise
115
- # @see http://wiki.commonjs.org/wiki/Promises/A
116
- def promise(*args, &block)
117
- return Concurrent::Promise.new(*args, &block)
118
- end
119
- module_function :promise
120
- end
@@ -1,22 +0,0 @@
1
- require 'concurrent/global_thread_pool'
2
-
3
- module Concurrent
4
-
5
- class NullThreadPool
6
- behavior(:global_thread_pool)
7
-
8
- def self.post(*args, &block)
9
- Thread.new(*args, &block)
10
- return true
11
- end
12
-
13
- def post(*args, &block)
14
- return NullThreadPool.post(*args, &block)
15
- end
16
-
17
- def <<(block)
18
- NullThreadPool.post(&block)
19
- return self
20
- end
21
- end
22
- end
@@ -1,161 +0,0 @@
1
- require 'thread'
2
- require 'functional'
3
-
4
- behavior_info(:sync_event_demux,
5
- start: 0,
6
- stop: 0,
7
- stopped?: 0,
8
- accept: 0,
9
- respond: 2,
10
- close: 0)
11
-
12
- behavior_info(:async_event_demux,
13
- start: 0,
14
- stop: 0,
15
- stopped?: 0,
16
- set_reactor: 1)
17
-
18
- behavior_info(:demux_reactor,
19
- handle: -2)
20
-
21
- module Concurrent
22
-
23
- class Reactor
24
-
25
- behavior(:demux_reactor)
26
-
27
- RESERVED_EVENTS = [ :stop ]
28
-
29
- EventContext = Struct.new(:event, :args, :callback)
30
-
31
- def initialize(demux = nil)
32
- @demux = demux
33
- if @demux.nil? || @demux.behaves_as?(:async_event_demux)
34
- @sync = false
35
- @queue = Queue.new
36
- @demux.set_reactor(self) unless @demux.nil?
37
- elsif @demux.behaves_as?(:sync_event_demux)
38
- @sync = true
39
- else
40
- raise ArgumentError.new("invalid event demultiplexer '#{@demux}'")
41
- end
42
-
43
- @running = false
44
- @handlers = Hash.new
45
- @mutex = Mutex.new
46
- end
47
-
48
- def running?
49
- return @running
50
- end
51
-
52
- def add_handler(event, &block)
53
- raise ArgumentError.new('no block given') unless block_given?
54
- event = event.to_sym
55
- raise ArgumentError.new("'#{event}' is a reserved event") if RESERVED_EVENTS.include?(event)
56
- @mutex.synchronize {
57
- @handlers[event] = block
58
- }
59
- return true
60
- end
61
-
62
- def remove_handler(event)
63
- handler = @mutex.synchronize {
64
- @handlers.delete(event.to_sym)
65
- }
66
- return ! handler.nil?
67
- end
68
-
69
- def stop_on_signal(*signals)
70
- signals.each{|signal| Signal.trap(signal){ Thread.new{ self.stop }}}
71
- end
72
-
73
- def handle(event, *args)
74
- raise NotImplementedError.new("demultiplexer '#{@demux.class}' is synchronous") if @sync
75
- return [:stopped, 'reactor not running'] unless running?
76
- context = EventContext.new(event.to_sym, args.dup, Queue.new)
77
- @queue.push(context)
78
- return context.callback.pop
79
- end
80
-
81
- def start
82
- raise StandardError.new('already running') if self.running?
83
- @sync ? (@running = true; run_sync) : (@running = true; run_async)
84
- end
85
- alias_method :run, :start
86
-
87
- def stop
88
- return true unless self.running?
89
- if @sync
90
- @demux.stop
91
- else
92
- @queue.push(:stop)
93
- end
94
- return true
95
- end
96
-
97
- private
98
-
99
- def handle_event(context)
100
- raise ArgumentError.new('no block given') unless block_given?
101
-
102
- handler = @mutex.synchronize {
103
- @handlers[context.event]
104
- }
105
-
106
- if handler.nil?
107
- response = yield(:noop, "'#{context.event}' handler not found")
108
- else
109
- begin
110
- result = handler.call(*context.args)
111
- response = yield(:ok, result)
112
- rescue Exception => ex
113
- response = yield(:ex, ex)
114
- end
115
- end
116
-
117
- return response
118
- end
119
-
120
- def finalize_stop
121
- @mutex.synchronize do
122
- @running = false
123
- @demux.stop unless @demux.nil?
124
- @demux = nil
125
- end
126
- end
127
-
128
- def run_sync
129
- @demux.start
130
-
131
- loop do
132
- break if @demux.stopped?
133
- context = @demux.accept
134
- if context.nil?
135
- @demux.close
136
- else
137
- response = handle_event(context) do |result, message|
138
- [result, message]
139
- end
140
- @demux.respond(*response)
141
- end
142
- end
143
-
144
- finalize_stop
145
- end
146
-
147
- def run_async
148
- @demux.start unless @demux.nil?
149
-
150
- loop do
151
- context = @queue.pop
152
- break if context == :stop
153
- handle_event(context) do |result, message|
154
- context.callback.push([result, message])
155
- end
156
- end
157
-
158
- finalize_stop
159
- end
160
- end
161
- end
@@ -1,74 +0,0 @@
1
- require 'drb/drb'
2
- require 'drb/acl'
3
- require 'functional'
4
- require 'concurrent/reactor'
5
-
6
- module Concurrent
7
- class Reactor
8
-
9
- class DRbAsyncDemux
10
-
11
- behavior(:async_event_demux)
12
-
13
- DEFAULT_URI = 'druby://localhost:12345'
14
- DEFAULT_ACL = %w[allow all]
15
-
16
- def initialize(opts = {})
17
- @uri = opts[:uri] || DEFAULT_URI
18
- @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
19
- end
20
-
21
- def set_reactor(reactor)
22
- raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
23
- @reactor = reactor
24
- end
25
-
26
- def start
27
- DRb.install_acl(@acl)
28
- @service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
29
- end
30
-
31
- def stop
32
- @service = DRb.stop_service
33
- end
34
-
35
- def stopped?
36
- return @service.nil?
37
- end
38
-
39
- private
40
-
41
- class Demultiplexer
42
-
43
- def initialize(reactor)
44
- @reactor = reactor
45
- end
46
-
47
- Concurrent::Reactor::RESERVED_EVENTS.each do |event|
48
- define_method(event){|*args| false }
49
- end
50
-
51
- def method_missing(method, *args, &block)
52
- (class << self; self; end).class_eval do
53
- define_method(method) do |*args|
54
- result = @reactor.handle(method, *args)
55
- case result.first
56
- when :ok
57
- return result.last
58
- when :ex
59
- raise result.last
60
- when :noop
61
- raise NoMethodError.new("undefined method '#{method}' for #{self}")
62
- else
63
- raise DRb::DRbUnknownError.new("unexpected error when calling method '#{method}'")
64
- end
65
- end
66
- end
67
- self.send(method, *args)
68
- end
69
- end
70
- end
71
-
72
- DRbAsyncDemultiplexer = DRbAsyncDemux
73
- end
74
- end
@@ -1,98 +0,0 @@
1
- require 'socket'
2
- require 'drb/acl'
3
- require 'functional'
4
- require 'concurrent/reactor'
5
-
6
- module Concurrent
7
- class Reactor
8
-
9
- class TcpSyncDemux
10
-
11
- behavior(:sync_event_demux)
12
-
13
- DEFAULT_HOST = '127.0.0.1'
14
- DEFAULT_PORT = 12345
15
- DEFAULT_ACL = %[allow all]
16
-
17
- def initialize(opts = {})
18
- @host = opts[:host] || DEFAULT_HOST
19
- @port = opts[:port] || DEFAULT_PORT
20
- @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
21
- end
22
-
23
- def start
24
- @server = TCPServer.new(@host, @port)
25
- end
26
-
27
- def stop
28
- atomic {
29
- @socket.close unless @socket.nil?
30
- @server.close unless @server.nil?
31
- @server = @socket = nil
32
- }
33
- end
34
-
35
- def stopped?
36
- return @server.nil?
37
- end
38
-
39
- def accept
40
- @socket = @server.accept if @socket.nil?
41
- return nil unless @acl.allow_socket?(@socket)
42
- event, args = get_message(@socket)
43
- return nil if event.nil?
44
- return Reactor::EventContext.new(event, args)
45
- end
46
-
47
- def respond(result, message)
48
- return nil if @socket.nil?
49
- @socket.puts(format_message(result, message))
50
- end
51
-
52
- def close
53
- @socket.close
54
- @socket = nil
55
- end
56
-
57
- def self.format_message(event, *args)
58
- args = args.reduce('') do |memo, arg|
59
- memo << "#{arg}\r\n"
60
- end
61
- return ":#{event}\r\n#{args}\r\n"
62
- end
63
- def format_message(*args) self.class.format_message(*args); end
64
-
65
- def self.parse_message(message)
66
- return atomic {
67
- event = message.first.match /^:?(\w+)/
68
- event = event[1].to_s.downcase.to_sym unless event.nil?
69
-
70
- args = message.slice(1, message.length) || []
71
-
72
- [event, args]
73
- }
74
- end
75
- def parse_message(*args) self.class.parse_message(*args); end
76
-
77
- def self.get_message(socket)
78
- message = []
79
- while line = socket.gets
80
- if line.nil? || (line = line.strip).empty?
81
- break
82
- else
83
- message << line
84
- end
85
- end
86
-
87
- if message.empty?
88
- return nil
89
- else
90
- return parse_message(message)
91
- end
92
- end
93
- def get_message(*args) self.class.get_message(*args); end
94
- end
95
-
96
- TcpSyncDemultiplexer = TcpSyncDemux
97
- end
98
- end