engineyard-serverside 1.2.0
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.
- data/LICENSE +19 -0
- data/bin/engineyard-serverside +10 -0
- data/lib/engineyard-serverside.rb +49 -0
- data/lib/engineyard-serverside/bundle_installer.rb +4 -0
- data/lib/engineyard-serverside/cli.rb +146 -0
- data/lib/engineyard-serverside/configuration.rb +130 -0
- data/lib/engineyard-serverside/default_maintenance_page.html +29 -0
- data/lib/engineyard-serverside/deploy.rb +321 -0
- data/lib/engineyard-serverside/deploy_hook.rb +80 -0
- data/lib/engineyard-serverside/lockfile_parser.rb +55 -0
- data/lib/engineyard-serverside/logged_output.rb +78 -0
- data/lib/engineyard-serverside/server.rb +70 -0
- data/lib/engineyard-serverside/strategies/git.rb +136 -0
- data/lib/engineyard-serverside/task.rb +62 -0
- data/lib/engineyard-serverside/version.rb +3 -0
- data/lib/vendor/dataflow/HISTORY +52 -0
- data/lib/vendor/dataflow/LICENSE +19 -0
- data/lib/vendor/dataflow/README.textile +290 -0
- data/lib/vendor/dataflow/Rakefile +36 -0
- data/lib/vendor/dataflow/dataflow.rb +120 -0
- data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
- data/lib/vendor/dataflow/dataflow/equality.rb +28 -0
- data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
- data/lib/vendor/dataflow/dataflow/port.rb +54 -0
- data/lib/vendor/dataflow/examples/barrier.rb +9 -0
- data/lib/vendor/dataflow/examples/data_driven.rb +17 -0
- data/lib/vendor/dataflow/examples/dataflow_http_gets.rb +13 -0
- data/lib/vendor/dataflow/examples/flow.rb +20 -0
- data/lib/vendor/dataflow/examples/future_http_gets.rb +12 -0
- data/lib/vendor/dataflow/examples/future_queue.rb +11 -0
- data/lib/vendor/dataflow/examples/instance_variables.rb +15 -0
- data/lib/vendor/dataflow/examples/laziness.rb +9 -0
- data/lib/vendor/dataflow/examples/local_variables.rb +11 -0
- data/lib/vendor/dataflow/examples/messages.rb +26 -0
- data/lib/vendor/dataflow/examples/port_http_gets.rb +13 -0
- data/lib/vendor/dataflow/examples/port_send.rb +10 -0
- data/lib/vendor/dataflow/examples/ring.rb +21 -0
- data/lib/vendor/dataflow/spec/actor_spec.rb +28 -0
- data/lib/vendor/dataflow/spec/anonymous_variables_spec.rb +21 -0
- data/lib/vendor/dataflow/spec/barrier_spec.rb +25 -0
- data/lib/vendor/dataflow/spec/by_need_spec.rb +55 -0
- data/lib/vendor/dataflow/spec/dataflow_spec.rb +151 -0
- data/lib/vendor/dataflow/spec/equality_spec.rb +40 -0
- data/lib/vendor/dataflow/spec/flow_spec.rb +25 -0
- data/lib/vendor/dataflow/spec/forker_spec.rb +28 -0
- data/lib/vendor/dataflow/spec/future_queue_spec.rb +31 -0
- data/lib/vendor/dataflow/spec/inspect_spec.rb +19 -0
- data/lib/vendor/dataflow/spec/need_later_spec.rb +12 -0
- data/lib/vendor/dataflow/spec/port_spec.rb +26 -0
- data/lib/vendor/dataflow/spec/spec.opts +1 -0
- data/lib/vendor/dataflow/spec/spec_helper.rb +10 -0
- data/lib/vendor/escape/Readme +21 -0
- data/lib/vendor/escape/doc_include/template/qualitysmith.rb +631 -0
- data/lib/vendor/escape/lib/escape.rb +247 -0
- data/lib/vendor/json_pure/CHANGES +166 -0
- data/lib/vendor/json_pure/COPYING +58 -0
- data/lib/vendor/json_pure/GPL +340 -0
- data/lib/vendor/json_pure/README +358 -0
- data/lib/vendor/json_pure/Rakefile +292 -0
- data/lib/vendor/json_pure/TODO +1 -0
- data/lib/vendor/json_pure/VERSION +1 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
- data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
- data/lib/vendor/json_pure/benchmarks/generator2_benchmark.rb +222 -0
- data/lib/vendor/json_pure/benchmarks/generator_benchmark.rb +224 -0
- data/lib/vendor/json_pure/benchmarks/ohai.json +1216 -0
- data/lib/vendor/json_pure/benchmarks/ohai.ruby +1 -0
- data/lib/vendor/json_pure/benchmarks/parser2_benchmark.rb +251 -0
- data/lib/vendor/json_pure/benchmarks/parser_benchmark.rb +259 -0
- data/lib/vendor/json_pure/bin/edit_json.rb +9 -0
- data/lib/vendor/json_pure/bin/prettify_json.rb +75 -0
- data/lib/vendor/json_pure/data/example.json +1 -0
- data/lib/vendor/json_pure/data/index.html +38 -0
- data/lib/vendor/json_pure/data/prototype.js +4184 -0
- data/lib/vendor/json_pure/ext/json/ext/generator/extconf.rb +16 -0
- data/lib/vendor/json_pure/ext/json/ext/generator/generator.c +1323 -0
- data/lib/vendor/json_pure/ext/json/ext/generator/generator.h +170 -0
- data/lib/vendor/json_pure/ext/json/ext/parser/extconf.rb +15 -0
- data/lib/vendor/json_pure/ext/json/ext/parser/parser.c +1935 -0
- data/lib/vendor/json_pure/ext/json/ext/parser/parser.h +71 -0
- data/lib/vendor/json_pure/ext/json/ext/parser/parser.rl +792 -0
- data/lib/vendor/json_pure/install.rb +26 -0
- data/lib/vendor/json_pure/lib/json.rb +10 -0
- data/lib/vendor/json_pure/lib/json/Array.xpm +21 -0
- data/lib/vendor/json_pure/lib/json/FalseClass.xpm +21 -0
- data/lib/vendor/json_pure/lib/json/Hash.xpm +21 -0
- data/lib/vendor/json_pure/lib/json/Key.xpm +73 -0
- data/lib/vendor/json_pure/lib/json/NilClass.xpm +21 -0
- data/lib/vendor/json_pure/lib/json/Numeric.xpm +28 -0
- data/lib/vendor/json_pure/lib/json/String.xpm +96 -0
- data/lib/vendor/json_pure/lib/json/TrueClass.xpm +21 -0
- data/lib/vendor/json_pure/lib/json/add/core.rb +148 -0
- data/lib/vendor/json_pure/lib/json/add/rails.rb +58 -0
- data/lib/vendor/json_pure/lib/json/common.rb +397 -0
- data/lib/vendor/json_pure/lib/json/editor.rb +1371 -0
- data/lib/vendor/json_pure/lib/json/ext.rb +15 -0
- data/lib/vendor/json_pure/lib/json/json.xpm +1499 -0
- data/lib/vendor/json_pure/lib/json/pure.rb +77 -0
- data/lib/vendor/json_pure/lib/json/pure/generator.rb +452 -0
- data/lib/vendor/json_pure/lib/json/pure/parser.rb +307 -0
- data/lib/vendor/json_pure/lib/json/version.rb +8 -0
- data/lib/vendor/json_pure/tests/fixtures/fail1.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail10.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail11.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail12.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail13.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail14.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail18.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail19.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail2.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail20.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail21.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail22.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail23.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail24.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail25.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail27.json +2 -0
- data/lib/vendor/json_pure/tests/fixtures/fail28.json +2 -0
- data/lib/vendor/json_pure/tests/fixtures/fail3.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail4.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail5.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail6.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail7.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail8.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/fail9.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/pass1.json +56 -0
- data/lib/vendor/json_pure/tests/fixtures/pass15.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/pass16.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/pass17.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/pass2.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/pass26.json +1 -0
- data/lib/vendor/json_pure/tests/fixtures/pass3.json +6 -0
- data/lib/vendor/json_pure/tests/test_json.rb +361 -0
- data/lib/vendor/json_pure/tests/test_json_addition.rb +162 -0
- data/lib/vendor/json_pure/tests/test_json_encoding.rb +68 -0
- data/lib/vendor/json_pure/tests/test_json_fixtures.rb +34 -0
- data/lib/vendor/json_pure/tests/test_json_generate.rb +122 -0
- data/lib/vendor/json_pure/tests/test_json_rails.rb +144 -0
- data/lib/vendor/json_pure/tests/test_json_unicode.rb +76 -0
- data/lib/vendor/json_pure/tools/fuzz.rb +139 -0
- data/lib/vendor/json_pure/tools/server.rb +61 -0
- data/lib/vendor/open4/lib/open4.rb +403 -0
- data/lib/vendor/thor/CHANGELOG.rdoc +89 -0
- data/lib/vendor/thor/LICENSE +20 -0
- data/lib/vendor/thor/README.rdoc +297 -0
- data/lib/vendor/thor/Thorfile +69 -0
- data/lib/vendor/thor/bin/rake2thor +86 -0
- data/lib/vendor/thor/bin/thor +6 -0
- data/lib/vendor/thor/lib/thor.rb +244 -0
- data/lib/vendor/thor/lib/thor/actions.rb +275 -0
- data/lib/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/lib/vendor/thor/lib/thor/actions/directory.rb +91 -0
- data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
- data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
- data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
- data/lib/vendor/thor/lib/thor/base.rb +540 -0
- data/lib/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/vendor/thor/lib/thor/error.rb +30 -0
- data/lib/vendor/thor/lib/thor/group.rb +271 -0
- data/lib/vendor/thor/lib/thor/invocation.rb +180 -0
- data/lib/vendor/thor/lib/thor/parser.rb +4 -0
- data/lib/vendor/thor/lib/thor/parser/argument.rb +67 -0
- data/lib/vendor/thor/lib/thor/parser/arguments.rb +150 -0
- data/lib/vendor/thor/lib/thor/parser/option.rb +128 -0
- data/lib/vendor/thor/lib/thor/parser/options.rb +169 -0
- data/lib/vendor/thor/lib/thor/rake_compat.rb +66 -0
- data/lib/vendor/thor/lib/thor/runner.rb +314 -0
- data/lib/vendor/thor/lib/thor/shell.rb +83 -0
- data/lib/vendor/thor/lib/thor/shell/basic.rb +239 -0
- data/lib/vendor/thor/lib/thor/shell/color.rb +108 -0
- data/lib/vendor/thor/lib/thor/task.rb +102 -0
- data/lib/vendor/thor/lib/thor/util.rb +230 -0
- data/lib/vendor/thor/lib/thor/version.rb +3 -0
- data/lib/vendor/thor/thor.gemspec +120 -0
- data/spec/custom_deploy_spec.rb +95 -0
- data/spec/deploy_hook_spec.rb +211 -0
- data/spec/fixtures/gitrepo.tar.gz +0 -0
- data/spec/fixtures/gitrepo/foo +0 -0
- data/spec/fixtures/invalid_hook.rb +1 -0
- data/spec/fixtures/valid_hook.rb +1 -0
- data/spec/git_strategy_spec.rb +22 -0
- data/spec/lockfile_parser_spec.rb +30 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/lockfiles/0.9-no-bundler +111 -0
- data/spec/support/lockfiles/0.9-with-bundler +117 -0
- data/spec/support/lockfiles/1.0-no-bundler +54 -0
- data/spec/support/lockfiles/1.0.0.rc.1-with-bundler +162 -0
- data/spec/support/lockfiles/not-a-lockfile +10 -0
- metadata +279 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
== 0.3.0 / 2009-08-29
|
|
2
|
+
|
|
3
|
+
* Major enhancements
|
|
4
|
+
|
|
5
|
+
* "flow" abstraction for threading (use it to create threads and optionally
|
|
6
|
+
pass it a variable to be bound output, or override it to modify need_later
|
|
7
|
+
for other threading strategies such as thread pools)
|
|
8
|
+
|
|
9
|
+
* Dataflow::FutureQueue
|
|
10
|
+
|
|
11
|
+
* Nested binding through variables possible
|
|
12
|
+
|
|
13
|
+
* Minor enhancements
|
|
14
|
+
|
|
15
|
+
* Better #inspect and UnificationError debugging output
|
|
16
|
+
|
|
17
|
+
* "barrier" abstraction for manually preventing execution until variable
|
|
18
|
+
arguments have been bound
|
|
19
|
+
|
|
20
|
+
* Use mixin methods as class/module methods optionally
|
|
21
|
+
e.g. Dataflow.local {|v| v }
|
|
22
|
+
|
|
23
|
+
== 0.2.1 / 2009-07-29
|
|
24
|
+
|
|
25
|
+
* Minor enhancements
|
|
26
|
+
|
|
27
|
+
* Leave __send__ and __id__ alone when acting as a proxy
|
|
28
|
+
|
|
29
|
+
== 0.2.0 / 2009-07-09
|
|
30
|
+
|
|
31
|
+
* Major enhancements
|
|
32
|
+
|
|
33
|
+
* Made equality between objects and dataflow variables more transparent
|
|
34
|
+
(load equality changes with: require 'dataflow/equality')
|
|
35
|
+
|
|
36
|
+
* Minor enhancements
|
|
37
|
+
|
|
38
|
+
* Made #inspect work with unbound variables to not crash deubggers/repls/etc
|
|
39
|
+
|
|
40
|
+
* Made relationship between lazy and dataflow behavior more strict
|
|
41
|
+
|
|
42
|
+
== 0.1.1 / 2009-06-13
|
|
43
|
+
|
|
44
|
+
* Minor enhancements
|
|
45
|
+
|
|
46
|
+
* Got the "require_path" set correctly so rubygems can be used =)
|
|
47
|
+
|
|
48
|
+
== 0.1.0 / 2009-06-13
|
|
49
|
+
|
|
50
|
+
* 1 major enhancement
|
|
51
|
+
|
|
52
|
+
* Birthday!
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2009 Larry Diehl
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
h1. What's this?
|
|
2
|
+
|
|
3
|
+
A Ruby library that adds Dataflow variables (inspired by the Oz
|
|
4
|
+
language). Dataflow variables have the property that they can only
|
|
5
|
+
be bound/assigned to once, or have an equivalent value as an existing
|
|
6
|
+
assignment (see "unification").
|
|
7
|
+
|
|
8
|
+
Dataflow variables must be declared before they are used, and can be
|
|
9
|
+
passed around as data without actually being bound. If the variable
|
|
10
|
+
gets used (in this library this means a method call) while being
|
|
11
|
+
unbound then the currently executing thread will suspend.
|
|
12
|
+
|
|
13
|
+
h1. What's the point?
|
|
14
|
+
|
|
15
|
+
Ruby is Object Oriented (with the ability to mutate local, instance,
|
|
16
|
+
class, and global variables, and even constants), and on top of that
|
|
17
|
+
it has powerful reflection and meta-programming abilities. While these
|
|
18
|
+
features are useful for certain problems, they are not within the
|
|
19
|
+
declarative model. Staying in the declarative model gives one 2 advantages:
|
|
20
|
+
# It is easy to reason about what the program does
|
|
21
|
+
# Simple but powerful concurrency is possible
|
|
22
|
+
|
|
23
|
+
Ruby, like many other OO languages, is facing the hurdles of taking
|
|
24
|
+
advantage of the increase of processor cores within a simple parallel
|
|
25
|
+
programming model. This library lets you program Ruby in the
|
|
26
|
+
declarative concurrent model when you need to take advantage of multiple cores
|
|
27
|
+
(assuming a Ruby implementation that uses native threads in one way or
|
|
28
|
+
another).
|
|
29
|
+
|
|
30
|
+
The trick to this kind of programming is binding variables from other
|
|
31
|
+
threads. The nice thing is that many existing
|
|
32
|
+
libraries/classes/methods can still be used, just avoid
|
|
33
|
+
side-effects. Use regular Ruby threading to create threads, use
|
|
34
|
+
"local" or "declare" to create new variables, and use "unify" to bind
|
|
35
|
+
variables.
|
|
36
|
+
|
|
37
|
+
h1. Install
|
|
38
|
+
|
|
39
|
+
To install the latest release as a gem:
|
|
40
|
+
<pre>sudo gem install dataflow</pre>
|
|
41
|
+
|
|
42
|
+
h1. IRC
|
|
43
|
+
|
|
44
|
+
<pre>#dataflow-gem @ freenode.net</pre>
|
|
45
|
+
|
|
46
|
+
h1. Examples
|
|
47
|
+
|
|
48
|
+
<pre>
|
|
49
|
+
# Local variables
|
|
50
|
+
include Dataflow
|
|
51
|
+
|
|
52
|
+
local do |x, y, z|
|
|
53
|
+
# notice how the order automatically gets resolved
|
|
54
|
+
Thread.new { unify y, x + 2 }
|
|
55
|
+
Thread.new { unify z, y + 3 }
|
|
56
|
+
Thread.new { unify x, 1 }
|
|
57
|
+
z #=> 6
|
|
58
|
+
end
|
|
59
|
+
</pre>
|
|
60
|
+
|
|
61
|
+
<pre>
|
|
62
|
+
# Module methods version
|
|
63
|
+
|
|
64
|
+
Dataflow.local do |x, y, z|
|
|
65
|
+
# notice how the order automatically gets resolved
|
|
66
|
+
Thread.new { Dataflow.unify y, x + 2 }
|
|
67
|
+
Thread.new { Dataflow.unify z, y + 3 }
|
|
68
|
+
Thread.new { Dataflow.unify x, 1 }
|
|
69
|
+
z #=> 6
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Note that a gobal Dataflow.declare is not supported
|
|
73
|
+
</pre>
|
|
74
|
+
|
|
75
|
+
<pre>
|
|
76
|
+
# Instance variables
|
|
77
|
+
class AnimalHouse
|
|
78
|
+
include Dataflow
|
|
79
|
+
declare :small_cat, :big_cat
|
|
80
|
+
|
|
81
|
+
def fetch_big_cat
|
|
82
|
+
Thread.new { unify big_cat, small_cat.upcase }
|
|
83
|
+
unify small_cat, 'cat'
|
|
84
|
+
big_cat
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
AnimalHouse.new.fetch_big_cat #=> 'CAT'
|
|
89
|
+
</pre>
|
|
90
|
+
|
|
91
|
+
<pre>
|
|
92
|
+
# Data-driven concurrency
|
|
93
|
+
include Dataflow
|
|
94
|
+
|
|
95
|
+
local do |stream, doubles, triples, squares|
|
|
96
|
+
unify stream, Array.new(5) { Dataflow::Variable.new }
|
|
97
|
+
|
|
98
|
+
Thread.new { unify doubles, stream.map {|n| n*2 } }
|
|
99
|
+
Thread.new { unify triples, stream.map {|n| n*3 } }
|
|
100
|
+
Thread.new { unify squares, stream.map {|n| n**2 } }
|
|
101
|
+
|
|
102
|
+
Thread.new { stream.each {|x| unify x, rand(100) } }
|
|
103
|
+
|
|
104
|
+
puts "original: #{stream.inspect}"
|
|
105
|
+
puts "doubles: #{doubles.inspect}"
|
|
106
|
+
puts "triples: #{triples.inspect}"
|
|
107
|
+
puts "squares: #{squares.inspect}"
|
|
108
|
+
end
|
|
109
|
+
</pre>
|
|
110
|
+
|
|
111
|
+
<pre>
|
|
112
|
+
# By-need trigger laziness
|
|
113
|
+
include Dataflow
|
|
114
|
+
|
|
115
|
+
local do |x, y, z|
|
|
116
|
+
Thread.new { unify y, by_need { 4 } }
|
|
117
|
+
Thread.new { unify z, x + y }
|
|
118
|
+
Thread.new { unify x, by_need { 3 } }
|
|
119
|
+
z #=> 7
|
|
120
|
+
end
|
|
121
|
+
</pre>
|
|
122
|
+
|
|
123
|
+
<pre>
|
|
124
|
+
# Need-later future expressions
|
|
125
|
+
include Dataflow
|
|
126
|
+
|
|
127
|
+
local do |x, y, z|
|
|
128
|
+
unify y, need_later { 4 }
|
|
129
|
+
unify z, need_later { x + y }
|
|
130
|
+
unify x, need_later { 3 }
|
|
131
|
+
z #=> 7
|
|
132
|
+
end
|
|
133
|
+
</pre>
|
|
134
|
+
|
|
135
|
+
<pre>
|
|
136
|
+
include Dataflow
|
|
137
|
+
|
|
138
|
+
# flow without parameters
|
|
139
|
+
local do |x|
|
|
140
|
+
flow do
|
|
141
|
+
# other stuff
|
|
142
|
+
unify x, 1337
|
|
143
|
+
end
|
|
144
|
+
x #=> 1337
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# flow with an output parameter
|
|
148
|
+
local do |x|
|
|
149
|
+
flow(x) do
|
|
150
|
+
# other stuff
|
|
151
|
+
1337
|
|
152
|
+
end
|
|
153
|
+
x #=> 1337
|
|
154
|
+
end
|
|
155
|
+
</pre>
|
|
156
|
+
|
|
157
|
+
<pre>
|
|
158
|
+
# barrier
|
|
159
|
+
include Dataflow
|
|
160
|
+
|
|
161
|
+
local do |lock1, lock2|
|
|
162
|
+
flow { unify lock1, :unlocked }
|
|
163
|
+
flow { unify lock2, :unlocked }
|
|
164
|
+
barrier lock1, lock2
|
|
165
|
+
puts "Barrier broken!"
|
|
166
|
+
end
|
|
167
|
+
</pre>
|
|
168
|
+
|
|
169
|
+
<pre>
|
|
170
|
+
# FutureQueue
|
|
171
|
+
include Dataflow
|
|
172
|
+
|
|
173
|
+
local do |queue, first, second|
|
|
174
|
+
unify queue, Dataflow::FutureQueue.new
|
|
175
|
+
queue.pop first
|
|
176
|
+
queue.push 1
|
|
177
|
+
queue.push 2
|
|
178
|
+
queue.pop second
|
|
179
|
+
first #=> 1
|
|
180
|
+
second #=> 2
|
|
181
|
+
end
|
|
182
|
+
</pre>
|
|
183
|
+
|
|
184
|
+
h1. Anonymous variables
|
|
185
|
+
|
|
186
|
+
Sometimes you may want to pack a data structure with variables that do not need to be referenced with labels. For those cases anonymous variables are a good choice, here are some options:
|
|
187
|
+
|
|
188
|
+
<pre>
|
|
189
|
+
include Dataflow
|
|
190
|
+
Array.new(3) { Dataflow::Variable.new }
|
|
191
|
+
Array.new(3) { Dataflow.local }
|
|
192
|
+
Array.new(3) { local }
|
|
193
|
+
# and technically not anonymous
|
|
194
|
+
Array.new(3) { local {|v| v } }
|
|
195
|
+
</pre>
|
|
196
|
+
|
|
197
|
+
h1. Debugging
|
|
198
|
+
|
|
199
|
+
If you are having trouble and need to debug dataflow variables, simply call #inspect.
|
|
200
|
+
|
|
201
|
+
If the variable has already been bound, it call inspect on its bound value like normal.However, if the variable is not bound yet then you will get a special string that contains the proxies #__id__ that you can use to track down which proxy objects are being passed around to which parts of your program:
|
|
202
|
+
<pre>
|
|
203
|
+
include Dataflow
|
|
204
|
+
local do |my_var|
|
|
205
|
+
my_var.inspect # => #<Dataflow::Variable:2637860 unbound>
|
|
206
|
+
end
|
|
207
|
+
</pre>
|
|
208
|
+
|
|
209
|
+
h1. Fork method customization
|
|
210
|
+
|
|
211
|
+
By default both #flow and #need_later use Thread.fork as their fork method. Youc an access the fork method via Dataflow.forker.
|
|
212
|
+
|
|
213
|
+
If you would like to use a custom forker, simple set it to an object that responds to #call and internally calls a block passed to it (for an example of a synchronous forker, see spec/forker_spec.rb):
|
|
214
|
+
<pre>
|
|
215
|
+
Dataflow.forker = MyClass.method(:fork_with_threadpool)
|
|
216
|
+
</pre>
|
|
217
|
+
|
|
218
|
+
Also note that #flow is used interally by #need_later, in case you want to override that specifically.
|
|
219
|
+
|
|
220
|
+
h1. Ports using Dataflow
|
|
221
|
+
|
|
222
|
+
Ports are an extension of the declarative concurrent model to support nondeterministic behavior. They accomplish this through the use of a single state variable. Ports are also inspired by the Oz language.
|
|
223
|
+
|
|
224
|
+
An Actor class in the style of Erlang message-passing processes is also provided. It makes use of the asynchronous behavior of ports, but otherwise uses no state variables.
|
|
225
|
+
|
|
226
|
+
h1. Examples using Ports
|
|
227
|
+
|
|
228
|
+
<pre>
|
|
229
|
+
include Dataflow
|
|
230
|
+
|
|
231
|
+
local do |port, stream|
|
|
232
|
+
unify port, Dataflow::Port.new(stream)
|
|
233
|
+
Thread.new {port.send 2}
|
|
234
|
+
Thread.new {port.send 8}
|
|
235
|
+
Thread.new {port.send 1024}
|
|
236
|
+
stream.take(3).sort #=> [2, 8, 1024]
|
|
237
|
+
end
|
|
238
|
+
</pre>
|
|
239
|
+
|
|
240
|
+
h1. Examples using Actors
|
|
241
|
+
|
|
242
|
+
<pre>
|
|
243
|
+
include Dataflow
|
|
244
|
+
|
|
245
|
+
Ping = Actor.new {
|
|
246
|
+
3.times {
|
|
247
|
+
case receive
|
|
248
|
+
when "Ping"
|
|
249
|
+
puts "Ping"
|
|
250
|
+
Pong.send "Pong"
|
|
251
|
+
end
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
Pong = Actor.new {
|
|
256
|
+
3.times {
|
|
257
|
+
case receive
|
|
258
|
+
when "Pong"
|
|
259
|
+
puts "Pong"
|
|
260
|
+
Ping.send "Ping"
|
|
261
|
+
end
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
Actor.new { Ping.send "Ping" }
|
|
266
|
+
|
|
267
|
+
Ping.join
|
|
268
|
+
Pong.join
|
|
269
|
+
</pre>
|
|
270
|
+
|
|
271
|
+
h1. Equality
|
|
272
|
+
|
|
273
|
+
Most Ruby implmentations will not use method calls for equality
|
|
274
|
+
operations in base types/classes. This means equality between dataflow
|
|
275
|
+
variables and those base types will not behave as expected. Require
|
|
276
|
+
the following to get equality on base types that uses method calls,
|
|
277
|
+
while still passing rubyspec:
|
|
278
|
+
|
|
279
|
+
<pre>require "dataflow/equality"</pre>
|
|
280
|
+
|
|
281
|
+
h1. References
|
|
282
|
+
|
|
283
|
+
The basis of dataflow variables around a language is not common among
|
|
284
|
+
popular languages and may be confusing to some. For an in-depth
|
|
285
|
+
introduction to the Oz language and the techniques used in this
|
|
286
|
+
library (including by_need triggers, port objects, and comparisons to Erlang message passing) see the book "Concepts, Techniques, and Models of Computer Programming":http://en.wikipedia.org/wiki/Concepts,_Techniques,_and_Models_of_Computer_Programming
|
|
287
|
+
|
|
288
|
+
h1. Contributors
|
|
289
|
+
|
|
290
|
+
larrytheliquid, amiller
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "rake/gempackagetask"
|
|
3
|
+
require "rake/clean"
|
|
4
|
+
require "spec/rake/spectask"
|
|
5
|
+
require File.expand_path("./dataflow")
|
|
6
|
+
|
|
7
|
+
Spec::Rake::SpecTask.new do |t|
|
|
8
|
+
t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
desc "Run the specs"
|
|
12
|
+
task :default => :spec
|
|
13
|
+
|
|
14
|
+
spec = Gem::Specification.new do |s|
|
|
15
|
+
s.name = "dataflow"
|
|
16
|
+
s.rubyforge_project = s.name
|
|
17
|
+
s.version = Dataflow::VERSION
|
|
18
|
+
s.author = "Larry Diehl"
|
|
19
|
+
s.email = "larrytheliquid" + "@" + "gmail.com"
|
|
20
|
+
s.homepage = "http://github.com/larrytheliquid/dataflow"
|
|
21
|
+
s.summary = "Dataflow concurrency for Ruby (inspired by the Oz language)"
|
|
22
|
+
s.description = s.summary
|
|
23
|
+
s.files = %w[LICENSE HISTORY Rakefile README.textile dataflow.rb] + Dir["dataflow/**/*"] + Dir["examples/**/*"]
|
|
24
|
+
s.require_path = '.'
|
|
25
|
+
s.test_files = Dir["spec/**/*"]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Rake::GemPackageTask.new(spec) do |package|
|
|
29
|
+
package.gem_spec = spec
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc 'Install the package as a gem.'
|
|
33
|
+
task :install => [:clean, :package] do
|
|
34
|
+
gem = Dir['pkg/*.gem'].first
|
|
35
|
+
sh "sudo gem install --no-rdoc --no-ri --local #{gem}"
|
|
36
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require 'monitor'
|
|
2
|
+
|
|
3
|
+
module Dataflow
|
|
4
|
+
VERSION = "0.3.1"
|
|
5
|
+
class << self
|
|
6
|
+
attr_accessor :forker
|
|
7
|
+
end
|
|
8
|
+
self.forker = Thread.method(:fork)
|
|
9
|
+
|
|
10
|
+
def self.included(cls)
|
|
11
|
+
class << cls
|
|
12
|
+
def declare(*readers)
|
|
13
|
+
readers.each do |name|
|
|
14
|
+
class_eval <<-RUBY
|
|
15
|
+
def #{name}
|
|
16
|
+
return @__dataflow_#{name}__ if defined? @__dataflow_#{name}__
|
|
17
|
+
Variable::LOCK.synchronize { @__dataflow_#{name}__ ||= Variable.new }
|
|
18
|
+
end
|
|
19
|
+
RUBY
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def local(&block)
|
|
26
|
+
return Variable.new unless block_given?
|
|
27
|
+
vars = Array.new(block.arity) { Variable.new }
|
|
28
|
+
block.call *vars
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def unify(variable, value)
|
|
32
|
+
variable.__unify__ value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def by_need(&block)
|
|
36
|
+
Variable.new &block
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def barrier(*variables)
|
|
40
|
+
variables.each{|v| v.__wait__ }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def flow(output=nil, &block)
|
|
44
|
+
Dataflow.forker.call do
|
|
45
|
+
result = block.call
|
|
46
|
+
unify output, result if output
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def need_later(&block)
|
|
51
|
+
local do |future|
|
|
52
|
+
flow(future) { block.call }
|
|
53
|
+
future
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
extend self
|
|
58
|
+
|
|
59
|
+
# Note that this class uses instance variables directly rather than nicely
|
|
60
|
+
# initialized instance variables in get/set methods for memory and
|
|
61
|
+
# performance reasons
|
|
62
|
+
class Variable
|
|
63
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
|
64
|
+
LOCK = Monitor.new
|
|
65
|
+
def initialize(&block) @__trigger__ = block if block_given? end
|
|
66
|
+
|
|
67
|
+
# Lazy-load conditions to be nice on memory usage
|
|
68
|
+
def __binding_condition__() @__binding_condition__ ||= LOCK.new_cond end
|
|
69
|
+
|
|
70
|
+
def __unify__(value)
|
|
71
|
+
LOCK.synchronize do
|
|
72
|
+
__activate_trigger__ if @__trigger__
|
|
73
|
+
if @__bound__
|
|
74
|
+
return @__value__.__unify__(value) if @__value__.__dataflow__? rescue nil
|
|
75
|
+
raise UnificationError, "#{@__value__.inspect} != #{value.inspect}" if self != value
|
|
76
|
+
else
|
|
77
|
+
@__value__ = value
|
|
78
|
+
@__bound__ = true
|
|
79
|
+
__binding_condition__.broadcast # wakeup all method callers
|
|
80
|
+
@__binding_condition__ = nil # GC
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
@__value__
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def __activate_trigger__
|
|
87
|
+
@__value__ = @__trigger__.call
|
|
88
|
+
@__bound__ = true
|
|
89
|
+
@__trigger__ = nil # GC
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def __wait__
|
|
93
|
+
LOCK.synchronize do
|
|
94
|
+
unless @__bound__
|
|
95
|
+
if @__trigger__
|
|
96
|
+
__activate_trigger__
|
|
97
|
+
else
|
|
98
|
+
__binding_condition__.wait
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end unless @__bound__
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def method_missing(name, *args, &block)
|
|
105
|
+
return "#<Dataflow::Variable:#{__id__} unbound>" if !@__bound__ && name == :inspect
|
|
106
|
+
__wait__
|
|
107
|
+
@__value__.__send__(name, *args, &block)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def __dataflow__?
|
|
111
|
+
true
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
UnificationError = Class.new StandardError
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
require "#{File.dirname(__FILE__)}/dataflow/port"
|
|
119
|
+
require "#{File.dirname(__FILE__)}/dataflow/actor"
|
|
120
|
+
require "#{File.dirname(__FILE__)}/dataflow/future_queue"
|