org-converge 0.0.9 → 0.0.10

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: fd70719da7320b3897953946f0a2963b7357af63
4
+ data.tar.gz: 7132c1734caa2456114f35c029dad12615188073
5
+ SHA512:
6
+ metadata.gz: a11513f0b8d6395a12cf9372d8ebc5fcbf7afeb45ff2dffae3bb6230b3137c4c163b3eea5282ff895793d4d00854345a2d7352d28d3a7ab5ba5987ca2ac7f329
7
+ data.tar.gz: 50ef8e63011189ffd2f02dacbb4f32357b2b4d8c2ad410611a2b79eb4873ed282a95877e1f5a6b5e748bf6d538a99d7f95b9998ce9d7e9ef4b819056983b6045
data/Gemfile CHANGED
@@ -3,6 +3,7 @@ source 'https://rubygems.org'
3
3
  group :development, :test do
4
4
  gem 'rake'
5
5
  gem 'rspec'
6
+ gem 'nats', '0.5.0.beta.12'
6
7
  end
7
8
 
8
9
  gemspec
data/README.org CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  ** Description
9
9
 
10
- This attempts to be an experiment of using Org mode syntax to
10
+ This is an experiment of using Org mode to
11
11
  create documentable reproducible runs, borrowing some ideas
12
12
  of what is possible to do with tools like =chef-solo=,
13
13
  =rake=, =foreman=, etc...
@@ -18,15 +18,16 @@ of what is possible to do with tools like =chef-solo=,
18
18
 
19
19
  ** Motivation
20
20
 
21
- The Org babel syntax has proven to be flexible enough to writing
22
- /reproducible research/ papers. Then, I believe that configuring and setting up
23
- a server for example is something that could be also be done using
24
- the same syntax, given that /converging/ the configuration is something
25
- that one ought to be able to reproduce.
21
+ [[http://orgmode.org/worg/org-contrib/babel/Org Babel][Org Mode]] has proven to be flexible enough to write
22
+ [[http://www.jstatsoft.org/v46/i03][reproducible research papers]].
23
+ Then, I believe that configuring and setting up
24
+ a server for example, is something that could also be done using
25
+ the same approach, given that /converging/ the configuration
26
+ is a kind of run that one ought to be able to reproduce.
26
27
 
27
28
  ** Usage
28
29
 
29
- To run the blocks in parallel...
30
+ To run the blocks in parallel:
30
31
 
31
32
  #+begin_src sh
32
33
  org-converge path/to/setup-file.org --runmode=parallel
@@ -45,12 +46,121 @@ it is possible to make the blocks depend on one another.
45
46
  org-converge path/to/setup-file.org --runmode=chained
46
47
  #+end_src
47
48
 
49
+ In case the blocks have results blocks, it is possible to run
50
+ the blocks and matched against the results with the ~org-spec~ helper command:
51
+
52
+ #+begin_src sh
53
+ org-spec path/to/file-spec.org
54
+ #+end_src
55
+
48
56
  *** Other commands available
49
57
 
50
58
  : org-run # alias for org-converge
51
59
  : org-tangle # just tangles the contents without running the blocks
52
60
 
53
- ** Quick example
61
+ ** How it works
62
+
63
+ Org Converge uses a liberally extended version of Org Babel
64
+ features in order to give support for converging the configuration
65
+ of a server, and the [[https://github.com/wallyqs/org-ruby][Ruby implementation of the Org mode parser]]
66
+ which makes integrating with useful Ruby tools like foreman, rake, rspec and ohai more straightforward.
67
+
68
+ For example, using Org Babel we can easily spread config
69
+ files on a server by writing the following on a ~server.org~ file.
70
+
71
+ #+begin_src sh
72
+ ,#+begin_src yaml :tangle /etc/component.yml
73
+ multitenant: false
74
+ status_port: 10004
75
+ ,#+end_src
76
+ #+end_src
77
+
78
+ And then configure it by running it as follows, (considering we have
79
+ the correct permissions for tangling at =/etc/component.yml=):
80
+
81
+ #+begin_src sh
82
+ sudo org-converge server.org
83
+ #+end_src
84
+
85
+ Next, let's say that we no only one want to set the configured templates,
86
+ but that we also want to install some packages. In that case, we
87
+ should be able to do the following:
88
+ (Note: Currently, only named blocks would be run)
89
+
90
+ #+begin_src sh
91
+ ,** Configuring the component
92
+  
93
+ ,#+begin_src yaml :tangle /etc/component.yml
94
+ multitenant: false
95
+ status_port: 10004
96
+ ,#+end_src
97
+
98
+ ,** Installing the dependencies
99
+
100
+ Need the following so that ~bundle install~ can compile
101
+ the native extensions correctly.
102
+
103
+ # Giving the block a name would make it run
104
+  
105
+ ,#+name: build_essentials
106
+ ,#+begin_src sh
107
+ apt-get install build-essentials -y
108
+ ,#+end_src
109
+  
110
+ Then the following should work:
111
+  
112
+ ,#+name: bundle_install 
113
+ ,#+begin_src sh
114
+ cd project_path
115
+ bundle install
116
+ ,#+end_src
117
+ #+end_src
118
+
119
+ Since we are using Org mode syntax, it is possible to reuse this setup file by including it.
120
+
121
+ #+begin_src sh
122
+ ,#+TITLE: Another setup
123
+
124
+ Include the code blocks from the server into this:
125
+ ,#+include: "server.org"
126
+
127
+ ,#+name: install_org_mode
128
+ ,#+begin_src sh
129
+ apt-get install org-mode -y
130
+ ,#+end_src
131
+ #+end_src
132
+
133
+ #+end_src
134
+
135
+ ** Examples
136
+
137
+ Currently there is support for the following kind of runs:
138
+
139
+ - runs where the blocks need to run sequentially (~--runmode=sequential~) ::
140
+
141
+ Each code block is part of a step to be ran
142
+
143
+ - runs where the blocks need to be run in parallel (~--runmode=parallel~) ::
144
+
145
+ One example of this is having what is supposed to be a distributed system running locally for development (where ~foreman~ would be used).
146
+
147
+ - runs where the blocks need to be run in sequence according to defined dependencies (~--runmode=chained~) ::
148
+
149
+ Set of runs that are usually covered by using something like rake, make, etc...
150
+
151
+ - runs where the blocks are run and matched against the expected results for testing (~--runmode=spec~) ::
152
+
153
+ Each block is run and there is an assertion to check whether the contents in ~#+RESULTS~ block match
154
+
155
+ Besides being able to specify which kind of run to use through an option, it is also possible
156
+ to define this within the Org mode file itself as an in buffer setting:
157
+
158
+ #+begin_src org
159
+ ,#+TITLE: Defining the runmode as an in buffer setting
160
+ ,#+runmode: sequential
161
+ #+end_src
162
+
163
+ *** Parallel runs
54
164
 
55
165
  The following is an example of running 3 processes
56
166
  in parallel by defining them as code blocks from
@@ -58,20 +168,20 @@ an Org mode file:
58
168
 
59
169
  #+begin_src sh
60
170
  ,#+TITLE: Running Org babel processes in parallel
61
-
171
+  
62
172
  ,* Print with different languages
63
-  
173
+   
64
174
  ,#+name: hello_from_bash
65
175
  ,#+begin_src sh :shebang #!/bin/bash
66
176
  while true; do echo "hello world from bash"; sleep 1; done
67
177
  ,#+end_src
68
-  
178
+    
69
179
  ,#+name: hello_from_ruby
70
180
  ,#+begin_src ruby :shebang #!/usr/local/bin/ruby
71
181
  $stdout.sync = true
72
182
  loop { puts "hello world from ruby" ; sleep 1 }
73
183
  ,#+end_src
74
-  
184
+    
75
185
  ,#+name: hello_from_python
76
186
  ,#+begin_src python :shebang #!/usr/bin/python
77
187
  import time
@@ -86,7 +196,7 @@ an Org mode file:
86
196
  We store this in a file named =hello.org= and then run it as follows:
87
197
 
88
198
  #+begin_src sh
89
- org-converge hello.org
199
+ org-run hello.org
90
200
  #+end_src
91
201
 
92
202
  This would produce an output similar to the following:
@@ -94,7 +204,7 @@ This would produce an output similar to the following:
94
204
  #+begin_src sh
95
205
  [2014-05-04T19:23:40 +0900] Tangling 0 files...
96
206
  [2014-05-04T19:23:40 +0900] Tangling succeeded!
97
- [2014-05-04T19:23:40 +0900] Tangling 3 scripts within directory: /Users/mariko/repos/org-converge/run...
207
+ [2014-05-04T19:23:40 +0900] Tangling 3 scripts within directory: /Users/wallyqs/repos/org-converge/run...
98
208
  [2014-05-04T19:23:40 +0900] Running code blocks now! (3 runnable blocks found in total)
99
209
  [2014-05-04T19:23:40 +0900] hello_from_bash (4664) -- started with pid 4664
100
210
  [2014-05-04T19:23:40 +0900] hello_from_ruby (4665) -- started with pid 4665
@@ -105,56 +215,70 @@ This would produce an output similar to the following:
105
215
  [2014-05-04T19:23:42 +0900] hello_from_ruby (4665) -- hello world from ruby
106
216
  #+end_src
107
217
 
108
- ** How it works
109
-
110
- Org Converge uses an liberally extended version of Org Babel
111
- features in order to give support for converging the configuration
112
- of a server.
113
-
114
- For example, using Org Babel and macros we can easily spread config
115
- files on a server by writing the following on a ~server.org~ file.
218
+ Also possible to specify the name of the block to be ran:
116
219
 
117
220
  #+begin_src sh
118
- ,#+begin_src yaml :tangle /etc/component.yml
119
- multitenant: false
120
- status_port: 10004
121
- ,#+end_src
221
+ org-run hello.org --name from_ruby
122
222
  #+end_src
123
223
 
124
- And then configure it by running it as follows, (considering we have
125
- the correct permissions for tangling at =/etc/component.yml=):
224
+ *** Spec mode
225
+
226
+ In case the Org mode file has a results block which represents the expected result,
227
+ there is an ~org-spec~ command which can be useful to check whether there is change.
228
+ For example, given the following file stored in ~test.org~:
126
229
 
127
230
  #+begin_src sh
128
- sudo org-converge server.org
231
+ ,#+TITLE: Expected results example
232
+  
233
+ ,#+name: hello
234
+ ,#+begin_src ruby :results output
235
+ 10.times do
236
+ puts "hola"
237
+ end
238
+ ,#+end_src
239
+  
240
+ ,#+RESULTS: hello
241
+ ,#+begin_example
242
+ hola
243
+ hola
244
+ hola
245
+ hola
246
+ hola
247
+ hola
248
+ hola
249
+ hola
250
+ hola
251
+ hola
252
+ ,#+end_example
129
253
  #+end_src
130
254
 
131
- Next, let's say that we no only one want to set the configured templates,
132
- but that we also want to install some packages. In that case, we
133
- should be able to do the following:
255
+ We can be able to verify whether this is still correct by running ~org-spec test.org~
134
256
 
135
257
  #+begin_src sh
136
- ,* Configuring the component
137
-
138
- ,#+begin_src yaml :tangle /etc/component.yml
139
- multitenant: false
140
- status_port: 10004
141
- ,#+end_src
142
-
143
- ,* Installing the dependencies
144
-
145
- Need the following so that ~bundle install~ can compile
146
- the native extensions correctly.
258
+ Checking results from 'hello' code block: OK
259
+ #+end_src
147
260
 
148
- ,#+begin_src sh
149
- apt-get install build-essentials -y
150
- ,#+end_src
151
-  
152
- Then the following should work:
153
-  
154
- ,#+begin_src sh
155
- cd project_path
156
- bundle install
157
- ,#+end_src
261
+ As an example, let's say that the behavior of the original code block changed, and now says hello 5 times instead.
262
+ In that case the output would be as follows:
263
+
264
+ #+begin_src diff
265
+ Checking results from 'hello' code block: DIFF
266
+ @@ -1,11 +1,6 @@
267
+ -hola
268
+ -hola
269
+ -hola
270
+ -hola
271
+ -hola
272
+ -hola
273
+ -hola
274
+ -hola
275
+ -hola
276
+ -hola
277
+ +hello
278
+ +hello
279
+ +hello
280
+ +hello
281
+ +hello
158
282
  #+end_src
159
283
 
160
284
  ** Contributing
data/TODO CHANGED
@@ -2,7 +2,7 @@
2
2
  #+TODO: TODO | DONE CANCELED
3
3
  #+startup: showeverything
4
4
 
5
- * [0/7] > 0.0.9 version
5
+ * [0/9] 0.1.0 version
6
6
 
7
7
  - [ ] Macros can be loaded and applied to the configuration
8
8
  - [ ] Actually support converging and idempotency (~--runmode=idempotent~)
@@ -14,9 +14,15 @@
14
14
  - [ ] Display how the run would look like without making changes
15
15
  : org-converge setupfile.org --dry-run
16
16
  - [ ] Use :eval for evaling blocks (off by default)
17
- - [ ] Can use :dir for running a process relative to that directory
17
+ - [ ] Can use ~:dir~ for running a process relative to that directory
18
+ - [ ] Bugfix for when results blocks have only inline examples or images
19
+ - [ ] Bugfix for when the result from a ~org-spec~ run has non-zero exit status
18
20
 
19
- * [1/1] 0.0.8 version
21
+ * [1/1] 0.0.10
22
+
23
+ - [X] Add ~:procs~ to code blocks to identify how many times it should run
24
+
25
+ * [1/1] 0.0.8, 0.0.9 version
20
26
 
21
27
  - [X] ~org-spec~ exploration!
22
28
 
@@ -64,7 +64,8 @@ module Orgmode
64
64
  :mkdirp => line.block_header_arguments[':mkdirp'],
65
65
  :name => line.properties['block_name'],
66
66
  :before => line.block_header_arguments[':before'],
67
- :after => line.block_header_arguments[':after']
67
+ :after => line.block_header_arguments[':after'],
68
+ :procs => line.block_header_arguments[':procs'],
68
69
  }
69
70
  @scripts[@scripts_counter][:lang] = line.block_lang
70
71
  # TODO: have a way to specify which are the default binaries to be used per language
@@ -163,8 +163,7 @@ module OrgConverge
163
163
  # Decision: Only run blocks which have a name
164
164
  next unless script[:header][:name]
165
165
 
166
- display_name = script[:header][:name]
167
- @engine.register display_name, cmd, { :cwd => @root_dir, :logger => logger }
166
+ run_procs(script, cmd)
168
167
  end
169
168
  logger.info "Running code blocks now! (#{babel.ob.scripts.count} runnable blocks found in total)"
170
169
  @engine.start
@@ -178,8 +177,7 @@ module OrgConverge
178
177
  scripts.each do |key, script|
179
178
  file = File.expand_path("#{@run_dir}/#{key}")
180
179
  cmd = "#{script[:lang]} #{file}"
181
- display_name = script[:header][:name]
182
- @engine.register display_name, cmd, { :cwd => @root_dir, :logger => logger }
180
+ run_procs(script, cmd)
183
181
  end
184
182
 
185
183
  logger.info "Running code blocks now! (#{scripts.count} runnable blocks found in total)"
@@ -281,6 +279,7 @@ module OrgConverge
281
279
  exit 1 if failed.count > 0
282
280
  end
283
281
 
282
+ private
284
283
  def diff(expected_lines, actual_lines)
285
284
  output = ""
286
285
  file_length_difference = 0
@@ -335,5 +334,18 @@ module OrgConverge
335
334
  puts block[:lines]
336
335
  end
337
336
  end
337
+
338
+ def run_procs(script, cmd)
339
+ display_name = script[:header][:name]
340
+ if script[:header][:procs]
341
+ procs = script[:header][:procs].to_i
342
+ procs.times do |i|
343
+ proc_name = "#{display_name}-#{i}"
344
+ @engine.register proc_name, cmd, { :cwd => @root_dir, :logger => logger }
345
+ end
346
+ else
347
+ @engine.register display_name, cmd, { :cwd => @root_dir, :logger => logger }
348
+ end
349
+ end
338
350
  end
339
351
  end
@@ -1,3 +1,3 @@
1
1
  module OrgConverge
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
data/org-converge.gemspec CHANGED
@@ -14,9 +14,10 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "org-converge"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = OrgConverge::VERSION
17
- gem.add_runtime_dependency('docopt', '~> 0.5.0')
18
- gem.add_runtime_dependency('org-ruby', '~> 0.9.6')
19
- gem.add_runtime_dependency('foreman', '~> 0.63.0')
20
- gem.add_runtime_dependency('tco', '~> 0.1.0')
17
+ gem.add_runtime_dependency('docopt', '~> 0.5')
18
+ gem.add_runtime_dependency('org-ruby', '~> 0.9')
19
+ gem.add_runtime_dependency('foreman', '~> 0.63')
20
+ gem.add_runtime_dependency('tco', '~> 0.1')
21
21
  gem.add_runtime_dependency('rake', '~> 10.3')
22
+ gem.add_runtime_dependency('diff-lcs', '~> 1.2')
22
23
  end
@@ -6,7 +6,7 @@ with all output being flushed to the screen.
6
6
  - Count some numbers with bash
7
7
 
8
8
  #+name: bash_counter
9
- #+begin_src sh :shebang #!/bin/bash
9
+ #+begin_src bash :shebang #!/bin/bash
10
10
  echo '' > out.log
11
11
  for i in `seq 1 5`; do
12
12
  echo "Writing! $i"
@@ -8,27 +8,27 @@
8
8
  ** Runnable blocks
9
9
 
10
10
  #+name: runnable_block_1
11
- #+begin_src sh :results output
11
+ #+begin_src bash :results output
12
12
  echo "first" > output.log
13
13
  #+end_src
14
14
 
15
15
  ** COMMENT Non runnable blocks
16
16
 
17
17
  #+name: not_runnable_block_2
18
- #+begin_src sh :results output
18
+ #+begin_src bash :results output
19
19
  echo "should not run" >> output.log
20
20
  #+end_src
21
21
 
22
22
  ** More runnable blocks
23
23
 
24
24
  #+name: runnable_block_3
25
- #+begin_src sh :results output
25
+ #+begin_src bash :results output
26
26
  echo "third" >> output.log
27
27
  #+end_src
28
28
 
29
29
  *** COMMENT Not runnable block
30
30
 
31
31
  #+name: not_runnable_block_4
32
- #+begin_src sh :results output
32
+ #+begin_src bash :results output
33
33
  echo "fourth" >> output.log
34
34
  #+end_src
@@ -7,7 +7,7 @@ results, we can try checking whether the contents from the code block
7
7
  are evaling into what is being documented in the results block.
8
8
 
9
9
  #+name: hello
10
- #+begin_src sh :results output code :exports both
10
+ #+begin_src bash :results output code :exports both
11
11
  for i in `seq 20`; do
12
12
  echo "hello"
13
13
  done
@@ -26,7 +26,7 @@ This one would fail near christmas, outside of Japan,
26
26
  when the site is down, or there is a change in the rss.xml being provided.
27
27
 
28
28
  #+name: christmas_check
29
- #+begin_src sh :results output
29
+ #+begin_src bash :results output
30
30
  curl https://isitchristmas.com/rss.xml 2> /dev/null | grep title
31
31
  # curl isitchristmastyet.com 2> /dev/null
32
32
  #+end_src
@@ -34,29 +34,14 @@ curl https://isitchristmas.com/rss.xml 2> /dev/null | grep title
34
34
  #+RESULTS: christmas_check
35
35
  #+begin_example
36
36
  <title>Is It Christmas?</title>
37
- <title>いいえ</title>
38
- <title>いいえ</title>
39
- <title>いいえ</title>
40
- <title>いいえ</title>
41
- <title>いいえ</title>
42
- <title>いいえ</title>
43
- <title>いいえ</title>
44
- <title>いいえ</title>
45
- <title>いいえ</title>
46
- <title>いいえ</title>
47
- #+end_example
48
-
49
- #+RESULTS: fetch_google
50
- #+begin_example
51
- <title>Is It Christmas?</title>
52
- <title>いいえ</title>
53
- <title>いいえ</title>
54
- <title>いいえ</title>
55
- <title>いいえ</title>
56
- <title>いいえ</title>
57
- <title>いいえ</title>
58
- <title>いいえ</title>
59
- <title>いいえ</title>
60
- <title>いいえ</title>
61
- <title>いいえ</title>
37
+ <title>NO</title>
38
+ <title>NO</title>
39
+ <title>NO</title>
40
+ <title>NO</title>
41
+ <title>NO</title>
42
+ <title>NO</title>
43
+ <title>NO</title>
44
+ <title>NO</title>
45
+ <title>NO</title>
46
+ <title>NO</title>
62
47
  #+end_example
@@ -9,7 +9,7 @@ With ~:after first~, the ~second~ block becomes
9
9
  a prerequisite of the ~first~ block.
10
10
 
11
11
  #+name: second
12
- #+begin_src sh :after first
12
+ #+begin_src bash :after first
13
13
  for i in `seq 5 10`; do
14
14
  echo $i >> out.log
15
15
  done
@@ -35,7 +35,7 @@ The same with ~:before all~, this would be executed
35
35
  at the beginning.
36
36
 
37
37
  #+name: prologue
38
- #+begin_src sh :before first :results output
38
+ #+begin_src bash :before first :results output
39
39
  echo "init" > out.log
40
40
  #+end_src
41
41
 
@@ -0,0 +1,347 @@
1
+ #+TITLE: Sequential and Distributed runs to solve Problem #4 from Project Euler, written in Org mode Babel mode
2
+ #+startup: showeverything
3
+
4
+ [[https://projecteuler.net/problem=4][Problem #4]] from Project Euler reads as follows:
5
+
6
+ #+begin_quote
7
+ A palindromic number reads the same both ways.
8
+ The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
9
+ Find the largest palindrome made from the product of two 3-digit numbers.
10
+ #+end_quote
11
+
12
+ We can notice the following from the problem:
13
+
14
+ - The definition of a palindrome ::
15
+ Can be implemented considering that the reverse list of chars should be identical to the original list.
16
+
17
+ - There is exponential growth ::
18
+ We look for the largest palindrome in the range of 3 digit numbers (100 - 999).
19
+ For this, we iterate 2 times on the range, multiply the entries and make the palindrome check.
20
+
21
+ *** First implementation: Sequential run to find the largest palindrome
22
+
23
+ A straightforward implementation of the problem is by iterating twice
24
+ over the same range and grabbing the highest largest number:
25
+
26
+ #+name: sequential_palindrome_check
27
+ #+begin_src ruby :results output
28
+ require 'benchmark'
29
+
30
+ def palindrome_check(number)
31
+ digits = number.to_s.split('').map(&:to_i)
32
+ reverse_is_equal = digits == digits.reverse ? true : false
33
+
34
+ reverse_is_equal
35
+ end
36
+
37
+ SMALLEST_NUMBER = 100
38
+ LARGEST_NUMBER = 999
39
+
40
+ last_palindrome = 0
41
+ last_x = 0
42
+ last_y = 0
43
+ bm = Benchmark.measure do
44
+ SMALLEST_NUMBER.upto(LARGEST_NUMBER).each do |i|
45
+ SMALLEST_NUMBER.upto(LARGEST_NUMBER).each do |j|
46
+
47
+ product = i * j
48
+ is_palindrome = palindrome_check(product)
49
+ if is_palindrome and product > last_palindrome
50
+ last_palindrome = product
51
+ last_x = i
52
+ last_y = j
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ puts "The largest palindrome within this range is: #{last_palindrome} (x: #{last_x}, y: #{last_y}) and it took #{bm}"
59
+ #+end_src
60
+
61
+ #+RESULTS:
62
+ : The largest palindrome within this range is: 906609 (x: 913, y: 993) and it took 16.36000
63
+
64
+ For 3 digits, this approach seems like good enough. But what if we
65
+ want to find out the largest palindrome number with 4 digits? Since
66
+ growth is exponential, running this in a single process will take a
67
+ while to finish.
68
+
69
+ *** Second implementation: Distributed parallel run to find the largest palindrome
70
+
71
+ One way to improve things is to parallelize the computation and
72
+ coordinating the aggregation of the results by using a message
73
+ bus. Borrowing [[http://blog.gopheracademy.com/plumbing-and-semantics][an idea]] in this case we use [[http://blog.gopheracademy.com/plumbing-and-semantics][NATS]].
74
+
75
+ The approach to take here will be:
76
+
77
+ - Split the ranges in subranges according to the number of subscribers
78
+ - Make each one of the subscribers do the computation for us and emit
79
+ the response with the results
80
+ - Collect the responses and identify the smallest, largest palindrome
81
+ within the range
82
+
83
+ For this run, we will have 10 checkers doing the calculation in
84
+ parallel, and one process collecting the replies.
85
+
86
+ #+name: dist_palindrome_checks_aggregator
87
+ #+begin_src ruby
88
+ # palindrome_checks_aggregator.rb
89
+ require 'nats/client'
90
+ require 'json'
91
+
92
+ sleep 6 # Wait for the checkers to be ready before sending compute requests
93
+ $stdout.sync = true
94
+ ["TERM", "INT"].each { |sig| trap(sig) { NATS.stop } }
95
+
96
+ MIN_RANGE = 100
97
+ MAX_RANGE = 999
98
+ CHECKERS = 10
99
+
100
+ @checkers_responses = 0
101
+ @palindromes = []
102
+
103
+ NATS.start {
104
+ # Stop running at the same time as the nats-server
105
+ EM.add_timer(40) { NATS.stop; exit 0 }
106
+ NATS.subscribe('palindromes-check.responses') do |msg, reply, sub|
107
+ palindromes_computation = JSON.parse(msg)
108
+ puts "Thanks, got: #{palindromes_computation['palindromes_found'].count} palindromes."
109
+ @palindromes << palindromes_computation['palindromes_found'].flatten
110
+ @checkers_responses += 1
111
+
112
+ total = @palindromes.flatten.count
113
+ smallest = @palindromes.flatten.min
114
+ largest = @palindromes.flatten.max
115
+ puts ">>>> So far we have found #{total} palindromes between #{MIN_RANGE} and #{MAX_RANGE}"
116
+ puts ">>>> The smallest one is #{smallest}"
117
+ puts ">>>> The largest one is #{largest}"
118
+ File.open('result', 'w') {|f| f.puts largest }
119
+ end
120
+
121
+ balanced_check = MAX_RANGE / CHECKERS
122
+
123
+ ranges = []
124
+ min_range = MIN_RANGE
125
+ begin
126
+ next_min_range = min_range + balanced_check
127
+ ranges << [min_range, next_min_range - 1]
128
+ min_range = next_min_range
129
+ end while min_range < MAX_RANGE
130
+
131
+ ranges.each do |range|
132
+ range_start = range.first
133
+ range_finish = [range.last, MAX_RANGE].min
134
+ range_info = {'start' => range_start, 'upto' => range_finish, 'min' => MIN_RANGE, 'max' => MAX_RANGE}
135
+
136
+ # Only want one checker to respond to this
137
+ NATS.request('palindromes-check.requests', nil, :max => 1) do |response|
138
+ checker_info = JSON.parse(response)
139
+ puts "Sending compute request to: #{checker_info}: #{range_info}"
140
+ NATS.publish("palindromes-check.#{checker_info['checker_id']}.compute", range_info.to_json) do
141
+ puts "Registered: #{range_info} to be done by #{checker_info['checker_id']}."
142
+ end
143
+ end
144
+
145
+ end
146
+ }
147
+ #+end_src
148
+
149
+ And each one of the checkers, has code as the one below to be able to
150
+ announce itself. Setting ~:procs 10~ to match the number of checkers
151
+ in the aggregator.
152
+
153
+ #+name: dist_palindrome_checker
154
+ #+begin_src ruby :procs 10
155
+ # palindrome_checker.rb
156
+ require 'nats/client'
157
+ require 'securerandom'
158
+ require 'json'
159
+
160
+ sleep 4 # wait a little before the server starts
161
+ $stdout.sync = true
162
+
163
+ CHECKER_ID = SecureRandom.uuid
164
+ CHECKER_INFO = {'checker_id' => CHECKER_ID }
165
+
166
+ @offerings = 0
167
+ @palindromes = []
168
+
169
+ def palindrome_check(number)
170
+ digits = number.to_s.split('').map(&:to_i)
171
+ reverse_is_equal = digits == digits.reverse ? true : false
172
+
173
+ reverse_is_equal
174
+ end
175
+
176
+ def compute_palindromes_in_range(range_info)
177
+ range = JSON.parse(range_info)
178
+
179
+ range_min = range['min']
180
+ range_max = range['max']
181
+ range_start = range['start']
182
+ range_upto = range['upto']
183
+
184
+ range_min.upto(range_max) do |i|
185
+ # Split this subrange among other checkers
186
+ range_start.upto(range_upto) do |j|
187
+ product = i * j
188
+ is_palindrome = palindrome_check(product)
189
+ @palindromes << product if is_palindrome
190
+ end
191
+ end
192
+
193
+ results = {'palindromes_found' => @palindromes }
194
+
195
+ results
196
+ end
197
+
198
+ NATS.start do
199
+ puts "[#{CHECKER_ID}] Ready for requests"
200
+ NATS.subscribe('palindromes-check.requests') do |msg, reply, sub|
201
+ EM.add_timer(@offerings) { NATS.publish(reply, CHECKER_INFO.to_json) }
202
+ @offerings += 1
203
+ end
204
+
205
+ NATS.subscribe("palindromes-check.#{CHECKER_ID}.compute") do |msg, reply, sub|
206
+ puts "Start working on: #{msg}"
207
+ results = compute_palindromes_in_range(msg)
208
+ @offerings -= 1
209
+ NATS.publish("palindromes-check.responses", results.to_json) do
210
+ puts "I'm done then."
211
+ NATS.stop
212
+ exit 0
213
+ end
214
+ end
215
+ end
216
+ #+end_src
217
+
218
+ **** Starting the run
219
+
220
+ Ruby implementation of NATS can be installed with:
221
+
222
+ #+begin_src sh
223
+ gem list | grep nats.*0.5.0.beta.12
224
+ [ $? -ne 0 ] && gem install nats --pre
225
+ #+end_src
226
+
227
+ And we execute the run as follows:
228
+
229
+ #+name: dist_nats_server_daemon
230
+ #+begin_src bash
231
+ # timeout nats in 30 seconds
232
+ (bundle exec nats-server) & sleep 40; kill $! 2> /dev/null || :
233
+ #+end_src
234
+
235
+ : palindrome_checks_aggregator.rb &
236
+ : for i in `seq 1 10`; do
237
+ : ruby palindrome_checker.rb &
238
+ : done
239
+
240
+ Or since this Gist is also written in literate Org mode style, it can be run as follows:
241
+
242
+ : gem install org-converge
243
+ : org-run palindromes.org
244
+
245
+ Sample output from this would look like this:
246
+
247
+ #+begin_src sh
248
+ [2014-05-27T04:40:51 +0900] Tangling 0 files...
249
+ [2014-05-27T04:40:51 +0900] Tangling succeeded!
250
+ [2014-05-27T04:40:51 +0900] Tangling 7 scripts within directory: /Users/mariko/Dropbox/repos/org-converge/run...
251
+ [2014-05-27T04:40:51 +0900] Running code blocks now! (7 runnable blocks found in total)
252
+ [2014-05-27T04:40:52 +0900] sequential_palindrome_check (87486) -- started with pid 87486
253
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checks_aggregator (87487) -- started with pid 87487
254
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-0 (87489) -- started with pid 87489
255
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-1 (87491) -- started with pid 87491
256
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-2 (87493) -- started with pid 87493
257
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-3 (87494) -- started with pid 87494
258
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-4 (87496) -- started with pid 87496
259
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-5 (87498) -- started with pid 87498
260
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-6 (87499) -- started with pid 87499
261
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-7 (87500) -- started with pid 87500
262
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-8 (87501) -- started with pid 87501
263
+ [2014-05-27T04:40:52 +0900] dist_palindrome_checker-9 (87502) -- started with pid 87502
264
+ [2014-05-27T04:40:52 +0900] dist_nats_server_daemon (87503) -- started with pid 87503
265
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-0 (87489) -- [dc401559-c0c8-450b-a0fd-f2093b0f59e0] Ready for requests
266
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-7 (87500) -- [7624024f-1be8-4962-aad6-aa2ae8366f0e] Ready for requests
267
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-1 (87491) -- [218a8813-d5e9-4bc0-a206-c12ac5086126] Ready for requests
268
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-4 (87496) -- [69b2b618-8a67-40c1-bf5a-988077a49251] Ready for requests
269
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-8 (87501) -- [1e11550a-d609-461e-8ec6-9eae82c27ac6] Ready for requests
270
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-2 (87493) -- [d1148625-360a-49ff-bd4d-257fecd9e7d6] Ready for requests
271
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-5 (87498) -- [e72b34e7-22ff-42e0-9d6b-92aa26e15ace] Ready for requests
272
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-3 (87494) -- [2f2b4180-3fcf-4461-8b59-632fdd5236a7] Ready for requests
273
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-6 (87499) -- [d5129048-0994-4cd3-9cae-44c0d394de1e] Ready for requests
274
+ [2014-05-27T04:41:00 +0900] dist_palindrome_checker-9 (87502) -- [5c2b3866-41dd-4338-9c28-343d28291853] Ready for requests
275
+ [2014-05-27T04:41:02 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"dc401559-c0c8-450b-a0fd-f2093b0f59e0"}: {"start"=>100, "upto"=>198, "min"=>100, "max"=>999}
276
+ [2014-05-27T04:41:02 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>100, "upto"=>198, "min"=>100, "max"=>999} to be done by dc401559-c0c8-450b-a0fd-f2093b0f59e0.
277
+ [2014-05-27T04:41:02 +0900] dist_palindrome_checker-0 (87489) -- Start working on: {"start":100,"upto":198,"min":100,"max":999}
278
+ [2014-05-27T04:41:03 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"7624024f-1be8-4962-aad6-aa2ae8366f0e"}: {"start"=>199, "upto"=>297, "min"=>100, "max"=>999}
279
+ [2014-05-27T04:41:03 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>199, "upto"=>297, "min"=>100, "max"=>999} to be done by 7624024f-1be8-4962-aad6-aa2ae8366f0e.
280
+ [2014-05-27T04:41:03 +0900] dist_palindrome_checker-7 (87500) -- Start working on: {"start":199,"upto":297,"min":100,"max":999}
281
+ [2014-05-27T04:41:04 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"218a8813-d5e9-4bc0-a206-c12ac5086126"}: {"start"=>298, "upto"=>396, "min"=>100, "max"=>999}
282
+ [2014-05-27T04:41:04 +0900] dist_palindrome_checker-1 (87491) -- Start working on: {"start":298,"upto":396,"min":100,"max":999}
283
+ [2014-05-27T04:41:04 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>298, "upto"=>396, "min"=>100, "max"=>999} to be done by 218a8813-d5e9-4bc0-a206-c12ac5086126.
284
+ [2014-05-27T04:41:05 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"1e11550a-d609-461e-8ec6-9eae82c27ac6"}: {"start"=>397, "upto"=>495, "min"=>100, "max"=>999}
285
+ [2014-05-27T04:41:05 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>397, "upto"=>495, "min"=>100, "max"=>999} to be done by 1e11550a-d609-461e-8ec6-9eae82c27ac6.
286
+ [2014-05-27T04:41:05 +0900] dist_palindrome_checker-8 (87501) -- Start working on: {"start":397,"upto":495,"min":100,"max":999}
287
+ [2014-05-27T04:41:06 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"d1148625-360a-49ff-bd4d-257fecd9e7d6"}: {"start"=>496, "upto"=>594, "min"=>100, "max"=>999}
288
+ [2014-05-27T04:41:06 +0900] dist_palindrome_checker-2 (87493) -- Start working on: {"start":496,"upto":594,"min":100,"max":999}
289
+ [2014-05-27T04:41:06 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>496, "upto"=>594, "min"=>100, "max"=>999} to be done by d1148625-360a-49ff-bd4d-257fecd9e7d6.
290
+ [2014-05-27T04:41:07 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"69b2b618-8a67-40c1-bf5a-988077a49251"}: {"start"=>595, "upto"=>693, "min"=>100, "max"=>999}
291
+ [2014-05-27T04:41:07 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>595, "upto"=>693, "min"=>100, "max"=>999} to be done by 69b2b618-8a67-40c1-bf5a-988077a49251.
292
+ [2014-05-27T04:41:07 +0900] dist_palindrome_checker-4 (87496) -- Start working on: {"start":595,"upto":693,"min":100,"max":999}
293
+ [2014-05-27T04:41:08 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"d5129048-0994-4cd3-9cae-44c0d394de1e"}: {"start"=>694, "upto"=>792, "min"=>100, "max"=>999}
294
+ [2014-05-27T04:41:08 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>694, "upto"=>792, "min"=>100, "max"=>999} to be done by d5129048-0994-4cd3-9cae-44c0d394de1e.
295
+ [2014-05-27T04:41:08 +0900] dist_palindrome_checker-6 (87499) -- Start working on: {"start":694,"upto":792,"min":100,"max":999}
296
+ [2014-05-27T04:41:09 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"e72b34e7-22ff-42e0-9d6b-92aa26e15ace"}: {"start"=>793, "upto"=>891, "min"=>100, "max"=>999}
297
+ [2014-05-27T04:41:09 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>793, "upto"=>891, "min"=>100, "max"=>999} to be done by e72b34e7-22ff-42e0-9d6b-92aa26e15ace.
298
+ [2014-05-27T04:41:09 +0900] dist_palindrome_checker-5 (87498) -- Start working on: {"start":793,"upto":891,"min":100,"max":999}
299
+ [2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 658 palindromes.
300
+ [2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 658 palindromes between 100 and 999
301
+ [2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
302
+ [2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 180081
303
+ [2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"2f2b4180-3fcf-4461-8b59-632fdd5236a7"}: {"start"=>892, "upto"=>990, "min"=>100, "max"=>999}
304
+ [2014-05-27T04:41:10 +0900] dist_palindrome_checker-3 (87494) -- Start working on: {"start":892,"upto":990,"min":100,"max":999}
305
+ [2014-05-27T04:41:10 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>892, "upto"=>990, "min"=>100, "max"=>999} to be done by 2f2b4180-3fcf-4461-8b59-632fdd5236a7.
306
+ [2014-05-27T04:41:11 +0900] dist_palindrome_checks_aggregator (87487) -- Sending compute request to: {"checker_id"=>"dc401559-c0c8-450b-a0fd-f2093b0f59e0"}: {"start"=>991, "upto"=>999, "min"=>100, "max"=>999}
307
+ [2014-05-27T04:41:11 +0900] dist_palindrome_checks_aggregator (87487) -- Registered: {"start"=>991, "upto"=>999, "min"=>100, "max"=>999} to be done by dc401559-c0c8-450b-a0fd-f2093b0f59e0.
308
+ [2014-05-27T04:41:11 +0900] dist_palindrome_checker-0 (87489) -- Start working on: {"start":991,"upto":999,"min":100,"max":999}
309
+ [2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 662 palindromes.
310
+ [2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 1320 palindromes between 100 and 999
311
+ [2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
312
+ [2014-05-27T04:41:12 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
313
+ [2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 422 palindromes.
314
+ [2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 1742 palindromes between 100 and 999
315
+ [2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
316
+ [2014-05-27T04:41:14 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
317
+ [2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 287 palindromes.
318
+ [2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2029 palindromes between 100 and 999
319
+ [2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
320
+ [2014-05-27T04:41:16 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
321
+ [2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 265 palindromes.
322
+ [2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2294 palindromes between 100 and 999
323
+ [2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
324
+ [2014-05-27T04:41:18 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
325
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 204 palindromes.
326
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2498 palindromes between 100 and 999
327
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
328
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
329
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 175 palindromes.
330
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2673 palindromes between 100 and 999
331
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
332
+ [2014-05-27T04:41:20 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
333
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 162 palindromes.
334
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2835 palindromes between 100 and 999
335
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
336
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
337
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 154 palindromes.
338
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 2989 palindromes between 100 and 999
339
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
340
+ [2014-05-27T04:41:21 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
341
+ [2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- Thanks, got: 139 palindromes.
342
+ [2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> So far we have found 3128 palindromes between 100 and 999
343
+ [2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The smallest one is 10201
344
+ [2014-05-27T04:41:22 +0900] dist_palindrome_checks_aggregator (87487) -- >>>> The largest one is 906609
345
+ [2014-05-27T04:41:34 +0900] sequential_palindrome_check (87486) -- The largest palindrome within this range is: 906609 (x: 913, y: 993) and it took 18.470000 0.270000 18.740000 ( 38.710531)
346
+ [2014-05-27T04:41:34 +0900] sequential_palindrome_check (87486) -- exited with code 0
347
+ #+end_src
@@ -5,7 +5,7 @@
5
5
  In this example, we will have scripts being chained one after another.
6
6
 
7
7
  #+name: first
8
- #+begin_src sh :shebang #!/bin/bash
8
+ #+begin_src bash :shebang #!/bin/bash
9
9
  sleep 5
10
10
  echo "first" > out.log
11
11
  #+end_src
@@ -119,7 +119,7 @@ describe OrgConverge::Command do
119
119
  success.should == true
120
120
  end
121
121
 
122
- it "should run 'expected_results' with example blocks" do
122
+ pending "should run 'expected_results' with example blocks" do
123
123
  example_dir = File.join(EXAMPLES_DIR, 'expected_results')
124
124
  setup_file = File.join(example_dir, 'spec2.org')
125
125
 
@@ -131,4 +131,18 @@ describe OrgConverge::Command do
131
131
  success = o.execute!
132
132
  success.should == true
133
133
  end
134
+
135
+ it "should run 'multi_proc' with the same number of defined :procs" do
136
+ example_dir = File.join(EXAMPLES_DIR, 'multi_proc')
137
+ setup_file = File.join(example_dir, 'run.org')
138
+
139
+ o = OrgConverge::Command.new({
140
+ '<org_file>' => setup_file,
141
+ '--root-dir' => example_dir
142
+ })
143
+ success = o.execute!
144
+ success.should == true
145
+ largest = File.open("#{example_dir}/result").read
146
+ largest.should == "906609\n"
147
+ end
134
148
  end
metadata CHANGED
@@ -1,71 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: org-converge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
5
- prerelease:
4
+ version: 0.0.10
6
5
  platform: ruby
7
6
  authors:
8
7
  - Waldemar Quevedo
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-05-05 00:00:00.000000000 Z
11
+ date: 2014-05-26 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: docopt
16
- requirement: &70315024394420 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
21
- version: 0.5.0
19
+ version: '0.5'
22
20
  type: :runtime
23
21
  prerelease: false
24
- version_requirements: *70315024394420
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0.5'
25
27
  - !ruby/object:Gem::Dependency
26
28
  name: org-ruby
27
- requirement: &70315024393940 !ruby/object:Gem::Requirement
28
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
31
  - - ~>
31
32
  - !ruby/object:Gem::Version
32
- version: 0.9.6
33
+ version: '0.9'
33
34
  type: :runtime
34
35
  prerelease: false
35
- version_requirements: *70315024393940
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '0.9'
36
41
  - !ruby/object:Gem::Dependency
37
42
  name: foreman
38
- requirement: &70315024393480 !ruby/object:Gem::Requirement
39
- none: false
43
+ requirement: !ruby/object:Gem::Requirement
40
44
  requirements:
41
45
  - - ~>
42
46
  - !ruby/object:Gem::Version
43
- version: 0.63.0
47
+ version: '0.63'
44
48
  type: :runtime
45
49
  prerelease: false
46
- version_requirements: *70315024393480
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.63'
47
55
  - !ruby/object:Gem::Dependency
48
56
  name: tco
49
- requirement: &70315020658160 !ruby/object:Gem::Requirement
50
- none: false
57
+ requirement: !ruby/object:Gem::Requirement
51
58
  requirements:
52
59
  - - ~>
53
60
  - !ruby/object:Gem::Version
54
- version: 0.1.0
61
+ version: '0.1'
55
62
  type: :runtime
56
63
  prerelease: false
57
- version_requirements: *70315020658160
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.1'
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: rake
60
- requirement: &70315020657280 !ruby/object:Gem::Requirement
61
- none: false
71
+ requirement: !ruby/object:Gem::Requirement
62
72
  requirements:
63
73
  - - ~>
64
74
  - !ruby/object:Gem::Version
65
75
  version: '10.3'
66
76
  type: :runtime
67
77
  prerelease: false
68
- version_requirements: *70315020657280
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '10.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: diff-lcs
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '1.2'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '1.2'
69
97
  description: A light configuration management tool for Org mode
70
98
  email:
71
99
  - waldemar.quevedo@gmail.com
@@ -106,33 +134,33 @@ files:
106
134
  - spec/converge_examples/expected_results/spec.org
107
135
  - spec/converge_examples/expected_results/spec2.org
108
136
  - spec/converge_examples/linked_tasks/tasks.org
137
+ - spec/converge_examples/multi_proc/run.org
109
138
  - spec/converge_examples/runlist_example/setup.org
110
139
  - spec/converge_examples/specified_block/run.org
111
140
  - spec/converge_spec.rb
112
141
  - spec/spec_helper.rb
113
142
  homepage: https://github.com/wallyqs/org-converge
114
143
  licenses: []
144
+ metadata: {}
115
145
  post_install_message:
116
146
  rdoc_options: []
117
147
  require_paths:
118
148
  - lib
119
149
  required_ruby_version: !ruby/object:Gem::Requirement
120
- none: false
121
150
  requirements:
122
- - - ! '>='
151
+ - - '>='
123
152
  - !ruby/object:Gem::Version
124
153
  version: '0'
125
154
  required_rubygems_version: !ruby/object:Gem::Requirement
126
- none: false
127
155
  requirements:
128
- - - ! '>='
156
+ - - '>='
129
157
  - !ruby/object:Gem::Version
130
158
  version: '0'
131
159
  requirements: []
132
160
  rubyforge_project:
133
- rubygems_version: 1.8.10
161
+ rubygems_version: 2.2.2
134
162
  signing_key:
135
- specification_version: 3
163
+ specification_version: 4
136
164
  summary: Provides an 'org-converge' command which can be used for tangling and running
137
165
  Org mode code blocks
138
166
  test_files:
@@ -143,8 +171,8 @@ test_files:
143
171
  - spec/converge_examples/expected_results/spec.org
144
172
  - spec/converge_examples/expected_results/spec2.org
145
173
  - spec/converge_examples/linked_tasks/tasks.org
174
+ - spec/converge_examples/multi_proc/run.org
146
175
  - spec/converge_examples/runlist_example/setup.org
147
176
  - spec/converge_examples/specified_block/run.org
148
177
  - spec/converge_spec.rb
149
178
  - spec/spec_helper.rb
150
- has_rdoc: