vinted-thread 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.
@@ -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: []