acts-as-taggable-on 2.0.0.pre4 → 2.0.0.pre5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +16 -15
- data/VERSION +1 -1
- data/lib/acts-as-taggable-on.rb +6 -6
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +7 -7
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +25 -8
- data/lib/acts_as_taggable_on/acts_as_taggable_on/{aggregate.rb → collection.rb} +33 -28
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +49 -41
- data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +29 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +20 -13
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +39 -51
- data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +2 -2
- data/lib/acts_as_taggable_on/tag.rb +2 -1
- data/lib/acts_as_taggable_on/tagging.rb +1 -0
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +56 -9
- data/spec/acts_as_taggable_on/taggable_spec.rb +29 -19
- data/spec/bm.rb +52 -0
- data/spec/models.rb +10 -6
- data/spec/schema.rb +5 -1
- metadata +19 -8
- data/lib/acts_as_taggable_on/compatibility/tag.rb +0 -3
- data/lib/acts_as_taggable_on/compatibility/tagging.rb +0 -3
data/Rakefile
CHANGED
@@ -1,4 +1,20 @@
|
|
1
1
|
begin
|
2
|
+
# Rspec 1.3.0
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
|
5
|
+
desc 'Default: run specs'
|
6
|
+
task :default => :spec
|
7
|
+
Spec::Rake::SpecTask.new do |t|
|
8
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
9
|
+
end
|
10
|
+
|
11
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
12
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
13
|
+
t.rcov = true
|
14
|
+
t.rcov_opts = ['--exclude', 'spec']
|
15
|
+
end
|
16
|
+
|
17
|
+
rescue LoadError
|
2
18
|
# Rspec 2.0
|
3
19
|
require 'rspec/core/rake_task'
|
4
20
|
|
@@ -12,23 +28,8 @@ begin
|
|
12
28
|
t.pattern = "spec/**/*_spec.rb"
|
13
29
|
t.rcov = true
|
14
30
|
t.rcov_opts = ['--exclude', 'spec']
|
15
|
-
end
|
16
|
-
|
17
|
-
rescue LoadError
|
18
|
-
# Rspec 1.3.0
|
19
|
-
require 'spec/rake/spectask'
|
20
|
-
|
21
|
-
desc 'Default: run specs'
|
22
|
-
task :default => :spec
|
23
|
-
Spec::Rake::SpecTask.new do |t|
|
24
|
-
t.spec_files = FileList["spec/**/*_spec.rb"]
|
25
31
|
end
|
26
32
|
|
27
|
-
Spec::Rake::SpecTask.new('rcov') do |t|
|
28
|
-
t.spec_files = FileList["spec/**/*_spec.rb"]
|
29
|
-
t.rcov = true
|
30
|
-
t.rcov_opts = ['--exclude', 'spec']
|
31
|
-
end
|
32
33
|
rescue LoadError
|
33
34
|
puts "Rspec not available. Install it with: gem install rspec"
|
34
35
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.0.
|
1
|
+
2.0.0.pre5
|
data/lib/acts-as-taggable-on.rb
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
require "active_record"
|
2
2
|
require "action_view"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require "acts_as_taggable_on/compatibility/tagging"
|
8
|
-
end
|
4
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
require "acts_as_taggable_on/compatibility/active_record_backports" if ActiveRecord::VERSION::MAJOR < 3
|
9
7
|
|
10
8
|
require "acts_as_taggable_on/acts_as_taggable_on"
|
11
9
|
require "acts_as_taggable_on/acts_as_taggable_on/core"
|
12
|
-
require "acts_as_taggable_on/acts_as_taggable_on/
|
10
|
+
require "acts_as_taggable_on/acts_as_taggable_on/collection"
|
13
11
|
require "acts_as_taggable_on/acts_as_taggable_on/cache"
|
14
12
|
require "acts_as_taggable_on/acts_as_taggable_on/ownership"
|
15
13
|
require "acts_as_taggable_on/acts_as_taggable_on/related"
|
@@ -20,6 +18,8 @@ require "acts_as_taggable_on/tag_list"
|
|
20
18
|
require "acts_as_taggable_on/tags_helper"
|
21
19
|
require "acts_as_taggable_on/tagging"
|
22
20
|
|
21
|
+
$LOAD_PATH.shift
|
22
|
+
|
23
23
|
if defined?(ActiveRecord::Base)
|
24
24
|
ActiveRecord::Base.extend ActsAsTaggableOn::Taggable
|
25
25
|
ActiveRecord::Base.send :include, ActsAsTaggableOn::Tagger
|
@@ -17,7 +17,7 @@ module ActsAsTaggableOn
|
|
17
17
|
if ::ActiveRecord::VERSION::MAJOR < 3
|
18
18
|
include ActsAsTaggableOn::ActiveRecord::Backports
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
write_inheritable_attribute(:tag_types, tag_types)
|
22
22
|
class_inheritable_reader(:tag_types)
|
23
23
|
|
@@ -28,14 +28,14 @@ module ActsAsTaggableOn
|
|
28
28
|
def self.taggable?
|
29
29
|
true
|
30
30
|
end
|
31
|
+
|
32
|
+
include ActsAsTaggableOn::Taggable::Core
|
33
|
+
include ActsAsTaggableOn::Taggable::Collection
|
34
|
+
include ActsAsTaggableOn::Taggable::Cache
|
35
|
+
include ActsAsTaggableOn::Taggable::Ownership
|
36
|
+
include ActsAsTaggableOn::Taggable::Related
|
31
37
|
end
|
32
38
|
end
|
33
|
-
|
34
|
-
include ActsAsTaggableOn::Taggable::Core
|
35
|
-
include ActsAsTaggableOn::Taggable::Aggregate
|
36
|
-
include ActsAsTaggableOn::Taggable::Cache
|
37
|
-
include ActsAsTaggableOn::Taggable::Ownership
|
38
|
-
include ActsAsTaggableOn::Taggable::Related
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -11,26 +11,43 @@ module ActsAsTaggableOn::Taggable
|
|
11
11
|
before_save :save_cached_tag_list
|
12
12
|
end
|
13
13
|
|
14
|
-
base.
|
15
|
-
base.class_eval %(
|
16
|
-
def self.caching_#{tag_type.singularize}_list?
|
17
|
-
caching_tag_list_on?("#{tag_type}")
|
18
|
-
end
|
19
|
-
)
|
20
|
-
end
|
14
|
+
base.intialize_acts_as_taggable_on_cache
|
21
15
|
end
|
22
16
|
|
23
17
|
module ClassMethods
|
18
|
+
def intialize_acts_as_taggable_on_cache
|
19
|
+
tag_types.map(&:to_s).each do |tag_type|
|
20
|
+
class_eval %(
|
21
|
+
def self.caching_#{tag_type.singularize}_list?
|
22
|
+
caching_tag_list_on?("#{tag_type}")
|
23
|
+
end
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def acts_as_taggable_on(*args)
|
29
|
+
super(*args)
|
30
|
+
intialize_acts_as_taggable_on_cache
|
31
|
+
end
|
32
|
+
|
24
33
|
def caching_tag_list_on?(context)
|
25
34
|
column_names.include?("cached_#{context.to_s.singularize}_list")
|
26
35
|
end
|
27
36
|
end
|
28
37
|
|
29
38
|
module InstanceMethods
|
39
|
+
def tag_list_cache_set_on(context)
|
40
|
+
variable_name = "@#{context.to_s.singularize}_list"
|
41
|
+
!instance_variable_get(variable_name).nil?
|
42
|
+
end
|
43
|
+
|
30
44
|
def save_cached_tag_list
|
31
45
|
tag_types.map(&:to_s).each do |tag_type|
|
32
46
|
if self.class.send("caching_#{tag_type.singularize}_list?")
|
33
|
-
|
47
|
+
if tag_list_cache_set_on(tag_type)
|
48
|
+
list = tag_list_cache_on(tag_type.singularize).to_a.flatten.compact.join(', ')
|
49
|
+
self["cached_#{tag_type.singularize}_list"] = list
|
50
|
+
end
|
34
51
|
end
|
35
52
|
end
|
36
53
|
end
|
@@ -1,35 +1,41 @@
|
|
1
1
|
module ActsAsTaggableOn::Taggable
|
2
|
-
module
|
2
|
+
module Collection
|
3
3
|
def self.included(base)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
base.tag_types.map(&:to_s).each do |tag_type|
|
10
|
-
base.class_eval %(
|
11
|
-
def #{tag_type.singularize}_counts(options = {})
|
12
|
-
tag_counts_on('#{tag_type}', options)
|
13
|
-
end
|
14
|
-
|
15
|
-
def top_#{tag_type}(limit = 10)
|
16
|
-
tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.top_#{tag_type}(limit = 10)
|
20
|
-
tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
|
21
|
-
end
|
22
|
-
)
|
23
|
-
end
|
4
|
+
base.send :include, ActsAsTaggableOn::Taggable::Collection::InstanceMethods
|
5
|
+
base.extend ActsAsTaggableOn::Taggable::Collection::ClassMethods
|
6
|
+
base.initialize_acts_as_taggable_on_collection
|
24
7
|
end
|
25
8
|
|
26
9
|
module ClassMethods
|
27
|
-
def
|
28
|
-
|
29
|
-
|
10
|
+
def initialize_acts_as_taggable_on_collection
|
11
|
+
tag_types.map(&:to_s).each do |tag_type|
|
12
|
+
class_eval %(
|
13
|
+
def self.#{tag_type.singularize}_counts(options={})
|
14
|
+
tag_counts_on('#{tag_type}', options)
|
15
|
+
end
|
30
16
|
|
31
|
-
|
32
|
-
|
17
|
+
def #{tag_type.singularize}_counts(options = {})
|
18
|
+
tag_counts_on('#{tag_type}', options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def top_#{tag_type}(limit = 10)
|
22
|
+
tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.top_#{tag_type}(limit = 10)
|
26
|
+
tag_counts_on('#{tag_type}', :order => 'count desc', :limit => limit.to_i)
|
27
|
+
end
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def acts_as_taggable_on(*args)
|
33
|
+
super(*args)
|
34
|
+
initialize_acts_as_taggable_on_collection
|
35
|
+
end
|
36
|
+
|
37
|
+
def tag_counts_on(context, options = {})
|
38
|
+
all_tag_counts(options.merge({:on => context.to_s}))
|
33
39
|
end
|
34
40
|
|
35
41
|
# Calculate the tag counts for all tags.
|
@@ -43,7 +49,7 @@ module ActsAsTaggableOn::Taggable
|
|
43
49
|
# :at_least - Exclude tags with a frequency less than the given value
|
44
50
|
# :at_most - Exclude tags with a frequency greater than the given value
|
45
51
|
# :on - Scope the find to only include a certain context
|
46
|
-
def
|
52
|
+
def all_tag_counts(options = {})
|
47
53
|
options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id
|
48
54
|
|
49
55
|
start_at = sanitize_sql(["#{Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
|
@@ -79,7 +85,6 @@ module ActsAsTaggableOn::Taggable
|
|
79
85
|
group_by << " AND #{having}" unless having.blank?
|
80
86
|
|
81
87
|
Tag.select("#{Tag.table_name}.*, COUNT(*) AS count").joins(joins.join(" ")).where(conditions).group(group_by).limit(options[:limit]).order(options[:order])
|
82
|
-
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
@@ -6,51 +6,51 @@ module ActsAsTaggableOn::Taggable
|
|
6
6
|
|
7
7
|
base.class_eval do
|
8
8
|
attr_writer :custom_contexts
|
9
|
-
|
10
9
|
after_save :save_tags
|
11
|
-
|
12
|
-
def self.tagged_with(*args)
|
13
|
-
find_options_for_find_tagged_with(*args)
|
14
|
-
end
|
15
10
|
end
|
16
11
|
|
17
|
-
base.
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
12
|
+
base.initialize_acts_as_taggable_on_core
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def initialize_acts_as_taggable_on_core
|
17
|
+
tag_types.map(&:to_s).each do |tag_type|
|
18
|
+
context_taggings = "#{tag_type.singularize}_taggings".to_sym
|
19
|
+
context_tags = tag_type.to_sym
|
20
|
+
|
21
|
+
class_eval do
|
22
|
+
has_many context_taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "Tagging",
|
23
|
+
:conditions => ['#{Tagging.table_name}.tagger_id IS NULL AND #{Tagging.table_name}.context = ?', tag_type]
|
24
|
+
has_many context_tags, :through => context_taggings, :source => :tag
|
30
25
|
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
class_eval %(
|
28
|
+
def #{tag_type.singularize}_list
|
29
|
+
tag_list_on('#{tag_type}')
|
30
|
+
end
|
35
31
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
32
|
+
def #{tag_type.singularize}_list=(new_tags)
|
33
|
+
set_tag_list_on('#{tag_type}', new_tags)
|
34
|
+
end
|
35
|
+
|
36
|
+
def all_#{tag_type}_list
|
37
|
+
all_tags_list_on('#{tag_type}')
|
38
|
+
end
|
39
|
+
)
|
40
|
+
end
|
44
41
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
|
43
|
+
def acts_as_taggable_on(*args)
|
44
|
+
super(*args)
|
45
|
+
initialize_acts_as_taggable_on_core
|
46
|
+
end
|
47
|
+
|
48
48
|
# all column names are necessary for PostgreSQL group clause
|
49
49
|
def grouped_column_names_for(object)
|
50
50
|
object.column_names.map { |column| "#{object.table_name}.#{column}" }.join(", ")
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
53
|
+
def tagged_with(tags, options = {})
|
54
54
|
tag_list = TagList.from(tags)
|
55
55
|
|
56
56
|
return {} if tag_list.empty?
|
@@ -98,19 +98,19 @@ module ActsAsTaggableOn::Taggable
|
|
98
98
|
group = "#{grouped_column_names_for(self)} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
|
99
99
|
end
|
100
100
|
|
101
|
+
|
101
102
|
joins(joins.join(" ")).group(group).where(conditions.join(" AND ")).readonly(false)
|
102
103
|
end
|
103
104
|
|
104
105
|
def is_taggable?
|
105
106
|
true
|
106
107
|
end
|
107
|
-
|
108
108
|
end
|
109
109
|
|
110
110
|
module InstanceMethods
|
111
111
|
# all column names are necessary for PostgreSQL group clause
|
112
112
|
def grouped_column_names_for(object)
|
113
|
-
|
113
|
+
self.class.grouped_column_names_for(object)
|
114
114
|
end
|
115
115
|
|
116
116
|
def custom_contexts
|
@@ -156,7 +156,13 @@ module ActsAsTaggableOn::Taggable
|
|
156
156
|
##
|
157
157
|
# Returns all tags that are not owned of a given context
|
158
158
|
def tags_on(context)
|
159
|
-
|
159
|
+
if respond_to?(context)
|
160
|
+
# If the association is available, use it:
|
161
|
+
send(context).all
|
162
|
+
else
|
163
|
+
# If the association is not available, query it the old fashioned way
|
164
|
+
base_tags.where(["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id IS NULL", context.to_s]).all
|
165
|
+
end
|
160
166
|
end
|
161
167
|
|
162
168
|
def set_tag_list_on(context, new_list)
|
@@ -180,7 +186,7 @@ module ActsAsTaggableOn::Taggable
|
|
180
186
|
end
|
181
187
|
|
182
188
|
def save_tags
|
183
|
-
transaction do
|
189
|
+
transaction do
|
184
190
|
tagging_contexts.each do |context|
|
185
191
|
tag_list = tag_list_cache_on(context).uniq
|
186
192
|
|
@@ -192,11 +198,13 @@ module ActsAsTaggableOn::Taggable
|
|
192
198
|
new_tags = tag_list - current_tags
|
193
199
|
|
194
200
|
# Find taggings to remove:
|
195
|
-
old_taggings =
|
196
|
-
|
197
|
-
:context => context.to_s, :tag_id => old_tags)
|
201
|
+
old_taggings = taggings.where(:tagger_type => nil, :tagger_id => nil,
|
202
|
+
:context => context.to_s, :tag_id => old_tags).all
|
198
203
|
|
199
|
-
|
204
|
+
if old_taggings.present?
|
205
|
+
# Destroy old taggings:
|
206
|
+
Tagging.destroy_all :id => old_taggings.map(&:id)
|
207
|
+
end
|
200
208
|
|
201
209
|
# Create new taggings:
|
202
210
|
new_tags.each do |tag|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActsAsTaggableOn::Taggable
|
2
|
+
module Dirty
|
3
|
+
def self.included(base)
|
4
|
+
include ActsAsTaggableOn::Taggable::Dirty::InstanceMethods
|
5
|
+
|
6
|
+
base.tag_types.map(&:to_s).each do |tag_type|
|
7
|
+
base.class_eval %(
|
8
|
+
def #{tag_type.singularize}_list_changed?
|
9
|
+
tag_list_changed_on?('#{tag_type}')
|
10
|
+
tag_list_on('#{tag_type}')
|
11
|
+
end
|
12
|
+
|
13
|
+
def #{tag_type.singularize}_list=(new_tags)
|
14
|
+
change_tag_list_on('#{tag_type}', new_tags)
|
15
|
+
super(new_tags)
|
16
|
+
end
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module InstanceMethods
|
22
|
+
def tag_list_changed_on?(context)
|
23
|
+
end
|
24
|
+
|
25
|
+
def change_tag_list_on(context, new_tags)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -6,18 +6,26 @@ module ActsAsTaggableOn::Taggable
|
|
6
6
|
|
7
7
|
base.class_eval do
|
8
8
|
after_save :save_owned_tags
|
9
|
-
end
|
10
|
-
|
11
|
-
base.tag_types.map(&:to_s).each do |tag_type|
|
12
|
-
base.class_eval %(
|
13
|
-
def #{tag_type}_from(owner)
|
14
|
-
owner_tag_list_on(owner, '#{tag_type}')
|
15
|
-
end
|
16
|
-
)
|
17
9
|
end
|
10
|
+
|
11
|
+
base.initialize_acts_as_taggable_on_ownership
|
18
12
|
end
|
19
13
|
|
20
14
|
module ClassMethods
|
15
|
+
def acts_as_taggable_on(*args)
|
16
|
+
initialize_acts_as_taggable_on_ownership
|
17
|
+
super(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize_acts_as_taggable_on_ownership
|
21
|
+
tag_types.map(&:to_s).each do |tag_type|
|
22
|
+
class_eval %(
|
23
|
+
def #{tag_type}_from(owner)
|
24
|
+
owner_tag_list_on(owner, '#{tag_type}')
|
25
|
+
end
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
21
29
|
end
|
22
30
|
|
23
31
|
module InstanceMethods
|
@@ -65,16 +73,15 @@ module ActsAsTaggableOn::Taggable
|
|
65
73
|
# Find existing tags or create non-existing tags:
|
66
74
|
tag_list = Tag.find_or_create_all_with_like_by_name(tag_list.uniq)
|
67
75
|
|
68
|
-
owned_tags = owner_tags_on(owner, context)
|
69
|
-
|
70
|
-
|
71
|
-
new_tags = tag_list - owned_tags
|
76
|
+
owned_tags = owner_tags_on(owner, context)
|
77
|
+
old_tags = owned_tags - tag_list
|
78
|
+
new_tags = tag_list - owned_tags
|
72
79
|
|
73
80
|
# Find all taggings that belong to the taggable (self), are owned by the owner,
|
74
81
|
# have the correct context, and are removed from the list.
|
75
82
|
old_taggings = Tagging.where(:taggable_id => id, :taggable_type => self.class.base_class.to_s,
|
76
83
|
:tagger_type => owner.class.to_s, :tagger_id => owner.id,
|
77
|
-
:tag_id => old_tags, :context => context)
|
84
|
+
:tag_id => old_tags, :context => context).all
|
78
85
|
|
79
86
|
if old_taggings.present?
|
80
87
|
# Destroy old taggings:
|
@@ -1,75 +1,63 @@
|
|
1
1
|
module ActsAsTaggableOn::Taggable
|
2
2
|
module Related
|
3
3
|
def self.included(base)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
base.send :include, ActsAsTaggableOn::Taggable::Related::InstanceMethods
|
5
|
+
base.extend ActsAsTaggableOn::Taggable::Related::ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def initialize_acts_as_taggable_on_related
|
10
|
+
tag_types.map(&:to_s).each do |tag_type|
|
11
|
+
class_eval %(
|
12
|
+
def find_related_#{tag_type}(options = {})
|
13
|
+
related_tags_for('#{tag_type}', self.class, options)
|
14
|
+
end
|
15
|
+
alias_method :find_related_on_#{tag_type}, :find_related_#{tag_type}
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
def find_related_#{tag_type}_for(klass, options = {})
|
18
|
+
related_tags_for('#{tag_type}', klass, options)
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
def find_matching_contexts(search_context, result_context, options = {})
|
22
|
+
matching_contexts_for(search_context.to_s, result_context.to_s, self.class, options)
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def find_matching_contexts_for(klass, search_context, result_context, options = {})
|
26
|
+
matching_contexts_for(search_context.to_s, result_context.to_s, klass, options)
|
27
|
+
end
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def acts_as_taggable_on(*args)
|
33
|
+
super(*args)
|
34
|
+
initialize_acts_as_taggable_on_related
|
28
35
|
end
|
29
|
-
end
|
30
|
-
|
31
|
-
module ClassMethods
|
32
36
|
end
|
33
37
|
|
34
38
|
module InstanceMethods
|
35
39
|
def matching_contexts_for(search_context, result_context, klass, options = {})
|
36
|
-
search_conditions = matching_context_search_options(search_context, result_context, klass, options)
|
37
|
-
|
38
|
-
# klass.select(search_conditions[:select]).from(search_conditions[:from]).where(search_conditions[:conditions]).group(search_conditions[:group]).order(search_conditions[:order])
|
39
|
-
klass.scoped(search_conditions)
|
40
|
-
end
|
41
|
-
|
42
|
-
def matching_context_search_options(search_context, result_context, klass, options = {})
|
43
40
|
tags_to_find = tags_on(search_context).collect { |t| t.name }
|
44
41
|
|
45
42
|
exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
|
46
|
-
|
47
|
-
{ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
}.update(options)
|
43
|
+
|
44
|
+
klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
|
45
|
+
:from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
|
46
|
+
:conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?) AND #{Tagging.table_name}.context = ?", tags_to_find, result_context],
|
47
|
+
:group => grouped_column_names_for(klass),
|
48
|
+
:order => "count DESC" }.update(options))
|
53
49
|
end
|
54
50
|
|
55
51
|
def related_tags_for(context, klass, options = {})
|
56
|
-
search_conditions = related_search_options(context, klass, options)
|
57
|
-
|
58
|
-
# klass.select(search_conditions[:select]).from(search_conditions[:from]).where(search_conditions[:conditions]).group(search_conditions[:group]).order(search_conditions[:order])
|
59
|
-
klass.scoped(search_conditions)
|
60
|
-
end
|
61
|
-
|
62
|
-
def related_search_options(context, klass, options = {})
|
63
52
|
tags_to_find = tags_on(context).collect { |t| t.name }
|
64
53
|
|
65
54
|
exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
|
66
55
|
|
67
|
-
{ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
}.update(options)
|
56
|
+
klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
|
57
|
+
:from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
|
58
|
+
:conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?)", tags_to_find],
|
59
|
+
:group => grouped_column_names_for(klass),
|
60
|
+
:order => "count DESC" }.update(options))
|
73
61
|
end
|
74
62
|
end
|
75
63
|
end
|
@@ -6,10 +6,10 @@ module ActsAsTaggableOn
|
|
6
6
|
named_scope :where, lambda { |conditions| { :conditions => conditions } }
|
7
7
|
named_scope :joins, lambda { |joins| { :joins => joins } }
|
8
8
|
named_scope :group, lambda { |group| { :group => group } }
|
9
|
-
named_scope :readonly, lambda { |readonly| { :readonly => readonly } }
|
10
9
|
named_scope :order, lambda { |order| { :order => order } }
|
11
10
|
named_scope :select, lambda { |select| { :select => select } }
|
12
|
-
named_scope :limit, lambda { |limit| { :limit => limit } }
|
11
|
+
named_scope :limit, lambda { |limit| { :limit => limit } }
|
12
|
+
named_scope :readonly, lambda { |readonly| { :readonly => readonly } }
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -35,19 +35,10 @@ describe "Acts As Taggable On" do
|
|
35
35
|
@taggable.should respond_to(:tags, :skills, :languages)
|
36
36
|
end
|
37
37
|
|
38
|
-
it "should generate a cached column checker for each tag type" do
|
39
|
-
TaggableModel.should respond_to(:caching_tag_list?, :caching_skill_list?, :caching_language_list?)
|
40
|
-
end
|
41
|
-
|
42
38
|
it "should add tagged_with and tag_counts to singleton" do
|
43
39
|
TaggableModel.should respond_to(:tagged_with, :tag_counts)
|
44
40
|
end
|
45
41
|
|
46
|
-
it "should add saving of tag lists and cached tag lists to the instance" do
|
47
|
-
@taggable.should respond_to(:save_cached_tag_list)
|
48
|
-
@taggable.should respond_to(:save_tags)
|
49
|
-
end
|
50
|
-
|
51
42
|
it "should generate a tag_list accessor/setter for each tag type" do
|
52
43
|
@taggable.should respond_to(:tag_list, :skill_list, :language_list)
|
53
44
|
@taggable.should respond_to(:tag_list=, :skill_list=, :language_list=)
|
@@ -215,5 +206,61 @@ describe "Acts As Taggable On" do
|
|
215
206
|
}.should_not raise_error
|
216
207
|
end
|
217
208
|
end
|
209
|
+
|
210
|
+
describe 'Caching' do
|
211
|
+
before(:each) do
|
212
|
+
@taggable = CachedModel.new(:name => "Bob Jones")
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should add saving of tag lists and cached tag lists to the instance" do
|
216
|
+
@taggable.should respond_to(:save_cached_tag_list)
|
217
|
+
@taggable.should respond_to(:save_tags)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should generate a cached column checker for each tag type" do
|
221
|
+
CachedModel.should respond_to(:caching_tag_list?)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'should not have cached tags' do
|
225
|
+
@taggable.cached_tag_list.should be_blank
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should cache tags' do
|
229
|
+
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
230
|
+
@taggable.cached_tag_list.should == 'awesome, epic'
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'should keep the cache' do
|
234
|
+
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
235
|
+
@taggable = CachedModel.find(@taggable)
|
236
|
+
@taggable.save!
|
237
|
+
@taggable.cached_tag_list.should == 'awesome, epic'
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should update the cache' do
|
241
|
+
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
242
|
+
@taggable.update_attributes(:tag_list => 'awesome')
|
243
|
+
@taggable.cached_tag_list.should == 'awesome'
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'should remove the cache' do
|
247
|
+
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
248
|
+
@taggable.update_attributes(:tag_list => '')
|
249
|
+
@taggable.cached_tag_list.should be_blank
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'should have a tag list' do
|
253
|
+
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
254
|
+
@taggable = CachedModel.find(@taggable.id)
|
255
|
+
@taggable.tag_list.sort.should == %w(awesome epic).sort
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'should keep the tag list' do
|
259
|
+
@taggable.update_attributes(:tag_list => 'awesome, epic')
|
260
|
+
@taggable = CachedModel.find(@taggable.id)
|
261
|
+
@taggable.save!
|
262
|
+
@taggable.tag_list.sort.should == %w(awesome epic).sort
|
263
|
+
end
|
264
|
+
end
|
218
265
|
|
219
266
|
end
|
@@ -88,7 +88,7 @@ describe "Taggable" do
|
|
88
88
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "Ruby")
|
89
89
|
|
90
90
|
Tag.find(:all).size.should == 1
|
91
|
-
TaggableModel.tagged_with("ruby").
|
91
|
+
TaggableModel.tagged_with("ruby").to_a.should == TaggableModel.tagged_with("Ruby").to_a
|
92
92
|
end
|
93
93
|
|
94
94
|
it "should be able to get tag counts on model as a whole" do
|
@@ -108,10 +108,20 @@ describe "Taggable" do
|
|
108
108
|
TaggableModel.all_tag_counts.first.count.should == 3 # ruby
|
109
109
|
end
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
if ActiveRecord::VERSION::MAJOR >= 3
|
112
|
+
it "should not return read-only records" do
|
113
|
+
TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
114
|
+
TaggableModel.tagged_with("ruby").first.should_not be_readonly
|
115
|
+
end
|
116
|
+
else
|
117
|
+
xit "should not return read-only records" do
|
118
|
+
# apparantly, there is no way to set readonly to false in a scope if joins are made
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should be possible to return writable records" do
|
122
|
+
TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
123
|
+
TaggableModel.tagged_with("ruby").first(:readonly => false).should_not be_readonly
|
124
|
+
end
|
115
125
|
end
|
116
126
|
|
117
127
|
it "should be able to get scoped tag counts" do
|
@@ -145,9 +155,9 @@ describe "Taggable" do
|
|
145
155
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
|
146
156
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
|
147
157
|
|
148
|
-
TaggableModel.tagged_with("ruby", :order => 'taggable_models.name').
|
149
|
-
TaggableModel.tagged_with("ruby, rails", :order => 'taggable_models.name').
|
150
|
-
TaggableModel.tagged_with(["ruby", "rails"], :order => 'taggable_models.name').
|
158
|
+
TaggableModel.tagged_with("ruby", :order => 'taggable_models.name').to_a.should == [bob, frank, steve]
|
159
|
+
TaggableModel.tagged_with("ruby, rails", :order => 'taggable_models.name').to_a.should == [bob, frank]
|
160
|
+
TaggableModel.tagged_with(["ruby", "rails"], :order => 'taggable_models.name').to_a.should == [bob, frank]
|
151
161
|
end
|
152
162
|
|
153
163
|
it "should be able to find tagged with any tag" do
|
@@ -155,9 +165,9 @@ describe "Taggable" do
|
|
155
165
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
|
156
166
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
|
157
167
|
|
158
|
-
TaggableModel.tagged_with(["ruby", "java"], :order => 'taggable_models.name', :any => true).
|
159
|
-
TaggableModel.tagged_with(["c++", "fitter"], :order => 'taggable_models.name', :any => true).
|
160
|
-
TaggableModel.tagged_with(["depressed", "css"], :order => 'taggable_models.name', :any => true).
|
168
|
+
TaggableModel.tagged_with(["ruby", "java"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank, steve]
|
169
|
+
TaggableModel.tagged_with(["c++", "fitter"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, steve]
|
170
|
+
TaggableModel.tagged_with(["depressed", "css"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank]
|
161
171
|
end
|
162
172
|
|
163
173
|
it "should be able to find tagged on a custom tag context" do
|
@@ -166,7 +176,7 @@ describe "Taggable" do
|
|
166
176
|
bob.tag_list_on(:rotors).should == ["spinning","jumping"]
|
167
177
|
bob.save
|
168
178
|
|
169
|
-
TaggableModel.tagged_with("spinning", :on => :rotors).
|
179
|
+
TaggableModel.tagged_with("spinning", :on => :rotors).to_a.should == [bob]
|
170
180
|
end
|
171
181
|
|
172
182
|
it "should be able to use named scopes to chain tag finds" do
|
@@ -175,10 +185,10 @@ describe "Taggable" do
|
|
175
185
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, python')
|
176
186
|
|
177
187
|
# Let's only find those productive Rails developers
|
178
|
-
TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').
|
179
|
-
TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').
|
180
|
-
TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).
|
181
|
-
TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).
|
188
|
+
TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').to_a.should == [bob, frank]
|
189
|
+
TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').to_a.should == [bob, steve]
|
190
|
+
TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).to_a.should == [bob]
|
191
|
+
TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).to_a.should == [bob]
|
182
192
|
end
|
183
193
|
|
184
194
|
it "should be able to find tagged with only the matching tags" do
|
@@ -186,7 +196,7 @@ describe "Taggable" do
|
|
186
196
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "fitter, happier, inefficient")
|
187
197
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => "fitter, happier")
|
188
198
|
|
189
|
-
TaggableModel.tagged_with("fitter, happier", :match_all => true).
|
199
|
+
TaggableModel.tagged_with("fitter, happier", :match_all => true).to_a.should == [steve]
|
190
200
|
end
|
191
201
|
|
192
202
|
it "should be able to find tagged with some excluded tags" do
|
@@ -194,7 +204,7 @@ describe "Taggable" do
|
|
194
204
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "happier")
|
195
205
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => "happier")
|
196
206
|
|
197
|
-
TaggableModel.tagged_with("lazy", :exclude => true).
|
207
|
+
TaggableModel.tagged_with("lazy", :exclude => true).to_a.should == [frank, steve]
|
198
208
|
end
|
199
209
|
|
200
210
|
it "should not create duplicate taggings" do
|
@@ -212,7 +222,7 @@ describe "Taggable" do
|
|
212
222
|
end
|
213
223
|
|
214
224
|
it "should return all column names joined for TaggableModel GROUP clause" do
|
215
|
-
@taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.id, taggable_models.name, taggable_models.type
|
225
|
+
@taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.id, taggable_models.name, taggable_models.type"
|
216
226
|
end
|
217
227
|
end
|
218
228
|
|
data/spec/bm.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'action_view'
|
3
|
+
require File.expand_path('../../lib/acts-as-taggable-on', __FILE__)
|
4
|
+
|
5
|
+
if defined?(ActiveRecord::Acts::TaggableOn)
|
6
|
+
ActiveRecord::Base.send :include, ActiveRecord::Acts::TaggableOn
|
7
|
+
ActiveRecord::Base.send :include, ActiveRecord::Acts::Tagger
|
8
|
+
ActionView::Base.send :include, TagsHelper if defined?(ActionView::Base)
|
9
|
+
end
|
10
|
+
|
11
|
+
TEST_DATABASE_FILE = File.join(File.dirname(__FILE__), '..', 'test.sqlite3')
|
12
|
+
File.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)
|
13
|
+
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => TEST_DATABASE_FILE
|
14
|
+
|
15
|
+
ActiveRecord::Base.silence do
|
16
|
+
ActiveRecord::Migration.verbose = false
|
17
|
+
ActiveRecord::Schema.define :version => 0 do
|
18
|
+
create_table "taggings", :force => true do |t|
|
19
|
+
t.integer "tag_id", :limit => 11
|
20
|
+
t.integer "taggable_id", :limit => 11
|
21
|
+
t.string "taggable_type"
|
22
|
+
t.string "context"
|
23
|
+
t.datetime "created_at"
|
24
|
+
t.integer "tagger_id", :limit => 11
|
25
|
+
t.string "tagger_type"
|
26
|
+
end
|
27
|
+
|
28
|
+
add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
|
29
|
+
add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
|
30
|
+
|
31
|
+
create_table "tags", :force => true do |t|
|
32
|
+
t.string "name"
|
33
|
+
end
|
34
|
+
|
35
|
+
create_table :taggable_models, :force => true do |t|
|
36
|
+
t.column :name, :string
|
37
|
+
t.column :type, :string
|
38
|
+
t.column :cached_tag_list, :string
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class TaggableModel < ActiveRecord::Base
|
43
|
+
acts_as_taggable
|
44
|
+
acts_as_taggable_on :languages
|
45
|
+
acts_as_taggable_on :skills
|
46
|
+
acts_as_taggable_on :needs, :offerings
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
puts Benchmark.measure {
|
51
|
+
1000.times { TaggableModel.create :tag_list => "awesome, epic, neat" }
|
52
|
+
}
|
data/spec/models.rb
CHANGED
@@ -5,6 +5,10 @@ class TaggableModel < ActiveRecord::Base
|
|
5
5
|
acts_as_taggable_on :needs, :offerings
|
6
6
|
end
|
7
7
|
|
8
|
+
class CachedModel < ActiveRecord::Base
|
9
|
+
acts_as_taggable
|
10
|
+
end
|
11
|
+
|
8
12
|
class OtherTaggableModel < ActiveRecord::Base
|
9
13
|
acts_as_taggable_on :tags, :languages
|
10
14
|
acts_as_taggable_on :needs, :offerings
|
@@ -24,9 +28,9 @@ end
|
|
24
28
|
class UntaggableModel < ActiveRecord::Base
|
25
29
|
end
|
26
30
|
|
27
|
-
if ActiveRecord::VERSION::MAJOR < 3
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
31
|
+
# if ActiveRecord::VERSION::MAJOR < 3
|
32
|
+
# [TaggableModel, CachedModel, OtherTaggableModel, InheritingTaggableModel,
|
33
|
+
# AlteredInheritingTaggableModel, TaggableUser, UntaggableModel].each do |klass|
|
34
|
+
# klass.send(:include, ActsAsTaggableOn::ActiveRecord::Backports)
|
35
|
+
# end
|
36
|
+
# end
|
data/spec/schema.rb
CHANGED
@@ -19,6 +19,11 @@ ActiveRecord::Schema.define :version => 0 do
|
|
19
19
|
create_table :taggable_models, :force => true do |t|
|
20
20
|
t.column :name, :string
|
21
21
|
t.column :type, :string
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :cached_models, :force => true do |t|
|
25
|
+
t.column :name, :string
|
26
|
+
t.column :type, :string
|
22
27
|
t.column :cached_tag_list, :string
|
23
28
|
end
|
24
29
|
|
@@ -29,7 +34,6 @@ ActiveRecord::Schema.define :version => 0 do
|
|
29
34
|
create_table :other_taggable_models, :force => true do |t|
|
30
35
|
t.column :name, :string
|
31
36
|
t.column :type, :string
|
32
|
-
#t.column :cached_tag_list, :string
|
33
37
|
end
|
34
38
|
|
35
39
|
create_table :untaggable_models, :force => true do |t|
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts-as-taggable-on
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: true
|
5
|
+
segments:
|
6
|
+
- 2
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- pre5
|
10
|
+
version: 2.0.0.pre5
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Michael Bleigh
|
@@ -9,7 +15,7 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2010-03-
|
18
|
+
date: 2010-03-25 00:00:00 +01:00
|
13
19
|
default_executable:
|
14
20
|
dependencies: []
|
15
21
|
|
@@ -30,16 +36,15 @@ files:
|
|
30
36
|
- VERSION
|
31
37
|
- lib/acts-as-taggable-on.rb
|
32
38
|
- lib/acts_as_taggable_on/acts_as_taggable_on.rb
|
33
|
-
- lib/acts_as_taggable_on/acts_as_taggable_on/aggregate.rb
|
34
39
|
- lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb
|
40
|
+
- lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb
|
35
41
|
- lib/acts_as_taggable_on/acts_as_taggable_on/core.rb
|
42
|
+
- lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb
|
36
43
|
- lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb
|
37
44
|
- lib/acts_as_taggable_on/acts_as_taggable_on/related.rb
|
38
45
|
- lib/acts_as_taggable_on/acts_as_tagger.rb
|
39
46
|
- lib/acts_as_taggable_on/compatibility/Gemfile
|
40
47
|
- lib/acts_as_taggable_on/compatibility/active_record_backports.rb
|
41
|
-
- lib/acts_as_taggable_on/compatibility/tag.rb
|
42
|
-
- lib/acts_as_taggable_on/compatibility/tagging.rb
|
43
48
|
- lib/acts_as_taggable_on/tag.rb
|
44
49
|
- lib/acts_as_taggable_on/tag_list.rb
|
45
50
|
- lib/acts_as_taggable_on/tagging.rb
|
@@ -55,6 +60,7 @@ files:
|
|
55
60
|
- spec/acts_as_taggable_on/tagger_spec.rb
|
56
61
|
- spec/acts_as_taggable_on/tagging_spec.rb
|
57
62
|
- spec/acts_as_taggable_on/tags_helper_spec.rb
|
63
|
+
- spec/bm.rb
|
58
64
|
- spec/models.rb
|
59
65
|
- spec/schema.rb
|
60
66
|
- spec/spec.opts
|
@@ -72,18 +78,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
78
|
requirements:
|
73
79
|
- - ">="
|
74
80
|
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
75
83
|
version: "0"
|
76
|
-
version:
|
77
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
85
|
requirements:
|
79
86
|
- - ">"
|
80
87
|
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 1
|
90
|
+
- 3
|
91
|
+
- 1
|
81
92
|
version: 1.3.1
|
82
|
-
version:
|
83
93
|
requirements: []
|
84
94
|
|
85
95
|
rubyforge_project:
|
86
|
-
rubygems_version: 1.3.
|
96
|
+
rubygems_version: 1.3.6
|
87
97
|
signing_key:
|
88
98
|
specification_version: 3
|
89
99
|
summary: ActsAsTaggableOn is a tagging plugin for Rails that provides multiple tagging contexts on a single model.
|
@@ -96,6 +106,7 @@ test_files:
|
|
96
106
|
- spec/acts_as_taggable_on/tagger_spec.rb
|
97
107
|
- spec/acts_as_taggable_on/tagging_spec.rb
|
98
108
|
- spec/acts_as_taggable_on/tags_helper_spec.rb
|
109
|
+
- spec/bm.rb
|
99
110
|
- spec/models.rb
|
100
111
|
- spec/schema.rb
|
101
112
|
- spec/spec_helper.rb
|