vinted-thread 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
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/channel'
12
+
13
+ # A process should only interact with the outside the outside through messages,
14
+ # it still uses a thread, but it should make it safer to use than sharing and
15
+ # locks.
16
+ class Thread::Process
17
+ def self.all
18
+ @@processes ||= {}
19
+ end
20
+
21
+ def self.register (name, process)
22
+ all[name] = process
23
+ end
24
+
25
+ def self.unregister (name)
26
+ all.delete(name)
27
+ end
28
+
29
+ def self.[] (name)
30
+ all[name]
31
+ end
32
+
33
+ # Create a new process executing the block.
34
+ def initialize (&block)
35
+ @channel = Thread::Channel.new
36
+
37
+ Thread.new {
38
+ instance_eval(&block)
39
+
40
+ @channel = nil
41
+ }
42
+ end
43
+
44
+ # Send a message to the process.
45
+ def send (what)
46
+ unless @channel
47
+ raise RuntimeError, 'the process has terminated'
48
+ end
49
+
50
+ @channel.send(what)
51
+
52
+ self
53
+ end
54
+
55
+ alias << send
56
+
57
+ private
58
+ def receive
59
+ @channel.receive
60
+ end
61
+
62
+ def receive!
63
+ @channel.receive!
64
+ end
65
+ end
66
+
67
+ class Thread
68
+ # Helper to create a process.
69
+ def self.process (&block)
70
+ Thread::Process.new(&block)
71
+ end
72
+ end
@@ -0,0 +1,83 @@
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 promise is an object that lets you wait for a value to be delivered to it.
14
+ class Thread::Promise
15
+ # Create a promise.
16
+ def initialize
17
+ @mutex = Mutex.new
18
+ end
19
+
20
+ # Check if a value has been delivered.
21
+ def delivered?
22
+ @mutex.synchronize {
23
+ instance_variable_defined? :@value
24
+ }
25
+ end
26
+
27
+ alias realized? delivered?
28
+
29
+ # Deliver a value.
30
+ def deliver (value)
31
+ return self if delivered?
32
+
33
+ @mutex.synchronize {
34
+ @value = value
35
+
36
+ cond.broadcast if cond?
37
+ }
38
+
39
+ self
40
+ end
41
+
42
+ alias << deliver
43
+
44
+ # Get the value that's been delivered, if none has been delivered yet the call
45
+ # will block until one is delivered.
46
+ #
47
+ # An optional timeout can be passed which will return nil if nothing has been
48
+ # delivered.
49
+ def value (timeout = nil)
50
+ return @value if delivered?
51
+
52
+ @mutex.synchronize {
53
+ cond.wait(@mutex, *timeout)
54
+ }
55
+
56
+ return @value if delivered?
57
+ end
58
+
59
+ alias ~ value
60
+
61
+ private
62
+ def cond?
63
+ instance_variable_defined? :@cond
64
+ end
65
+
66
+ def cond
67
+ @cond ||= ConditionVariable.new
68
+ end
69
+ end
70
+
71
+ class Thread
72
+ # Helper method to create a promise.
73
+ def self.promise
74
+ Thread::Promise.new
75
+ end
76
+ end
77
+
78
+ module Kernel
79
+ # Helper method to create a promise.
80
+ def promise
81
+ Thread::Promise.new
82
+ end
83
+ end
@@ -0,0 +1,38 @@
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 recursive mutex lets you lock in various threads recursively, allowing
14
+ # you to do multiple locks one inside another.
15
+ #
16
+ # You really shouldn't use this, but in some cases it makes your life easier.
17
+ class RecursiveMutex < Mutex
18
+ def initialize
19
+ @threads_lock = Mutex.new
20
+ @threads = Hash.new { |h, k| h[k] = 0 }
21
+
22
+ super
23
+ end
24
+
25
+ # Lock the mutex.
26
+ def lock
27
+ super if @threads_lock.synchronize{ (@threads[Thread.current] += 1) == 1 }
28
+ end
29
+
30
+ # Unlock the mutex.
31
+ def unlock
32
+ if @threads_lock.synchronize{ (@threads[Thread.current] -= 1) == 0 }
33
+ @threads.delete(Thread.current)
34
+
35
+ super
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thread/channel'
4
+
5
+ describe Thread::Channel do
6
+ it 'receives in the proper order' do
7
+ ch = Thread.channel
8
+ ch.send 'lol'
9
+ ch.send 'wut'
10
+
11
+ ch.receive.should == 'lol'
12
+ ch.receive.should == 'wut'
13
+ end
14
+
15
+ it 'receives with constraints properly' do
16
+ ch = Thread.channel
17
+ ch.send 'lol'
18
+ ch.send 'wut'
19
+
20
+ ch.receive { |v| v == 'wut' }.should == 'wut'
21
+ ch.receive.should == 'lol'
22
+ end
23
+
24
+ it 'receives nil when using non blocking mode and the channel is empty' do
25
+ ch = Thread.channel
26
+
27
+ ch.receive!.should == nil
28
+ end
29
+
30
+ it 'guards sending properly' do
31
+ ch = Thread.channel { |v| v.is_a? Integer }
32
+
33
+ expect {
34
+ ch.send 23
35
+ }.to_not raise_error
36
+
37
+ expect {
38
+ ch.send 'lol'
39
+ }.to raise_error
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thread/delay'
4
+
5
+ describe Thread::Delay do
6
+ it 'delivers a value properly' do
7
+ d = Thread.delay {
8
+ 42
9
+ }
10
+
11
+ d.value.should == 42
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thread/every'
4
+
5
+ describe Thread::Every do
6
+ it 'delivers a value properly' do
7
+ e = Thread.every(5) { sleep 0.5; 42 }
8
+
9
+ e.value.should == 42
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thread/future'
4
+
5
+ describe Thread::Future do
6
+ it 'delivers a value properly' do
7
+ f = Thread.future {
8
+ sleep 0.2
9
+
10
+ 42
11
+ }
12
+
13
+ f.value.should == 42
14
+ end
15
+
16
+ it 'properly checks if anything has been delivered' do
17
+ f = Thread.future {
18
+ sleep 0.2
19
+
20
+ 42
21
+ }
22
+
23
+ f.delivered?.should == false
24
+ sleep 0.3
25
+ f.delivered?.should == true
26
+ end
27
+
28
+ it 'does not block when a timeout is passed' do
29
+ f = Thread.future {
30
+ sleep 0.2
31
+
32
+ 42
33
+ }
34
+
35
+ f.value(0).should == nil
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thread/pipe'
4
+
5
+ describe Thread::Pipe do
6
+ it 'handles passing properly' do
7
+ p = Thread |-> d { d * 2 } |-> d { d * 4 }
8
+
9
+ p << 2
10
+ p << 4
11
+
12
+ p.deq.should == 16
13
+ p.deq.should == 32
14
+ end
15
+
16
+ it 'empty works properly' do
17
+ p = Thread |-> d { sleep 0.2; d * 2 } |-> d { d * 4 }
18
+
19
+ p.empty?.should == true
20
+ p.enq 42
21
+ p.empty?.should == false
22
+ p.deq
23
+ p.empty?.should == true
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ #! /usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thread/promise'
4
+
5
+ describe Thread::Promise do
6
+ it 'delivers a value properly' do
7
+ p = Thread.promise
8
+
9
+ Thread.new {
10
+ sleep 0.2
11
+
12
+ p << 42
13
+ }
14
+
15
+ p.value.should == 42
16
+ end
17
+
18
+ it 'properly checks if anything has been delivered' do
19
+ p = Thread.promise
20
+
21
+ Thread.new {
22
+ sleep 0.2
23
+
24
+ p << 42
25
+ }
26
+
27
+ p.delivered?.should == false
28
+ sleep 0.3
29
+ p.delivered?.should == true
30
+ end
31
+
32
+ it 'does not block when a timeout is passed' do
33
+ p = Thread.promise
34
+
35
+ p.value(0).should == nil
36
+ end
37
+ end
data/thread.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new {|s|
2
+ s.name = 'vinted-thread'
3
+ s.version = '0.1.1'
4
+ s.author = 'Justas Janauskas'
5
+ s.email = 'jjanauskas@gmail.com'
6
+ s.homepage = 'http://github.com/meh/ruby-thread'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.summary = 'Various extensions to the base thread library.'
9
+ s.description = 'Includes a thread pool, message passing capabilities, a recursive mutex, promise, future and delay.'
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
13
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ s.require_paths = ['lib']
15
+
16
+ s.add_development_dependency 'rspec'
17
+ s.add_development_dependency 'rake'
18
+ }
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vinted-thread
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Justas Janauskas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Includes a thread pool, message passing capabilities, a recursive mutex,
42
+ promise, future and delay.
43
+ email: jjanauskas@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .travis.yml
49
+ - README.md
50
+ - Rakefile
51
+ - lib/thread/channel.rb
52
+ - lib/thread/delay.rb
53
+ - lib/thread/every.rb
54
+ - lib/thread/future.rb
55
+ - lib/thread/pipe.rb
56
+ - lib/thread/pool.rb
57
+ - lib/thread/process.rb
58
+ - lib/thread/promise.rb
59
+ - lib/thread/recursive_mutex.rb
60
+ - tests/channel_spec.rb
61
+ - tests/delay_spec.rb
62
+ - tests/every_spec.rb
63
+ - tests/future_spec.rb
64
+ - tests/pipe_spec.rb
65
+ - tests/promise_spec.rb
66
+ - thread.gemspec
67
+ homepage: http://github.com/meh/ruby-thread
68
+ licenses: []
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.0.3
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Various extensions to the base thread library.
90
+ test_files: []