jakewendt-simply_taggable 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,53 @@
1
+ = Simply Taggable
2
+
3
+ Introduction goes here.
4
+
5
+ == TODO
6
+
7
+ Build generator to install migrations, javascript, stylesheets, tasks, autotest
8
+
9
+ Generator also creates factory initializer
10
+
11
+ Build complete tests
12
+
13
+ Import existing model tests.
14
+
15
+ Add namable type tags/taggings
16
+
17
+
18
+ == Example
19
+
20
+ Example goes here.
21
+
22
+
23
+
24
+ == Usage
25
+
26
+ config.gem 'jakewendt-simply_taggable',
27
+ :source => 'http://rubygems.org'
28
+
29
+ script/generate simply_taggable
30
+ script/generate simply_taggable_tagger User <- Maybe
31
+
32
+
33
+ == Gemified with Jeweler
34
+
35
+ vi Rakefile
36
+ rake version:write
37
+
38
+ rake version:bump:patch
39
+ rake version:bump:minor
40
+ rake version:bump:major
41
+
42
+ rake gemspec
43
+
44
+ rake install
45
+ rake release
46
+
47
+
48
+ == Credit and References
49
+
50
+ Can't remember which one, but I'm sure that I got much of this from a
51
+ Ryan Bates Railscast.
52
+
53
+ Copyright (c) 2009 [George 'Jake' Wendt], released under the MIT license
data/app/models/tag.rb ADDED
@@ -0,0 +1,36 @@
1
+ class Tag < ActiveRecord::Base
2
+ # belongs_to :user
3
+ belongs_to :tagger, :polymorphic => true #, :counter_cache => true
4
+ has_many :taggings, :dependent => :destroy
5
+ has_many :taggables, :through => :taggings
6
+
7
+ validates_presence_of :tagger_id, :tagger_type
8
+ validates_presence_of :name
9
+ validates_length_of :name, :in => 1..250
10
+ validates_uniqueness_of :name, :scope => [:tagger_id, :tagger_type]
11
+
12
+ attr_accessible :name
13
+
14
+ class MultipleTagsFound < StandardError
15
+ attr_reader :message;
16
+ def initialize(message="Multiple tags found")
17
+ @message = message
18
+ end
19
+ end
20
+
21
+ def before_save
22
+ name.squish!
23
+ end
24
+
25
+ def self.find_or_create(conditions={})
26
+ tags = find(:all, :conditions => conditions)
27
+ case tags.length
28
+ when 0
29
+ self.create!(conditions)
30
+ when 1
31
+ tags[0]
32
+ else raise MultipleTagsFound.new("Multiple tags found matching #{conditions.inspect}.")
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,4 @@
1
+ class Tagging < ActiveRecord::Base
2
+ belongs_to :taggable, :polymorphic => true
3
+ belongs_to :tag, :counter_cache => :taggables_count
4
+ end
data/config/routes.rb ADDED
File without changes
File without changes
@@ -0,0 +1,71 @@
1
+ class SimplyTaggableGenerator < Rails::Generator::Base
2
+
3
+ def manifest
4
+ # See Rails::Generator::Commands::Create
5
+ # rails-2.3.10/lib/rails_generator/commands.rb
6
+ # for code methods for record (Manifest)
7
+ record do |m|
8
+ m.directory('config/autotest')
9
+ m.file('autotest_simply_taggable.rb', 'config/autotest/simply_taggable.rb')
10
+ m.directory('lib/tasks')
11
+ m.file('simply_taggable.rake', 'lib/tasks/simply_taggable.rake')
12
+
13
+ %w( create_tags create_taggings ).each do |migration|
14
+ m.migration_template "migrations/#{migration}.rb",
15
+ 'db/migrate', :migration_file_name => migration
16
+ end
17
+
18
+ m.directory('public/javascripts')
19
+ Dir["#{File.dirname(__FILE__)}/templates/javascripts/*js"].each{|file|
20
+ f = file.split('/').slice(-2,2).join('/')
21
+ m.file(f, "public/javascripts/#{File.basename(file)}")
22
+ }
23
+ m.directory('public/stylesheets')
24
+ Dir["#{File.dirname(__FILE__)}/templates/stylesheets/*css"].each{|file|
25
+ f = file.split('/').slice(-2,2).join('/')
26
+ m.file(f, "public/stylesheets/#{File.basename(file)}")
27
+ }
28
+
29
+ # m.directory('test/functional/pages')
30
+ # Dir["#{File.dirname(__FILE__)}/templates/functional/*rb"].each{|file|
31
+ # f = file.split('/').slice(-2,2).join('/')
32
+ # m.file(f, "test/functional/pages/#{File.basename(file)}")
33
+ # }
34
+ # m.directory('test/unit/pages')
35
+ # Dir["#{File.dirname(__FILE__)}/templates/unit/*rb"].each{|file|
36
+ # f = file.split('/').slice(-2,2).join('/')
37
+ # m.file(f, "test/unit/pages/#{File.basename(file)}")
38
+ # }
39
+ end
40
+ end
41
+
42
+ end
43
+ module Rails::Generator::Commands
44
+ class Create
45
+ def migration_template(relative_source,
46
+ relative_destination, template_options = {})
47
+ migration_directory relative_destination
48
+ migration_file_name = template_options[
49
+ :migration_file_name] || file_name
50
+ if migration_exists?(migration_file_name)
51
+ puts "Another migration is already named #{migration_file_name}: #{existing_migrations(migration_file_name).first}: Skipping"
52
+ else
53
+ template(relative_source, "#{relative_destination}/#{next_migration_string}_#{migration_file_name}.rb", template_options)
54
+ end
55
+ end
56
+ end # Create
57
+ class Base
58
+ protected
59
+ # the loop through migrations happens so fast
60
+ # that they all have the same timestamp which
61
+ # won't work when you actually try to migrate.
62
+ # All the timestamps MUST be unique.
63
+ def next_migration_string(padding = 3)
64
+ @s = (!@s.nil?)? @s.to_i + 1 : if ActiveRecord::Base.timestamped_migrations
65
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
66
+ else
67
+ "%.#{padding}d" % next_migration_number
68
+ end
69
+ end
70
+ end # Base
71
+ end
@@ -0,0 +1,2 @@
1
+ # From `script/generate simply_taggable` ...
2
+ require 'simply_taggable/autotest'
@@ -0,0 +1,15 @@
1
+ class CreateTaggings < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :taggings do |t|
4
+ t.references :taggable, :polymorphic => true
5
+ t.references :tag
6
+ t.timestamps
7
+ end
8
+ add_index :taggings, [:taggable_id,:taggable_type], :name => 'by_taggable'
9
+ add_index :taggings, :tag_id, :name => 'by_tag_id'
10
+ end
11
+
12
+ def self.down
13
+ drop_table :taggings
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ class CreateTags < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :tags do |t|
4
+ t.references :tagger, :polymorphic => true
5
+ t.string :name
6
+ t.integer :taggables_count, :null => false, :default => 0
7
+ t.timestamps
8
+ end
9
+ add_index :tags, [:name,:tagger_id,:tagger_type], :unique => true, :name => 'by_name'
10
+ end
11
+
12
+ def self.down
13
+ drop_table :tags
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # From `script/generate simply_taggable` ...
2
+ unless Gem.source_index.find_name('jakewendt-simply_taggable').empty?
3
+ gem 'jakewendt-simply_taggable'
4
+ require 'simply_taggable/test_tasks'
5
+ end
@@ -0,0 +1 @@
1
+ require 'simply_taggable'
@@ -0,0 +1,7 @@
1
+ module SimplyTaggable
2
+ # predefined namespace
3
+ end
4
+ require 'simply_taggable/base'
5
+ require 'simply_taggable/assertions'
6
+
7
+ require 'active_support'
@@ -0,0 +1,33 @@
1
+ module SimplyTaggable::Assertions
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+ module ClassMethods
6
+
7
+ def assert_simply_taggable
8
+
9
+ test "should be simply taggable" do
10
+ assert model_name.constantize.new.respond_to?(:tags)
11
+ assert model_name.constantize.new.respond_to?(:taggings)
12
+ # self.class.assert_should_have_many :taggings
13
+ # self.class.assert_should_have_many :tags, :polymorphic => true
14
+ end
15
+
16
+ end
17
+
18
+ def assert_simply_taggable_tagger
19
+
20
+ test "should be simply taggable tagger" do
21
+ # self.class.assert_should_have_many :tags, :polymorphic => true
22
+
23
+ assert model_name.constantize.new.respond_to?(:tags)
24
+ # assert model_name.constantize.new.respond_to?(:taggings)
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ end
31
+ require 'active_support'
32
+ require 'active_support/test_case'
33
+ ActiveSupport::TestCase.send(:include,SimplyTaggable::Assertions)
@@ -0,0 +1,60 @@
1
+ module SimplyTaggable::Base
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ module ClassMethods
7
+
8
+ def simply_taggable_tagger
9
+
10
+ has_many :tags,
11
+ :as => :tagger,
12
+ :dependent => :destroy
13
+
14
+ end
15
+
16
+ def simply_taggable
17
+
18
+ # add some options like :by => :user
19
+ # in case User isn't the model of choice
20
+
21
+ include SimplyTaggable::Base::InstanceMethods
22
+
23
+ has_many :taggings,
24
+ :as => :taggable,
25
+ :dependent => :destroy
26
+
27
+ has_many :tags,
28
+ :through => :taggings
29
+
30
+ attr_writer :tag_names
31
+ attr_accessible :tag_names
32
+ after_save :assign_tags
33
+
34
+ end
35
+ end
36
+
37
+ module InstanceMethods
38
+
39
+ def tag_names
40
+ @tag_names || tags.map(&:name).join(', ')
41
+ end
42
+
43
+ private
44
+
45
+ def assign_tags
46
+ if @tag_names
47
+ self.tags = @tag_names.names_to_array.map do |name|
48
+ Tag.find_or_create({
49
+ :name => name.squish,
50
+ :tagger => self.tagger
51
+ # :user_id => self.user_id
52
+ }) if !name.blank?
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ require 'active_record'
60
+ ActiveRecord::Base.send(:include, SimplyTaggable::Base)
@@ -0,0 +1 @@
1
+ Dir["#{File.dirname(__FILE__)}/../tasks/**/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,48 @@
1
+ module SimplyTaggable;end
2
+ namespace :test do
3
+ namespace :units do
4
+ Rake::TestTask.new(:simply_taggable => "db:test:prepare") do |t|
5
+ t.pattern = File.expand_path(File.join(
6
+ File.dirname(__FILE__),'/../../test/unit/taggable/*_test.rb'))
7
+ t.libs << "test"
8
+ t.verbose = true
9
+ end
10
+ end
11
+ namespace :functionals do
12
+ Rake::TestTask.new(:simply_taggable => "db:test:prepare") do |t|
13
+ t.pattern = File.expand_path(File.join(
14
+ File.dirname(__FILE__),'/../../test/functional/taggable/*_test.rb'))
15
+ t.libs << "test"
16
+ t.verbose = true
17
+ end
18
+ end
19
+ end
20
+ Rake::Task['test:functionals'].prerequisites.unshift(
21
+ "test:functionals:simply_taggable" )
22
+ Rake::Task['test:units'].prerequisites.unshift(
23
+ "test:units:simply_taggable" )
24
+
25
+ # I thought of possibly just including this file
26
+ # but that would make __FILE__ different.
27
+ # Hmmm
28
+
29
+ #
30
+ # used in simply_helpful's rake test:coverage to run gem's
31
+ # tests in the context of the application
32
+ #
33
+ @gem_test_dirs ||= []
34
+ #@gem_test_dirs << File.expand_path(File.join(File.dirname(__FILE__),
35
+ # '/../../test/unit/taggable/'))
36
+ #@gem_test_dirs << File.expand_path(File.join(File.dirname(__FILE__),
37
+ # '/../../test/functional/taggable/'))
38
+
39
+ #
40
+ # More flexible. Find all test files, pick out their dir, uniq 'em and add.
41
+ #
42
+ Dir.glob( File.expand_path(File.join(File.dirname(__FILE__),
43
+ '/../../test/*/taggable/*_test.rb'))
44
+ ).collect{|f|
45
+ File.dirname(f)
46
+ }.uniq.each{ |dir|
47
+ @gem_test_dirs << dir
48
+ }
@@ -0,0 +1,54 @@
1
+ desc "Explaining what the task does"
2
+ namespace :simply_taggable do
3
+
4
+ desc "Install"
5
+ task :install => [:prep, :update] do
6
+ puts "in install"
7
+ end
8
+
9
+ task :prep => :environment do
10
+ puts "in prep" # just once
11
+ # append require 'simply_taggable/tasks' to Rakefile
12
+ end
13
+
14
+ desc "Update"
15
+ task :update => :environment do
16
+ puts "in update"
17
+
18
+ # FileUtils.mkdir_p('db/migrate') unless File.directory?('db/migrate')
19
+ # rsync_command = <<-EOF.gsub(/\s+/,' ').squish!
20
+ # rsync -ruv
21
+ # --exclude='*_test_only_*rb'
22
+ # --exclude='versions'
23
+ # vendor/plugins/ucb_ccls_engine/db/migrate db
24
+ # EOF
25
+ # system rsync_command
26
+ #
27
+ # FileUtils.mkdir_p('public') unless File.directory?('public')
28
+ # rsync_command = <<-EOF.gsub(/\s+/,' ').squish!
29
+ # rsync -ruv
30
+ # --exclude='versions'
31
+ # vendor/plugins/ucb_ccls_engine/public .
32
+ # EOF
33
+ # system rsync_command
34
+ #
35
+ # rsync_command = <<-EOF.gsub(/\s+/,' ').squish!
36
+ # rsync -ruv
37
+ # --exclude='app'
38
+ # --exclude='assets'
39
+ # --exclude='config'
40
+ # --exclude='db'
41
+ # --exclude='extensions'
42
+ # --exclude='fixtures'
43
+ # --exclude='helpers'
44
+ # --exclude='log'
45
+ # --exclude='versions'
46
+ # --exclude='test_helper.rb'
47
+ # --exclude='engine_\*_test.rb'
48
+ # vendor/plugins/ucb_ccls_engine/test .
49
+ # EOF
50
+ # system rsync_command
51
+
52
+ end
53
+
54
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'jakewendt-simply_taggable'
@@ -0,0 +1,11 @@
1
+ class ApplicationController < ActionController::Base
2
+
3
+ def redirections
4
+ @redirections ||= HashWithIndifferentAccess.new({
5
+ :not_be_user => {
6
+ :redirect_to => user_path(current_user)
7
+ }
8
+ })
9
+ end
10
+
11
+ end
@@ -0,0 +1,2 @@
1
+ class Post < ActiveRecord::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ class User < ActiveRecord::Base
2
+ end
data/test/factories.rb ADDED
@@ -0,0 +1,6 @@
1
+ Factory.define :tag do |f|
2
+ f.name "Tag Name"
3
+ f.association :tagger
4
+ end
5
+ Factory.define :tagging do |f|
6
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class PostTest < ActiveSupport::TestCase
4
+
5
+ assert_simply_taggable
6
+
7
+ end
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ class SimplyTaggable::TagTest < ActiveSupport::TestCase
4
+
5
+ assert_should_initially_belong_to :tagger, :polymorphic => true
6
+ assert_should_have_many :taggings
7
+
8
+ assert_should_require :name
9
+ assert_should_not_protect_attribute :name
10
+ assert_should_protect_attribute :tagger_id
11
+ assert_should_protect_attribute :tagger_type
12
+
13
+ end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class SimplyTaggable::TaggingTest < ActiveSupport::TestCase
4
+
5
+ assert_should_belong_to :tag
6
+ assert_should_belong_to :taggable, :polymorphic => true
7
+
8
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class UserTest < ActiveSupport::TestCase
4
+
5
+ assert_simply_taggable_tagger
6
+
7
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jakewendt-simply_taggable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 2
10
+ version: 0.3.2
11
+ platform: ruby
12
+ authors:
13
+ - George 'Jake' Wendt
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-10 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ version: "2"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: jakewendt-rails_extension
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ description: longer description of your gem
50
+ email: github@jake.otherinbox.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files:
56
+ - README.rdoc
57
+ files:
58
+ - app/models/tag.rb
59
+ - app/models/tagging.rb
60
+ - config/routes.rb
61
+ - generators/simply_taggable/USAGE
62
+ - generators/simply_taggable/simply_taggable_generator.rb
63
+ - generators/simply_taggable/templates/autotest_simply_taggable.rb
64
+ - generators/simply_taggable/templates/migrations/create_taggings.rb
65
+ - generators/simply_taggable/templates/migrations/create_tags.rb
66
+ - generators/simply_taggable/templates/simply_taggable.rake
67
+ - lib/jakewendt-simply_taggable.rb
68
+ - lib/simply_taggable.rb
69
+ - lib/simply_taggable/assertions.rb
70
+ - lib/simply_taggable/base.rb
71
+ - lib/simply_taggable/tasks.rb
72
+ - lib/simply_taggable/test_tasks.rb
73
+ - lib/tasks/simply_taggable_tasks.rake
74
+ - rails/init.rb
75
+ - README.rdoc
76
+ - test/app/controllers/application_controller.rb
77
+ - test/app/models/post.rb
78
+ - test/app/models/user.rb
79
+ - test/factories.rb
80
+ - test/unit/post_test.rb
81
+ - test/unit/taggable/tag_test.rb
82
+ - test/unit/taggable/tagging_test.rb
83
+ - test/unit/user_test.rb
84
+ has_rdoc: true
85
+ homepage: http://github.com/jakewendt/simply_taggable
86
+ licenses: []
87
+
88
+ post_install_message:
89
+ rdoc_options: []
90
+
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ requirements: []
112
+
113
+ rubyforge_project:
114
+ rubygems_version: 1.6.2
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: one-line summary of your gem
118
+ test_files:
119
+ - test/app/controllers/application_controller.rb
120
+ - test/app/models/post.rb
121
+ - test/app/models/user.rb
122
+ - test/factories.rb
123
+ - test/unit/post_test.rb
124
+ - test/unit/taggable/tag_test.rb
125
+ - test/unit/taggable/tagging_test.rb
126
+ - test/unit/user_test.rb