erlectricity 0.1.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 (42) hide show
  1. data/Manifest.txt +41 -0
  2. data/README.txt +3 -0
  3. data/Rakefile +68 -0
  4. data/examples/gruff/gruff.erl +62 -0
  5. data/examples/gruff/gruff_provider.rb +38 -0
  6. data/examples/gruff/gruff_run.erl +17 -0
  7. data/examples/gruff/stat_run.erl +18 -0
  8. data/examples/gruff/stat_writer.erl +40 -0
  9. data/examples/tinderl/tinderl.erl +41 -0
  10. data/examples/tinderl/tinderl.rb +23 -0
  11. data/lib/erlectricity/condition.rb +48 -0
  12. data/lib/erlectricity/conditions/hash.rb +15 -0
  13. data/lib/erlectricity/conditions/static.rb +17 -0
  14. data/lib/erlectricity/conditions/type.rb +19 -0
  15. data/lib/erlectricity/constants.rb +37 -0
  16. data/lib/erlectricity/decoder.rb +202 -0
  17. data/lib/erlectricity/encoder.rb +127 -0
  18. data/lib/erlectricity/errors/decode_error.rb +3 -0
  19. data/lib/erlectricity/errors/encode_error.rb +3 -0
  20. data/lib/erlectricity/errors/erlectricity_error.rb +3 -0
  21. data/lib/erlectricity/match_context.rb +20 -0
  22. data/lib/erlectricity/matcher.rb +60 -0
  23. data/lib/erlectricity/port.rb +46 -0
  24. data/lib/erlectricity/receiver.rb +74 -0
  25. data/lib/erlectricity/types/function.rb +3 -0
  26. data/lib/erlectricity/types/new_function.rb +3 -0
  27. data/lib/erlectricity/types/new_reference.rb +3 -0
  28. data/lib/erlectricity/types/pid.rb +3 -0
  29. data/lib/erlectricity/types/reference.rb +3 -0
  30. data/lib/erlectricity/version.rb +9 -0
  31. data/lib/erlectricity.rb +23 -0
  32. data/setup.rb +1585 -0
  33. data/test/condition_spec.rb +78 -0
  34. data/test/decode_spec.rb +133 -0
  35. data/test/encode_spec.rb +125 -0
  36. data/test/matcher_spec.rb +73 -0
  37. data/test/port_spec.rb +35 -0
  38. data/test/receiver_spec.rb +105 -0
  39. data/test/spec_suite.rb +2 -0
  40. data/test/test_erlectricity.rb +2 -0
  41. data/test/test_helper.rb +36 -0
  42. metadata +87 -0
data/Manifest.txt ADDED
@@ -0,0 +1,41 @@
1
+ Manifest.txt
2
+ README.txt
3
+ Rakefile
4
+ examples/gruff/gruff.erl
5
+ examples/gruff/gruff_provider.rb
6
+ examples/gruff/gruff_run.erl
7
+ examples/gruff/stat_run.erl
8
+ examples/gruff/stat_writer.erl
9
+ examples/tinderl/tinderl.erl
10
+ examples/tinderl/tinderl.rb
11
+ lib/erlectricity.rb
12
+ lib/erlectricity/condition.rb
13
+ lib/erlectricity/conditions/hash.rb
14
+ lib/erlectricity/conditions/static.rb
15
+ lib/erlectricity/conditions/type.rb
16
+ lib/erlectricity/constants.rb
17
+ lib/erlectricity/decoder.rb
18
+ lib/erlectricity/encoder.rb
19
+ lib/erlectricity/errors/decode_error.rb
20
+ lib/erlectricity/errors/encode_error.rb
21
+ lib/erlectricity/errors/erlectricity_error.rb
22
+ lib/erlectricity/match_context.rb
23
+ lib/erlectricity/matcher.rb
24
+ lib/erlectricity/port.rb
25
+ lib/erlectricity/receiver.rb
26
+ lib/erlectricity/types/function.rb
27
+ lib/erlectricity/types/new_function.rb
28
+ lib/erlectricity/types/new_reference.rb
29
+ lib/erlectricity/types/pid.rb
30
+ lib/erlectricity/types/reference.rb
31
+ lib/erlectricity/version.rb
32
+ setup.rb
33
+ test/condition_spec.rb
34
+ test/decode_spec.rb
35
+ test/encode_spec.rb
36
+ test/matcher_spec.rb
37
+ test/port_spec.rb
38
+ test/receiver_spec.rb
39
+ test/spec_suite.rb
40
+ test/test_erlectricity.rb
41
+ test/test_helper.rb
data/README.txt ADDED
@@ -0,0 +1,3 @@
1
+ README for erlectricity
2
+ =======================
3
+
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ require 'rubygems'
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
+
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"]
31
+
32
+ class Hoe
33
+ def extra_deps
34
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
35
+ end
36
+ end
37
+
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 = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
53
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
54
+ end
55
+
56
+ desc 'Release the website and new gem version'
57
+ task :deploy => [:check_version, :release]
58
+
59
+ task :check_version do
60
+ unless ENV['VERSION']
61
+ puts 'Must pass a VERSION=x.y.z release version'
62
+ exit
63
+ end
64
+ unless ENV['VERSION'] == VERS
65
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
66
+ exit
67
+ end
68
+ end
@@ -0,0 +1,62 @@
1
+ -module(gruff).
2
+ -export([start/0, stop/0, plot/4]).
3
+
4
+ start() ->
5
+ spawn(fun() ->
6
+ register(gruff, self()),
7
+ process_flag(trap_exit, true),
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).
12
+
13
+ stop() -> gruff ! stop.
14
+
15
+ plot(Name, Font, Data, Labels) ->
16
+ gruff ! {plot, self(), Name, Font, Data, Labels},
17
+ receive
18
+ {result, Bin} -> Bin
19
+ end.
20
+
21
+ send_data(_Port, []) -> ok;
22
+ send_data(Port, [{Name, Points}|Rest]) ->
23
+ Data = {data, Name, Points},
24
+ Port ! {self(), {command, term_to_binary(Data)}},
25
+ send_data(Port, Rest).
26
+
27
+ send_labels(Port, Labels) ->
28
+ Data = {labels, Labels},
29
+ Port ! {self(), {command, term_to_binary(Data)}}.
30
+
31
+
32
+ port_loop(Port) ->
33
+ receive
34
+ {plot, Caller, Name, Font, Data, Labels} ->
35
+ PlotData = term_to_binary({plot, Name, 'Line', Font}),
36
+ Port ! {self(), {command, PlotData}},
37
+
38
+ send_data(Port, Data),
39
+ send_labels(Port, Labels),
40
+
41
+ EndData = term_to_binary('end'),
42
+ Port ! {self(), {command, EndData}},
43
+ Result = get_result(Port),
44
+ Caller ! {result, Result },
45
+
46
+ port_loop(Port);
47
+
48
+ stop ->
49
+ Port ! {self(), close},
50
+ receive
51
+ {Port, closed} -> exit(normal)
52
+ end
53
+ end.
54
+
55
+ get_result(Port) ->
56
+ receive
57
+ {Port, {data, Data}} ->
58
+ {result, Bin} = binary_to_term(Data),
59
+ Bin;
60
+ {'EXIT', Port, Reason} ->
61
+ exit({port_terminated,Reason})
62
+ end.
@@ -0,0 +1,38 @@
1
+ $:.unshift(File.dirname(__FILE__) + "/../../lib/")
2
+ require 'rubygems'
3
+ require 'erlectricity'
4
+ require 'gruff'
5
+
6
+ receive do
7
+
8
+
9
+
10
+ match(:plot, string(:name), atom(:style), string(:font)) do
11
+ graph = Gruff.const_get(style).new
12
+ graph.title = name
13
+ graph.font = font
14
+ graph.legend_font_size = 10
15
+
16
+
17
+ receive do
18
+ match(:data, atom(:name), list(:points)) do
19
+ graph.data name, points
20
+ receive_loop
21
+ end
22
+
23
+ match(:labels, hash(:label_data)) do
24
+ graph.labels = label_data
25
+ receive_loop
26
+ end
27
+
28
+ match(:end){ :ok }
29
+ end
30
+
31
+
32
+ send! :result, graph.to_blob
33
+ receive_loop
34
+ end
35
+
36
+ end
37
+
38
+
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env escript
2
+ -export([main/1]).
3
+ main(_Any) ->
4
+ Data = [
5
+ {apples, [10, 2, 3, 4, 4, 3]},
6
+ {oranges, [4, 8, 7, 9, 8, 9]},
7
+ {watermelons, [2, 3, 1, 5, 6, 8]},
8
+ {peaches, [9, 9, 10, 8, 7, 9]}
9
+ ],
10
+ gruff:start(),
11
+ Result = gruff:plot(
12
+ <<"My Charts">>,
13
+ <<"/Users/scott/Library/Fonts/Arial">>,
14
+ Data,
15
+ [{0, <<"2003">>}, {2, <<"2004">>}, {4, <<"2005">>}]
16
+ ),
17
+ file:write_file("out.png", Result).
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env escript
2
+ -export([main/1]).
3
+ main(_Any) ->
4
+ gruff:start(),
5
+ MemoryWriter = stat_writer:start(<<"Memory Info">>, fun() -> erlang:memory() end),
6
+ ProcessWriter = stat_writer:start(<<"Process Info">>,
7
+ fun() ->
8
+ {_, QueueLength} = erlang:process_info(erlang:whereis(gruff), message_queue_len),
9
+ [{processes, erlang:system_info(process_count)},
10
+ {gruff_queue_length, QueueLength}]
11
+ end
12
+ ),
13
+ receive
14
+ after 20000 ->
15
+ MemoryWriter ! stop,
16
+ ProcessWriter ! stop,
17
+ elang:halt()
18
+ end.
@@ -0,0 +1,40 @@
1
+ -module(stat_writer).
2
+ -export([start/2, loop/3]).
3
+
4
+ start(Title, Fun) ->
5
+ spawn(?MODULE, loop, [Title, Fun, []]).
6
+
7
+ loop(Title, Fun, []) ->
8
+ Data = accumulate([], Fun()),
9
+ loop(Title, Fun, Data, 0).
10
+
11
+ loop(Title, Fun, Data, Generation) ->
12
+ receive
13
+ {stop} -> ok
14
+ after 3000 ->
15
+ NewGeneration = Generation + 1,
16
+ NewData = accumulate(Data, Fun()),
17
+ NewChart = gruff:plot(
18
+ list_to_binary([Title, << "- Generation" >>, integer_to_list(NewGeneration)]),
19
+ <<"/Users/scott/Library/Fonts/Arial">>,
20
+ NewData,
21
+ []
22
+ ),
23
+ file:write_file(io_lib:format("~s - ~s.png", [Title, integer_to_list(NewGeneration)]),NewChart),
24
+ loop(Title, Fun, NewData, NewGeneration)
25
+ end.
26
+
27
+ process_axis({Name, PreviousReadings}, {Name, Reading}) ->
28
+ {Name, [Reading|PreviousReadings]}.
29
+
30
+ accumulate(Data, []) -> Data;
31
+ accumulate([], [{Name, Reading}|Rest]) ->
32
+ Data = [{Name, [Reading]}],
33
+ accumulate(Data, Rest);
34
+ accumulate(Data, [{Name, Reading}|Rest]) ->
35
+ MergedData = case lists:keysearch(Name, 1, Data) of
36
+ {value, Axis} -> lists:keyreplace(Name, 1, Data, process_axis(Axis, {Name, Reading}));
37
+ false ->
38
+ [{Name, [Reading]}|Data]
39
+ end,
40
+ accumulate(MergedData, Rest).
@@ -0,0 +1,41 @@
1
+ -module(tinderl).
2
+ -export([start/4, stop/0, speak/1, paste/1]).
3
+
4
+ start(Domain, Email, Password, Room) ->
5
+ spawn(fun() ->
6
+ register(tinderl, self()),
7
+ process_flag(trap_exit, true),
8
+ Cmd = lists:flatten(io_lib:format("ruby ./tinderl.rb ~s ~s ~s ~s", [Domain, Email, Password, Room])),
9
+ Port = open_port({spawn, Cmd}, [{packet, 4}, use_stdio, exit_status, binary]),
10
+ port_loop(Port)
11
+ end).
12
+
13
+ stop() -> tinderl ! stop.
14
+
15
+ speak(String) when is_binary(String) -> tinderl ! {speak, self(), String}.
16
+ paste(String) when is_binary(String) -> tinderl ! {paste, self(), String}.
17
+
18
+ port_loop(Port) ->
19
+ receive
20
+ {speak, _Caller, String} ->
21
+ Data = term_to_binary({speak, String}),
22
+ Port ! {self(), {command, Data}},
23
+
24
+ port_loop(Port);
25
+
26
+ {paste, _Caller, String} ->
27
+ Data = term_to_binary({paste, String}),
28
+ Port ! {self(), {command, Data}},
29
+
30
+ port_loop(Port);
31
+
32
+ stop ->
33
+ Port ! {self(), close},
34
+ receive
35
+ {Port, closed} -> exit(normal)
36
+ end;
37
+
38
+ {'EXIT', Port, Reason} ->
39
+ exit({port_terminated,Reason})
40
+ end.
41
+
@@ -0,0 +1,23 @@
1
+ $:.unshift(File.dirname(__FILE__) + "/../../lib/")
2
+ require 'rubygems'
3
+ require 'erlectricity'
4
+ require 'tinder'
5
+
6
+ domain, email, password, room_name = *ARGV
7
+ campfire = Tinder::Campfire.new domain
8
+ campfire.login email, password
9
+ room = campfire.find_room_by_name room_name
10
+
11
+ receive do
12
+ match(:speak, any(:comment)) do
13
+ room.speak comment
14
+ receive_loop
15
+ end
16
+
17
+ match(:paste, any(:comment)) do
18
+ room.paste comment
19
+ receive_loop
20
+ end
21
+ end
22
+
23
+ room.leave if room
@@ -0,0 +1,48 @@
1
+ module Erlectricity
2
+ class Condition
3
+ attr_accessor :binding_name
4
+
5
+ def initialize(binding_name=nil)
6
+ self.binding_name = binding_name
7
+ end
8
+
9
+ def bindings_for(arg)
10
+ {}
11
+ end
12
+
13
+ def satisfies?(arg)
14
+ false
15
+ end
16
+
17
+ end
18
+
19
+ module Conditions
20
+ def atom(name=nil)
21
+ TypeCondition.new(Symbol, name)
22
+ end
23
+
24
+ def any(name=nil)
25
+ TypeCondition.new(Object, name)
26
+ end
27
+
28
+ def number(name=nil)
29
+ TypeCondition.new(Fixnum, name)
30
+ end
31
+
32
+ def pid(name=nil)
33
+ TypeCondition.new(Erlectricity::Pid, name)
34
+ end
35
+
36
+ def string(name=nil)
37
+ TypeCondition.new(String, name)
38
+ end
39
+
40
+ def list(name=nil)
41
+ TypeCondition.new(Array, name)
42
+ end
43
+
44
+ def hash(name=nil)
45
+ HashCondition.new(name)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,15 @@
1
+ module Erlectricity
2
+ class HashCondition < Condition
3
+
4
+ def satisfies?(arg)
5
+ return false unless arg.class == Array
6
+ arg.all?{|x| x.class == Array && x.length == 2}
7
+ end
8
+
9
+ def bindings_for(arg)
10
+ return {} unless self.binding_name
11
+ flattened = arg.inject([]){|memo, kv| memo + kv}
12
+ {self.binding_name => Hash[*flattened]}
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Erlectricity
2
+ class StaticCondition < Condition
3
+ attr_accessor :value
4
+ def initialize(value, name=nil)
5
+ self.value = value
6
+ super(name)
7
+ end
8
+
9
+ def satisfies?(arg)
10
+ arg.eql? value
11
+ end
12
+
13
+ def bindings_for(arg)
14
+ {}
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module Erlectricity
2
+ class TypeCondition < Condition
3
+ attr_accessor :type
4
+
5
+ def initialize(type, name=nil)
6
+ self.type = type
7
+ super(name)
8
+ end
9
+
10
+ def satisfies?(arg)
11
+ arg.is_a? self.type
12
+ end
13
+
14
+ def bindings_for(arg)
15
+ return {} unless self.binding_name
16
+ {self.binding_name => arg}
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,37 @@
1
+ module Erlectricity
2
+ module External
3
+ module Types
4
+ SMALL_INT = 97
5
+ INT = 98
6
+
7
+ SMALL_BIGNUM = 110
8
+ LARGE_BIGNUM = 111
9
+
10
+ FLOAT = 99
11
+
12
+ ATOM = 100
13
+ REF = 101 #old style reference
14
+ NEW_REF = 114
15
+ PORT = 102 #not supported accross node boundaries
16
+ PID = 103
17
+
18
+ SMALL_TUPLE = 104
19
+ LARGE_TUPLE = 105
20
+
21
+ NIL = 106
22
+ STRING = 107
23
+ LIST = 108
24
+ BIN = 109
25
+
26
+ FUN = 117
27
+ NEW_FUN = 112
28
+ end
29
+
30
+ VERSION = 131
31
+
32
+ MAX_INT = (1 << 27) -1
33
+ MIN_INT = -(1 << 27)
34
+ MAX_ATOM = 255
35
+ end
36
+
37
+ end
@@ -0,0 +1,202 @@
1
+ module Erlectricity
2
+ class Decoder
3
+ attr_accessor :in
4
+ include Erlectricity::External::Types
5
+
6
+ def self.read_any_from(string)
7
+ new(StringIO.new(string)).read_any
8
+ end
9
+
10
+ def initialize(ins)
11
+ @in = ins
12
+ @peeked = ""
13
+ end
14
+
15
+ def read_any
16
+ fail("Bad Magic") unless read_1 == Erlectricity::External::VERSION
17
+ read_any_raw
18
+ end
19
+
20
+ def read_any_raw
21
+ case peek_1
22
+ when ATOM then read_atom
23
+ when SMALL_INT then read_small_int
24
+ when INT then read_int
25
+ when SMALL_BIGNUM then read_small_bignum
26
+ when LARGE_BIGNUM then read_large_bignum
27
+ when FLOAT then read_float
28
+ when NEW_REF then read_new_reference
29
+ when PID then read_pid
30
+ when SMALL_TUPLE then read_small_tuple
31
+ when LARGE_TUPLE then read_large_tuple
32
+ when NIL then read_nil
33
+ when STRING then read_erl_string
34
+ when LIST then read_list
35
+ when BIN then read_bin
36
+ else
37
+ fail("Unknown term tag: #{peek_1}")
38
+ end
39
+ end
40
+
41
+ def read(length)
42
+ if length < @peeked.length
43
+ result = @peeked[0...length]
44
+ @peeked = @peeked[length..-1]
45
+ length = 0
46
+ else
47
+ result = @peeked
48
+ @peeked = ''
49
+ length -= result.length
50
+ end
51
+
52
+ if length > 0
53
+ result << @in.read(length)
54
+ end
55
+ result
56
+ end
57
+
58
+ def peek(length)
59
+ if length <= @peeked.length
60
+ @peeked[0...length]
61
+ else
62
+ read_bytes = @in.read(length - @peeked.length)
63
+ @peeked << read_bytes if read_bytes
64
+ @peeked
65
+ end
66
+ end
67
+
68
+ def peek_1
69
+ peek(1).unpack("C").first
70
+ end
71
+
72
+ def peek_2
73
+ peek(2).unpack("n").first
74
+ end
75
+
76
+ def read_1
77
+ read(1).unpack("C").first
78
+ end
79
+
80
+ def read_2
81
+ read(2).unpack("n").first
82
+ end
83
+
84
+ def read_4
85
+ read(4).unpack("N").first
86
+ end
87
+
88
+ def read_string(length)
89
+ read(length)
90
+ end
91
+
92
+ def read_atom
93
+ fail("Invalid Type, not an atom") unless read_1 == ATOM
94
+ length = read_2
95
+ read_string(length).to_sym
96
+ end
97
+
98
+ def read_small_int
99
+ fail("Invalid Type, not a small int") unless read_1 == SMALL_INT
100
+ read_1
101
+ end
102
+
103
+ def read_int
104
+ fail("Invalid Type, not an int") unless read_1 == INT
105
+ value = read_4
106
+ negative = (value >> 31)[0] == 1
107
+ value = (value - (1 << 32)) if negative
108
+ value = Fixnum.induced_from(value)
109
+ end
110
+
111
+ def read_small_bignum
112
+ fail("Invalid Type, not a small bignum") unless read_1 == SMALL_BIGNUM
113
+ size = read_1
114
+ sign = read_1
115
+ bytes = read_string(size).unpack("C" * size)
116
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
117
+ byte, index = *byte_index
118
+ value = (byte * (256 ** index))
119
+ sign != 0 ? (result - value) : (result + value)
120
+ end
121
+ Bignum.induced_from(added)
122
+ end
123
+
124
+ def read_large_bignum
125
+ fail("Invalid Type, not a large bignum") unless read_1 == LARGE_BIGNUM
126
+ size = read_4
127
+ sign = read_1
128
+ bytes = read_string(size).unpack("C" * size)
129
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
130
+ byte, index = *byte_index
131
+ value = (byte * (256 ** index))
132
+ sign != 0 ? (result - value) : (result + value)
133
+ end
134
+ Bignum.induced_from(added)
135
+ end
136
+
137
+ def read_float
138
+ fail("Invalid Type, not a float") unless read_1 == FLOAT
139
+ string_value = read_string(31)
140
+ result = string_value.to_f
141
+ end
142
+
143
+ def read_new_reference
144
+ fail("Invalid Type, not a new-style reference") unless read_1 == NEW_REF
145
+ size = read_2
146
+ node = read_atom
147
+ creation = read_1
148
+ id = (0...size).map{|i| read_4 }
149
+ NewReference.new(node, creation, id)
150
+ end
151
+
152
+ def read_pid
153
+ fail("Invalid Type, not a pid") unless read_1 == PID
154
+ node = read_atom
155
+ id = read_4
156
+ serial = read_4
157
+ creation = read_1
158
+ Pid.new(node, id, serial, creation)
159
+ end
160
+
161
+ def read_small_tuple
162
+ fail("Invalid Type, not a small tuple") unless read_1 == SMALL_TUPLE
163
+ arity = read_1
164
+
165
+ (0...arity).map{|i| read_any_raw }
166
+ end
167
+
168
+ def read_large_tuple
169
+ fail("Invalid Type, not a small tuple") unless read_1 == LARGE_TUPLE
170
+ arity = read_4
171
+ (0...arity).map{|i| read_any_raw}
172
+ end
173
+
174
+ def read_nil
175
+ fail("Invalid Type, not a nil list") unless read_1 == NIL
176
+ []
177
+ end
178
+
179
+ def read_erl_string
180
+ fail("Invalid Type, not an erlang string") unless read_1 == STRING
181
+ length = read_2
182
+ read_string(length).unpack('C' * length)
183
+ end
184
+
185
+ def read_list
186
+ fail("Invalid Type, not an erlang list") unless read_1 == LIST
187
+ length = read_4
188
+ (0...length).map{|i| read_any_raw}
189
+ end
190
+
191
+ def read_bin
192
+ fail("Invalid Type, not an erlang binary") unless read_1 == BIN
193
+ length = read_4
194
+ read_string(length)
195
+ end
196
+
197
+ def fail(str)
198
+ raise DecodeError, str
199
+ end
200
+
201
+ end
202
+ end