acts-as-taggable-on 1.0.14 → 1.1.0
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/VERSION +1 -1
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +86 -44
- data/lib/acts_as_taggable_on/tag.rb +11 -0
- data/lib/acts_as_taggable_on/tag_list.rb +6 -11
- data/lib/acts_as_taggable_on/tagging.rb +6 -0
- data/rails/init.rb +1 -3
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +0 -14
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +16 -2
- data/spec/acts_as_taggable_on/tag_list_spec.rb +18 -0
- data/spec/acts_as_taggable_on/taggable_spec.rb +69 -37
- data/spec/acts_as_taggable_on/tagger_spec.rb +17 -2
- data/spec/acts_as_taggable_on/tagging_spec.rb +9 -0
- data/spec/spec_helper.rb +13 -2
- metadata +2 -2
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0
|
|
1
|
+
1.1.0
|
|
@@ -19,15 +19,15 @@ module ActiveRecord
|
|
|
19
19
|
args.compact! if args
|
|
20
20
|
for tag_type in args
|
|
21
21
|
tag_type = tag_type.to_s
|
|
22
|
-
# use aliased_join_table_name for context condition so that
|
|
22
|
+
# use aliased_join_table_name for context condition so that sphinx can join multiple
|
|
23
23
|
# tag references from same model without getting an ambiguous column error
|
|
24
|
-
|
|
24
|
+
class_eval do
|
|
25
25
|
has_many "#{tag_type.singularize}_taggings".to_sym, :as => :taggable, :dependent => :destroy,
|
|
26
|
-
:include => :tag, :conditions => ['#{aliased_join_table_name rescue
|
|
26
|
+
:include => :tag, :conditions => ['#{aliased_join_table_name || Tagging.table_name rescue Tagging.table_name}.context = ?',tag_type], :class_name => "Tagging"
|
|
27
27
|
has_many "#{tag_type}".to_sym, :through => "#{tag_type.singularize}_taggings".to_sym, :source => :tag
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
class_eval <<-RUBY
|
|
31
31
|
def self.taggable?
|
|
32
32
|
true
|
|
33
33
|
end
|
|
@@ -82,11 +82,10 @@ module ActiveRecord
|
|
|
82
82
|
end
|
|
83
83
|
RUBY
|
|
84
84
|
end
|
|
85
|
-
|
|
86
85
|
if respond_to?(:tag_types)
|
|
87
86
|
write_inheritable_attribute( :tag_types, (tag_types + args).uniq )
|
|
88
87
|
else
|
|
89
|
-
|
|
88
|
+
class_eval do
|
|
90
89
|
write_inheritable_attribute(:tag_types, args.uniq)
|
|
91
90
|
class_inheritable_reader :tag_types
|
|
92
91
|
|
|
@@ -117,6 +116,7 @@ module ActiveRecord
|
|
|
117
116
|
# Pass either a tag string, or an array of strings or tags
|
|
118
117
|
#
|
|
119
118
|
# Options:
|
|
119
|
+
# :any - find models that match any of the given tags
|
|
120
120
|
# :exclude - Find models that are not tagged with the given tags
|
|
121
121
|
# :match_all - Find models that match all of the given tags, not just one
|
|
122
122
|
# :conditions - A piece of SQL conditions to add to the query
|
|
@@ -139,9 +139,9 @@ module ActiveRecord
|
|
|
139
139
|
end
|
|
140
140
|
|
|
141
141
|
def find_options_for_find_tagged_with(tags, options = {})
|
|
142
|
-
|
|
142
|
+
tag_list = TagList.from(tags)
|
|
143
143
|
|
|
144
|
-
return {} if
|
|
144
|
+
return {} if tag_list.empty?
|
|
145
145
|
|
|
146
146
|
joins = []
|
|
147
147
|
conditions = []
|
|
@@ -150,11 +150,16 @@ module ActiveRecord
|
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
if options.delete(:exclude)
|
|
153
|
-
tags_conditions =
|
|
153
|
+
tags_conditions = tag_list.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
|
|
154
154
|
conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND (#{tags_conditions}) WHERE #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
|
|
155
155
|
|
|
156
|
+
elsif options.delete(:any)
|
|
157
|
+
tags_conditions = tag_list.map { |t| sanitize_sql(["#{Tag.table_name}.name LIKE ?", t]) }.join(" OR ")
|
|
158
|
+
conditions << "#{table_name}.#{primary_key} IN (SELECT #{Tagging.table_name}.taggable_id FROM #{Tagging.table_name} JOIN #{Tag.table_name} ON #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND (#{tags_conditions}) WHERE #{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"
|
|
159
|
+
|
|
156
160
|
else
|
|
157
|
-
tags = Tag.named_like_any(
|
|
161
|
+
tags = Tag.named_like_any(tag_list)
|
|
162
|
+
return { :conditions => "1 = 0" } unless tags.length == tag_list.length
|
|
158
163
|
|
|
159
164
|
tags.each do |tag|
|
|
160
165
|
safe_tag = tag.name.gsub(/[^a-zA-Z0-9]/, '')
|
|
@@ -184,7 +189,8 @@ module ActiveRecord
|
|
|
184
189
|
|
|
185
190
|
{ :joins => joins.join(" "),
|
|
186
191
|
:group => group,
|
|
187
|
-
:conditions => conditions.join(" AND ")
|
|
192
|
+
:conditions => conditions.join(" AND "),
|
|
193
|
+
:readonly => false }.update(options)
|
|
188
194
|
end
|
|
189
195
|
|
|
190
196
|
# Calculate the tag counts for all tags.
|
|
@@ -222,14 +228,32 @@ module ActiveRecord
|
|
|
222
228
|
|
|
223
229
|
joins = ["LEFT OUTER JOIN #{Tagging.table_name} ON #{Tag.table_name}.id = #{Tagging.table_name}.tag_id"]
|
|
224
230
|
joins << sanitize_sql(["AND #{Tagging.table_name}.context = ?",options.delete(:on).to_s]) unless options[:on].nil?
|
|
225
|
-
|
|
226
231
|
joins << " INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{Tagging.table_name}.taggable_id"
|
|
227
|
-
|
|
232
|
+
|
|
233
|
+
unless descends_from_active_record?
|
|
228
234
|
# Current model is STI descendant, so add type checking to the join condition
|
|
229
|
-
joins << " AND #{table_name}.#{
|
|
235
|
+
joins << " AND #{table_name}.#{inheritance_column} = '#{name}'"
|
|
230
236
|
end
|
|
231
237
|
|
|
232
|
-
|
|
238
|
+
# Based on a proposed patch by donV to ActiveRecord Base
|
|
239
|
+
# This is needed because merge_joins and construct_join are private in ActiveRecord Base
|
|
240
|
+
if scope && scope[:joins]
|
|
241
|
+
case scope[:joins]
|
|
242
|
+
when Array
|
|
243
|
+
scope_joins = scope[:joins].flatten
|
|
244
|
+
strings = scope_joins.select{|j| j.is_a? String}
|
|
245
|
+
joins << strings.join(' ') + " "
|
|
246
|
+
symbols = scope_joins - strings
|
|
247
|
+
join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, symbols, nil)
|
|
248
|
+
joins << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
|
|
249
|
+
joins.flatten!
|
|
250
|
+
when Symbol, Hash
|
|
251
|
+
join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, scope[:joins], nil)
|
|
252
|
+
joins << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
|
|
253
|
+
when String
|
|
254
|
+
joins << scope[:joins]
|
|
255
|
+
end
|
|
256
|
+
end
|
|
233
257
|
|
|
234
258
|
at_least = sanitize_sql(['COUNT(*) >= ?', options.delete(:at_least)]) if options[:at_least]
|
|
235
259
|
at_most = sanitize_sql(['COUNT(*) <= ?', options.delete(:at_most)]) if options[:at_most]
|
|
@@ -261,29 +285,40 @@ module ActiveRecord
|
|
|
261
285
|
def is_taggable?
|
|
262
286
|
self.class.is_taggable?
|
|
263
287
|
end
|
|
264
|
-
|
|
288
|
+
|
|
265
289
|
def add_custom_context(value)
|
|
266
290
|
custom_contexts << value.to_s unless custom_contexts.include?(value.to_s) or self.class.tag_types.map(&:to_s).include?(value.to_s)
|
|
267
291
|
end
|
|
268
292
|
|
|
269
|
-
def tag_list_on(context, owner=nil)
|
|
270
|
-
var_name = context.to_s.singularize + "_list"
|
|
293
|
+
def tag_list_on(context, owner = nil)
|
|
271
294
|
add_custom_context(context)
|
|
272
|
-
|
|
273
|
-
|
|
295
|
+
cache = tag_list_cache_on(context)
|
|
296
|
+
return owner ? cache[owner] : cache[owner] if cache[owner]
|
|
297
|
+
|
|
274
298
|
if !owner && self.class.caching_tag_list_on?(context) and !(cached_value = cached_tag_list_on(context)).nil?
|
|
275
|
-
|
|
299
|
+
cache[owner] = TagList.from(cached_tag_list_on(context))
|
|
276
300
|
else
|
|
277
|
-
|
|
301
|
+
cache[owner] = TagList.new(*tags_on(context, owner).map(&:name))
|
|
278
302
|
end
|
|
279
303
|
end
|
|
304
|
+
|
|
305
|
+
def all_tags_list_on(context)
|
|
306
|
+
variable_name = "@all_#{context.to_s.singularize}_list"
|
|
307
|
+
return instance_variable_get(variable_name) if instance_variable_get(variable_name)
|
|
308
|
+
instance_variable_set(variable_name, TagList.new(all_tags_on(context).map(&:name)).freeze)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def all_tags_on(context)
|
|
312
|
+
opts = {:conditions => ["#{Tagging.table_name}.context = ?", context.to_s]}
|
|
313
|
+
base_tags.find(:all, opts.merge(:order => "#{Tagging.table_name}.created_at"))
|
|
314
|
+
end
|
|
280
315
|
|
|
281
|
-
def tags_on(context, owner=nil)
|
|
316
|
+
def tags_on(context, owner = nil)
|
|
282
317
|
if owner
|
|
283
318
|
opts = {:conditions => ["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id = ? AND #{Tagging.table_name}.tagger_type = ?",
|
|
284
319
|
context.to_s, owner.id, owner.class.to_s]}
|
|
285
320
|
else
|
|
286
|
-
opts = {:conditions => ["#{Tagging.table_name}.context = ?", context.to_s]}
|
|
321
|
+
opts = {:conditions => ["#{Tagging.table_name}.context = ? AND #{Tagging.table_name}.tagger_id IS NULL", context.to_s]}
|
|
287
322
|
end
|
|
288
323
|
base_tags.find(:all, opts)
|
|
289
324
|
end
|
|
@@ -291,14 +326,21 @@ module ActiveRecord
|
|
|
291
326
|
def cached_tag_list_on(context)
|
|
292
327
|
self["cached_#{context.to_s.singularize}_list"]
|
|
293
328
|
end
|
|
329
|
+
|
|
330
|
+
def tag_list_cache_on(context)
|
|
331
|
+
variable_name = "@#{context.to_s.singularize}_list"
|
|
332
|
+
cache = instance_variable_get(variable_name)
|
|
333
|
+
instance_variable_set(variable_name, cache = {}) unless cache
|
|
334
|
+
cache
|
|
335
|
+
end
|
|
294
336
|
|
|
295
|
-
def set_tag_list_on(context,new_list, tagger=nil)
|
|
296
|
-
|
|
337
|
+
def set_tag_list_on(context, new_list, tagger = nil)
|
|
338
|
+
tag_list_cache_on(context)[tagger] = TagList.from(new_list)
|
|
297
339
|
add_custom_context(context)
|
|
298
340
|
end
|
|
299
341
|
|
|
300
342
|
def tag_counts_on(context, options={})
|
|
301
|
-
self.class.tag_counts_on(context, options.merge(:id =>
|
|
343
|
+
self.class.tag_counts_on(context, options.merge(:id => id))
|
|
302
344
|
end
|
|
303
345
|
|
|
304
346
|
def related_tags_for(context, klass, options = {})
|
|
@@ -308,9 +350,9 @@ module ActiveRecord
|
|
|
308
350
|
end
|
|
309
351
|
|
|
310
352
|
def related_search_options(context, klass, options = {})
|
|
311
|
-
tags_to_find =
|
|
353
|
+
tags_to_find = tags_on(context).collect { |t| t.name }
|
|
312
354
|
|
|
313
|
-
exclude_self = "#{klass.table_name}.id != #{
|
|
355
|
+
exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
|
|
314
356
|
|
|
315
357
|
{ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
|
|
316
358
|
:from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
|
|
@@ -327,9 +369,9 @@ module ActiveRecord
|
|
|
327
369
|
end
|
|
328
370
|
|
|
329
371
|
def matching_context_search_options(search_context, result_context, klass, options = {})
|
|
330
|
-
tags_to_find =
|
|
372
|
+
tags_to_find = tags_on(search_context).collect { |t| t.name }
|
|
331
373
|
|
|
332
|
-
exclude_self = "#{klass.table_name}.id != #{
|
|
374
|
+
exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
|
|
333
375
|
|
|
334
376
|
{ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
|
|
335
377
|
:from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
|
|
@@ -342,24 +384,24 @@ module ActiveRecord
|
|
|
342
384
|
def save_cached_tag_list
|
|
343
385
|
self.class.tag_types.map(&:to_s).each do |tag_type|
|
|
344
386
|
if self.class.send("caching_#{tag_type.singularize}_list?")
|
|
345
|
-
self["cached_#{tag_type.singularize}_list"] =
|
|
387
|
+
self["cached_#{tag_type.singularize}_list"] = tag_list_cache_on(tag_type.singularize).tags.join(', ')
|
|
346
388
|
end
|
|
347
389
|
end
|
|
348
390
|
end
|
|
349
391
|
|
|
350
392
|
def save_tags
|
|
351
393
|
(custom_contexts + self.class.tag_types.map(&:to_s)).each do |tag_type|
|
|
352
|
-
|
|
353
|
-
owner
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
394
|
+
tag_list_cache = tag_list_cache_on(tag_type)
|
|
395
|
+
for owner, tag_list in tag_list_cache
|
|
396
|
+
new_tag_names = tag_list - tags_on(tag_type, owner).map(&:name)
|
|
397
|
+
old_tags = tags_on(tag_type, owner).reject { |tag| tag_list.include?(tag.name) }
|
|
398
|
+
transaction do
|
|
399
|
+
base_tags.delete(*old_tags) if old_tags.any?
|
|
400
|
+
new_tag_names.each do |new_tag_name|
|
|
401
|
+
new_tag = Tag.find_or_create_with_like_by_name(new_tag_name)
|
|
402
|
+
Tagging.create(:tag_id => new_tag.id, :context => tag_type,
|
|
403
|
+
:taggable => self, :tagger => owner)
|
|
404
|
+
end
|
|
363
405
|
end
|
|
364
406
|
end
|
|
365
407
|
end
|
|
@@ -369,7 +411,7 @@ module ActiveRecord
|
|
|
369
411
|
|
|
370
412
|
def reload_with_tag_list(*args)
|
|
371
413
|
self.class.tag_types.each do |tag_type|
|
|
372
|
-
|
|
414
|
+
instance_variable_set("@#{tag_type.to_s.singularize}_list", nil)
|
|
373
415
|
end
|
|
374
416
|
|
|
375
417
|
reload_without_tag_list(*args)
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
class Tag < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
attr_accessible :name
|
|
4
|
+
|
|
5
|
+
### ASSOCIATIONS:
|
|
6
|
+
|
|
2
7
|
has_many :taggings, :dependent => :destroy
|
|
3
8
|
|
|
9
|
+
### VALIDATIONS:
|
|
10
|
+
|
|
4
11
|
validates_presence_of :name
|
|
5
12
|
validates_uniqueness_of :name
|
|
6
13
|
|
|
14
|
+
### NAMED SCOPES:
|
|
15
|
+
|
|
7
16
|
named_scope :named, lambda { |name| { :conditions => ["name = ?", name] } }
|
|
8
17
|
named_scope :named_like, lambda { |name| { :conditions => ["name LIKE ?", "%#{name}%"] } }
|
|
9
18
|
named_scope :named_like_any, lambda { |list| { :conditions => list.map { |tag| sanitize_sql(["name LIKE ?", tag.to_s]) }.join(" OR ") } }
|
|
10
19
|
|
|
20
|
+
### METHODS:
|
|
21
|
+
|
|
11
22
|
# LIKE is used for cross-database case-insensitivity
|
|
12
23
|
def self.find_or_create_with_like_by_name(name)
|
|
13
24
|
find(:first, :conditions => ["name LIKE ?", name]) || create(:name => name)
|
|
@@ -41,9 +41,10 @@ class TagList < Array
|
|
|
41
41
|
# tag_list = TagList.new("Round", "Square,Cube")
|
|
42
42
|
# tag_list.to_s # 'Round, "Square,Cube"'
|
|
43
43
|
def to_s
|
|
44
|
-
|
|
44
|
+
tags = frozen? ? self.dup : self
|
|
45
|
+
tags.send(:clean!)
|
|
45
46
|
|
|
46
|
-
map do |name|
|
|
47
|
+
tags.map do |name|
|
|
47
48
|
name.include?(delimiter) ? "\"#{name}\"" : name
|
|
48
49
|
end.join(delimiter.ends_with?(" ") ? delimiter : "#{delimiter} ")
|
|
49
50
|
end
|
|
@@ -55,7 +56,7 @@ class TagList < Array
|
|
|
55
56
|
map!(&:strip)
|
|
56
57
|
uniq!
|
|
57
58
|
end
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
def extract_and_apply_options!(args)
|
|
60
61
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
61
62
|
options.assert_valid_keys :parse
|
|
@@ -79,17 +80,11 @@ class TagList < Array
|
|
|
79
80
|
string = string.to_s.dup
|
|
80
81
|
|
|
81
82
|
# Parse the quoted tags
|
|
82
|
-
string.gsub!(/"(.*?)"\s
|
|
83
|
-
string.gsub!(/'(.*?)'\s
|
|
83
|
+
string.gsub!(/(\A|#{delimiter})\s*"(.*?)"\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
|
|
84
|
+
string.gsub!(/(\A|#{delimiter})\s*'(.*?)'\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
|
|
84
85
|
|
|
85
86
|
tag_list.add(string.split(delimiter))
|
|
86
87
|
end
|
|
87
88
|
end
|
|
88
|
-
|
|
89
|
-
def from_owner(owner, *tags)
|
|
90
|
-
returning from(*tags) do |taglist|
|
|
91
|
-
taglist.owner = owner
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
89
|
end
|
|
95
90
|
end
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
class Tagging < ActiveRecord::Base #:nodoc:
|
|
2
|
+
attr_accessible :tag, :tag_id, :context,
|
|
3
|
+
:taggable, :taggable_type, :taggable_id,
|
|
4
|
+
:tagger, :tagger_type, :tagger_id
|
|
5
|
+
|
|
2
6
|
belongs_to :tag
|
|
3
7
|
belongs_to :taggable, :polymorphic => true
|
|
4
8
|
belongs_to :tagger, :polymorphic => true
|
|
5
9
|
|
|
6
10
|
validates_presence_of :context
|
|
7
11
|
validates_presence_of :tag_id
|
|
12
|
+
|
|
13
|
+
validates_uniqueness_of :tag_id, :scope => [:taggable_type, :taggable_id, :context, :tagger_id, :tagger_type]
|
|
8
14
|
end
|
data/rails/init.rb
CHANGED
|
@@ -2,6 +2,4 @@ require 'acts-as-taggable-on'
|
|
|
2
2
|
|
|
3
3
|
ActiveRecord::Base.send :include, ActiveRecord::Acts::TaggableOn
|
|
4
4
|
ActiveRecord::Base.send :include, ActiveRecord::Acts::Tagger
|
|
5
|
-
ActionView::Base.send :include, TagsHelper if defined?(ActionView::Base)
|
|
6
|
-
|
|
7
|
-
RAILS_DEFAULT_LOGGER.info "** acts_as_taggable_on: initialized properly."
|
|
5
|
+
ActionView::Base.send :include, TagsHelper if defined?(ActionView::Base)
|
|
@@ -176,16 +176,6 @@ describe "Acts As Taggable On" do
|
|
|
176
176
|
end
|
|
177
177
|
|
|
178
178
|
describe 'Tagging Contexts' do
|
|
179
|
-
before(:all) do
|
|
180
|
-
class Array
|
|
181
|
-
def freq
|
|
182
|
-
k=Hash.new(0)
|
|
183
|
-
self.each {|e| k[e]+=1}
|
|
184
|
-
k
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
179
|
it 'should eliminate duplicate tagging contexts ' do
|
|
190
180
|
TaggableModel.acts_as_taggable_on(:skills, :skills)
|
|
191
181
|
TaggableModel.tag_types.freq[:skills].should_not == 3
|
|
@@ -212,10 +202,6 @@ describe "Acts As Taggable On" do
|
|
|
212
202
|
TaggableModel.acts_as_taggable_on([nil])
|
|
213
203
|
}.should_not raise_error
|
|
214
204
|
end
|
|
215
|
-
|
|
216
|
-
after(:all) do
|
|
217
|
-
class Array; remove_method :freq; end
|
|
218
|
-
end
|
|
219
205
|
end
|
|
220
206
|
|
|
221
207
|
end
|
|
@@ -48,8 +48,22 @@ describe "acts_as_tagger" do
|
|
|
48
48
|
|
|
49
49
|
it 'should by default create the tag context on-the-fly' do
|
|
50
50
|
@taggable.tag_list_on(:here_ond_now).should be_empty
|
|
51
|
-
@tagger.tag(@taggable, :with=>'that', :on
|
|
52
|
-
@taggable.tag_list_on(:here_ond_now).
|
|
51
|
+
@tagger.tag(@taggable, :with=>'that', :on => :here_ond_now)
|
|
52
|
+
@taggable.tag_list_on(:here_ond_now).should_not include('that')
|
|
53
|
+
@taggable.all_tags_list_on(:here_ond_now).should include('that')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "should show all the tag list when both public and owned tags exist" do
|
|
57
|
+
@taggable.tag_list = 'ruby, python'
|
|
58
|
+
@tagger.tag(@taggable, :with => 'java, lisp', :on => :tags)
|
|
59
|
+
@taggable.all_tags_on(:tags).map(&:name).sort.should == %w(ruby python java lisp).sort
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should not add owned tags to the common list" do
|
|
63
|
+
@taggable.tag_list = 'ruby, python'
|
|
64
|
+
@tagger.tag(@taggable, :with => 'java, lisp', :on => :foo)
|
|
65
|
+
@tagger.tag(@taggable, :with => '', :on => :foo)
|
|
66
|
+
@taggable.tag_list.should == %w(ruby python)
|
|
53
67
|
end
|
|
54
68
|
|
|
55
69
|
it "should throw an exception when the default is over-ridden" do
|
|
@@ -20,6 +20,18 @@ describe TagList do
|
|
|
20
20
|
@tag_list.include?("wicked").should be_true
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
it "should be able to add delimited list of words with quoted delimiters" do
|
|
24
|
+
@tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
|
|
25
|
+
@tag_list.include?("cool, wicked").should be_true
|
|
26
|
+
@tag_list.include?("really cool, really wicked").should be_true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should be able to handle other uses of quotation marks correctly" do
|
|
30
|
+
@tag_list.add("john's cool car, mary's wicked toy", :parse => true)
|
|
31
|
+
@tag_list.include?("john's cool car").should be_true
|
|
32
|
+
@tag_list.include?("mary's wicked toy").should be_true
|
|
33
|
+
end
|
|
34
|
+
|
|
23
35
|
it "should be able to add an array of words" do
|
|
24
36
|
@tag_list.add(["cool", "wicked"], :parse => true)
|
|
25
37
|
@tag_list.include?("cool").should be_true
|
|
@@ -49,4 +61,10 @@ describe TagList do
|
|
|
49
61
|
@tag_list.add("cool","rad,bodacious")
|
|
50
62
|
@tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
|
|
51
63
|
end
|
|
64
|
+
|
|
65
|
+
it "should be able to call to_s on a frozen tag list" do
|
|
66
|
+
@tag_list.freeze
|
|
67
|
+
lambda { @tag_list.add("cool","rad,bodacious") }.should raise_error
|
|
68
|
+
lambda { @tag_list.to_s }.should_not raise_error
|
|
69
|
+
end
|
|
52
70
|
end
|
|
@@ -7,35 +7,40 @@ describe "Taggable" do
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
it "should have tag types" do
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
for type in [:tags, :languages, :skills, :needs, :offerings]
|
|
11
|
+
TaggableModel.tag_types.should include type
|
|
12
|
+
end
|
|
13
|
+
@taggable.tag_types.should == TaggableModel.tag_types
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
it "should have tag_counts_on" do
|
|
15
17
|
TaggableModel.tag_counts_on(:tags).should be_empty
|
|
16
|
-
|
|
18
|
+
|
|
17
19
|
@taggable.tag_list = ["awesome", "epic"]
|
|
18
20
|
@taggable.save
|
|
19
21
|
|
|
20
22
|
TaggableModel.tag_counts_on(:tags).count.should == 2
|
|
21
23
|
@taggable.tag_counts_on(:tags).count.should == 2
|
|
22
24
|
end
|
|
23
|
-
|
|
25
|
+
|
|
24
26
|
it "should be able to create tags" do
|
|
25
27
|
@taggable.skill_list = "ruby, rails, css"
|
|
26
|
-
@taggable.instance_variable_get("@skill_list").instance_of?(
|
|
28
|
+
@taggable.instance_variable_get("@skill_list").instance_of?(Hash).should be_true
|
|
29
|
+
@taggable.instance_variable_get("@skill_list")[nil].instance_of?(TagList).should be_true
|
|
27
30
|
@taggable.save
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
Tag.find(:all).size.should == 3
|
|
30
33
|
end
|
|
31
|
-
|
|
34
|
+
|
|
32
35
|
it "should be able to create tags through the tag list directly" do
|
|
33
36
|
@taggable.tag_list_on(:test).add("hello")
|
|
34
|
-
@taggable.
|
|
37
|
+
@taggable.tag_list_cache_on(:test).should_not be_empty
|
|
38
|
+
@taggable.save
|
|
39
|
+
@taggable.save_tags
|
|
35
40
|
@taggable.reload
|
|
36
41
|
@taggable.tag_list_on(:test).should == ["hello"]
|
|
37
42
|
end
|
|
38
|
-
|
|
43
|
+
|
|
39
44
|
it "should differentiate between contexts" do
|
|
40
45
|
@taggable.skill_list = "ruby, rails, css"
|
|
41
46
|
@taggable.tag_list = "ruby, bob, charlie"
|
|
@@ -44,7 +49,7 @@ describe "Taggable" do
|
|
|
44
49
|
@taggable.skill_list.include?("ruby").should be_true
|
|
45
50
|
@taggable.skill_list.include?("bob").should be_false
|
|
46
51
|
end
|
|
47
|
-
|
|
52
|
+
|
|
48
53
|
it "should be able to remove tags through list alone" do
|
|
49
54
|
@taggable.skill_list = "ruby, rails, css"
|
|
50
55
|
@taggable.save
|
|
@@ -55,13 +60,13 @@ describe "Taggable" do
|
|
|
55
60
|
@taggable.reload
|
|
56
61
|
@taggable.should have(2).skills
|
|
57
62
|
end
|
|
58
|
-
|
|
63
|
+
|
|
59
64
|
it "should be able to find by tag" do
|
|
60
65
|
@taggable.skill_list = "ruby, rails, css"
|
|
61
66
|
@taggable.save
|
|
62
67
|
TaggableModel.find_tagged_with("ruby").first.should == @taggable
|
|
63
68
|
end
|
|
64
|
-
|
|
69
|
+
|
|
65
70
|
it "should be able to find by tag with context" do
|
|
66
71
|
@taggable.skill_list = "ruby, rails, css"
|
|
67
72
|
@taggable.tag_list = "bob, charlie"
|
|
@@ -70,25 +75,27 @@ describe "Taggable" do
|
|
|
70
75
|
TaggableModel.find_tagged_with("bob", :on => :skills).first.should_not == @taggable
|
|
71
76
|
TaggableModel.find_tagged_with("bob", :on => :tags).first.should == @taggable
|
|
72
77
|
end
|
|
73
|
-
|
|
78
|
+
|
|
74
79
|
it "should be able to use the tagged_with named scope" do
|
|
75
80
|
@taggable.skill_list = "ruby, rails, css"
|
|
76
81
|
@taggable.tag_list = "bob, charlie"
|
|
77
82
|
@taggable.save
|
|
78
|
-
|
|
83
|
+
|
|
79
84
|
TaggableModel.tagged_with("ruby").first.should == @taggable
|
|
85
|
+
TaggableModel.tagged_with("ruby, css").first.should == @taggable
|
|
86
|
+
TaggableModel.tagged_with("ruby, nonexistingtag").should be_empty
|
|
80
87
|
TaggableModel.tagged_with("bob", :on => :skills).first.should_not == @taggable
|
|
81
88
|
TaggableModel.tagged_with("bob", :on => :tags).first.should == @taggable
|
|
82
89
|
end
|
|
83
|
-
|
|
90
|
+
|
|
84
91
|
it "should not care about case" do
|
|
85
92
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby")
|
|
86
93
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "Ruby")
|
|
87
|
-
|
|
94
|
+
|
|
88
95
|
Tag.find(:all).size.should == 1
|
|
89
96
|
TaggableModel.find_tagged_with("ruby").should == TaggableModel.find_tagged_with("Ruby")
|
|
90
97
|
end
|
|
91
|
-
|
|
98
|
+
|
|
92
99
|
it "should be able to get tag counts on model as a whole" do
|
|
93
100
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
|
94
101
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
|
@@ -96,33 +103,39 @@ describe "Taggable" do
|
|
|
96
103
|
TaggableModel.tag_counts.should_not be_empty
|
|
97
104
|
TaggableModel.skill_counts.should_not be_empty
|
|
98
105
|
end
|
|
99
|
-
|
|
106
|
+
|
|
100
107
|
it "should be able to get all tag counts on model as whole" do
|
|
101
108
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
|
102
109
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
|
103
110
|
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
|
104
|
-
|
|
111
|
+
|
|
105
112
|
TaggableModel.all_tag_counts.should_not be_empty
|
|
106
113
|
TaggableModel.all_tag_counts.first.count.should == 3 # ruby
|
|
107
114
|
end
|
|
108
|
-
|
|
115
|
+
|
|
116
|
+
it "should not return read-only records" do
|
|
117
|
+
TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
|
118
|
+
|
|
119
|
+
TaggableModel.tagged_with("ruby").first.should_not be_readonly
|
|
120
|
+
end
|
|
121
|
+
|
|
109
122
|
it "should be able to get scoped tag counts" do
|
|
110
123
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
|
111
124
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
|
112
125
|
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
|
113
|
-
|
|
126
|
+
|
|
114
127
|
TaggableModel.tagged_with("ruby").tag_counts.first.count.should == 2 # ruby
|
|
115
128
|
TaggableModel.tagged_with("ruby").skill_counts.first.count.should == 1 # ruby
|
|
116
129
|
end
|
|
117
|
-
|
|
130
|
+
|
|
118
131
|
it "should be able to get all scoped tag counts" do
|
|
119
132
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
|
120
133
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
|
121
134
|
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
|
122
|
-
|
|
135
|
+
|
|
123
136
|
TaggableModel.tagged_with("ruby").all_tag_counts.first.count.should == 3 # ruby
|
|
124
137
|
end
|
|
125
|
-
|
|
138
|
+
|
|
126
139
|
it "should be able to set a custom tag context list" do
|
|
127
140
|
bob = TaggableModel.create(:name => "Bob")
|
|
128
141
|
bob.set_tag_list_on(:rotors, "spinning, jumping")
|
|
@@ -131,17 +144,27 @@ describe "Taggable" do
|
|
|
131
144
|
bob.reload
|
|
132
145
|
bob.tags_on(:rotors).should_not be_empty
|
|
133
146
|
end
|
|
134
|
-
|
|
147
|
+
|
|
135
148
|
it "should be able to find tagged" do
|
|
136
149
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
|
|
137
150
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
|
|
138
151
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
|
|
139
|
-
|
|
152
|
+
|
|
140
153
|
TaggableModel.find_tagged_with("ruby", :order => 'taggable_models.name').should == [bob, frank, steve]
|
|
141
154
|
TaggableModel.find_tagged_with("ruby, rails", :order => 'taggable_models.name').should == [bob, frank]
|
|
142
155
|
TaggableModel.find_tagged_with(["ruby", "rails"], :order => 'taggable_models.name').should == [bob, frank]
|
|
143
156
|
end
|
|
144
|
-
|
|
157
|
+
|
|
158
|
+
it "should be able to find tagged with any tag" do
|
|
159
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
|
|
160
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
|
|
161
|
+
steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
|
|
162
|
+
|
|
163
|
+
TaggableModel.find_tagged_with(["ruby", "java"], :order => 'taggable_models.name', :any => true).should == [bob, frank, steve]
|
|
164
|
+
TaggableModel.find_tagged_with(["c++", "fitter"], :order => 'taggable_models.name', :any => true).should == [bob, steve]
|
|
165
|
+
TaggableModel.find_tagged_with(["depressed", "css"], :order => 'taggable_models.name', :any => true).should == [bob, frank]
|
|
166
|
+
end
|
|
167
|
+
|
|
145
168
|
it "should be able to find tagged on a custom tag context" do
|
|
146
169
|
bob = TaggableModel.create(:name => "Bob")
|
|
147
170
|
bob.set_tag_list_on(:rotors, "spinning, jumping")
|
|
@@ -154,29 +177,38 @@ describe "Taggable" do
|
|
|
154
177
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
|
|
155
178
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
|
|
156
179
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, python')
|
|
157
|
-
|
|
180
|
+
|
|
158
181
|
# Let's only find those productive Rails developers
|
|
159
182
|
TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').should == [bob, frank]
|
|
160
183
|
TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').should == [bob, steve]
|
|
161
184
|
TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).should == [bob]
|
|
162
185
|
TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).should == [bob]
|
|
163
186
|
end
|
|
164
|
-
|
|
187
|
+
|
|
165
188
|
it "should be able to find tagged with only the matching tags" do
|
|
166
189
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "lazy, happier")
|
|
167
190
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "fitter, happier, inefficient")
|
|
168
191
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => "fitter, happier")
|
|
169
|
-
|
|
192
|
+
|
|
170
193
|
TaggableModel.find_tagged_with("fitter, happier", :match_all => true).should == [steve]
|
|
171
194
|
end
|
|
172
|
-
|
|
195
|
+
|
|
173
196
|
it "should be able to find tagged with some excluded tags" do
|
|
174
197
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "happier, lazy")
|
|
175
198
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "happier")
|
|
176
199
|
steve = TaggableModel.create(:name => 'Steve', :tag_list => "happier")
|
|
177
|
-
|
|
200
|
+
|
|
178
201
|
TaggableModel.find_tagged_with("lazy", :exclude => true).should == [frank, steve]
|
|
179
202
|
end
|
|
203
|
+
|
|
204
|
+
it "should not create duplicate taggings" do
|
|
205
|
+
bob = TaggableModel.create(:name => "Bob")
|
|
206
|
+
lambda {
|
|
207
|
+
bob.tag_list << "happier"
|
|
208
|
+
bob.tag_list << "happier"
|
|
209
|
+
bob.save
|
|
210
|
+
}.should change(Tagging, :count).by(1)
|
|
211
|
+
end
|
|
180
212
|
|
|
181
213
|
describe "Single Table Inheritance" do
|
|
182
214
|
before do
|
|
@@ -185,32 +217,32 @@ describe "Taggable" do
|
|
|
185
217
|
@inherited_same = InheritingTaggableModel.new(:name => "inherited same")
|
|
186
218
|
@inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
|
|
187
219
|
end
|
|
188
|
-
|
|
220
|
+
|
|
189
221
|
it "should be able to save tags for inherited models" do
|
|
190
222
|
@inherited_same.tag_list = "bob, kelso"
|
|
191
223
|
@inherited_same.save
|
|
192
224
|
InheritingTaggableModel.find_tagged_with("bob").first.should == @inherited_same
|
|
193
225
|
end
|
|
194
|
-
|
|
226
|
+
|
|
195
227
|
it "should find STI tagged models on the superclass" do
|
|
196
228
|
@inherited_same.tag_list = "bob, kelso"
|
|
197
229
|
@inherited_same.save
|
|
198
230
|
TaggableModel.find_tagged_with("bob").first.should == @inherited_same
|
|
199
231
|
end
|
|
200
|
-
|
|
232
|
+
|
|
201
233
|
it "should be able to add on contexts only to some subclasses" do
|
|
202
234
|
@inherited_different.part_list = "fork, spoon"
|
|
203
235
|
@inherited_different.save
|
|
204
236
|
InheritingTaggableModel.find_tagged_with("fork", :on => :parts).should be_empty
|
|
205
237
|
AlteredInheritingTaggableModel.find_tagged_with("fork", :on => :parts).first.should == @inherited_different
|
|
206
238
|
end
|
|
207
|
-
|
|
239
|
+
|
|
208
240
|
it "should have different tag_counts_on for inherited models" do
|
|
209
241
|
@inherited_same.tag_list = "bob, kelso"
|
|
210
242
|
@inherited_same.save!
|
|
211
243
|
@inherited_different.tag_list = "fork, spoon"
|
|
212
244
|
@inherited_different.save!
|
|
213
|
-
|
|
245
|
+
|
|
214
246
|
InheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso)
|
|
215
247
|
AlteredInheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(fork spoon)
|
|
216
248
|
TaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso fork spoon)
|
|
@@ -6,17 +6,32 @@ describe "Tagger" do
|
|
|
6
6
|
@user = TaggableUser.new
|
|
7
7
|
@taggable = TaggableModel.new(:name => "Bob Jones")
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
it "should have taggings" do
|
|
11
11
|
@user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
|
|
12
12
|
@user.owned_taggings.size == 2
|
|
13
13
|
end
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
it "should have tags" do
|
|
16
16
|
@user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
|
|
17
17
|
@user.owned_tags.size == 2
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
it "should not overlap or lose tags from different users" do
|
|
21
|
+
@user2 = TaggableUser.new
|
|
22
|
+
lambda{
|
|
23
|
+
@user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
|
|
24
|
+
@user2.tag(@taggable, :with => 'java, python, lisp, ruby', :on => :tags)
|
|
25
|
+
}.should change(Tagging, :count).by(6)
|
|
26
|
+
|
|
27
|
+
@user.owned_tags.map(&:name).should == %w(ruby scheme)
|
|
28
|
+
@user2.owned_tags.map(&:name).sort.should == %w(java python lisp ruby).sort
|
|
29
|
+
@taggable.tags_from(@user).should == %w(ruby scheme)
|
|
30
|
+
@taggable.tags_from(@user2).should == %w(java python lisp ruby)
|
|
31
|
+
@taggable.all_tags_list_on(:tags).sort.should == %w(ruby scheme java python lisp).sort
|
|
32
|
+
@taggable.all_tags_on(:tags).size.should == 6
|
|
33
|
+
end
|
|
34
|
+
|
|
20
35
|
it "is tagger" do
|
|
21
36
|
@user.is_tagger?.should(be_true)
|
|
22
37
|
end
|
|
@@ -13,4 +13,13 @@ describe Tagging do
|
|
|
13
13
|
@tagging.should_not be_valid
|
|
14
14
|
@tagging.errors.on(:tag_id).should == "can't be blank"
|
|
15
15
|
end
|
|
16
|
+
|
|
17
|
+
it "should not create duplicate taggings" do
|
|
18
|
+
@taggable = TaggableModel.create(:name => "Bob Jones")
|
|
19
|
+
@tag = Tag.create(:name => "awesome")
|
|
20
|
+
|
|
21
|
+
lambda {
|
|
22
|
+
2.times { Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags') }
|
|
23
|
+
}.should change(Tagging, :count).by(1)
|
|
24
|
+
end
|
|
16
25
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
|
|
2
2
|
require 'rubygems'
|
|
3
|
-
require '
|
|
3
|
+
require 'active_record'
|
|
4
4
|
require 'spec'
|
|
5
5
|
|
|
6
6
|
module Spec::Example::ExampleGroupMethods
|
|
7
7
|
alias :context :describe
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
class Array
|
|
11
|
+
def freq
|
|
12
|
+
k=Hash.new(0)
|
|
13
|
+
each {|e| k[e]+=1}
|
|
14
|
+
k
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
10
18
|
TEST_DATABASE_FILE = File.join(File.dirname(__FILE__), '..', 'test.sqlite3')
|
|
11
19
|
|
|
12
20
|
File.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)
|
|
@@ -16,7 +24,10 @@ ActiveRecord::Base.establish_connection(
|
|
|
16
24
|
|
|
17
25
|
RAILS_DEFAULT_LOGGER = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
ActiveRecord::Base.silence do
|
|
28
|
+
ActiveRecord::Migration.verbose = false
|
|
29
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
|
30
|
+
end
|
|
20
31
|
|
|
21
32
|
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
|
22
33
|
require File.join(File.dirname(__FILE__), '..', 'init')
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: acts-as-taggable-on
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Bleigh
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date:
|
|
12
|
+
date: 2010-02-03 00:00:00 +01:00
|
|
13
13
|
default_executable:
|
|
14
14
|
dependencies: []
|
|
15
15
|
|