tinker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f35fd6efa911604ae7b1115bf22cd4111d49555a
4
+ data.tar.gz: 8118de83736f98bad6c5523bb6001bbaa7fe9da0
5
+ SHA512:
6
+ metadata.gz: 7dae780939f9307a276780ec57562ed5ee7d4f631914e22657a0ddefe52c91f6da4ed1e487a8a40b0f20fd4d1638809b21a4debc4fd7a30f33d4ac5c0ab1763e
7
+ data.tar.gz: 034a46d13632d872c47d75cff47d9480132b9d47bd4897c72f4d28fe5deddc83a9e8c164789f6c3b61fd649e906e3096f39cd354e17a2a0a458ba1c55be3e24a
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --backtrace
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tinker.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Guillaume Malette
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Tinker
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'tinker'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install tinker
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,34 @@
1
+ require "tinker/version"
2
+
3
+ require 'singleton'
4
+ require 'socket'
5
+ require 'em-websocket'
6
+ require 'json'
7
+ require 'set'
8
+ require 'securerandom'
9
+
10
+ require 'pry'
11
+
12
+ require 'tinker/monkey_patch'
13
+
14
+ require 'tinker/evented'
15
+ require 'tinker/context'
16
+ require 'tinker/context/roster'
17
+
18
+ require 'tinker/reactor'
19
+ require 'tinker/engine'
20
+ require 'tinker/application'
21
+ require 'tinker/room'
22
+ require 'tinker/client'
23
+ require 'tinker/websocket'
24
+ require 'tinker/network/message'
25
+
26
+ require 'tinker/event'
27
+ require 'tinker/event/environment'
28
+
29
+
30
+ module Tinker
31
+ class << self
32
+ attr_accessor :application
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ class Tinker::Application < Tinker::Engine
2
+ include Tinker::Reactor
3
+
4
+ on "meta.client.join", :on_client_join
5
+ on "meta.client.leave", :on_client_leave
6
+
7
+ def initialize
8
+ super
9
+ Tinker.application ||= self
10
+ end
11
+
12
+ def on_client_join(event)
13
+ add_client(event.environment.client)
14
+ end
15
+
16
+ def on_client_leave(event)
17
+ event.environment.client.disconnect
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ class Tinker::Client
2
+ attr_reader :socket, :id
3
+
4
+ def initialize(socket)
5
+ @socket = socket
6
+ @id = SecureRandom.uuid
7
+ @contexts = Set.new
8
+ end
9
+
10
+ def join(context)
11
+ @contexts.add context
12
+ send(action: 'meta.context.join', context: context.id, params: { type: context.class })
13
+ end
14
+
15
+ def leave(context)
16
+ @contexts.delete context
17
+ send(action: 'meta.context.leave', context: context.id, params: { type: context.class })
18
+ end
19
+
20
+ def disconnect
21
+ @contexts.each do |context|
22
+ context.remove_client(self)
23
+ end
24
+ end
25
+
26
+ def to_json(*a)
27
+ {
28
+ id: id
29
+ }.to_json(*a)
30
+ end
31
+
32
+ def send(params)
33
+ socket.send(params)
34
+ end
35
+ end
@@ -0,0 +1,141 @@
1
+ module Tinker::Context
2
+ include Tinker::Evented
3
+
4
+ class << self
5
+ def contexts
6
+ @contexts ||= {}
7
+ end
8
+ end
9
+
10
+ def self.included(base)
11
+ base.send :include, InstanceMethods
12
+ base.send :extend, ClassMethods
13
+ end
14
+
15
+ module InstanceMethods
16
+ attr_reader :roster, :id
17
+
18
+ def initialize
19
+ @id = SecureRandom.uuid
20
+ @roster = Set.new
21
+ initialize_listeners
22
+ Tinker::Context.contexts[@id] = self
23
+ super
24
+ end
25
+
26
+
27
+ # Public: Removes this context from accessible contexts
28
+ #
29
+ #
30
+ # Examples
31
+ #
32
+ # @room.release
33
+ #
34
+ # Returns self
35
+ def release
36
+ @roster.each do |client|
37
+ remove_client(client)
38
+ end
39
+
40
+ Tinker::Context.contexts.delete @id
41
+ self
42
+ end
43
+
44
+ # Public: Sends the message to all connected clients of this room
45
+ #
46
+ # params - The message to send to the clients
47
+ #
48
+ # Examples
49
+ #
50
+ # @room.broadcast({:chat => "message"})
51
+ #
52
+ # options:
53
+ # - except => list of clients to whom the message will not be sent
54
+ # Returns self
55
+ def broadcast(params)
56
+ except = Array(params.delete(:except)) || []
57
+ @roster.each{ |client| self.send_to_client(client, params) unless except.include?(client) }
58
+ self
59
+ end
60
+
61
+ # Public: Adds a client to the roster
62
+ #
63
+ # client - The client to add to the roster
64
+ #
65
+ # Examples
66
+ #
67
+ # @room.add_client(client)
68
+ #
69
+ # Returns self
70
+ def add_client(client)
71
+ @roster.add(client)
72
+ client.join(self)
73
+
74
+ env = Tinker::Event::Environment.new(client, self)
75
+ dispatch Tinker::Event.new("client.join", env)
76
+
77
+ broadcast(:action => "meta.roster.add", :params => {:id => client.id}, :except => client)
78
+
79
+ self
80
+ end
81
+
82
+ # Public: Removes a client from the roster
83
+ #
84
+ # client - The client to remove
85
+ #
86
+ # Examples
87
+ #
88
+ # @room.remove_client(client)
89
+ #
90
+ # Returns self
91
+ def remove_client(client)
92
+ @roster.delete client
93
+ client.leave(self)
94
+
95
+ env = Tinker::Event::Environment.new(client, self)
96
+ dispatch Tinker::Event.new("client.leave", env)
97
+
98
+ broadcast(:action => "meta.roster.remove", :params => {:id => client.id}, :except => client)
99
+
100
+ self
101
+ end
102
+
103
+ def send_to_client(client, reply_to = nil, params)
104
+ params = params.dup.merge({:context => @id, :reply_to => reply_to})
105
+ client.send(params)
106
+ end
107
+
108
+
109
+ def dispatch(event)
110
+ event.environment = Tinker::Event::Environment.new(event.environment.client, self)
111
+ super(event)
112
+ end
113
+
114
+ private
115
+ def initialize_listeners
116
+ self.class.ancestors_binding_definitions.each do |block|
117
+ self.instance_eval &block
118
+ end
119
+ end
120
+ end
121
+
122
+ module ClassMethods
123
+ def binding_definitions
124
+ @binding_definitions ||= []
125
+ end
126
+
127
+ def ancestors_binding_definitions
128
+ ancestors.select{|klass| klass < Tinker::Context}.reduce([]){|arr, klass| arr.push *klass.binding_definitions }
129
+ end
130
+
131
+ %w(on every).each do |m|
132
+ define_method(m.to_sym) do |*args, &block|
133
+ args << block if block
134
+ binding_definitions.push(Proc.new{
135
+ self.send(m, *args)
136
+ })
137
+ end
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,18 @@
1
+ module Tinker::Context::Roster
2
+ module Synchronize
3
+ def self.included(base)
4
+ raise ArgumentError, 'Must be included in a `Tinker::Context`' unless base < Tinker::Context
5
+
6
+ base.send :include, InstanceMethods
7
+
8
+ base.on "client.join", :synchronize_roster
9
+ base.on "client.leave", :synchronize_roster
10
+ end
11
+
12
+ module InstanceMethods
13
+ def synchronize_roster(event)
14
+ broadcast :action => "meta.roster.synchronize", :params => { :roster => @roster }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ class Tinker::Engine
2
+ include Singleton
3
+ include Tinker::Context
4
+
5
+ attr_accessor :config
6
+
7
+ def initialize
8
+ super
9
+ end
10
+
11
+ def self.configure
12
+ @singleton__mutex__.synchronize {
13
+ app = self.send(:allocate)
14
+ app.config = Configuration.new
15
+ yield app.config if block_given?
16
+ @singleton__instance__ = app
17
+ }
18
+ end
19
+
20
+ def self.release_singleton
21
+ @singleton__mutex__.synchronize {
22
+ @singleton__instance__ = nil
23
+ }
24
+ self
25
+ end
26
+
27
+ class Configuration
28
+ attr_accessor :port, :host
29
+
30
+ def initialize
31
+ {
32
+ port: "6202",
33
+ host: "0.0.0.0"
34
+ }.each do |k, v|
35
+ self.send("#{k}=", v)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ class Tinker::Event
2
+ attr_accessor :environment, :params, :name
3
+
4
+ def initialize(name, environment, params = {})
5
+ @name = name
6
+ @environment = environment
7
+ @params = params
8
+ end
9
+
10
+ def env
11
+ environment
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ class Tinker::Event::Environment < Hash
2
+ attr_reader :client, :context
3
+
4
+ def initialize(client, context, params = {})
5
+ @client = client
6
+ @context = context
7
+ super params
8
+ end
9
+ end
@@ -0,0 +1,48 @@
1
+ module Tinker::Evented
2
+ def on(event_name, *callbacks, &block)
3
+ raise ArgumentError, 'No callbacks given' unless callbacks.any? || block
4
+ _dispatchers[event_name].push(*callbacks) if callbacks.any?
5
+ _dispatchers[event_name].push(&block) if block
6
+ end
7
+
8
+ def every(time, *callbacks, &block)
9
+ callbacks << block if block
10
+ EventMachine.add_periodic_timer(time) do
11
+ env = Tinker::Event::Environment.new(nil, self)
12
+ event = Tinker::Event.new("meta.timer.tick", env)
13
+ callbacks.each do |callback|
14
+ event_callback(event, callback)
15
+ end
16
+ end
17
+ end
18
+
19
+ # Internal: Disatches an event
20
+ #
21
+ # event - The event to dispatch to the listeners
22
+ #
23
+ # Examples
24
+ #
25
+ # @room.dispatch(Event.new("event_name", nil, :param1 => "value1"))
26
+ def dispatch(event)
27
+ _dispatchers[event.name].each do |callback|
28
+ event_callback event, callback
29
+ end
30
+ end
31
+
32
+ protected
33
+
34
+ def event_callback(event, callback)
35
+ if callback.respond_to? :call
36
+ callback.call(event)
37
+ elsif callback.is_a?(Class) && callback.instance_methods.include?(:call)
38
+ callback.new.call(event)
39
+ elsif callback.is_a?(Symbol) && self.respond_to?(callback)
40
+ self.send(callback, event)
41
+ end
42
+ end
43
+
44
+ private
45
+ def _dispatchers
46
+ @dispatchers ||= Hash.new{|h,k| h[k] = []}
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ class Set
2
+ def to_json(*a)
3
+ to_a.to_json(*a)
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Tinker::Network
2
+ class Message
3
+ attr_reader :socket, :body
4
+
5
+ def initialize(params)
6
+ [:socket, :body].each do |param|
7
+ instance_variable_set("@#{param}", params[param])
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,105 @@
1
+ module Tinker::Reactor
2
+ include Tinker::Evented
3
+
4
+ attr_reader :event_queue, :message_queue
5
+
6
+ def trap_sigint
7
+ Signal.trap("INT"){ stop }
8
+ end
9
+
10
+ def stop
11
+ EventMachine.stop_server @websocket_server
12
+ EventMachine.add_periodic_timer(1){ wait_for_connections_and_stop }
13
+ end
14
+
15
+ def clients
16
+ @clients ||= {}
17
+ end
18
+
19
+ def run
20
+ return if @event_queue
21
+
22
+ trap_sigint
23
+
24
+ @event_queue = Queue.new
25
+ @message_queue = Queue.new
26
+
27
+ @event_thread = Thread.new do
28
+ Thread.current.abort_on_exception = true
29
+ loop do
30
+ event = @event_queue.pop
31
+ # puts "Processing event: #{event.inspect}"
32
+ event.env.context.dispatch event
33
+ end
34
+ end
35
+
36
+ @message_thread = Thread.new do
37
+ Thread.current.abort_on_exception = true
38
+ loop do
39
+ message = @message_queue.pop
40
+ # puts "Sending message: #{message.inspect}"
41
+ message.socket.send(message.body)
42
+ end
43
+ end
44
+
45
+ EventMachine.run do
46
+ Backro::Application.instance.send(:initialize)
47
+
48
+ puts "Starting EventMachine on port #{self.config.port}"
49
+
50
+ @websocket_server = EventMachine::start_server(self.config.host, self.config.port, EventMachine::WebSocket::Connection, {}) do |ws|
51
+ websocket = Tinker::WebSocket.new(ws)
52
+
53
+ client = Tinker::Client.new(websocket)
54
+ clients[ws] = client
55
+ port, ip = Socket.unpack_sockaddr_in(ws.get_peername)
56
+
57
+ ws.onopen do
58
+ puts "WebSocket Connection open (#{ip}:#{port})"
59
+
60
+ env = Tinker::Event::Environment.new(client, Tinker.application)
61
+ @event_queue.push(Tinker::Event.new("meta.client.join", env))
62
+ end
63
+
64
+ ws.onmessage do |message|
65
+ begin
66
+ # puts "Incoming message (#{ip}:#{port}): #{message}"
67
+ json = JSON(message)
68
+
69
+ env = Tinker::Event::Environment.new(client, (Tinker::Context.contexts[json['context']] || Tinker.application))
70
+ event = Tinker::Event.new("client.message.#{json['action']}", env, json['params'])
71
+
72
+ @event_queue.push(event)
73
+ rescue JSON::ParserError
74
+ # puts "Invalid message (#{ip}:#{port})"
75
+ ws.send({:type => :error, :action => :message, :errors => ["Invalid message format"]}.to_json)
76
+ end
77
+ end
78
+
79
+ ws.onclose do
80
+ puts "WebSocket Connection closed (#{ip}:#{port})"
81
+
82
+ env = Tinker::Event::Environment.new(client, Tinker.application)
83
+ @event_queue.push(Tinker::Event.new("meta.client.leave", env))
84
+
85
+ clients.delete ws
86
+ end
87
+ end
88
+ end
89
+
90
+ @event_thread.terminate
91
+ @message_thread.terminate
92
+
93
+ end
94
+
95
+ private
96
+ def wait_for_connections_and_stop
97
+ if clients.empty?
98
+ EventMachine.stop
99
+ true
100
+ else
101
+ puts "Waiting for #{clients.size} connection(s) to finish"
102
+ false
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,3 @@
1
+ class Tinker::Room
2
+ include Tinker::Context
3
+ end
@@ -0,0 +1,3 @@
1
+ module Tinker
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,12 @@
1
+ class Tinker::WebSocket
2
+ attr_reader :socket
3
+
4
+ def initialize(websocket)
5
+ @socket = websocket
6
+ end
7
+
8
+ def send(params)
9
+ message = params.to_json
10
+ Tinker.application.message_queue << Tinker::Network::Message.new(:body => message, :socket => socket)
11
+ end
12
+ end
data/readme ADDED
File without changes
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+ require 'pry'
4
+ class MockSocket
5
+ attr_reader :messages
6
+
7
+ def initialize
8
+ @messages = []
9
+ end
10
+
11
+ def send(params)
12
+ messages << params
13
+ end
14
+ end
15
+
16
+
17
+ shared_examples "a context" do
18
+
19
+ context "#add_client" do
20
+ before {
21
+ context.add_client(client_1)
22
+ context.add_client(client_2)
23
+ }
24
+
25
+ it "adds the client to the roster" do
26
+ context.roster.should include(client_1)
27
+ end
28
+
29
+ it "sends a 'meta.context.join' message" do
30
+ message = client_1.socket.messages.first
31
+ message[:action].should == 'meta.context.join'
32
+ end
33
+
34
+ it "sends the event to other clients" do
35
+ message = client_1.socket.messages.last
36
+ message[:action].should == 'meta.roster.add'
37
+ message[:params][:id].should == client_2.id
38
+ end
39
+
40
+ it "doesn't send the event to self" do
41
+ client_2.socket.messages.each do |message|
42
+ if message[:action] == 'meta.roster.add'
43
+ message[:params][:id].should_not == client_2.id
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ context "#send_to_client" do
50
+ before {
51
+ context.send_to_client(client_1, :action => :test, :params => {})
52
+ }
53
+
54
+ it "sends the message to the client" do
55
+ client_1.socket.messages.last[:action].should == :test
56
+ end
57
+ end
58
+
59
+ context "#remove_client" do
60
+ before {
61
+ context.add_client(client_1)
62
+ context.add_client(client_2)
63
+
64
+ context.remove_client(client_1)
65
+ }
66
+
67
+ it "removes the client from the roster" do
68
+ context.roster.should_not include(client_1)
69
+ end
70
+
71
+ it "sends a message to the removed client" do
72
+ client_1.socket.messages.last[:action].should == "meta.context.leave"
73
+ end
74
+
75
+ it "sends a message to the other clients" do
76
+ client_2.socket.messages.last[:action].should == "meta.roster.remove"
77
+ end
78
+ end
79
+
80
+ context "#release" do
81
+ before {
82
+ context.add_client(client_1)
83
+ context.release
84
+ }
85
+
86
+ it "removes itself from the global roster" do
87
+ Tinker::Context.contexts.should_not include(context)
88
+ end
89
+
90
+ it "disconnects all clients" do
91
+ client_1.socket.messages.last[:action].should == "meta.context.leave"
92
+ end
93
+ end
94
+
95
+ context "#broadcast" do
96
+ let(:message) { {:action => "test.broadcast", :params => {}, :context => context.id, :reply_to => nil } }
97
+
98
+ before {
99
+ context.add_client(client_1)
100
+ context.add_client(client_2)
101
+ context.broadcast(message)
102
+ }
103
+
104
+ it "sends the message to all clients" do
105
+ client_1.socket.messages.last.should == message
106
+ client_2.socket.messages.last.should == message
107
+ end
108
+ end
109
+ end
110
+
111
+
112
+
113
+ describe "Tinker::Context" do
114
+ let(:socket_1) { MockSocket.new }
115
+ let(:client_1) { Tinker::Client.new(socket_1) }
116
+
117
+ let(:socket_2) { MockSocket.new }
118
+ let(:client_2) { Tinker::Client.new(socket_2) }
119
+
120
+ context "Tinker::Room" do
121
+ let(:context) { Tinker::Room.new }
122
+
123
+ it_behaves_like "a context"
124
+ end
125
+
126
+ context "Tinker::Application" do
127
+ before { Tinker::Application.release_singleton }
128
+ let(:context) { Tinker::Application.instance }
129
+
130
+ it_behaves_like "a context"
131
+ end
132
+
133
+ describe "Tinker::Context::Roster::Synchronized" do
134
+ let(:context) { SynchronizedContext.new }
135
+ before {
136
+ context.add_client(client_1)
137
+ context.add_client(client_2)
138
+ }
139
+
140
+ it "sends the roster to all clients upon connection" do
141
+ message = client_2.socket.messages.detect{ |m| m[:action] == "meta.roster.synchronize" }
142
+ message[:action].should == "meta.roster.synchronize"
143
+
144
+ message[:params][:roster].should have(2).members
145
+
146
+ message[:params][:roster].select{ |c| c.id == client_1.id }.should have(1).member
147
+ message[:params][:roster].select{ |c| c.id == client_2.id }.should have(1).member
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples "a callback" do
4
+ before { context.on "event", callback }
5
+
6
+ it "sends the event" do
7
+ event = Tinker::Event.new("event", Tinker::Event::Environment.new(nil, context))
8
+ callback.should_receive(:call).with(event)
9
+ context.dispatch(event)
10
+ end
11
+
12
+ describe "#every" do
13
+ it "is called periodically" do
14
+ EM.run {
15
+ count = 0
16
+ callback.should_receive(:call).at_least(2).times
17
+ context.every(0.01, callback) do
18
+ EM.stop if (count += 1) >= 2
19
+ end
20
+ }
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "Evented" do
26
+ class Tester
27
+ def call(*params)
28
+ end
29
+ end
30
+
31
+ let(:context) { Tinker::Room.new }
32
+
33
+ context "with a Proc" do
34
+ let(:callback) { Proc.new{} }
35
+
36
+ it_behaves_like "a callback"
37
+ end
38
+
39
+ context "with a class instance" do
40
+ let(:callback) { Tester.new }
41
+
42
+ it_behaves_like "a callback"
43
+ end
44
+ end
@@ -0,0 +1,25 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'tinker'
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+ #config.mock_framework = :mocha
15
+
16
+ # Run specs in random order to surface order dependencies. If you find an
17
+ # order dependency and want to debug it, you can fix the order by providing
18
+ # the seed, which is printed after each run.
19
+ # --seed 1234
20
+ config.order = 'random'
21
+ end
22
+
23
+ class SynchronizedContext < Tinker::Room
24
+ include Tinker::Context::Roster::Synchronize
25
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/tinker/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Guillaume Malette"]
6
+ gem.email = ["gmalette@gmail.com"]
7
+ gem.description = %q{Tinker is a prototype for realtime games}
8
+ gem.summary = %q{Tinker is a prototype for realtime games}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "tinker"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Tinker::VERSION
17
+
18
+ gem.add_dependency "activesupport"
19
+ gem.add_dependency "em-websocket"
20
+ gem.add_dependency "rake"
21
+
22
+ gem.add_development_dependency "rspec"
23
+ gem.add_development_dependency "mocha"
24
+ gem.add_development_dependency "pry"
25
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tinker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Guillaume Malette
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: em-websocket
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mocha
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Tinker is a prototype for realtime games
98
+ email:
99
+ - gmalette@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - Gemfile
107
+ - LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - lib/tinker.rb
111
+ - lib/tinker/application.rb
112
+ - lib/tinker/client.rb
113
+ - lib/tinker/context.rb
114
+ - lib/tinker/context/roster.rb
115
+ - lib/tinker/engine.rb
116
+ - lib/tinker/event.rb
117
+ - lib/tinker/event/environment.rb
118
+ - lib/tinker/evented.rb
119
+ - lib/tinker/monkey_patch.rb
120
+ - lib/tinker/network/message.rb
121
+ - lib/tinker/reactor.rb
122
+ - lib/tinker/room.rb
123
+ - lib/tinker/version.rb
124
+ - lib/tinker/websocket.rb
125
+ - readme
126
+ - spec/context_spec.rb
127
+ - spec/events_spec.rb
128
+ - spec/spec_helper.rb
129
+ - tinker.gemspec
130
+ homepage: ''
131
+ licenses: []
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.2.2
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Tinker is a prototype for realtime games
153
+ test_files:
154
+ - spec/context_spec.rb
155
+ - spec/events_spec.rb
156
+ - spec/spec_helper.rb