branch 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/LICENSE.md +22 -0
  4. data/README.md +126 -0
  5. data/lib/branch.rb +33 -0
  6. metadata +50 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7c72ad76f5d6090801c0cd8b5f6a5c6652390034
4
+ data.tar.gz: 58d91717c99e5bc49be2c78eb3928cede01b7687
5
+ SHA512:
6
+ metadata.gz: ac7ed88f7af8615dd991413660823fdd3144b4aa310419583563b58e5194f6df7115f8a980dd62447f22f71e1d8f19e23c01e0845cd7b6e2437f8fdb24067aaf
7
+ data.tar.gz: db6744d098f641eed0d2d8cacad99b8d90799d532bd4f5a4bc9e20b85a833c90b014f308ce6c0cbffabb19f517a74eda532d35d5958cda1fa9a0f78d8937b2a3
@@ -0,0 +1,7 @@
1
+ # Branch Changelog
2
+
3
+ ## v0.1.0
4
+
5
+ **February 11, 2014**
6
+
7
+ * `new` Initial version
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+ =====================
3
+
4
+ Copyright (c) 2014 Andrey 'lolmaus' Mikhaylov
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,126 @@
1
+ Branch
2
+ ======
3
+
4
+ **Run blocks asynchronously with little effort. A Ruby equivalent for JS `setTimeout`.**
5
+
6
+ This tiny lib was written to slightly reduce the amount of scaffolding required to do threads in Ruby. It is aimed at simpler use cases, for more complicated scenarios using vanilla thread syntax is recommended.
7
+
8
+ I hope Branch can save some frustration for people who discover that implementing a straightforward JS `setTimeout(function() { ... }, 0)` with Ruby is much more complicated and less intuitive. On the other hand, Branch is not an escape from getting to know how threads work.
9
+
10
+
11
+ How it works
12
+ ------------
13
+
14
+ 1. First of all, wrap your code with the `Branch.new { ... }` wrapper.
15
+ 2. Within that wrapper, the `branch { ... }` method is available. It starts the passed block in a new asynchronous thread.
16
+ 3. The end of the `Branch.new { ... }` wrapper will wait for all the threads to finish. In other words, the end of wrapper synchonizes your code. If you start another `Branch.new { ... }` afterwards, it will start sequentially after the previous branch is complete.
17
+ 4. To start a thread with a delay, use `branch(2) { ... }`. This example will be executed after two seconds, without blocking the main thread.
18
+ 5. If you need to synchronize a certain operation in order to prevent a race condition (JS coders beware!), you can use a mutex like this:
19
+
20
+ ```rb
21
+ branch do |mutexes|
22
+ mutexes[:meaningful_mutex_name].synchronize { ... }
23
+ end
24
+ ```
25
+
26
+ 6. You don't need to instantiate mutexes manually. To reuse a mutex in another thread, simply access the `mutexes` hash with the same key. You can use anything for keys, e. g. integers, but a meaningful symbol is recommended.
27
+ 7. Within a `branch`, you can use as many mutexes as you need.
28
+
29
+
30
+
31
+ Example usage
32
+ -------------
33
+
34
+ Please look into these pieces of code to see how Branch usage compares to vanilla syntax
35
+
36
+
37
+ ### Simple example
38
+
39
+ #### Vanilla threads
40
+
41
+ Requires a fair amount of scaffolding:
42
+
43
+ * A thread array is to be defined manually.
44
+ * Each thread should be added to that array.
45
+ * Threads should be joined so that the main script doesn't exit before all threads finish.
46
+
47
+ ```rb
48
+ threads = []
49
+ puts "Starting threads"
50
+ threads << Thread.new { sleep 5; puts "Thread 1 finished." }
51
+ threads << Thread.new { sleep 2; puts "Thread 2 finished." }
52
+ threads << Thread.new { sleep 1; puts "Thread 3 finished." }
53
+ puts "All threads started."
54
+ threads.each { |t| t.join }
55
+ puts "All threads complete."
56
+ ```
57
+
58
+
59
+ #### Branch equivalent
60
+
61
+ All the scaffolding you need is you need is a `Branch.new { }` wrapper.
62
+
63
+ ```ruby
64
+ Branch.new do
65
+ puts "Starting threads"
66
+ branch { sleep 5; puts "Thread 1 finished." }
67
+ branch { sleep 2; puts "Thread 2 finished." }
68
+ branch { sleep 1; puts "Thread 3 finished." }
69
+ puts "All threads started."
70
+ end
71
+ puts "All threads complete."
72
+ ```
73
+
74
+
75
+
76
+
77
+ ### Thread synchronization with multiple mutexes
78
+
79
+ All mutexes have to be instantiated manually.
80
+
81
+ #### Vanilla threads
82
+
83
+ ```rb
84
+ threads = []
85
+
86
+ mutex_array_access = Mutex.new
87
+ mutex_database_transaction = Mutex.new
88
+ mutex_coffee_brewing = Mutex.new
89
+
90
+ 10.times do
91
+ threads << Thread.new do
92
+
93
+ # Imitating a time-consuming operation
94
+ sleep rand(1..5)
95
+
96
+ mutex_array_access .synchronize { shared_array << 'foo' if shared_array.length < 5 }
97
+ mutex_database_transaction.synchronize { DB::send('foo', 888) { |foo| foo.bar }}
98
+ mutex_coffee_brewing .synchronize { coffee_machine.clean.fill('water').make_coffee }
99
+
100
+ end
101
+ end
102
+
103
+ threads.each { |t| t.join }
104
+ ```
105
+
106
+
107
+ #### Branch equivalent
108
+
109
+ Mutexes are instantiated automatically when they're first used and will persist throughuout the `Branch.new{ }` wrapper.
110
+
111
+ ```ruby
112
+ Branch.new do
113
+ 10.times do
114
+ branch do |mutexes|
115
+
116
+ # Imitating a time-consuming operation
117
+ sleep rand(1..5)
118
+
119
+ mutexes[:array_access] .synchronize { shared_array << 'foo' if shared_array.length < 5 }
120
+ mutexes[:database_transaction].synchronize { DB::send('foo', 888) { |foo| foo.bar }}
121
+ mutexes[:coffee_brewing] .synchronize { coffee_machine.clean.fill('water').make_coffee }
122
+
123
+ end
124
+ end
125
+ end
126
+ ```
@@ -0,0 +1,33 @@
1
+ class Branch
2
+
3
+ VERSION = "0.1.0"
4
+ DATE = "2014-07-31"
5
+
6
+ def initialize(&block)
7
+ @threads = []
8
+ @mutexes = Hash.new { |hash, key| hash[key] = Mutex.new }
9
+
10
+ # Executing the passed block within the context
11
+ # of this class' instance.
12
+ instance_eval &block if block_given?
13
+
14
+ # Waiting for all threads to finish
15
+ @threads.each { |thr| thr.join }
16
+ end
17
+
18
+ # This method will be available within a block
19
+ # passed to `Branch.new`.
20
+ def branch(delay = false, &block)
21
+
22
+ # Starting a new thread
23
+ @threads << Thread.new do
24
+
25
+ # Implementing the timeout functionality
26
+ sleep delay if delay.is_a? Numeric
27
+
28
+ # Executing the block passed to `branch`,
29
+ # providing mutexes into the block.
30
+ block.call @mutexes
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: branch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - lolmaus (Andrey Mikhaylov)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-31 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Run blocks asynchronously with little effort, a Ruby equivalent for JS
14
+ setTimeout
15
+ email:
16
+ - lolmaus@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - CHANGELOG.md
22
+ - LICENSE.md
23
+ - README.md
24
+ - lib/branch.rb
25
+ homepage: https://github.com/lolmaus/branch
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.3.6
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.2.2
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: This gem tries to reduce the amount of scaffolding required to be built manually
49
+ in order to fire a couple of threads.
50
+ test_files: []