sarb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ # Text-editor extra files
2
+ *.swp
3
+
4
+ # Version Manager files
5
+ .rvmrc
6
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rspec"
4
+ gem "em-websocket"
5
+
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,8 @@
1
+ require "rubygems"
2
+ require "rake"
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
@@ -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
+
@@ -0,0 +1,8 @@
1
+ module Sarb
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+ end
7
+ end
8
+
data/lib/sarb.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "em-websocket"
2
+ require "json"
3
+
4
+ require "sarb/application"
5
+ require "sarb/connection"
6
+ require "sarb/version"
7
+
8
+ module Sarb
9
+ end
10
+
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
+
@@ -0,0 +1,5 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "sarb"
5
+
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: []