Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

remove reliance on erlectricity

  • Loading branch information...
commit 41503465479e8762916d6997d91639f0d7308a13 1 parent 1ba84eb
@mojombo authored
View
3  .gitignore
@@ -3,3 +3,6 @@
coverage
rdoc
pkg
+ext/bert/c/Makefile
+ext/bert/c/*.bundle
+ext/bert/c/*.o
View
4 History.txt
@@ -1,3 +1,7 @@
+=
+ * Major Changes
+ * Remove reliance on Erlectricity.
+
= 1.0.0 / 2009-10-19
* No changes. Production ready!
View
27 Rakefile
@@ -12,6 +12,9 @@ begin
gem.authors = ["Tom Preston-Werner"]
gem.add_dependency('erlectricity', '>= 1.1.0')
gem.add_development_dependency("thoughtbot-shoulda")
+ gem.require_paths = ["lib", "ext"]
+ gem.files.include("ext")
+ gem.extensions << 'ext/bert/c/extconf.rb'
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
end
rescue LoadError
@@ -19,12 +22,32 @@ rescue LoadError
end
require 'rake/testtask'
-Rake::TestTask.new(:test) do |test|
+Rake::TestTask.new(:runtests) do |test|
test.libs << 'lib' << 'test'
test.pattern = 'test/**/*_test.rb'
test.verbose = true
end
+task :test => :check_dependencies do
+ require 'fileutils'
+
+ puts "\nCleaning extension build files and running all specs in native ruby mode..."
+ ['rm -f ext/bert/c/*.bundle', 'rm -f ext/bert/c/*.o'].each do |cmd|
+ `#{cmd}` && puts(cmd)
+ end
+ pid = fork do
+ exec 'rake runtests'
+ end
+ Process.waitpid(pid)
+
+ puts "\nRunning `make` to build extensions and rerunning decoder specs..."
+ Dir.chdir('ext/bert/c') { `make` }
+ pid = fork do
+ exec 'rake runtests'
+ end
+ Process.waitpid(pid)
+end
+
begin
require 'rcov/rcovtask'
Rcov::RcovTask.new do |test|
@@ -38,8 +61,6 @@ rescue LoadError
end
end
-task :test => :check_dependencies
-
task :default => :test
require 'rake/rdoctask'
View
352 ext/bert/c/decode.c
@@ -0,0 +1,352 @@
+#include "ruby.h"
+#include <string.h>
+
+#define ERL_VERSION 131
+#define ERL_SMALL_INT 97
+#define ERL_INT 98
+#define ERL_SMALL_BIGNUM 110
+#define ERL_LARGE_BIGNUM 111
+#define ERL_FLOAT 99
+#define ERL_ATOM 100
+#define ERL_SMALL_TUPLE 104
+#define ERL_LARGE_TUPLE 105
+#define ERL_NIL 106
+#define ERL_STRING 107
+#define ERL_LIST 108
+#define ERL_BIN 109
+
+static VALUE mBERT;
+static VALUE cDecode;
+void Init_decode();
+
+VALUE method_decode(VALUE klass, VALUE rString);
+
+VALUE read_any_raw(unsigned char **pData);
+
+// checkers
+
+void check_int(int num) {
+ char buf[17];
+ sprintf(buf, "%u", num);
+ rb_raise(rb_eStandardError, buf);
+}
+
+void check_str(char *str) {
+ rb_raise(rb_eStandardError, str);
+}
+
+// string peekers/readers
+
+unsigned int peek_1(unsigned char **pData) {
+ return (unsigned int) **pData;
+}
+
+unsigned int peek_2(unsigned char **pData) {
+ return (unsigned int) ((**pData << 8) + *(*pData + 1));
+}
+
+unsigned int peek_4(unsigned char **pData) {
+ return (unsigned int) ((**pData << 24) + (*(*pData + 1) << 16) + (*(*pData + 2) << 8) + *(*pData + 3));
+}
+
+unsigned int read_1(unsigned char **pData) {
+ unsigned int val = peek_1(pData);
+ *pData += 1;
+ return val;
+}
+
+unsigned int read_2(unsigned char **pData) {
+ unsigned int val = peek_2(pData);
+ *pData += 2;
+ return val;
+}
+
+unsigned int read_4(unsigned char **pData) {
+ unsigned int val = peek_4(pData);
+ *pData += 4;
+ return val;
+}
+
+// tuples, lists
+
+VALUE read_small_tuple(unsigned char **pData) {
+ if(read_1(pData) != ERL_SMALL_TUPLE) {
+ rb_raise(rb_eStandardError, "Invalid Type, not a small tuple");
+ }
+
+ int arity = read_1(pData);
+
+ VALUE array = rb_ary_new2(arity);
+
+ int i;
+ for(i = 0; i < arity; ++i) {
+ rb_ary_store(array, i, read_any_raw(pData));
+ }
+
+ return array;
+}
+
+VALUE read_large_tuple(unsigned char **pData) {
+ if(read_1(pData) != ERL_LARGE_TUPLE) {
+ rb_raise(rb_eStandardError, "Invalid Type, not a large tuple");
+ }
+
+ int arity = read_4(pData);
+
+ VALUE array = rb_ary_new2(arity);
+
+ int i;
+ for(i = 0; i < arity; ++i) {
+ rb_ary_store(array, i, read_any_raw(pData));
+ }
+
+ return array;
+}
+
+VALUE read_list(unsigned char **pData) {
+ if(read_1(pData) != ERL_LIST) {
+ rb_raise(rb_eStandardError, "Invalid Type, not an erlang list");
+ }
+
+ int size = read_4(pData);
+
+ VALUE list_class = rb_const_get(mBERT, rb_intern("List"));
+ VALUE array = rb_funcall(list_class, rb_intern("new"), 1, INT2NUM(size));
+
+ int i;
+ for(i = 0; i < size; ++i) {
+ rb_ary_store(array, i, read_any_raw(pData));
+ }
+
+ read_1(pData);
+
+ return array;
+}
+
+// primitives
+
+void read_string_raw(unsigned char *dest, unsigned char **pData, int length) {
+ memcpy((char *) dest, (char *) *pData, length);
+ *(dest + length) = (unsigned char) 0;
+ *pData += length;
+}
+
+VALUE read_bin(unsigned char **pData) {
+ if(read_1(pData) != ERL_BIN) {
+ rb_raise(rb_eStandardError, "Invalid Type, not an erlang binary");
+ }
+
+ int length = read_4(pData);
+
+ unsigned char buf[length + 1];
+ read_string_raw(buf, pData, length);
+
+ return rb_str_new((char *) buf, length);
+}
+
+VALUE read_string(unsigned char **pData) {
+ if(read_1(pData) != ERL_STRING) {
+ rb_raise(rb_eStandardError, "Invalid Type, not an erlang string");
+ }
+
+ int length = read_2(pData);
+
+ unsigned char buf[length + 1];
+ read_string_raw(buf, pData, length);
+
+ VALUE list_class = rb_const_get(mBERT, rb_intern("List"));
+ VALUE array = rb_funcall(list_class, rb_intern("new"), 1, INT2NUM(length));
+
+ int i = 0;
+ for(i; i < length; ++i) {
+ rb_ary_store(array, i, INT2NUM(*(buf + i)));
+ }
+
+ return array;
+}
+
+VALUE read_atom(unsigned char **pData) {
+ if(read_1(pData) != ERL_ATOM) {
+ rb_raise(rb_eStandardError, "Invalid Type, not an atom");
+ }
+
+ int length = read_2(pData);
+
+ unsigned char buf[length + 1];
+ read_string_raw(buf, pData, length);
+
+ return ID2SYM(rb_intern((char *) buf));
+}
+
+VALUE read_small_int(unsigned char **pData) {
+ if(read_1(pData) != ERL_SMALL_INT) {
+ rb_raise(rb_eStandardError, "Invalid Type, not a small int");
+ }
+
+ int value = read_1(pData);
+
+ return INT2FIX(value);
+}
+
+VALUE read_int(unsigned char **pData) {
+ if(read_1(pData) != ERL_INT) {
+ rb_raise(rb_eStandardError, "Invalid Type, not an int");
+ }
+
+ long long value = read_4(pData);
+
+ long long negative = ((value >> 31) & 0x1 == 1);
+
+ if(negative) {
+ value = (value - ((long long) 1 << 32));
+ }
+
+ return INT2FIX(value);
+}
+
+VALUE read_small_bignum(unsigned char **pData) {
+ if(read_1(pData) != ERL_SMALL_BIGNUM) {
+ rb_raise(rb_eStandardError, "Invalid Type, not a small bignum");
+ }
+
+ unsigned int size = read_1(pData);
+ unsigned int sign = read_1(pData);
+
+ VALUE num = INT2NUM(0);
+ VALUE tmp;
+
+ unsigned char buf[size + 1];
+ read_string_raw(buf, pData, size);
+
+ int i;
+ for(i = 0; i < size; ++i) {
+ tmp = INT2FIX(*(buf + i));
+ tmp = rb_funcall(tmp, rb_intern("<<"), 1, INT2NUM(i * 8));
+ num = rb_funcall(num, rb_intern("+"), 1, tmp);
+ }
+
+ if(sign) {
+ num = rb_funcall(num, rb_intern("*"), 1, INT2NUM(-1));
+ }
+
+ return num;
+}
+
+VALUE read_large_bignum(unsigned char **pData) {
+ if(read_1(pData) != ERL_LARGE_BIGNUM) {
+ rb_raise(rb_eStandardError, "Invalid Type, not a small bignum");
+ }
+
+ unsigned int size = read_4(pData);
+ unsigned int sign = read_1(pData);
+
+ VALUE num = INT2NUM(0);
+ VALUE tmp;
+
+ unsigned char buf[size + 1];
+ read_string_raw(buf, pData, size);
+
+ int i;
+ for(i = 0; i < size; ++i) {
+ tmp = INT2FIX(*(buf + i));
+ tmp = rb_funcall(tmp, rb_intern("<<"), 1, INT2NUM(i * 8));
+
+ num = rb_funcall(num, rb_intern("+"), 1, tmp);
+ }
+
+ if(sign) {
+ num = rb_funcall(num, rb_intern("*"), 1, INT2NUM(-1));
+ }
+
+ return num;
+}
+
+VALUE read_float(unsigned char **pData) {
+ if(read_1(pData) != ERL_FLOAT) {
+ rb_raise(rb_eStandardError, "Invalid Type, not a float");
+ }
+
+ unsigned char buf[32];
+ read_string_raw(buf, pData, 31);
+
+ VALUE rString = rb_str_new2((char *) buf);
+
+ return rb_funcall(rString, rb_intern("to_f"), 0);
+}
+
+VALUE read_nil(unsigned char **pData) {
+ if(read_1(pData) != ERL_NIL) {
+ rb_raise(rb_eStandardError, "Invalid Type, not a nil list");
+ }
+
+ VALUE list_class = rb_const_get(mBERT, rb_intern("List"));
+ return rb_funcall(list_class, rb_intern("new"), 0);
+}
+
+// read_any_raw
+
+VALUE read_any_raw(unsigned char **pData) {
+ switch(peek_1(pData)) {
+ case ERL_SMALL_INT:
+ return read_small_int(pData);
+ break;
+ case ERL_INT:
+ return read_int(pData);
+ break;
+ case ERL_FLOAT:
+ return read_float(pData);
+ break;
+ case ERL_ATOM:
+ return read_atom(pData);
+ break;
+ case ERL_SMALL_TUPLE:
+ return read_small_tuple(pData);
+ break;
+ case ERL_LARGE_TUPLE:
+ return read_large_tuple(pData);
+ break;
+ case ERL_NIL:
+ return read_nil(pData);
+ break;
+ case ERL_STRING:
+ return read_string(pData);
+ break;
+ case ERL_LIST:
+ return read_list(pData);
+ break;
+ case ERL_BIN:
+ return read_bin(pData);
+ break;
+ case ERL_SMALL_BIGNUM:
+ return read_small_bignum(pData);
+ break;
+ case ERL_LARGE_BIGNUM:
+ return read_large_bignum(pData);
+ break;
+ }
+ return Qnil;
+}
+
+VALUE method_decode(VALUE klass, VALUE rString) {
+ unsigned char *data = (unsigned char *) StringValuePtr(rString);
+
+ unsigned char **pData = &data;
+
+ // check protocol version
+ if(read_1(pData) != ERL_VERSION) {
+ rb_raise(rb_eStandardError, "Bad Magic");
+ }
+
+ return read_any_raw(pData);
+}
+
+VALUE method_impl(VALUE klass) {
+ return rb_str_new("C", 2);
+}
+
+void Init_decode() {
+ mBERT = rb_const_get(rb_cObject, rb_intern("BERT"));
+ cDecode = rb_define_class_under(mBERT, "Decode", rb_cObject);
+ rb_define_singleton_method(cDecode, "decode", method_decode, 1);
+ rb_define_singleton_method(cDecode, "impl", method_impl, 0);
+}
View
11 ext/bert/c/extconf.rb
@@ -0,0 +1,11 @@
+# Loads mkmf which is used to make makefiles for Ruby extensions
+require 'mkmf'
+
+# Give it a name
+extension_name = 'decode'
+
+# The destination
+dir_config(extension_name)
+
+# Do the work
+create_makefile(extension_name)
View
37 lib/bert.rb
@@ -1,33 +1,24 @@
require 'rubygems'
-require 'erlectricity'
-require 'bert/encoder'
-require 'bert/decoder'
+$:.unshift File.join(File.dirname(__FILE__), *%w[.. ext])
-module BERT
- def self.encode(ruby)
- Encoder.encode(ruby)
- end
+require 'bert/bert'
+require 'bert/types'
- def self.decode(bert)
- Decoder.decode(bert)
- end
-
- def self.ebin(str)
- bytes = []
- str.each_byte { |b| bytes << b.to_s }
- "<<" + bytes.join(',') + ">>"
- end
+begin
+ # try to load the C extension
+ require 'bert/c/decode'
+rescue LoadError
+ # fall back on the pure ruby version
+ require 'bert/decode'
end
-module BERT
- class Tuple < Array
- def inspect
- "t#{super}"
- end
- end
-end
+require 'bert/encode'
+
+require 'bert/encoder'
+require 'bert/decoder'
+# Global method for specifying that an array should be encoded as a tuple.
def t
BERT::Tuple
end
View
27 lib/bert/bert.rb
@@ -0,0 +1,27 @@
+module BERT
+ def self.encode(ruby)
+ Encoder.encode(ruby)
+ end
+
+ def self.decode(bert)
+ Decoder.decode(bert)
+ end
+
+ def self.ebin(str)
+ bytes = []
+ str.each_byte { |b| bytes << b.to_s }
+ "<<" + bytes.join(',') + ">>"
+ end
+
+ class List < Array
+ def inspect
+ "l#{super}"
+ end
+ end
+
+ class Tuple < Array
+ def inspect
+ "t#{super}"
+ end
+ end
+end
View
192 lib/bert/decode.rb
@@ -0,0 +1,192 @@
+module BERT
+ class Decode
+ attr_accessor :in
+ include Types
+
+ def self.impl
+ 'Ruby'
+ end
+
+ def self.decode(string)
+ new(StringIO.new(string)).read_any
+ end
+
+ def initialize(ins)
+ @in = ins
+ @peeked = ""
+ end
+
+ def read_any
+ fail("Bad Magic") unless read_1 == MAGIC
+ read_any_raw
+ end
+
+ def read_any_raw
+ case peek_1
+ when ATOM then read_atom
+ when SMALL_INT then read_small_int
+ when INT then read_int
+ when SMALL_BIGNUM then read_small_bignum
+ when LARGE_BIGNUM then read_large_bignum
+ when FLOAT then read_float
+ when SMALL_TUPLE then read_small_tuple
+ when LARGE_TUPLE then read_large_tuple
+ when NIL then read_nil
+ when STRING then read_erl_string
+ when LIST then read_list
+ when BIN then read_bin
+ else
+ fail("Unknown term tag: #{peek_1}")
+ end
+ end
+
+ def read(length)
+ if length < @peeked.length
+ result = @peeked[0...length]
+ @peeked = @peeked[length..-1]
+ length = 0
+ else
+ result = @peeked
+ @peeked = ''
+ length -= result.length
+ end
+
+ if length > 0
+ result << @in.read(length)
+ end
+ result
+ end
+
+ def peek(length)
+ if length <= @peeked.length
+ @peeked[0...length]
+ else
+ read_bytes = @in.read(length - @peeked.length)
+ @peeked << read_bytes if read_bytes
+ @peeked
+ end
+ end
+
+ def peek_1
+ peek(1).unpack("C").first
+ end
+
+ def peek_2
+ peek(2).unpack("n").first
+ end
+
+ def read_1
+ read(1).unpack("C").first
+ end
+
+ def read_2
+ read(2).unpack("n").first
+ end
+
+ def read_4
+ read(4).unpack("N").first
+ end
+
+ def read_string(length)
+ read(length)
+ end
+
+ def read_atom
+ fail("Invalid Type, not an atom") unless read_1 == ATOM
+ length = read_2
+ a = read_string(length)
+ case a
+ when ""
+ Marshal.load("\004\b:\005") # Workaround for inability to do ''.to_sym
+ else
+ a.to_sym
+ end
+ end
+
+ def read_small_int
+ fail("Invalid Type, not a small int") unless read_1 == SMALL_INT
+ read_1
+ end
+
+ def read_int
+ fail("Invalid Type, not an int") unless read_1 == INT
+ value = read_4
+ negative = (value >> 31)[0] == 1
+ value = (value - (1 << 32)) if negative
+ value = Fixnum.induced_from(value)
+ end
+
+ def read_small_bignum
+ fail("Invalid Type, not a small bignum") unless read_1 == SMALL_BIGNUM
+ size = read_1
+ sign = read_1
+ bytes = read_string(size).unpack("C" * size)
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
+ byte, index = *byte_index
+ value = (byte * (256 ** index))
+ sign != 0 ? (result - value) : (result + value)
+ end
+ Bignum.induced_from(added)
+ end
+
+ def read_large_bignum
+ fail("Invalid Type, not a large bignum") unless read_1 == LARGE_BIGNUM
+ size = read_4
+ sign = read_1
+ bytes = read_string(size).unpack("C" * size)
+ added = bytes.zip((0..bytes.length).to_a).inject(0) do |result, byte_index|
+ byte, index = *byte_index
+ value = (byte * (256 ** index))
+ sign != 0 ? (result - value) : (result + value)
+ end
+ Bignum.induced_from(added)
+ end
+
+ def read_float
+ fail("Invalid Type, not a float") unless read_1 == FLOAT
+ string_value = read_string(31)
+ result = string_value.to_f
+ end
+
+ def read_small_tuple
+ fail("Invalid Type, not a small tuple") unless read_1 == SMALL_TUPLE
+ arity = read_1
+ (0...arity).map { |i| read_any_raw }
+ end
+
+ def read_large_tuple
+ fail("Invalid Type, not a small tuple") unless read_1 == LARGE_TUPLE
+ arity = read_4
+ (0...arity).map { |i| read_any_raw }
+ end
+
+ def read_nil
+ fail("Invalid Type, not a nil list") unless read_1 == NIL
+ List.new([])
+ end
+
+ def read_erl_string
+ fail("Invalid Type, not an erlang string") unless read_1 == STRING
+ length = read_2
+ List.new(read_string(length).unpack('C' * length))
+ end
+
+ def read_list
+ fail("Invalid Type, not an erlang list") unless read_1 == LIST
+ length = read_4
+ list = (0...length).map { |i| read_any_raw }
+ read_1
+ List.new(list)
+ end
+
+ def read_bin
+ fail("Invalid Type, not an erlang binary") unless read_1 == BIN
+ length = read_4
+ read_string(length)
+ end
+
+ def fail(str)
+ raise str
+ end
+ end
+end
View
13 lib/bert/decoder.rb
@@ -5,20 +5,17 @@ class Decoder
#
# Returns a Ruby object
def self.decode(bert)
- simple_ruby = Erlectricity::Decoder.decode(bert)
+ simple_ruby = Decode.decode(bert)
convert(simple_ruby)
end
- # Convert Erlectricity representation of BERT complex types into
- # corresponding Ruby types.
+ # Convert simple Ruby form into complex Ruby form.
# +item+ is the Ruby object to convert
#
# Returns the converted Ruby object
def self.convert(item)
case item
- when TrueClass, FalseClass
- item.to_s.to_sym
- when Erl::List
+ when List
item.map { |x| convert(x) }
when Array
if item[0] == :bert
@@ -43,9 +40,9 @@ def self.convert_bert(item)
item[2].inject({}) do |acc, x|
acc[convert(x[0])] = convert(x[1]); acc
end
- when TrueClass
+ when :true
true
- when FalseClass
+ when :false
false
when :time
Time.at(item[2] * 1_000_000 + item[3], item[4])
View
142 lib/bert/encode.rb
@@ -0,0 +1,142 @@
+module BERT
+ class Encode
+ include Types
+
+ attr_accessor :out
+
+ def initialize(out)
+ self.out = out
+ end
+
+ def self.encode(data)
+ io = StringIO.new
+ self.new(io).write_any(data)
+ io.string
+ end
+
+ def write_any obj
+ write_1 MAGIC
+ write_any_raw obj
+ end
+
+ def write_any_raw obj
+ case obj
+ when Symbol then write_symbol(obj)
+ when Fixnum, Bignum then write_fixnum(obj)
+ when Float then write_float(obj)
+ when BERT::List then write_list(obj)
+ when Array then write_tuple(obj)
+ when String then write_binary(obj)
+ else
+ fail(obj)
+ end
+ end
+
+ def write_1(byte)
+ out.write([byte].pack("C"))
+ end
+
+ def write_2(short)
+ out.write([short].pack("n"))
+ end
+
+ def write_4(long)
+ out.write([long].pack("N"))
+ end
+
+ def write_string(string)
+ out.write(string)
+ end
+
+ def write_boolean(bool)
+ write_symbol(bool.to_s.to_sym)
+ end
+
+ def write_symbol(sym)
+ fail(sym) unless sym.is_a?(Symbol)
+ data = sym.to_s
+ write_1 ATOM
+ write_2 data.length
+ write_string data
+ end
+
+ def write_fixnum(num)
+ if num >= 0 && num < 256
+ write_1 SMALL_INT
+ write_1 num
+ elsif num <= MAX_INT && num >= MIN_INT
+ write_1 INT
+ write_4 num
+ else
+ write_bignum num
+ end
+ end
+
+ def write_float(float)
+ write_1 FLOAT
+ write_string format("%15.15e", float).ljust(31, "\000")
+ end
+
+ def write_bignum(num)
+ if num.is_a?(Bignum)
+ n = num.size
+ else
+ n = (num.to_s(2).size / 8.0).ceil
+ end
+ if n <= 256
+ write_1 SMALL_BIGNUM
+ write_1 n
+ write_bignum_guts(num)
+ else
+ write_1 LARGE_BIGNUM
+ write_4 n
+ write_bignum_guts(num)
+ end
+ end
+
+ def write_bignum_guts(num)
+ write_1 (num >= 0 ? 0 : 1)
+ num = num.abs
+ i = 0
+ while (rem = (num >> i * 8) % (256)) != 0
+ write_1 rem
+ i += 1
+ end
+ end
+
+ def write_tuple(data)
+ fail(data) unless data.is_a? Array
+
+ if data.length < 256
+ write_1 SMALL_TUPLE
+ write_1 data.length
+ else
+ write_1 LARGE_TUPLE
+ write_4 data.length
+ end
+
+ data.each { |e| write_any_raw e }
+ end
+
+ def write_list(data)
+ fail(data) unless data.is_a? Array
+ write_1 NIL and return if data.empty?
+ write_1 LIST
+ write_4 data.length
+ data.each{|e| write_any_raw e }
+ write_1 NIL
+ end
+
+ def write_binary(data)
+ write_1 BIN
+ write_4 data.length
+ write_string data
+ end
+
+ private
+
+ def fail(obj)
+ raise "Cannot encode to erlang external format: #{obj.inspect}"
+ end
+ end
+end
View
11 lib/bert/encoder.rb
@@ -6,24 +6,23 @@ class Encoder
# Returns a BERT
def self.encode(ruby)
complex_ruby = convert(ruby)
- Erlectricity::Encoder.encode(complex_ruby)
+ Encode.encode(complex_ruby)
end
- # Convert Ruby types into corresponding Erlectricity representation
- # of BERT complex types.
+ # Convert complex Ruby form in simple Ruby form.
# +item+ is the Ruby object to convert
#
# Returns the converted Ruby object
def self.convert(item)
case item
when Hash
- pairs = Erl::List[]
+ pairs = List[]
item.each_pair { |k, v| pairs << [convert(k), convert(v)] }
[:bert, :dict, pairs]
when Tuple
item.map { |x| convert(x) }
when Array
- Erl::List.new(item.map { |x| convert(x) })
+ List.new(item.map { |x| convert(x) })
when nil
[:bert, :nil]
when TrueClass
@@ -33,7 +32,7 @@ def self.convert(item)
when Time
[:bert, :time, item.to_i / 1_000_000, item.to_i % 1_000_000, item.usec]
when Regexp
- options = Erl::List[]
+ options = List[]
options << :caseless if item.options & Regexp::IGNORECASE > 0
options << :extended if item.options & Regexp::EXTENDED > 0
options << :multiline if item.options & Regexp::MULTILINE > 0
View
21 lib/bert/types.rb
@@ -0,0 +1,21 @@
+module BERT
+ module Types
+ SMALL_INT = 97
+ INT = 98
+ SMALL_BIGNUM = 110
+ LARGE_BIGNUM = 111
+ FLOAT = 99
+ ATOM = 100
+ SMALL_TUPLE = 104
+ LARGE_TUPLE = 105
+ NIL = 106
+ STRING = 107
+ LIST = 108
+ BIN = 109
+ FUN = 117
+ NEW_FUN = 112
+ MAGIC = 131
+ MAX_INT = (1 << 27) -1
+ MIN_INT = -(1 << 27)
+ end
+end
View
4 test/decoder_test.rb
@@ -33,13 +33,13 @@ class DecoderTest < Test::Unit::TestCase
end
should "convert true" do
- before = [:bert, true]
+ before = [:bert, :true]
after = true
assert_equal after, BERT::Decoder.convert(before)
end
should "convert false" do
- before = [:bert, false]
+ before = [:bert, :false]
after = false
assert_equal after, BERT::Decoder.convert(before)
end
View
6 test/encoder_test.rb
@@ -27,7 +27,7 @@ class EncoderTest < Test::Unit::TestCase
should "convert hash to tuple with array of tuples" do
arr = BERT::Encoder.convert({:foo => 'bar'})
assert arr.is_a?(Array)
- assert arr[2].is_a?(Erl::List)
+ assert arr[2].is_a?(BERT::List)
assert arr[2][0].is_a?(Array)
end
@@ -38,13 +38,13 @@ class EncoderTest < Test::Unit::TestCase
should "convert array to erl list" do
list = BERT::Encoder.convert([1, 2])
- assert list.is_a?(Erl::List)
+ assert list.is_a?(BERT::List)
end
should "convert an array in a tuple" do
arrtup = BERT::Encoder.convert(t[:foo, [1, 2]])
assert arrtup.is_a?(Array)
- assert arrtup[1].is_a?(Erl::List)
+ assert arrtup[1].is_a?(BERT::List)
end
should "convert true" do
View
13 test/test_helper.rb
@@ -5,15 +5,4 @@
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'bert'
-
-class Test::Unit::TestCase
-end
-
-# So I can easily see which arrays are Erl::List
-module Erl
- class List
- def inspect
- "l#{super}"
- end
- end
-end
Please sign in to comment.
Something went wrong with that request. Please try again.