seekingalpha_thread 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 34ba9568e012ba79315091c9d17d3ddca949a78a
4
+ data.tar.gz: 45a64a3d8f0979fac3713da7970aafc40af9e752
5
+ SHA512:
6
+ metadata.gz: 90170a1870d4be263ac93a69526334951201c7cedc52dd8e91a37cdaeab0859429715d45f9bdddf6fb3f6bbc41f4cb39c192279870acfb5529db4f2bc3b18c52
7
+ data.tar.gz: 9d01b958cf27490c341ec917e67691ab2bb3813866981a96fc47b4ba04268570098c9d30077a3562e5f819c13c3f83cd772e19325fe7a9c975b3b5199093502b
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ pkg
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
8
+ - 2.2.1
9
+ - ruby-head
10
+ - jruby
11
+ - rbx
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
data/README.md ADDED
@@ -0,0 +1,229 @@
1
+ # thread
2
+
3
+ [![Build Status](https://travis-ci.org/meh/ruby-thread.svg?branch=master)](https://travis-ci.org/meh/ruby-thread)
4
+
5
+ Various extensions to the thread library in ruby.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'thread'
12
+
13
+ Or install it yourself as:
14
+
15
+ $ gem install thread
16
+
17
+ ## Usage
18
+
19
+ ### Pool
20
+
21
+ All the implementations I looked at were either buggy or wasted CPU resources
22
+ for no apparent reason, for example used a sleep of 0.01 seconds to then check for
23
+ readiness and stuff like this.
24
+
25
+ This implementation uses standard locking functions to work properly across multiple Ruby
26
+ implementations.
27
+
28
+ ```ruby
29
+ require 'thread/pool'
30
+
31
+ pool = Thread.pool(4)
32
+
33
+ 10.times {
34
+ pool.process {
35
+ sleep 2
36
+
37
+ puts 'lol'
38
+ }
39
+ }
40
+
41
+ pool.shutdown
42
+ ```
43
+
44
+ You should get 4 lols every 2 seconds and it should exit after 10 of them.
45
+
46
+ ### Channel
47
+
48
+ This implements a channel where you can write messages and receive messages.
49
+
50
+ ```ruby
51
+ require 'thread/channel'
52
+
53
+ channel = Thread.channel
54
+ channel.send 'wat'
55
+ channel.receive # => 'wat'
56
+
57
+ channel = Thread.channel { |o| o.is_a?(Integer) }
58
+ channel.send 'wat' # => ArgumentError: guard mismatch
59
+
60
+ Thread.new {
61
+ while num = channel.receive(&:even?)
62
+ puts 'Aye!'
63
+ end
64
+ }
65
+
66
+ Thread.new {
67
+ while num = channel.receive(&:odd?)
68
+ puts 'Arrr!'
69
+ end
70
+ }
71
+
72
+ loop {
73
+ channel.send rand(1_000_000_000)
74
+
75
+ sleep 0.5
76
+ }
77
+ ```
78
+
79
+ ### Pipe
80
+
81
+ A pipe allows you to execute various tasks on a set of data in parallel,
82
+ each datum inserted in the pipe is passed along through queues to the various
83
+ functions composing the pipe, the final result is inserted in the final queue.
84
+
85
+ ```ruby
86
+ require 'thread/pipe'
87
+
88
+ p = Thread |-> d { d * 2 } |-> d { d * 4 }
89
+ p << 2
90
+
91
+ puts ~p # => 16
92
+ ```
93
+
94
+ ### Process
95
+
96
+ A process helps reducing programming errors coming from race conditions and the
97
+ like, the only way to interact with a process is through messages.
98
+
99
+ Multiple processes should talk with eachother through messages.
100
+
101
+ ```ruby
102
+ require 'thread/process'
103
+
104
+ p = Thread.process {
105
+ loop {
106
+ puts receive.inspect
107
+ }
108
+ }
109
+
110
+ p << 42
111
+ p << 23
112
+ ```
113
+
114
+ ### Promise
115
+
116
+ This implements the promise pattern, allowing you to pass around an object
117
+ where you can send a value and extract a value, in a thread-safe way, accessing
118
+ the value will wait for the value to be delivered.
119
+
120
+ ```ruby
121
+ require 'thread/promise'
122
+
123
+ p = Thread.promise
124
+
125
+ Thread.new {
126
+ sleep 5
127
+ p << 42
128
+ }
129
+
130
+ puts ~p # => 42
131
+ ```
132
+
133
+ ### Future
134
+
135
+ A future is somewhat a promise, except you pass it a block to execute in
136
+ another thread.
137
+
138
+ The value returned by the block will be the value of the promise.
139
+
140
+ By default, `Thread.future` executes the block in a newly-created thread.
141
+
142
+ `Thread.future` accepts an optional argument of type `Thread.pool` if you want
143
+ the block executed in an existing thread-pool.
144
+
145
+ You can also use the `Thread::Pool` helper `#future`
146
+
147
+ ```ruby
148
+ require 'thread/future'
149
+
150
+ f = Thread.future {
151
+ sleep 5
152
+
153
+ 42
154
+ }
155
+
156
+ puts ~f # => 42
157
+ ```
158
+
159
+ ```ruby
160
+ require 'thread/pool'
161
+ require 'thread/future'
162
+
163
+ pool = Thread.pool 4
164
+ f = Thread.future pool do
165
+ sleep 5
166
+ 42
167
+ end
168
+
169
+ puts ~f # => 42
170
+ ```
171
+
172
+ ```ruby
173
+ require 'thread/pool'
174
+ require 'thread/future'
175
+
176
+ pool = Thread.pool 4
177
+ f = pool.future {
178
+ sleep 5
179
+ 42
180
+ }
181
+
182
+ puts ~f # => 42
183
+ ```
184
+
185
+
186
+ ### Delay
187
+
188
+ A delay is kind of a promise, except the block is called when the value is
189
+ being accessed and the result is cached.
190
+
191
+ ```ruby
192
+ require 'thread/delay'
193
+
194
+ d = Thread.delay {
195
+ 42
196
+ }
197
+
198
+ puts ~d # => 42
199
+ ```
200
+
201
+ ### Every
202
+
203
+ An every executes the block every given seconds and yields the value to the
204
+ every object, you can then check if the current value is old or how much time
205
+ is left until the second call is done.
206
+
207
+ ```ruby
208
+ require 'net/http'
209
+ require 'thread/every'
210
+
211
+ e = Thread.every(5) {
212
+ Net::HTTP.get(URI.parse('http://www.whattimeisit.com/')).match %r{<B>(.*?)<BR>\s+(.*?)</B>}m do |m|
213
+ { date: m[1], time: m[2] }
214
+ end
215
+ }
216
+
217
+ loop do
218
+ puts ~e
219
+ end
220
+ ```
221
+
222
+ ## Contributing
223
+
224
+ 1. Fork it ( https://github.com/meh/ruby-thread/fork )
225
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
226
+ 3. Verify new and old specs are green (`rake`)
227
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
228
+ 5. Push to the branch (`git push origin my-new-feature`)
229
+ 6. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,109 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ require 'thread'
12
+
13
+ # A channel lets you send and receive various messages in a thread-safe way.
14
+ #
15
+ # It also allows for guards upon sending and retrieval, to ensure the passed
16
+ # messages are safe to be consumed.
17
+ class Thread::Channel
18
+ # Create a channel with optional initial messages and optional channel guard.
19
+ def initialize(messages = [], &block)
20
+ @messages = []
21
+ @mutex = Mutex.new
22
+ @check = block
23
+
24
+ messages.each {|o|
25
+ send o
26
+ }
27
+ end
28
+
29
+ # Send a message to the channel.
30
+ #
31
+ # If there's a guard, the value is passed to it, if the guard returns a falsy value
32
+ # an ArgumentError exception is raised and the message is not sent.
33
+ def send(what)
34
+ if @check && !@check.call(what)
35
+ raise ArgumentError, 'guard mismatch'
36
+ end
37
+
38
+ @mutex.synchronize {
39
+ @messages << what
40
+
41
+ cond.broadcast if cond?
42
+ }
43
+
44
+ self
45
+ end
46
+
47
+ # Receive a message, if there are none the call blocks until there's one.
48
+ #
49
+ # If a block is passed, it's used as guard to match to a message.
50
+ def receive(&block)
51
+ message = nil
52
+ found = false
53
+
54
+ if block
55
+ until found
56
+ @mutex.synchronize {
57
+ if index = @messages.find_index(&block)
58
+ message = @messages.delete_at(index)
59
+ found = true
60
+ else
61
+ cond.wait @mutex
62
+ end
63
+ }
64
+ end
65
+ else
66
+ until found
67
+ @mutex.synchronize {
68
+ if @messages.empty?
69
+ cond.wait @mutex
70
+ end
71
+
72
+ unless @messages.empty?
73
+ message = @messages.shift
74
+ found = true
75
+ end
76
+ }
77
+ end
78
+ end
79
+
80
+ message
81
+ end
82
+
83
+ # Receive a message, if there are none the call returns nil.
84
+ #
85
+ # If a block is passed, it's used as guard to match to a message.
86
+ def receive!(&block)
87
+ if block
88
+ @messages.delete_at(@messages.find_index(&block))
89
+ else
90
+ @messages.shift
91
+ end
92
+ end
93
+
94
+ private
95
+ def cond?
96
+ instance_variable_defined? :@cond
97
+ end
98
+
99
+ def cond
100
+ @cond ||= ConditionVariable.new
101
+ end
102
+ end
103
+
104
+ class Thread
105
+ # Helper to create a channel.
106
+ def self.channel(*args, &block)
107
+ Thread::Channel.new(*args, &block)
108
+ end
109
+ end
@@ -0,0 +1,94 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
6
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
7
+ #
8
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
9
+ #++
10
+
11
+ require 'thread'
12
+
13
+ # A delay is an object that incapsulates a block which is called upon
14
+ # value retrieval, and its result cached.
15
+ class Thread::Delay
16
+ # Create a delay with the passed block.
17
+ def initialize (&block)
18
+ raise ArgumentError, 'no block given' unless block
19
+
20
+ @mutex = Mutex.new
21
+ @block = block
22
+ end
23
+
24
+ # Check if an exception has been raised.
25
+ def exception?
26
+ @mutex.synchronize {
27
+ instance_variable_defined? :@exception
28
+ }
29
+ end
30
+
31
+ # Return the raised exception.
32
+ def exception
33
+ @mutex.synchronize {
34
+ @exception
35
+ }
36
+ end
37
+
38
+ # Check if the delay has been called.
39
+ def delivered?
40
+ @mutex.synchronize {
41
+ instance_variable_defined? :@value
42
+ }
43
+ end
44
+
45
+ alias realized? delivered?
46
+
47
+ # Get the value of the delay, if it's already been executed, return the
48
+ # cached result, otherwise execute the block and return the value.
49
+ #
50
+ # In case the block raises an exception, it will be raised, the exception is
51
+ # cached and will be raised every time you access the value.
52
+ def value
53
+ @mutex.synchronize {
54
+ raise @exception if instance_variable_defined? :@exception
55
+
56
+ return @value if instance_variable_defined? :@value
57
+
58
+ begin
59
+ @value = @block.call
60
+ rescue Exception => e
61
+ @exception = e
62
+
63
+ raise
64
+ end
65
+ }
66
+ end
67
+
68
+ alias ~ value
69
+
70
+ # Do the same as {#value}, but return nil in case of exception.
71
+ def value!
72
+ begin
73
+ value
74
+ rescue Exception
75
+ nil
76
+ end
77
+ end
78
+
79
+ alias ! value!
80
+ end
81
+
82
+ class Thread
83
+ # Helper to create Thread::Delay
84
+ def self.delay (&block)
85
+ Thread::Delay.new(&block)
86
+ end
87
+ end
88
+
89
+ module Kernel
90
+ # Helper to create a Thread::Delay
91
+ def delay (&block)
92
+ Thread::Delay.new(&block)
93
+ end
94
+ end