sarb 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/.gitignore +6 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +24 -0
- data/README.md +26 -0
- data/Rakefile +8 -0
- data/lib/sarb/application.rb +52 -0
- data/lib/sarb/connection.rb +32 -0
- data/lib/sarb/version.rb +8 -0
- data/lib/sarb.rb +10 -0
- data/sarb.gemspec +17 -0
- data/spec/lib/sarb/application_spec.rb +139 -0
- data/spec/lib/sarb/connection_spec.rb +62 -0
- data/spec/spec_helper.rb +5 -0
- metadata +70 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.2.2)
|
5
|
+
em-websocket (0.5.0)
|
6
|
+
eventmachine (>= 0.12.9)
|
7
|
+
http_parser.rb (~> 0.5.3)
|
8
|
+
eventmachine (1.0.3)
|
9
|
+
http_parser.rb (0.5.3)
|
10
|
+
rspec (2.13.0)
|
11
|
+
rspec-core (~> 2.13.0)
|
12
|
+
rspec-expectations (~> 2.13.0)
|
13
|
+
rspec-mocks (~> 2.13.0)
|
14
|
+
rspec-core (2.13.1)
|
15
|
+
rspec-expectations (2.13.0)
|
16
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
17
|
+
rspec-mocks (2.13.1)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
em-websocket
|
24
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Socket Action Ruby (sarb)
|
2
|
+
|
3
|
+
Framework for em-websocket that uses actions and triggers for real-time communication with your app.
|
4
|
+
|
5
|
+
## Example
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require "sarb"
|
9
|
+
|
10
|
+
app = Sarb::Application.new
|
11
|
+
app.action(:foo) { |session, args| session.message(:action => :bar) }
|
12
|
+
app.run
|
13
|
+
```
|
14
|
+
|
15
|
+
On client side:
|
16
|
+
|
17
|
+
```javascript
|
18
|
+
var ws = new WebSocket("ws://127.0.0.1:8080/");
|
19
|
+
ws.onmessage = function(message) { console.log(message) };
|
20
|
+
ws.send(JSON.stringify({ action: "foo" }))
|
21
|
+
```
|
22
|
+
|
23
|
+
## License
|
24
|
+
|
25
|
+
The MIT License - Copyright (c) 2012-2013 Craig Jackson
|
26
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sarb
|
2
|
+
class Application
|
3
|
+
DEFAULTS = {
|
4
|
+
:host => "127.0.0.1",
|
5
|
+
:port => 8080
|
6
|
+
}
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@actions = {}
|
10
|
+
@hooks = {
|
11
|
+
:connection_open => [method(:connection_open)],
|
12
|
+
:connection_close => [method(:connection_close)]
|
13
|
+
}
|
14
|
+
@connections = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def action(name, &block)
|
18
|
+
@actions[name.to_sym] = block
|
19
|
+
end
|
20
|
+
|
21
|
+
def hook(name, &block)
|
22
|
+
@hooks[name.to_sym] = [] unless @hooks.has_key?(name.to_sym)
|
23
|
+
@hooks[name.to_sym] << block
|
24
|
+
end
|
25
|
+
|
26
|
+
def new_connection(ws)
|
27
|
+
Connection.setup(self, ws)
|
28
|
+
end
|
29
|
+
|
30
|
+
def connection_open(args)
|
31
|
+
@connections << args[:connection]
|
32
|
+
end
|
33
|
+
|
34
|
+
def connection_close(args)
|
35
|
+
@connections.delete(args[:connection])
|
36
|
+
end
|
37
|
+
|
38
|
+
def run(options = {})
|
39
|
+
EventMachine::WebSocket.start(DEFAULTS.merge(options), &method(:new_connection))
|
40
|
+
end
|
41
|
+
|
42
|
+
def invoke(connection, message)
|
43
|
+
data = JSON.parse(message)
|
44
|
+
@actions[data["action"].to_sym].call(connection, data["args"])
|
45
|
+
end
|
46
|
+
|
47
|
+
def trigger(name, args)
|
48
|
+
@hooks[name.to_sym].each { |block| block.call(args) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Sarb
|
2
|
+
class Connection
|
3
|
+
def initialize(app, ws)
|
4
|
+
@app = app
|
5
|
+
@ws = ws
|
6
|
+
end
|
7
|
+
|
8
|
+
def onopen(handshake)
|
9
|
+
@app.trigger :connection_open, :connection => self
|
10
|
+
end
|
11
|
+
|
12
|
+
def onmessage(message)
|
13
|
+
@app.invoke self, message
|
14
|
+
end
|
15
|
+
|
16
|
+
def onclose(event)
|
17
|
+
@app.trigger :connection_close, :connection => self
|
18
|
+
end
|
19
|
+
|
20
|
+
def message(message)
|
21
|
+
@ws.send(message.to_json)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.setup(app, ws)
|
25
|
+
connection = Connection.new(app, ws)
|
26
|
+
ws.onopen &connection.method(:onopen)
|
27
|
+
ws.onmessage &connection.method(:onmessage)
|
28
|
+
ws.onclose &connection.method(:onclose)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/lib/sarb/version.rb
ADDED
data/lib/sarb.rb
ADDED
data/sarb.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "sarb"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.summary = "Socket Action Ruby"
|
5
|
+
s.description = "Framework for em-websocket that uses actions and triggers for real-time communication with your app."
|
6
|
+
s.authors = ["Craig Jackson"]
|
7
|
+
s.email = "tapocol@gmail.com"
|
8
|
+
s.homepage = "https://github.com/craigjackson/sarb"
|
9
|
+
|
10
|
+
s.files = `git ls-files`.split("\n")
|
11
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
12
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
|
15
|
+
s.add_dependency("em-websocket", ">= 0.5.0")
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Sarb::Application do
|
4
|
+
before do
|
5
|
+
@app = Sarb::Application.new
|
6
|
+
end
|
7
|
+
|
8
|
+
context "initialize" do
|
9
|
+
it "should set @actions @hooks @connections" do
|
10
|
+
@app.instance_variable_get(:@actions).should == {}
|
11
|
+
@app.instance_variable_get(:@hooks).should == {
|
12
|
+
:connection_open => [@app.method(:connection_open)],
|
13
|
+
:connection_close => [@app.method(:connection_close)]
|
14
|
+
}
|
15
|
+
@app.instance_variable_get(:@connections).should == []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "action" do
|
20
|
+
it "should add an action" do
|
21
|
+
block = Proc.new {}
|
22
|
+
@app.action :foo, &block
|
23
|
+
expected = {:foo => block}
|
24
|
+
@app.instance_variable_get(:@actions).should == expected
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should add an action and convert name to sym" do
|
28
|
+
block = Proc.new {}
|
29
|
+
@app.action "foo", &block
|
30
|
+
expected = {:foo => block}
|
31
|
+
@app.instance_variable_get(:@actions).should == expected
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "hook" do
|
36
|
+
before do
|
37
|
+
@app.instance_variable_set(:@hooks, {})
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should add a new hook" do
|
41
|
+
block = Proc.new {}
|
42
|
+
@app.hook :foo, &block
|
43
|
+
expected = {:foo => [block]}
|
44
|
+
@app.instance_variable_get(:@hooks).should == expected
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should add a new hook and convert name to sym" do
|
48
|
+
block = Proc.new {}
|
49
|
+
@app.hook "foo", &block
|
50
|
+
expected = {:foo => [block]}
|
51
|
+
@app.instance_variable_get(:@hooks).should == expected
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should add a new hook to the existing hooks" do
|
55
|
+
block1 = Proc.new { "block1" }
|
56
|
+
@app.instance_variable_set(:@hooks, {:foo => [block1]})
|
57
|
+
block2 = Proc.new { "block2" }
|
58
|
+
@app.hook :foo, &block2
|
59
|
+
expected = {:foo => [block1, block2]}
|
60
|
+
@app.instance_variable_get(:@hooks).should == expected
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "new_connection" do
|
65
|
+
it "should pass along the websocket to the Connection and set onmessage event" do
|
66
|
+
@connection = Sarb::Connection.new(@app, "ws")
|
67
|
+
Sarb::Connection.should_receive(:setup).with(@app, "ws").and_return(@connection)
|
68
|
+
@app.new_connection("ws").should === @connection
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "connection_open" do
|
73
|
+
it "should add to @connections" do
|
74
|
+
connection = "connection"
|
75
|
+
@app.connection_open({:connection => connection})
|
76
|
+
@app.instance_variable_get(:@connections).should == [connection]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "connection_close" do
|
81
|
+
it "should remove from @connections" do
|
82
|
+
connection1 = "connection1"
|
83
|
+
connection2 = "connection2"
|
84
|
+
@app.instance_variable_set(:@connections, [connection1, connection2])
|
85
|
+
@app.connection_close({:connection => connection1})
|
86
|
+
@app.instance_variable_get(:@connections).should == [connection2]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "run" do
|
91
|
+
it "should start an EventMachine::WebSocket with defaults" do
|
92
|
+
method = Proc.new {}
|
93
|
+
@app.stub(:method => method)
|
94
|
+
# TODO: Not really sure how to test &method is passed. "with" does not actually test &method.
|
95
|
+
EventMachine::WebSocket.should_receive(:start).with(Sarb::Application::DEFAULTS, &method)
|
96
|
+
@app.run
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should start an EventMachine::WebSocket with given host and default port" do
|
100
|
+
method = Proc.new {}
|
101
|
+
@app.stub(:method => method)
|
102
|
+
# TODO: Not really sure how to test &method is passed. "with" does not actually test &method.
|
103
|
+
EventMachine::WebSocket.should_receive(:start).with(:host => "testhost", :port => Sarb::Application::DEFAULTS[:port], &method)
|
104
|
+
@app.run :host => "testhost"
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should start an EventMachine::WebSocket with default host and given port" do
|
108
|
+
method = Proc.new {}
|
109
|
+
@app.stub(:method => method)
|
110
|
+
# TODO: Not really sure how to test &method is passed. "with" does not actually test &method.
|
111
|
+
EventMachine::WebSocket.should_receive(:start).with(:host => Sarb::Application::DEFAULTS[:host], :port => "testport", &method)
|
112
|
+
@app.run :port => "testport"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "invoke" do
|
117
|
+
it "should call action's method" do
|
118
|
+
@ws = "ws"
|
119
|
+
connection = Sarb::Connection.new(@app, @ws)
|
120
|
+
block = Proc.new {}
|
121
|
+
@app.instance_variable_set(:@actions, {:action => block})
|
122
|
+
JSON.should_receive(:parse).with("message").and_return({"action" => "action", "args" => {"foo" => "bar"}})
|
123
|
+
block.should_receive(:call).with(connection, {"foo" => "bar"})
|
124
|
+
@app.invoke(connection, "message")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "trigger" do
|
129
|
+
it "should call all hooks' methods" do
|
130
|
+
block1 = Proc.new { "block1" }
|
131
|
+
block2 = Proc.new { "block2" }
|
132
|
+
@app.instance_variable_set(:@hooks, {:foo => [block1, block2]})
|
133
|
+
block1.should_receive(:call).with({:foo => :bar})
|
134
|
+
block2.should_receive(:call).with({:foo => :bar})
|
135
|
+
@app.trigger "foo", {:foo => :bar}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Sarb::Connection do
|
4
|
+
before do
|
5
|
+
@app = Sarb::Application.new
|
6
|
+
@ws = EventMachine::WebSocket::Connection.new("asdf1234", {})
|
7
|
+
@connection = Sarb::Connection.new(@app, @ws)
|
8
|
+
end
|
9
|
+
|
10
|
+
context "initialize" do
|
11
|
+
it "should set app and ws" do
|
12
|
+
@connection.instance_variable_get(:@app).should === @app
|
13
|
+
@connection.instance_variable_get(:@ws).should === @ws
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "onopen" do
|
18
|
+
before do
|
19
|
+
@handshake = EventMachine::WebSocket::Handshake.new("asdf1234")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should trigger app :connection_open" do
|
23
|
+
@app.should_receive(:trigger).with(:connection_open, {:connection => @connection})
|
24
|
+
@connection.onopen(@handshake)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "onmessage" do
|
29
|
+
it "should use the app's handler" do
|
30
|
+
@app.should_receive(:invoke).with(@connection, "message")
|
31
|
+
@connection.onmessage("message")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "onclose" do
|
36
|
+
it "should trigger app :connection_close" do
|
37
|
+
@app.should_receive(:trigger).with(:connection_close, {:connection => @connection})
|
38
|
+
@connection.onclose({})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "message" do
|
43
|
+
it "should send through ws" do
|
44
|
+
message = "message"
|
45
|
+
message.should_receive(:to_json).and_return("message_str")
|
46
|
+
@ws.should_receive(:send).with("message_str")
|
47
|
+
@connection.message(message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "setup" do
|
52
|
+
it "should create new Connection and add 'on' events" do
|
53
|
+
Sarb::Connection.should_receive(:new).with(@app, @ws).and_return(@connection)
|
54
|
+
# TODO: Putting the intended blocks in the 'with' method on the following stubs causes an error.
|
55
|
+
@ws.should_receive(:onopen)
|
56
|
+
@ws.should_receive(:onmessage)
|
57
|
+
@ws.should_receive(:onclose)
|
58
|
+
Sarb::Connection.setup(@app, @ws)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sarb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Craig Jackson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: em-websocket
|
16
|
+
requirement: &7758080 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *7758080
|
25
|
+
description: Framework for em-websocket that uses actions and triggers for real-time
|
26
|
+
communication with your app.
|
27
|
+
email: tapocol@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- .rspec
|
34
|
+
- Gemfile
|
35
|
+
- Gemfile.lock
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- lib/sarb.rb
|
39
|
+
- lib/sarb/application.rb
|
40
|
+
- lib/sarb/connection.rb
|
41
|
+
- lib/sarb/version.rb
|
42
|
+
- sarb.gemspec
|
43
|
+
- spec/lib/sarb/application_spec.rb
|
44
|
+
- spec/lib/sarb/connection_spec.rb
|
45
|
+
- spec/spec_helper.rb
|
46
|
+
homepage: https://github.com/craigjackson/sarb
|
47
|
+
licenses: []
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.8.10
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Socket Action Ruby
|
70
|
+
test_files: []
|