rumor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +61 -0
- data/Rakefile +1 -0
- data/lib/rumor.rb +30 -0
- data/lib/rumor/async/resque.rb +38 -0
- data/lib/rumor/channel.rb +27 -0
- data/lib/rumor/rumor.rb +119 -0
- data/lib/rumor/source.rb +31 -0
- data/lib/rumor/version.rb +3 -0
- data/rumor.gemspec +26 -0
- data/spec/rumor/channel_spec.rb +49 -0
- data/spec/rumor_spec.rb +72 -0
- data/spec/spec_helper.rb +7 -0
- metadata +161 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Mattias Putman
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Rumor
|
2
|
+
|
3
|
+
All event processing is done asynchronously. Different adapters can be used to handle the processing (currently only Resque, default).
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
### Let those controllers rumor
|
8
|
+
|
9
|
+
**First**
|
10
|
+
|
11
|
+
Add rumor capabilities to your controller by adding `include Rumor::Source`.
|
12
|
+
|
13
|
+
**Then**
|
14
|
+
|
15
|
+
Add rumor instructions in your controller methods.
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# Rumor about an event.
|
19
|
+
rumor(:upgrade).on('john').mention(plan: plan.id).tag(:important).spread
|
20
|
+
# Rumor only to certain channels.
|
21
|
+
# Rumor whatever you want.
|
22
|
+
rumor(:profit).tag(:finally).spread only: [:mixpanel]
|
23
|
+
```
|
24
|
+
|
25
|
+
**Where does the rumor come from?**
|
26
|
+
|
27
|
+
The `rumor` method is a regular method defined in your controller (defined by including `Source`). You can use it to add default values to your rumors.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
class AccountController
|
31
|
+
include Rumor::Source
|
32
|
+
|
33
|
+
def rumor event
|
34
|
+
super(event).on(current_user.id).tag(:accounts)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
### Adding Rumor Channels
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
class MixpanelChannel < Rumor::Channel
|
43
|
+
|
44
|
+
# This is just a regular class.
|
45
|
+
def initialize tracker
|
46
|
+
@tracker = tracker
|
47
|
+
end
|
48
|
+
|
49
|
+
# Matches only upgrade events with the important tag.
|
50
|
+
on(:upgrade) do |rumor|
|
51
|
+
rumor.subject # => 'john'
|
52
|
+
rumor.tag # => [:important]
|
53
|
+
plan = Plan.find rumor.mentions[:plan]
|
54
|
+
@tracker.track 'Upgraded Account', to: plan.name
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Register the channel.
|
59
|
+
tracker = Mixpanel::Tracker.new Environment::MIXPANEL_TOKEN,
|
60
|
+
Rumor.register :mixpanel, MixpanelChannel.new tracker
|
61
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/rumor.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "rumor/version"
|
2
|
+
require 'rumor/channel'
|
3
|
+
require 'rumor/rumor'
|
4
|
+
require 'rumor/source'
|
5
|
+
|
6
|
+
module Rumor
|
7
|
+
class << self
|
8
|
+
attr_accessor :channels
|
9
|
+
attr_accessor :async_handler
|
10
|
+
end
|
11
|
+
|
12
|
+
@channels = {}
|
13
|
+
|
14
|
+
# Internal: Register a new channel.
|
15
|
+
def self.register name, channel
|
16
|
+
self.channels[name] = channel
|
17
|
+
end
|
18
|
+
|
19
|
+
# Internal: Spread a rumor to required channels.
|
20
|
+
def self.spread rumor
|
21
|
+
self.channels.each do |name, channel|
|
22
|
+
channel.send rumor if rumor.to?(name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Internal: Spread a rumor asynchronously.
|
27
|
+
def self.spread_async rumor
|
28
|
+
self.async_handler.spread_async rumor
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'resque'
|
2
|
+
|
3
|
+
module Rumor
|
4
|
+
module Async
|
5
|
+
|
6
|
+
class Resque
|
7
|
+
|
8
|
+
def self.spread_async rumor
|
9
|
+
::Resque.enqueue Job, rumor.to_h
|
10
|
+
end
|
11
|
+
|
12
|
+
class Job
|
13
|
+
@queue = :rumor
|
14
|
+
|
15
|
+
def self.perform rumor_hash
|
16
|
+
hash = hash_to_symbols rumor_hash
|
17
|
+
hash[:mentions] = hash_to_symbols hash[:mentions]
|
18
|
+
hash[:tags].map! &:to_sym
|
19
|
+
hash[:time] = Time.new hash[:time]
|
20
|
+
# Deserialize the rumor.
|
21
|
+
rumor = Rumor.from_h hash
|
22
|
+
# Spread again.
|
23
|
+
::Rumor.spread rumor
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.hash_to_symbols hash
|
27
|
+
symbol_hash = {}
|
28
|
+
hash.each do |k,v|
|
29
|
+
symbol_hash[k.to_sym] = v
|
30
|
+
end
|
31
|
+
symbol_hash
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Rumor.async_handler = Rumor::Async::Resque
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rumor
|
2
|
+
|
3
|
+
# Public: A Channel is a module that can be included in any class.
|
4
|
+
#
|
5
|
+
# It provides an 'on' method for matching rumors by event.
|
6
|
+
class Channel
|
7
|
+
class << self
|
8
|
+
attr_accessor :handlers
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.inherited klass
|
12
|
+
klass.handlers = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
# Internal: Send a Rumor to this channel.
|
16
|
+
def send rumor
|
17
|
+
handle = self.class.handlers[rumor.event.to_sym]
|
18
|
+
raise "No handler for event #{rumor.event}" unless handle
|
19
|
+
self.instance_exec rumor, &handle
|
20
|
+
end
|
21
|
+
|
22
|
+
# Public: Catch all events with specified name.
|
23
|
+
def self.on event, &handle
|
24
|
+
self.handlers[event] = handle
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/rumor/rumor.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
module Rumor
|
2
|
+
|
3
|
+
# Public: A Rumor represents some knowledge about
|
4
|
+
# something that can be spread.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# Rumor.new(:upgraded).on('user1').mention(plan: :tasty).tag(:business).spread
|
9
|
+
#
|
10
|
+
class Rumor
|
11
|
+
|
12
|
+
# Public: A rumor has an event name.
|
13
|
+
# this is required for every rumor.
|
14
|
+
attr_accessor :event
|
15
|
+
|
16
|
+
# Public: Wo the rumor is about
|
17
|
+
# This is mostly the user that executed the event.
|
18
|
+
attr_accessor :subject
|
19
|
+
|
20
|
+
# Public: The mentions of the rumor.
|
21
|
+
# All the information a rumor mentions.
|
22
|
+
attr_accessor :mentions
|
23
|
+
|
24
|
+
# Public: Every rumor has some tags.
|
25
|
+
# A Rumor can be categorized in multiple optional tags.
|
26
|
+
attr_accessor :tags
|
27
|
+
|
28
|
+
# Public: Create Rumor from hash.
|
29
|
+
def self.from_h hash
|
30
|
+
self.new(hash[:event], hash[:time]).
|
31
|
+
mention(hash[:mentions]).
|
32
|
+
on(hash[:subject]).
|
33
|
+
tag(*hash[:tags])
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Creates a new rumor.
|
37
|
+
#
|
38
|
+
# event - event of the rumor.
|
39
|
+
def initialize event, time = nil
|
40
|
+
@event = event
|
41
|
+
@tags = []
|
42
|
+
@mentions = {}
|
43
|
+
@time = time
|
44
|
+
end
|
45
|
+
|
46
|
+
# Public: Tell who/what the rumor is concerning.
|
47
|
+
def on subject
|
48
|
+
@subject = subject
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
# Public: Mention some things in the rumor.
|
53
|
+
# Merges with already mentioned information.
|
54
|
+
def mention mentions = {}
|
55
|
+
@mentions.merge!(mentions) do |key, old_val, new_val|
|
56
|
+
if old.kind_of?(Array)
|
57
|
+
old_val + new_val
|
58
|
+
elsif old.kind_of?(Hash)
|
59
|
+
old_val.merge new_val
|
60
|
+
else
|
61
|
+
new_val
|
62
|
+
end
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: Add some tags to the rumor.
|
68
|
+
def tag *tags
|
69
|
+
@tags += tags
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
# Public: Copy a rumor while altering information.
|
74
|
+
def copy &alter
|
75
|
+
Rumor.new(hash).tap &alter
|
76
|
+
end
|
77
|
+
|
78
|
+
# Spread the rumor to all applicable channels.
|
79
|
+
#
|
80
|
+
# conditions - some conditions on the spreading (Hash).
|
81
|
+
# :only - The channels to spread to (and none other).
|
82
|
+
# :except - The channels not to spread to.
|
83
|
+
#
|
84
|
+
# Returns nothing.
|
85
|
+
def spread conditions = {}
|
86
|
+
@time = Time.now.utc
|
87
|
+
@only = conditions[:only]
|
88
|
+
@except = conditions[:except]
|
89
|
+
::Rumor.spread_async self
|
90
|
+
end
|
91
|
+
|
92
|
+
# Public: The time the rumor was spread.
|
93
|
+
def time
|
94
|
+
@time
|
95
|
+
end
|
96
|
+
|
97
|
+
# Public: Whether to send this rumor to the given channel.
|
98
|
+
#
|
99
|
+
# channel - Name of the channel.
|
100
|
+
def to? channel
|
101
|
+
(!@only && !@except) ||
|
102
|
+
(@only && @only.include?(channel)) ||
|
103
|
+
(@except && !@except.include?(channel))
|
104
|
+
end
|
105
|
+
|
106
|
+
# Public: Rumor in hash form.
|
107
|
+
#
|
108
|
+
# Returns the rumor converted to a Hash.
|
109
|
+
def to_h
|
110
|
+
{
|
111
|
+
event: event,
|
112
|
+
subject: subject,
|
113
|
+
mentions: mentions,
|
114
|
+
tags: tags,
|
115
|
+
time: time
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/rumor/source.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rumor
|
2
|
+
|
3
|
+
# Public: Include this module everywhere you want to be
|
4
|
+
# able to rumor. This gives you the benefit that the rumor
|
5
|
+
# method can easily be overrided.
|
6
|
+
#
|
7
|
+
# Exampe:
|
8
|
+
#
|
9
|
+
# class Controller
|
10
|
+
# include Rumor::Rumoring
|
11
|
+
#
|
12
|
+
# def rumor subject
|
13
|
+
# super.on(current_user)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# def upgrade
|
17
|
+
# # some code
|
18
|
+
# rumor(:upgraded).mention(plan: :basic).spread only: :kissmetrics
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
module Source
|
23
|
+
|
24
|
+
# Public: Acts as a specialized factory for rumors.
|
25
|
+
#
|
26
|
+
# Returns a new Rumor.
|
27
|
+
def rumor event
|
28
|
+
Rumor.new(event)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/rumor.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rumor/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "rumor"
|
8
|
+
gem.version = Rumor::VERSION
|
9
|
+
gem.authors = ["Mattias Putman"]
|
10
|
+
gem.email = ["mattias.putman@gmail.com"]
|
11
|
+
gem.description = %q{Rumor}
|
12
|
+
gem.summary = %q{Rumor}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency 'resque'
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
gem.add_development_dependency 'guard'
|
23
|
+
gem.add_development_dependency 'guard-minitest'
|
24
|
+
gem.add_development_dependency 'mocha'
|
25
|
+
gem.add_development_dependency 'rb-fsevent', '~> 0.9'
|
26
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestChannel < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
class ExampleChannel < Rumor::Channel
|
6
|
+
def helper
|
7
|
+
"helper"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@channel = ExampleChannel.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_define_handler
|
16
|
+
assert_equal ExampleChannel.handlers, {}
|
17
|
+
handle = proc {}
|
18
|
+
ExampleChannel.on(:upgrade, &handle)
|
19
|
+
assert_equal ExampleChannel.handlers[:upgrade], handle
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_send_rumor
|
23
|
+
upgrade = proc {}
|
24
|
+
install = proc { |rumor| @rumor = rumor }
|
25
|
+
ExampleChannel.on(:upgrade, &upgrade)
|
26
|
+
ExampleChannel.on(:install, &install)
|
27
|
+
|
28
|
+
@channel.send Rumor::Rumor.new(:install).
|
29
|
+
tag(:business).
|
30
|
+
on(:cool_user).
|
31
|
+
mention(plan: :enterprise)
|
32
|
+
|
33
|
+
rumor = @channel.instance_variable_get :@rumor
|
34
|
+
assert rumor.event == :install && rumor.tags == [:business] &&
|
35
|
+
rumor.mentions == { plan: :enterprise } && rumor.subject == :cool_user
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_use_methods
|
39
|
+
ExampleChannel.on(:method_test) do |rumor|
|
40
|
+
helper
|
41
|
+
end
|
42
|
+
@channel.expects(:helper).once
|
43
|
+
@channel.send Rumor::Rumor.new(:method_test)
|
44
|
+
end
|
45
|
+
|
46
|
+
def teardown
|
47
|
+
ExampleChannel.handlers = {}
|
48
|
+
end
|
49
|
+
end
|
data/spec/rumor_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestRumor < MiniTest::Unit::TestCase
|
4
|
+
include Rumor::Source
|
5
|
+
|
6
|
+
class ExampleChannel < Rumor::Channel
|
7
|
+
end
|
8
|
+
|
9
|
+
class IntegrationChannel < Rumor::Channel
|
10
|
+
def initialize delegate
|
11
|
+
@delegate = delegate
|
12
|
+
end
|
13
|
+
|
14
|
+
on(:upgrade) do |rumor|
|
15
|
+
@delegate.upgrade
|
16
|
+
end
|
17
|
+
|
18
|
+
on(:install) do |rumor|
|
19
|
+
@delegate.install
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup
|
24
|
+
@channel = ExampleChannel.new
|
25
|
+
@rumor = Rumor::Rumor.new(:upgrade).mention price: 8
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_channels_initialized
|
29
|
+
assert_equal Rumor.channels, {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_add_channel
|
33
|
+
Rumor.register :example, @channel
|
34
|
+
assert_equal Rumor.channels[:example], @channel
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_spread_both
|
38
|
+
left, right = ExampleChannel.new, ExampleChannel.new
|
39
|
+
Rumor.register :left, left
|
40
|
+
Rumor.register :right, right
|
41
|
+
left.expects(:send).with(@rumor).once
|
42
|
+
right.expects(:send).with(@rumor).once
|
43
|
+
Rumor.spread @rumor
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_spread_filter
|
47
|
+
left, right = ExampleChannel.new, ExampleChannel.new
|
48
|
+
@rumor.stubs(:to?).with(:left).returns true
|
49
|
+
@rumor.stubs(:to?).with(:right).returns false
|
50
|
+
Rumor.register :left, left
|
51
|
+
Rumor.register :right, right
|
52
|
+
left.expects(:send).with(@rumor).once
|
53
|
+
right.expects(:send).with(@rumor).never
|
54
|
+
Rumor.spread @rumor
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_spread_async
|
58
|
+
Rumor::Async::Resque.expects(:spread_async).with(@rumor).once
|
59
|
+
Rumor.spread_async @rumor
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_integration
|
63
|
+
channel1 = mock
|
64
|
+
Rumor.register :channel1, IntegrationChannel.new(channel1)
|
65
|
+
channel1.expects(:upgrade)
|
66
|
+
rumor(:upgrade).mention(plan: :enterprise).spread
|
67
|
+
end
|
68
|
+
|
69
|
+
def teardown
|
70
|
+
Rumor.channels = {}
|
71
|
+
end
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rumor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mattias Putman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: resque
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: guard
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: guard-minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: mocha
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rb-fsevent
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.9'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0.9'
|
110
|
+
description: Rumor
|
111
|
+
email:
|
112
|
+
- mattias.putman@gmail.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- Gemfile
|
119
|
+
- Guardfile
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- lib/rumor.rb
|
124
|
+
- lib/rumor/async/resque.rb
|
125
|
+
- lib/rumor/channel.rb
|
126
|
+
- lib/rumor/rumor.rb
|
127
|
+
- lib/rumor/source.rb
|
128
|
+
- lib/rumor/version.rb
|
129
|
+
- rumor.gemspec
|
130
|
+
- spec/rumor/channel_spec.rb
|
131
|
+
- spec/rumor_spec.rb
|
132
|
+
- spec/spec_helper.rb
|
133
|
+
homepage: ''
|
134
|
+
licenses: []
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ! '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 1.8.19
|
154
|
+
signing_key:
|
155
|
+
specification_version: 3
|
156
|
+
summary: Rumor
|
157
|
+
test_files:
|
158
|
+
- spec/rumor/channel_spec.rb
|
159
|
+
- spec/rumor_spec.rb
|
160
|
+
- spec/spec_helper.rb
|
161
|
+
has_rdoc:
|