Permalink
Browse files

Added the user stamp files. Updated README and install.rb.

  • Loading branch information...
1 parent 4fa62b5 commit 2ef9f29cda7a4a47dce64124b0b55b12b5c080a6 @jnunemaker committed Oct 17, 2008
Showing with 418 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +20 −0 MIT-LICENSE
  3. +31 −0 README
  4. +11 −0 Rakefile
  5. +5 −0 init.rb
  6. +15 −0 install.rb
  7. +48 −0 lib/user_stamp.rb
  8. +24 −0 spec/spec_helper.rb
  9. +51 −0 spec/user_stamp_class_methods_spec.rb
  10. +51 −0 spec/user_stamp_spec.rb
  11. +161 −0 spec/user_stamp_sweeper_spec.rb
View
1 .gitignore
@@ -0,0 +1 @@
+.DS_Store
View
20 MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 [John Nunemaker]
+
+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:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+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.
View
31 README
@@ -0,0 +1,31 @@
+UserStamp
+=========
+
+Rails plugin that makes stamping records with a user when they are
+created and updated dirt simple. It assumes that your controller has
+a current_user method. It also assumes that any record being stamped
+has two attributes--creator_id and updater_id. You can override both
+of these assumptions easily.
+
+Setup
+=====
+
+1. Install plugin
+2. Add user_stamp to application.rb, like the following:
+
+ class ApplicationController < ActionController::Base
+ user_stamp Post, Asset, Job
+ end
+
+
+Defaults
+========
+UserStamp.creator_attribute = :creator_id
+UserStamp.updater_attribute = :updater_id
+UserStamp.current_user_method = :current_user
+
+If your user stamped columns and current_user method are different,
+just create an initializer such as config/initializers/user_stamp.rb
+and copy and paste the defaults above, changing them to fit your app.
+
+Copyright (c) 2008 [John Nunemaker], released under the MIT license
View
11 Rakefile
@@ -0,0 +1,11 @@
+require 'rake'
+require 'spec/rake/spectask'
+
+desc 'Default: run specs.'
+task :default => :spec
+
+desc 'Run the specs'
+Spec::Rake::SpecTask.new(:spec) do |t|
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
+ t.spec_files = FileList['spec/**/*_spec.rb']
+end
View
5 init.rb
@@ -0,0 +1,5 @@
+require 'user_stamp'
+
+class ActionController::Base
+ extend UserStamp::ClassMethods
+end
View
15 install.rb
@@ -0,0 +1,15 @@
+instructions = <<EOF
+
+#{'*' * 62}
+Don't forget to add user stamp to your application controller.
+
+ class ApplicationController < ActionController::Base
+ user_stamp Post, Asset, Job
+ end
+
+View the README for more information.
+#{'*' * 62}
+
+EOF
+
+puts instructions
View
48 lib/user_stamp.rb
@@ -0,0 +1,48 @@
+module UserStamp
+ mattr_accessor :creator_attribute
+ mattr_accessor :updater_attribute
+ mattr_accessor :current_user_method
+
+ def self.creator_assignment_method
+ "#{UserStamp.creator_attribute}="
+ end
+
+ def self.updater_assignment_method
+ "#{UserStamp.updater_attribute}="
+ end
+
+ module ClassMethods
+ def user_stamp(*models)
+ models.each { |klass| klass.add_observer(UserStampSweeper.instance) }
+
+ class_eval do
+ cache_sweeper :user_stamp_sweeper
+ end
+ end
+ end
+end
+
+UserStamp.creator_attribute = :creator_id
+UserStamp.updater_attribute = :updater_id
+UserStamp.current_user_method = :current_user
+
+class UserStampSweeper < ActionController::Caching::Sweeper
+ def before_save(record)
+ return unless current_user
+
+ if record.respond_to?(UserStamp.creator_assignment_method) && record.new_record?
+ record.send(UserStamp.creator_assignment_method, current_user.id)
+ end
+
+ if record.respond_to?(UserStamp.updater_assignment_method)
+ record.send(UserStamp.updater_assignment_method, current_user.id)
+ end
+ end
+
+ private
+ def current_user
+ if controller.respond_to?(UserStamp.current_user_method)
+ controller.send UserStamp.current_user_method
+ end
+ end
+end
View
24 spec/spec_helper.rb
@@ -0,0 +1,24 @@
+require 'rubygems'
+
+gem 'rspec'
+require 'spec'
+
+%w[activesupport activerecord actionpack].each do |lib|
+ gem lib
+ require lib
+end
+
+require 'action_controller'
+
+$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+require 'user_stamp'
+
+UserStampSweeper.instance
+
+class User
+ attr_accessor :id
+
+ def initialize(id);
+ @id = id
+ end
+end
View
51 spec/user_stamp_class_methods_spec.rb
@@ -0,0 +1,51 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+class FauxModelBase
+ def self.add_observer(observer_instance); end
+end
+
+class Post < FauxModelBase; end
+class Category < FauxModelBase; end
+class Label < FauxModelBase; end
+
+class FauxApplicationController
+ def self.cache_sweeper(sweepers); end
+
+ def self.current_user
+ User.new(220)
+ end
+end
+
+class PostsController < FauxApplicationController
+ extend UserStamp::ClassMethods
+end
+
+describe UserStamp::ClassMethods do
+ before do
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :current_user
+ end
+
+ it "should add user_stamp method" do
+ PostsController.respond_to?(:user_stamp).should == true
+ end
+
+ def user_stamp
+ PostsController.user_stamp Post, Category, Label
+ end
+
+ describe "#user_stamp" do
+ it "should add UserStampSweeper as observer for each model" do
+ [Post, Category, Label].each do |klass|
+ klass.should_receive(:add_observer).with(UserStampSweeper.instance).once
+ end
+ user_stamp
+ end
+
+ it "should setup cache sweeper for controller" do
+ PostsController.should_receive(:cache_sweeper).with(:user_stamp_sweeper).once
+ user_stamp
+ end
+ end
+end
View
51 spec/user_stamp_spec.rb
@@ -0,0 +1,51 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe UserStamp do
+ before do
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :current_user
+ end
+
+ it "should default creator_attribute to creator_id" do
+ UserStamp.creator_attribute.should == :creator_id
+ end
+
+ it "should default updater_attribute to updater_id" do
+ UserStamp.updater_attribute.should == :updater_id
+ end
+
+ it "should default current_user_method to current_user" do
+ UserStamp.current_user_method.should == :current_user
+ end
+
+ it "should have accessor for creator_attribute" do
+ UserStamp.creator_attribute = 'mofo_id'
+ UserStamp.creator_attribute.should == 'mofo_id'
+ end
+
+ it "should have accessor for updater_attribute" do
+ UserStamp.updater_attribute = 'mofo_id'
+ UserStamp.updater_attribute.should == 'mofo_id'
+ end
+
+ it "should have accessor for current_user_method" do
+ UserStamp.current_user_method = 'my_current_user'
+ UserStamp.current_user_method.should == 'my_current_user'
+ end
+
+ describe "assignment methods" do
+ before do
+ UserStamp.creator_attribute = 'creator_mofo_id'
+ UserStamp.updater_attribute = 'updater_mofo_id'
+ end
+
+ it "should include creator assignment method" do
+ UserStamp.creator_assignment_method.should == 'creator_mofo_id='
+ end
+
+ it "should include updater assignment method" do
+ UserStamp.updater_assignment_method.should == 'updater_mofo_id='
+ end
+ end
+end
View
161 spec/user_stamp_sweeper_spec.rb
@@ -0,0 +1,161 @@
+require File.dirname(__FILE__) + '/spec_helper'
+
+class PostsController
+ def self.current_user
+ User.new(220)
+ end
+end
+
+describe UserStampSweeper, "#before_save" do
+ before do
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :current_user
+ @sweeper = UserStampSweeper.instance
+ @sweeper.stub!(:controller).and_return(PostsController)
+ end
+
+ describe "(with new record)" do
+ it "should set creator_id if attribute exists" do
+ record = mock('Record', :creator_id= => nil, :updater_id= => nil, :new_record? => true)
+ record.should_receive(:creator_id=).with(220).once
+ @sweeper.before_save(record)
+ end
+
+ it "should NOT set creator_id if attribute does not exist" do
+ record = mock('Record', :new_record? => true, :updater_id= => nil, :respond_to? => false)
+ record.should_receive(:respond_to?).with("creator_id=").and_return(false)
+ record.should_not_receive(:creator_id=)
+ @sweeper.before_save(record)
+ end
+ end
+
+ describe "(with non new record)" do
+ it "should NOT set creator_id if attribute exists" do
+ record = mock('Record', :creator_id= => nil, :updater_id= => nil, :new_record? => false)
+ record.should_not_receive(:creator_id=)
+ @sweeper.before_save(record)
+ end
+
+ it "should NOT set creator_id if attribute does not exist" do
+ record = mock('Record', :updater_id= => nil, :new_record? => false)
+ record.should_not_receive(:creator_id=)
+ @sweeper.before_save(record)
+ end
+ end
+
+ it "should set updater_id if attribute exists" do
+ record = mock('Record', :creator_id= => nil, :updater_id= => nil, :new_record? => :false)
+ record.should_receive(:updater_id=)
+ @sweeper.before_save(record)
+ end
+
+ it "should NOT set updater_id if attribute does not exist" do
+ record = mock('Record', :creator_id= => nil, :updater_id= => nil, :new_record? => :false, :respond_to? => false)
+ record.should_receive(:respond_to?).with("updater_id=").and_return(false)
+ record.should_not_receive(:updater_id=)
+ @sweeper.before_save(record)
+ end
+end
+
+describe UserStampSweeper, "#before_save (with custom attribute names)" do
+ before do
+ UserStamp.creator_attribute = :created_by
+ UserStamp.updater_attribute = :updated_by
+ UserStamp.current_user_method = :current_user
+ @sweeper = UserStampSweeper.instance
+ @sweeper.stub!(:controller).and_return(PostsController)
+ end
+
+ describe "(with new record)" do
+ it "should set created_by if attribute exists" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => true)
+ record.should_receive(:created_by=).with(220).once
+ @sweeper.before_save(record)
+ end
+
+ it "should NOT set created_by if attribute does not exist" do
+ record = mock('Record', :new_record? => true, :updated_by= => nil, :respond_to? => false)
+ record.should_receive(:respond_to?).with("created_by=").and_return(false)
+ record.should_not_receive(:created_by=)
+ @sweeper.before_save(record)
+ end
+ end
+
+ describe "(with non new record)" do
+ it "should NOT set created_by if attribute exists" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => false)
+ record.should_not_receive(:created_by=)
+ @sweeper.before_save(record)
+ end
+
+ it "should NOT set created_by if attribute does not exist" do
+ record = mock('Record', :updated_by= => nil, :new_record? => false)
+ record.should_not_receive(:created_by=)
+ @sweeper.before_save(record)
+ end
+ end
+
+ it "should set updated_by if attribute exists" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => :false)
+ record.should_receive(:updated_by=)
+ @sweeper.before_save(record)
+ end
+
+ it "should NOT set updated_by if attribute does not exist" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => :false, :respond_to? => false)
+ record.should_receive(:respond_to?).with("updated_by=").and_return(false)
+ record.should_not_receive(:updated_by=)
+ @sweeper.before_save(record)
+ end
+end
+
+describe UserStampSweeper, "#current_user" do
+ before do
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :current_user
+ @sweeper = UserStampSweeper.instance
+ end
+
+ it "should send current_user if controller responds to it" do
+ user = mock('User')
+ controller = mock('Controller', :current_user => user)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_receive(:current_user)
+ @sweeper.send(:current_user)
+ end
+
+ it "should not send current_user if controller does not respond to it" do
+ user = mock('User')
+ controller = mock('Controller', :respond_to? => false)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_not_receive(:current_user)
+ @sweeper.send(:current_user)
+ end
+end
+
+describe UserStampSweeper, "#current_user (with custom current_user_method)" do
+ before do
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :my_user
+ @sweeper = UserStampSweeper.instance
+ end
+
+ it "should send current_user if controller responds to it" do
+ user = mock('User')
+ controller = mock('Controller', :my_user => user)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_receive(:my_user)
+ @sweeper.send(:current_user)
+ end
+
+ it "should not send current_user if controller does not respond to it" do
+ user = mock('User')
+ controller = mock('Controller', :respond_to? => false)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_not_receive(:my_user)
+ @sweeper.send(:current_user)
+ end
+end

0 comments on commit 2ef9f29

Please sign in to comment.