mirror of
https://github.com/discourse/discourse.git
synced 2026-08-13 06:25:11 -05:00
remove trailing whitespaces ❤️
This commit is contained in:
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
require "rspec/core/rake_task"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
RSpec::Core::RakeTask.new(:test) do |spec|
|
||||
spec.pattern = 'spec/*_spec.rb'
|
||||
|
||||
@@ -7,7 +7,7 @@ module DiscourseEmoji
|
||||
|
||||
initializer "discourse_emoji.configure_rails_initialization" do |app|
|
||||
|
||||
app.config.after_initialize do
|
||||
app.config.after_initialize do
|
||||
DiscoursePluginRegistry.setup(DiscourseEmoji::Plugin)
|
||||
Post.white_listed_image_classes << "emoji"
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@ require 'discourse_plugin'
|
||||
module DiscourseEmoji
|
||||
|
||||
class Plugin < DiscoursePlugin
|
||||
|
||||
|
||||
def setup
|
||||
# Add our Assets
|
||||
register_js('discourse_emoji',
|
||||
register_js('discourse_emoji',
|
||||
server_side: File.expand_path('../../../vendor/assets/javascripts/discourse_emoji.js', __FILE__))
|
||||
register_css('discourse_emoji')
|
||||
end
|
||||
|
||||
+4
-4
@@ -9,15 +9,15 @@ describe DiscourseEmoji::Plugin do
|
||||
|
||||
context '.setup' do
|
||||
|
||||
it 'registers its js' do
|
||||
it 'registers its js' do
|
||||
plugin.expects(:register_js).with('discourse_emoji', any_parameters)
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
it 'registers its css' do
|
||||
it 'registers its css' do
|
||||
plugin.expects(:register_css).with('discourse_emoji')
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ RSpec.configure do |config|
|
||||
|
||||
config.mock_framework = :mocha
|
||||
config.color_enabled = true
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
style = ""
|
||||
if (opts && opts.environment === "email") {
|
||||
// Hard code sizes for email view
|
||||
style = 'width="20" height="20"';
|
||||
style = 'width="20" height="20"';
|
||||
}
|
||||
|
||||
|
||||
this.textResult = text.replace(/\:([a-z\_\+\-0-9]+)\:/g, function (m1, m2) {
|
||||
return (emoji.indexOf(m2) !== -1) ?
|
||||
'<img alt="' + m2 + '" title=":' + m2 + ':" src="/assets/emoji/' + m2 + '.png" ' + style + ' class="emoji"/>' :
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
if (Discourse && Discourse.ComposerView) {
|
||||
Discourse.ComposerView.on("initWmdEditor", function(event){
|
||||
|
||||
|
||||
template = Handlebars.compile("<div class='autocomplete'>" +
|
||||
"<ul>" +
|
||||
"{{#each options}}" +
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
$('#wmd-input').autocomplete({
|
||||
template: template,
|
||||
key: ":",
|
||||
key: ":",
|
||||
transformComplete: function(v){ return v + ":"; },
|
||||
dataSource: function(term, callback){
|
||||
|
||||
@@ -50,14 +50,14 @@
|
||||
}
|
||||
|
||||
var options = []
|
||||
var i;
|
||||
var i;
|
||||
for (i=0; i < emoji.length; i++) {
|
||||
if (emoji[i].indexOf(term) == 0) {
|
||||
options.push(emoji[i]);
|
||||
if(options.length > 4) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (options.length <= 4) {
|
||||
for (i=0; i < emoji.length; i++) {
|
||||
if (emoji[i].indexOf(term) > 0) {
|
||||
@@ -66,7 +66,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
callback(options)
|
||||
}
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
require "rspec/core/rake_task"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
RSpec::Core::RakeTask.new(:test) do |spec|
|
||||
spec.pattern = 'spec/*_spec.rb'
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ RSpec.configure do |config|
|
||||
|
||||
config.mock_framework = :mocha
|
||||
config.color_enabled = true
|
||||
|
||||
|
||||
config.before(:each) do
|
||||
DiscourseEvent.clear
|
||||
end
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
require "rspec/core/rake_task"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
RSpec::Core::RakeTask.new(:test) do |spec|
|
||||
spec.pattern = 'spec/*_spec.rb'
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ module DiscoursePoll
|
||||
|
||||
initializer "discourse_poll.configure_rails_initialization" do |app|
|
||||
|
||||
app.config.after_initialize do
|
||||
app.config.after_initialize do
|
||||
DiscoursePluginRegistry.setup(DiscoursePoll::Plugin)
|
||||
end
|
||||
|
||||
@@ -18,4 +18,4 @@ module DiscoursePoll
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,12 +36,12 @@ en:
|
||||
long_form: 'voted for this post'
|
||||
|
||||
archetypes:
|
||||
poll:
|
||||
poll:
|
||||
title: "Poll Topic"
|
||||
options:
|
||||
single_vote:
|
||||
single_vote:
|
||||
title: "Only allow one vote"
|
||||
description: "A user may only vote on one post."
|
||||
private_poll:
|
||||
private_poll:
|
||||
title: "Voting is Private"
|
||||
description: "Hide who voted for what choice."
|
||||
description: "Hide who voted for what choice."
|
||||
|
||||
+5
-5
@@ -5,9 +5,9 @@ module DiscoursePoll
|
||||
|
||||
MAX_SORT_ORDER = 2147483647
|
||||
POLL_OPTIONS = {private_poll: 1, single_vote: 1}
|
||||
|
||||
|
||||
def setup
|
||||
|
||||
|
||||
# Add our Assets
|
||||
register_js('discourse_poll')
|
||||
register_css('discourse_poll')
|
||||
@@ -26,15 +26,15 @@ module DiscoursePoll
|
||||
post.sort_order = 1
|
||||
else
|
||||
post.sort_order = DiscoursePoll::Plugin::MAX_SORT_ORDER
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module TopicViewSerializerMixin
|
||||
|
||||
def self.included(base)
|
||||
base.attributes :private_poll, :single_vote
|
||||
base.attributes :private_poll, :single_vote
|
||||
end
|
||||
|
||||
|
||||
def private_poll
|
||||
object.topic.has_meta_data_boolean?(:private_poll)
|
||||
end
|
||||
|
||||
+8
-8
@@ -9,22 +9,22 @@ describe DiscoursePoll::Plugin do
|
||||
|
||||
context '.setup' do
|
||||
|
||||
it 'registers its js' do
|
||||
it 'registers its js' do
|
||||
plugin.expects(:register_js)
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
it 'registers its css' do
|
||||
it 'registers its css' do
|
||||
plugin.expects(:register_css)
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
it 'registers a poll archetype' do
|
||||
it 'registers a poll archetype' do
|
||||
plugin.expects(:register_archetype).with('poll', DiscoursePoll::Plugin::POLL_OPTIONS)
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
it 'registers a handler on post_create' do
|
||||
it 'registers a handler on post_create' do
|
||||
plugin.expects(:listen_for).with(:before_create_post)
|
||||
plugin.setup
|
||||
end
|
||||
@@ -38,7 +38,7 @@ describe DiscoursePoll::Plugin do
|
||||
|
||||
it "doesn't set the sort order" do
|
||||
plugin.before_create_post(post)
|
||||
post.sort_order.should_not == DiscoursePoll::Plugin::MAX_SORT_ORDER
|
||||
post.sort_order.should_not == DiscoursePoll::Plugin::MAX_SORT_ORDER
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ RSpec.configure do |config|
|
||||
|
||||
config.mock_framework = :mocha
|
||||
config.color_enabled = true
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
(function() {
|
||||
window.Discourse.Post.reopen({
|
||||
|
||||
voteAction: function () {
|
||||
voteAction: function () {
|
||||
return this.get('actionByName.vote');
|
||||
}.property('actionByName.vote'),
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
}.property('replyBelowUrlComputed', 'topic.archetype'),
|
||||
|
||||
// Vote for this post
|
||||
vote: function() {
|
||||
vote: function() {
|
||||
voteType = Discourse.get('site.post_action_types').findProperty('name_key', 'vote');
|
||||
this.get('voteAction').act();
|
||||
Em.run.next(function () {
|
||||
this.set('topic.voted_in_topic', true);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
this.get('voteAction').undo();
|
||||
Em.run.next(function () {
|
||||
this.set('topic.voted_in_topic', false);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1,9 +1,9 @@
|
||||
(function() {
|
||||
Discourse.PostActionType.reopen({
|
||||
|
||||
|
||||
isVote: function() {
|
||||
return (this.get('name_key') === 'vote');
|
||||
}.property('name_key')
|
||||
|
||||
});
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
(function() {
|
||||
window.Discourse.PostView.reopen({
|
||||
|
||||
|
||||
extraClass: function() {
|
||||
if (this.get('showVotes')) return 'votes';
|
||||
return null;
|
||||
}.property('showVotes'),
|
||||
|
||||
showVotes: function() {
|
||||
var post = this.get('post');
|
||||
var post = this.get('post');
|
||||
if (post.get('post_number') === 1) return;
|
||||
if (post.get('post_type') !== Discourse.Post.REGULAR_TYPE) return;
|
||||
if (post.get('reply_to_post_number')) return;
|
||||
@@ -15,4 +15,4 @@
|
||||
}.property('post.post_number', 'post.post_type', 'post.reply_to_post_number')
|
||||
|
||||
})
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
Vendored
+3
-3
@@ -4,9 +4,9 @@
|
||||
|
||||
// Append our template for the poll controls
|
||||
if (this.get('controller.content.archetype') == 'poll') {
|
||||
this.get('childViews').pushObject(Discourse.VoteControlsView.create());
|
||||
this.get('childViews').pushObject(Discourse.VoteControlsView.create());
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
+1
-1
@@ -6,4 +6,4 @@
|
||||
}.property()
|
||||
|
||||
});
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
Vendored
+1
-1
@@ -11,4 +11,4 @@
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
Vendored
+2
-2
@@ -6,7 +6,7 @@
|
||||
if (this.get('topic.archetype') === 'poll') {
|
||||
this.renderIcon(buffer, 'check-empty', 'poll');
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
Vendored
+1
-1
@@ -38,4 +38,4 @@
|
||||
}.property('post.voteAction.can_act')
|
||||
|
||||
})
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
require "rspec/core/rake_task"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
RSpec::Core::RakeTask.new(:test) do |spec|
|
||||
spec.pattern = 'spec/*_spec.rb'
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
Rails.application.routes.draw do
|
||||
|
||||
Rails.application.routes.draw do
|
||||
|
||||
put 't/:slug/:topic_id/complete' => 'topics#complete', :constraints => {:topic_id => /\d+/}
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ module DiscourseTask
|
||||
|
||||
initializer "discourse_task.configure_rails_initialization" do |app|
|
||||
|
||||
app.config.after_initialize do
|
||||
app.config.after_initialize do
|
||||
DiscoursePluginRegistry.setup(DiscourseTask::Plugin)
|
||||
end
|
||||
|
||||
@@ -17,4 +17,4 @@ module DiscourseTask
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ module DiscourseTask
|
||||
|
||||
module TopicViewSerializerMixin
|
||||
def self.included(base)
|
||||
base.attributes :can_complete_task, :complete, :completed_at
|
||||
base.attributes :can_complete_task, :complete, :completed_at
|
||||
end
|
||||
|
||||
def can_complete_task
|
||||
@@ -73,7 +73,7 @@ module DiscourseTask
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
render nothing: true
|
||||
end
|
||||
|
||||
|
||||
+6
-6
@@ -8,20 +8,20 @@ describe DiscourseTask::Plugin do
|
||||
|
||||
context '.setup' do
|
||||
|
||||
it 'registers its js' do
|
||||
it 'registers its js' do
|
||||
plugin.expects(:register_js).with('discourse_task')
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
it 'registers its css' do
|
||||
it 'registers its css' do
|
||||
plugin.expects(:register_css).with('discourse_task')
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
it 'registers a task archetype' do
|
||||
it 'registers a task archetype' do
|
||||
plugin.expects(:register_archetype).with('task')
|
||||
plugin.setup
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ RSpec.configure do |config|
|
||||
|
||||
config.mock_framework = :mocha
|
||||
config.color_enabled = true
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
|
||||
|
||||
Discourse.TopicController.reopen({
|
||||
|
||||
// Allow the user to complete the task
|
||||
@@ -10,6 +10,6 @@
|
||||
|
||||
})
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
|
||||
|
||||
Discourse.Topic.reopen({
|
||||
|
||||
// Allow the user to complete the task
|
||||
@@ -10,14 +10,14 @@
|
||||
jQuery.ajax(this.get('url') + "/complete", {
|
||||
type: 'PUT',
|
||||
data: {
|
||||
complete: this.get('complete') ? 'true' : 'false'
|
||||
complete: this.get('complete') ? 'true' : 'false'
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
|
||||
|
||||
Discourse.TopicFooterButtonsView.prototype.on("additionalButtons", function(childViews) {
|
||||
var topic = this.get('topic');
|
||||
if (topic.get('archetype') == 'task' && topic.get('can_complete_task')) {
|
||||
@@ -15,16 +15,16 @@
|
||||
|
||||
renderIcon: function (buffer) {
|
||||
if (!this.get('complete')) {
|
||||
buffer.push("<i class='icon-cog'></i>")
|
||||
}
|
||||
},
|
||||
buffer.push("<i class='icon-cog'></i>")
|
||||
}
|
||||
},
|
||||
|
||||
text: function () {
|
||||
if (this.get('complete')) {
|
||||
return Em.String.i18n("task.reverse");
|
||||
return Em.String.i18n("task.reverse");
|
||||
} else {
|
||||
return Em.String.i18n("task.complete_action");
|
||||
}
|
||||
}
|
||||
}.property('complete'),
|
||||
|
||||
click: function(e) {
|
||||
@@ -35,6 +35,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -9,7 +9,7 @@
|
||||
if (topic.get('complete')) icon = 'ok';
|
||||
this.renderIcon(buffer, icon, 'task');
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
Discourse.TopicStatusView.reopen({
|
||||
@@ -18,4 +18,4 @@
|
||||
}.observes('topic.complete')
|
||||
})
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
Vendored
+1
-1
@@ -11,4 +11,4 @@
|
||||
}
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
}).call(this);
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ App.IndexModel = Ember.Object.extend({
|
||||
processes = processes.sort(function(a,b){
|
||||
return a.get('uniqueId') < b.get('uniqueId') ? -1 : 1;
|
||||
});
|
||||
// somewhat odd ...
|
||||
// somewhat odd ...
|
||||
_this.set('processes', null);
|
||||
_this.set('processes', processes);
|
||||
});
|
||||
@@ -55,7 +55,7 @@ App.IndexModel = Ember.Object.extend({
|
||||
discover: function(){
|
||||
var _this = this;
|
||||
this.set('processes', Em.A());
|
||||
|
||||
|
||||
this.ensureSubscribed();
|
||||
|
||||
this.set("discovering", true);
|
||||
|
||||
+43
-43
@@ -1752,7 +1752,7 @@ var MapWithDefault = Ember.MapWithDefault = function(options) {
|
||||
@static
|
||||
@param [options]
|
||||
@param {anything} [options.defaultValue]
|
||||
@return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
|
||||
@return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
|
||||
`Ember.MapWithDefault` otherwise returns `Ember.Map`
|
||||
*/
|
||||
MapWithDefault.create = function(options) {
|
||||
@@ -1826,7 +1826,7 @@ var FIRST_KEY = /^([^\.\*]+)/;
|
||||
|
||||
If you plan to run on IE8 and older browsers then you should use this
|
||||
method anytime you want to retrieve a property on an object that you don't
|
||||
know for sure is private. (Properties beginning with an underscore '_'
|
||||
know for sure is private. (Properties beginning with an underscore '_'
|
||||
are considered private.)
|
||||
|
||||
On all newer browsers, you only need to use this method to retrieve
|
||||
@@ -1888,7 +1888,7 @@ get = function get(obj, keyName) {
|
||||
|
||||
If you plan to run on IE8 and older browsers then you should use this
|
||||
method anytime you want to set a property on an object that you don't
|
||||
know for sure is private. (Properties beginning with an underscore '_'
|
||||
know for sure is private. (Properties beginning with an underscore '_'
|
||||
are considered private.)
|
||||
|
||||
On all newer browsers, you only need to use this method to set
|
||||
@@ -4227,7 +4227,7 @@ Ember.RunLoop = RunLoop;
|
||||
|
||||
```javascript
|
||||
Ember.run(function(){
|
||||
// code to be execute within a RunLoop
|
||||
// code to be execute within a RunLoop
|
||||
});
|
||||
```
|
||||
|
||||
@@ -4266,7 +4266,7 @@ var run = Ember.run;
|
||||
|
||||
```javascript
|
||||
Ember.run.begin();
|
||||
// code to be execute within a RunLoop
|
||||
// code to be execute within a RunLoop
|
||||
Ember.run.end();
|
||||
```
|
||||
|
||||
@@ -4284,7 +4284,7 @@ Ember.run.begin = function() {
|
||||
|
||||
```javascript
|
||||
Ember.run.begin();
|
||||
// code to be execute within a RunLoop
|
||||
// code to be execute within a RunLoop
|
||||
Ember.run.end();
|
||||
```
|
||||
|
||||
@@ -6935,7 +6935,7 @@ Ember.String = {
|
||||
'action_name'.classify(); // 'ActionName'
|
||||
'css-class-name'.classify(); // 'CssClassName'
|
||||
'my favorite items'.classify(); // 'MyFavoriteItems'
|
||||
```
|
||||
```
|
||||
|
||||
@method classify
|
||||
@param {String} str the string to classify
|
||||
@@ -7357,7 +7357,7 @@ Ember.Enumerable = Ember.Mixin.create(
|
||||
|
||||
@method nextObject
|
||||
@param {Number} index the current index of the iteration
|
||||
@param {Object} previousObject the value returned by the last call to
|
||||
@param {Object} previousObject the value returned by the last call to
|
||||
`nextObject`.
|
||||
@param {Object} context a context object you can use to maintain state.
|
||||
@return {Object} the next object in the iteration or undefined
|
||||
@@ -8422,9 +8422,9 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
|
||||
|
||||
@method arrayContentWillChange
|
||||
@param {Number} startIdx The starting index in the array that will change.
|
||||
@param {Number} removeAmt The number of items that will be removed. If you
|
||||
@param {Number} removeAmt The number of items that will be removed. If you
|
||||
pass `null` assumes 0
|
||||
@param {Number} addAmt The number of items that will be added If you
|
||||
@param {Number} addAmt The number of items that will be added If you
|
||||
pass `null` assumes 0.
|
||||
@return {Ember.Array} receiver
|
||||
*/
|
||||
@@ -8898,11 +8898,11 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
|
||||
passed array. You should also call `this.enumerableContentDidChange()`
|
||||
|
||||
@method replace
|
||||
@param {Number} idx Starting index in the array to replace. If
|
||||
@param {Number} idx Starting index in the array to replace. If
|
||||
idx >= length, then append to the end of the array.
|
||||
@param {Number} amt Number of elements that should be removed from
|
||||
@param {Number} amt Number of elements that should be removed from
|
||||
the array, starting at *idx*.
|
||||
@param {Array} objects An array of zero or more objects that should be
|
||||
@param {Array} objects An array of zero or more objects that should be
|
||||
inserted into the array at *idx*
|
||||
*/
|
||||
replace: Ember.required(),
|
||||
@@ -10157,14 +10157,14 @@ CoreObject.PrototypeMixin = Mixin.create({
|
||||
view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
|
||||
```
|
||||
Adding a single property that is not an array will just add it in the array:
|
||||
|
||||
|
||||
```javascript
|
||||
var view = App.FooBarView.create({
|
||||
classNames: 'baz'
|
||||
})
|
||||
view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
|
||||
```
|
||||
|
||||
|
||||
Using the `concatenatedProperties` property, we can tell to Ember that mix
|
||||
the content of the properties.
|
||||
|
||||
@@ -14249,7 +14249,7 @@ class:
|
||||
* `mouseEnter`
|
||||
* `mouseLeave`
|
||||
|
||||
Form events:
|
||||
Form events:
|
||||
|
||||
* `submit`
|
||||
* `change`
|
||||
@@ -14257,7 +14257,7 @@ class:
|
||||
* `focusOut`
|
||||
* `input`
|
||||
|
||||
HTML5 drag and drop events:
|
||||
HTML5 drag and drop events:
|
||||
|
||||
* `dragStart`
|
||||
* `drag`
|
||||
@@ -15794,14 +15794,14 @@ Ember.View.reopenClass({
|
||||
`className` and optional `falsyClassName`.
|
||||
|
||||
- if a `className` or `falsyClassName` has been specified:
|
||||
- if the value is truthy and `className` has been specified,
|
||||
- if the value is truthy and `className` has been specified,
|
||||
`className` is returned
|
||||
- if the value is falsy and `falsyClassName` has been specified,
|
||||
- if the value is falsy and `falsyClassName` has been specified,
|
||||
`falsyClassName` is returned
|
||||
- otherwise `null` is returned
|
||||
- if the value is `true`, the dasherized last part of the supplied path
|
||||
- if the value is `true`, the dasherized last part of the supplied path
|
||||
is returned
|
||||
- if the value is not `false`, `undefined` or `null`, the `value`
|
||||
- if the value is not `false`, `undefined` or `null`, the `value`
|
||||
is returned
|
||||
- if none of the above rules apply, `null` is returned
|
||||
|
||||
@@ -16651,7 +16651,7 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
|
||||
|
||||
Given an empty `<body>` and the following code:
|
||||
|
||||
```javascript
|
||||
```javascript
|
||||
someItemsView = Ember.CollectionView.create({
|
||||
classNames: ['a-collection'],
|
||||
content: ['A','B','C'],
|
||||
@@ -17823,7 +17823,7 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
|
||||
|
||||
## Example with bound options
|
||||
|
||||
Bound hash options are also supported. Example:
|
||||
Bound hash options are also supported. Example:
|
||||
|
||||
```handlebars
|
||||
{{repeat text countBinding="numRepeats"}}
|
||||
@@ -17861,15 +17861,15 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
|
||||
{{concatenate prop1 prop2 prop3}}. If any of the properties change,
|
||||
the helpr will re-render. Note that dependency keys cannot be
|
||||
using in conjunction with multi-property helpers, since it is ambiguous
|
||||
which property the dependent keys would belong to.
|
||||
|
||||
which property the dependent keys would belong to.
|
||||
|
||||
## Use with unbound helper
|
||||
|
||||
The {{unbound}} helper can be used with bound helper invocations
|
||||
The {{unbound}} helper can be used with bound helper invocations
|
||||
to render them in their unbound form, e.g.
|
||||
|
||||
```handlebars
|
||||
{{unbound capitalize name}}
|
||||
{{unbound capitalize name}}
|
||||
```
|
||||
|
||||
In this example, if the name property changes, the helper
|
||||
@@ -17895,7 +17895,7 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) {
|
||||
view = data.view,
|
||||
currentContext = (options.contexts && options.contexts[0]) || this,
|
||||
normalized,
|
||||
pathRoot, path,
|
||||
pathRoot, path,
|
||||
loc, hashOption;
|
||||
|
||||
// Detect bound options (e.g. countBinding="otherCount")
|
||||
@@ -18001,7 +18001,7 @@ function evaluateMultiPropertyBoundHelper(context, fn, normalizedProperties, opt
|
||||
// Assemble liast of watched properties that'll re-render this helper.
|
||||
watchedProperties = [];
|
||||
for (boundOption in boundOptions) {
|
||||
if (boundOptions.hasOwnProperty(boundOption)) {
|
||||
if (boundOptions.hasOwnProperty(boundOption)) {
|
||||
watchedProperties.push(normalizePath(context, boundOptions[boundOption], data));
|
||||
}
|
||||
}
|
||||
@@ -18936,14 +18936,14 @@ EmberHandlebars.registerHelper('unless', function(context, options) {
|
||||
|
||||
Result in the following rendered output:
|
||||
|
||||
```html
|
||||
```html
|
||||
<img class="aValue">
|
||||
```
|
||||
|
||||
A boolean return value will insert a specified class name if the property
|
||||
returns `true` and remove the class name if the property returns `false`.
|
||||
|
||||
A class name is provided via the syntax
|
||||
A class name is provided via the syntax
|
||||
`somePropertyName:class-name-if-true`.
|
||||
|
||||
```javascript
|
||||
@@ -19100,9 +19100,9 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
|
||||
@method bindClasses
|
||||
@for Ember.Handlebars
|
||||
@param {Ember.Object} context The context from which to lookup properties
|
||||
@param {String} classBindings A string, space-separated, of class bindings
|
||||
@param {String} classBindings A string, space-separated, of class bindings
|
||||
to use
|
||||
@param {Ember.View} view The view in which observers should look for the
|
||||
@param {Ember.View} view The view in which observers should look for the
|
||||
element to update
|
||||
@param {Srting} bindAttrId Optional bindAttr id used to lookup elements
|
||||
@return {Array} An array of class names to add
|
||||
@@ -19792,7 +19792,7 @@ Ember.Handlebars.registerHelper('unbound', function(property, fn) {
|
||||
// Unbound helper call.
|
||||
options.data.isUnbound = true;
|
||||
helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing;
|
||||
out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
delete options.data.isUnbound;
|
||||
return out;
|
||||
}
|
||||
@@ -20087,7 +20087,7 @@ GroupedEach.prototype = {
|
||||
|
||||
```handlebars
|
||||
{{#view App.MyView }}
|
||||
{{each view.items itemViewClass="App.AnItemView"}}
|
||||
{{each view.items itemViewClass="App.AnItemView"}}
|
||||
{{/view}}
|
||||
```
|
||||
|
||||
@@ -20118,7 +20118,7 @@ GroupedEach.prototype = {
|
||||
<div class="ember-view">Greetings Sara</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
### Representing each item with a Controller.
|
||||
By default the controller lookup within an `{{#each}}` block will be
|
||||
the controller of the template where the `{{#each}}` was used. If each
|
||||
@@ -20126,10 +20126,10 @@ GroupedEach.prototype = {
|
||||
`itemController` option which references a controller by lookup name.
|
||||
Each item in the loop will be wrapped in an instance of this controller
|
||||
and the item itself will be set to the `content` property of that controller.
|
||||
|
||||
|
||||
This is useful in cases where properties of model objects need transformation
|
||||
or synthesis for display:
|
||||
|
||||
|
||||
```javascript
|
||||
App.DeveloperController = Ember.ObjectController.extend({
|
||||
isAvailableForHire: function(){
|
||||
@@ -20137,13 +20137,13 @@ GroupedEach.prototype = {
|
||||
}.property('isEmployed', 'isSeekingWork')
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
```handlebars
|
||||
{{#each person in Developers itemController="developer"}}
|
||||
{{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
|
||||
{{/each}}
|
||||
```
|
||||
|
||||
|
||||
@method each
|
||||
@for Ember.Handlebars.helpers
|
||||
@param [name] {String} name for item (used with `in`)
|
||||
@@ -21082,7 +21082,7 @@ helpers = helpers || Ember.Handlebars.helpers; data = data || {};
|
||||
var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this;
|
||||
|
||||
function program1(depth0,data) {
|
||||
|
||||
|
||||
var buffer = '', hashTypes;
|
||||
data.buffer.push("<option value=\"\">");
|
||||
hashTypes = {};
|
||||
@@ -21092,7 +21092,7 @@ function program1(depth0,data) {
|
||||
}
|
||||
|
||||
function program3(depth0,data) {
|
||||
|
||||
|
||||
var hashTypes;
|
||||
hashTypes = {'contentBinding': "STRING"};
|
||||
data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{
|
||||
@@ -21107,7 +21107,7 @@ function program3(depth0,data) {
|
||||
stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data});
|
||||
if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
|
||||
return buffer;
|
||||
|
||||
|
||||
}),
|
||||
attributeBindings: ['multiple', 'disabled', 'tabindex'],
|
||||
|
||||
|
||||
+80
-80
@@ -184,99 +184,99 @@ performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
|
||||
|
||||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 1: return $$[$0-1];
|
||||
case 1: return $$[$0-1];
|
||||
break;
|
||||
case 2: this.$ = new yy.ProgramNode([], $$[$0]);
|
||||
case 2: this.$ = new yy.ProgramNode([], $$[$0]);
|
||||
break;
|
||||
case 3: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]);
|
||||
case 3: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]);
|
||||
break;
|
||||
case 4: this.$ = new yy.ProgramNode($$[$0-1], []);
|
||||
case 4: this.$ = new yy.ProgramNode($$[$0-1], []);
|
||||
break;
|
||||
case 5: this.$ = new yy.ProgramNode($$[$0]);
|
||||
case 5: this.$ = new yy.ProgramNode($$[$0]);
|
||||
break;
|
||||
case 6: this.$ = new yy.ProgramNode([], []);
|
||||
case 6: this.$ = new yy.ProgramNode([], []);
|
||||
break;
|
||||
case 7: this.$ = new yy.ProgramNode([]);
|
||||
case 7: this.$ = new yy.ProgramNode([]);
|
||||
break;
|
||||
case 8: this.$ = [$$[$0]];
|
||||
case 8: this.$ = [$$[$0]];
|
||||
break;
|
||||
case 9: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
||||
case 9: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
||||
break;
|
||||
case 10: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
|
||||
case 10: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]);
|
||||
break;
|
||||
case 11: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
|
||||
case 11: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]);
|
||||
break;
|
||||
case 12: this.$ = $$[$0];
|
||||
case 12: this.$ = $$[$0];
|
||||
break;
|
||||
case 13: this.$ = $$[$0];
|
||||
case 13: this.$ = $$[$0];
|
||||
break;
|
||||
case 14: this.$ = new yy.ContentNode($$[$0]);
|
||||
case 14: this.$ = new yy.ContentNode($$[$0]);
|
||||
break;
|
||||
case 15: this.$ = new yy.CommentNode($$[$0]);
|
||||
case 15: this.$ = new yy.CommentNode($$[$0]);
|
||||
break;
|
||||
case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
|
||||
case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
|
||||
break;
|
||||
case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
|
||||
case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
|
||||
break;
|
||||
case 18: this.$ = $$[$0-1];
|
||||
case 18: this.$ = $$[$0-1];
|
||||
break;
|
||||
case 19: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
|
||||
case 19: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]);
|
||||
break;
|
||||
case 20: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true);
|
||||
case 20: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true);
|
||||
break;
|
||||
case 21: this.$ = new yy.PartialNode($$[$0-1]);
|
||||
case 21: this.$ = new yy.PartialNode($$[$0-1]);
|
||||
break;
|
||||
case 22: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]);
|
||||
case 22: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]);
|
||||
break;
|
||||
case 23:
|
||||
case 23:
|
||||
break;
|
||||
case 24: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
|
||||
case 24: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]];
|
||||
break;
|
||||
case 25: this.$ = [[$$[$0-1]].concat($$[$0]), null];
|
||||
case 25: this.$ = [[$$[$0-1]].concat($$[$0]), null];
|
||||
break;
|
||||
case 26: this.$ = [[$$[$0-1]], $$[$0]];
|
||||
case 26: this.$ = [[$$[$0-1]], $$[$0]];
|
||||
break;
|
||||
case 27: this.$ = [[$$[$0]], null];
|
||||
case 27: this.$ = [[$$[$0]], null];
|
||||
break;
|
||||
case 28: this.$ = [[new yy.DataNode($$[$0])], null];
|
||||
case 28: this.$ = [[new yy.DataNode($$[$0])], null];
|
||||
break;
|
||||
case 29: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
||||
case 29: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
||||
break;
|
||||
case 30: this.$ = [$$[$0]];
|
||||
case 30: this.$ = [$$[$0]];
|
||||
break;
|
||||
case 31: this.$ = $$[$0];
|
||||
case 31: this.$ = $$[$0];
|
||||
break;
|
||||
case 32: this.$ = new yy.StringNode($$[$0]);
|
||||
case 32: this.$ = new yy.StringNode($$[$0]);
|
||||
break;
|
||||
case 33: this.$ = new yy.IntegerNode($$[$0]);
|
||||
case 33: this.$ = new yy.IntegerNode($$[$0]);
|
||||
break;
|
||||
case 34: this.$ = new yy.BooleanNode($$[$0]);
|
||||
case 34: this.$ = new yy.BooleanNode($$[$0]);
|
||||
break;
|
||||
case 35: this.$ = new yy.DataNode($$[$0]);
|
||||
case 35: this.$ = new yy.DataNode($$[$0]);
|
||||
break;
|
||||
case 36: this.$ = new yy.HashNode($$[$0]);
|
||||
case 36: this.$ = new yy.HashNode($$[$0]);
|
||||
break;
|
||||
case 37: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
||||
case 37: $$[$0-1].push($$[$0]); this.$ = $$[$0-1];
|
||||
break;
|
||||
case 38: this.$ = [$$[$0]];
|
||||
case 38: this.$ = [$$[$0]];
|
||||
break;
|
||||
case 39: this.$ = [$$[$0-2], $$[$0]];
|
||||
case 39: this.$ = [$$[$0-2], $$[$0]];
|
||||
break;
|
||||
case 40: this.$ = [$$[$0-2], new yy.StringNode($$[$0])];
|
||||
case 40: this.$ = [$$[$0-2], new yy.StringNode($$[$0])];
|
||||
break;
|
||||
case 41: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])];
|
||||
case 41: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])];
|
||||
break;
|
||||
case 42: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])];
|
||||
case 42: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])];
|
||||
break;
|
||||
case 43: this.$ = [$$[$0-2], new yy.DataNode($$[$0])];
|
||||
case 43: this.$ = [$$[$0-2], new yy.DataNode($$[$0])];
|
||||
break;
|
||||
case 44: this.$ = new yy.PartialNameNode($$[$0]);
|
||||
case 44: this.$ = new yy.PartialNameNode($$[$0]);
|
||||
break;
|
||||
case 45: this.$ = new yy.IdNode($$[$0]);
|
||||
case 45: this.$ = new yy.IdNode($$[$0]);
|
||||
break;
|
||||
case 46: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
|
||||
case 46: $$[$0-2].push($$[$0]); this.$ = $$[$0-2];
|
||||
break;
|
||||
case 47: this.$ = [$$[$0]];
|
||||
case 47: this.$ = [$$[$0]];
|
||||
break;
|
||||
}
|
||||
},
|
||||
@@ -566,75 +566,75 @@ case 0:
|
||||
if(yy_.yytext.slice(-1) !== "\\") this.begin("mu");
|
||||
if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
|
||||
if(yy_.yytext) return 14;
|
||||
|
||||
|
||||
break;
|
||||
case 1: return 14;
|
||||
case 1: return 14;
|
||||
break;
|
||||
case 2:
|
||||
if(yy_.yytext.slice(-1) !== "\\") this.popState();
|
||||
if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1);
|
||||
return 14;
|
||||
|
||||
|
||||
break;
|
||||
case 3: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15;
|
||||
case 3: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15;
|
||||
break;
|
||||
case 4: this.begin("par"); return 24;
|
||||
case 4: this.begin("par"); return 24;
|
||||
break;
|
||||
case 5: return 16;
|
||||
case 5: return 16;
|
||||
break;
|
||||
case 6: return 20;
|
||||
case 6: return 20;
|
||||
break;
|
||||
case 7: return 19;
|
||||
case 7: return 19;
|
||||
break;
|
||||
case 8: return 19;
|
||||
case 8: return 19;
|
||||
break;
|
||||
case 9: return 23;
|
||||
case 9: return 23;
|
||||
break;
|
||||
case 10: return 23;
|
||||
case 10: return 23;
|
||||
break;
|
||||
case 11: this.popState(); this.begin('com');
|
||||
case 11: this.popState(); this.begin('com');
|
||||
break;
|
||||
case 12: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
|
||||
case 12: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15;
|
||||
break;
|
||||
case 13: return 22;
|
||||
case 13: return 22;
|
||||
break;
|
||||
case 14: return 36;
|
||||
case 14: return 36;
|
||||
break;
|
||||
case 15: return 35;
|
||||
case 15: return 35;
|
||||
break;
|
||||
case 16: return 35;
|
||||
case 16: return 35;
|
||||
break;
|
||||
case 17: return 39;
|
||||
case 17: return 39;
|
||||
break;
|
||||
case 18: /*ignore whitespace*/
|
||||
case 18: /*ignore whitespace*/
|
||||
break;
|
||||
case 19: this.popState(); return 18;
|
||||
case 19: this.popState(); return 18;
|
||||
break;
|
||||
case 20: this.popState(); return 18;
|
||||
case 20: this.popState(); return 18;
|
||||
break;
|
||||
case 21: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30;
|
||||
case 21: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 30;
|
||||
break;
|
||||
case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30;
|
||||
case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 30;
|
||||
break;
|
||||
case 23: yy_.yytext = yy_.yytext.substr(1); return 28;
|
||||
case 23: yy_.yytext = yy_.yytext.substr(1); return 28;
|
||||
break;
|
||||
case 24: return 32;
|
||||
case 24: return 32;
|
||||
break;
|
||||
case 25: return 32;
|
||||
case 25: return 32;
|
||||
break;
|
||||
case 26: return 31;
|
||||
case 26: return 31;
|
||||
break;
|
||||
case 27: return 35;
|
||||
case 27: return 35;
|
||||
break;
|
||||
case 28: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35;
|
||||
case 28: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 35;
|
||||
break;
|
||||
case 29: return 'INVALID';
|
||||
case 29: return 'INVALID';
|
||||
break;
|
||||
case 30: /*ignore whitespace*/
|
||||
case 30: /*ignore whitespace*/
|
||||
break;
|
||||
case 31: this.popState(); return 37;
|
||||
case 31: this.popState(); return 37;
|
||||
break;
|
||||
case 32: return 5;
|
||||
case 32: return 5;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ window.MessageBus = (function() {
|
||||
callbacks: callbacks,
|
||||
clientId: clientId,
|
||||
stop: false,
|
||||
|
||||
|
||||
start: function(opts) {
|
||||
var poll,
|
||||
_this = this;
|
||||
|
||||
+27
-27
@@ -40,11 +40,11 @@ module MessageBus::Implementation
|
||||
def logger
|
||||
return @logger if @logger
|
||||
require 'logger'
|
||||
@logger = Logger.new(STDOUT)
|
||||
@logger = Logger.new(STDOUT)
|
||||
end
|
||||
|
||||
def sockets_enabled?
|
||||
@sockets_enabled == false ? false : true
|
||||
@sockets_enabled == false ? false : true
|
||||
end
|
||||
|
||||
def sockets_enabled=(val)
|
||||
@@ -68,13 +68,13 @@ module MessageBus::Implementation
|
||||
end
|
||||
|
||||
def off
|
||||
@off = true
|
||||
@off = true
|
||||
end
|
||||
|
||||
def on
|
||||
@off = false
|
||||
def on
|
||||
@off = false
|
||||
end
|
||||
|
||||
|
||||
# Allow us to inject a redis db
|
||||
def redis_config=(config)
|
||||
@redis_config = config
|
||||
@@ -114,10 +114,10 @@ module MessageBus::Implementation
|
||||
end
|
||||
|
||||
def allow_broadcast?
|
||||
@allow_broadcast ||=
|
||||
@allow_broadcast ||=
|
||||
if defined? ::Rails
|
||||
::Rails.env.test? || ::Rails.env.development?
|
||||
else
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
@@ -130,9 +130,9 @@ module MessageBus::Implementation
|
||||
MessageBus::Diagnostics.enable
|
||||
end
|
||||
|
||||
def publish(channel, data, opts = nil)
|
||||
return if @off
|
||||
|
||||
def publish(channel, data, opts = nil)
|
||||
return if @off
|
||||
|
||||
user_ids = nil
|
||||
if opts
|
||||
user_ids = opts[:user_ids] if opts
|
||||
@@ -142,14 +142,14 @@ module MessageBus::Implementation
|
||||
data: data,
|
||||
user_ids: user_ids
|
||||
})
|
||||
|
||||
|
||||
reliable_pub_sub.publish(encode_channel_name(channel), encoded_data)
|
||||
end
|
||||
|
||||
def blocking_subscribe(channel=nil, &blk)
|
||||
if channel
|
||||
reliable_pub_sub.subscribe(encode_channel_name(channel), &blk)
|
||||
else
|
||||
else
|
||||
reliable_pub_sub.global_subscribe(&blk)
|
||||
end
|
||||
end
|
||||
@@ -173,7 +173,7 @@ module MessageBus::Implementation
|
||||
def subscribe(channel=nil, &blk)
|
||||
subscribe_impl(channel, nil, &blk)
|
||||
end
|
||||
|
||||
|
||||
# subscribe only on current site
|
||||
def local_subscribe(channel=nil, &blk)
|
||||
site_id = MessageBus.site_id_lookup.call if MessageBus.site_id_lookup
|
||||
@@ -181,15 +181,15 @@ module MessageBus::Implementation
|
||||
end
|
||||
|
||||
def backlog(channel=nil, last_id)
|
||||
old =
|
||||
old =
|
||||
if channel
|
||||
reliable_pub_sub.backlog(encode_channel_name(channel), last_id)
|
||||
else
|
||||
else
|
||||
reliable_pub_sub.global_backlog(encode_channel_name(channel), last_id)
|
||||
end
|
||||
|
||||
old.each{ |m|
|
||||
decode_message!(m)
|
||||
decode_message!(m)
|
||||
}
|
||||
old
|
||||
end
|
||||
@@ -199,32 +199,32 @@ module MessageBus::Implementation
|
||||
reliable_pub_sub.last_id(encode_channel_name(channel))
|
||||
end
|
||||
|
||||
protected
|
||||
protected
|
||||
|
||||
def decode_message!(msg)
|
||||
channel, site_id = decode_channel_name(msg.channel)
|
||||
msg.channel = channel
|
||||
msg.channel = channel
|
||||
msg.site_id = site_id
|
||||
parsed = JSON.parse(msg.data)
|
||||
parsed = JSON.parse(msg.data)
|
||||
msg.data = parsed["data"]
|
||||
msg.user_ids = parsed["user_ids"]
|
||||
end
|
||||
|
||||
def subscribe_impl(channel, site_id, &blk)
|
||||
@subscriptions ||= {}
|
||||
@subscriptions ||= {}
|
||||
@subscriptions[site_id] ||= {}
|
||||
@subscriptions[site_id][channel] ||= []
|
||||
@subscriptions[site_id][channel] << blk
|
||||
@subscriptions[site_id][channel] ||= []
|
||||
@subscriptions[site_id][channel] << blk
|
||||
ensure_subscriber_thread
|
||||
end
|
||||
|
||||
def ensure_subscriber_thread
|
||||
@mutex ||= Mutex.new
|
||||
@mutex.synchronize do
|
||||
@mutex.synchronize do
|
||||
return if @subscriber_thread
|
||||
@subscriber_thread = Thread.new do
|
||||
reliable_pub_sub.global_subscribe do |msg|
|
||||
begin
|
||||
begin
|
||||
decode_message!(msg)
|
||||
|
||||
globals = @subscriptions[nil]
|
||||
@@ -232,7 +232,7 @@ module MessageBus::Implementation
|
||||
|
||||
global_globals = globals[nil] if globals
|
||||
local_globals = locals[nil] if locals
|
||||
|
||||
|
||||
globals = globals[msg.channel] if globals
|
||||
locals = locals[msg.channel] if locals
|
||||
|
||||
@@ -243,7 +243,7 @@ module MessageBus::Implementation
|
||||
rescue => e
|
||||
MessageBus.logger.warn "failed to process message #{msg.inspect}\n ex: #{e} backtrace: #{e.backtrace}"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+5
-5
@@ -8,7 +8,7 @@ class MessageBus::Client
|
||||
@subscriptions = {}
|
||||
end
|
||||
|
||||
def close
|
||||
def close
|
||||
return unless @async_response
|
||||
write_and_close "[]"
|
||||
end
|
||||
@@ -31,12 +31,12 @@ class MessageBus::Client
|
||||
end
|
||||
|
||||
def subscriptions
|
||||
@subscriptions
|
||||
@subscriptions
|
||||
end
|
||||
|
||||
def backlog
|
||||
r = []
|
||||
@subscriptions.each do |k,v|
|
||||
@subscriptions.each do |k,v|
|
||||
next if v.to_i < 0
|
||||
messages = MessageBus.backlog(k,v)
|
||||
messages.each do |msg|
|
||||
@@ -46,8 +46,8 @@ class MessageBus::Client
|
||||
end
|
||||
# stats message for all newly subscribed
|
||||
status_message = nil
|
||||
@subscriptions.each do |k,v|
|
||||
if v.to_i == -1
|
||||
@subscriptions.each do |k,v|
|
||||
if v.to_i == -1
|
||||
status_message ||= {}
|
||||
status_message[k] = MessageBus.last_id(k)
|
||||
end
|
||||
|
||||
+10
-10
@@ -4,23 +4,23 @@ class MessageBus::ConnectionManager
|
||||
|
||||
def initialize
|
||||
@clients = {}
|
||||
@subscriptions = {}
|
||||
@subscriptions = {}
|
||||
end
|
||||
|
||||
def notify_clients(msg)
|
||||
begin
|
||||
site_subs = @subscriptions[msg.site_id]
|
||||
begin
|
||||
site_subs = @subscriptions[msg.site_id]
|
||||
subscription = site_subs[msg.channel] if site_subs
|
||||
|
||||
return unless subscription
|
||||
|
||||
|
||||
subscription.each do |client_id|
|
||||
client = @clients[client_id]
|
||||
if client
|
||||
allowed = !msg.user_ids || msg.user_ids.include?(client.user_id)
|
||||
if allowed
|
||||
if allowed
|
||||
client << msg
|
||||
# turns out you can delete from a set while itereating
|
||||
# turns out you can delete from a set while itereating
|
||||
remove_client(client)
|
||||
end
|
||||
end
|
||||
@@ -29,7 +29,7 @@ class MessageBus::ConnectionManager
|
||||
MessageBus.logger.error "notify clients crash #{e} : #{e.backtrace}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def add_client(client)
|
||||
@clients[client.client_id] = client
|
||||
@subscriptions[client.site_id] ||= {}
|
||||
@@ -51,8 +51,8 @@ class MessageBus::ConnectionManager
|
||||
end
|
||||
|
||||
def subscribe_client(client,channel)
|
||||
set = @subscriptions[client.site_id][channel]
|
||||
unless set
|
||||
set = @subscriptions[client.site_id][channel]
|
||||
unless set
|
||||
set = Set.new
|
||||
@subscriptions[client.site_id][channel] = set
|
||||
end
|
||||
@@ -65,5 +65,5 @@ class MessageBus::ConnectionManager
|
||||
subscriptions: @subscriptions
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
+7
-7
@@ -1,15 +1,15 @@
|
||||
class MessageBus::Diagnostics
|
||||
def self.full_process_path
|
||||
begin
|
||||
info = `ps -eo "%p|$|%a" | grep '^\\s*#{Process.pid}'`
|
||||
begin
|
||||
info = `ps -eo "%p|$|%a" | grep '^\\s*#{Process.pid}'`
|
||||
info.strip.split('|$|')[1]
|
||||
rescue
|
||||
# skip it ... not linux or something weird
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.hostname
|
||||
begin
|
||||
begin
|
||||
`hostname`.strip
|
||||
rescue
|
||||
# skip it
|
||||
@@ -21,8 +21,8 @@ class MessageBus::Diagnostics
|
||||
start_time = Time.now.to_f
|
||||
hostname = self.hostname
|
||||
|
||||
# it may make sense to add a channel per machine/host to streamline
|
||||
# process to process comms
|
||||
# it may make sense to add a channel per machine/host to streamline
|
||||
# process to process comms
|
||||
MessageBus.subscribe('/_diagnostics/hup') do |msg|
|
||||
if Process.pid == msg.data["pid"] && hostname == msg.data["hostname"]
|
||||
$shutdown = true
|
||||
@@ -33,7 +33,7 @@ class MessageBus::Diagnostics
|
||||
|
||||
MessageBus.subscribe('/_diagnostics/discover') do |msg|
|
||||
MessageBus.on_connect.call msg.site_id if MessageBus.on_connect
|
||||
MessageBus.publish '/_diagnostics/process-discovery', {
|
||||
MessageBus.publish '/_diagnostics/process-discovery', {
|
||||
pid: Process.pid,
|
||||
process_name: $0,
|
||||
full_path: full_path,
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
class MessageBus::Message < Struct.new(:global_id, :message_id, :channel , :data)
|
||||
|
||||
|
||||
attr_accessor :site_id, :user_ids
|
||||
|
||||
def self.decode(encoded)
|
||||
@@ -10,7 +10,7 @@ class MessageBus::Message < Struct.new(:global_id, :message_id, :channel , :data
|
||||
MessageBus::Message.new encoded[0..s1].to_i, encoded[s1+1..s2].to_i, encoded[s2+1..s3-1].gsub("$$123$$", "|"), encoded[s3+1..-1]
|
||||
end
|
||||
|
||||
# only tricky thing to encode is pipes in a channel name ... do a straight replace
|
||||
# only tricky thing to encode is pipes in a channel name ... do a straight replace
|
||||
def encode
|
||||
global_id.to_s << "|" << message_id.to_s << "|" << channel.gsub("|","$$123$$") << "|" << data
|
||||
end
|
||||
|
||||
@@ -8,13 +8,13 @@ class MessageBus::MessageHandler
|
||||
def self.handle(name,&blk)
|
||||
raise ArgumentError.new("expecting block") unless block_given?
|
||||
raise ArgumentError.new("name") unless name
|
||||
|
||||
|
||||
@@handlers ||= {}
|
||||
@@handlers[name] = blk
|
||||
end
|
||||
|
||||
def self.call(site_id, name, data, current_user_id)
|
||||
begin
|
||||
begin
|
||||
MessageBus.on_connect.call(site_id) if MessageBus.on_connect
|
||||
@@handlers[name].call(data,current_user_id)
|
||||
ensure
|
||||
|
||||
@@ -57,14 +57,14 @@ HTML
|
||||
# from ember-rails
|
||||
def indent(string)
|
||||
string.gsub(/$(.)/m, "\\1 ").strip
|
||||
end
|
||||
end
|
||||
|
||||
def call(env)
|
||||
|
||||
return @app.call(env) unless env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
|
||||
|
||||
route = env['PATH_INFO'].split('/message-bus/_diagnostics')[1]
|
||||
|
||||
|
||||
if MessageBus.is_admin_lookup.nil? || !MessageBus.is_admin_lookup.call(env)
|
||||
return [403, {}, ['not allowed']]
|
||||
end
|
||||
@@ -85,14 +85,14 @@ HTML
|
||||
|
||||
asset = route.split('/assets/')[1]
|
||||
if asset && !asset !~ /\//
|
||||
content = asset_contents(asset)
|
||||
content = asset_contents(asset)
|
||||
split = asset.split('.')
|
||||
if split[1] == 'handlebars'
|
||||
content = translate_handlebars(split[0],content)
|
||||
end
|
||||
return [200, {'content-type' => 'text/javascript;'}, [content]]
|
||||
end
|
||||
|
||||
|
||||
return [404, {}, ['not found']]
|
||||
end
|
||||
end
|
||||
|
||||
+22
-22
@@ -9,7 +9,7 @@ class MessageBus::Rack::Middleware
|
||||
def self.start_listener
|
||||
unless @started_listener
|
||||
MessageBus.subscribe do |msg|
|
||||
EM.next_tick do
|
||||
EM.next_tick do
|
||||
@@connection_manager.notify_clients(msg) if @@connection_manager
|
||||
end
|
||||
end
|
||||
@@ -25,9 +25,9 @@ class MessageBus::Rack::Middleware
|
||||
|
||||
def self.backlog_to_json(backlog)
|
||||
m = backlog.map do |msg|
|
||||
{
|
||||
{
|
||||
:global_id => msg.global_id,
|
||||
:message_id => msg.message_id,
|
||||
:message_id => msg.message_id,
|
||||
:channel => msg.channel,
|
||||
:data => msg.data
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class MessageBus::Rack::Middleware
|
||||
end
|
||||
|
||||
def call(env)
|
||||
|
||||
|
||||
return @app.call(env) unless env['PATH_INFO'] =~ /^\/message-bus/
|
||||
|
||||
# special debug/test route
|
||||
@@ -46,7 +46,7 @@ class MessageBus::Rack::Middleware
|
||||
return [200,{"Content-Type" => "text/html"},["sent"]]
|
||||
end
|
||||
|
||||
if env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
|
||||
if env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
|
||||
diags = MessageBus::Rack::Diagnostics.new(@app)
|
||||
return diags.call(env)
|
||||
end
|
||||
@@ -54,9 +54,9 @@ class MessageBus::Rack::Middleware
|
||||
client_id = env['PATH_INFO'].split("/")[2]
|
||||
return [404, {}, ["not found"]] unless client_id
|
||||
|
||||
user_id = MessageBus.user_id_lookup.call(env) if MessageBus.user_id_lookup
|
||||
site_id = MessageBus.site_id_lookup.call(env) if MessageBus.site_id_lookup
|
||||
|
||||
user_id = MessageBus.user_id_lookup.call(env) if MessageBus.user_id_lookup
|
||||
site_id = MessageBus.site_id_lookup.call(env) if MessageBus.site_id_lookup
|
||||
|
||||
client = MessageBus::Client.new(client_id: client_id, user_id: user_id, site_id: site_id)
|
||||
|
||||
connection = env['em.connection']
|
||||
@@ -65,20 +65,20 @@ class MessageBus::Rack::Middleware
|
||||
request.POST.each do |k,v|
|
||||
client.subscribe(k, v)
|
||||
end
|
||||
|
||||
|
||||
backlog = client.backlog
|
||||
headers = {}
|
||||
headers["Cache-Control"] = "must-revalidate, private, max-age=0"
|
||||
headers["Content-Type"] ="application/json; charset=utf-8"
|
||||
|
||||
if backlog.length > 0
|
||||
if backlog.length > 0
|
||||
[200, headers, [self.class.backlog_to_json(backlog)] ]
|
||||
elsif MessageBus.long_polling_enabled? && env['QUERY_STRING'] !~ /dlp=t/
|
||||
response = Thin::AsyncResponse.new(env)
|
||||
response.headers["Cache-Control"] = "must-revalidate, private, max-age=0"
|
||||
response.headers["Content-Type"] ="application/json; charset=utf-8"
|
||||
response.status = 200
|
||||
client.async_response = response
|
||||
client.async_response = response
|
||||
|
||||
@@connection_manager.add_client(client)
|
||||
|
||||
@@ -86,16 +86,16 @@ class MessageBus::Rack::Middleware
|
||||
client.close
|
||||
@@connection_manager.remove_client(client)
|
||||
}
|
||||
|
||||
|
||||
throw :async
|
||||
else
|
||||
else
|
||||
[200, headers, ["[]"]]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# there is also another in cramp this is from https://github.com/macournoyer/thin_async/blob/master/lib/thin/async.rb
|
||||
# there is also another in cramp this is from https://github.com/macournoyer/thin_async/blob/master/lib/thin/async.rb
|
||||
module Thin
|
||||
unless defined?(DeferrableBody)
|
||||
# Based on version from James Tucker <raggi@rubyforge.org>
|
||||
@@ -115,7 +115,7 @@ module Thin
|
||||
@body_callback = blk
|
||||
schedule_dequeue
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def schedule_dequeue
|
||||
return unless @body_callback
|
||||
@@ -129,14 +129,14 @@ module Thin
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Response whos body is sent asynchronously.
|
||||
class AsyncResponse
|
||||
include Rack::Response::Helpers
|
||||
|
||||
|
||||
attr_reader :headers, :callback, :closed
|
||||
attr_accessor :status
|
||||
|
||||
|
||||
def initialize(env, status=200, headers={})
|
||||
@callback = env['async.callback']
|
||||
@body = DeferrableBody.new
|
||||
@@ -144,25 +144,25 @@ module Thin
|
||||
@headers = headers
|
||||
@headers_sent = false
|
||||
end
|
||||
|
||||
|
||||
def send_headers
|
||||
return if @headers_sent
|
||||
@callback.call [@status, @headers, @body]
|
||||
@headers_sent = true
|
||||
end
|
||||
|
||||
|
||||
def write(body)
|
||||
send_headers
|
||||
@body.call(body.respond_to?(:each) ? body : [body])
|
||||
end
|
||||
alias :<< :write
|
||||
|
||||
|
||||
# Tell Thin the response is complete and the connection can be closed.
|
||||
def done
|
||||
@closed = true
|
||||
send_headers
|
||||
::EM.next_tick { @body.succeed }
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
+24
-24
@@ -1,17 +1,17 @@
|
||||
require 'redis'
|
||||
# the heart of the message bus, it acts as 2 things
|
||||
# the heart of the message bus, it acts as 2 things
|
||||
#
|
||||
# 1. A channel multiplexer
|
||||
# 2. Backlog storage per-multiplexed channel.
|
||||
# 2. Backlog storage per-multiplexed channel.
|
||||
#
|
||||
# ids are all sequencially increasing numbers starting at 0
|
||||
# ids are all sequencially increasing numbers starting at 0
|
||||
#
|
||||
|
||||
|
||||
class MessageBus::ReliablePubSub
|
||||
|
||||
class NoMoreRetries < StandardError; end
|
||||
class BackLogOutOfOrder < StandardError
|
||||
class BackLogOutOfOrder < StandardError
|
||||
attr_accessor :highest_id
|
||||
|
||||
def initialize(highest_id)
|
||||
@@ -26,7 +26,7 @@ class MessageBus::ReliablePubSub
|
||||
def max_publish_retries
|
||||
@max_publish_retries ||= 10
|
||||
end
|
||||
|
||||
|
||||
def max_publish_wait=(ms)
|
||||
@max_publish_wait = ms
|
||||
end
|
||||
@@ -35,11 +35,11 @@ class MessageBus::ReliablePubSub
|
||||
@max_publish_wait ||= 500
|
||||
end
|
||||
|
||||
# max_backlog_size is per multiplexed channel
|
||||
# max_backlog_size is per multiplexed channel
|
||||
def initialize(redis_config = {}, max_backlog_size = 1000)
|
||||
@redis_config = redis_config
|
||||
@max_backlog_size = 1000
|
||||
# we can store a ton here ...
|
||||
# we can store a ton here ...
|
||||
@max_global_backlog_size = 100000
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ class MessageBus::ReliablePubSub
|
||||
def max_global_backlog_size=(val)
|
||||
@max_global_backlog_size = val
|
||||
end
|
||||
|
||||
|
||||
# per channel backlog size
|
||||
def max_backlog_size=(val)
|
||||
@max_backlog_size = val
|
||||
@@ -62,7 +62,7 @@ class MessageBus::ReliablePubSub
|
||||
"discourse_#{db}"
|
||||
end
|
||||
|
||||
# redis connection used for publishing messages
|
||||
# redis connection used for publishing messages
|
||||
def pub_redis
|
||||
@pub_redis ||= new_redis_connection
|
||||
end
|
||||
@@ -84,14 +84,14 @@ class MessageBus::ReliablePubSub
|
||||
end
|
||||
|
||||
# use with extreme care, will nuke all of the data
|
||||
def reset!
|
||||
def reset!
|
||||
pub_redis.keys("__mb_*").each do |k|
|
||||
pub_redis.del k
|
||||
end
|
||||
end
|
||||
|
||||
def publish(channel, data)
|
||||
redis = pub_redis
|
||||
redis = pub_redis
|
||||
backlog_id_key = backlog_id_key(channel)
|
||||
backlog_key = backlog_key(channel)
|
||||
|
||||
@@ -126,13 +126,13 @@ class MessageBus::ReliablePubSub
|
||||
end
|
||||
|
||||
def last_id(channel)
|
||||
redis = pub_redis
|
||||
redis = pub_redis
|
||||
backlog_id_key = backlog_id_key(channel)
|
||||
redis.get(backlog_id_key).to_i
|
||||
end
|
||||
|
||||
def backlog(channel, last_id = nil)
|
||||
redis = pub_redis
|
||||
redis = pub_redis
|
||||
backlog_key = backlog_key(channel)
|
||||
items = redis.zrangebyscore backlog_key, last_id.to_i + 1, "+inf"
|
||||
|
||||
@@ -150,7 +150,7 @@ class MessageBus::ReliablePubSub
|
||||
items.map! do |i|
|
||||
pipe = i.index "|"
|
||||
message_id = i[0..pipe].to_i
|
||||
channel = i[pipe+1..-1]
|
||||
channel = i[pipe+1..-1]
|
||||
m = get_message(channel, message_id)
|
||||
m
|
||||
end
|
||||
@@ -160,11 +160,11 @@ class MessageBus::ReliablePubSub
|
||||
end
|
||||
|
||||
def get_message(channel, message_id)
|
||||
redis = pub_redis
|
||||
redis = pub_redis
|
||||
backlog_key = backlog_key(channel)
|
||||
|
||||
items = redis.zrangebyscore backlog_key, message_id, message_id
|
||||
if items && items[0]
|
||||
if items && items[0]
|
||||
MessageBus::Message.decode(items[0])
|
||||
else
|
||||
nil
|
||||
@@ -172,8 +172,8 @@ class MessageBus::ReliablePubSub
|
||||
end
|
||||
|
||||
def subscribe(channel, last_id = nil)
|
||||
# trivial implementation for now,
|
||||
# can cut down on connections if we only have one global subscriber
|
||||
# trivial implementation for now,
|
||||
# can cut down on connections if we only have one global subscriber
|
||||
raise ArgumentError unless block_given?
|
||||
|
||||
if last_id
|
||||
@@ -212,7 +212,7 @@ class MessageBus::ReliablePubSub
|
||||
|
||||
clear_backlog = lambda do
|
||||
retries = 4
|
||||
begin
|
||||
begin
|
||||
highest_id = process_global_backlog(highest_id, retries > 0, &blk)
|
||||
rescue BackLogOutOfOrder => e
|
||||
highest_id = e.highest_id
|
||||
@@ -231,7 +231,7 @@ class MessageBus::ReliablePubSub
|
||||
end
|
||||
|
||||
redis.subscribe(redis_channel_name) do |on|
|
||||
on.subscribe do
|
||||
on.subscribe do
|
||||
if highest_id
|
||||
clear_backlog.call(&blk)
|
||||
end
|
||||
@@ -242,12 +242,12 @@ class MessageBus::ReliablePubSub
|
||||
# we have 2 options
|
||||
#
|
||||
# 1. message came in the correct order GREAT, just deal with it
|
||||
# 2. message came in the incorrect order COMPLICATED, wait a tiny bit and clear backlog
|
||||
|
||||
# 2. message came in the incorrect order COMPLICATED, wait a tiny bit and clear backlog
|
||||
|
||||
if highest_id.nil? || m.global_id == highest_id + 1
|
||||
highest_id = m.global_id
|
||||
highest_id = m.global_id
|
||||
yield m
|
||||
else
|
||||
else
|
||||
clear_backlog.call(&blk)
|
||||
end
|
||||
end
|
||||
|
||||
+7
-7
@@ -1,23 +1,23 @@
|
||||
require 'spec_helper'
|
||||
require 'message_bus'
|
||||
|
||||
describe MessageBus::Client do
|
||||
|
||||
describe MessageBus::Client do
|
||||
|
||||
describe "subscriptions" do
|
||||
|
||||
|
||||
before do
|
||||
@client = MessageBus::Client.new :client_id => 'abc'
|
||||
end
|
||||
|
||||
it "should provide a list of subscriptions" do
|
||||
it "should provide a list of subscriptions" do
|
||||
@client.subscribe('/hello', nil)
|
||||
@client.subscriptions['/hello'].should_not be_nil
|
||||
@client.subscriptions['/hello'].should_not be_nil
|
||||
end
|
||||
|
||||
it "should provide backlog for subscribed channel" do
|
||||
it "should provide backlog for subscribed channel" do
|
||||
@client.subscribe('/hello', nil)
|
||||
MessageBus.publish '/hello', 'world'
|
||||
log = @client.backlog
|
||||
log = @client.backlog
|
||||
log.length.should == 1
|
||||
log[0].channel.should == '/hello'
|
||||
log[0].data.should == 'world'
|
||||
|
||||
+12
-12
@@ -2,7 +2,7 @@ require 'spec_helper'
|
||||
require 'message_bus'
|
||||
|
||||
class FakeAsync
|
||||
|
||||
|
||||
attr_accessor :cleanup_timer
|
||||
|
||||
def <<(val)
|
||||
@@ -20,58 +20,58 @@ class FakeTimer
|
||||
def cancel; @cancelled = true; end
|
||||
end
|
||||
|
||||
describe MessageBus::ConnectionManager do
|
||||
describe MessageBus::ConnectionManager do
|
||||
|
||||
before do
|
||||
before do
|
||||
@manager = MessageBus::ConnectionManager.new
|
||||
@client = MessageBus::Client.new(client_id: "xyz", user_id: 1, site_id: 10)
|
||||
@resp = FakeAsync.new
|
||||
@client.async_response = @resp
|
||||
@client.subscribe('test', -1)
|
||||
@manager.add_client(@client)
|
||||
@manager.add_client(@client)
|
||||
@client.cleanup_timer = FakeTimer.new
|
||||
end
|
||||
|
||||
it "should cancel the timer after its responds" do
|
||||
it "should cancel the timer after its responds" do
|
||||
m = MessageBus::Message.new(1,1,"test","data")
|
||||
m.site_id = 10
|
||||
@manager.notify_clients(m)
|
||||
@client.cleanup_timer.cancelled.should == true
|
||||
end
|
||||
|
||||
it "should be able to lookup an identical client" do
|
||||
it "should be able to lookup an identical client" do
|
||||
@manager.lookup_client(@client.client_id).should == @client
|
||||
end
|
||||
|
||||
it "should be subscribed to a channel" do
|
||||
it "should be subscribed to a channel" do
|
||||
@manager.stats[:subscriptions][10]["test"].length == 1
|
||||
end
|
||||
|
||||
it "should not notify clients on incorrect site" do
|
||||
it "should not notify clients on incorrect site" do
|
||||
m = MessageBus::Message.new(1,1,"test","data")
|
||||
m.site_id = 9
|
||||
@manager.notify_clients(m)
|
||||
@resp.sent.should == nil
|
||||
end
|
||||
|
||||
it "should notify clients on the correct site" do
|
||||
it "should notify clients on the correct site" do
|
||||
m = MessageBus::Message.new(1,1,"test","data")
|
||||
m.site_id = 10
|
||||
@manager.notify_clients(m)
|
||||
@resp.sent.should_not == nil
|
||||
end
|
||||
|
||||
it "should strip site id and user id from the payload delivered" do
|
||||
it "should strip site id and user id from the payload delivered" do
|
||||
m = MessageBus::Message.new(1,1,"test","data")
|
||||
m.user_ids = [1]
|
||||
m.site_id = 10
|
||||
@manager.notify_clients(m)
|
||||
parsed = JSON.parse(@resp.sent)
|
||||
parsed = JSON.parse(@resp.sent)
|
||||
parsed[0]["site_id"].should == nil
|
||||
parsed[0]["user_id"].should == nil
|
||||
end
|
||||
|
||||
it "should not deliver unselected" do
|
||||
it "should not deliver unselected" do
|
||||
m = MessageBus::Message.new(1,1,"test","data")
|
||||
m.user_ids = [5]
|
||||
m.site_id = 10
|
||||
|
||||
+13
-13
@@ -5,17 +5,17 @@ require 'redis'
|
||||
|
||||
describe MessageBus do
|
||||
|
||||
before do
|
||||
MessageBus.site_id_lookup do
|
||||
before do
|
||||
MessageBus.site_id_lookup do
|
||||
"magic"
|
||||
end
|
||||
MessageBus.redis_config = {}
|
||||
end
|
||||
|
||||
it "should automatically decode hashed messages" do
|
||||
it "should automatically decode hashed messages" do
|
||||
data = nil
|
||||
MessageBus.subscribe("/chuck") do |msg|
|
||||
data = msg.data
|
||||
MessageBus.subscribe("/chuck") do |msg|
|
||||
data = msg.data
|
||||
end
|
||||
MessageBus.publish("/chuck", {:norris => true})
|
||||
wait_for(1000){ data }
|
||||
@@ -23,10 +23,10 @@ describe MessageBus do
|
||||
data["norris"].should == true
|
||||
end
|
||||
|
||||
it "should get a message if it subscribes to it" do
|
||||
it "should get a message if it subscribes to it" do
|
||||
@data,@site_id,@channel = nil
|
||||
|
||||
MessageBus.subscribe("/chuck") do |msg|
|
||||
|
||||
MessageBus.subscribe("/chuck") do |msg|
|
||||
@data = msg.data
|
||||
@site_id = msg.site_id
|
||||
@channel = msg.channel
|
||||
@@ -36,7 +36,7 @@ describe MessageBus do
|
||||
MessageBus.publish("/chuck", "norris", user_ids: [1,2,3])
|
||||
|
||||
wait_for(1000){@data}
|
||||
|
||||
|
||||
@data.should == 'norris'
|
||||
@site_id.should == 'magic'
|
||||
@channel.should == '/chuck'
|
||||
@@ -45,10 +45,10 @@ describe MessageBus do
|
||||
end
|
||||
|
||||
|
||||
it "should get global messages if it subscribes to them" do
|
||||
it "should get global messages if it subscribes to them" do
|
||||
@data,@site_id,@channel = nil
|
||||
|
||||
MessageBus.subscribe do |msg|
|
||||
|
||||
MessageBus.subscribe do |msg|
|
||||
@data = msg.data
|
||||
@site_id = msg.site_id
|
||||
@channel = msg.channel
|
||||
@@ -57,7 +57,7 @@ describe MessageBus do
|
||||
MessageBus.publish("/chuck", "norris")
|
||||
|
||||
wait_for(1000){@data}
|
||||
|
||||
|
||||
@data.should == 'norris'
|
||||
@site_id.should == 'magic'
|
||||
@channel.should == '/chuck'
|
||||
|
||||
@@ -3,14 +3,14 @@ require 'message_bus'
|
||||
|
||||
describe MessageBus::MessageHandler do
|
||||
|
||||
it "should properly register message handlers" do
|
||||
it "should properly register message handlers" do
|
||||
MessageBus::MessageHandler.handle "/hello" do |m|
|
||||
m
|
||||
end
|
||||
MessageBus::MessageHandler.call("site","/hello", "world", 1).should == "world"
|
||||
end
|
||||
|
||||
it "should correctly load message handlers" do
|
||||
it "should correctly load message handlers" do
|
||||
MessageBus::MessageHandler.load_handlers("#{File.dirname(__FILE__)}/handlers")
|
||||
MessageBus::MessageHandler.call("site","/dupe", "1", 1).should == "11"
|
||||
end
|
||||
@@ -19,7 +19,7 @@ describe MessageBus::MessageHandler do
|
||||
MessageBus::MessageHandler.handle "/channel" do |m|
|
||||
m
|
||||
end
|
||||
|
||||
|
||||
connected = false
|
||||
disconnected = false
|
||||
|
||||
@@ -31,9 +31,9 @@ describe MessageBus::MessageHandler do
|
||||
end
|
||||
|
||||
MessageBus::MessageHandler.call("site_id", "/channel", "data", 1)
|
||||
|
||||
|
||||
connected.should == true
|
||||
disconnected.should == true
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
+15
-15
@@ -7,7 +7,7 @@ describe MessageBus::Rack::Middleware do
|
||||
|
||||
class FakeAsyncMiddleware
|
||||
|
||||
def self.in_async?
|
||||
def self.in_async?
|
||||
@@in_async if defined? @@in_async
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ describe MessageBus::Rack::Middleware do
|
||||
EM.run {
|
||||
env['async.callback'] = lambda { |r|
|
||||
# more judo with deferrable body, at this point we just have headers
|
||||
r[2].callback do
|
||||
r[2].callback do
|
||||
# even more judo cause rack test does not call each like the spec says
|
||||
body = ""
|
||||
r[2].each do |m|
|
||||
@@ -35,7 +35,7 @@ describe MessageBus::Rack::Middleware do
|
||||
}
|
||||
|
||||
EM::Timer.new(1) { EM.stop }
|
||||
|
||||
|
||||
defer = lambda {
|
||||
if !result
|
||||
@@in_async = true
|
||||
@@ -63,7 +63,7 @@ describe MessageBus::Rack::Middleware do
|
||||
end
|
||||
|
||||
describe "long polling" do
|
||||
before do
|
||||
before do
|
||||
MessageBus.sockets_enabled = false
|
||||
MessageBus.long_polling_enabled = true
|
||||
end
|
||||
@@ -83,7 +83,7 @@ describe MessageBus::Rack::Middleware do
|
||||
parsed[0]["data"]["/foo"].should == MessageBus.last_id("/foo")
|
||||
end
|
||||
|
||||
it "should respond to long polls when data is available" do
|
||||
it "should respond to long polls when data is available" do
|
||||
|
||||
Thread.new do
|
||||
wait_for(2000) { FakeAsyncMiddleware.in_async? }
|
||||
@@ -98,7 +98,7 @@ describe MessageBus::Rack::Middleware do
|
||||
parsed[0]["data"].should == "bar"
|
||||
end
|
||||
|
||||
it "should timeout within its alloted slot" do
|
||||
it "should timeout within its alloted slot" do
|
||||
begin
|
||||
MessageBus.long_polling_interval = 10
|
||||
s = Time.now.to_f * 1000
|
||||
@@ -110,9 +110,9 @@ describe MessageBus::Rack::Middleware do
|
||||
end
|
||||
end
|
||||
|
||||
describe "diagnostics" do
|
||||
describe "diagnostics" do
|
||||
|
||||
it "should return a 403 if a user attempts to get at the _diagnostics path" do
|
||||
it "should return a 403 if a user attempts to get at the _diagnostics path" do
|
||||
get "/message-bus/_diagnostics"
|
||||
last_response.status.should == 403
|
||||
end
|
||||
@@ -131,9 +131,9 @@ describe MessageBus::Rack::Middleware do
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
describe "polling" do
|
||||
before do
|
||||
before do
|
||||
MessageBus.sockets_enabled = false
|
||||
MessageBus.long_polling_enabled = false
|
||||
end
|
||||
@@ -149,8 +149,8 @@ describe MessageBus::Rack::Middleware do
|
||||
last_response.should be_ok
|
||||
end
|
||||
|
||||
it "should correctly understand that -1 means stuff from now onwards" do
|
||||
|
||||
it "should correctly understand that -1 means stuff from now onwards" do
|
||||
|
||||
MessageBus.publish('foo', 'bar')
|
||||
|
||||
post "/message-bus/ABCD", {
|
||||
@@ -164,7 +164,7 @@ describe MessageBus::Rack::Middleware do
|
||||
|
||||
end
|
||||
|
||||
it "should respond with the data if messages exist in the backlog" do
|
||||
it "should respond with the data if messages exist in the backlog" do
|
||||
id = MessageBus.last_id('/foo')
|
||||
|
||||
MessageBus.publish("/foo", "barbs")
|
||||
@@ -182,10 +182,10 @@ describe MessageBus::Rack::Middleware do
|
||||
parsed[1]["data"].should == "borbs"
|
||||
end
|
||||
|
||||
it "should not get consumed messages" do
|
||||
it "should not get consumed messages" do
|
||||
MessageBus.publish("/foo", "barbs")
|
||||
id = MessageBus.last_id('/foo')
|
||||
|
||||
|
||||
client_id = "ABCD"
|
||||
post "/message-bus/#{client_id}", {
|
||||
'/foo' => id
|
||||
|
||||
+5
-5
@@ -28,12 +28,12 @@ describe MessageBus::ReliablePubSub do
|
||||
end
|
||||
end
|
||||
|
||||
it 'gets every response from child processes' do
|
||||
it 'gets every response from child processes' do
|
||||
pid = nil
|
||||
Redis.new(:db => 10).flushall
|
||||
begin
|
||||
pids = (1..10).map{spawn_child}
|
||||
responses = []
|
||||
pids = (1..10).map{spawn_child}
|
||||
responses = []
|
||||
bus = MessageBus::ReliablePubSub.new(:db => 10)
|
||||
Thread.new do
|
||||
bus.subscribe("/response", 0) do |msg|
|
||||
@@ -41,7 +41,7 @@ describe MessageBus::ReliablePubSub do
|
||||
end
|
||||
end
|
||||
10.times{bus.publish("/echo", Process.pid.to_s)}
|
||||
wait_for 4000 do
|
||||
wait_for 4000 do
|
||||
responses.count == 100
|
||||
end
|
||||
|
||||
@@ -50,7 +50,7 @@ describe MessageBus::ReliablePubSub do
|
||||
responses.count.should == 100
|
||||
ensure
|
||||
if pids
|
||||
pids.each do |pid|
|
||||
pids.each do |pid|
|
||||
Process.kill("HUP", pid)
|
||||
Process.wait(pid)
|
||||
end
|
||||
|
||||
+33
-33
@@ -7,22 +7,22 @@ describe MessageBus::ReliablePubSub do
|
||||
MessageBus::ReliablePubSub.new(:db => 10)
|
||||
end
|
||||
|
||||
before do
|
||||
before do
|
||||
@bus = new_test_bus
|
||||
@bus.reset!
|
||||
end
|
||||
|
||||
it "should be able to access the backlog" do
|
||||
it "should be able to access the backlog" do
|
||||
@bus.publish "/foo", "bar"
|
||||
@bus.publish "/foo", "baz"
|
||||
|
||||
@bus.backlog("/foo", 0).to_a.should == [
|
||||
@bus.backlog("/foo", 0).to_a.should == [
|
||||
MessageBus::Message.new(1,1,'/foo','bar'),
|
||||
MessageBus::Message.new(2,2,'/foo','baz')
|
||||
]
|
||||
end
|
||||
|
||||
it "should truncate channels correctly" do
|
||||
it "should truncate channels correctly" do
|
||||
@bus.max_backlog_size = 2
|
||||
4.times do |t|
|
||||
@bus.publish "/foo", t.to_s
|
||||
@@ -34,18 +34,18 @@ describe MessageBus::ReliablePubSub do
|
||||
]
|
||||
end
|
||||
|
||||
it "should be able to grab a message by id" do
|
||||
it "should be able to grab a message by id" do
|
||||
id1 = @bus.publish "/foo", "bar"
|
||||
id2 = @bus.publish "/foo", "baz"
|
||||
@bus.get_message("/foo", id2).should == MessageBus::Message.new(2, 2, "/foo", "baz")
|
||||
@bus.get_message("/foo", id1).should == MessageBus::Message.new(1, 1, "/foo", "bar")
|
||||
end
|
||||
|
||||
it "should be able to access the global backlog" do
|
||||
it "should be able to access the global backlog" do
|
||||
@bus.publish "/foo", "bar"
|
||||
@bus.publish "/hello", "world"
|
||||
@bus.publish "/hello", "world"
|
||||
@bus.publish "/foo", "baz"
|
||||
@bus.publish "/hello", "planet"
|
||||
@bus.publish "/hello", "planet"
|
||||
|
||||
@bus.global_backlog.to_a.should == [
|
||||
MessageBus::Message.new(1, 1, "/foo", "bar"),
|
||||
@@ -55,7 +55,7 @@ describe MessageBus::ReliablePubSub do
|
||||
]
|
||||
end
|
||||
|
||||
it "should correctly omit dropped messages from the global backlog" do
|
||||
it "should correctly omit dropped messages from the global backlog" do
|
||||
@bus.max_backlog_size = 1
|
||||
@bus.publish "/foo", "a"
|
||||
@bus.publish "/foo", "b"
|
||||
@@ -68,12 +68,12 @@ describe MessageBus::ReliablePubSub do
|
||||
]
|
||||
end
|
||||
|
||||
it "should have the correct number of messages for multi threaded access" do
|
||||
it "should have the correct number of messages for multi threaded access" do
|
||||
threads = []
|
||||
4.times do
|
||||
threads << Thread.new do
|
||||
bus = new_test_bus
|
||||
25.times {
|
||||
4.times do
|
||||
threads << Thread.new do
|
||||
bus = new_test_bus
|
||||
25.times {
|
||||
bus.publish "/foo", "."
|
||||
}
|
||||
end
|
||||
@@ -86,14 +86,14 @@ describe MessageBus::ReliablePubSub do
|
||||
it "should be able to subscribe globally with recovery" do
|
||||
@bus.publish("/foo", "1")
|
||||
@bus.publish("/bar", "2")
|
||||
got = []
|
||||
got = []
|
||||
|
||||
t = Thread.new do
|
||||
new_test_bus.global_subscribe(0) do |msg|
|
||||
t = Thread.new do
|
||||
new_test_bus.global_subscribe(0) do |msg|
|
||||
got << msg
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@bus.publish("/bar", "3")
|
||||
|
||||
wait_for(100) do
|
||||
@@ -101,29 +101,29 @@ describe MessageBus::ReliablePubSub do
|
||||
end
|
||||
|
||||
t.kill
|
||||
|
||||
|
||||
got.length.should == 3
|
||||
got.map{|m| m.data}.should == ["1","2","3"]
|
||||
end
|
||||
|
||||
it "should be able to encode and decode messages properly" do
|
||||
it "should be able to encode and decode messages properly" do
|
||||
m = MessageBus::Message.new 1,2,'||','||'
|
||||
MessageBus::Message.decode(m.encode).should == m
|
||||
end
|
||||
|
||||
it "should handle subscribe on single channel, with recovery" do
|
||||
it "should handle subscribe on single channel, with recovery" do
|
||||
@bus.publish("/foo", "1")
|
||||
@bus.publish("/bar", "2")
|
||||
got = []
|
||||
got = []
|
||||
|
||||
t = Thread.new do
|
||||
new_test_bus.subscribe("/foo",0) do |msg|
|
||||
t = Thread.new do
|
||||
new_test_bus.subscribe("/foo",0) do |msg|
|
||||
got << msg
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@bus.publish("/foo", "3")
|
||||
|
||||
|
||||
wait_for(100) do
|
||||
got.length == 2
|
||||
end
|
||||
@@ -133,22 +133,22 @@ describe MessageBus::ReliablePubSub do
|
||||
got.map{|m| m.data}.should == ["1","3"]
|
||||
end
|
||||
|
||||
it "should not get backlog if subscribe is called without params" do
|
||||
it "should not get backlog if subscribe is called without params" do
|
||||
@bus.publish("/foo", "1")
|
||||
got = []
|
||||
got = []
|
||||
|
||||
t = Thread.new do
|
||||
new_test_bus.subscribe("/foo") do |msg|
|
||||
t = Thread.new do
|
||||
new_test_bus.subscribe("/foo") do |msg|
|
||||
got << msg
|
||||
end
|
||||
end
|
||||
|
||||
# sleep 50ms to allow the bus to correctly subscribe,
|
||||
# sleep 50ms to allow the bus to correctly subscribe,
|
||||
# I thought about adding a subscribed callback, but outside of testing it matters less
|
||||
sleep 0.05
|
||||
|
||||
@bus.publish("/foo", "2")
|
||||
|
||||
|
||||
wait_for(100) do
|
||||
got.length == 1
|
||||
end
|
||||
@@ -158,7 +158,7 @@ describe MessageBus::ReliablePubSub do
|
||||
got.map{|m| m.data}.should == ["2"]
|
||||
end
|
||||
|
||||
it "should allow us to get last id on a channel" do
|
||||
it "should allow us to get last id on a channel" do
|
||||
@bus.last_id("/foo").should == 0
|
||||
@bus.publish("/foo", "1")
|
||||
@bus.last_id("/foo").should == 1
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env rake
|
||||
require "bundler/gem_tasks"
|
||||
require "rspec/core/rake_task"
|
||||
require "rspec/core/rake_task"
|
||||
|
||||
RSpec::Core::RakeTask.new(:test) do |spec|
|
||||
spec.pattern = 'spec/*_spec.rb'
|
||||
|
||||
@@ -14,7 +14,7 @@ module RailsMultisite
|
||||
handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
||||
@@connection_handlers[spec] = handler
|
||||
end
|
||||
else
|
||||
else
|
||||
handler = @@default_connection_handler
|
||||
end
|
||||
ActiveRecord::Base.connection_handler = handler
|
||||
@@ -30,25 +30,25 @@ module RailsMultisite
|
||||
yield db
|
||||
ActiveRecord::Base.connection_handler.clear_active_connections!
|
||||
end
|
||||
establish_connection(:db => old)
|
||||
establish_connection(:db => old)
|
||||
ActiveRecord::Base.connection_handler.clear_active_connections! unless connected
|
||||
end
|
||||
|
||||
def self.all_dbs
|
||||
["default"] +
|
||||
["default"] +
|
||||
if defined?(@@db_spec_cache) && @@db_spec_cache
|
||||
@@db_spec_cache.keys.to_a
|
||||
else
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def self.current_db
|
||||
db = ActiveRecord::Base.connection_pool.spec.config[:db_key] || "default"
|
||||
db = ActiveRecord::Base.connection_pool.spec.config[:db_key] || "default"
|
||||
end
|
||||
|
||||
def self.config_filename=(config_filename)
|
||||
@@config_filename = config_filename
|
||||
@@config_filename = config_filename
|
||||
end
|
||||
|
||||
def self.config_filename
|
||||
@@ -90,8 +90,8 @@ module RailsMultisite
|
||||
@@host_spec_cache[host] = @@default_spec
|
||||
end
|
||||
|
||||
# inject our connection_handler pool
|
||||
# WARNING MONKEY PATCH
|
||||
# inject our connection_handler pool
|
||||
# WARNING MONKEY PATCH
|
||||
#
|
||||
# see: https://github.com/rails/rails/issues/8344#issuecomment-10800848
|
||||
#
|
||||
@@ -103,7 +103,7 @@ module RailsMultisite
|
||||
|
||||
module NewConnectionHandler
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
klass.class_eval do
|
||||
define_singleton_method :connection_handler do
|
||||
Thread.current[:connection_handler] || @connection_handler
|
||||
end
|
||||
@@ -122,7 +122,7 @@ module RailsMultisite
|
||||
|
||||
def call(env)
|
||||
request = Rack::Request.new(env)
|
||||
begin
|
||||
begin
|
||||
|
||||
#TODO: add a callback so users can simply go to a domain to register it, or something
|
||||
return [404, {}, ["not found"]] unless @@host_spec_cache[request.host]
|
||||
@@ -139,9 +139,9 @@ module RailsMultisite
|
||||
if opts[:host]
|
||||
@@host_spec_cache[opts[:host]]
|
||||
else
|
||||
@@db_spec_cache[opts[:db]]
|
||||
@@db_spec_cache[opts[:db]]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,6 +16,6 @@ module RailsMultisite
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+4
-4
@@ -4,17 +4,17 @@ task "multisite:generate:config" => :environment do
|
||||
|
||||
if File.exists?(filename)
|
||||
puts "Config is already generated at #{RailsMultisite::ConnectionManagement::CONFIG_FILE}"
|
||||
else
|
||||
else
|
||||
puts "Generated config file at #{RailsMultisite::ConnectionManagement::CONFIG_FILE}"
|
||||
File.open(filename, 'w') do |f|
|
||||
File.open(filename, 'w') do |f|
|
||||
f.write <<-CONFIG
|
||||
# site_name:
|
||||
# site_name:
|
||||
# adapter: postgresql
|
||||
# database: db_name
|
||||
# host: localhost
|
||||
# pool: 5
|
||||
# timeout: 5000
|
||||
# db_id: 1 # optionally include other settings you need
|
||||
# db_id: 1 # optionally include other settings you need
|
||||
# host_names:
|
||||
# - www.mysite.com
|
||||
# - www.anothersite.com
|
||||
|
||||
@@ -6,7 +6,7 @@ describe RailsMultisite::ConnectionManagement do
|
||||
include Rack::Test::Methods
|
||||
|
||||
def app
|
||||
|
||||
|
||||
RailsMultisite::ConnectionManagement.config_filename = 'spec/fixtures/two_dbs.yml'
|
||||
RailsMultisite::ConnectionManagement.load_settings!
|
||||
|
||||
@@ -18,7 +18,7 @@ describe RailsMultisite::ConnectionManagement do
|
||||
}.to_app
|
||||
end
|
||||
|
||||
after do
|
||||
after do
|
||||
RailsMultisite::ConnectionManagement.clear_settings!
|
||||
end
|
||||
|
||||
@@ -31,12 +31,12 @@ describe RailsMultisite::ConnectionManagement do
|
||||
get 'http://second.localhost/html'
|
||||
last_response.should be_ok
|
||||
end
|
||||
|
||||
|
||||
it 'returns 200 for valid main site' do
|
||||
get 'http://default.localhost/html'
|
||||
last_response.should be_ok
|
||||
end
|
||||
|
||||
|
||||
it 'returns 404 for invalid site' do
|
||||
get '/html'
|
||||
last_response.should be_not_found
|
||||
|
||||
@@ -24,7 +24,7 @@ describe RailsMultisite::ConnectionManagement do
|
||||
before do
|
||||
subject.config_filename = "spec/fixtures/two_dbs.yml"
|
||||
subject.load_settings!
|
||||
end
|
||||
end
|
||||
its(:all_dbs) { should == ['default', 'second']}
|
||||
|
||||
context 'second db' do
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
second:
|
||||
second:
|
||||
adapter: sqlite3
|
||||
database: second_db
|
||||
username: username
|
||||
password: password
|
||||
db_id: 1
|
||||
db_id: 1
|
||||
host_names:
|
||||
- second.localhost
|
||||
- 2nd.localhost
|
||||
- 2nd.localhost
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ ENV["RAILS_ENV"] ||= 'test'
|
||||
RSpec.configure do |config|
|
||||
|
||||
config.color_enabled = true
|
||||
|
||||
|
||||
config.before(:suite) do
|
||||
ActiveRecord::Base.configurations['test'] = (YAML::load(File.open("spec/fixtures/database.yml"))['test'])
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user