tagged 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/generators/tagged_migration/tagged_migration_generator.rb +11 -0
- data/generators/tagged_migration/templates/migration.rb +23 -0
- data/lib/tagged.rb +57 -0
- data/lib/tagged/adapters/abstract_adapter.rb +4 -0
- data/lib/tagged/adapters/active_record_adapter.rb +35 -0
- data/lib/tagged/adapters/mongo_mapper_adapter.rb +32 -0
- data/lib/tagged/tag.rb +5 -0
- data/lib/tagged/tag_list.rb +22 -0
- data/lib/tagged/tagging.rb +4 -0
- data/rails/init.rb +1 -0
- data/test/active_record_test.rb +55 -0
- data/test/delimiter_test.rb +24 -0
- data/test/mongo_mapper_schema.rb +8 -0
- data/test/mongo_mapper_test.rb +51 -0
- data/test/schema.rb +38 -0
- data/test/tag_list_test.rb +37 -0
- data/test/tagging_test.rb +41 -0
- data/test/test_helper.rb +7 -0
- metadata +82 -0
data/.gitignore
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |g|
|
9
|
+
g.name = 'tagged'
|
10
|
+
g.summary = %(Simple ORM agnostic tagging.)
|
11
|
+
g.description = %(Simple ORM agnostic tagging.)
|
12
|
+
g.email = 'matt@toastyapps.com'
|
13
|
+
g.homepage = 'http://github.com/toastyapps/tagged'
|
14
|
+
g.authors = %w(toastyapps)
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts 'Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com'
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.libs = %w(test)
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CreateTagged < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :taggings do |t|
|
4
|
+
t.belongs_to :tagged, :polymorphic => true
|
5
|
+
t.belongs_to :tag
|
6
|
+
t.datetime :created_at
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table :tags do |t|
|
10
|
+
t.string :name
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :tags, :name
|
14
|
+
add_index :taggings, :tag_id
|
15
|
+
add_index :taggings, [:taggable_id, :taggable_type]
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
drop_table :taggings
|
21
|
+
drop_table :tags
|
22
|
+
end
|
23
|
+
end
|
data/lib/tagged.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Tagged
|
2
|
+
|
3
|
+
module Extension
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
def self.tagged
|
7
|
+
include Tagged::Base
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Base
|
14
|
+
|
15
|
+
def self.included(model)
|
16
|
+
model.class_eval do
|
17
|
+
def self.delimiter
|
18
|
+
@@delimiter ||= ','
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.delimiter=(value)
|
22
|
+
@@delimiter = value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def delimiter
|
28
|
+
self.class.delimiter
|
29
|
+
end
|
30
|
+
|
31
|
+
def tag_list
|
32
|
+
self._tag_list
|
33
|
+
end
|
34
|
+
|
35
|
+
def tag_list=(list)
|
36
|
+
self._tag_list = Tagged::TagList.new(list.split(delimiter).map(&:strip))
|
37
|
+
end
|
38
|
+
|
39
|
+
def tag(list)
|
40
|
+
list.split(delimiter).map {|tag| self._tag_list << tag.strip }
|
41
|
+
end
|
42
|
+
|
43
|
+
def untag(items)
|
44
|
+
items.split(delimiter).map{|tag| self._tag_list.delete(tag.strip)}
|
45
|
+
end
|
46
|
+
|
47
|
+
def _tag_list
|
48
|
+
@tag_list ||= Tagged::TagList.new([], delimiter)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'tagged/tag'
|
54
|
+
require 'tagged/tag_list'
|
55
|
+
require 'tagged/adapters/abstract_adapter'
|
56
|
+
|
57
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'tagged'
|
2
|
+
|
3
|
+
module Tagged
|
4
|
+
|
5
|
+
module ActiveRecordExtension
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
@@tagged_adapter = ActiveRecordAdapter.new
|
9
|
+
extend ClassMethods
|
10
|
+
include Tagged::Base
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def tagged
|
16
|
+
self.class_eval do
|
17
|
+
has_many :taggings, :as => :tagged, :dependent => :destroy
|
18
|
+
has_many :tags, :through => :taggings
|
19
|
+
after_save :save_tags
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def save_tags
|
25
|
+
tag_list.each do |tag_name|
|
26
|
+
tags << ::Tag.find_or_initialize_by_name(tag_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
class ActiveRecordAdapter < AbstractAdapter
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
ActiveRecord::Base.send(:include, Tagged::ActiveRecordExtension)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'tagged'
|
2
|
+
|
3
|
+
module Tagged
|
4
|
+
|
5
|
+
module MongoMapperExtension
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
@@tagged_adapter = MongoMapperAdapter.new
|
9
|
+
include Tagged::Base
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
class MongoMapperAdapter < AbstractAdapter
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module MongoMapper
|
19
|
+
module Document
|
20
|
+
module ClassMethods
|
21
|
+
def tagged
|
22
|
+
include Tagged::MongoMapperExtension
|
23
|
+
key :tags, Array
|
24
|
+
before_save :save_tags
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def save_tags
|
29
|
+
self.tags = self.tag_list
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/tagged/tag.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Tagged
|
2
|
+
class TagList < Array
|
3
|
+
attr_accessor :tags, :delimiter
|
4
|
+
def initialize(*list)
|
5
|
+
self.delimiter = ','
|
6
|
+
if list[0].is_a?(Array)
|
7
|
+
self.delimiter = list[1]
|
8
|
+
list = list[0]
|
9
|
+
end
|
10
|
+
list = list.is_a?(Array) ? list : list.split(self.delimiter).collect(&:strip).reject(&:blank)
|
11
|
+
super(list)
|
12
|
+
end
|
13
|
+
|
14
|
+
def +(list)
|
15
|
+
Tagged::TagList.new(self.to_a + list, self.delimiter)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s(delimiter = nil)
|
19
|
+
join(delimiter || self.delimiter)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'tagged'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'active_record'
|
3
|
+
require 'tagged/adapters/active_record_adapter'
|
4
|
+
require 'schema'
|
5
|
+
|
6
|
+
|
7
|
+
class ActiveRecordTest < Test::Unit::TestCase
|
8
|
+
context "A Tagged ActiveRecord class" do
|
9
|
+
should "respond to tagged class methods" do
|
10
|
+
[:delimiter, :delimiter=].each do |method|
|
11
|
+
assert Post.respond_to?(method)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "A Tagged ActiveRecord instance" do
|
17
|
+
setup do
|
18
|
+
@post = Post.new
|
19
|
+
end
|
20
|
+
|
21
|
+
should "respond to tagged instance methods" do
|
22
|
+
[:tag, :tag_list, :untag].each do |method|
|
23
|
+
assert @post.respond_to?(method)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
should "respond to taggings" do
|
28
|
+
assert @post.respond_to?(:taggings)
|
29
|
+
end
|
30
|
+
|
31
|
+
should "have no tags to begin with" do
|
32
|
+
assert_equal [], @post.tag_list
|
33
|
+
end
|
34
|
+
|
35
|
+
should "be able to add a tag" do
|
36
|
+
@post.tag('foo')
|
37
|
+
assert_equal ['foo'], @post.tag_list
|
38
|
+
end
|
39
|
+
|
40
|
+
should "be able to remove a tag" do
|
41
|
+
@post.tag('foo')
|
42
|
+
@post.untag('foo')
|
43
|
+
assert_equal [], @post.tag_list
|
44
|
+
end
|
45
|
+
|
46
|
+
should "be able to save tags" do
|
47
|
+
@post.tag('foo,bar')
|
48
|
+
@post.save
|
49
|
+
assert_equal 2, Tag.count
|
50
|
+
assert_equal 2, Tagging.count
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Bar
|
4
|
+
include Tagged::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
class TaggingTest < Test::Unit::TestCase
|
8
|
+
context "A tagged instance with a custom delimiter" do
|
9
|
+
setup do
|
10
|
+
Bar.delimiter = '|'
|
11
|
+
@bar = Bar.new
|
12
|
+
@bar.tag('hoge|fuga|piyo')
|
13
|
+
end
|
14
|
+
|
15
|
+
should "respond with the correct tags" do
|
16
|
+
assert_equal ['hoge', 'fuga', 'piyo'], @bar.tag_list
|
17
|
+
end
|
18
|
+
|
19
|
+
should "be able to represent the tags as a string" do
|
20
|
+
assert_equal "hoge|fuga|piyo", @bar.tag_list.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'mongo_mapper'
|
3
|
+
require 'tagged/adapters/mongo_mapper_adapter'
|
4
|
+
require 'mongo_mapper_schema'
|
5
|
+
|
6
|
+
|
7
|
+
class MongoMapperTest < Test::Unit::TestCase
|
8
|
+
context "A Tagged MongoMapper class" do
|
9
|
+
should "respond to tagged class methods" do
|
10
|
+
[:delimiter, :delimiter=].each do |method|
|
11
|
+
assert Article.respond_to?(method)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "A Tagged MongoMapper instance" do
|
17
|
+
setup do
|
18
|
+
@article = Article.new
|
19
|
+
end
|
20
|
+
|
21
|
+
should "respond to tagged instance methods" do
|
22
|
+
[:tag, :tag_list, :untag].each do |method|
|
23
|
+
assert @article.respond_to?(method)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
should "have no tags to begin with" do
|
28
|
+
assert_equal [], @article.tag_list
|
29
|
+
end
|
30
|
+
|
31
|
+
should "be able to add a tag" do
|
32
|
+
@article.tag('foo')
|
33
|
+
assert_equal ['foo'], @article.tag_list
|
34
|
+
end
|
35
|
+
|
36
|
+
should "be able to remove a tag" do
|
37
|
+
@article.tag('foo')
|
38
|
+
@article.untag('foo')
|
39
|
+
assert_equal [], @article.tag_list
|
40
|
+
end
|
41
|
+
|
42
|
+
should "be able to save tags" do
|
43
|
+
@article.tag('foo,bar')
|
44
|
+
@article.save
|
45
|
+
@find_article = Article.find(@article.id)
|
46
|
+
assert_equal ['foo', 'bar'], @find_article.tags
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
data/test/schema.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
ActiveRecord::Base.configurations = {'sqlite3' => {:adapter => 'sqlite3', :database => ':memory:'}}
|
2
|
+
ActiveRecord::Base.establish_connection('sqlite3')
|
3
|
+
ActiveRecord::Base.logger = Logger.new(STDERR)
|
4
|
+
ActiveRecord::Base.logger.level = Logger::WARN
|
5
|
+
|
6
|
+
class CreateSchema < ActiveRecord::Migration
|
7
|
+
def self.up
|
8
|
+
create_table :taggings do |t|
|
9
|
+
t.belongs_to :tagged, :polymorphic => true
|
10
|
+
t.belongs_to :tag
|
11
|
+
t.datetime :created_at
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table :tags do |t|
|
15
|
+
t.string :name
|
16
|
+
end
|
17
|
+
create_table :posts do |t|
|
18
|
+
t.string :title, :default => ''
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
CreateSchema.suppress_messages do
|
24
|
+
CreateSchema.migrate(:up)
|
25
|
+
end
|
26
|
+
|
27
|
+
class Tagging < ActiveRecord::Base
|
28
|
+
belongs_to :tag
|
29
|
+
belongs_to :tagged, :polymorphic => true
|
30
|
+
end
|
31
|
+
|
32
|
+
class Post < ActiveRecord::Base
|
33
|
+
tagged
|
34
|
+
end
|
35
|
+
|
36
|
+
class Tag < ActiveRecord::Base
|
37
|
+
has_many :taggings, :dependent => :destroy
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TaggingTest < Test::Unit::TestCase
|
4
|
+
context "A tag_list" do
|
5
|
+
setup do
|
6
|
+
@list = Tagged::TagList.new
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'be able to add tags with tags#+=' do
|
10
|
+
tags = ['foo', 'bar']
|
11
|
+
@list += tags
|
12
|
+
assert_equal tags, @list
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'be able to add tags with <<' do
|
16
|
+
tags = ['foo', 'bar']
|
17
|
+
tags.each do |tag|
|
18
|
+
@list << tag
|
19
|
+
end
|
20
|
+
assert_equal tags, @list
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'be able to represent the tags in a string' do
|
24
|
+
tags = ['foo', 'bar']
|
25
|
+
@list += tags
|
26
|
+
assert_equal "foo,bar", @list.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'be able to remove tags' do
|
30
|
+
tags = ['foo', 'bar']
|
31
|
+
@list += tags
|
32
|
+
@list.delete('foo')
|
33
|
+
assert_equal ['bar'], @list
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Foo
|
4
|
+
include Tagged::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
class TaggingTest < Test::Unit::TestCase
|
8
|
+
context "A tagged instance" do
|
9
|
+
setup do
|
10
|
+
@foo = Foo.new
|
11
|
+
@foo.tag("hoge, fuga, piyo")
|
12
|
+
end
|
13
|
+
|
14
|
+
should "respond with the correct tags" do
|
15
|
+
assert_equal ['hoge', 'fuga', 'piyo'], @foo.tag_list
|
16
|
+
end
|
17
|
+
|
18
|
+
should "be able to add tags" do
|
19
|
+
@foo.tag('osake')
|
20
|
+
assert_equal ['hoge', 'fuga', 'piyo', 'osake'], @foo.tag_list
|
21
|
+
end
|
22
|
+
|
23
|
+
should "be able to remove a tag" do
|
24
|
+
@foo.untag('fuga')
|
25
|
+
assert_equal ['hoge', 'piyo'], @foo.tag_list
|
26
|
+
end
|
27
|
+
|
28
|
+
should "be able to remove multiple tags" do
|
29
|
+
@foo.untag('hoge, fuga')
|
30
|
+
assert_equal ['piyo'], @foo.tag_list
|
31
|
+
end
|
32
|
+
|
33
|
+
should "be able to represent the tags as a string" do
|
34
|
+
assert_equal "hoge,fuga,piyo", @foo.tag_list.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
should "be able to represent the tags as a custom string" do
|
38
|
+
assert_equal "hoge, fuga, piyo", @foo.tag_list.to_s(', ')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tagged
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- toastyapps
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-21 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Simple ORM agnostic tagging.
|
17
|
+
email: matt@toastyapps.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- Rakefile
|
27
|
+
- VERSION
|
28
|
+
- generators/tagged_migration/tagged_migration_generator.rb
|
29
|
+
- generators/tagged_migration/templates/migration.rb
|
30
|
+
- lib/tagged.rb
|
31
|
+
- lib/tagged/adapters/abstract_adapter.rb
|
32
|
+
- lib/tagged/adapters/active_record_adapter.rb
|
33
|
+
- lib/tagged/adapters/mongo_mapper_adapter.rb
|
34
|
+
- lib/tagged/tag.rb
|
35
|
+
- lib/tagged/tag_list.rb
|
36
|
+
- lib/tagged/tagging.rb
|
37
|
+
- rails/init.rb
|
38
|
+
- test/active_record_test.rb
|
39
|
+
- test/delimiter_test.rb
|
40
|
+
- test/mongo_mapper_schema.rb
|
41
|
+
- test/mongo_mapper_test.rb
|
42
|
+
- test/schema.rb
|
43
|
+
- test/tag_list_test.rb
|
44
|
+
- test/tagging_test.rb
|
45
|
+
- test/test_helper.rb
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/toastyapps/tagged
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options:
|
52
|
+
- --charset=UTF-8
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.5
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Simple ORM agnostic tagging.
|
74
|
+
test_files:
|
75
|
+
- test/active_record_test.rb
|
76
|
+
- test/delimiter_test.rb
|
77
|
+
- test/mongo_mapper_schema.rb
|
78
|
+
- test/mongo_mapper_test.rb
|
79
|
+
- test/schema.rb
|
80
|
+
- test/tag_list_test.rb
|
81
|
+
- test/tagging_test.rb
|
82
|
+
- test/test_helper.rb
|