linkingpaths-acts_as_scribe 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -23,20 +23,47 @@ Install
23
23
 
24
24
  `rake db:migrate`
25
25
 
26
- Usage
27
- -----
26
+ Record activities in your models
27
+ ---------------------------------------------
28
28
 
29
- * Make your ActiveRecord model acts as scribe.
30
29
  <pre>
31
30
  class Comment < ActiveRecord::Base
32
31
  record_activity_of :user
33
32
  end
34
33
  </pre>
34
+ You can use any association that is related to an user:
35
+ <pre>
36
+ class Post < ActiveRecord::Base
37
+ belongs_to :author, :class_name => "User"
38
+ record_activity_of :author
39
+ end
40
+ </pre>
41
+
42
+ This will register automatically a new activity when you create or destroy a new record. If you want control over the activities registration based on your model's state just use the :if option
35
43
 
36
- * If you want to record activities not related to any specific model just use `record_activities :activity` in your user model:
37
44
  <pre>
38
- class User < ActiveRecord::Base
39
- record_activities [:featured_on_home, :logged_in, :logged_out]
45
+ class Post < ActiveRecord::Base
46
+ belongs_to :author, :class_name => "User"
47
+ record_activity_of :author, :if => Proc.new { |post| post.private == false }
48
+ end
49
+ </pre>
50
+
51
+
52
+ Record activities without related item
53
+ --------------------------------------
54
+
55
+ If you want to record activities not related to any specific model just use `Activity.report` in your code:
56
+ <pre>
57
+ def grant_admin(user)
58
+ user.admin = true
59
+ Activity.report(current_user, :grant_admin, user)
60
+ end
61
+ </pre>
62
+ If the action is not related to any item, just don't use it.
63
+ <pre>
64
+ def login
65
+ current_user = User.find(…)
66
+ Activity.report(current_user, :login)
40
67
  end
41
68
  </pre>
42
69
 
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 0
4
+ :major: 0
@@ -8,9 +8,11 @@ class ActsAsScribeMigration < ActiveRecord::Migration
8
8
  t.string :item_type
9
9
  t.timestamps
10
10
  end
11
+ add_index :activities, [:item_type, :item_id]
11
12
  end
12
13
 
13
14
  def self.down
15
+ remove_index :activities, [:item_type, :item_id]
14
16
  drop_table :activities
15
17
  end
16
18
 
data/lib/activity.rb CHANGED
@@ -1,17 +1,44 @@
1
1
  class Activity < ActiveRecord::Base
2
+ named_scope :by_user, lambda { |users|
3
+ { :conditions => { :user_id => users}}
4
+ }
5
+
6
+ named_scope :by_action, lambda { |action|
7
+ { :conditions => { :action => action }}
8
+ }
9
+
10
+ named_scope :by_item, lambda { |item|
11
+ { :conditions => { :item_type => item.class.name, :item_id => item.id }}
12
+ }
13
+
14
+ named_scope :created_since, lambda { |time_ago|
15
+ { :conditions => ['created_at > ?', time_ago]}
16
+ }
17
+
18
+
2
19
  belongs_to :user
3
20
  belongs_to :item, :polymorphic => true
4
21
  validates_presence_of :user_id
5
22
 
6
23
  def self.created_by(user)
7
- Activity.find(:all, :conditions => { :user_id => user.id})
24
+ raise "Activity.created_by(user) has been deprecated. Use Activity.by_user(user) instead."
8
25
  end
9
26
 
10
27
  def self.without_model_created_by(user)
11
- Activity.find(:all, :conditions => { :user_id => user.id, :item_type => nil, :item_id => nil})
28
+ raise "Activity.without_model_created_by(user) has been deprecated. Use Activity.by_user(user) and filter the results instead."
12
29
  end
13
30
 
14
31
  def without_model?
15
32
  item.nil?
16
33
  end
17
- end
34
+
35
+ def self.report(user, action, object=nil)
36
+ returning Activity.new do |a|
37
+ a.item = object if object
38
+ a.action = action
39
+ a.user = user
40
+ a.save!
41
+ end
42
+ end
43
+
44
+ end
@@ -1,3 +1,4 @@
1
+ require 'activity'
1
2
  require 'scribe'
2
3
 
3
4
  ActiveRecord::Base.send :include, LinkingPaths::Acts::Scribe
data/lib/scribe.rb CHANGED
@@ -14,7 +14,14 @@ module LinkingPaths
14
14
  has_many :activities, :as => :item, :dependent => :destroy
15
15
  after_create do |record|
16
16
  unless options[:if].kind_of?(Proc) and not options[:if].call(record)
17
- record.create_activity_from_self
17
+ user = record.send(activity_options[:actor])
18
+ Activity.report(user, :create, record)
19
+ end
20
+ end
21
+ after_destroy do |record|
22
+ unless options[:if].kind_of?(Proc) and not options[:if].call(record)
23
+ user = record.send(activity_options[:actor])
24
+ Activity.report(user, :destroy, record)
18
25
  end
19
26
  end
20
27
  }
@@ -22,13 +29,9 @@ module LinkingPaths
22
29
  end
23
30
 
24
31
  def record_activities(actions = [])
25
- include_scribe_instance_methods {
26
- has_many :activities
27
- has_many :activities_without_model, :class_name => "Activity", :conditions => { :item_type => nil, :item_id => nil }
28
- }
29
- self.activity_options.merge! :actions => actions
32
+ raise "record_activities(#{actions.join ','}) has been deprecated. Use Activity.report(user, #{actions.first}), etc. instead."
30
33
  end
31
-
34
+
32
35
  def include_scribe_instance_methods(&block)
33
36
  unless included_modules.include? InstanceMethods
34
37
  yield if block_given?
@@ -37,32 +40,13 @@ module LinkingPaths
37
40
  include InstanceMethods
38
41
  end
39
42
  end
40
-
43
+
41
44
  end
42
45
 
43
46
  module InstanceMethods
44
-
45
- def create_activity_from_self
46
- activity = Activity.new
47
- activity.item = self
48
- activity.action = ActiveSupport::Inflector::underscore(self.class)
49
- actor_id = self.send( activity_options[:actor].to_s + "_id" )
50
- activity.user_id = actor_id
51
- activity.save
52
- end
53
-
54
47
  def record_activity(action)
55
- if activity_options[:actions] && activity_options[:actions].include?(action)
56
- activity = Activity.new
57
- activity.action = action.to_s
58
- activity.user_id = self.id
59
- activity.save!
60
- else
61
- raise "The action #{action} can't be tracked."
62
- end
63
- end
64
-
65
-
48
+ raise "record_activity has been deprecated. Use Activity.report(actor, action, item)."
49
+ end
66
50
  end
67
51
 
68
52
  end
data/spec/factories.rb ADDED
@@ -0,0 +1,14 @@
1
+ Factory.define :user do |user|
2
+ end
3
+ Factory.define :group do |group|
4
+ end
5
+ Factory.define :activity do |activity|
6
+ activity.association :user
7
+ end
8
+ Factory.define :membership do |membership|
9
+ membership.association :user
10
+ end
11
+ Factory.define :post do |post|
12
+ post.private false
13
+ post.association :author, :factory => :user
14
+ end
data/spec/models.rb ADDED
@@ -0,0 +1,20 @@
1
+ class Post < ActiveRecord::Base
2
+ belongs_to :author, :class_name => "User"
3
+ record_activity_of :author, :if => Proc.new { |post| post.private == false }
4
+ end
5
+
6
+
7
+ class Membership < ActiveRecord::Base
8
+ belongs_to :user
9
+ belongs_to :group
10
+ record_activity_of :user
11
+ end
12
+
13
+ class Group < ActiveRecord::Base
14
+ has_many :users, :through => :memberships
15
+ end
16
+
17
+ class User < ActiveRecord::Base
18
+ has_many :groups, :through => :memberships
19
+ end
20
+
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Activity" do
4
+
5
+ describe "when creating an instance of a model with a actor != user" do
6
+ before do
7
+ @p = Factory :post
8
+ @act = Activity.last
9
+ end
10
+ it "should find the created activity by the user" do
11
+ @act.user.should == @p.author
12
+ end
13
+ end
14
+
15
+ describe "when creating an instance of a model with a :if option" do
16
+ before do
17
+ @p = Factory(:post, :private => true)
18
+ end
19
+ it "should not create the activity" do
20
+ Activity.by_item(@p).should have(0).things
21
+ end
22
+ end
23
+
24
+ describe "when creating a new instance of a tracked model" do
25
+ before do
26
+ @m = Factory :membership
27
+ @act = Activity.last
28
+ end
29
+ it "should find the created activity by the user" do
30
+ Activity.by_user(@m.user).should include(@act)
31
+ end
32
+ it "should find the created activity by an users list" do
33
+ Activity.by_user([@m.user, Factory(:user)]).should include(@act)
34
+ end
35
+ it "should find the created activity by the action" do
36
+ Activity.by_action(:create).should include(@act)
37
+ end
38
+ it "should find the created activity by the item" do
39
+ Activity.by_item(@m).should include(@act)
40
+ end
41
+ it "should find the created activity by the creation date" do
42
+ Activity.created_since(5.second.ago).should include(@act)
43
+ end
44
+ it "should be related to an user" do
45
+ @act.should respond_to(:user)
46
+ end
47
+ it "should be related to an item" do
48
+ @act.should respond_to(:item)
49
+ end
50
+ end
51
+
52
+ describe "when destroying an instance of a tracked model" do
53
+ before do
54
+ Factory(:membership).destroy
55
+ @act = Activity.last
56
+ end
57
+ it "should find the created activity by the action" do
58
+ Activity.by_action(:destroy).should include(@act)
59
+ end
60
+ end
61
+
62
+ describe "when reporting a specific action" do
63
+ it "should create a new activity" do
64
+ lambda {
65
+ Activity.report(Factory(:user), :grant_admin, Factory(:group))
66
+ }.should change(Activity, :count).by(1)
67
+ end
68
+ it "should allow to report actions without a item" do
69
+ Activity.report(Factory(:user), :login)
70
+ end
71
+ end
72
+
73
+ end
@@ -1,9 +1,4 @@
1
1
  ActiveRecord::Schema.define(:version => 1) do
2
- create_table :jaikus do |t|
3
- t.string :content
4
- t.integer :user_id
5
- t.timestamps
6
- end
7
2
  create_table :activities do |t|
8
3
  t.integer :user_id
9
4
  t.string :action
@@ -14,4 +9,16 @@ ActiveRecord::Schema.define(:version => 1) do
14
9
  create_table :users do |t|
15
10
  t.string :login
16
11
  end
12
+ create_table :groups do |t|
13
+ t.string :name
14
+ end
15
+ create_table :memberships do |t|
16
+ t.integer :user_id
17
+ t.integer :group_id
18
+ end
19
+ create_table :posts do |t|
20
+ t.integer :author_id
21
+ t.boolean :private
22
+ t.string :title
23
+ end
17
24
  end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ gem 'activerecord'
3
+ require 'active_record'
4
+ require 'factory_girl'
5
+ require 'spec'
6
+
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
8
+ require 'acts_as_scribe'
9
+
10
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
11
+ load(File.dirname(__FILE__) + "/schema.rb")
12
+ load(File.dirname(__FILE__) + "/models.rb")
13
+
14
+
15
+
16
+ Spec::Runner.configure do |config|
17
+
18
+ end
metadata CHANGED
@@ -1,21 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linkingpaths-acts_as_scribe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Linking Paths
8
+ - "Aitor Garc\xC3\xADa"
9
+ - Roberto Salicio
8
10
  autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
13
 
12
- date: 2008-10-16 00:00:00 -07:00
14
+ date: 2009-02-24 00:00:00 -08:00
13
15
  default_executable:
14
16
  dependencies: []
15
17
 
16
18
  description: A simple plugin that allows to keep track of the users activity. Common uses could be user's wall, public timeline portlets, etc...
17
- email:
18
- - aitor@linkingpaths.com
19
+ email: aitor@linkingpaths.com
19
20
  executables: []
20
21
 
21
22
  extensions: []
@@ -23,38 +24,29 @@ extensions: []
23
24
  extra_rdoc_files: []
24
25
 
25
26
  files:
26
- - MIT-LICENSE
27
27
  - README.markdown
28
- - Rakefile
29
- - acts_as_scribe.gemspec
30
- - generators
28
+ - VERSION.yml
31
29
  - generators/acts_as_scribe_migration
32
30
  - generators/acts_as_scribe_migration/acts_as_scribe_migration_generator.rb
33
31
  - generators/acts_as_scribe_migration/templates
34
32
  - generators/acts_as_scribe_migration/templates/migration.rb
35
33
  - generators/acts_as_scribe_migration/USAGE
36
- - init.rb
37
- - lib
38
34
  - lib/activity.rb
39
35
  - lib/acts_as_scribe.rb
40
36
  - lib/scribe.rb
41
- - test
42
- - test/.DS_Store
43
- - test/factories.rb
44
- - test/functional
45
- - test/functional/acts_as_scribe_test.rb
46
- - test/schema.rb
47
- - test/test_helper.rb
48
- - test/unit
49
- - test/unit/activity_test.rb
37
+ - spec/factories.rb
38
+ - spec/models
39
+ - spec/models/activity_spec.rb
40
+ - spec/models.rb
41
+ - spec/schema.rb
42
+ - spec/spec.opts
43
+ - spec/spec_helper.rb
50
44
  has_rdoc: true
51
45
  homepage: http://github.com/linkingpaths/acts_as_scribe
52
- post_install_message: |+
53
-
54
- For more information on acts_as_scribe, see http://github.com/linkingpaths/acts_as_scribe
55
-
56
- rdoc_options: []
57
-
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --inline-source
49
+ - --charset=UTF-8
58
50
  require_paths:
59
51
  - lib
60
52
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -71,7 +63,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
63
  version:
72
64
  requirements: []
73
65
 
74
- rubyforge_project: acts_as_scribe
66
+ rubyforge_project:
75
67
  rubygems_version: 1.2.0
76
68
  signing_key:
77
69
  specification_version: 2
data/MIT-LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright (c) 2008 Linking Paths (http://www.linkingpaths.com)
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile DELETED
@@ -1,22 +0,0 @@
1
- require 'rake'
2
- require 'rake/testtask'
3
- require 'rake/rdoctask'
4
-
5
- desc 'Default: run unit tests.'
6
- task :default => :test
7
-
8
- desc 'Test the acts_as_scribe plugin.'
9
- Rake::TestTask.new(:test) do |t|
10
- t.libs << 'lib'
11
- t.pattern = 'test/**/*_test.rb'
12
- t.verbose = true
13
- end
14
-
15
- desc 'Generate documentation for the acts_as_scribe plugin.'
16
- Rake::RDocTask.new(:rdoc) do |rdoc|
17
- rdoc.rdoc_dir = 'rdoc'
18
- rdoc.title = 'ActsAsScribe'
19
- rdoc.options << '--line-numbers' << '--inline-source'
20
- rdoc.rdoc_files.include('README')
21
- rdoc.rdoc_files.include('lib/**/*.rb')
22
- end
@@ -1,22 +0,0 @@
1
- Gem::Specification.new do |s|
2
- s.name = %q{acts_as_scribe}
3
- s.version = "0.0.2"
4
-
5
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
- s.authors = ["Linking Paths"]
7
- s.date = %q{2008-10-16}
8
- s.description = %q{A simple plugin that allows to keep track of the users activity. Common uses could be user's wall, public timeline portlets, etc...}
9
- s.email = ["aitor@linkingpaths.com"]
10
- s.files = ["MIT-LICENSE", "README.markdown", "Rakefile", "acts_as_scribe.gemspec", "generators", "generators/acts_as_scribe_migration", "generators/acts_as_scribe_migration/acts_as_scribe_migration_generator.rb", "generators/acts_as_scribe_migration/templates", "generators/acts_as_scribe_migration/templates/migration.rb", "generators/acts_as_scribe_migration/USAGE", "init.rb", "lib", "lib/activity.rb", "lib/acts_as_scribe.rb", "lib/scribe.rb", "test", "test/.DS_Store", "test/factories.rb", "test/functional", "test/functional/acts_as_scribe_test.rb", "test/schema.rb", "test/test_helper.rb", "test/unit", "test/unit/activity_test.rb" ]
11
- s.has_rdoc = true
12
- s.homepage = %q{http://github.com/linkingpaths/acts_as_scribe}
13
- s.post_install_message = %q{
14
- For more information on acts_as_scribe, see http://github.com/linkingpaths/acts_as_scribe
15
-
16
- }
17
- s.require_paths = ["lib"]
18
- s.rubyforge_project = %q{acts_as_scribe}
19
- s.rubygems_version = %q{1.2.0}
20
- s.summary = %q{A simple plugin that allows to keep track of the users activity. Common uses could be user's wall, public timeline portlets, etc...}
21
-
22
- end
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require 'acts_as_scribe'
data/test/factories.rb DELETED
@@ -1,5 +0,0 @@
1
- Factory.define :user do |u|
2
- end
3
-
4
- Factory.define :jaiku do |u|
5
- end
@@ -1,46 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
-
3
- class ActsAsScribeTest < Test::Unit::TestCase
4
-
5
- context "The acts_as_scribe plugin" do
6
-
7
- setup do
8
- @margie = Factory(:user, :login => 'm.thatcher')
9
- @jaiku = Factory(:jaiku, :content => "To solve Britain’s economic Disease with Socialism is like treating leukaemia with leeches.", :user => @margie)
10
- @activity = @jaiku.activities.first
11
- end
12
-
13
- should 'include the correct methods on user and jaiku class' do
14
- [:activities, :create_activity_from_self].each{|method|
15
- assert @jaiku.respond_to?(method, "Jaiku should responds_to #{method}")
16
- }
17
- [:activities, :activities_without_model, :record_activity].each{|method|
18
- assert @margie.respond_to?(method, "Jaiku should responds_to #{method}")
19
- }
20
- end
21
- should 'create a new activity every time a jaiku is created' do
22
- assert_equal 1, @jaiku.activities.size, "Create a jaiku should create a new activity"
23
- end
24
-
25
- should 'link the activities created on a model with the user that is generating the activity' do
26
- assert_equal @margie, @activity.user, "The activity should be registered as made by the user that create the jaiku"
27
- end
28
-
29
- should 'link the new activities to the correct model and id' do
30
- assert_equal @jaiku.class.to_s, @activity.item_type, "The activity should be linked to the first jaiku"
31
- assert_equal @jaiku.id, @activity.item_id, "The activity should be linked to the first jaiku"
32
- end
33
-
34
- should 'raise an exception if we try to record an activity that is not defined on the user class' do
35
- assert_raise RuntimeError do
36
- @margie.record_activity :not_defined_featured
37
- end
38
- end
39
-
40
- should 'create an activity without model if we use the record_activity method on a user' do
41
- @margie.record_activity :featured_on_home
42
- assert_equal 1, @margie.activities_without_model.size, "Track an unlinked activity should create a new activity on the user model"
43
- end
44
-
45
- end
46
- end
data/test/test_helper.rb DELETED
@@ -1,39 +0,0 @@
1
- require 'test/unit'
2
- require 'rubygems'
3
-
4
- gem 'activerecord'
5
- require 'active_record'
6
-
7
- begin require 'redgreen'; rescue LoadError; end
8
-
9
- begin
10
- require 'shoulda'
11
- require 'shoulda/active_record'
12
- rescue LoadError => load_error
13
- $stderr.puts
14
- $stderr.puts "You need shoulda to run acts_as_scribe's tests. `gem install thoughtbot-shoulda` and try again."
15
- $stderr.puts
16
- exit
17
- end
18
-
19
- require 'factory_girl'
20
- require File.expand_path(File.dirname(__FILE__) + '/factories')
21
-
22
- require File.dirname(__FILE__) + "/../init"
23
-
24
-
25
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
26
- load(File.dirname(__FILE__) + "/schema.rb")
27
-
28
- class Jaiku < ActiveRecord::Base
29
- belongs_to :user
30
- record_activity_of :user
31
- end
32
-
33
- class User < ActiveRecord::Base
34
- has_many :jaikus
35
- record_activities [:featured_on_home, :logged_in, :logged_out]
36
- end
37
-
38
-
39
-
@@ -1,40 +0,0 @@
1
- require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
-
3
- class ActivityTest < Test::Unit::TestCase
4
-
5
- should_belong_to :user
6
- should_belong_to :item
7
-
8
- context 'An Activity model' do
9
-
10
- setup do
11
- @margie = Factory(:user, :login => 'm.thatcher')
12
- @britain = Factory(:jaiku, :content => "To solve Britain’s economic Disease with Socialism is like treating leukaemia with leeches.", :user => @margie)
13
- @margie_activities = @britain.activities
14
-
15
- @reagan = Factory(:user, :login => 'r.reagan')
16
- @reagan.record_activity :logged_in
17
- end
18
-
19
- context 'at class level' do
20
- should 'have a `created_by` method to allow us to find activities created by a given user' do
21
- assert Activity.respond_to?:created_by
22
- assert_same_elements @margie_activities, Activity.created_by(@margie)
23
- end
24
- should 'have a `without_model_created_by` method to allow us to find activities created by a given user and not related to any item' do
25
- assert Activity.respond_to?:without_model_created_by
26
- assert_same_elements @reagan.activities, Activity.without_model_created_by(@reagan)
27
- end
28
- end
29
- context 'at instance level' do
30
- should 'be linked to the correct item' do
31
- assert_equal @britain, @britain.activities.first.item
32
- end
33
- should 'not be linked to any item is the activity has been generated without a model' do
34
- assert_nil @reagan.activities.first.item
35
- assert @reagan.activities.first.without_model?
36
- end
37
- end
38
-
39
- end
40
- end