socketable-rails 0.1.2
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/MIT-LICENSE +20 -0
- data/README.rdoc +62 -0
- data/Rakefile +27 -0
- data/app/controllers/socketable_controller.rb +44 -0
- data/config/initializers/events.rb +32 -0
- data/config/initializers/form_builder.rb +39 -0
- data/lib/assets/javascripts/socketable_rails/main.js +3 -0
- data/lib/assets/javascripts/socketable_rails/socketable_init.js +7 -0
- data/lib/assets/javascripts/socketable_rails/socketable_ujs.js +33 -0
- data/lib/socketable-rails.rb +5 -0
- data/lib/socketable-rails/engine.rb +4 -0
- data/lib/socketable-rails/version.rb +3 -0
- data/lib/tasks/install.rake +67 -0
- metadata +106 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
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.rdoc
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
= SocketableRails
|
2
|
+
|
3
|
+
Tests coming soon.
|
4
|
+
|
5
|
+
Socketable-rails uses @DanKnox Websocket-Rails gem: http://github.com/DanKnox/websocket-rails.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
Add to Gemfile
|
10
|
+
gem 'socketable-rails'
|
11
|
+
|
12
|
+
Then
|
13
|
+
$ cd rails/app/path
|
14
|
+
$ bundle install
|
15
|
+
$ rake socketable:install
|
16
|
+
$ thin start
|
17
|
+
|
18
|
+
|
19
|
+
== Usage
|
20
|
+
|
21
|
+
Building a realtime chat:
|
22
|
+
|
23
|
+
=== message.rb
|
24
|
+
Normal model
|
25
|
+
class Message < ActiveRecord::Base
|
26
|
+
attr_accessible :content
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
=== home/index.html.erb
|
31
|
+
You need to add a :websocket => true parameter to your form
|
32
|
+
<%= form_for @message, :websocket => true do |f| %>
|
33
|
+
<%= f.text_area :content %>
|
34
|
+
<button class="btn">Submit</button>
|
35
|
+
<% end %>
|
36
|
+
<div id="msgs">
|
37
|
+
</div>
|
38
|
+
|
39
|
+
=== messages_controller.rb
|
40
|
+
Create a function named *websocket* in your controller to handle the request
|
41
|
+
class MessagesController < ApplicationController
|
42
|
+
def websocket(params, socket)
|
43
|
+
message = Message.create(params[:message])
|
44
|
+
socket.broadcast(message, :create_message)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
=== javascript
|
49
|
+
Bind the event you triggered in the controller
|
50
|
+
Socketable.dispatcher().bind('create_message', function(data) {
|
51
|
+
$('#msgs').append($('<div></div>').html(data.content));
|
52
|
+
});
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
== Contributing
|
57
|
+
|
58
|
+
1. Fork it
|
59
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
60
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
61
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
62
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'SocketableRails'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class SocketableController < WebsocketRails::BaseController
|
2
|
+
attr_accessor :params
|
3
|
+
|
4
|
+
# Handle all requests
|
5
|
+
def request
|
6
|
+
begin
|
7
|
+
@params = formated_params
|
8
|
+
controller.new.websocket(params, self)
|
9
|
+
rescue Exception => e
|
10
|
+
error_message e
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def emit(data, to_event)
|
15
|
+
send_message(to_event, data)
|
16
|
+
end
|
17
|
+
|
18
|
+
def broadcast(data, to_event)
|
19
|
+
broadcast_message(to_event, data)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def formated_params
|
26
|
+
params = {}
|
27
|
+
Rack::Utils.parse_nested_query(data).each do |key, value|
|
28
|
+
key = key.to_sym
|
29
|
+
params[key] = value
|
30
|
+
end
|
31
|
+
params[:path] = Rails.application.routes.recognize_path(params[:path])
|
32
|
+
params
|
33
|
+
end
|
34
|
+
|
35
|
+
def error_message(e)
|
36
|
+
puts "-- Error in websocket function"
|
37
|
+
puts e.message
|
38
|
+
end
|
39
|
+
|
40
|
+
def controller
|
41
|
+
"#{@params[:path][:controller]}_controller".camelize.constantize
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
WebsocketRails.setup do |config|
|
2
|
+
# Uncomment to override the default log level. The log level can be
|
3
|
+
# any of the standard Logger log levels. By default it will mirror the
|
4
|
+
# current Rails environment log level.
|
5
|
+
# config.log_level = :debug
|
6
|
+
|
7
|
+
# Uncomment to change the default log file path.
|
8
|
+
# config.log_path = "#{Rails.root}/log/websocket_rails.log"
|
9
|
+
|
10
|
+
# Set to true if you wish to log the internal websocket_rails events
|
11
|
+
# such as the keepalive `websocket_rails.ping` event.
|
12
|
+
# config.log_internal_events = false
|
13
|
+
|
14
|
+
# Change to true to enable standalone server mode
|
15
|
+
# Start the standalone server with rake websocket_rails:start_server
|
16
|
+
# * Requires Redis
|
17
|
+
config.standalone = false
|
18
|
+
|
19
|
+
# Change to true to enable channel synchronization between
|
20
|
+
# multiple server instances.
|
21
|
+
# * Requires Redis.
|
22
|
+
config.synchronize = false
|
23
|
+
|
24
|
+
# Uncomment and edit to point to a different redis instance.
|
25
|
+
# Will not be used unless standalone or synchronization mode
|
26
|
+
# is enabled.
|
27
|
+
# config.redis_options = {:host => 'localhost', :port => '6379'}
|
28
|
+
end
|
29
|
+
|
30
|
+
WebsocketRails::EventMap.describe do
|
31
|
+
subscribe :request, "socketable#request"
|
32
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActionView::Helpers::FormHelper
|
2
|
+
alias :orig_form_for :form_for
|
3
|
+
|
4
|
+
def form_for(record, options = {}, &proc)
|
5
|
+
if options.include?(:websocket)
|
6
|
+
options[:html] ||= {}
|
7
|
+
options[:html][:websocket] = options.delete(:websocket) if options.has_key?(:websocket)
|
8
|
+
end
|
9
|
+
orig_form_for(record, options, &proc)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ActionView::Helpers::FormTagHelper
|
14
|
+
def html_options_for_form(url_for_options, options)
|
15
|
+
options.stringify_keys.tap do |html_options|
|
16
|
+
html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
|
17
|
+
# The following URL is unescaped, this is just a hash of options, and it is the
|
18
|
+
# responsibility of the caller to escape all the values.
|
19
|
+
html_options["action"] = url_for(url_for_options)
|
20
|
+
html_options["accept-charset"] = "UTF-8"
|
21
|
+
|
22
|
+
html_options["data-remote"] = true if html_options.delete("remote")
|
23
|
+
|
24
|
+
# Add option for data-websocket
|
25
|
+
html_options["data-websocket"] = true if html_options.delete("websocket")
|
26
|
+
|
27
|
+
if html_options["data-remote"] &&
|
28
|
+
!embed_authenticity_token_in_remote_forms &&
|
29
|
+
html_options["authenticity_token"].blank?
|
30
|
+
# The authenticity token is taken from the meta tag in this case
|
31
|
+
html_options["authenticity_token"] = false
|
32
|
+
elsif html_options["authenticity_token"] == true
|
33
|
+
# Include the default authenticity_token, which is only generated when its set to nil,
|
34
|
+
# but we needed the true value to override the default of no authenticity_token on data-remote.
|
35
|
+
html_options["authenticity_token"] = nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
(function(window, $) {
|
2
|
+
window.Socketable = function() {
|
3
|
+
var selector, dispatcher, path, host_with_port;
|
4
|
+
|
5
|
+
path = window.location.pathname;
|
6
|
+
host_with_port = window.location.host;
|
7
|
+
selector = 'form[data-websocket]';
|
8
|
+
|
9
|
+
return {
|
10
|
+
DEFAULT_EVENT_NAME: 'request',
|
11
|
+
dispatcher: function() {
|
12
|
+
if(typeof dispatcher !== 'object') {
|
13
|
+
dispatcher = new WebSocketRails(host_with_port + "/websocket");
|
14
|
+
}
|
15
|
+
return dispatcher;
|
16
|
+
},
|
17
|
+
exists: function() {
|
18
|
+
return $(selector).length > 0;
|
19
|
+
},
|
20
|
+
data: function() {
|
21
|
+
// if seletor is form
|
22
|
+
return $(selector).serialize() + "&path=" + $(selector).attr('action');
|
23
|
+
},
|
24
|
+
onDefaultAction: function(fn) {
|
25
|
+
// if selector is form
|
26
|
+
$(selector).submit(function(e) {
|
27
|
+
e.preventDefault();
|
28
|
+
fn();
|
29
|
+
});
|
30
|
+
}
|
31
|
+
};
|
32
|
+
}();
|
33
|
+
})(window, jQuery);
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rails'
|
2
|
+
namespace :socketable do
|
3
|
+
task :install => [:add_js_to_manifest, :remove_rack_lock_on_development]
|
4
|
+
|
5
|
+
desc "Add config.middleware.delete(Rack::Lock)"
|
6
|
+
task :remove_rack_lock_on_development do
|
7
|
+
config = "config/environments/development.rb"
|
8
|
+
|
9
|
+
def remove_middleware_code
|
10
|
+
out = ?\n
|
11
|
+
out << " # Line generated by socketable:install task"
|
12
|
+
out << ?\n
|
13
|
+
out << " config.middleware.delete(Rack::Lock)"
|
14
|
+
out << ?\n
|
15
|
+
out << 'end'
|
16
|
+
end
|
17
|
+
|
18
|
+
def config.middleware_removed?
|
19
|
+
not (contents =~ /config\.middleware\.delete\(Rack::Lock\)/m).nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
def config.contents
|
23
|
+
open(self).read
|
24
|
+
end
|
25
|
+
|
26
|
+
def config.add_configuration_code
|
27
|
+
data = contents
|
28
|
+
data = data.split('end')
|
29
|
+
data.delete_at(data.length-1)
|
30
|
+
|
31
|
+
data.last.concat ?\n
|
32
|
+
data.last.concat " # Line generated by socketable:install task"
|
33
|
+
data.last.concat ?\n
|
34
|
+
data.last.concat " config.middleware.delete(Rack::Lock)"
|
35
|
+
data.last.concat ?\n
|
36
|
+
data << nil
|
37
|
+
|
38
|
+
data = data.join('end')
|
39
|
+
|
40
|
+
open self, 'w' do |f|
|
41
|
+
f << data
|
42
|
+
# f << data.gsub!(/(.*)\nend/, "\1#{remove_middleware_code}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
unless config.middleware_removed?
|
47
|
+
config.add_configuration_code
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "Add socketable javascript to manifest"
|
52
|
+
task :add_js_to_manifest do
|
53
|
+
manifest = "app/assets/javascripts/application.js"
|
54
|
+
|
55
|
+
def manifest.socketable_added?
|
56
|
+
not (open(self).read =~ /\/\/= require socketable_rails\/main/m).nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
def manifest.add_socketable_js_to_manifest
|
60
|
+
open(self, 'a+'){ |f| f << "\n//= require socketable_rails/main\n" }
|
61
|
+
end
|
62
|
+
|
63
|
+
unless manifest.socketable_added?
|
64
|
+
manifest.add_socketable_js_to_manifest
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: socketable-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rafael Garcia
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.12
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.12
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: websocket-rails
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: coffee-rails
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Very small and simple gem that makes using websockets really easy.
|
63
|
+
email:
|
64
|
+
- rafbgarcia@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- app/controllers/socketable_controller.rb
|
70
|
+
- config/initializers/form_builder.rb
|
71
|
+
- config/initializers/events.rb
|
72
|
+
- lib/socketable-rails.rb
|
73
|
+
- lib/tasks/install.rake
|
74
|
+
- lib/socketable-rails/version.rb
|
75
|
+
- lib/socketable-rails/engine.rb
|
76
|
+
- lib/assets/javascripts/socketable_rails/socketable_init.js
|
77
|
+
- lib/assets/javascripts/socketable_rails/main.js
|
78
|
+
- lib/assets/javascripts/socketable_rails/socketable_ujs.js
|
79
|
+
- MIT-LICENSE
|
80
|
+
- Rakefile
|
81
|
+
- README.rdoc
|
82
|
+
homepage: https://github.com/rafbgarcia/socketable-rails
|
83
|
+
licenses: []
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.8.25
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: Rails websocket made easy
|
106
|
+
test_files: []
|