rediline 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rvmrc +2 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +63 -0
- data/README.md +143 -0
- data/Rakefile +34 -0
- data/VERSION +1 -0
- data/init.rb +4 -0
- data/lib/rediline.rb +16 -0
- data/lib/rediline/entry.rb +65 -0
- data/lib/rediline/object.rb +57 -0
- data/lib/rediline/redis.rb +35 -0
- data/lib/rediline/timeline.rb +7 -0
- data/lib/rediline/timeline/user.rb +42 -0
- data/lib/rediline/user.rb +15 -0
- data/rediline.gemspec +89 -0
- data/spec/entry_spec.rb +127 -0
- data/spec/object_spec.rb +99 -0
- data/spec/redis_spec.rb +63 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/timeline.rb +34 -0
- data/spec/support/timeline_owner.rb +34 -0
- data/spec/support/user.rb +20 -0
- data/spec/timeline/user_spec.rb +71 -0
- data/spec/timeline_spec.rb +6 -0
- data/spec/user_spec.rb +13 -0
- metadata +169 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "redis", '2.0.7'
|
4
|
+
gem "redis-namespace", '0.10.0'
|
5
|
+
gem "json"
|
6
|
+
gem "i18n"
|
7
|
+
gem "activesupport", "~> 3.0.0"
|
8
|
+
gem "activemodel", '~> 3.0.0'
|
9
|
+
|
10
|
+
group :development do
|
11
|
+
gem "jeweler"
|
12
|
+
end
|
13
|
+
|
14
|
+
group :test do
|
15
|
+
gem "rspec", '~> 2.0.0.beta'
|
16
|
+
gem "rspec-rails", '~> 2.0.0.beta'
|
17
|
+
gem "mocha", '0.9.8'
|
18
|
+
gem "timecop", '0.3.5'
|
19
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activemodel (3.0.0)
|
5
|
+
activesupport (= 3.0.0)
|
6
|
+
builder (~> 2.1.2)
|
7
|
+
i18n (~> 0.4.1)
|
8
|
+
activesupport (3.0.0)
|
9
|
+
builder (2.1.2)
|
10
|
+
diff-lcs (1.1.2)
|
11
|
+
gemcutter (0.6.1)
|
12
|
+
git (1.2.5)
|
13
|
+
i18n (0.4.1)
|
14
|
+
jeweler (1.4.0)
|
15
|
+
gemcutter (>= 0.1.0)
|
16
|
+
git (>= 1.2.5)
|
17
|
+
rubyforge (>= 2.0.0)
|
18
|
+
json (1.4.6)
|
19
|
+
json_pure (1.4.6)
|
20
|
+
mocha (0.9.8)
|
21
|
+
rake
|
22
|
+
nokogiri (1.4.3.1)
|
23
|
+
rack (1.2.1)
|
24
|
+
rack-test (0.5.4)
|
25
|
+
rack (>= 1.0)
|
26
|
+
rake (0.8.7)
|
27
|
+
redis (2.0.7)
|
28
|
+
redis-namespace (0.10.0)
|
29
|
+
redis (< 3.0.0)
|
30
|
+
rspec (2.0.0.beta.18)
|
31
|
+
rspec-core (= 2.0.0.beta.18)
|
32
|
+
rspec-expectations (= 2.0.0.beta.18)
|
33
|
+
rspec-mocks (= 2.0.0.beta.18)
|
34
|
+
rspec-core (2.0.0.beta.18)
|
35
|
+
rspec-expectations (2.0.0.beta.18)
|
36
|
+
diff-lcs (>= 1.1.2)
|
37
|
+
rspec-mocks (2.0.0.beta.18)
|
38
|
+
rspec-rails (2.0.0.beta.18)
|
39
|
+
rspec (>= 2.0.0.beta.14)
|
40
|
+
webrat (>= 0.7.0)
|
41
|
+
rubyforge (2.0.4)
|
42
|
+
json_pure (>= 1.1.7)
|
43
|
+
timecop (0.3.5)
|
44
|
+
webrat (0.7.1)
|
45
|
+
nokogiri (>= 1.2.0)
|
46
|
+
rack (>= 1.0)
|
47
|
+
rack-test (>= 0.5.3)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
activemodel (~> 3.0.0)
|
54
|
+
activesupport (~> 3.0.0)
|
55
|
+
i18n
|
56
|
+
jeweler
|
57
|
+
json
|
58
|
+
mocha (= 0.9.8)
|
59
|
+
redis (= 2.0.7)
|
60
|
+
redis-namespace (= 0.10.0)
|
61
|
+
rspec (~> 2.0.0.beta)
|
62
|
+
rspec-rails (~> 2.0.0.beta)
|
63
|
+
timecop (= 0.3.5)
|
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# RediLine
|
2
|
+
*Redis Backed Timeline*
|
3
|
+
|
4
|
+
Rediline is a ruby library which intends to allow you to create timelines for your users in ruby.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add the following to your Gemfile :
|
9
|
+
|
10
|
+
gem "rediline"
|
11
|
+
|
12
|
+
Bundle install it and you're done, it's installed.
|
13
|
+
|
14
|
+
## Configuring the user model
|
15
|
+
|
16
|
+
Your user model should look like the following :
|
17
|
+
|
18
|
+
class User < ActiveRecord::Base
|
19
|
+
include Redline::User
|
20
|
+
|
21
|
+
rediline :timeline do
|
22
|
+
list :egocentric do
|
23
|
+
[user]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
This will create a timeline which will be called "timeline", with one list named "egocentric".
|
29
|
+
In this list, you must return an array of all the users which will see the event created there.
|
30
|
+
|
31
|
+
For exemple, if your users have friends, you could do the following :
|
32
|
+
|
33
|
+
class User < ActiveRecord::Base
|
34
|
+
include Redline::User
|
35
|
+
|
36
|
+
rediline :timeline do
|
37
|
+
list :egocentric do
|
38
|
+
[user]
|
39
|
+
end
|
40
|
+
|
41
|
+
list :public do
|
42
|
+
user.friends.all
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
With this, any of your users will have two lists : an "egocentric" one, which will contain all the actions made by this same user.
|
48
|
+
And a "public" one, which will contain all the actions made by this user's friends.
|
49
|
+
|
50
|
+
You can retrieve a list's actions with the each method.
|
51
|
+
|
52
|
+
User.first.timeline.each(:egocentric) do |action|
|
53
|
+
p action.inspect
|
54
|
+
end
|
55
|
+
|
56
|
+
## Configuring the objects models and triggering events
|
57
|
+
|
58
|
+
You can potentially trigger events in any kind of model, whether they are linked to an ORM or not.
|
59
|
+
However, when including `Rediline::Object`, your model should be compatible with `ActiveModel::Callbacks`.
|
60
|
+
|
61
|
+
Here's what your model could look like :
|
62
|
+
|
63
|
+
class Post < ActiveRecord::Base
|
64
|
+
include Redline::Object
|
65
|
+
|
66
|
+
redline :timeline,
|
67
|
+
:user => :owner,
|
68
|
+
:verb => :created,
|
69
|
+
:when => :after_create
|
70
|
+
end
|
71
|
+
|
72
|
+
An after_create event will be added to this model and triggered every time a new post is created.
|
73
|
+
By default, we rely on the "user" method. But you can overwrite it to anything else like we do with "owner" here.
|
74
|
+
|
75
|
+
You can also use procs to define the values.
|
76
|
+
|
77
|
+
class Post < ActiveRecord::Base
|
78
|
+
include Redline::Object
|
79
|
+
|
80
|
+
redline :timeline,
|
81
|
+
:user => lambda {|post| post.owner },
|
82
|
+
:verb => :created,
|
83
|
+
:when => :after_create
|
84
|
+
end
|
85
|
+
|
86
|
+
## Configuration
|
87
|
+
|
88
|
+
By default, we use localhost:6379 as the redis server with the namespace "rediline".
|
89
|
+
However, you can change that.
|
90
|
+
|
91
|
+
Rediline has a redis setter which can be given a string or a Redis object.
|
92
|
+
This means if you're already using Redis in your app, Rediline can re-use the existing connection.
|
93
|
+
|
94
|
+
String: `Rediline.redis = 'localhost:6379'`
|
95
|
+
Redis: `Resque.redis = $redis`
|
96
|
+
|
97
|
+
In a rails app, I have an initializer in `config/initializers/rediline.rb` where I load `config/rediline.yml` and set the redis information appropriately.
|
98
|
+
|
99
|
+
My rediline.yml file is the following :
|
100
|
+
|
101
|
+
development:
|
102
|
+
host: localhost
|
103
|
+
port: 6379
|
104
|
+
test:
|
105
|
+
host: localhost
|
106
|
+
port: 6379
|
107
|
+
|
108
|
+
And the initializer :
|
109
|
+
|
110
|
+
rediline_config = YAML::load(Rails.root.join('config', 'rediline.yml').read)[Rails.env]
|
111
|
+
Rediline.redis = Redis.new(
|
112
|
+
:host => rediline_config['host'],
|
113
|
+
:port => rediline_config['port'],
|
114
|
+
:password => rediline_config['password']
|
115
|
+
)
|
116
|
+
|
117
|
+
## Development
|
118
|
+
|
119
|
+
Want to hack on Rediline?
|
120
|
+
|
121
|
+
First clone the repo and run the tests:
|
122
|
+
|
123
|
+
git clone git://github.com/dmathieu/rediline.git
|
124
|
+
cd rediline
|
125
|
+
bundle install
|
126
|
+
rake test
|
127
|
+
|
128
|
+
If the tests do not pass make sure you have Redis installed
|
129
|
+
correctly.
|
130
|
+
|
131
|
+
|
132
|
+
## Contributing
|
133
|
+
|
134
|
+
Once you've made your great commits:
|
135
|
+
|
136
|
+
1. [Fork][1] Rediline
|
137
|
+
2. Create a topic branch - `git checkout -b my_branch`
|
138
|
+
3. Push to your branch - `git push origin my_branch`
|
139
|
+
4. Create an [Issue][2] with a link to your branch
|
140
|
+
5. That's it!
|
141
|
+
|
142
|
+
[1]: http://help.github.com/forking/
|
143
|
+
[2]: http://github.com/dmathieu/rediline/issues
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "rubygems"
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
#
|
6
|
+
# The rspec tasks
|
7
|
+
#
|
8
|
+
require 'rspec/core'
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
task :default => :spec
|
11
|
+
RSpec::Core::RakeTask.new(:spec)
|
12
|
+
|
13
|
+
#
|
14
|
+
# Jeweler
|
15
|
+
#
|
16
|
+
begin
|
17
|
+
require 'jeweler'
|
18
|
+
Jeweler::Tasks.new do |gemspec|
|
19
|
+
gemspec.name = "rediline"
|
20
|
+
gemspec.summary = "Redis Backed Timeline"
|
21
|
+
gemspec.description = "Timeline library"
|
22
|
+
gemspec.email = "42@dmathieu.com"
|
23
|
+
gemspec.homepage = "http://github.com/dmathieu/rediline"
|
24
|
+
gemspec.authors = ["Damien MATHIEU"]
|
25
|
+
|
26
|
+
gemspec.add_dependency "redis", '2.0.7'
|
27
|
+
gemspec.add_dependency "redis-namespace", '0.10.0'
|
28
|
+
gemspec.add_dependency "json"
|
29
|
+
gemspec.add_dependency "i18n"
|
30
|
+
gemspec.add_dependency "activesupport", "3.0.0"
|
31
|
+
end
|
32
|
+
rescue LoadError
|
33
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
34
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/init.rb
ADDED
data/lib/rediline.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
|
5
|
+
require 'redis/namespace'
|
6
|
+
require 'rediline/redis'
|
7
|
+
require 'rediline/entry'
|
8
|
+
require 'rediline/timeline'
|
9
|
+
require 'rediline/object'
|
10
|
+
require 'rediline/user'
|
11
|
+
|
12
|
+
module Rediline
|
13
|
+
extend Rediline::Redis
|
14
|
+
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'active_support/core_ext'
|
3
|
+
|
4
|
+
module Rediline
|
5
|
+
|
6
|
+
class Entry
|
7
|
+
attr_reader :content
|
8
|
+
|
9
|
+
def initialize(content)
|
10
|
+
@content = parse(content)
|
11
|
+
@objects = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_json
|
15
|
+
@content.to_json
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(name, *args)
|
19
|
+
return content[name] if content.include?(name)
|
20
|
+
if content.include?(:"#{name}_object") && content.include?(:"#{name}_object")
|
21
|
+
return @objects[name] ||= content[:"#{name}_object"].constantize.find(content[:"#{name}_id"])
|
22
|
+
end
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond_to?(name, *args)
|
27
|
+
return true if content.include?(name.to_s)
|
28
|
+
return true if content.include?("#{name}_object") && content.include?("#{name}_object")
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def parse(string)
|
34
|
+
if string.is_a?(String)
|
35
|
+
string = JSON.parse(string).symbolize_keys
|
36
|
+
|
37
|
+
[:user_id, :user_object, :object_id, :object_object, :verb].each do |f|
|
38
|
+
raise "invalid content : missing field #{f}" if string[f].nil?
|
39
|
+
end
|
40
|
+
else
|
41
|
+
string.symbolize_keys!
|
42
|
+
|
43
|
+
[:user, :object, :verb].each do |f|
|
44
|
+
raise "invalid content : missing field #{f}" if string[f].nil?
|
45
|
+
end
|
46
|
+
string[:created_at] = string[:created_at].nil? ? Time.now.utc.to_s : string[:created_at].to_s
|
47
|
+
|
48
|
+
object = string[:object]
|
49
|
+
string.keys.each do |k|
|
50
|
+
string[k] = string[k].call(object) if string[k].is_a?(Proc)
|
51
|
+
|
52
|
+
case string[k]
|
53
|
+
when String, Symbol, Numeric
|
54
|
+
next
|
55
|
+
else
|
56
|
+
string[:"#{k}_object"] = string[k].class.to_s
|
57
|
+
string[:"#{k}_id"] = string[k].id.to_s
|
58
|
+
string.delete k
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
string
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Rediline
|
2
|
+
module Object
|
3
|
+
|
4
|
+
def self.included(model)
|
5
|
+
model.send(:extend, ClassMethods)
|
6
|
+
|
7
|
+
model.class_eval do
|
8
|
+
private
|
9
|
+
def rediline_key(field_name, entry, type, user=nil)
|
10
|
+
raise "no entry provided" if entry.nil?
|
11
|
+
user = entry.user if user.nil?
|
12
|
+
"#{field_name.to_s}:#{user.class.to_s}.#{user.id.to_s}:#{type}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def rediline_insert!(entry, key)
|
16
|
+
Rediline.redis.del(key) unless Rediline.redis.type(key) == 'list'
|
17
|
+
Rediline.redis.rpush(key, entry.to_json)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def rediline(field_name, attrs)
|
24
|
+
attrs.symbolize_keys!
|
25
|
+
callback = attrs.delete :when
|
26
|
+
|
27
|
+
define_method "rediline_#{callback}" do
|
28
|
+
if attrs.frozen?
|
29
|
+
entry = Rediline::Entry.new(attrs.dup)
|
30
|
+
else
|
31
|
+
attrs[:object] = self
|
32
|
+
case attrs[:user]
|
33
|
+
when Symbol, String
|
34
|
+
attrs[:user] = send(attrs[:user])
|
35
|
+
when Proc
|
36
|
+
attrs[:user] = attrs[:user].call(self)
|
37
|
+
when nil
|
38
|
+
attrs[:user] = send(:user)
|
39
|
+
end
|
40
|
+
attrs.freeze
|
41
|
+
entry = Rediline::Entry.new(attrs.dup)
|
42
|
+
end
|
43
|
+
|
44
|
+
entry.user.send(field_name).lists.each_pair do |k, v|
|
45
|
+
v.each do |user|
|
46
|
+
rediline_insert! entry, rediline_key(field_name, entry, k, user)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
true
|
51
|
+
end
|
52
|
+
send(callback, "rediline_#{callback}")
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Rediline
|
2
|
+
|
3
|
+
module Redis
|
4
|
+
|
5
|
+
# Accepts:
|
6
|
+
# 1. A 'hostname:port' string
|
7
|
+
# 2. A 'hostname:port:db' string (to select the Redis db)
|
8
|
+
# 3. An instance of `Redis`, `Redis::Client`, or `Redis::Namespace`.
|
9
|
+
def redis=(server)
|
10
|
+
case server
|
11
|
+
when String
|
12
|
+
host, port, db = server.split(':')
|
13
|
+
redis = ::Redis.new(:host => host, :port => port,
|
14
|
+
:thread_safe => true, :db => db)
|
15
|
+
@redis = ::Redis::Namespace.new(:rediline, :redis => redis)
|
16
|
+
when ::Redis, ::Redis::Client
|
17
|
+
@redis = ::Redis::Namespace.new(:rediline, :redis => server)
|
18
|
+
when ::Redis::Namespace
|
19
|
+
@redis = server
|
20
|
+
when nil
|
21
|
+
@redis = nil
|
22
|
+
else
|
23
|
+
raise "I don't know what to do with #{server.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the current Redis connection. If none has been created, will
|
28
|
+
# create a new one.
|
29
|
+
def redis
|
30
|
+
return @redis if @redis
|
31
|
+
self.redis = 'localhost:6379'
|
32
|
+
self.redis
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rediline
|
2
|
+
module Timeline
|
3
|
+
class User
|
4
|
+
attr_reader :field_name, :user, :block, :lists
|
5
|
+
|
6
|
+
def initialize(field_name, user, block)
|
7
|
+
@field_name, @user, @block = field_name, user
|
8
|
+
@lists = {}
|
9
|
+
instance_eval(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def each(type)
|
13
|
+
raise "you must provide a block" unless block_given?
|
14
|
+
(0..count(type)-1).each do |i|
|
15
|
+
data = Rediline.redis.lindex(key(type), i)
|
16
|
+
yield Rediline::Entry.new(data)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_a(type)
|
21
|
+
result = Array.new
|
22
|
+
self.each(type) do |entry|
|
23
|
+
result << entry
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def count(type)
|
29
|
+
Rediline.redis.llen(key(type))
|
30
|
+
end
|
31
|
+
|
32
|
+
def list(name, &block)
|
33
|
+
@lists[name] = instance_eval(&block)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def key(type)
|
38
|
+
"#{field_name.to_s}:#{@user.class.to_s}.#{@user.id.to_s}:#{type}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rediline
|
2
|
+
module User
|
3
|
+
|
4
|
+
def self.included(model)
|
5
|
+
model.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
module ClassMethods
|
8
|
+
def rediline(field_name, &block)
|
9
|
+
define_method field_name.to_sym do
|
10
|
+
Rediline::Timeline::User.new(field_name.to_sym, self, block)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/rediline.gemspec
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rediline}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Damien MATHIEU"]
|
12
|
+
s.date = %q{2010-09-23}
|
13
|
+
s.description = %q{Timeline library}
|
14
|
+
s.email = %q{42@dmathieu.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.md"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
".rvmrc",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"init.rb",
|
27
|
+
"lib/rediline.rb",
|
28
|
+
"lib/rediline/entry.rb",
|
29
|
+
"lib/rediline/object.rb",
|
30
|
+
"lib/rediline/redis.rb",
|
31
|
+
"lib/rediline/timeline.rb",
|
32
|
+
"lib/rediline/timeline/user.rb",
|
33
|
+
"lib/rediline/user.rb",
|
34
|
+
"rediline.gemspec",
|
35
|
+
"spec/entry_spec.rb",
|
36
|
+
"spec/object_spec.rb",
|
37
|
+
"spec/redis_spec.rb",
|
38
|
+
"spec/spec_helper.rb",
|
39
|
+
"spec/support/timeline.rb",
|
40
|
+
"spec/support/timeline_owner.rb",
|
41
|
+
"spec/support/user.rb",
|
42
|
+
"spec/timeline/user_spec.rb",
|
43
|
+
"spec/timeline_spec.rb",
|
44
|
+
"spec/user_spec.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/dmathieu/rediline}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.7}
|
50
|
+
s.summary = %q{Redis Backed Timeline}
|
51
|
+
s.test_files = [
|
52
|
+
"spec/entry_spec.rb",
|
53
|
+
"spec/object_spec.rb",
|
54
|
+
"spec/redis_spec.rb",
|
55
|
+
"spec/spec_helper.rb",
|
56
|
+
"spec/support/timeline.rb",
|
57
|
+
"spec/support/timeline_owner.rb",
|
58
|
+
"spec/support/user.rb",
|
59
|
+
"spec/timeline/user_spec.rb",
|
60
|
+
"spec/timeline_spec.rb",
|
61
|
+
"spec/user_spec.rb"
|
62
|
+
]
|
63
|
+
|
64
|
+
if s.respond_to? :specification_version then
|
65
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
66
|
+
s.specification_version = 3
|
67
|
+
|
68
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
69
|
+
s.add_runtime_dependency(%q<redis>, ["= 2.0.7"])
|
70
|
+
s.add_runtime_dependency(%q<redis-namespace>, ["= 0.10.0"])
|
71
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
72
|
+
s.add_runtime_dependency(%q<i18n>, [">= 0"])
|
73
|
+
s.add_runtime_dependency(%q<activesupport>, ["= 3.0.0"])
|
74
|
+
else
|
75
|
+
s.add_dependency(%q<redis>, ["= 2.0.7"])
|
76
|
+
s.add_dependency(%q<redis-namespace>, ["= 0.10.0"])
|
77
|
+
s.add_dependency(%q<json>, [">= 0"])
|
78
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
79
|
+
s.add_dependency(%q<activesupport>, ["= 3.0.0"])
|
80
|
+
end
|
81
|
+
else
|
82
|
+
s.add_dependency(%q<redis>, ["= 2.0.7"])
|
83
|
+
s.add_dependency(%q<redis-namespace>, ["= 0.10.0"])
|
84
|
+
s.add_dependency(%q<json>, [">= 0"])
|
85
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
86
|
+
s.add_dependency(%q<activesupport>, ["= 3.0.0"])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
data/spec/entry_spec.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rediline::Entry do
|
5
|
+
|
6
|
+
it 'should initialize' do
|
7
|
+
lambda do
|
8
|
+
Rediline::Entry.new valid_hash
|
9
|
+
end.should_not raise_error
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should initialize with a hash' do
|
13
|
+
lambda do
|
14
|
+
Rediline::Entry.new valid_hash
|
15
|
+
end.should_not raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'when initializing with a string' do
|
19
|
+
[:object_object, :object_id, :user_object, :user_id, :verb].each do |f|
|
20
|
+
it "should require a #{f}" do
|
21
|
+
c = valid_json
|
22
|
+
c.delete f
|
23
|
+
lambda do
|
24
|
+
Rediline::Entry.new c.to_json
|
25
|
+
end.should raise_error "invalid content : missing field #{f}"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should define the #{f} attribute" do
|
29
|
+
entry = Rediline::Entry.new valid_json.to_json
|
30
|
+
entry.send(f).should_not be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
[:object, :user].each do |o|
|
35
|
+
it "should not have any #{o} object in its content" do
|
36
|
+
entry = Rediline::Entry.new valid_json.to_json
|
37
|
+
entry.content[o].should be_nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'when initializing with a hash' do
|
43
|
+
[:object, :user, :verb].each do |f|
|
44
|
+
it "should require a #{f}" do
|
45
|
+
c = valid_hash
|
46
|
+
c.delete f
|
47
|
+
lambda do
|
48
|
+
Rediline::Entry.new c
|
49
|
+
end.should raise_error "invalid content : missing field #{f}"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should define the #{f} attribute" do
|
53
|
+
entry = Rediline::Entry.new valid_hash
|
54
|
+
entry.send(f).should_not be_nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
[:object, :user].each do |o|
|
59
|
+
it "should not have any #{o} object in its content" do
|
60
|
+
entry = Rediline::Entry.new valid_json.to_json
|
61
|
+
entry.content[o].should be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should allow us to define an other object' do
|
66
|
+
c = valid_hash
|
67
|
+
c[:second_object] = TestingTimelineObject.new(666)
|
68
|
+
entry = Rediline::Entry.new c
|
69
|
+
entry.second_object.should be_kind_of(TestingTimelineObject)
|
70
|
+
entry.second_object.id.should eql('666')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should allow us to define an other object as a proc' do
|
74
|
+
c = valid_hash
|
75
|
+
c[:second_object] = lambda {|o| o.id }
|
76
|
+
entry = Rediline::Entry.new c
|
77
|
+
entry.second_object.should eql(42)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'creation date' do
|
82
|
+
it 'should define the creation date' do
|
83
|
+
Timecop.freeze(Time.now) do
|
84
|
+
entry = Rediline::Entry.new valid_hash
|
85
|
+
entry.created_at.should eql(Time.now.utc.to_s)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should be possible to define our own creation date' do
|
90
|
+
Timecop.freeze(Time.now) do
|
91
|
+
c = valid_hash
|
92
|
+
c[:created_at] = Date.new(2010, 01, 01).to_s
|
93
|
+
entry = Rediline::Entry.new c
|
94
|
+
entry.created_at.should eql(Date.new(2010, 01, 01).to_s)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'to_json' do
|
100
|
+
it 'should return the attributes in json' do
|
101
|
+
entry = Rediline::Entry.new valid_hash
|
102
|
+
entry.to_json.should be_kind_of(String)
|
103
|
+
json = JSON.parse(entry.to_json)
|
104
|
+
valid_json.each_pair do |k, v|
|
105
|
+
valid_json[k].to_s.should eql(json[k.to_s])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def valid_hash
|
111
|
+
{
|
112
|
+
:object => TestingTimelineObject.new(42),
|
113
|
+
:user => User.new(1),
|
114
|
+
:verb => :created
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def valid_json
|
119
|
+
{
|
120
|
+
:object_object => "TestingTimelineObject",
|
121
|
+
:object_id => 42,
|
122
|
+
:user_object => "User",
|
123
|
+
:user_id => 1,
|
124
|
+
:verb => :created
|
125
|
+
}
|
126
|
+
end
|
127
|
+
end
|
data/spec/object_spec.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rediline::Object do
|
5
|
+
before :each do
|
6
|
+
@object = TestingTimelineObject.new(1, User.new(1))
|
7
|
+
@entry = Rediline::Entry.new(valid_log)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should have the rediline method' do
|
11
|
+
TestingTimelineObject.respond_to?(:rediline).should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
[:after_create, :before_destroy].each do |c|
|
15
|
+
it "should create the #{c} callback" do
|
16
|
+
@object.respond_to?("rediline_#{c}".to_sym).should be_true
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should not fail to call the callback' do
|
20
|
+
lambda do
|
21
|
+
@object.send("rediline_#{c}".to_sym)
|
22
|
+
end.should_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should add the log for the egocentric list' do
|
26
|
+
length = User.new(1).timeline.count(:egocentric)
|
27
|
+
@object.send("rediline_#{c}".to_sym)
|
28
|
+
User.new(1).timeline.count(:egocentric).should eql(length + 1)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should add the logs for the public list' do
|
32
|
+
length1 = User.new(15).timeline.count(:public)
|
33
|
+
length2 = User.new(16).timeline.count(:public)
|
34
|
+
@object.send("rediline_#{c}".to_sym)
|
35
|
+
User.new(15).timeline.count(:public).should eql(length1 + 1)
|
36
|
+
User.new(16).timeline.count(:public).should eql(length2 + 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'not default user field' do
|
40
|
+
before :each do
|
41
|
+
@object = TestingTimelineObjectWithOwner.new(1, User.new(1))
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not fail to call the callback' do
|
45
|
+
lambda do
|
46
|
+
@object.send("rediline_#{c}".to_sym)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should add the log for the egocentric list' do
|
51
|
+
length = User.new(1).timeline.count(:egocentric)
|
52
|
+
@object.send("rediline_#{c}".to_sym)
|
53
|
+
User.new(1).timeline.count(:egocentric).should eql(length + 1)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should add the logs for the public list' do
|
57
|
+
length1 = User.new(15).timeline.count(:public)
|
58
|
+
length2 = User.new(16).timeline.count(:public)
|
59
|
+
@object.send("rediline_#{c}".to_sym)
|
60
|
+
User.new(15).timeline.count(:public).should eql(length1 + 1)
|
61
|
+
User.new(16).timeline.count(:public).should eql(length2 + 1)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'rediline_key' do
|
67
|
+
it 'should return the timeline\'s key' do
|
68
|
+
@object.send(:rediline_key, :timeline, @entry, :egocentric).should eql('timeline:User.1:egocentric')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should define a different user' do
|
72
|
+
@object.send(:rediline_key, :timeline, @entry, :egocentric, User.new(15)).should eql('timeline:User.15:egocentric')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'rediline_insert!' do
|
77
|
+
it 'should delete the key if it was not a list' do
|
78
|
+
Rediline.redis.set "testing", "string key"
|
79
|
+
lambda do
|
80
|
+
@object.send(:rediline_insert!, {:test => true}, "testing")
|
81
|
+
end.should_not raise_error
|
82
|
+
Rediline.redis.type("testing").should eql('list')
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should push a new key to the list' do
|
86
|
+
length = Rediline.redis.llen("testing")
|
87
|
+
@object.send(:rediline_insert!, {:test => true}, "testing")
|
88
|
+
Rediline.redis.llen("testing").should eql(length + 1)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def valid_log
|
93
|
+
{
|
94
|
+
:object => @object,
|
95
|
+
:user => User.new(1),
|
96
|
+
:verb => :created
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
data/spec/redis_spec.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rediline do
|
5
|
+
|
6
|
+
describe 'redis=' do
|
7
|
+
it 'should define a redis server with a string' do
|
8
|
+
lambda do
|
9
|
+
Rediline.redis = 'localhost:6379'
|
10
|
+
end.should_not raise_error
|
11
|
+
end
|
12
|
+
it 'should define a redis server with a string/db' do
|
13
|
+
lambda do
|
14
|
+
Rediline.redis = 'localhost:6379:dmathieu'
|
15
|
+
end.should_not raise_error
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should define a redis server with a Redis object' do
|
19
|
+
lambda do
|
20
|
+
Rediline.redis = ::Redis.new(:host => 'localhost', :port => '6379',
|
21
|
+
:thread_safe => true, :db => 'dmathieu')
|
22
|
+
end.should_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should define a redis server with a Redis::Client object' do
|
26
|
+
lambda do
|
27
|
+
Rediline.redis = ::Redis::Client.new(:host => 'localhost', :port => '6379',
|
28
|
+
:thread_safe => true, :db => 'dmathieu')
|
29
|
+
end.should_not raise_error
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should define a redis server with a Redis::Namespace object' do
|
33
|
+
lambda do
|
34
|
+
redis = ::Redis.new(:host => 'localhost', :port => '6379',
|
35
|
+
:thread_safe => true, :db => 'dmathieu')
|
36
|
+
Rediline.redis = ::Redis::Namespace.new(:dmathieu, :redis => redis)
|
37
|
+
end.should_not raise_error
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should close the connection' do
|
41
|
+
lambda do
|
42
|
+
Rediline.redis = nil
|
43
|
+
end.should_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should not know what to do with that' do
|
47
|
+
lambda do
|
48
|
+
Rediline.redis = Rediline::Redis
|
49
|
+
end.should raise_error
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'redis' do
|
54
|
+
it 'should return the redis object' do
|
55
|
+
Rediline.redis.should be_kind_of Redis::Namespace
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should initialize a new redis object' do
|
59
|
+
Rediline.redis = nil
|
60
|
+
Rediline.redis.should be_kind_of Redis::Namespace
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
class TestingTimelineObject
|
2
|
+
extend ActiveModel::Callbacks
|
3
|
+
define_model_callbacks :create, :destroy
|
4
|
+
include Rediline::Object
|
5
|
+
|
6
|
+
rediline :timeline,
|
7
|
+
:user => :user,
|
8
|
+
:verb => :created,
|
9
|
+
:when => :after_create
|
10
|
+
rediline :timeline,
|
11
|
+
:user => lambda {|o| o.user },
|
12
|
+
:verb => :destroyed,
|
13
|
+
:when => :before_destroy
|
14
|
+
|
15
|
+
attr_reader :id, :user
|
16
|
+
def initialize(id, user=nil)
|
17
|
+
@id, @user = id, user
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find(id, user=nil)
|
21
|
+
self.new(id, user)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create
|
25
|
+
_run_create_callbacks do
|
26
|
+
# Your create action methods here
|
27
|
+
end
|
28
|
+
end
|
29
|
+
def destroy
|
30
|
+
_run_destroy_callbacks do
|
31
|
+
# Your destroy action methods here
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class TestingTimelineObjectWithOwner
|
2
|
+
extend ActiveModel::Callbacks
|
3
|
+
define_model_callbacks :create, :destroy
|
4
|
+
include Rediline::Object
|
5
|
+
|
6
|
+
rediline :timeline,
|
7
|
+
:user => :owner,
|
8
|
+
:verb => :created,
|
9
|
+
:when => :after_create
|
10
|
+
rediline :timeline,
|
11
|
+
:user => :owner,
|
12
|
+
:verb => :created,
|
13
|
+
:when => :before_destroy
|
14
|
+
|
15
|
+
attr_reader :id, :owner
|
16
|
+
def initialize(id, owner=nil)
|
17
|
+
@id, @owner = id, owner
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find(id, owner=nil)
|
21
|
+
self.new(id, owner)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create
|
25
|
+
_run_create_callbacks do
|
26
|
+
# Your create action methods here
|
27
|
+
end
|
28
|
+
end
|
29
|
+
def destroy
|
30
|
+
_run_destroy_callbacks do
|
31
|
+
# Your destroy action methods here
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class User
|
2
|
+
include Rediline::User
|
3
|
+
rediline :timeline do
|
4
|
+
list :egocentric do
|
5
|
+
[user]
|
6
|
+
end
|
7
|
+
list :public do
|
8
|
+
[User.new(15), User.new(16)]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :id
|
13
|
+
def initialize(id)
|
14
|
+
@id = id
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.find(id)
|
18
|
+
self.new(id)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rediline::Timeline::User do
|
5
|
+
before :each do
|
6
|
+
@timeline = User.new(1).timeline
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'lists' do
|
10
|
+
it 'should have defined the egocentric list' do
|
11
|
+
@timeline.lists.should_not be_empty
|
12
|
+
end
|
13
|
+
it 'should have the egocentric list with one user' do
|
14
|
+
@timeline.lists[:egocentric].length.should eql(1)
|
15
|
+
end
|
16
|
+
it 'should have the public list with two users' do
|
17
|
+
@timeline.lists[:public].length.should eql(2)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should be able to add a new list' do
|
21
|
+
@timeline.lists[:testing].should be_nil
|
22
|
+
@timeline.list(:testing) { [user] }
|
23
|
+
@timeline.lists[:testing].should_not be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'each' do
|
28
|
+
it 'should require a block' do
|
29
|
+
lambda do
|
30
|
+
@timeline.each(:egocentric)
|
31
|
+
end.should raise_error 'you must provide a block'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should loop through the list' do
|
35
|
+
@timeline.each(:egocentric) do |entry|
|
36
|
+
entry.should be_kind_of(Rediline::Entry)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
[:object, :user].each do |o|
|
41
|
+
it "should not have any #{o} in it\'s values" do
|
42
|
+
@timeline.each(:egocentric) do |entry|
|
43
|
+
entry.content[o].should be_nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'to_a' do
|
50
|
+
it 'should return an array' do
|
51
|
+
@timeline.to_a(:egocentric).should be_kind_of(Array)
|
52
|
+
end
|
53
|
+
it 'should have the entries' do
|
54
|
+
@timeline.to_a(:egocentric).each do |entry|
|
55
|
+
entry.should be_kind_of(Rediline::Entry)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe 'count' do
|
61
|
+
it 'should return an integer' do
|
62
|
+
@timeline.count(:egocentric).should be_kind_of(Integer)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'key' do
|
67
|
+
it 'should return the timeline\'s key' do
|
68
|
+
@timeline.send(:key, :egocentric).should eql('timeline:User.1:egocentric')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/spec/user_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Rediline::User do
|
5
|
+
|
6
|
+
it 'should have the timeline method' do
|
7
|
+
User.new(1).respond_to?(:timeline).should eql(true)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should return a timeline object' do
|
11
|
+
User.new(1).timeline.should be_kind_of(Rediline::Timeline::User)
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rediline
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Damien MATHIEU
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-23 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: redis
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - "="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 0
|
30
|
+
- 7
|
31
|
+
version: 2.0.7
|
32
|
+
type: :runtime
|
33
|
+
prerelease: false
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: redis-namespace
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - "="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
- 10
|
45
|
+
- 0
|
46
|
+
version: 0.10.0
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: json
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: i18n
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
type: :runtime
|
74
|
+
prerelease: false
|
75
|
+
version_requirements: *id004
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: activesupport
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - "="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 3
|
85
|
+
- 0
|
86
|
+
- 0
|
87
|
+
version: 3.0.0
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *id005
|
91
|
+
description: Timeline library
|
92
|
+
email: 42@dmathieu.com
|
93
|
+
executables: []
|
94
|
+
|
95
|
+
extensions: []
|
96
|
+
|
97
|
+
extra_rdoc_files:
|
98
|
+
- README.md
|
99
|
+
files:
|
100
|
+
- .gitignore
|
101
|
+
- .rvmrc
|
102
|
+
- Gemfile
|
103
|
+
- Gemfile.lock
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- VERSION
|
107
|
+
- init.rb
|
108
|
+
- lib/rediline.rb
|
109
|
+
- lib/rediline/entry.rb
|
110
|
+
- lib/rediline/object.rb
|
111
|
+
- lib/rediline/redis.rb
|
112
|
+
- lib/rediline/timeline.rb
|
113
|
+
- lib/rediline/timeline/user.rb
|
114
|
+
- lib/rediline/user.rb
|
115
|
+
- rediline.gemspec
|
116
|
+
- spec/entry_spec.rb
|
117
|
+
- spec/object_spec.rb
|
118
|
+
- spec/redis_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
- spec/support/timeline.rb
|
121
|
+
- spec/support/timeline_owner.rb
|
122
|
+
- spec/support/user.rb
|
123
|
+
- spec/timeline/user_spec.rb
|
124
|
+
- spec/timeline_spec.rb
|
125
|
+
- spec/user_spec.rb
|
126
|
+
has_rdoc: true
|
127
|
+
homepage: http://github.com/dmathieu/rediline
|
128
|
+
licenses: []
|
129
|
+
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options:
|
132
|
+
- --charset=UTF-8
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
hash: 1586793397385962776
|
141
|
+
segments:
|
142
|
+
- 0
|
143
|
+
version: "0"
|
144
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
segments:
|
150
|
+
- 0
|
151
|
+
version: "0"
|
152
|
+
requirements: []
|
153
|
+
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 1.3.7
|
156
|
+
signing_key:
|
157
|
+
specification_version: 3
|
158
|
+
summary: Redis Backed Timeline
|
159
|
+
test_files:
|
160
|
+
- spec/entry_spec.rb
|
161
|
+
- spec/object_spec.rb
|
162
|
+
- spec/redis_spec.rb
|
163
|
+
- spec/spec_helper.rb
|
164
|
+
- spec/support/timeline.rb
|
165
|
+
- spec/support/timeline_owner.rb
|
166
|
+
- spec/support/user.rb
|
167
|
+
- spec/timeline/user_spec.rb
|
168
|
+
- spec/timeline_spec.rb
|
169
|
+
- spec/user_spec.rb
|