danthes 1.0.1

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.
@@ -0,0 +1,17 @@
1
+ require 'generators/danthes'
2
+
3
+ module Danthes
4
+ module Generators
5
+ class RedisInstallGenerator < Base
6
+ desc 'Create sample redis config file and add faye-redis gem to Gemfile'
7
+
8
+ def copy_files
9
+ template "danthes_redis.yml", "config/danthes_redis.yml"
10
+ end
11
+
12
+ def add_redis_gem
13
+ add_gem 'faye-redis'
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ require 'rails/generators/base'
2
+
3
+ module Danthes
4
+ module Generators
5
+ class Base < Rails::Generators::Base
6
+ def self.source_root
7
+ File.dirname(__FILE__) + "/templates"
8
+ end
9
+
10
+ def self.banner
11
+ "rails generate danthes:#{generator_name}"
12
+ end
13
+
14
+ private
15
+
16
+ def add_gem(name, options = {})
17
+ gemfile_path = File.join(destination_root, 'Gemfile')
18
+ gemfile_content = File.read(gemfile_path)
19
+ File.open(gemfile_path, 'a') { |f| f.write("\n") } unless gemfile_content =~ /\n\Z/
20
+ gem name, options unless gemfile_content.include? name
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ # Run with: rackup private_pub.ru -s thin -E production
2
+ require "bundler/setup"
3
+ require "yaml"
4
+ require "faye"
5
+ require "danthes"
6
+ require "thin"
7
+
8
+ Danthes.load_config(File.expand_path("../config/danthes.yml", __FILE__))
9
+ Faye::WebSocket.load_adapter(Danthes.config[:adapter])
10
+
11
+ path = File.expand_path("../config/danthes_redis.yml", __FILE__)
12
+ if File.exist?(path)
13
+ Danthes.load_redis_config(path)
14
+ end
15
+
16
+ run Danthes.faye_app
@@ -0,0 +1,16 @@
1
+ development:
2
+ adapter: thin
3
+ server: "http://localhost:9292"
4
+ secret_token: "secret"
5
+ mount: '/faye'
6
+ test:
7
+ adapter: thin
8
+ server: "http://localhost:9292"
9
+ secret_token: "secret"
10
+ mount: '/faye'
11
+ production:
12
+ adapter: thin
13
+ server: "http://faye.example.com"
14
+ mount: '/faye'
15
+ secret_token: "<%= defined?(SecureRandom) ? SecureRandom.hex(32) : ActiveSupport::SecureRandom.hex(32) %>"
16
+ signature_expiration: 3600 # one hour
@@ -0,0 +1,14 @@
1
+ development:
2
+ host: localhost
3
+ port: 6379
4
+ namespace: '/danthes'
5
+ test:
6
+ host: localhost
7
+ port: 6379
8
+ namespace: '/danthes'
9
+ production:
10
+ host: redis_host
11
+ port: redis_port
12
+ password: redis_password
13
+ database: redis_database
14
+ namespace: '/namespace'
@@ -0,0 +1,127 @@
1
+ describe "Danthes", ->
2
+ window.Faye = undefined
3
+ pub = undefined
4
+
5
+ signToChannel = (channel) ->
6
+ faye = {subscribe: jasmine.createSpy()}
7
+ spyOn(pub, 'faye').andCallFake (callback) ->
8
+ callback(faye)
9
+ options = {server: "server", channel: "#{channel}"}
10
+ pub.sign(options)
11
+ return [faye, options]
12
+
13
+ beforeEach ->
14
+ pub = window.Danthes
15
+ pub.reset()
16
+ script = document.getElementById('faye-connection-script')
17
+ if script?
18
+ script.parentNode.removeChild(script)
19
+
20
+ it "not adds a subscription callback without signing", ->
21
+ expect(pub.subscribe("hello", "callback")).toBe(false)
22
+ expect(pub.subscriptions).toEqual({})
23
+
24
+ it "adds a subscription callback", ->
25
+ signToChannel('hello')
26
+ pub.subscribe("hello", "callback")
27
+ expect(pub.subscriptions["hello"]['callback']).toEqual("callback")
28
+
29
+ it "has a fayeExtension which adds matching subscription signature and timestamp to outgoing message", ->
30
+ called = false
31
+ message = {channel: "/meta/subscribe", subscription: "hello"}
32
+ pub.subscriptions['hello'] = {}
33
+ pub.subscriptions['hello']['opts'] = {signature: "abcd", timestamp: "1234"}
34
+ pub.fayeExtension.outgoing message, (message) ->
35
+ expect(message.ext.danthes_signature).toEqual("abcd")
36
+ expect(message.ext.danthes_timestamp).toEqual("1234")
37
+ called = true
38
+ expect(called).toBeTruthy()
39
+
40
+ it "evaluates javascript in message response", ->
41
+ pub.handleResponse(eval: 'this.subscriptions.foo = "bar"')
42
+ expect(pub.subscriptions.foo).toEqual("bar")
43
+
44
+ it "triggers callback matching message channel in response", ->
45
+ called = false
46
+ signToChannel('test')
47
+ pub.subscribe "test", (data, channel) ->
48
+ expect(data).toEqual("abcd")
49
+ expect(channel).toEqual("test")
50
+ called = true
51
+ pub.handleResponse(channel: "test", data: "abcd")
52
+ expect(called).toBeTruthy()
53
+
54
+ it "triggers faye callback function immediately when fayeClient is available", ->
55
+ called = false
56
+ pub.fayeClient = "faye"
57
+ pub.faye (faye) ->
58
+ expect(faye).toEqual("faye")
59
+ called = true
60
+ expect(called).toBeTruthy()
61
+
62
+ it "adds fayeCallback when client and server aren't available", ->
63
+ pub.faye("callback")
64
+ expect(pub.fayeCallbacks[0]).toEqual("callback")
65
+
66
+ it "adds a script tag loading faye js when the server is present", ->
67
+ client = {addExtension: jasmine.createSpy()}
68
+ callback = jasmine.createSpy()
69
+ pub.server = "path/to/faye"
70
+ pub.faye(callback)
71
+ expect(pub.fayeCallbacks[0]).toEqual(callback)
72
+ script = document.getElementById('faye-connection-script')
73
+ expect(script).toBeDefined()
74
+ expect(script.type).toEqual("text/javascript")
75
+ expect(script.src).toMatch("path/to/faye/client.js")
76
+
77
+ it "adds a faye subscription with response handler when signing", ->
78
+ pub.fayeClient = 'string'
79
+ [faye, options] = signToChannel('somechannel')
80
+ expect(faye.subscribe).toHaveBeenCalled()
81
+ expect(pub.server).toEqual("server")
82
+ expect(pub.subscriptions.somechannel.opts).toEqual(options)
83
+
84
+ it "connects to faye server, adds extension, and executes callbacks", ->
85
+ callback = jasmine.createSpy()
86
+ client = {addExtension: jasmine.createSpy()}
87
+ window.Faye = {}
88
+ window.Faye.Client = (server) ->
89
+ expect(server).toEqual("server")
90
+ return client
91
+ pub.server = "server"
92
+ pub.fayeCallbacks.push(callback)
93
+ spyOn(pub, 'fayeExtension')
94
+ pub.connectToFaye()
95
+ expect(pub.fayeClient).toEqual(client)
96
+ expect(client.addExtension).toHaveBeenCalledWith(pub.fayeExtension)
97
+ expect(callback).toHaveBeenCalledWith(client)
98
+
99
+ it "adds subscription faye object into channel object", ->
100
+ sub = {callback: jasmine.createSpy(), errback: jasmine.createSpy()}
101
+ pub.fayeClient = {subscribe: jasmine.createSpy().andReturn(sub)}
102
+ options = {server: "server", channel: 'somechannel'}
103
+ pub.sign(options)
104
+ expect(sub.callback).toHaveBeenCalled()
105
+ expect(sub.errback).toHaveBeenCalled()
106
+ expect(pub.subscriptions.somechannel.sub).toEqual(sub)
107
+
108
+ it "removes subscription to the channel", ->
109
+ sub = {callback: jasmine.createSpy(), errback: jasmine.createSpy(), cancel: jasmine.createSpy()}
110
+ pub.fayeClient = {subscribe: jasmine.createSpy().andReturn(sub)}
111
+ options = {server: "server", channel: 'somechannel'}
112
+ pub.sign(options)
113
+ pub.unsubscribe('somechannel')
114
+ expect(sub.cancel).toHaveBeenCalled()
115
+ expect(pub.subscriptions.somechannel).toBeUndefined()
116
+ expect(pub.subscriptions).toEqual({})
117
+
118
+ it "removes all subscription to the channels", ->
119
+ sub = {callback: jasmine.createSpy(), errback: jasmine.createSpy(), cancel: jasmine.createSpy()}
120
+ pub.fayeClient = {subscribe: jasmine.createSpy().andReturn(sub)}
121
+ options = {server: "server", channel: 'somechannel'}
122
+ pub.sign(options)
123
+ pub.unsubscribeAll()
124
+ expect(sub.cancel).toHaveBeenCalled()
125
+ expect(pub.subscriptions.somechannel).toBeUndefined()
126
+ expect(pub.subscriptions).toEqual({})
127
+
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+
3
+ describe Danthes::FayeExtension do
4
+ before(:each) do
5
+ Danthes.startup
6
+ @faye = Danthes::FayeExtension.new
7
+ @message = {"channel" => "/meta/subscribe", "ext" => {}}
8
+ end
9
+
10
+ it "adds an error on an incoming subscription with a bad signature" do
11
+ @message["subscription"] = "hello"
12
+ @message["ext"]["danthes_signature"] = "bad"
13
+ @message["ext"]["danthes_timestamp"] = "123"
14
+ message = @faye.incoming(@message, lambda { |m| m })
15
+ message["error"].should eq("Incorrect signature.")
16
+ end
17
+
18
+ it "has no error when the signature matches the subscription" do
19
+ sub = Danthes.subscription(:channel => "hello")
20
+ @message["subscription"] = sub[:channel]
21
+ @message["ext"]["danthes_signature"] = sub[:signature]
22
+ @message["ext"]["danthes_timestamp"] = sub[:timestamp]
23
+ message = @faye.incoming(@message, lambda { |m| m })
24
+ message["error"].should be_nil
25
+ end
26
+
27
+ it "has an error when signature just expired" do
28
+ Danthes.config[:signature_expiration] = 1
29
+ sub = Danthes.subscription(:timestamp => 123, :channel => "hello")
30
+ @message["subscription"] = sub[:channel]
31
+ @message["ext"]["danthes_signature"] = sub[:signature]
32
+ @message["ext"]["danthes_timestamp"] = sub[:timestamp]
33
+ message = @faye.incoming(@message, lambda { |m| m })
34
+ message["error"].should eq("Signature has expired.")
35
+ end
36
+
37
+ it "has an error when trying to publish to a custom channel with a bad token" do
38
+ Danthes.config[:secret_token] = "good"
39
+ @message["channel"] = "/custom/channel"
40
+ @message["ext"]["danthes_token"] = "bad"
41
+ message = @faye.incoming(@message, lambda { |m| m })
42
+ message["error"].should eq("Incorrect token.")
43
+ end
44
+
45
+ it "raises an exception when attempting to call a custom channel without a secret_token set" do
46
+ @message["channel"] = "/custom/channel"
47
+ @message["ext"]["danthes_token"] = "bad"
48
+ lambda {
49
+ message = @faye.incoming(@message, lambda { |m| m })
50
+ }.should raise_error("No secret_token config set, ensure danthes.yml is loaded properly.")
51
+ end
52
+
53
+ it "has no error on other meta calls" do
54
+ @message["channel"] = "/meta/connect"
55
+ message = @faye.incoming(@message, lambda { |m| m })
56
+ message["error"].should be_nil
57
+ end
58
+
59
+ it "should not let message carry the private pub token after server's validation" do
60
+ Danthes.config[:secret_token] = "good"
61
+ @message["channel"] = "/custom/channel"
62
+ @message["ext"]["danthes_token"] = Danthes.config[:secret_token]
63
+ message = @faye.incoming(@message, lambda { |m| m })
64
+ message['ext']["danthes_token"].should be_nil
65
+ end
66
+
67
+ end
@@ -0,0 +1,183 @@
1
+ require "spec_helper"
2
+
3
+ describe Danthes do
4
+ before(:each) do
5
+ Danthes.startup
6
+ end
7
+
8
+ let(:config) { Danthes.config }
9
+
10
+ it "defaults server to nil" do
11
+ config[:server].should be_nil
12
+ end
13
+
14
+ it "defaults signature_expiration to nil" do
15
+ config[:signature_expiration].should be_nil
16
+ end
17
+
18
+ it "defaults subscription timestamp to current time in milliseconds" do
19
+ time = Time.now
20
+ Time.stub!(:now).and_return(time)
21
+ Danthes.subscription[:timestamp].should eq((time.to_f * 1000).round)
22
+ end
23
+
24
+ it "loads a simple configuration file via load_config" do
25
+ Danthes.env = 'production'
26
+ Danthes.load_config("spec/fixtures/danthes.yml")
27
+ config[:server].should eq("http://example.com/faye")
28
+ config[:secret_token].should eq("PRODUCTION_SECRET_TOKEN")
29
+ config[:signature_expiration].should eq(600)
30
+ config[:adapter].should eq('thin')
31
+ end
32
+
33
+ context "when redis config exists" do
34
+ before do
35
+ Danthes.env = 'test'
36
+ Danthes.load_redis_config("spec/fixtures/danthes_redis.yml")
37
+ end
38
+
39
+ it "passes redis config to faye engine options" do
40
+ config[:engine][:type].should eq Faye::Redis
41
+ config[:engine][:host].should eq 'redis_host'
42
+ config[:engine][:port].should eq 'redis_port'
43
+ config[:engine][:password].should eq 'redis_password'
44
+ config[:engine][:database].should eq 'redis_database'
45
+ config[:engine][:namespace].should eq '/namespace'
46
+ end
47
+
48
+ it "should pass redis config and default options to faye" do
49
+ Faye::RackAdapter.should_receive(:new) do |options|
50
+ options[:engine].should eq Danthes.config[:engine]
51
+ options[:mount].should eq '/faye'
52
+ end
53
+ Danthes.faye_app
54
+ end
55
+ end
56
+
57
+ context "when redis config does not exist" do
58
+ it "should not have :engine inside of config hash" do
59
+ config.should_not include :engine
60
+ end
61
+
62
+ it "should have mount point" do
63
+ config[:mount].should eq '/faye'
64
+ end
65
+ end
66
+
67
+ it "raises an exception if an invalid environment is passed to load_config" do
68
+ lambda {
69
+ Danthes.load_config("spec/fixtures/danthes.yml", 'foo')
70
+ }.should raise_error ArgumentError
71
+ end
72
+
73
+ it "includes channel, server, and custom time in subscription" do
74
+ Danthes.config[:server] = "server"
75
+ Danthes.config[:mount] = '/faye'
76
+ subscription = Danthes.subscription(:timestamp => 123, :channel => "hello")
77
+ subscription[:timestamp].should eq(123)
78
+ subscription[:channel].should eq("hello")
79
+ subscription[:server].should eq("server/faye")
80
+ end
81
+
82
+ it "returns full server url from server and mount configs" do
83
+ Danthes.config[:server] = "server.com"
84
+ Danthes.config[:mount] = '/faye'
85
+ Danthes.server_url.should == 'server.com/faye'
86
+ end
87
+
88
+ it "does a sha1 digest of channel, timestamp, and secret token" do
89
+ Danthes.config[:secret_token] = "token"
90
+ subscription = Danthes.subscription(:timestamp => 123, :channel => "channel")
91
+ subscription[:signature].should eq(Digest::SHA1.hexdigest("tokenchannel123"))
92
+ end
93
+
94
+ it "formats a message hash given a channel and a string for eval" do
95
+ Danthes.config[:secret_token] = "token"
96
+ Danthes.message("chan", "foo").should eq(
97
+ :ext => {:danthes_token => "token"},
98
+ :channel => "chan",
99
+ :data => {
100
+ :channel => "chan",
101
+ :eval => "foo"
102
+ }
103
+ )
104
+ end
105
+
106
+ it "formats a message hash given a channel and a hash" do
107
+ Danthes.config[:secret_token] = "token"
108
+ Danthes.message("chan", :foo => "bar").should eq(
109
+ :ext => {:danthes_token => "token"},
110
+ :channel => "chan",
111
+ :data => {
112
+ :channel => "chan",
113
+ :data => {:foo => "bar"}
114
+ }
115
+ )
116
+ end
117
+
118
+ it "publish message as json to server using Net::HTTP" do
119
+ Danthes.config[:server] = "http://localhost"
120
+ Danthes.config[:mount] = '/faye/path'
121
+ message = 'foo'
122
+ faye = stub_request(:post, "http://localhost/faye/path").
123
+ with(:body => {"message"=>"\"foo\""},
124
+ :headers => {'Accept'=>'*/*', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Ruby'}).
125
+ to_return(:status => 200, :body => "", :headers => {})
126
+ Danthes.publish_message(message)
127
+ faye.should have_been_made.once
128
+ end
129
+
130
+ it "it should use HTTPS if the server URL says so" do
131
+ Danthes.config[:server] = "https://localhost"
132
+ Danthes.config[:mount] = '/faye/path'
133
+ http = mock(:http).as_null_object
134
+
135
+ Net::HTTP.should_receive(:new).and_return(http)
136
+ http.should_receive(:use_ssl=).with(true)
137
+
138
+ Danthes.publish_message('foo')
139
+ end
140
+
141
+ it "it should not use HTTPS if the server URL says not to" do
142
+ Danthes.config[:server] = "http://localhost"
143
+ http = mock(:http).as_null_object
144
+
145
+ Net::HTTP.should_receive(:new).and_return(http)
146
+ http.should_receive(:use_ssl=).with(false)
147
+
148
+ Danthes.publish_message('foo')
149
+ end
150
+
151
+ it "raises an exception if no server is specified when calling publish_message" do
152
+ lambda {
153
+ Danthes.publish_message("foo")
154
+ }.should raise_error(Danthes::Error)
155
+ end
156
+
157
+ it "publish_to passes message to publish_message call" do
158
+ Danthes.should_receive(:message).with("chan", "foo").and_return("message")
159
+ Danthes.should_receive(:publish_message).with("message").and_return(:result)
160
+ Danthes.publish_to("chan", "foo").should eq(:result)
161
+ end
162
+
163
+ it "has a Faye rack app instance" do
164
+ Danthes.faye_app.should be_kind_of(Faye::RackAdapter)
165
+ end
166
+
167
+ it "says signature has expired when time passed in is greater than expiration" do
168
+ Danthes.config[:signature_expiration] = 30*60
169
+ time = Danthes.subscription[:timestamp] - 31*60*1000
170
+ Danthes.signature_expired?(time).should be_true
171
+ end
172
+
173
+ it "says signature has not expired when time passed in is less than expiration" do
174
+ Danthes.config[:signature_expiration] = 30*60
175
+ time = Danthes.subscription[:timestamp] - 29*60*1000
176
+ Danthes.signature_expired?(time).should be_false
177
+ end
178
+
179
+ it "says signature has not expired when expiration is nil" do
180
+ Danthes.config[:signature_expiration] = nil
181
+ Danthes.signature_expired?(0).should be_false
182
+ end
183
+ end
@@ -0,0 +1,10 @@
1
+ development:
2
+ adapter: thin
3
+ server: http://dev.local:9292/faye
4
+ secret_token: DEVELOPMENT_SECRET_TOKEN
5
+ signature_expiration: 600
6
+ production:
7
+ adapter: thin
8
+ server: http://example.com/faye
9
+ secret_token: PRODUCTION_SECRET_TOKEN
10
+ signature_expiration: 600
@@ -0,0 +1,6 @@
1
+ test:
2
+ host: redis_host
3
+ port: redis_port
4
+ password: redis_password
5
+ database: redis_database
6
+ namespace: '/namespace'
@@ -0,0 +1,6 @@
1
+ src_dir: app/assets/javascripts/compiled
2
+
3
+ src_files:
4
+ - danthes.js
5
+
6
+ spec_dir: spec/coffeescripts/compiled
@@ -0,0 +1,23 @@
1
+ module Jasmine
2
+ class Config
3
+
4
+ # Add your overrides or custom config code here
5
+
6
+ end
7
+ end
8
+
9
+
10
+ # Note - this is necessary for rspec2, which has removed the backtrace
11
+ module Jasmine
12
+ class SpecBuilder
13
+ def declare_spec(parent, spec)
14
+ me = self
15
+ example_name = spec["name"]
16
+ @spec_ids << spec["id"]
17
+ backtrace = @example_locations[parent.description + " " + example_name]
18
+ parent.it example_name, {} do
19
+ me.report_spec(spec["id"])
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ $:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes
2
+
3
+ require 'rubygems'
4
+ require 'jasmine'
5
+ jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb'))
6
+ require jasmine_config_overrides if File.exist?(jasmine_config_overrides)
7
+ if Jasmine::Dependencies.rspec2?
8
+ require 'rspec'
9
+ else
10
+ require 'spec'
11
+ end
12
+
13
+ jasmine_config = Jasmine::Config.new
14
+ spec_builder = Jasmine::SpecBuilder.new(jasmine_config)
15
+
16
+ should_stop = false
17
+
18
+ if Jasmine::Dependencies.rspec2?
19
+ RSpec.configuration.after(:suite) do
20
+ spec_builder.stop if should_stop
21
+ end
22
+ else
23
+ Spec::Runner.configure do |config|
24
+ config.after(:suite) do
25
+ spec_builder.stop if should_stop
26
+ end
27
+ end
28
+ end
29
+
30
+ spec_builder.start
31
+ should_stop = true
32
+ spec_builder.declare_suites
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'faye'
4
+ require 'faye/redis'
5
+ Bundler.require(:default)
6
+ require 'webmock/rspec'
7
+ RSpec.configure do |config|
8
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: danthes
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alexander Simonov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faye
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.0
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: 0.8.0
30
+ description: Private pub/sub messaging in Rails through Faye. More Faye features supported.
31
+ Based on PrivatePub.
32
+ email:
33
+ - alex@simonov.me
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - .rspec
40
+ - .rvmrc
41
+ - .travis.yml
42
+ - CHANGELOG.md
43
+ - Gemfile
44
+ - Guardfile
45
+ - LICENSE
46
+ - README.md
47
+ - Rakefile
48
+ - app/assets/javascripts/danthes.js.coffee
49
+ - danthes.gemspec
50
+ - lib/danthes.rb
51
+ - lib/danthes/engine.rb
52
+ - lib/danthes/faye_extension.rb
53
+ - lib/danthes/version.rb
54
+ - lib/danthes/view_helpers.rb
55
+ - lib/generators/danthes.rb
56
+ - lib/generators/danthes/install_generator.rb
57
+ - lib/generators/danthes/redis_install_generator.rb
58
+ - lib/generators/templates/danthes.ru
59
+ - lib/generators/templates/danthes.yml
60
+ - lib/generators/templates/danthes_redis.yml
61
+ - spec/coffeescripts/danthes_spec.js.coffee
62
+ - spec/danthes/faye_extension_spec.rb
63
+ - spec/danthes_spec.rb
64
+ - spec/fixtures/danthes.yml
65
+ - spec/fixtures/danthes_redis.yml
66
+ - spec/javascripts/support/jasmine.yml
67
+ - spec/javascripts/support/jasmine_config.rb
68
+ - spec/javascripts/support/jasmine_runner.rb
69
+ - spec/spec_helper.rb
70
+ homepage: http://github.com/phenomena/danthes
71
+ licenses: []
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 1.8.24
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: Private pub/sub messaging through Faye.
94
+ test_files:
95
+ - spec/coffeescripts/danthes_spec.js.coffee
96
+ - spec/danthes/faye_extension_spec.rb
97
+ - spec/danthes_spec.rb
98
+ - spec/fixtures/danthes.yml
99
+ - spec/fixtures/danthes_redis.yml
100
+ - spec/javascripts/support/jasmine.yml
101
+ - spec/javascripts/support/jasmine_config.rb
102
+ - spec/javascripts/support/jasmine_runner.rb
103
+ - spec/spec_helper.rb
104
+ has_rdoc: