rediline 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 +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
|