bustle 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/README.md +216 -0
- data/Rakefile +11 -0
- data/bustle.gemspec +21 -0
- data/lib/bustle/version.rb +3 -0
- data/lib/bustle.rb +1 -0
- data/lib/specs/spec_helper.rb +8 -0
- metadata +107 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
# Bustle
|
2
|
+
|
3
|
+
Activities recording and retrieving using a simple Pub/Sub architecture.
|
4
|
+
|
5
|
+
The typical use cases are:
|
6
|
+
|
7
|
+
- Timeline (e.g. tracking activities such as posting and commenting for users)
|
8
|
+
- Logging
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'bustle'
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
### Configuration
|
21
|
+
|
22
|
+
First of all, you will need to configure Bustle. If you are using Rails, you can put the following code in an initializer (e.g. `config/initializers/bustle.rb`).
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
Bustle.config do |c|
|
26
|
+
# Specify an intepreter strategy for intepreting app data
|
27
|
+
# i.e. what your application uses for persistence
|
28
|
+
# Bustle ships with an ActiveRecord intepreter strategy
|
29
|
+
c.intepreter = Bustle::Intepreter::ActiveRecord
|
30
|
+
|
31
|
+
# Specify a storage strategy for storing activities
|
32
|
+
# Bustle ships with an ActiveRecord storage strategy
|
33
|
+
c.storage = Bustle::Storage::ActiveRecord
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
For ActiveRecord, you will need the following migration file:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class CreateBustleTables < ActiveRecord::Migration
|
41
|
+
def change
|
42
|
+
create_table :bustle_activities do |t|
|
43
|
+
t.string :reference_class
|
44
|
+
t.integer :reference_id
|
45
|
+
t.string :action
|
46
|
+
t.integer :publisher_id, :null => false
|
47
|
+
t.timestamps
|
48
|
+
end
|
49
|
+
|
50
|
+
create_table :bustle_publishers do |t|
|
51
|
+
t.string :reference_class, :null => false
|
52
|
+
t.integer :reference_id, :null => false
|
53
|
+
t.timestamps
|
54
|
+
end
|
55
|
+
|
56
|
+
create_table :bustle_subscribers do |t|
|
57
|
+
t.string :reference_class, :null => false
|
58
|
+
t.integer :reference_id, :null => false
|
59
|
+
t.timestamps
|
60
|
+
end
|
61
|
+
|
62
|
+
create_table :bustle_subscriptions do |t|
|
63
|
+
t.integer :publisher_id, :null => false
|
64
|
+
t.string :subscriber_id, :null => false
|
65
|
+
t.timestamps
|
66
|
+
end
|
67
|
+
|
68
|
+
add_index :bustle_activities, :publisher_id
|
69
|
+
add_index :bustle_publishers, [:reference_class, :reference_id], :unique => true
|
70
|
+
add_index :bustle_subscribers, [:reference_class, :reference_id], :unique => true
|
71
|
+
add_index :bustle_subscriptions, :publisher_id
|
72
|
+
add_index :bustle_subscriptions, :subscriber_id
|
73
|
+
add_index :bustle_subscriptions, [:publisher_id, :subscriber_id], :unique => true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
### Flow
|
79
|
+
|
80
|
+
Upon subscribing:
|
81
|
+
|
82
|
+
1. Subscriber registers itself if not already registered
|
83
|
+
2. Publisher registers itself if not already registered
|
84
|
+
3. A Subscription is created for Subscriber and Publisher
|
85
|
+
|
86
|
+
When activities occur:
|
87
|
+
|
88
|
+
1. Publisher registers itself if not already registered
|
89
|
+
2. Publisher publishes activity
|
90
|
+
|
91
|
+
### API
|
92
|
+
|
93
|
+
#### Register a Subscriber
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Bustle::Subscribers.add subscriber
|
97
|
+
|
98
|
+
# example
|
99
|
+
user = User.find(1)
|
100
|
+
Bustle::Subscribers.add user
|
101
|
+
```
|
102
|
+
|
103
|
+
#### Register a Publisher
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
Bustle::Publishers.add publisher
|
107
|
+
|
108
|
+
# example
|
109
|
+
post = Post.find(1)
|
110
|
+
Bustle::Publishers.add post
|
111
|
+
```
|
112
|
+
|
113
|
+
#### Create a Subscription
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
Bustle::Subscriptions.add bustle_publisher, bustle_subscriber
|
117
|
+
|
118
|
+
# example
|
119
|
+
publisher = Bustle::Publishers.find(Post.first)
|
120
|
+
subscriber = Bustle::Subscribers.find(User.first)
|
121
|
+
Bustle::Subscriptions.add publisher, subscriber
|
122
|
+
```
|
123
|
+
|
124
|
+
#### Find a Subscriber/Publisher/Subscription
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
Bustle::Subscribers.find subscriber
|
128
|
+
Bustle::Publishers.find publisher
|
129
|
+
Bustle::Subscriptions.find bustle_publisher, bustle_subscriber # => Bustle::Subscription
|
130
|
+
Bustle::Subscriptions.find bustle_publisher # => an array of Bustle::Subscription for the publisher
|
131
|
+
Bustle::Subscriptions.find bustle_subscriber # => an array of Bustle::Subscription for the subscriber
|
132
|
+
```
|
133
|
+
|
134
|
+
#### Remove a Subscriber/Publisher/Subscription
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
Bustle::Subscribers.remove subscriber
|
138
|
+
Bustle::Publishers.remove publisher
|
139
|
+
Bustle::Subscriptions.remove bustle_publisher, bustle_subscriber
|
140
|
+
```
|
141
|
+
|
142
|
+
Or:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
Bustle::Subscribers.find(subscriber).destroy
|
146
|
+
Bustle::Publishers.find(publisher).destroy
|
147
|
+
Bustle::Subscriptions.find(bustle_publisher, bustle_subscriber).destroy
|
148
|
+
```
|
149
|
+
|
150
|
+
#### Publish an Activity
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
Bustle::Activities.add bustle_publisher, action, activity
|
154
|
+
# or
|
155
|
+
Bustle::Publisher.publish action, activity
|
156
|
+
|
157
|
+
# example
|
158
|
+
post = Post.find(1)
|
159
|
+
comment = post.comments.add(:content => "I'm a comment")
|
160
|
+
Bustle::Publishers.add post
|
161
|
+
publisher = Bustle::Publishers.find post
|
162
|
+
publisher.publish 'new', comment
|
163
|
+
```
|
164
|
+
|
165
|
+
#### Activities
|
166
|
+
|
167
|
+
##### Retrieve Activities for a Subscriber
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
Bustle::Activities.for bustle_subscriber
|
171
|
+
# or
|
172
|
+
Bustle::Subscriber.activities
|
173
|
+
|
174
|
+
# example
|
175
|
+
subscriber = Bustle::Subscribers.find(User.first)
|
176
|
+
subscriber.activities
|
177
|
+
```
|
178
|
+
|
179
|
+
##### Retrieve Activities by a Publisher
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
Bustle::Activities.by bustle_publisher
|
183
|
+
# or
|
184
|
+
Bustle::Publisher.activities
|
185
|
+
|
186
|
+
# example
|
187
|
+
publisher = Bustle::Publishers.find(Post.first)
|
188
|
+
publisher.activities
|
189
|
+
```
|
190
|
+
|
191
|
+
##### Activities Filtering
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
Bustle::Activities.for(bustle_subscriber).filter :key => :value
|
195
|
+
# or
|
196
|
+
Bustle::Subscriber.activities.filter :key => :value
|
197
|
+
|
198
|
+
# example
|
199
|
+
subscriber = Bustle::Subscribers.find(User.first)
|
200
|
+
subscriber.activities.filter :action => 'new'
|
201
|
+
subscriber.activities.by(publisher).filter(:action => 'new')
|
202
|
+
```
|
203
|
+
|
204
|
+
Activities are normal enumerable objects from your chosen storage, so in ActiveRecord's case, you may use any Arel methods to query the result:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
subscriber.activities.filter(:action => 'new').order('created_at ASC').limit(10)
|
208
|
+
```
|
209
|
+
|
210
|
+
## License
|
211
|
+
|
212
|
+
This gem is released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
213
|
+
|
214
|
+
## Author
|
215
|
+
|
216
|
+
[Fred Wu](https://github.com/fredwu), originally built for [500 Startups](http://500.co).
|
data/Rakefile
ADDED
data/bustle.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/bustle/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Fred Wu"]
|
6
|
+
gem.email = ["ifredwu@gmail.com"]
|
7
|
+
gem.description = %q{Activities recording and retrieving using a simple Pub/Sub architecture.}
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.homepage = "https://github.com/fredwu/bustle"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "bustle"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Bustle::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency 'rake'
|
19
|
+
gem.add_development_dependency 'simplecov'
|
20
|
+
gem.add_development_dependency 'minitest-colorize'
|
21
|
+
end
|
data/lib/bustle.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bustle/version"
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bustle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Fred Wu
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
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: simplecov
|
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: minitest-colorize
|
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
|
+
description: Activities recording and retrieving using a simple Pub/Sub architecture.
|
63
|
+
email:
|
64
|
+
- ifredwu@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- Gemfile
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- bustle.gemspec
|
74
|
+
- lib/bustle.rb
|
75
|
+
- lib/bustle/version.rb
|
76
|
+
- lib/specs/spec_helper.rb
|
77
|
+
homepage: https://github.com/fredwu/bustle
|
78
|
+
licenses: []
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
hash: 3392583862411400704
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
hash: 3392583862411400704
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 1.8.24
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Activities recording and retrieving using a simple Pub/Sub architecture.
|
107
|
+
test_files: []
|