Removed superfluous 'tracks' directory at the root of the repository.

Testing commits to github.
This commit is contained in:
bsag 2008-05-20 21:28:26 +01:00
parent 6a42901514
commit 4cbf5a34d3
2269 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,94 @@
class CommentingGenerator < Rails::Generator::NamedBase
default_options :skip_migration => false
default_options :self_referential => false
attr_reader :parent_association_name
attr_reader :commentable_models
def initialize(runtime_args, runtime_options = {})
@parent_association_name = (runtime_args.include?("--self-referential") ? "commenter" : "comment")
@commentable_models = runtime_args.reject{|opt| opt =~ /^--/}.map do |commentable|
":" + commentable.underscore.pluralize
end
@commentable_models += [":comments"] if runtime_args.include?("--self-referential")
@commentable_models.uniq!
verify @commentable_models
hacks
runtime_args.unshift("placeholder")
super
end
def verify models
puts "** Warning: only one commentable model specified; tests may not run properly." if models.size < 2
models.each do |model|
model = model[1..-1].classify
next if model == "Comment" # don't load ourselves when --self-referential is used
self.class.const_get(model) rescue puts "** Error: model #{model[1..-1].classify} could not be loaded." or exit
end
end
def hacks
# add the extension require in environment.rb
phrase = "require 'commenting_extensions'"
filename = "#{RAILS_ROOT}/config/environment.rb"
unless (open(filename) do |file|
file.grep(/#{Regexp.escape phrase}/).any?
end)
open(filename, 'a+') do |file|
file.puts "\n" + phrase + "\n"
end
end
end
def manifest
record do |m|
m.class_collisions class_path, class_name, "#{class_name}Test"
m.directory File.join('app/models', class_path)
m.directory File.join('test/unit', class_path)
m.directory File.join('test/fixtures', class_path)
m.directory File.join('test/fixtures', class_path)
m.directory File.join('lib')
m.template 'comment.rb', File.join('app/models', class_path, "comment.rb")
m.template 'comment_test.rb', File.join('test/unit', class_path, "comment_test.rb")
m.template 'comments.yml', File.join('test/fixtures', class_path, "comments.yml")
m.template 'commenting.rb', File.join('app/models', class_path, "commenting.rb")
m.template 'commenting_test.rb', File.join('test/unit', class_path, "commenting_test.rb")
m.template 'commentings.yml', File.join('test/fixtures', class_path, "commentings.yml")
m.template 'commenting_extensions.rb', File.join('lib', 'commenting_extensions.rb')
unless options[:skip_migration]
m.migration_template 'migration.rb', 'db/migrate',
:migration_file_name => "create_comments_and_commentings"
end
end
end
protected
def banner
"Usage: #{$0} generate commenting [CommentableModelA CommentableModelB ...]"
end
def add_options!(opt)
opt.separator ''
opt.separator 'Options:'
opt.on("--skip-migration",
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
opt.on("--self-referential",
"Allow comments to comment themselves.") { |v| options[:self_referential] = v }
end
# Useful for generating tests/fixtures
def model_one
commentable_models[0][1..-1].classify
end
def model_two
commentable_models[1][1..-1].classify rescue model_one
end
end

View file

@ -0,0 +1,33 @@
# The Comment model. This model is automatically generated and added to your app if you run the commenting generator.
class Comment < ActiveRecord::Base
# If database speed becomes an issue, you could remove these validations and rescue the ActiveRecord database constraint errors instead.
validates_presence_of :name, :email, :body
validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
after_validation :prepend_url
# Set up the polymorphic relationship.
has_many_polymorphs :commentables,
:from => [<%= commentable_models.join(", ") %>],
:through => :commentings,
:dependent => :destroy,
<% if options[:self_referential] -%> :as => :<%= parent_association_name -%>,
<% end -%>
:parent_extend => proc {
}
# Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if something goes wrong.
class Error < StandardError
end
protected
def prepend_url
return if self[:url].blank?
if self[:url] !~ /^http(s):\/\//i
self.url = 'http://' + self[:url]
end
end
end

View file

@ -0,0 +1,12 @@
require File.dirname(__FILE__) + '/../test_helper'
class CommentTest < Test::Unit::TestCase
fixtures :comments, :commentings, <%= commentable_models[0..1].join(", ") -%>
def test_to_s
assert_equal "no1@nowhere.com", <%= model_two -%>.find(2).comments.first.email
assert_equal "http://letrails.cn", <%= model_two -%>.find(2).comments.last.url
assert_equal "http://fr.ivolo.us", <%= model_two -%>.find(2).comments.first.url
end
end

View file

@ -0,0 +1,13 @@
# The Commenting join model. This model is automatically generated and added to your app if you run the commenting generator.
class Commenting < ActiveRecord::Base
belongs_to :<%= parent_association_name -%><%= ", :foreign_key => \"#{parent_association_name}_id\", :class_name => \"Comment\"" if options[:self_referential] %>
belongs_to :commentable, :polymorphic => true
# This callback makes sure that an orphaned <tt>Comment</tt> is deleted if it no longer tags anything.
def before_destroy
<%= parent_association_name -%>.destroy_without_callbacks if <%= parent_association_name -%> and <%= parent_association_name -%>.commentings.count == 1
end
end

View file

@ -0,0 +1,30 @@
class ActiveRecord::Base
module CommentingExtensions
def comment_count
commentable?
self.comments.size
end
def comment_with(attributes)
commentable?(true)
begin
comment = Comment.create(attributes)
raise Comment::Error, "Comment could not be saved with" if comment.new_record?
comment.commentables << self
rescue
end
end
private
def commentable?(should_raise = false) #:nodoc:
unless flag = respond_to?(:<%= parent_association_name -%>s)
raise "#{self.class} is not a commentable model" if should_raise
end
flag
end
end
include CommentingExtensions
end

View file

@ -0,0 +1,30 @@
require File.dirname(__FILE__) + '/../test_helper'
class CommentingTest < Test::Unit::TestCase
fixtures :commentings, :comments, <%= commentable_models[0..1].join(", ") -%>
def setup
@obj1 = <%= model_two %>.find(1)
@obj2 = <%= model_two %>.find(2)
<% if commentable_models.size > 1 -%>
@obj3 = <%= model_one -%>.find(1)
<% end -%>
@comment1 = Comment.find(1)
@comment2 = Comment.find(2)
@commenting1 = Commenting.find(1)
end
def test_commentable
assert_raises(RuntimeError) do
@commenting1.send(:commentable?, true)
end
assert !@commenting1.send(:commentable?)
<% if commentable_models.size > 1 -%>
assert @obj3.send(:commentable?)
<% end -%>
<% if options[:self_referential] -%>
assert @comment1.send(:commentable?)
<% end -%>
end
end

View file

@ -0,0 +1,23 @@
---
<% if commentable_models.size > 1 -%>
commentings_003:
<%= parent_association_name -%>_id: "2"
id: "3"
commentable_type: <%= model_one %>
commentable_id: "1"
<% end -%>
commentings_004:
<%= parent_association_name -%>_id: "2"
id: "4"
commentable_type: <%= model_two %>
commentable_id: "2"
commentings_001:
<%= parent_association_name -%>_id: "1"
id: "1"
commentable_type: <%= model_two %>
commentable_id: "1"
commentings_002:
<%= parent_association_name -%>_id: "1"
id: "2"
commentable_type: <%= model_two %>
commentable_id: "2"

View file

@ -0,0 +1,13 @@
---
comments_001:
id: "1"
name: frivolous
email: no1@nowhere.com
url: http://fr.ivolo.us
body: this plugin rocks!
tags_002:
id: "2"
name: yuanyiz
email: no1@nowhere.com
url: http://letrails.cn
body: this plugin has saved my life

View file

@ -0,0 +1,28 @@
# A migration to add tables for Comment and Commenting. This file is automatically generated and added to your app if you run the commenting generator.
class CreateCommentsAndCommentings < ActiveRecord::Migration
# Add the new tables.
def self.up
create_table :comments do |t|
t.column :name, :string, :null => false
t.column :url, :string
t.column :email, :string
t.column :body, :text
end
create_table :commentings do |t|
t.column :<%= parent_association_name -%>_id, :integer, :null => false
t.column :commentable_id, :integer, :null => false
t.column :commentable_type, :string, :null => false
end
end
# Remove the tables.
def self.down
drop_table :comments
drop_table :commentings
end
end

View file

@ -0,0 +1,95 @@
require 'ruby-debug' and Debugger.start if ENV['USER'] == 'eweaver'
class TaggingGenerator < Rails::Generator::NamedBase
default_options :skip_migration => false
default_options :self_referential => false
attr_reader :parent_association_name
attr_reader :taggable_models
def initialize(runtime_args, runtime_options = {})
@parent_association_name = (runtime_args.include?("--self-referential") ? "tagger" : "tag")
@taggable_models = runtime_args.reject{|opt| opt =~ /^--/}.map do |taggable|
":" + taggable.underscore.pluralize
end
@taggable_models += [":tags"] if runtime_args.include?("--self-referential")
@taggable_models.uniq!
verify @taggable_models
hacks
runtime_args.unshift("placeholder")
super
end
def verify models
puts "** Warning: only one taggable model specified; tests may not run properly." if models.size < 2
models.each do |model|
model = model[1..-1].classify
next if model == "Tag" # don't load ourselves when --self-referential is used
self.class.const_get(model) rescue puts "** Error: model #{model[1..-1].classify} could not be loaded." or exit
end
end
def hacks
# add the extension require in environment.rb
phrase = "require 'tagging_extensions'"
filename = "#{RAILS_ROOT}/config/environment.rb"
unless (open(filename) do |file|
file.grep(/#{Regexp.escape phrase}/).any?
end)
open(filename, 'a+') do |file|
file.puts "\n" + phrase + "\n"
end
end
end
def manifest
record do |m|
m.class_collisions class_path, class_name, "#{class_name}Test"
m.directory File.join('app/models', class_path)
m.directory File.join('test/unit', class_path)
m.directory File.join('test/fixtures', class_path)
m.directory File.join('test/fixtures', class_path)
m.directory File.join('lib')
m.template 'tag.rb', File.join('app/models', class_path, "tag.rb")
m.template 'tag_test.rb', File.join('test/unit', class_path, "tag_test.rb")
m.template 'tags.yml', File.join('test/fixtures', class_path, "tags.yml")
m.template 'tagging.rb', File.join('app/models', class_path, "tagging.rb")
m.template 'tagging_test.rb', File.join('test/unit', class_path, "tagging_test.rb")
m.template 'taggings.yml', File.join('test/fixtures', class_path, "taggings.yml")
m.template 'tagging_extensions.rb', File.join('lib', 'tagging_extensions.rb')
unless options[:skip_migration]
m.migration_template 'migration.rb', 'db/migrate',
:migration_file_name => "create_tags_and_taggings"
end
end
end
protected
def banner
"Usage: #{$0} generate tagging [TaggableModelA TaggableModelB ...]"
end
def add_options!(opt)
opt.separator ''
opt.separator 'Options:'
opt.on("--skip-migration",
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
opt.on("--self-referential",
"Allow tags to tag themselves.") { |v| options[:self_referential] = v }
end
# Useful for generating tests/fixtures
def model_one
taggable_models[0][1..-1].classify
end
def model_two
taggable_models[1][1..-1].classify rescue model_one
end
end

View file

@ -0,0 +1,28 @@
# A migration to add tables for Tag and Tagging. This file is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs.
class CreateTagsAndTaggings < ActiveRecord::Migration
# Add the new tables.
def self.up
create_table :tags do |t|
t.column :name, :string, :null => false
end
add_index :tags, :name, :unique => true
create_table :taggings do |t|
t.column :<%= parent_association_name -%>_id, :integer, :null => false
t.column :taggable_id, :integer, :null => false
t.column :taggable_type, :string, :null => false
# t.column :position, :integer # Uncomment this if you need to use <tt>acts_as_list</tt>.
end
add_index :taggings, [:<%= parent_association_name -%>_id, :taggable_id, :taggable_type], :unique => true
end
# Remove the tables.
def self.down
drop_table :tags
drop_table :taggings
end
end

View file

@ -0,0 +1,39 @@
# The Tag model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs.
class Tag < ActiveRecord::Base
DELIMITER = " " # Controls how to split and join tagnames from strings. You may need to change the <tt>validates_format_of parameters</tt> if you change this.
# If database speed becomes an issue, you could remove these validations and rescue the ActiveRecord database constraint errors instead.
validates_presence_of :name
validates_uniqueness_of :name, :case_sensitive => false
# Change this validation if you need more complex tag names.
validates_format_of :name, :with => /^[a-zA-Z0-9\_\-]+$/, :message => "can not contain special characters"
# Set up the polymorphic relationship.
has_many_polymorphs :taggables,
:from => [<%= taggable_models.join(", ") %>],
:through => :taggings,
:dependent => :destroy,
<% if options[:self_referential] -%> :as => :<%= parent_association_name -%>,
<% end -%>
:skip_duplicates => false,
:parent_extend => proc {
# Defined on the taggable models, not on Tag itself. Return the tagnames associated with this record as a string.
def to_s
self.map(&:name).sort.join(Tag::DELIMITER)
end
}
# Callback to strip extra spaces from the tagname before saving it. If you allow tags to be renamed later, you might want to use the <tt>before_save</tt> callback instead.
def before_create
self.name = name.downcase.strip.squeeze(" ")
end
# Tag::Error class. Raised by ActiveRecord::Base::TaggingExtensions if something goes wrong.
class Error < StandardError
end
end

View file

@ -0,0 +1,10 @@
require File.dirname(__FILE__) + '/../test_helper'
class TagTest < Test::Unit::TestCase
fixtures :tags, :taggings, <%= taggable_models[0..1].join(", ") -%>
def test_to_s
assert_equal "delicious sexy", <%= model_two -%>.find(2).tags.to_s
end
end

View file

@ -0,0 +1,16 @@
# The Tagging join model. This model is automatically generated and added to your app if you run the tagging generator included with has_many_polymorphs.
class Tagging < ActiveRecord::Base
belongs_to :<%= parent_association_name -%><%= ", :foreign_key => \"#{parent_association_name}_id\", :class_name => \"Tag\"" if options[:self_referential] %>
belongs_to :taggable, :polymorphic => true
# If you also need to use <tt>acts_as_list</tt>, you will have to manage the tagging positions manually by creating decorated join records when you associate Tags with taggables.
# acts_as_list :scope => :taggable
# This callback makes sure that an orphaned <tt>Tag</tt> is deleted if it no longer tags anything.
def before_destroy
<%= parent_association_name -%>.destroy_without_callbacks if <%= parent_association_name -%> and <%= parent_association_name -%>.taggings.count == 1
end
end

View file

@ -0,0 +1,106 @@
class ActiveRecord::Base #:nodoc:
# These extensions make models taggable. This file is automatically generated and required by your app if you run the tagging generator included with has_many_polymorphs.
module TaggingExtensions
# Add tags to <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags.
#
# We need to avoid name conflicts with the built-in ActiveRecord association methods, thus the underscores.
def _add_tags incoming
taggable?(true)
tag_cast_to_string(incoming).each do |tag_name|
begin
tag = Tag.find_or_create_by_name(tag_name)
raise Tag::Error, "tag could not be saved: #{tag_name}" if tag.new_record?
tag.taggables << self
rescue ActiveRecord::StatementInvalid => e
raise unless e.to_s =~ /duplicate/i
end
end
end
# Removes tags from <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags.
def _remove_tags outgoing
taggable?(true)
outgoing = tag_cast_to_string(outgoing)
<% if options[:self_referential] %>
# because of http://dev.rubyonrails.org/ticket/6466
taggings.destroy(*(taggings.find(:all, :include => :<%= parent_association_name -%>).select do |tagging|
outgoing.include? tagging.<%= parent_association_name -%>.name
end))
<% else -%>
<%= parent_association_name -%>s.delete(*(<%= parent_association_name -%>s.select do |tag|
outgoing.include? tag.name
end))
<% end -%>
end
# Returns the tags on <tt>self</tt> as a string.
def tag_list
# Redefined later to avoid an RDoc parse error.
end
# Replace the existing tags on <tt>self</tt>. Accepts a string of tagnames, an array of tagnames, an array of ids, or an array of Tags.
def tag_with list
#:stopdoc:
taggable?(true)
list = tag_cast_to_string(list)
# Transactions may not be ideal for you here; be aware.
Tag.transaction do
current = <%= parent_association_name -%>s.map(&:name)
_add_tags(list - current)
_remove_tags(current - list)
end
self
#:startdoc:
end
# Returns the tags on <tt>self</tt> as a string.
def tag_list #:nodoc:
#:stopdoc:
taggable?(true)
<%= parent_association_name -%>s.reload
<%= parent_association_name -%>s.to_s
#:startdoc:
end
private
def tag_cast_to_string obj #:nodoc:
case obj
when Array
obj.map! do |item|
case item
when /^\d+$/, Fixnum then Tag.find(item).name # This will be slow if you use ids a lot.
when Tag then item.name
when String then item
else
raise "Invalid type"
end
end
when String
obj = obj.split(Tag::DELIMITER).map do |tag_name|
tag_name.strip.squeeze(" ")
end
else
raise "Invalid object of class #{obj.class} as tagging method parameter"
end.flatten.compact.map(&:downcase).uniq
end
# Check if a model is in the :taggables target list. The alternative to this check is to explicitly include a TaggingMethods module (which you would create) in each target model.
def taggable?(should_raise = false) #:nodoc:
unless flag = respond_to?(:<%= parent_association_name -%>s)
raise "#{self.class} is not a taggable model" if should_raise
end
flag
end
end
include TaggingExtensions
end

View file

@ -0,0 +1,62 @@
require File.dirname(__FILE__) + '/../test_helper'
class TaggingTest < Test::Unit::TestCase
fixtures :taggings, :tags, <%= taggable_models[0..1].join(", ") -%>
def setup
@obj1 = <%= model_two %>.find(1)
@obj2 = <%= model_two %>.find(2)
<% if taggable_models.size > 1 -%>
@obj3 = <%= model_one -%>.find(1)
<% end -%>
@tag1 = Tag.find(1)
@tag2 = Tag.find(2)
@tagging1 = Tagging.find(1)
end
def test_tag_with
@obj2.tag_with "dark columbian"
assert_equal "columbian dark", @obj2.tag_list
end
<% if options[:self_referential] -%>
def test_self_referential_tag_with
@tag1.tag_with [1, 2]
assert @tag1.tags.include?(@tag1)
assert !@tag2.tags.include?(@tag1)
end
<% end -%>
def test__add_tags
@obj1._add_tags "porter longneck"
assert Tag.find_by_name("porter").taggables.include?(@obj1)
assert Tag.find_by_name("longneck").taggables.include?(@obj1)
assert_equal "delicious longneck porter", @obj1.tag_list
@obj1._add_tags [2]
assert_equal "delicious longneck porter sexy", @obj1.tag_list
end
def test__remove_tags
@obj2._remove_tags ["2", @tag1]
assert @obj2.tags.empty?
end
def test_tag_list
assert_equal "delicious sexy", @obj2.tag_list
end
def test_taggable
assert_raises(RuntimeError) do
@tagging1.send(:taggable?, true)
end
assert !@tagging1.send(:taggable?)
<% if taggable_models.size > 1 -%>
assert @obj3.send(:taggable?)
<% end -%>
<% if options[:self_referential] -%>
assert @tag1.send(:taggable?)
<% end -%>
end
end

View file

@ -0,0 +1,23 @@
---
<% if taggable_models.size > 1 -%>
taggings_003:
<%= parent_association_name -%>_id: "2"
id: "3"
taggable_type: <%= model_one %>
taggable_id: "1"
<% end -%>
taggings_004:
<%= parent_association_name -%>_id: "2"
id: "4"
taggable_type: <%= model_two %>
taggable_id: "2"
taggings_001:
<%= parent_association_name -%>_id: "1"
id: "1"
taggable_type: <%= model_two %>
taggable_id: "1"
taggings_002:
<%= parent_association_name -%>_id: "1"
id: "2"
taggable_type: <%= model_two %>
taggable_id: "2"

View file

@ -0,0 +1,7 @@
---
tags_001:
name: delicious
id: "1"
tags_002:
name: sexy
id: "2"