activities 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +89 -0
- data/Rakefile +43 -0
- data/lib/activities.rb +14 -0
- data/lib/activities/active_record.rb +2 -0
- data/lib/activities/active_record/class_methods.rb +93 -0
- data/lib/activities/active_record/instance_methods.rb +55 -0
- data/lib/activities/activity.rb +5 -0
- data/lib/activities/dsl.rb +24 -0
- data/lib/activities/helper.rb +14 -0
- data/lib/activities/version.rb +8 -0
- data/test/activities/active_record_test.rb +244 -0
- data/test/resources/models.rb +21 -0
- data/test/schema.rb +28 -0
- data/test/test_helper.rb +11 -0
- metadata +89 -0
data/README.rdoc
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
= Introduction
|
2
|
+
|
3
|
+
Activities is a gem that enables social activities in ActiveRecord objects.
|
4
|
+
|
5
|
+
= Install
|
6
|
+
|
7
|
+
sudo gem install activities
|
8
|
+
|
9
|
+
You have to create a migration with the following code:
|
10
|
+
|
11
|
+
create_table :activities do |t|
|
12
|
+
t.references :tracker, :polymorphic => true, :null => false
|
13
|
+
t.references :trackable, :polymorphic => true, :null => false
|
14
|
+
t.string :action, :null => false
|
15
|
+
t.text :data, :null => true
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
add_index :activities, [:tracker_id, :trackable_id]
|
20
|
+
add_index :activities, [:tracker_id, :trackable_id, :action]
|
21
|
+
|
22
|
+
If you want the source go to http://github.com/fnando/activities
|
23
|
+
|
24
|
+
= Usage
|
25
|
+
|
26
|
+
Activities is plugged on associations. So, all you have to do is add something like this:
|
27
|
+
|
28
|
+
class User < ActiveRecord::Base
|
29
|
+
has_many :projects
|
30
|
+
activities_for :projects do
|
31
|
+
track :renamed, :if => proc {|r| !r.new_record? && r.name_changed? }, :on => :save
|
32
|
+
track :create
|
33
|
+
track :update
|
34
|
+
track :destroy
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
This will add activities when you create, update, destroy a project or the change its name.
|
39
|
+
|
40
|
+
To retrieve the activities, you can use the association +activities+.
|
41
|
+
|
42
|
+
@user.activities.all
|
43
|
+
|
44
|
+
By default, all attributes are stored in a field called +data+. You should overwrite the method
|
45
|
+
+to_activity+ and return a hash with the attributes that you really want to be saved.
|
46
|
+
|
47
|
+
class Project < ActiveRecord::Base
|
48
|
+
belongs_to :user
|
49
|
+
|
50
|
+
def to_activity
|
51
|
+
{ :name => name, :status => status }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
To display the activities, you should use the helper +render_activity+.
|
56
|
+
|
57
|
+
<% for activity in @activities %>
|
58
|
+
<%= render_activity @activity %>
|
59
|
+
<% end %>
|
60
|
+
|
61
|
+
The +render_activity+ helper will render a partial as <tt>app/views/activities/TRACKABLE_TYPE/ACTION</tt>.
|
62
|
+
So, if you want to render activities fro that project, you should create the following files:
|
63
|
+
|
64
|
+
app/views/activities/project/_renamed.html.erb
|
65
|
+
app/views/activities/project/_create.html.erb
|
66
|
+
app/views/activities/project/_update.html.erb
|
67
|
+
app/views/activities/project/_destroy.html.erb
|
68
|
+
|
69
|
+
The activity object will be available and you can display something like this:
|
70
|
+
|
71
|
+
<p>
|
72
|
+
<%= tracker.name %> created the
|
73
|
+
repository <%= link_to data[:name], project_path(trackable) %>
|
74
|
+
<%= time_ago_in_words data[:created_at] %>
|
75
|
+
</p>
|
76
|
+
|
77
|
+
= License
|
78
|
+
|
79
|
+
(The MIT License)
|
80
|
+
|
81
|
+
Copyright © 2010:
|
82
|
+
|
83
|
+
* Nando Vieira - http://simplesideias.com.br
|
84
|
+
|
85
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
86
|
+
|
87
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
88
|
+
|
89
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "jeweler"
|
2
|
+
require "rcov/rcovtask"
|
3
|
+
require "rake/testtask"
|
4
|
+
require "rake/rdoctask"
|
5
|
+
require "lib/activities/version"
|
6
|
+
|
7
|
+
Rcov::RcovTask.new do |t|
|
8
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
9
|
+
t.rcov_opts = ["--sort coverage", "--exclude .gem,.bundle,errors.rb"]
|
10
|
+
|
11
|
+
t.output_dir = "coverage"
|
12
|
+
t.libs << "test"
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
Rake::TestTask.new do |t|
|
17
|
+
t.libs << "lib"
|
18
|
+
t.libs << "test"
|
19
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
20
|
+
t.verbose = true
|
21
|
+
end
|
22
|
+
|
23
|
+
Rake::RDocTask.new do |rdoc|
|
24
|
+
rdoc.main = "README.rdoc"
|
25
|
+
rdoc.rdoc_dir = "doc"
|
26
|
+
rdoc.title = "Actitivies API"
|
27
|
+
rdoc.options += %w[ --line-numbers --inline-source --charset utf-8 ]
|
28
|
+
rdoc.rdoc_files.include("README.rdoc")
|
29
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
30
|
+
end
|
31
|
+
|
32
|
+
JEWEL = Jeweler::Tasks.new do |gem|
|
33
|
+
gem.name = "activities"
|
34
|
+
gem.email = "fnando.vieira@gmail.com"
|
35
|
+
gem.homepage = "http://github.com/fnando/activities"
|
36
|
+
gem.authors = ["Nando Vieira"]
|
37
|
+
gem.version = Activities::Version::STRING
|
38
|
+
gem.summary = "A framework for aggregating social activity."
|
39
|
+
gem.add_dependency "activerecord"
|
40
|
+
gem.files = FileList["{README,CHANGELOG}.rdoc", "{lib,test}/**/*", "Rakefile"]
|
41
|
+
end
|
42
|
+
|
43
|
+
Jeweler::GemcutterTasks.new
|
data/lib/activities.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "active_record"
|
2
|
+
require "activities/version"
|
3
|
+
require "activities/helper"
|
4
|
+
require "activities/active_record"
|
5
|
+
require "activities/activity"
|
6
|
+
require "activities/dsl"
|
7
|
+
|
8
|
+
module Activities
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveRecord::Base.class_eval do
|
12
|
+
include Activities::ActiveRecord::InstanceMethods
|
13
|
+
extend Activities::ActiveRecord::ClassMethods
|
14
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Activities
|
2
|
+
module ActiveRecord
|
3
|
+
module ClassMethods
|
4
|
+
# Add a new activity trigger.
|
5
|
+
#
|
6
|
+
# class User < ActiveRecord::Base
|
7
|
+
# has_many :tasks
|
8
|
+
#
|
9
|
+
# activities_for :tasks do
|
10
|
+
# track :create
|
11
|
+
# track :update
|
12
|
+
# track :destroy
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# The above statement will create activities when
|
17
|
+
# a <tt>Thing</tt> instance is created, updated or removed.
|
18
|
+
#
|
19
|
+
# By default, the activity tracker stores all
|
20
|
+
# attributes. But you can specify which attributes you want to
|
21
|
+
# save. Just overwrite the method <tt>to_activity</tt> on your
|
22
|
+
# trackable model.
|
23
|
+
#
|
24
|
+
# class Task < ActiveRecord::Base
|
25
|
+
# belongs_to :project
|
26
|
+
#
|
27
|
+
# def to_activity
|
28
|
+
# { :project_name => project.name, :task_name => name }
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# To track custom actions, you need to specify other options.
|
33
|
+
# Imagine you want to track when a task is marked as completed.
|
34
|
+
# You can add an activity to this action.
|
35
|
+
#
|
36
|
+
# class User < ActiveRecord::Base
|
37
|
+
# has_many :tasks
|
38
|
+
#
|
39
|
+
# activities_for :tasks do
|
40
|
+
# track :completed, :on => :update, :if => proc {|task| task.status_changed? && task.status == "completed" }
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# You can also track when an attribute changes:
|
45
|
+
#
|
46
|
+
# class User < ActiveRecord::Base
|
47
|
+
# has_many :projects
|
48
|
+
#
|
49
|
+
# activities_for :projects do
|
50
|
+
# track :renamed, :on => :update, :if => :name_changed?
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# There's also an <tt>:unless</tt> option. REMEMBER: you can't use the <tt>:unless</tt> and <tt>:if</tt>
|
55
|
+
# options at the same time.
|
56
|
+
#
|
57
|
+
def activities_for(reflection_name, &block)
|
58
|
+
reflection = self.reflections[reflection_name]
|
59
|
+
tracker_class = self
|
60
|
+
|
61
|
+
raise ArgumentError, "#{reflection_name.inspect} is not an existing association" unless reflection
|
62
|
+
raise ArgumentError, "no block given" unless block_given?
|
63
|
+
|
64
|
+
tracker_class.class_eval do
|
65
|
+
has_many :activities, :as => :tracker
|
66
|
+
end
|
67
|
+
|
68
|
+
model_class = reflection.class_name.constantize
|
69
|
+
|
70
|
+
model_class.class_eval do
|
71
|
+
unless self.respond_to?(:activity_trackers)
|
72
|
+
class << self
|
73
|
+
attr_accessor :activity_trackers
|
74
|
+
end
|
75
|
+
|
76
|
+
has_many :activities, :as => :trackable
|
77
|
+
|
78
|
+
self.activity_trackers = {}
|
79
|
+
|
80
|
+
after_create :process_activities_on_create
|
81
|
+
before_save :process_activities_on_update
|
82
|
+
before_destroy :process_activities_on_destroy
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
dsl = Activities::Dsl.new
|
87
|
+
dsl.trackable = model_class
|
88
|
+
dsl.reflection_name = reflection.primary_key_name.gsub(/_id$/, "")
|
89
|
+
dsl.instance_eval(&block)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Activities
|
2
|
+
module ActiveRecord
|
3
|
+
module InstanceMethods
|
4
|
+
def to_activity # :nodoc:
|
5
|
+
attributes
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
def process_activities(step)
|
10
|
+
[self.class.activity_trackers[step]].flatten.compact.each do |options|
|
11
|
+
next unless process_activity?(options)
|
12
|
+
|
13
|
+
::Activity.create!({
|
14
|
+
:tracker => self.send(options[:reflection_name]),
|
15
|
+
:trackable => self,
|
16
|
+
:action => options[:action].to_s,
|
17
|
+
:data => to_activity.symbolize_keys
|
18
|
+
})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def process_activity?(options)
|
23
|
+
if options[:if]
|
24
|
+
check_against = true
|
25
|
+
callback = options[:if]
|
26
|
+
elsif options[:unless]
|
27
|
+
check_against = false
|
28
|
+
callback = options[:unless]
|
29
|
+
else
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
|
33
|
+
if callback.respond_to?(:call)
|
34
|
+
result = callback[self]
|
35
|
+
elsif callback.kind_of?(Symbol)
|
36
|
+
result = send(callback)
|
37
|
+
end
|
38
|
+
|
39
|
+
!!result == check_against
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_activities_on_create
|
43
|
+
process_activities(:create)
|
44
|
+
end
|
45
|
+
|
46
|
+
def process_activities_on_update
|
47
|
+
process_activities(:update) unless new_record?
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_activities_on_destroy
|
51
|
+
process_activities(:destroy)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Activities
|
2
|
+
class Dsl
|
3
|
+
attr_accessor :trackable
|
4
|
+
attr_accessor :reflection_name
|
5
|
+
|
6
|
+
def track(action, options = {})
|
7
|
+
options = prepare_options(action, options)
|
8
|
+
check_validity!(options)
|
9
|
+
on = options.delete(:on)
|
10
|
+
trackable.activity_trackers[on] ||= []
|
11
|
+
trackable.activity_trackers[on] << options.merge(:action => action, :reflection_name => reflection_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
def prepare_options(action, options = {}) # :nodoc:
|
16
|
+
options[:on] ||= action if [:create, :update, :destroy].include?(action)
|
17
|
+
options
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_validity!(options) # :nodoc:
|
21
|
+
raise ArgumentError, "the track method expects :on to be set" unless [:create, :update, :destroy].include?(options[:on])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Activities
|
2
|
+
module Helper
|
3
|
+
def render_activity(activity)
|
4
|
+
path = "activities/#{activity.trackable_type.underscore}/#{activity.action}"
|
5
|
+
locals = {
|
6
|
+
:activity => activity,
|
7
|
+
:tracker => activity.tracker,
|
8
|
+
:trackable => activity.trackable,
|
9
|
+
:data => activity.data
|
10
|
+
}
|
11
|
+
render :partial => path, :locals => locals
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class Activities::ActiveRecordTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
%w[User Task Milestone Project].each do |name|
|
6
|
+
Object.send(:remove_const, name) rescue nil
|
7
|
+
end
|
8
|
+
load "resources/models.rb"
|
9
|
+
|
10
|
+
User.delete_all
|
11
|
+
Project.delete_all
|
12
|
+
Task.delete_all
|
13
|
+
Milestone.delete_all
|
14
|
+
Activity.delete_all
|
15
|
+
|
16
|
+
@user = User.create(:login => "johndoe")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_models_should_respond_to_activities_for
|
20
|
+
assert User.respond_to?(:activities_for)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_activities_for_expects_an_association
|
24
|
+
assert_raise ArgumentError do
|
25
|
+
User.activities_for
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_activities_for_expects_a_valid_association
|
30
|
+
assert_raise ArgumentError do
|
31
|
+
User.activities_for :invalid do
|
32
|
+
track :create
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_activities_for_expects_a_block
|
38
|
+
assert_raise ArgumentError do
|
39
|
+
User.activities_for :projects
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_setup_trackable_class
|
44
|
+
User.activities_for(:tasks) do
|
45
|
+
track :create
|
46
|
+
track :update
|
47
|
+
track :destroy
|
48
|
+
track :renamed, :on => :update, :if => :name_changed?
|
49
|
+
end
|
50
|
+
|
51
|
+
expected = {
|
52
|
+
:create => [{:reflection_name => "user", :action => :create}],
|
53
|
+
:update => [
|
54
|
+
{:reflection_name => "user", :action => :update},
|
55
|
+
{:reflection_name => "user", :action => :renamed, :if => :name_changed?}
|
56
|
+
],
|
57
|
+
:destroy => [{:reflection_name => "user", :action => :destroy}]
|
58
|
+
}
|
59
|
+
assert_equal(expected, Task.activity_trackers)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_add_multiple_trackers
|
63
|
+
User.activities_for(:tasks) { track :create }
|
64
|
+
Project.activities_for(:tasks) { track :create }
|
65
|
+
|
66
|
+
expected = {
|
67
|
+
:create => [
|
68
|
+
{ :reflection_name => "user", :action => :create },
|
69
|
+
{ :reflection_name => "project", :action => :create }
|
70
|
+
]
|
71
|
+
}
|
72
|
+
assert_equal(expected, Task.activity_trackers)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_add_multiple_activities
|
76
|
+
User.activities_for(:tasks) { track :create }
|
77
|
+
Project.activities_for(:tasks) { track :create }
|
78
|
+
|
79
|
+
@project = Project.create(:user => @user)
|
80
|
+
@task = @project.tasks.create(:user => @user, :name => "New task")
|
81
|
+
|
82
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "create"})
|
83
|
+
assert_equal 1, @project.activities.count(:conditions => {:action => "create"})
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_store_attributes_for_activity
|
87
|
+
User.activities_for(:tasks) do
|
88
|
+
track :create
|
89
|
+
end
|
90
|
+
|
91
|
+
@task = @user.tasks.create(:name => "New task")
|
92
|
+
@activity = @user.activities.first
|
93
|
+
|
94
|
+
assert_equal @task.attributes.symbolize_keys, @activity.data
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_activity_for_create
|
98
|
+
User.activities_for(:tasks) do
|
99
|
+
track :create
|
100
|
+
end
|
101
|
+
|
102
|
+
@task = @user.tasks.create(:name => "New task")
|
103
|
+
@task.update_attribute :name, "Updated task"
|
104
|
+
@task.destroy
|
105
|
+
|
106
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "create"})
|
107
|
+
assert_equal 1, @user.activities.count
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_activity_for_destroy
|
111
|
+
User.activities_for(:tasks) do
|
112
|
+
track :destroy
|
113
|
+
end
|
114
|
+
|
115
|
+
@task = @user.tasks.create(:name => "New task")
|
116
|
+
@task.update_attribute :name, "Updated task"
|
117
|
+
@task.destroy
|
118
|
+
|
119
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "destroy"})
|
120
|
+
assert_equal 1, @user.activities.count
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_activity_for_update
|
124
|
+
User.activities_for(:tasks) do
|
125
|
+
track :update
|
126
|
+
end
|
127
|
+
|
128
|
+
@task = @user.tasks.create(:name => "New task")
|
129
|
+
@task.update_attribute :name, "Updated task"
|
130
|
+
@task.destroy
|
131
|
+
|
132
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "update"})
|
133
|
+
assert_equal 1, @user.activities.count
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_create_activities_for_all_actions
|
137
|
+
User.activities_for(:tasks) do
|
138
|
+
track :create
|
139
|
+
track :update
|
140
|
+
track :destroy
|
141
|
+
end
|
142
|
+
|
143
|
+
@task = @user.tasks.create(:name => "New task")
|
144
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "create"})
|
145
|
+
|
146
|
+
@task.update_attribute :name, "Updated task"
|
147
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "update"})
|
148
|
+
|
149
|
+
@task.destroy
|
150
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "destroy"})
|
151
|
+
|
152
|
+
assert_equal 3, @user.activities.count
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_create_activity_respecting_the_if_option_using_symbol
|
156
|
+
User.activities_for(:projects) do
|
157
|
+
track :renamed, :on => :update, :if => :name_changed?
|
158
|
+
end
|
159
|
+
|
160
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
161
|
+
@project.update_attribute :name, "Updated project"
|
162
|
+
|
163
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "renamed"})
|
164
|
+
assert_equal 1, @user.activities.count
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_dont_create_activity_when_if_evaluation_returns_false_symbol
|
168
|
+
User.activities_for(:projects) do
|
169
|
+
track :renamed, :on => :update, :if => :name_changed?
|
170
|
+
end
|
171
|
+
|
172
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
173
|
+
assert_equal 0, Activity.count
|
174
|
+
|
175
|
+
@project.update_attribute :status, "archived"
|
176
|
+
assert_equal 0, Activity.count
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_create_activity_respecting_the_if_option_using_block
|
180
|
+
User.activities_for(:projects) do
|
181
|
+
track :renamed, :on => :update, :if => proc {|r| r.name_changed?}
|
182
|
+
end
|
183
|
+
|
184
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
185
|
+
@project.update_attribute :name, "Updated project"
|
186
|
+
|
187
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "renamed"})
|
188
|
+
assert_equal 1, @user.activities.count
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_dont_create_activity_when_if_evaluation_returns_false_block
|
192
|
+
User.activities_for(:projects) do
|
193
|
+
track :renamed, :on => :update, :if => proc {|r| r.name_changed?}
|
194
|
+
end
|
195
|
+
|
196
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
197
|
+
assert_equal 0, Activity.count
|
198
|
+
|
199
|
+
@project.update_attribute :status, "archived"
|
200
|
+
assert_equal 0, Activity.count
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_create_activity_respecting_the_unless_option_using_symbol
|
204
|
+
User.activities_for(:projects) do
|
205
|
+
track :renamed, :on => :update, :unless => :status_changed?
|
206
|
+
end
|
207
|
+
|
208
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
209
|
+
@project.update_attribute :name, "Updated project"
|
210
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "renamed"})
|
211
|
+
assert_equal 1, @user.activities.count
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_create_activity_respecting_the_unless_option_using_block
|
215
|
+
User.activities_for(:projects) do
|
216
|
+
track :renamed, :on => :update, :unless => proc {|r| r.status_changed?}
|
217
|
+
end
|
218
|
+
|
219
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
220
|
+
@project.update_attribute :name, "Updated project"
|
221
|
+
assert_equal 1, @user.activities.count(:conditions => {:action => "renamed"})
|
222
|
+
assert_equal 1, @user.activities.count
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_dont_create_activity_when_unless_evaluation_returns_false_block
|
226
|
+
User.activities_for(:projects) do
|
227
|
+
track :renamed, :on => :update, :unless => proc {|r| r.status_changed?}
|
228
|
+
end
|
229
|
+
|
230
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
231
|
+
@project.update_attributes :status => "archived", :name => "Updated project"
|
232
|
+
assert_equal 0, Activity.count
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_dont_create_activity_when_unless_evaluation_returns_false_symbol
|
236
|
+
User.activities_for(:projects) do
|
237
|
+
track :renamed, :on => :update, :unless => :status_changed?
|
238
|
+
end
|
239
|
+
|
240
|
+
@project = @user.projects.create(:name => "New project", :status => "opened")
|
241
|
+
@project.update_attributes :status => "archived", :name => "Updated project"
|
242
|
+
assert_equal 0, Activity.count
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Task < ActiveRecord::Base
|
2
|
+
belongs_to :user
|
3
|
+
belongs_to :project
|
4
|
+
end
|
5
|
+
|
6
|
+
class Project < ActiveRecord::Base
|
7
|
+
belongs_to :user
|
8
|
+
has_many :milestones
|
9
|
+
has_many :tasks
|
10
|
+
end
|
11
|
+
|
12
|
+
class Milestone < ActiveRecord::Base
|
13
|
+
belongs_to :user
|
14
|
+
belongs_to :project
|
15
|
+
end
|
16
|
+
|
17
|
+
class User < ActiveRecord::Base
|
18
|
+
has_many :milestones
|
19
|
+
has_many :tasks
|
20
|
+
has_many :projects
|
21
|
+
end
|
data/test/schema.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :users do |t|
|
3
|
+
t.string :login
|
4
|
+
end
|
5
|
+
|
6
|
+
create_table :tasks do |t|
|
7
|
+
t.string :name
|
8
|
+
t.references :user, :project
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :milestones do |t|
|
12
|
+
t.string :name
|
13
|
+
t.references :user, :project
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :projects do |t|
|
17
|
+
t.string :name, :status
|
18
|
+
t.references :user
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table :activities do |t|
|
22
|
+
t.references :tracker, :polymorphic => true, :null => false
|
23
|
+
t.references :trackable, :polymorphic => true, :null => false
|
24
|
+
t.string :action, :null => false
|
25
|
+
t.text :data, :null => true
|
26
|
+
t.timestamps
|
27
|
+
end
|
28
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
gem "test-unit"
|
3
|
+
require "test/unit"
|
4
|
+
require "active_record"
|
5
|
+
require "mocha"
|
6
|
+
|
7
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
8
|
+
load "schema.rb"
|
9
|
+
|
10
|
+
require "activities"
|
11
|
+
require "resources/models"
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activities
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Nando Vieira
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-13 00:00:00 -03:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: activerecord
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description:
|
33
|
+
email: fnando.vieira@gmail.com
|
34
|
+
executables: []
|
35
|
+
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files:
|
39
|
+
- README.rdoc
|
40
|
+
files:
|
41
|
+
- README.rdoc
|
42
|
+
- Rakefile
|
43
|
+
- lib/activities.rb
|
44
|
+
- lib/activities/active_record.rb
|
45
|
+
- lib/activities/active_record/class_methods.rb
|
46
|
+
- lib/activities/active_record/instance_methods.rb
|
47
|
+
- lib/activities/activity.rb
|
48
|
+
- lib/activities/dsl.rb
|
49
|
+
- lib/activities/helper.rb
|
50
|
+
- lib/activities/version.rb
|
51
|
+
- test/activities/active_record_test.rb
|
52
|
+
- test/resources/models.rb
|
53
|
+
- test/schema.rb
|
54
|
+
- test/test_helper.rb
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://github.com/fnando/activities
|
57
|
+
licenses: []
|
58
|
+
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --charset=UTF-8
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.6
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: A framework for aggregating social activity.
|
85
|
+
test_files:
|
86
|
+
- test/activities/active_record_test.rb
|
87
|
+
- test/resources/models.rb
|
88
|
+
- test/schema.rb
|
89
|
+
- test/test_helper.rb
|