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.
Files changed (49) hide show
  1. data/History.txt +14 -1
  2. data/LICENSE +20 -0
  3. data/README.md +130 -0
  4. data/Rakefile +63 -60
  5. data/VERSION.yml +4 -0
  6. data/examples/echo/README.md +12 -0
  7. data/examples/echo/echo.erl +13 -0
  8. data/examples/echo/echo.rb +11 -0
  9. data/examples/gruff/gruff.erl +17 -18
  10. data/examples/gruff/gruff_provider.rb +12 -19
  11. data/examples/gruff/{gruff_run.erl → gruff_run.sh} +5 -3
  12. data/examples/gruff/{stat_run.erl → stat_run.sh} +5 -3
  13. data/examples/gruff/stat_writer.erl +6 -6
  14. data/examples/simple/README.md +5 -0
  15. data/examples/simple/rerl.rb +111 -0
  16. data/examples/simple/rerl.sh +37 -0
  17. data/examples/tinderl/README.md +14 -0
  18. data/examples/tinderl/tinderl.erl +19 -21
  19. data/examples/tinderl/tinderl.rb +11 -10
  20. data/ext/decoder.c +67 -60
  21. data/lib/erlectricity.rb +4 -7
  22. data/lib/erlectricity/condition.rb +35 -20
  23. data/lib/erlectricity/conditions/boolean.rb +11 -0
  24. data/lib/erlectricity/conditions/hash.rb +9 -10
  25. data/lib/erlectricity/conditions/static.rb +31 -10
  26. data/lib/erlectricity/conditions/type.rb +14 -14
  27. data/lib/erlectricity/constants.rb +3 -4
  28. data/lib/erlectricity/decoder.rb +205 -199
  29. data/lib/erlectricity/encoder.rb +49 -35
  30. data/lib/erlectricity/errors/decode_error.rb +1 -1
  31. data/lib/erlectricity/errors/encode_error.rb +1 -1
  32. data/lib/erlectricity/errors/erlectricity_error.rb +1 -1
  33. data/lib/erlectricity/matcher.rb +15 -32
  34. data/lib/erlectricity/port.rb +11 -11
  35. data/lib/erlectricity/receiver.rb +54 -64
  36. data/lib/erlectricity/types/list.rb +3 -1
  37. data/test/condition_spec.rb +8 -9
  38. data/test/decode_spec.rb +27 -28
  39. data/test/encode_spec.rb +31 -24
  40. data/test/matcher_spec.rb +24 -12
  41. data/test/port_spec.rb +3 -4
  42. data/test/receiver_spec.rb +18 -20
  43. data/test/test_helper.rb +9 -5
  44. metadata +36 -29
  45. data/CONTRIBUTORS +0 -2
  46. data/Manifest.txt +0 -45
  47. data/README.txt +0 -43
  48. data/setup.rb +0 -1585
  49. 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
- NAME = "erlectricity"
23
- REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
- VERS = Erlectricity::VERSION::STRING + (REV ? ".#{REV}" : "")
25
- CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
26
- RDOC_OPTS = ['--quiet', '--title', 'erlectricity documentation',
27
- "--opname", "index.html",
28
- "--line-numbers",
29
- "--main", "README",
30
- "--inline-source"]
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
- class Hoe
33
- def extra_deps
34
- @extra_deps.reject { |x| Array(x).first == 'hoe' }
35
- end
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
- # Generate all the Rake tasks
39
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
40
- hoe = Hoe.new(GEM_NAME, VERS) do |p|
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
- desc 'Release the website and new gem version'
60
- task :deploy => [:check_version, :release]
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
- task :check_version do
63
- unless ENV['VERSION']
64
- puts 'Must pass a VERSION=x.y.z release version'
65
- exit
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
- unless ENV['VERSION'] == VERS
68
- puts "Please update your version.rb to match the release version, currently #{VERS}"
69
- exit
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,4 @@
1
+ ---
2
+ :major: 1
3
+ :minor: 0
4
+ :patch: 0
@@ -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.
@@ -0,0 +1,11 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), *%w[../../lib])
2
+
3
+ require 'rubygems'
4
+ require 'erlectricity'
5
+
6
+ receive do |f|
7
+ f.when([:echo, String]) do |text|
8
+ f.send!([:result, "You said: #{text}"])
9
+ f.receive_loop
10
+ end
11
+ end
@@ -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}, use_stdio, exit_status, binary]),
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__) + "/../../lib/")
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