diff --git a/.gitignore b/.gitignore index edaf6dc..0c76dce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ +.DS_Store +Gemfile.lock +gemfiles/*.gemfile.lock pkg -.DS_Store \ No newline at end of file diff --git a/Appraisals b/Appraisals new file mode 100644 index 0000000..28bb8f0 --- /dev/null +++ b/Appraisals @@ -0,0 +1,11 @@ +appraise "activerecord23" do + gem "activerecord", "~> 2.3.14" +end + +appraise "activerecord30" do + gem "activerecord", "~> 3.0.10" +end + +appraise "activerecord31" do + gem "activerecord", "~> 3.1.1" +end diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c80ee36 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "http://rubygems.org" + +gemspec diff --git a/README.rdoc b/README.rdoc index 496f29f..f83d036 100644 --- a/README.rdoc +++ b/README.rdoc @@ -43,6 +43,10 @@ The rest all fit neatly in an options hash. - :subject is automatically set to self, which is good most of the time. You can however override it if you need to, using :subject. - :secondary_subject can let you specify something else that's related to the event. A comment to a blog post would be a good example. - :if => symbol or proc/lambda lets you put conditions on when a TimelineEvent is created. It's passed right to the after_xxx ActiveRecord event hook, so it's has the same behavior. +- :event_class_name => string specifying the event class name (or an array of them) you'd like you use. Defaults to "TimelineEvent". + - If you specify more than one event class name, an object for each will be created in the appropriate callbacks. +- any other parameter is treated as TimelineEvent's attribute + - This is useful if you add a custom field to timeline_events table Here's another example: diff --git a/Rakefile b/Rakefile index c2c65aa..65484cb 100644 --- a/Rakefile +++ b/Rakefile @@ -1,9 +1,13 @@ require 'rake' require 'rake/testtask' require 'rake/rdoctask' +require 'bundler/gem_tasks' +require 'appraisal' -desc 'Default: run unit tests.' -task :default => :test +desc 'Default: run unit tests against all supported versions of ActiveRecord' +task :default => ["appraisal:install"] do |t| + exec("rake appraisal test") +end desc 'Test the timeline_fu plugin.' Rake::TestTask.new(:test) do |t| @@ -12,20 +16,6 @@ Rake::TestTask.new(:test) do |t| t.verbose = true end -begin - require 'jeweler' - Jeweler::Tasks.new do |s| - s.name = "timeline_fu" - s.summary = %Q{Easily build timelines, much like GitHub's news feed} - s.email = "james@giraffesoft.ca" - s.homepage = "http://github.com/giraffesoft/timeline_fu" - s.description = "Easily build timelines, much like GitHub's news feed" - s.authors = ["James Golick", "Mathieu Martin", "Francois Beausoleil"] - end -rescue LoadError - puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" -end - desc 'Generate documentation for the timeline_fu plugin.' Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' diff --git a/VERSION.yml b/VERSION.yml deleted file mode 100644 index 3b60975..0000000 --- a/VERSION.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -:major: 0 -:minor: 4 -:patch: 1 diff --git a/gemfiles/activerecord23.gemfile b/gemfiles/activerecord23.gemfile new file mode 100644 index 0000000..cbeb2ff --- /dev/null +++ b/gemfiles/activerecord23.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source "http://rubygems.org" + +gem "activerecord", "~> 2.3.14" + +gemspec :path=>"../" \ No newline at end of file diff --git a/gemfiles/activerecord30.gemfile b/gemfiles/activerecord30.gemfile new file mode 100644 index 0000000..e7cf3ad --- /dev/null +++ b/gemfiles/activerecord30.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source "http://rubygems.org" + +gem "activerecord", "~> 3.0.10" + +gemspec :path=>"../" \ No newline at end of file diff --git a/gemfiles/activerecord31.gemfile b/gemfiles/activerecord31.gemfile new file mode 100644 index 0000000..336cfbb --- /dev/null +++ b/gemfiles/activerecord31.gemfile @@ -0,0 +1,7 @@ +# This file was generated by Appraisal + +source "http://rubygems.org" + +gem "activerecord", "~> 3.1.1" + +gemspec :path=>"../" \ No newline at end of file diff --git a/lib/timeline_fu.rb b/lib/timeline_fu.rb index 125e179..99bfb42 100644 --- a/lib/timeline_fu.rb +++ b/lib/timeline_fu.rb @@ -1,6 +1,7 @@ -require 'timeline_fu/fires' +require "active_record" -module TimelineFu +module TimelineFu + autoload :Fires, "timeline_fu/fires" end -ActiveRecord::Base.send :include, TimelineFu::Fires +ActiveRecord::Base.send(:include, TimelineFu::Fires) diff --git a/lib/timeline_fu/fires.rb b/lib/timeline_fu/fires.rb index 2bf71c3..75b01d9 100644 --- a/lib/timeline_fu/fires.rb +++ b/lib/timeline_fu/fires.rb @@ -16,9 +16,15 @@ def fires(event_type, opts) opts[:subject] = :self unless opts.has_key?(:subject) - method_name = :"fire_#{event_type}_after_#{opts[:on]}" + on = opts.delete(:on) + _if = opts.delete(:if) + _unless = opts.delete(:unless) + + event_class_names = Array(opts.delete(:event_class_name) || "TimelineEvent") + + method_name = :"fire_#{event_type}_after_#{on}" define_method(method_name) do - create_options = [:actor, :subject, :secondary_subject].inject({}) do |memo, sym| + create_options = opts.keys.inject({}) do |memo, sym| if opts[sym] if opts[sym].respond_to?(:call) memo[sym] = opts[sym].call(self) @@ -32,10 +38,12 @@ def fires(event_type, opts) end create_options[:event_type] = event_type.to_s - TimelineEvent.create!(create_options) + event_class_names.each do |class_name| + class_name.classify.constantize.create!(create_options) + end end - send(:"after_#{opts[:on]}", method_name, :if => opts[:if]) + send(:"after_#{on}", method_name, :if => _if, :unless => _unless) end end end diff --git a/lib/timeline_fu/version.rb b/lib/timeline_fu/version.rb new file mode 100644 index 0000000..8a73f9c --- /dev/null +++ b/lib/timeline_fu/version.rb @@ -0,0 +1,3 @@ +module TimelineFu + VERSION = "0.4.4" +end diff --git a/test/fires_test.rb b/test/fires_test.rb index 3be36f6..1646964 100644 --- a/test/fires_test.rb +++ b/test/fires_test.rb @@ -75,4 +75,25 @@ def test_should_set_secondary_subject_to_self_when_requested :event_type => 'comment_deleted') @comment.destroy end + + def test_should_set_additional_attributes_when_present + @site = Site.create(:name => 'foo.com') + @article = Article.new(:body => 'cool article!', :author => @james, :site => @site) + TimelineEvent.expects(:create!).with(:actor => @james, :subject => @article, :event_type => 'article_created', :site => @site) + @article.save + end + + def test_should_use_specified_event_class_when_present + @company = Company.new(:owner => @james, :name => 'A great company!') + CompanyEvent.expects(:create!).with(:actor => @james, :subject => @company, :event_type => 'company_created') + @company.save + end + + def test_should_support_specifying_multiple_event_classes + CompanyEvent.stubs(:create!) + @company = Company.create(:owner => @james, :name => 'A great company!') + CompanyEvent.expects(:create!).with(:actor => @james, :subject => @company, :event_type => 'company_updated') + IRSEvent.expects(:create!).with(:actor => @james, :subject => @company, :event_type => 'company_updated') + @company.save + end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 4312d2e..5eee0f7 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,10 +1,10 @@ require 'rubygems' -require 'activerecord' -require 'mocha' require 'test/unit' +require 'mocha' require 'logger' -require File.dirname(__FILE__)+'/../lib/timeline_fu' +$:.push File.expand_path("../lib", __FILE__) +require "timeline_fu" ActiveRecord::Base.configurations = {'sqlite3' => {:adapter => 'sqlite3', :database => ':memory:'}} ActiveRecord::Base.establish_connection('sqlite3') @@ -27,6 +27,20 @@ t.integer :list_id, :author_id t.string :body end + + create_table :sites do |t| + t.string :name + end + + create_table :articles do |t| + t.integer :site_id + t.string :body + end + + create_table :companies do |t| + t.integer :owner_id + t.string :name + end end class Person < ActiveRecord::Base @@ -64,6 +78,32 @@ class Comment < ActiveRecord::Base :secondary_subject => :self end +class Site < ActiveRecord::Base +end + +class Article < ActiveRecord::Base + belongs_to :author, :class_name => "Person" + belongs_to :site + + fires :article_created, :actor => :author, + :on => :create, + :site => :site +end + +class Company < ActiveRecord::Base + belongs_to :owner, :class_name => "Person" + + fires :company_created, :actor => :owner, + :on => :create, + :event_class_name => "CompanyEvent" + + fires :company_updated, :actor => :owner, + :on => :update, + :event_class_name => ["CompanyEvent", "IRSEvent"] +end + +IRSEvent = Class.new +CompanyEvent = Class.new TimelineEvent = Class.new class Test::Unit::TestCase diff --git a/timeline_fu.gemspec b/timeline_fu.gemspec index 7b84709..6cec7c1 100644 --- a/timeline_fu.gemspec +++ b/timeline_fu.gemspec @@ -1,55 +1,29 @@ # -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) +require "timeline_fu/version" Gem::Specification.new do |s| - s.name = %q{timeline_fu} - s.version = "0.4.1" - - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.name = "timeline_fu" + s.version = TimelineFu::VERSION s.authors = ["James Golick", "Mathieu Martin", "Francois Beausoleil"] - s.date = %q{2011-06-23} - s.description = %q{Easily build timelines, much like GitHub's news feed} - s.email = %q{james@giraffesoft.ca} - s.extra_rdoc_files = [ - "README.rdoc" - ] - s.files = [ - ".gitignore", - "MIT-LICENSE", - "README.rdoc", - "Rakefile", - "VERSION.yml", - "generators/timeline_fu/USAGE", - "generators/timeline_fu/templates/migration.rb", - "generators/timeline_fu/templates/model.rb", - "generators/timeline_fu/timeline_fu_generator.rb", - "init.rb", - "lib/timeline_fu.rb", - "lib/timeline_fu/fires.rb", - "lib/timeline_fu/macros.rb", - "lib/timeline_fu/matchers.rb", - "shoulda_macros/timeline_fu_shoulda.rb", - "test/fires_test.rb", - "test/test_helper.rb", - "timeline_fu.gemspec" - ] + s.email = "james@giraffesoft.ca" + s.homepage = "https://github.com/jamesgolick/timeline_fu" + s.summary = "Easily build timelines, much like GitHub's news feed" + s.description = "Easily build timelines, much like GitHub's news feed" + + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + s.require_paths = ["lib"] + s.has_rdoc = true - s.homepage = %q{http://github.com/giraffesoft/timeline_fu} + s.extra_rdoc_files = ["README.rdoc"] s.rdoc_options = ["--charset=UTF-8"] - s.require_paths = ["lib"] - s.rubygems_version = %q{1.3.1} - s.summary = %q{Easily build timelines, much like GitHub's news feed} - s.test_files = [ - "test/fires_test.rb", - "test/test_helper.rb" - ] - if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - s.specification_version = 2 + s.add_runtime_dependency "activerecord" - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - else - end - else - end + s.add_development_dependency "appraisal" + s.add_development_dependency "logger" + s.add_development_dependency "mocha" + s.add_development_dependency "sqlite3" end