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