mojombo-bertrpc 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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.md
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 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,40 @@
1
+ BERTRPC
2
+ =======
3
+
4
+ By Tom Preston-Werner (tom@mojombo.com)
5
+
6
+ WARNING: This software is alpha and should not be used in production without
7
+ extensive testing. You should not consider this project production ready until
8
+ it is released as 1.0.
9
+
10
+
11
+ Description
12
+ -----------
13
+
14
+ BERTRPC is a Ruby BERT-RPC client library.
15
+
16
+
17
+ Installation
18
+ ------------
19
+
20
+ gem install mojombo-bertrpc -s http://gems.github.com
21
+
22
+
23
+ Example
24
+ -------
25
+
26
+ require 'bertrpc'
27
+
28
+ svc = BERTRPC::Service.new('localhost', 9999)
29
+ svc.calc.add.call(1, 2)
30
+ # => 3
31
+
32
+ This generates a BERT-RPC request like so:
33
+
34
+ -> {call, calc, add, [1, 2]}
35
+
36
+
37
+ Copyright
38
+ ---------
39
+
40
+ Copyright (c) 2009 Tom Preston-Werner. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "bertrpc"
8
+ gem.summary = %Q{BERTRPC is a Ruby BERT-RPC client library.}
9
+ gem.email = "tom@mojombo.com"
10
+ gem.homepage = "http://github.com/mojombo/bertrpc"
11
+ gem.authors = ["Tom Preston-Werner"]
12
+ gem.add_dependency('erlectricity', '>= 1.0.1')
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
18
+ end
19
+
20
+ require 'rake/testtask'
21
+ Rake::TestTask.new(:test) do |test|
22
+ test.libs << 'lib' << 'test'
23
+ test.pattern = 'test/**/*_test.rb'
24
+ test.verbose = true
25
+ end
26
+
27
+ begin
28
+ require 'rcov/rcovtask'
29
+ Rcov::RcovTask.new do |test|
30
+ test.libs << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+ rescue LoadError
35
+ task :rcov do
36
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
37
+ end
38
+ end
39
+
40
+
41
+ task :default => :test
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ if File.exist?('VERSION.yml')
46
+ config = YAML.load(File.read('VERSION.yml'))
47
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "bertrpc #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
57
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bertrpc.gemspec ADDED
@@ -0,0 +1,58 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{bertrpc}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Tom Preston-Werner"]
9
+ s.date = %q{2009-05-18}
10
+ s.email = %q{tom@mojombo.com}
11
+ s.extra_rdoc_files = [
12
+ "LICENSE",
13
+ "README.md"
14
+ ]
15
+ s.files = [
16
+ ".document",
17
+ ".gitignore",
18
+ "LICENSE",
19
+ "README.md",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "bertrpc.gemspec",
23
+ "lib/bertrpc.rb",
24
+ "lib/bertrpc/errors.rb",
25
+ "lib/bertrpc/fun.rb",
26
+ "lib/bertrpc/mod.rb",
27
+ "lib/bertrpc/service.rb",
28
+ "test/fun_test.rb",
29
+ "test/mod_test.rb",
30
+ "test/service_test.rb",
31
+ "test/test_helper.rb"
32
+ ]
33
+ s.has_rdoc = true
34
+ s.homepage = %q{http://github.com/mojombo/bertrpc}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.0}
38
+ s.summary = %q{BERTRPC is a Ruby BERT-RPC client library.}
39
+ s.test_files = [
40
+ "test/fun_test.rb",
41
+ "test/mod_test.rb",
42
+ "test/service_test.rb",
43
+ "test/test_helper.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 2
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<erlectricity>, [">= 1.0.1"])
52
+ else
53
+ s.add_dependency(%q<erlectricity>, [">= 1.0.1"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<erlectricity>, [">= 1.0.1"])
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ module BERTRPC
2
+ class BERTRPCError < StandardError
3
+
4
+ end
5
+
6
+ class ProtocolError < BERTRPCError
7
+
8
+ end
9
+
10
+ class ServerError < BERTRPCError
11
+
12
+ end
13
+
14
+ class UserError < BERTRPCError
15
+
16
+ end
17
+ end
@@ -0,0 +1,84 @@
1
+ module BERTRPC
2
+ class Fun
3
+ def initialize(svc, mod, fun)
4
+ @svc = svc
5
+ @mod = mod
6
+ @fun = fun
7
+ end
8
+
9
+ def call(*args)
10
+ args = [*args]
11
+ bert_request = encode_ruby_request([:call, @mod, @fun, args])
12
+ bert_response = sync_request(bert_request)
13
+ decode_bert_response(bert_response)
14
+ end
15
+
16
+ # private
17
+
18
+ def sync_request(bert_request)
19
+ sock = TCPSocket.new(@svc.host, @svc.port)
20
+ sock.write([bert_request.length].pack("N"))
21
+ sock.write(bert_request)
22
+ len = sock.read(4).unpack('N').first
23
+ bert_response = sock.read(len)
24
+ sock.close
25
+ bert_response
26
+ end
27
+
28
+ def encode_ruby_request(ruby_request)
29
+ ruby_payload = convert(ruby_request)
30
+ Erlectricity::Encoder.encode(ruby_payload)
31
+ end
32
+
33
+ def decode_bert_response(bert_response)
34
+ ruby_response = Erlectricity::Decoder.decode(bert_response)
35
+ case ruby_response[0]
36
+ when :reply
37
+ deconvert(ruby_response[1])
38
+ when :error
39
+ error(ruby_response[1])
40
+ else
41
+ raise
42
+ end
43
+ end
44
+
45
+ def error(err)
46
+ case err[0]
47
+ when :protocol
48
+ raise ProtocolError.new(err[2])
49
+ when :server
50
+ raise ServerError.new(err[2])
51
+ when :user
52
+ raise UserError.new(err[2])
53
+ else
54
+ raise
55
+ end
56
+ end
57
+
58
+ def convert(item)
59
+ if item.instance_of?(Hash)
60
+ a = [:dict]
61
+ item.each_pair { |k, v| a << [convert(k), convert(v)] }
62
+ a
63
+ elsif item.instance_of?(Array)
64
+ item.map { |x| convert(x) }
65
+ else
66
+ item
67
+ end
68
+ end
69
+
70
+ def deconvert(item)
71
+ if item.instance_of?(Array)
72
+ if item.first == :dict
73
+ item[1..-1].inject({}) do |acc, x|
74
+ acc[deconvert(x[0])] = deconvert(x[1]); acc
75
+ end
76
+ else
77
+ item.map { |x| deconvert(x) }
78
+ end
79
+ else
80
+ item
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,12 @@
1
+ module BERTRPC
2
+ class Mod
3
+ def initialize(svc, mod)
4
+ @svc = svc
5
+ @mod = mod
6
+ end
7
+
8
+ def method_missing(cmd, *args)
9
+ Fun.new(@svc, @mod, cmd)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module BERTRPC
2
+ class Service
3
+ attr_accessor :host, :port
4
+
5
+ def initialize(host, port)
6
+ @host = host
7
+ @port = port
8
+ end
9
+
10
+ def method_missing(cmd, *args)
11
+ Mod.new(self, cmd)
12
+ end
13
+ end
14
+ end
data/lib/bertrpc.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'erlectricity'
2
+ require 'socket'
3
+
4
+ require 'bertrpc/service'
5
+ require 'bertrpc/mod'
6
+ require 'bertrpc/fun'
7
+ require 'bertrpc/errors'
data/test/fun_test.rb ADDED
@@ -0,0 +1,118 @@
1
+ require 'test_helper'
2
+
3
+ class FunTest < Test::Unit::TestCase
4
+ context "A Fun" do
5
+ setup do
6
+ @svc = BERTRPC::Service.new('localhost', 9941)
7
+ end
8
+
9
+ should "be created with a Service, module name, and fun name" do
10
+ assert BERTRPC::Fun.new(@svc, :mymod, :myfun).is_a?(BERTRPC::Fun)
11
+ end
12
+ end
13
+
14
+ context "A Fun instance" do
15
+ setup do
16
+ svc = BERTRPC::Service.new('localhost', 9941)
17
+ @fun = BERTRPC::Fun.new(svc, :mymod, :myfun)
18
+ end
19
+
20
+ should "call with single-arity" do
21
+ req = @fun.encode_ruby_request([:call, :mymod, :myfun, [1]])
22
+ res = @fun.encode_ruby_request([:reply, 2])
23
+ @fun.expects(:sync_request).with(req).returns(res)
24
+ assert_equal 2, @fun.call(1)
25
+ end
26
+
27
+ should "call with single-arity array" do
28
+ req = @fun.encode_ruby_request([:call, :mymod, :myfun, [[1, 2, 3]]])
29
+ res = @fun.encode_ruby_request([:reply, [4, 5, 6]])
30
+ @fun.expects(:sync_request).with(req).returns(res)
31
+ assert_equal [4, 5, 6], @fun.call([1, 2, 3])
32
+ end
33
+
34
+ should "call with multi-arity" do
35
+ req = @fun.encode_ruby_request([:call, :mymod, :myfun, [1, 2, 3]])
36
+ res = @fun.encode_ruby_request([:reply, [4, 5, 6]])
37
+ @fun.expects(:sync_request).with(req).returns(res)
38
+ assert_equal [4, 5, 6], @fun.call(1, 2, 3)
39
+ end
40
+
41
+ context "converter" do
42
+ should "convert top level hashes to BERT-RPC dict form" do
43
+ assert_equal([:dict, [:foo, 1], [:bar, 2]], @fun.convert({:foo => 1, :bar => 2}))
44
+ end
45
+
46
+ should "convert nested hashes in the same way" do
47
+ assert_equal([1, 2, [:dict, [:foo, 1]]], @fun.convert([1, 2, {:foo => 1}]))
48
+ end
49
+
50
+ should "keep everything else the same" do
51
+ assert_equal [1, 2, "foo", :bar, 3.14], @fun.convert([1, 2, "foo", :bar, 3.14])
52
+ end
53
+ end
54
+
55
+ context "deconverter" do
56
+ should "convert top level BERT-RPC dict forms to hashes" do
57
+ assert_equal({:foo => 1, :bar => 2}, @fun.deconvert([:dict, [:foo, 1], [:bar, 2]]))
58
+ end
59
+
60
+ should "convert nested dicts in the same way" do
61
+ assert_equal([1, 2, {:foo => 1}], @fun.deconvert([1, 2, [:dict, [:foo, 1]]]))
62
+ end
63
+
64
+ should "keep everything else the same" do
65
+ assert_equal [1, 2, "foo", :bar, 3.14], @fun.deconvert([1, 2, "foo", :bar, 3.14])
66
+ end
67
+ end
68
+
69
+ context "sync_request" do
70
+ should "read and write BERT-Ps from the socket" do
71
+ io = stub()
72
+ io.expects(:write).with("\000\000\000\003")
73
+ io.expects(:write).with("foo")
74
+ io.expects(:read).with(4).returns("\000\000\000\003")
75
+ io.expects(:read).with(3).returns("bar")
76
+ io.expects(:close)
77
+ TCPSocket.expects(:new).returns(io)
78
+ assert_equal "bar", @fun.sync_request("foo")
79
+ end
80
+ end
81
+
82
+ context "ruby request encoder" do
83
+ should "return BERT-RPC encoded request" do
84
+ bert = "\203h\004d\000\004calld\000\005mymodd\000\005myfunh\003a\001a\002a\003"
85
+ assert_equal bert, @fun.encode_ruby_request([:call, :mymod, :myfun, [1, 2, 3]])
86
+ end
87
+ end
88
+
89
+ context "bert response decoder" do
90
+ should "return response when successful" do
91
+ req = @fun.encode_ruby_request([:reply, [1, 2, 3]])
92
+ res = @fun.decode_bert_response(req)
93
+ assert_equal [1, 2, 3], res
94
+ end
95
+
96
+ should "raise a ProtocolError error when protocol level error is returned" do
97
+ req = @fun.encode_ruby_request([:error, [:protocol, 1, "invalid"]])
98
+ assert_raises(BERTRPC::ProtocolError) do
99
+ @fun.decode_bert_response(req)
100
+ end
101
+ end
102
+
103
+ should "raise a ServerError error when server level error is returned" do
104
+ req = @fun.encode_ruby_request([:error, [:server, 1, "invalid"]])
105
+ assert_raises(BERTRPC::ServerError) do
106
+ @fun.decode_bert_response(req)
107
+ end
108
+ end
109
+
110
+ should "raise a UserError error when user level error is returned" do
111
+ req = @fun.encode_ruby_request([:error, [:user, 1, "invalid"]])
112
+ assert_raises(BERTRPC::UserError) do
113
+ @fun.decode_bert_response(req)
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
data/test/mod_test.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ class ModTest < Test::Unit::TestCase
4
+ context "A Mod" do
5
+ setup do
6
+ @svc = BERTRPC::Service.new('localhost', 9941)
7
+ end
8
+
9
+ should "be created with a Service and module name" do
10
+ assert BERTRPC::Mod.new(@svc, :mymod).is_a?(BERTRPC::Mod)
11
+ end
12
+ end
13
+
14
+ context "A Mod instance" do
15
+ setup do
16
+ svc = BERTRPC::Service.new('localhost', 9941)
17
+ @mod = BERTRPC::Mod.new(@svc, :mymod)
18
+ end
19
+
20
+ should "return a Fun instance" do
21
+ assert @mod.myfun.is_a?(BERTRPC::Fun)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class ServiceTest < Test::Unit::TestCase
4
+ context "A Service" do
5
+ should "be created with host and port" do
6
+ svc = BERTRPC::Service.new('localhost', 9941)
7
+ assert svc.is_a?(BERTRPC::Service)
8
+ end
9
+ end
10
+
11
+ context "A Service Instance" do
12
+ setup do
13
+ @svc = BERTRPC::Service.new('localhost', 9941)
14
+ end
15
+
16
+ should "return it's host" do
17
+ assert_equal 'localhost', @svc.host
18
+ end
19
+
20
+ should "return it's port" do
21
+ assert_equal 9941, @svc.port
22
+ end
23
+
24
+ should "return a Mod instance" do
25
+ assert @svc.mymod.is_a?(BERTRPC::Mod)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'bertrpc'
9
+
10
+ class Test::Unit::TestCase
11
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mojombo-bertrpc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tom Preston-Werner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-18 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: erlectricity
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.1
24
+ version:
25
+ description:
26
+ email: tom@mojombo.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.md
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.md
39
+ - Rakefile
40
+ - VERSION
41
+ - bertrpc.gemspec
42
+ - lib/bertrpc.rb
43
+ - lib/bertrpc/errors.rb
44
+ - lib/bertrpc/fun.rb
45
+ - lib/bertrpc/mod.rb
46
+ - lib/bertrpc/service.rb
47
+ - test/fun_test.rb
48
+ - test/mod_test.rb
49
+ - test/service_test.rb
50
+ - test/test_helper.rb
51
+ has_rdoc: true
52
+ homepage: http://github.com/mojombo/bertrpc
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.2.0
74
+ signing_key:
75
+ specification_version: 2
76
+ summary: BERTRPC is a Ruby BERT-RPC client library.
77
+ test_files:
78
+ - test/fun_test.rb
79
+ - test/mod_test.rb
80
+ - test/service_test.rb
81
+ - test/test_helper.rb