rails_chat 0.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,72 @@
1
+ function buildRailsChat(doc) {
2
+ var self = {
3
+ connecting: false,
4
+ fayeClient: null,
5
+ fayeCallbacks: [],
6
+ subscriptions: {},
7
+ subscriptionCallbacks: {},
8
+
9
+ faye: function(callback) {
10
+ if (self.fayeClient) {
11
+ callback(self.fayeClient);
12
+ } else {
13
+ self.fayeCallbacks.push(callback);
14
+ if (self.subscriptions.server && !self.connecting) {
15
+ self.connecting = true;
16
+ var script = doc.createElement("script");
17
+ script.type = "text/javascript";
18
+ script.src = self.subscriptions.server + ".js";
19
+ script.onload = self.connectToFaye;
20
+ doc.documentElement.appendChild(script);
21
+ }
22
+ }
23
+ },
24
+
25
+ connectToFaye: function() {
26
+ self.fayeClient = new Faye.Client(self.subscriptions.server);
27
+ self.fayeClient.addExtension(self.fayeExtension);
28
+ for (var i=0; i < self.fayeCallbacks.length; i++) {
29
+ self.fayeCallbacks[i](self.fayeClient);
30
+ };
31
+ },
32
+
33
+ fayeExtension: {
34
+ outgoing: function(message, callback) {
35
+ if (message.channel == "/meta/subscribe") {
36
+ // Attach the signature and timestamp to subscription messages
37
+ var subscription = self.subscriptions[message.subscription];
38
+ if (!message.ext) message.ext = {};
39
+ message.ext.rails_chat_signature = subscription.signature;
40
+ message.ext.rails_chat_timestamp = subscription.timestamp;
41
+ }
42
+ callback(message);
43
+ }
44
+ },
45
+
46
+ sign: function(options) {
47
+ if (!self.subscriptions.server) {
48
+ self.subscriptions.server = options.server;
49
+ }
50
+ self.subscriptions[options.channel] = options;
51
+ self.faye(function(faye) {
52
+ faye.subscribe(options.channel, self.handleResponse);
53
+ });
54
+ },
55
+
56
+ handleResponse: function(message) {
57
+ if (message.eval) {
58
+ eval(message.eval);
59
+ }
60
+ if (callback = self.subscriptionCallbacks[message.channel]) {
61
+ callback(message.data, message.channel);
62
+ }
63
+ },
64
+
65
+ subscribe: function(channel, callback) {
66
+ self.subscriptionCallbacks[channel] = callback;
67
+ }
68
+ };
69
+ return self;
70
+ }
71
+
72
+ var RailsChat = buildRailsChat(document);
@@ -0,0 +1,115 @@
1
+ .emoticon {
2
+ display: inline-block;
3
+ width: 24px;
4
+ height: 24px;
5
+ text-indent: -10000px;
6
+ overflow: hidden;
7
+ background: url('emoticons.png') no-repeat;
8
+ text-align: left;
9
+ position: relative;
10
+ top:30%;
11
+ }
12
+ .emoticon > * {
13
+ display: none;
14
+ }
15
+ .emoticon-smile { background-position: 0 0; }
16
+ .emoticon-sad-smile { background-position: 0 -29px; }
17
+ .emoticon-big-smile { background-position: 0 -58px; }
18
+ .emoticon-cool { background-position: 0 -87px; }
19
+ .emoticon-surprised { background-position: 0 -116px; }
20
+ .emoticon-wink { background-position: 0 -145px; }
21
+ .emoticon-crying { background-position: 0 -174px; }
22
+ .emoticon-sweating { background-position: 0 -203px; }
23
+ .emoticon-speechless { background-position: 0 -232px; }
24
+ .emoticon-kiss { background-position: 0 -261px; }
25
+ .emoticon-tongue-out { background-position: 0 -290px; }
26
+ .emoticon-blush { background-position: 0 -319px; }
27
+ .emoticon-wondering { background-position: 0 -348px; }
28
+ .emoticon-sleepy { background-position: 0 -377px; }
29
+ .emoticon-dull { background-position: 0 -406px; }
30
+ .emoticon-in-love { background-position: 0 -435px; }
31
+ .emoticon-evil-grin { background-position: 0 -464px; }
32
+ .emoticon-talking { background-position: 0 -493px; }
33
+ .emoticon-yawn { background-position: 0 -522px; }
34
+ .emoticon-puke { background-position: 0 -551px; }
35
+ .emoticon-doh { background-position: 0 -580px; }
36
+ .emoticon-angry { background-position: 0 -609px; }
37
+ .emoticon-speechless-1 { background-position: 0 -638px; }
38
+ .emoticon-it-wasnt-me { background-position: 0 -667px; }
39
+ .emoticon-kiss-1 { background-position: 0 -696px; }
40
+ .emoticon-party { background-position: 0 -725px; }
41
+ .emoticon-tongue-out-1 { background-position: 0 -754px; }
42
+ .emoticon-wondering-1 { background-position: 0 -783px; }
43
+ .emoticon-worried { background-position: 0 -812px; }
44
+ .emoticon-mmm { background-position: 0 -841px; }
45
+ .emoticon-sleepy-1 { background-position: 0 -870px; }
46
+ .emoticon-dull-1 { background-position: 0 -899px; }
47
+ .emoticon-nerd { background-position: 0 -928px; }
48
+ .emoticon-evil-grin-1 { background-position: 0 -957px; }
49
+ .emoticon-lips-sealed { background-position: 0 -986px; }
50
+ .emoticon-hi { background-position: 0 -1015px; }
51
+ .emoticon-call { background-position: 0 -1044px; }
52
+ .emoticon-devil { background-position: 0 -1073px; }
53
+ .emoticon-angel { background-position: 0 -1102px; }
54
+ .emoticon-angry-1 { background-position: 0 -1131px; }
55
+ .emoticon-envy { background-position: 0 -1160px; }
56
+ .emoticon-worried-1 { background-position: 0 -1189px; }
57
+ .emoticon-nerd-1 { background-position: 0 -1218px; }
58
+ .emoticon-wait { background-position: 0 -1247px; }
59
+ .emoticon-bear { background-position: 0 -1276px; }
60
+ .emoticon-lips-sealed-1 { background-position: 0 -1305px; }
61
+ .emoticon-make-up { background-position: 0 -1334px; }
62
+ .emoticon-giggle { background-position: 0 -1363px; }
63
+ .emoticon-clapping { background-position: 0 -1392px; }
64
+ .emoticon-thinking { background-position: 0 -1421px; }
65
+ .emoticon-bow { background-position: 0 -1450px; }
66
+ .emoticon-rofl { background-position: 0 -1479px; }
67
+ .emoticon-whew { background-position: 0 -1508px; }
68
+ .emoticon-happy { background-position: 0 -1537px; }
69
+ .emoticon-smirk { background-position: 0 -1566px; }
70
+ .emoticon-nod { background-position: 0 -1595px; }
71
+ .emoticon-shake { background-position: 0 -1624px; }
72
+ .emoticon-punch { background-position: 0 -1653px; }
73
+ .emoticon-emo { background-position: 0 -1682px; }
74
+ .emoticon-yes { background-position: 0 -1711px; }
75
+ .emoticon-no { background-position: 0 -1740px; }
76
+ .emoticon-handshake { background-position: 0 -1769px; }
77
+ .emoticon-skype { background-position: 0 -1798px; }
78
+ .emoticon-heart { background-position: 0 -1827px; }
79
+ .emoticon-broken-heart { background-position: 0 -1856px; }
80
+ .emoticon-mail { background-position: 0 -1885px; }
81
+ .emoticon-flower { background-position: 0 -1914px; }
82
+ .emoticon-rain { background-position: 0 -1943px; }
83
+ .emoticon-sun { background-position: 0 -1972px; }
84
+ .emoticon-time { background-position: -29px 0; }
85
+ .emoticon-music { background-position: -29px -29px; }
86
+ .emoticon-movie { background-position: -29px -58px; }
87
+ .emoticon-phone { background-position: -29px -87px; }
88
+ .emoticon-coffee { background-position: -29px -116px; }
89
+ .emoticon-pizza { background-position: -29px -145px; }
90
+ .emoticon-cash { background-position: -29px -174px; }
91
+ .emoticon-muscle { background-position: -29px -203px; }
92
+ .emoticon-cake { background-position: -29px -232px; }
93
+ .emoticon-beer { background-position: -29px -261px; }
94
+ .emoticon-drink { background-position: -29px -290px; }
95
+ .emoticon-dance { background-position: -29px -319px; }
96
+ .emoticon-ninja { background-position: -29px -348px; }
97
+ .emoticon-star { background-position: -29px -377px; }
98
+ .emoticon-mooning { background-position: -29px -406px; }
99
+ .emoticon-middlefinger { background-position: -29px -435px; }
100
+ .emoticon-bandit { background-position: -29px -464px; }
101
+ .emoticon-drunk { background-position: -29px -493px; }
102
+ .emoticon-smoke { background-position: -29px -522px; }
103
+ .emoticon-toivo { background-position: -29px -551px; }
104
+ .emoticon-rock { background-position: -29px -580px; }
105
+ .emoticon-headbang { background-position: -29px -609px; }
106
+ .emoticon-bug { background-position: -29px -638px; }
107
+ .emoticon-fubar { background-position: -29px -666px; }
108
+ .emoticon-poolparty { background-position: -29px -695px; }
109
+ .emoticon-swear { background-position: -29px -724px; }
110
+ .emoticon-tmi { background-position: -29px -753px; }
111
+ .emoticon-heidy { background-position: -29px -782px; }
112
+ .emoticon-myspace { background-position: -29px -811px; }
113
+ .emoticon-malthe { background-position: -29px -840px; }
114
+ .emoticon-tauri { background-position: -29px -869px; }
115
+ .emoticon-priidu { background-position: -29px -898px; }
@@ -0,0 +1,27 @@
1
+ module RailsChat
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ def self.source_root
5
+ File.dirname(__FILE__) + "/templates"
6
+ end
7
+
8
+ def copy_files
9
+ template "rails_chat.yml", "config/rails_chat.yml"
10
+ if ::Rails.version < "3.1"
11
+ copy_file "../../../../app/assets/javascripts/rails_chat.js", "public/javascripts/rails_chat.js"
12
+ copy_file "../../../../app/assets/javascripts/emoticons_defination.js", "public/javascripts/emoticons_defination.js"
13
+ copy_file "../../../../app/assets/javascripts/emoticons.js", "public/javascripts/emoticons.js"
14
+ copy_file "../../../../app/assets/stylesheets/emoticons.css", "public/stylesheets/emoticons.css"
15
+ copy_file "../../../../app/assets/images/emoticons.png", "public/images/emoticons.png"
16
+ else
17
+ copy_file "../../../../app/assets/javascripts/rails_chat.js", "app/assets/javascripts/rails_chat.js"
18
+ copy_file "../../../../app/assets/javascripts/emoticons_defination.js", "app/assets/javascripts/emoticons_defination.js"
19
+ copy_file "../../../../app/assets/javascripts/emoticons.js", "app/assets/javascripts/emoticons.js"
20
+ copy_file "../../../../app/assets/stylesheets/emoticons.css", "app/assets/stylesheets/emoticons.css"
21
+ copy_file "../../../../app/assets/images/emoticons.png", "app/assets/images/emoticons.png"
22
+ end
23
+ copy_file "rails_chat.ru", "rails_chat.ru"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ # Run with: rackup rails_chat.ru -s thin -E production
2
+ require "bundler/setup"
3
+ require "yaml"
4
+ require "faye"
5
+ require "rails_chat"
6
+
7
+ Faye::WebSocket.load_adapter('thin')
8
+
9
+ RailsChat.load_config(File.expand_path("../config/rails_chat.yml", __FILE__), ENV["RAILS_ENV"] || "development")
10
+ run RailsChat.faye_app
@@ -0,0 +1,10 @@
1
+ development:
2
+ server: "http://localhost:9292/faye"
3
+ secret_token: "secret"
4
+ test:
5
+ server: "http://localhost:9292/faye"
6
+ secret_token: "secret"
7
+ production:
8
+ server: "http://example.com/faye"
9
+ secret_token: "<%= defined?(SecureRandom) ? SecureRandom.hex(32) : ActiveSupport::SecureRandom.hex(32) %>"
10
+ signature_expiration: 3600 # one hour
@@ -0,0 +1,16 @@
1
+ require "rails_chat/view_helpers"
2
+
3
+ module RailsChat
4
+ class Engine < Rails::Engine
5
+ # Loads the rails_chat.yml file if it exists.
6
+ initializer "rails_chat.config" do
7
+ path = Rails.root.join("config/rails_chat.yml")
8
+ RailsChat.load_config(path, Rails.env) if path.exist?
9
+ end
10
+
11
+ # Adds the ViewHelpers into ActionView::Base
12
+ initializer "rails_chat.view_helpers" do
13
+ ActionView::Base.send :include, ViewHelpers
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ module RailsChat
2
+ # This class is an extension for the Faye::RackAdapter.
3
+ # It is used inside of RailsChat.faye_app.
4
+ class FayeExtension
5
+ # Callback to handle incoming Faye messages. This authenticates both
6
+ # subscribe and publish calls.
7
+ def incoming(message, callback)
8
+ if message["channel"] == "/meta/subscribe"
9
+ authenticate_subscribe(message)
10
+ elsif message["channel"] !~ %r{^/meta/}
11
+ authenticate_publish(message)
12
+ end
13
+ callback.call(message)
14
+ end
15
+
16
+ private
17
+
18
+ # Ensure the subscription signature is correct and that it has not expired.
19
+ def authenticate_subscribe(message)
20
+ subscription = RailsChat.subscription(:channel => message["subscription"], :timestamp => message["ext"]["rails_chat_timestamp"])
21
+ if message["ext"]["rails_chat_signature"] != subscription[:signature]
22
+ message["error"] = "Incorrect signature."
23
+ elsif RailsChat.signature_expired? message["ext"]["rails_chat_timestamp"].to_i
24
+ message["error"] = "Signature has expired."
25
+ end
26
+ end
27
+
28
+ # Ensures the secret token is correct before publishing.
29
+ def authenticate_publish(message)
30
+ if RailsChat.config[:secret_token].nil?
31
+ raise Error, "No secret_token config set, ensure rails_chat.yml is loaded properly."
32
+ elsif message["ext"]["rails_chat_token"] != RailsChat.config[:secret_token]
33
+ message["error"] = "Incorrect token."
34
+ else
35
+ message["ext"]["rails_chat_token"] = nil
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ module RailsChat
2
+ module ViewHelpers
3
+ # Publish the given data or block to the client by sending
4
+ # a Net::HTTP POST request to the Faye server. If a block
5
+ # or string is passed in, it is evaluated as JavaScript
6
+ # on the client. Otherwise it will be converted to JSON
7
+ # for use in a JavaScript callback.
8
+ def publish_to(channel, data = nil, &block)
9
+ RailsChat.publish_to(channel, data || capture(&block))
10
+ end
11
+
12
+ # Subscribe the client to the given channel. This generates
13
+ # some JavaScript calling RailsChat.sign with the subscription
14
+ # options.
15
+ def subscribe_to(channel)
16
+ subscription = RailsChat.subscription(:channel => channel)
17
+ content_tag "script", :type => "text/javascript" do
18
+ raw("RailsChat.sign(#{subscription.to_json});")
19
+ end
20
+ end
21
+ end
22
+ end
data/lib/rails_chat.rb ADDED
@@ -0,0 +1,78 @@
1
+ require "digest/sha1"
2
+ require "net/http"
3
+ require "net/https"
4
+
5
+ require "rails_chat/faye_extension"
6
+ require "rails_chat/engine" if defined? Rails
7
+
8
+ module RailsChat
9
+ class Error < StandardError; end
10
+
11
+ class << self
12
+ attr_reader :config
13
+
14
+ # Resets the configuration to the default (empty hash)
15
+ def reset_config
16
+ @config = {}
17
+ end
18
+
19
+ # Loads the configuration from a given YAML file and environment (such as production)
20
+ def load_config(filename, environment)
21
+ yaml = YAML.load_file(filename)[environment.to_s]
22
+ raise ArgumentError, "The #{environment} environment does not exist in #{filename}" if yaml.nil?
23
+ yaml.each { |k, v| config[k.to_sym] = v }
24
+ end
25
+
26
+ # Publish the given data to a specific channel. This ends up sending
27
+ # a Net::HTTP POST request to the Faye server.
28
+ def publish_to(channel, data)
29
+ publish_message(message(channel, data))
30
+ end
31
+
32
+ # Sends the given message hash to the Faye server using Net::HTTP.
33
+ def publish_message(message)
34
+ raise Error, "No server specified, ensure rails_chat.yml was loaded properly." unless config[:server]
35
+ url = URI.parse(config[:server])
36
+
37
+ form = Net::HTTP::Post.new(url.path.empty? ? '/' : url.path)
38
+ form.set_form_data(:message => message.to_json)
39
+
40
+ http = Net::HTTP.new(url.host, url.port)
41
+ http.use_ssl = url.scheme == "https"
42
+ http.start {|h| h.request(form)}
43
+ end
44
+
45
+ # Returns a message hash for sending to Faye
46
+ def message(channel, data)
47
+ message = {:channel => channel, :data => {:channel => channel}, :ext => {:rails_chat_token => config[:secret_token]}}
48
+ if data.kind_of? String
49
+ message[:data][:eval] = data
50
+ else
51
+ message[:data][:data] = data
52
+ end
53
+ message
54
+ end
55
+
56
+ # Returns a subscription hash to pass to the RailsChat.sign call in JavaScript.
57
+ # Any options passed are merged to the hash.
58
+ def subscription(options = {})
59
+ sub = {:server => config[:server], :timestamp => (Time.now.to_f * 1000).round}.merge(options)
60
+ sub[:signature] = Digest::SHA1.hexdigest([config[:secret_token], sub[:channel], sub[:timestamp]].join)
61
+ sub
62
+ end
63
+
64
+ # Determine if the signature has expired given a timestamp.
65
+ def signature_expired?(timestamp)
66
+ timestamp < ((Time.now.to_f - config[:signature_expiration])*1000).round if config[:signature_expiration]
67
+ end
68
+
69
+ # Returns the Faye Rack application.
70
+ # Any options given are passed to the Faye::RackAdapter.
71
+ def faye_app(options = {})
72
+ options = {:mount => "/faye", :timeout => 45, :extensions => [FayeExtension.new]}.merge(options)
73
+ Faye::RackAdapter.new(options)
74
+ end
75
+ end
76
+
77
+ reset_config
78
+ end
@@ -0,0 +1,9 @@
1
+ development:
2
+ server: http://dev.local:9292/faye
3
+ secret_token: DEVELOPMENT_SECRET_TOKEN
4
+ signature_expiration: 600
5
+ production:
6
+ server: http://example.com/faye
7
+ secret_token: PRODUCTION_SECRET_TOKEN
8
+ signature_expiration: 600
9
+ #write down your secret token and url here
@@ -0,0 +1,108 @@
1
+ describe("RailsChat", function() {
2
+ var pub, doc;
3
+ beforeEach(function() {
4
+ Faye = {}; // To simulate global Faye object
5
+ doc = {};
6
+ pub = buildRailsChat(doc);
7
+ });
8
+
9
+ it("adds a subscription callback", function() {
10
+ pub.subscribe("hello", "callback");
11
+ expect(pub.subscriptionCallbacks["hello"]).toEqual("callback");
12
+ });
13
+
14
+ it("has a fayeExtension which adds matching subscription signature and timestamp to outgoing message", function() {
15
+ var called = false;
16
+ var message = {channel: "/meta/subscribe", subscription: "hello"}
17
+ pub.subscriptions["hello"] = {signature: "abcd", timestamp: "1234"}
18
+ pub.fayeExtension.outgoing(message, function(message) {
19
+ expect(message.ext.rails_chat_signature).toEqual("abcd");
20
+ expect(message.ext.rails_chat_timestamp).toEqual("1234");
21
+ called = true;
22
+ });
23
+ expect(called).toBeTruthy();
24
+ });
25
+
26
+ it("evaluates javascript in message response", function() {
27
+ pub.handleResponse({eval: 'self.subscriptions.foo = "bar"'});
28
+ expect(pub.subscriptions.foo).toEqual("bar");
29
+ });
30
+
31
+ it("triggers callback matching message channel in response", function() {
32
+ var called = false;
33
+ pub.subscribe("test", function(data, channel) {
34
+ expect(data).toEqual("abcd");
35
+ expect(channel).toEqual("test");
36
+ called = true;
37
+ });
38
+ pub.handleResponse({channel: "test", data: "abcd"});
39
+ expect(called).toBeTruthy();
40
+ });
41
+
42
+ it("adds a faye subscription with response handler when signing", function() {
43
+ var faye = {subscribe: jasmine.createSpy()};
44
+ spyOn(pub, 'faye').andCallFake(function(callback) {
45
+ callback(faye);
46
+ });
47
+ var options = {server: "server", channel: "somechannel"};
48
+ pub.sign(options);
49
+ expect(faye.subscribe).toHaveBeenCalledWith("somechannel", pub.handleResponse);
50
+ expect(pub.subscriptions.server).toEqual("server");
51
+ expect(pub.subscriptions.somechannel).toEqual(options);
52
+ });
53
+
54
+ it("adds a faye subscription with response handler when signing", function() {
55
+ var faye = {subscribe: jasmine.createSpy()};
56
+ spyOn(pub, 'faye').andCallFake(function(callback) {
57
+ callback(faye);
58
+ });
59
+ var options = {server: "server", channel: "somechannel"};
60
+ pub.sign(options);
61
+ expect(faye.subscribe).toHaveBeenCalledWith("somechannel", pub.handleResponse);
62
+ expect(pub.subscriptions.server).toEqual("server");
63
+ expect(pub.subscriptions.somechannel).toEqual(options);
64
+ });
65
+
66
+ it("triggers faye callback function immediately when fayeClient is available", function() {
67
+ var called = false;
68
+ pub.fayeClient = "faye";
69
+ pub.faye(function(faye) {
70
+ expect(faye).toEqual("faye");
71
+ called = true;
72
+ });
73
+ expect(called).toBeTruthy();
74
+ });
75
+
76
+ it("adds fayeCallback when client and server aren't available", function() {
77
+ pub.faye("callback");
78
+ expect(pub.fayeCallbacks[0]).toEqual("callback");
79
+ });
80
+
81
+ it("adds a script tag loading faye js when the server is present", function() {
82
+ script = {};
83
+ doc.createElement = function() { return script; };
84
+ doc.documentElement = {appendChild: jasmine.createSpy()};
85
+ pub.subscriptions.server = "path/to/faye";
86
+ pub.faye("callback");
87
+ expect(pub.fayeCallbacks[0]).toEqual("callback");
88
+ expect(script.type).toEqual("text/javascript");
89
+ expect(script.src).toEqual("path/to/faye.js");
90
+ expect(script.onload).toEqual(pub.connectToFaye);
91
+ expect(doc.documentElement.appendChild).toHaveBeenCalledWith(script);
92
+ });
93
+
94
+ it("connects to faye server, adds extension, and executes callbacks", function() {
95
+ callback = jasmine.createSpy();
96
+ client = {addExtension: jasmine.createSpy()};
97
+ Faye.Client = function(server) {
98
+ expect(server).toEqual("server")
99
+ return client;
100
+ };
101
+ pub.subscriptions.server = "server";
102
+ pub.fayeCallbacks.push(callback);
103
+ pub.connectToFaye();
104
+ expect(pub.fayeClient).toEqual(client);
105
+ expect(client.addExtension).toHaveBeenCalledWith(pub.fayeExtension);
106
+ expect(callback).toHaveBeenCalledWith(client);
107
+ });
108
+ });
@@ -0,0 +1,73 @@
1
+ # src_files
2
+ #
3
+ # Return an array of filepaths relative to src_dir to include before jasmine specs.
4
+ # Default: []
5
+ #
6
+ # EXAMPLE:
7
+ #
8
+ # src_files:
9
+ # - lib/source1.js
10
+ # - lib/source2.js
11
+ # - dist/**/*.js
12
+ #
13
+ src_files:
14
+ - app/assets/javascripts/rails_chat.js
15
+
16
+ # stylesheets
17
+ #
18
+ # Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs.
19
+ # Default: []
20
+ #
21
+ # EXAMPLE:
22
+ #
23
+ # stylesheets:
24
+ # - css/style.css
25
+ # - stylesheets/*.css
26
+ #
27
+ stylesheets:
28
+
29
+ # helpers
30
+ #
31
+ # Return an array of filepaths relative to spec_dir to include before jasmine specs.
32
+ # Default: ["helpers/**/*.js"]
33
+ #
34
+ # EXAMPLE:
35
+ #
36
+ # helpers:
37
+ # - helpers/**/*.js
38
+ #
39
+ helpers:
40
+
41
+ # spec_files
42
+ #
43
+ # Return an array of filepaths relative to spec_dir to include.
44
+ # Default: ["**/*[sS]pec.js"]
45
+ #
46
+ # EXAMPLE:
47
+ #
48
+ # spec_files:
49
+ # - **/*[sS]pec.js
50
+ #
51
+ spec_files:
52
+
53
+ # src_dir
54
+ #
55
+ # Source directory path. Your src_files must be returned relative to this path. Will use root if left blank.
56
+ # Default: project root
57
+ #
58
+ # EXAMPLE:
59
+ #
60
+ # src_dir: public
61
+ #
62
+ src_dir:
63
+
64
+ # spec_dir
65
+ #
66
+ # Spec directory path. Your spec_files must be returned relative to this path.
67
+ # Default: spec/javascripts
68
+ #
69
+ # EXAMPLE:
70
+ #
71
+ # spec_dir: spec/javascripts
72
+ #
73
+ spec_dir:
@@ -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