erlectricity 0.2.1 → 1.0.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/History.txt +14 -1
- data/LICENSE +20 -0
- data/README.md +130 -0
- data/Rakefile +63 -60
- data/VERSION.yml +4 -0
- data/examples/echo/README.md +12 -0
- data/examples/echo/echo.erl +13 -0
- data/examples/echo/echo.rb +11 -0
- data/examples/gruff/gruff.erl +17 -18
- data/examples/gruff/gruff_provider.rb +12 -19
- data/examples/gruff/{gruff_run.erl → gruff_run.sh} +5 -3
- data/examples/gruff/{stat_run.erl → stat_run.sh} +5 -3
- data/examples/gruff/stat_writer.erl +6 -6
- data/examples/simple/README.md +5 -0
- data/examples/simple/rerl.rb +111 -0
- data/examples/simple/rerl.sh +37 -0
- data/examples/tinderl/README.md +14 -0
- data/examples/tinderl/tinderl.erl +19 -21
- data/examples/tinderl/tinderl.rb +11 -10
- data/ext/decoder.c +67 -60
- data/lib/erlectricity.rb +4 -7
- data/lib/erlectricity/condition.rb +35 -20
- data/lib/erlectricity/conditions/boolean.rb +11 -0
- data/lib/erlectricity/conditions/hash.rb +9 -10
- data/lib/erlectricity/conditions/static.rb +31 -10
- data/lib/erlectricity/conditions/type.rb +14 -14
- data/lib/erlectricity/constants.rb +3 -4
- data/lib/erlectricity/decoder.rb +205 -199
- data/lib/erlectricity/encoder.rb +49 -35
- data/lib/erlectricity/errors/decode_error.rb +1 -1
- data/lib/erlectricity/errors/encode_error.rb +1 -1
- data/lib/erlectricity/errors/erlectricity_error.rb +1 -1
- data/lib/erlectricity/matcher.rb +15 -32
- data/lib/erlectricity/port.rb +11 -11
- data/lib/erlectricity/receiver.rb +54 -64
- data/lib/erlectricity/types/list.rb +3 -1
- data/test/condition_spec.rb +8 -9
- data/test/decode_spec.rb +27 -28
- data/test/encode_spec.rb +31 -24
- data/test/matcher_spec.rb +24 -12
- data/test/port_spec.rb +3 -4
- data/test/receiver_spec.rb +18 -20
- data/test/test_helper.rb +9 -5
- metadata +36 -29
- data/CONTRIBUTORS +0 -2
- data/Manifest.txt +0 -45
- data/README.txt +0 -43
- data/setup.rb +0 -1585
- data/test/test_erlectricity.rb +0 -2
data/History.txt
CHANGED
@@ -1 +1,14 @@
|
|
1
|
-
|
1
|
+
==
|
2
|
+
* Backward Incompatible Changes
|
3
|
+
* Implicit array call for f.when(:echo, String) must now be called as
|
4
|
+
f.when([:echo, String]) to eliminate ambiguity
|
5
|
+
* Implicit array call for f.send!(:ok, "foo") must now be called as
|
6
|
+
f.send!([:ok, "foo"]) to eliminate ambiguity
|
7
|
+
* The receive loop now defaults to using file descriptors 3 and 3
|
8
|
+
instead of STDIN and STDOUT. This prevents inadvertent output
|
9
|
+
statements from silently corrupting the transfer protocol.
|
10
|
+
* Erlang atoms 'true' and 'false' are now converted into Ruby booleans
|
11
|
+
* Erlectricity::Decoder.read_any_from -> Erlectricity::Decoder.decode
|
12
|
+
* Major Enhancements
|
13
|
+
* Calling `rake` now runs tests (with and without compiled C extensions)
|
14
|
+
* Package management is now done by Jeweler
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Scott Fleckenstein and Tom Preston-Werner
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
Erlectricity
|
2
|
+
============
|
3
|
+
|
4
|
+
http://github.com/mojombo/erlectricity
|
5
|
+
|
6
|
+
By Scott Fleckenstein, Tom Preston-Werner
|
7
|
+
|
8
|
+
Development Status: Production/Stable
|
9
|
+
|
10
|
+
|
11
|
+
Description
|
12
|
+
-----------
|
13
|
+
|
14
|
+
Erlectricity allows a Ruby program to receive and respond to Erlang messages
|
15
|
+
sent over the Erlang binary protocol.
|
16
|
+
|
17
|
+
|
18
|
+
Install
|
19
|
+
-------
|
20
|
+
|
21
|
+
$ gem install erlectricity
|
22
|
+
|
23
|
+
-or-
|
24
|
+
|
25
|
+
$ gem install mojombo-erlectricity -s http://gems.github.com
|
26
|
+
|
27
|
+
|
28
|
+
The Simplest Example
|
29
|
+
--------------------
|
30
|
+
|
31
|
+
### Ruby side (echo.rb)
|
32
|
+
|
33
|
+
require 'rubygems'
|
34
|
+
require 'erlectricity'
|
35
|
+
|
36
|
+
receive do |f|
|
37
|
+
f.when([:echo, String]) do |text|
|
38
|
+
f.send!([:result, "You said: #{text}"])
|
39
|
+
f.receive_loop
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
### Erlang side (echo.erl)
|
44
|
+
|
45
|
+
-module(echo).
|
46
|
+
-export([test/0]).
|
47
|
+
|
48
|
+
test() ->
|
49
|
+
Cmd = "ruby echo.rb",
|
50
|
+
Port = open_port({spawn, Cmd}, [{packet, 4}, nouse_stdio, exit_status, binary]),
|
51
|
+
Payload = term_to_binary({echo, <<"hello world!">>}),
|
52
|
+
port_command(Port, Payload),
|
53
|
+
receive
|
54
|
+
{Port, {data, Data}} ->
|
55
|
+
{result, Text} = binary_to_term(Data),
|
56
|
+
io:format("~p~n", [Text])
|
57
|
+
end.
|
58
|
+
|
59
|
+
|
60
|
+
Data Type Conversions and Matching
|
61
|
+
----------------------------------
|
62
|
+
|
63
|
+
% Port is the port opened via open_port({spawn, Cmd}, [{packet, 4}, ...])
|
64
|
+
% Message is the Erlang term to encode and send to the port
|
65
|
+
send(Port, Message) ->
|
66
|
+
port_command(Port, term_to_binary(Message)).
|
67
|
+
|
68
|
+
# Each triplet below represents:
|
69
|
+
# (line 1) the Erlang call
|
70
|
+
# (line 2) the Ruby matcher
|
71
|
+
# (line 3) the Ruby output
|
72
|
+
|
73
|
+
send(Port, test).
|
74
|
+
f.when(:test) { p :ok }
|
75
|
+
# :ok
|
76
|
+
|
77
|
+
send(Port, {atom, symbol}).
|
78
|
+
f.when([:atom, Symbol]) { |sym| p sym }
|
79
|
+
# :symbol
|
80
|
+
|
81
|
+
send(Port, {number, 1}).
|
82
|
+
f.when([:number, Fixnum]) { |num| p num }
|
83
|
+
# 1
|
84
|
+
|
85
|
+
send(Port, {string, <<"foo">>}).
|
86
|
+
f.when([:string, String]) { |str| p str }
|
87
|
+
# "foo"
|
88
|
+
|
89
|
+
send(Port, {array, [1,2,3]}).
|
90
|
+
f.when([:array, Array]) { |arr| p arr }
|
91
|
+
# [1, 2, 3]
|
92
|
+
|
93
|
+
send(Port, {array, [<<"abc">>, <<"def">>]}).
|
94
|
+
f.when([:array, Array]) { |arr| p arr }
|
95
|
+
# ["abc", "def"]
|
96
|
+
|
97
|
+
send(Port, {hash, [{key,val}]}).
|
98
|
+
f.when([:hash, Erl.hash]) { |hash| p hash }
|
99
|
+
# {:key=>:val}
|
100
|
+
|
101
|
+
send(Port, {object, {1,{2},3,<<"four">>}}).
|
102
|
+
f.when([:object, Any]) { |any| p any }
|
103
|
+
# [1, [2], 3, "four"]
|
104
|
+
|
105
|
+
|
106
|
+
Contribute
|
107
|
+
----------
|
108
|
+
|
109
|
+
If you'd like to hack on Erlectricity, start by forking my repo on GitHub:
|
110
|
+
|
111
|
+
http://github.com/mojombo/erlectricity
|
112
|
+
|
113
|
+
To get all of the dependencies, install the gem first. The best way to get
|
114
|
+
your changes merged back into core is as follows:
|
115
|
+
|
116
|
+
1. Clone down your fork
|
117
|
+
1. Create a topic branch to contain your change
|
118
|
+
1. Hack away
|
119
|
+
1. Add tests and make sure everything still passes by running `rake`
|
120
|
+
1. If you are adding new functionality, document it in the README.md
|
121
|
+
1. Do not change the version number, I will do that on my end
|
122
|
+
1. If necessary, rebase your commits into logical chunks, without errors
|
123
|
+
1. Push the branch up to GitHub
|
124
|
+
1. Send me (mojombo) a pull request for your branch
|
125
|
+
|
126
|
+
|
127
|
+
Copyright
|
128
|
+
---------
|
129
|
+
|
130
|
+
Copyright (c) 2009 Scott Fleckenstein and Tom Preston-Werner. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,71 +1,74 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
-
require 'rake/clean'
|
4
|
-
require 'rake/testtask'
|
5
|
-
require 'rake/packagetask'
|
6
|
-
require 'rake/gempackagetask'
|
7
|
-
require 'rake/rdoctask'
|
8
|
-
require 'rake/contrib/rubyforgepublisher'
|
9
|
-
require 'fileutils'
|
10
|
-
require 'hoe'
|
11
|
-
include FileUtils
|
12
|
-
require File.join(File.dirname(__FILE__), 'lib', 'erlectricity', 'version')
|
13
|
-
|
14
|
-
AUTHOR = 'Scott Fleckenstein' # can also be an array of Authors
|
15
|
-
EMAIL = "nullstyle@gmail.com"
|
16
|
-
DESCRIPTION = "A library to interface erlang and ruby through the erlang port system"
|
17
|
-
GEM_NAME = 'erlectricity' # what ppl will type to install your gem
|
18
|
-
RUBYFORGE_PROJECT = 'erlectricity' # The unix name for your project
|
19
|
-
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
20
|
-
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
21
3
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
"
|
28
|
-
"
|
29
|
-
|
30
|
-
"
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "erlectricity"
|
8
|
+
gem.rubyforge_project = "erlectricity"
|
9
|
+
gem.summary = "A library to interface erlang and ruby through the erlang port system"
|
10
|
+
gem.email = "tom@mojombo.com"
|
11
|
+
gem.homepage = "http://github.com/mojombo/erlectricity"
|
12
|
+
gem.authors = ["Scott Fleckenstein", "Tom Preston-Werner"]
|
13
|
+
gem.require_paths = ["lib", "ext"]
|
14
|
+
gem.files.include("ext")
|
15
|
+
gem.extensions << 'ext/extconf.rb'
|
31
16
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
17
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
36
21
|
end
|
37
22
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
p.author = AUTHOR
|
42
|
-
p.description = DESCRIPTION
|
43
|
-
p.email = EMAIL
|
44
|
-
p.summary = DESCRIPTION
|
45
|
-
p.url = HOMEPATH
|
46
|
-
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
47
|
-
p.test_globs = ["test/**/test_*.rb"]
|
48
|
-
p.clean_globs = CLEAN #An array of file patterns to delete on clean.
|
49
|
-
|
50
|
-
# == Optional
|
51
|
-
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
52
|
-
p.extra_deps = [
|
53
|
-
['concurrent', '0.2.2'],
|
54
|
-
] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
55
|
-
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
56
|
-
p.spec_extras = {:extensions => ['ext/extconf.rb']}
|
57
|
-
end
|
23
|
+
task :test do
|
24
|
+
require 'open3'
|
25
|
+
require 'fileutils'
|
58
26
|
|
59
|
-
|
60
|
-
|
27
|
+
puts "\nCleaning extension build files and running all specs in native ruby mode..."
|
28
|
+
`rm -f ext/*.bundle` && puts("rm -f ext/*.bundle")
|
29
|
+
`rm -f ext/*.o` && puts("rm -f ext/*.o")
|
30
|
+
Open3.popen3("ruby test/spec_suite.rb") do |stdin, stdout, stderr|
|
31
|
+
while !stdout.eof?
|
32
|
+
print stdout.read(1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "\nRunning `make` to build extensions and rerunning decoder specs..."
|
37
|
+
Dir.chdir('ext') { `make` }
|
38
|
+
Open3.popen3("ruby test/decode_spec.rb") do |stdin, stdout, stderr|
|
39
|
+
while !stdout.eof?
|
40
|
+
print stdout.read(1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
61
44
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
45
|
+
begin
|
46
|
+
require 'rcov/rcovtask'
|
47
|
+
Rcov::RcovTask.new do |test|
|
48
|
+
test.libs << 'test'
|
49
|
+
test.pattern = 'test/**/*_test.rb'
|
50
|
+
test.verbose = true
|
66
51
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
52
|
+
rescue LoadError
|
53
|
+
task :rcov do
|
54
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
70
55
|
end
|
71
56
|
end
|
57
|
+
|
58
|
+
|
59
|
+
task :default => :test
|
60
|
+
|
61
|
+
require 'rake/rdoctask'
|
62
|
+
Rake::RDocTask.new do |rdoc|
|
63
|
+
if File.exist?('VERSION.yml')
|
64
|
+
config = YAML.load(File.read('VERSION.yml'))
|
65
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
66
|
+
else
|
67
|
+
version = ""
|
68
|
+
end
|
69
|
+
|
70
|
+
rdoc.rdoc_dir = 'rdoc'
|
71
|
+
rdoc.title = "erlectricity #{version}"
|
72
|
+
rdoc.rdoc_files.include('README*')
|
73
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
74
|
+
end
|
data/VERSION.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
This is a simple echo server example showing off basic Erlectricity usage.
|
2
|
+
|
3
|
+
$ cd examples/echo
|
4
|
+
$ erl
|
5
|
+
Erlang (BEAM) emulator version 5.6.4 [source] [smp:2] [async-threads:0] [kernel-poll:false]
|
6
|
+
|
7
|
+
Eshell V5.6.4 (abort with ^G)
|
8
|
+
1> c(echo).
|
9
|
+
{ok,echo}
|
10
|
+
2> echo:test().
|
11
|
+
<<"You said: hello world!">>
|
12
|
+
ok
|
@@ -0,0 +1,13 @@
|
|
1
|
+
-module(echo).
|
2
|
+
-export([test/0]).
|
3
|
+
|
4
|
+
test() ->
|
5
|
+
Cmd = "ruby echo.rb",
|
6
|
+
Port = open_port({spawn, Cmd}, [{packet, 4}, nouse_stdio, exit_status, binary]),
|
7
|
+
Payload = term_to_binary({echo, <<"hello world!">>}),
|
8
|
+
port_command(Port, Payload),
|
9
|
+
receive
|
10
|
+
{Port, {data, Data}} ->
|
11
|
+
{result, Text} = binary_to_term(Data),
|
12
|
+
io:format("~p~n", [Text])
|
13
|
+
end.
|
data/examples/gruff/gruff.erl
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
-module(gruff).
|
2
2
|
-export([start/0, stop/0, plot/4]).
|
3
3
|
|
4
|
-
start() ->
|
5
|
-
spawn(fun() ->
|
6
|
-
register(gruff, self()),
|
7
|
-
process_flag(trap_exit, true),
|
4
|
+
start() ->
|
5
|
+
spawn(fun() ->
|
6
|
+
register(gruff, self()),
|
7
|
+
process_flag(trap_exit, true),
|
8
8
|
Cmd = "ruby ./gruff_provider.rb",
|
9
|
-
Port = open_port({spawn, Cmd}, [{packet, 4},
|
10
|
-
port_loop(Port)
|
11
|
-
end).
|
9
|
+
Port = open_port({spawn, Cmd}, [{packet, 4}, nouse_stdio, exit_status, binary]),
|
10
|
+
port_loop(Port)
|
11
|
+
end).
|
12
12
|
|
13
|
-
stop() -> gruff ! stop.
|
13
|
+
stop() -> gruff ! stop.
|
14
14
|
|
15
|
-
plot(Name, Font, Data, Labels) ->
|
15
|
+
plot(Name, Font, Data, Labels) ->
|
16
16
|
gruff ! {plot, self(), Name, Font, Data, Labels},
|
17
17
|
receive
|
18
18
|
{result, Bin} -> Bin
|
@@ -28,7 +28,6 @@ send_labels(Port, Labels) ->
|
|
28
28
|
Data = {labels, Labels},
|
29
29
|
Port ! {self(), {command, term_to_binary(Data)}}.
|
30
30
|
|
31
|
-
|
32
31
|
port_loop(Port) ->
|
33
32
|
receive
|
34
33
|
{plot, Caller, Name, Font, Data, Labels} ->
|
@@ -37,18 +36,18 @@ port_loop(Port) ->
|
|
37
36
|
|
38
37
|
send_data(Port, Data),
|
39
38
|
send_labels(Port, Labels),
|
40
|
-
|
39
|
+
|
41
40
|
EndData = term_to_binary('end'),
|
42
41
|
Port ! {self(), {command, EndData}},
|
43
42
|
Result = get_result(Port),
|
44
43
|
Caller ! {result, Result },
|
45
|
-
|
44
|
+
|
46
45
|
port_loop(Port);
|
47
|
-
|
48
|
-
stop ->
|
49
|
-
Port ! {self(), close},
|
50
|
-
receive
|
51
|
-
{Port, closed} -> exit(normal)
|
46
|
+
|
47
|
+
stop ->
|
48
|
+
Port ! {self(), close},
|
49
|
+
receive
|
50
|
+
{Port, closed} -> exit(normal)
|
52
51
|
end
|
53
52
|
end.
|
54
53
|
|
@@ -57,6 +56,6 @@ get_result(Port) ->
|
|
57
56
|
{Port, {data, Data}} ->
|
58
57
|
{result, Bin} = binary_to_term(Data),
|
59
58
|
Bin;
|
60
|
-
{'EXIT', Port, Reason} ->
|
59
|
+
{'EXIT', Port, Reason} ->
|
61
60
|
exit({port_terminated,Reason})
|
62
61
|
end.
|
@@ -1,38 +1,31 @@
|
|
1
|
-
$:.unshift(File.dirname(__FILE__)
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[../../lib])
|
2
|
+
|
2
3
|
require 'erlectricity'
|
3
4
|
require 'rubygems'
|
4
5
|
require 'gruff'
|
5
6
|
|
6
7
|
receive do |f|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
f.when(:plot, String, Symbol, String) do |name, style, font|
|
8
|
+
f.when([:plot, String, Symbol, String]) do |name, style, font|
|
11
9
|
graph = Gruff.const_get(style).new
|
12
10
|
graph.title = name
|
13
11
|
graph.font = font
|
14
12
|
graph.legend_font_size = 10
|
15
|
-
|
16
|
-
|
13
|
+
|
17
14
|
f.receive do |g|
|
18
|
-
g.when(:data, Symbol, Array) do |name, points|
|
15
|
+
g.when([:data, Symbol, Array]) do |name, points|
|
19
16
|
graph.data name, points
|
20
17
|
g.receive_loop
|
21
18
|
end
|
22
|
-
|
23
|
-
g.when(:labels, Erl.hash) do |label_data|
|
19
|
+
|
20
|
+
g.when([:labels, Erl.hash]) do |label_data|
|
24
21
|
graph.labels = label_data
|
25
22
|
g.receive_loop
|
26
23
|
end
|
27
|
-
|
28
|
-
g.when(:end){ :ok }
|
24
|
+
|
25
|
+
g.when(:end) { :ok }
|
29
26
|
end
|
30
|
-
|
31
|
-
|
32
|
-
f.send! :result, graph.to_blob
|
27
|
+
|
28
|
+
f.send!([:result, graph.to_blob])
|
33
29
|
f.receive_loop
|
34
30
|
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
|
31
|
+
end
|