ledger 0.0.1 → 0.0.3
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/README.md +166 -2
- data/ledger.gemspec +4 -1
- data/lib/ledger.rb +13 -1
- data/lib/ledger/creates_events.rb +48 -0
- data/lib/ledger/event.rb +19 -0
- data/lib/ledger/has_events.rb +26 -0
- data/lib/ledger/version.rb +1 -1
- metadata +23 -4
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# Ledger
|
2
2
|
|
3
|
-
|
3
|
+
Does your app have the concept of accounts, with multiple users per account?
|
4
|
+
|
5
|
+
Yes?
|
6
|
+
|
7
|
+
Great.
|
8
|
+
|
9
|
+
Ledger will easily allow you to create an activity stream of user events on a per account basis.
|
4
10
|
|
5
11
|
## Installation
|
6
12
|
|
@@ -18,7 +24,165 @@ Or install it yourself as:
|
|
18
24
|
|
19
25
|
## Usage
|
20
26
|
|
21
|
-
|
27
|
+
Start by adding the `HasEvents` module to your account object.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
class Account < ActiveRecord::Base
|
31
|
+
…
|
32
|
+
include Ledger::HasEvents
|
33
|
+
…
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
Add in the `CreatesEvents` module to your controller.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class CategoriesController < ApplicationController
|
41
|
+
…
|
42
|
+
include Ledger::CreatesEvents
|
43
|
+
…
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
Now all you need to do is call `#create_event` when you do something.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
def update
|
51
|
+
@category.update_attributes! params[:category]
|
52
|
+
create_event :updateated, @category
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
Retrieve your event stream like so
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
account.event_stream.each do |e|
|
60
|
+
puts "#{a.actor['name']} #{a.action} #{a.object} #{a.data['name']}"
|
61
|
+
end
|
62
|
+
"Mal Curtis updated Category Food"
|
63
|
+
```
|
64
|
+
|
65
|
+
`#event_stream` brings back the last 10 events. Send through an integer to get more.
|
66
|
+
|
67
|
+
Each event has the following (by default, for options see further down).
|
68
|
+
|
69
|
+
```
|
70
|
+
{
|
71
|
+
"key"=>"category_updated",
|
72
|
+
"action"=>"updated",
|
73
|
+
"object"=>"Category",
|
74
|
+
"actor"=>{
|
75
|
+
"id"=>1,
|
76
|
+
"email"=>"mal@mal.co.nz",
|
77
|
+
"name"=>"Mal Curtis"
|
78
|
+
},
|
79
|
+
"data"=>{
|
80
|
+
"id"=>1515,
|
81
|
+
"name"=>"Food"
|
82
|
+
},
|
83
|
+
"created_at"=>2013-03-03 09:28:59 +1300
|
84
|
+
}
|
85
|
+
```
|
86
|
+
|
87
|
+
Ledger isn’t opinionated about how you display your events in your app. You’ll need to figure that one out.
|
88
|
+
|
89
|
+
## Customizing
|
90
|
+
|
91
|
+
### Accounts & Users
|
92
|
+
|
93
|
+
Ledger expects there to be a `current_account` and `current_user` method when creating an event. If this doesn’t suit your app, smash this into an initializer.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Ledger.configure do |config|
|
97
|
+
config.event_scope_method = :current_account # Or whatevs
|
98
|
+
config.event_actor_method = :current_user # as above
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
### Moar object data
|
103
|
+
|
104
|
+
Ledger will try and add `id`, `email` and `name` from your user object and `id` and `name` from the object passed to `#create_event`. If you don’t have some of these methods, or want to add more information, just define `#event_details` and return a hash.
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
class User
|
108
|
+
include Ledger::HasEvents
|
109
|
+
def event_details
|
110
|
+
{ id: id, email: email, username: username }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Category
|
115
|
+
def event_details
|
116
|
+
{ id: id, parent: parent_id, description: description }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
### Moar event data
|
122
|
+
|
123
|
+
Want to send more information about events? Just send through the information at the end of the `#create_event` call.
|
124
|
+
|
125
|
+
```
|
126
|
+
create_event :state_changed, @category, from: from_state, to: @category.state
|
127
|
+
```
|
128
|
+
```
|
129
|
+
|
130
|
+
{
|
131
|
+
"key"=>"category_state_changed",
|
132
|
+
"action"=>"state_changed",
|
133
|
+
"object"=>"Category",
|
134
|
+
"actor"=>{
|
135
|
+
"id"=>1,
|
136
|
+
"email"=>"mal@mal.co.nz",
|
137
|
+
"name"=>"Mal Curtis"
|
138
|
+
},
|
139
|
+
"data"=>{
|
140
|
+
"id"=>1515,
|
141
|
+
"name"=>"Food",
|
142
|
+
"from"=>"available",
|
143
|
+
"to"=>"unavailable"
|
144
|
+
},
|
145
|
+
"created_at"=>2013-03-03 09:28:59 +1300
|
146
|
+
}
|
147
|
+
```
|
148
|
+
|
149
|
+
|
150
|
+
### Redis connection
|
151
|
+
|
152
|
+
Ledger defaults to `$redis`. If you want to set this manually, customize it in an initializer. Here's an example:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
Ledger.configure do |config|
|
156
|
+
uri = URI.parse(ENV["REDISTOGO_URL"] || 'redis://127.0.0.1:6379')
|
157
|
+
config.redis = Redis.new(
|
158
|
+
:host => uri.host,
|
159
|
+
:port => uri.port,
|
160
|
+
:password => uri.password
|
161
|
+
)
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
### Manual Events
|
166
|
+
|
167
|
+
You can add an event manually by creating an instance of `Ledger::Event`, then adding than in via `account.add_event`.
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
new_event = Ledger::Event.new key: "manual_event", data: { some: "thing" }
|
171
|
+
account.add_event new_event
|
172
|
+
```
|
173
|
+
|
174
|
+
### Direct Redis access
|
175
|
+
|
176
|
+
You can access redis directly through `#events`. This will be a [Nest](https://github.com/soveran/nest) instance, and you can call on this, or use its naming schema to do some other magic.
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
# Trim the events down to the last 100 events
|
180
|
+
account.events.ltrim 0, 100
|
181
|
+
|
182
|
+
# Create a new redis key (account:xxx:events:something_else)
|
183
|
+
account.events["something_else"].lpush "Some data"
|
184
|
+
```
|
185
|
+
|
22
186
|
|
23
187
|
## Contributing
|
24
188
|
|
data/ledger.gemspec
CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |gem|
|
|
5
5
|
gem.authors = ["Mal Curtis"]
|
6
6
|
gem.email = ["mal@sitepoint.com"]
|
7
7
|
gem.description = %q{Redis backed account activity streams}
|
8
|
-
gem.summary = %q{
|
8
|
+
gem.summary = %q{Creates a per account activity stream for your Saas Ruby app}
|
9
9
|
gem.homepage = ""
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
@@ -14,4 +14,7 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "ledger"
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Ledger::VERSION
|
17
|
+
|
18
|
+
# Declaritive Redis Keys
|
19
|
+
gem.add_runtime_dependency "nest"
|
17
20
|
end
|
data/lib/ledger.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
require "ledger/version"
|
2
|
+
require 'ledger/event'
|
3
|
+
require 'ledger/has_events'
|
4
|
+
require 'ledger/creates_events'
|
2
5
|
|
3
6
|
module Ledger
|
4
|
-
|
7
|
+
mattr_accessor :event_scope_method, :event_actor_method, :redis
|
8
|
+
|
9
|
+
@@event_scope_method = :current_account
|
10
|
+
@@event_actor_method = :current_user
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def configure
|
14
|
+
yield self
|
15
|
+
end
|
16
|
+
end
|
5
17
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Ledger
|
4
|
+
module CreatesEvents
|
5
|
+
def create_event action, object, data = {}
|
6
|
+
unless event_scope.respond_to? :add_event
|
7
|
+
raise "#{Ledger.event_scope_method} does not respond to #add_event.
|
8
|
+
Either include Ledger::HasEvents in that scope, or set the
|
9
|
+
'event_scope_method' in your Ledger configuration to an
|
10
|
+
object that does."
|
11
|
+
end
|
12
|
+
|
13
|
+
object_name = object.class.name.downcase
|
14
|
+
key = [object_name, action].join('_')
|
15
|
+
|
16
|
+
details = {
|
17
|
+
key: key,
|
18
|
+
action: action,
|
19
|
+
object: object_name,
|
20
|
+
actor: {},
|
21
|
+
data: data || {}
|
22
|
+
}
|
23
|
+
|
24
|
+
details[:data].merge! object.respond_to?(:event_details) ? \
|
25
|
+
object.event_details : \
|
26
|
+
{ id: object.id, name: object.name }
|
27
|
+
|
28
|
+
details[:actor].merge! event_actor.respond_to?(:event_details) ? \
|
29
|
+
event_actor.event_details : \
|
30
|
+
{ id: event_actor.id, email: event_actor.email, name: event_actor.name }
|
31
|
+
|
32
|
+
event_scope.add_event Ledger::Event.new(details)
|
33
|
+
end
|
34
|
+
|
35
|
+
def event_scope
|
36
|
+
send(Ledger.event_scope_method)
|
37
|
+
rescue NoMethodError
|
38
|
+
raise "Hey, I tried calling #{Ledger.event_scope_method} but it doesn't exist. You’ll need to set the `event_scope_method` configuration value to the method that returns your current account object."
|
39
|
+
end
|
40
|
+
|
41
|
+
def event_actor
|
42
|
+
send(Ledger.event_actor_method)
|
43
|
+
rescue NoMethodError
|
44
|
+
raise "Hey, I tried calling #{Ledger.event_scope_method} but it doesn't exist. You’ll need to set the `event_actor_method` configuration value to the method that returns your current user object."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
data/lib/ledger/event.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Ledger
|
2
|
+
class Event
|
3
|
+
attr_accessor :actor, :key, :action, :object, :data, :created_at
|
4
|
+
|
5
|
+
def initialize opts
|
6
|
+
opts.each do |attr, value|
|
7
|
+
self.send("#{attr}=", value) if respond_to?("#{attr}=")
|
8
|
+
end
|
9
|
+
self.created_at = Time.now
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def from_json json
|
14
|
+
require 'json'
|
15
|
+
self.new JSON.parse json
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'nest'
|
2
|
+
module Ledger
|
3
|
+
module HasEvents
|
4
|
+
def rdb
|
5
|
+
Nest.new(self.class.name.downcase)[to_param]
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.rdb
|
9
|
+
Nest.new(name, Ledger.redis)
|
10
|
+
end
|
11
|
+
|
12
|
+
def event_stream length = 10
|
13
|
+
events.lrange(0, length).map do |json|
|
14
|
+
Ledger::Event.from_json json
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_event event
|
19
|
+
events.lpush event.to_json
|
20
|
+
end
|
21
|
+
|
22
|
+
def events
|
23
|
+
rdb[:events]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/ledger/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ledger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
13
|
-
dependencies:
|
12
|
+
date: 2013-03-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nest
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
description: Redis backed account activity streams
|
15
31
|
email:
|
16
32
|
- mal@sitepoint.com
|
@@ -25,6 +41,9 @@ files:
|
|
25
41
|
- Rakefile
|
26
42
|
- ledger.gemspec
|
27
43
|
- lib/ledger.rb
|
44
|
+
- lib/ledger/creates_events.rb
|
45
|
+
- lib/ledger/event.rb
|
46
|
+
- lib/ledger/has_events.rb
|
28
47
|
- lib/ledger/version.rb
|
29
48
|
homepage: ''
|
30
49
|
licenses: []
|
@@ -49,6 +68,6 @@ rubyforge_project:
|
|
49
68
|
rubygems_version: 1.8.23
|
50
69
|
signing_key:
|
51
70
|
specification_version: 3
|
52
|
-
summary:
|
71
|
+
summary: Creates a per account activity stream for your Saas Ruby app
|
53
72
|
test_files: []
|
54
73
|
has_rdoc:
|