tagtical 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.1
1
+ 1.1.2
data/lib/tagtical/tag.rb CHANGED
@@ -227,25 +227,24 @@ module Tagtical
227
227
  # <tt>only</tt> - An array of the following: :parents, :current, :children. Will construct conditions to query the current, parent, and/or children STI classes.
228
228
  #
229
229
  def finder_type_condition(*args)
230
- options = convert_finder_type_arguments(*args)
231
- type = convert_type_options(options[:scope])
230
+ scopes, options = convert_finder_type_arguments(*args)
232
231
 
233
232
  # If we want [:current, :children] or [:current, :children, :parents] and we don't need the finder type condition,
234
233
  # then that means we don't need a condition at all since we are at the top-level sti class and we are essentially
235
234
  # searching the whole range of sti classes.
236
235
  if klass && !klass.finder_needs_type_condition?
237
- type.delete(:parents) # we are at the topmost level.
238
- type = [] if type==[:current, :children] # no condition is required if we want the current AND the children.
236
+ scopes.delete(:parents) # we are at the topmost level.
237
+ scopes = [] if scopes.sort==[:current, :children].sort # no condition is required if we want the current AND the children.
239
238
  end
240
239
 
241
240
  sti_names = []
242
- if type.include?(:current)
241
+ if scopes.include?(:current)
243
242
  sti_names << klass.sti_name
244
243
  end
245
- if type.include?(:children) && klass
244
+ if scopes.include?(:children) && klass
246
245
  sti_names.concat(klass.descendants.map(&:sti_name))
247
246
  end
248
- if type.include?(:parents) && klass # include searches up the STI chain
247
+ if scopes.include?(:parents) && klass # include searches up the STI chain
249
248
  parent_class = klass.superclass
250
249
  while parent_class <= Tagtical::Tag
251
250
  sti_names << parent_class.sti_name
@@ -340,8 +339,8 @@ module Tagtical
340
339
  end
341
340
 
342
341
  # Take operator types (ie <, >, =) and convert them into :children, :current, or :parents.
343
- def convert_type_options(input)
344
- Array.wrap(input || (klass ? [:current, :children] : :current)).map do |type, i|
342
+ def convert_scope_options(input)
343
+ Array.wrap(input || [:current, :children]).map do |type|
345
344
  if (t = type.to_s)=~/^[=><]+$/
346
345
  {"=" => :current, ">" => :parents, "<" => :children}.map do |operator, val|
347
346
  val if t.include?(operator)
@@ -372,8 +371,8 @@ module Tagtical
372
371
 
373
372
  def convert_finder_type_arguments(*args)
374
373
  options = args.extract_options!
375
- options[:scope] = args[0] if args[0] # allow for adding this in the front
376
- options
374
+ scopes = convert_scope_options(args.presence || options[:scope])
375
+ [scopes, options]
377
376
  end
378
377
 
379
378
  end
@@ -49,6 +49,11 @@ module Tagtical
49
49
  end
50
50
  alias << push
51
51
 
52
+ # Shorthand
53
+ def find(value)
54
+ detect { |t| t==value }
55
+ end
56
+
52
57
  ##
53
58
  # Add tags to the tag_list. Duplicate or blank tags will be ignored.
54
59
  # Use the <tt>:parse</tt> option to add an unparsed tag string.
@@ -120,26 +125,35 @@ module Tagtical
120
125
  args.flatten!
121
126
  end
122
127
 
128
+ # Returns an array by parsing the input.
123
129
  def extract(input, options={})
124
130
  case input
131
+ when Tagtical::Tag
132
+ TagValue.new(input.value, input.relevance)
125
133
  when String
126
- if !input.include?(delimiter) || options[:parse]==false
127
- [input]
128
- else
129
- input, arr = input.dup, []
130
-
131
- # Parse the quoted tags
132
- value_quotes.each do |value_quote|
133
- input.gsub!(/(\A|#{delimiter})\s*#{value_quote}(.*?)#{value_quote}\s*(#{delimiter}\s*|\z)/) { arr << $2 ; $3 }
134
+ [].tap do |arr|
135
+ if !input.include?(delimiter) || options[:parse]==false
136
+ arr << input
137
+ else
138
+ input = input.dup
139
+
140
+ # Parse the quoted tags
141
+ value_quotes.each do |value_quote|
142
+ input.gsub!(/(\A|#{delimiter})\s*#{value_quote}(.*?)#{value_quote}\s*(#{delimiter}\s*|\z)/) { arr << $2 ; $3 }
143
+ end
144
+
145
+ # Parse the unquoted tags
146
+ input.split(delimiter).each { |word| arr << word.strip }
134
147
  end
135
-
136
- # Parse the unquoted tags
137
- arr.concat(input.split(delimiter).each(&:strip!))
138
148
  end
139
149
  when Hash
140
150
  input.map { |value, relevance| TagValue.new(value, relevance) }
141
151
  when Array
142
- input
152
+ input.map { |value| extract(value) }
153
+ when Symbol # put at the end, rare case
154
+ extract(input.to_s)
155
+ else
156
+ raise("Cannot parse: #{input.inspect}")
143
157
  end
144
158
  end
145
159
 
@@ -39,8 +39,8 @@ module Tagtical::Taggable
39
39
  def save_cached_tag_list
40
40
  tag_types.each do |tag_type|
41
41
  if self.class.send("caching_#{tag_type.singularize}_list?")
42
- if tag_list = tag_list_cache_on(tag_type)[{}]
43
- self[tag_type.tag_list_name(:cached)] = tag_list.to_a.flatten.compact.join(', ')
42
+ if tag_list = tag_list_cache_on(tag_type)[[:children, :current]]
43
+ self[tag_type.tag_list_name(:cached)] = tag_list.to_s
44
44
  end
45
45
  end
46
46
  end
@@ -83,7 +83,7 @@ module Tagtical::Taggable
83
83
  end
84
84
 
85
85
  def find_tag_type!(input)
86
- tag_types.find { |t| t.match?(input) } || raise("Cannot find tag type:'#{input}' in #{tag_types.inspect}")
86
+ (@tag_type ||= {})[input] ||= tag_types.find { |t| t.match?(input) } || raise("Cannot find tag type:'#{input}' in #{tag_types.inspect}")
87
87
  end
88
88
 
89
89
  ##
@@ -206,11 +206,11 @@ module Tagtical::Taggable
206
206
  def set_tag_list_on(context, new_list, *args)
207
207
  tag_list = Tagtical::TagList.from(new_list)
208
208
  cascade_set_tag_list!(tag_list, context, *args)
209
- tag_list_cache_on(context)[scoping_options(context, *args)] = tag_list
209
+ tag_list_cache_on(context)[scopes_for_tag_list(context, *args)] = tag_list
210
210
  end
211
211
 
212
212
  def tag_list_on(context, *args)
213
- tag_list_cache_on(context)[scoping_options(context, *args)] ||= Tagtical::TagList.new(tags_on(context, *args).map(&:value))
213
+ tag_list_cache_on(context)[scopes_for_tag_list(context, *args)] ||= Tagtical::TagList.new(tags_on(context, *args))
214
214
  end
215
215
 
216
216
  def tag_list_cache_on(context, prefix=nil)
@@ -219,7 +219,7 @@ module Tagtical::Taggable
219
219
  end
220
220
 
221
221
  def all_tags_list_on(context, *args)
222
- tag_list_cache_on(context, :all)[scoping_options(context, *args)] ||= Tagtical::TagList.new(all_tags_on(context, *args).map(&:value)).freeze
222
+ tag_list_cache_on(context, :all)[scopes_for_tag_list(context, *args)] ||= Tagtical::TagList.new(all_tags_on(context, *args)).freeze
223
223
  end
224
224
 
225
225
  ##
@@ -254,17 +254,16 @@ module Tagtical::Taggable
254
254
  # Do the classes from top to bottom. We want the list from "tag" to run before "sub_tag" runs.
255
255
  # Otherwise, we will end up removing taggings from "sub_tag" since they aren't on "tag'.
256
256
  tag_types.sort_by(&:active_record_sti_level).each do |tag_type|
257
- (tag_list_cache_on(tag_type) || {}).each do |scoping_options, tag_list|
257
+ (tag_list_cache_on(tag_type) || {}).each do |scopes, tag_list|
258
+ # Tag list saving only runs if its affecting the current scope or the current and children scope
259
+ next unless [:<=, :==].any? { |scope| scopes_for_tag_list(tag_type, scope)==scopes }
258
260
  tag_list = tag_list.uniq
259
261
 
260
262
  # Find existing tags or create non-existing tags:
261
263
  tag_value_lookup = tag_type.scoping { find_or_create_tags(tag_list) }
262
264
  tags = tag_value_lookup.keys
263
265
 
264
- options = {:scope => [:current, :children]}.update(scoping_options)
265
- options[:scope] = Array(options[:scope]) + [:parents] # add in the parents because we need them later on down.
266
-
267
- current_tags = tags_on(tag_type, options)
266
+ current_tags = tags_on(tag_type, *[:parents].concat(scopes)) # add in the parents because we need them later on down.
268
267
  old_tags = current_tags - tags
269
268
  new_tags = tags - current_tags
270
269
 
@@ -291,6 +290,9 @@ module Tagtical::Taggable
291
290
  taggings.create!(:tag_id => tag.id, :taggable => self, :relevance => tag_value_lookup[tag].relevance) # Create new taggings:
292
291
  end
293
292
  end
293
+
294
+ # Force tag lists to reload to integrate any new tags from inheritance.
295
+ remove_tag_caches_on(tag_type)
294
296
  end
295
297
 
296
298
  true
@@ -298,18 +300,29 @@ module Tagtical::Taggable
298
300
 
299
301
  private
300
302
 
303
+ def remove_tag_caches_on(tag_type)
304
+ [nil, :all].each do |prefix|
305
+ ivar = tag_type.tag_list_ivar(prefix)
306
+ remove_instance_variable(ivar) if instance_variable_defined?(ivar)
307
+ end
308
+ end
309
+
301
310
  def tag_scope(input, *args)
302
311
  tags.where(find_tag_type!(input).finder_type_condition(*args))
303
312
  end
304
313
 
305
314
  def find_tag_type!(input)
306
- (@tag_type ||= {})[input] ||= self.class.find_tag_type!(input)
315
+ self.class.find_tag_type!(input)
307
316
  end
308
317
 
309
- def scoping_options(input, *args)
318
+ def finder_type_arguments_for_tag_list(input, *args)
310
319
  find_tag_type!(input).send(:convert_finder_type_arguments, *args)
311
320
  end
312
321
 
322
+ def scopes_for_tag_list(*args)
323
+ finder_type_arguments_for_tag_list(*args)[0].sort
324
+ end
325
+
313
326
  # Lets say tag class A inherits from B and B has a tag with value "foo". If we tag A with value "foo",
314
327
  # we want B to have only one instance of "foo" and that tag should be an instance of A (a subclass of B).
315
328
  def update_tagging_with_inherited_tag!(tagging, tags, tag_value_lookup)
@@ -322,8 +335,9 @@ module Tagtical::Taggable
322
335
  # If cascade tag types are specified, it will attempt to look at Tag subclasses with
323
336
  # possible_values and try to set those tag_lists with values from the possible_values list.
324
337
  def cascade_set_tag_list!(tag_list, context, *args)
325
- scoping_options = scoping_options(context, *args)
326
- if (cascade = scoping_options.delete(:cascade)) && (tag_type = find_tag_type!(context)).klass
338
+ scopes, options = finder_type_arguments_for_tag_list(context, *args)
339
+ raise("You must include children if you are cascading") if options[:cascade] && !scopes.include?(:current)
340
+ if (cascade = options.delete(:cascade)) && (tag_type = find_tag_type!(context)).klass
327
341
  tag_types = cascade==true ? self.tag_types : Array(cascade).map { |c| find_tag_type!(c) }
328
342
  tag_types.each do |t|
329
343
  if t.klass && t.klass <= tag_type.klass && t.klass.possible_values
@@ -334,7 +348,7 @@ module Tagtical::Taggable
334
348
  true
335
349
  end
336
350
  end
337
- tag_list_cache_on(t)[scoping_options.merge(:scope => :==)] = new_tag_list if !new_tag_list.empty?
351
+ tag_list_cache_on(t)[[:current]] = new_tag_list if !new_tag_list.empty?
338
352
  end
339
353
  end
340
354
  end
@@ -29,21 +29,22 @@ module Tagtical
29
29
  else
30
30
  write_inheritable_attribute(:tag_types, tag_types)
31
31
  class_inheritable_reader(:tag_types)
32
+
33
+ has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "Tagtical::Tagging"
34
+ has_many :tags, :through => :taggings, :class_name => "Tagtical::Tag"
32
35
 
33
36
  class_eval do
34
- has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "Tagtical::Tagging"
35
- has_many :tags, :through => :taggings, :class_name => "Tagtical::Tag"
36
-
37
37
  def self.taggable?
38
38
  true
39
39
  end
40
-
41
- include Tagtical::Taggable::Core
42
- include Tagtical::Taggable::Collection
43
- include Tagtical::Taggable::Cache
44
- include Tagtical::Taggable::Ownership
45
- include Tagtical::Taggable::Related
46
40
  end
41
+
42
+ include Tagtical::Taggable::Core
43
+ include Tagtical::Taggable::Collection
44
+ include Tagtical::Taggable::Cache
45
+ include Tagtical::Taggable::Ownership
46
+ include Tagtical::Taggable::Related
47
+
47
48
  end
48
49
 
49
50
  end
@@ -1,7 +1,11 @@
1
1
  require File.expand_path('../../spec_helper', __FILE__)
2
2
 
3
3
  describe Tagtical::TagList do
4
- before { @tag_list = Tagtical::TagList.new("awesome", "radical") }
4
+ before do
5
+ @klass = Tagtical::TagList
6
+ @tag_list = @klass.new("awesome", "radical")
7
+ end
8
+
5
9
  subject { @tag_list }
6
10
 
7
11
  it { should be_an Array }
@@ -70,8 +74,23 @@ describe Tagtical::TagList do
70
74
 
71
75
  it "should be able to add relevances with a string" do
72
76
  @tag_list.add("foo : 3.4, bar: 2.5")
73
- @tag_list.detect { |t| t=="foo" }.relevance.should == 3.4
74
- @tag_list.detect { |t| t=="bar" }.relevance.should == 2.5
77
+ @tag_list.find("foo").relevance.should == 3.4
78
+ @tag_list.find("bar").relevance.should == 2.5
79
+ end
80
+
81
+ it "should be able to add a symbol" do
82
+ @tag_list.add(:car)
83
+ @tag_list.find("car").should_not be_nil
84
+ end
85
+
86
+ it "should be able to add a list of tags" do
87
+ tags = [["foo", 1],["bar", 1.3],["car", 0.7]].map do |value, relevance|
88
+ Tagtical::Tag.new(:value => value).tap { |t| t["relevance"] = relevance }
89
+ end
90
+ @tag_list.add(tags)
91
+ tags.each do |tag|
92
+ @tag_list.find(tag.value).relevance.should == tag.relevance
93
+ end
75
94
  end
76
95
 
77
96
  it "should be able to remove words" do
@@ -92,7 +111,13 @@ describe Tagtical::TagList do
92
111
  its(:to_s) { should == "awesome, radical" }
93
112
 
94
113
  describe "#to_s" do
95
- before { @tag_list = Tagtical::TagList.new("far", "awesome : 4", "radical : 3", "car, bar:10.3", :parse => false) }
114
+ before do
115
+ @tag_list = Tagtical::TagList.new("far", "awesome : 4", "radical : 3", "car, bar:10.3", :parse => false)
116
+ @taggable = TaggableModel.new("taggable")
117
+ @taggable.set_tag_list "retro: 6, car:4, nature, test: 2.7 ", :cascade => true
118
+ @taggable.save
119
+ @taggable.reload
120
+ end
96
121
 
97
122
  it "should contain relevance with the relevance delimiter" do
98
123
  @tag_list.to_s.should include("awesome:4.0, radical:3.0")
@@ -102,6 +127,10 @@ describe Tagtical::TagList do
102
127
  @tag_list.to_s.should include(%{"car, bar":10.3})
103
128
  end
104
129
 
130
+ it "should include relevance in string" do
131
+ @taggable.tag_list.to_s.should == "retro:6.0, car:4.0, nature:1.0, test:2.7"
132
+ end
133
+
105
134
  end
106
135
 
107
136
  it "should quote escape tags with commas in them" do
@@ -338,7 +338,7 @@ describe Tagtical::Tag do
338
338
  end
339
339
  end
340
340
 
341
- describe "#convert_type_options" do
341
+ describe "#convert_scope_options" do
342
342
  {:<= => [:children, :current],
343
343
  :>= => [:parents, :current],
344
344
  :"<>" => [:children, :parents],
@@ -348,7 +348,7 @@ describe Tagtical::Tag do
348
348
  :"<" => [:children]
349
349
  }.each do |operator, expected|
350
350
  it "should convert #{operator.inspect} to #{expected.inspect}" do
351
- subject.send(:convert_type_options, operator).should have_same_elements(expected)
351
+ subject.send(:convert_scope_options, operator).should have_same_elements(expected)
352
352
  end
353
353
  end
354
354
  end
@@ -24,7 +24,7 @@ describe Tagtical::Taggable do
24
24
 
25
25
  it "should be able to create tags" do
26
26
  @taggable.skill_list = "ruby, rails, css"
27
- @taggable.tag_list_cache_on(:skill)[{}].should be_an_instance_of(Tagtical::TagList)
27
+ @taggable.tag_list_cache_on(:skill)[[:children, :current]].should be_an_instance_of(Tagtical::TagList)
28
28
 
29
29
  lambda { @taggable.save }.should change(Tagtical::Tag, :count).by(3)
30
30
 
@@ -127,7 +127,7 @@ describe Tagtical::Taggable do
127
127
  end
128
128
  end
129
129
 
130
- describe "tag retrieval with finder type conditions" do
130
+ describe "tag_list scoping behavior" do
131
131
  before do
132
132
  @taggables[0].tag_list = "bob"
133
133
  @taggables[1].tag_list = "charlie"
@@ -136,15 +136,35 @@ describe Tagtical::Taggable do
136
136
  @taggables[0].craft_list = "knitting"
137
137
  @taggables[1].craft_list = "pottery"
138
138
  @taggables.each(&:save!)
139
+ @taggables.each(&:reload)
140
+ end
141
+
142
+ it "should empty out inheriting tags" do
143
+ @taggables[0].tag_list = []
144
+ @taggables[0].save!
145
+ @taggables[0].reload
146
+
147
+ @taggables[0].crafts.should be_empty
148
+ end
149
+
150
+ it "should not empty out 'tag' type when :current scope" do
151
+ @taggables[0].set_tag_list([], :current)
152
+ @taggables[0].save!
153
+ @taggables[0].reload
154
+
155
+ @taggables[0].tags.should_not be_empty
156
+ @taggables[0].tags(:current).should be_empty
157
+ @taggables[0].skills.should_not be_empty
158
+ @taggables[0].crafts.should_not be_empty
139
159
  end
140
160
 
141
161
  it "should be able to query tags" do
142
162
  @taggables[0].tags(:scope => :current).should have_only_tag_values %w{bob}
143
- @taggables[0].tags(:scope => :==).should have_only_tag_values %w{bob}
163
+ @taggables[0].tags(:==).should have_only_tag_values %w{bob}
144
164
  @taggables[0].tags.should have_only_tag_values %w{bob knitting ruby}
145
165
  @taggables[0].tags(:scope => :children).should have_only_tag_values %w{knitting ruby}
146
166
  @taggables[0].tags(:scope => :<).should have_only_tag_values %w{knitting ruby}
147
- @taggables[1].crafts(:scope => :parents).should have_only_tag_values %w{charlie css}
167
+ @taggables[1].crafts(:parents).should have_only_tag_values %w{charlie css}
148
168
  @taggables[1].crafts(:scope => :>).should have_only_tag_values %w{charlie css}
149
169
 
150
170
  @taggables[1].crafts(:scope => [:parents, :current]).should have_only_tag_values %w{charlie css pottery}
@@ -446,14 +466,22 @@ describe Tagtical::Taggable do
446
466
 
447
467
  describe "Associations" do
448
468
  before(:each) do
449
- @taggable = TaggableModel.create(:tag_list => "awesome, epic")
469
+ @taggable = TaggableModel.create(:tag_list => "awesome, epic", :skill_list => "basketball, hiking, boxing")
450
470
  end
451
471
 
452
472
  it "should not remove tags when creating associated objects" do
453
473
  @taggable.untaggable_models.create!
454
474
  @taggable.reload
455
- @taggable.tag_list.should have(2).items
475
+ @taggable.tag_list.should have(5).items
476
+ end
477
+
478
+ its "tag_list methods should accept scope arguments" do
479
+ @taggable.tag_list(:current).should have(2).items
480
+ @taggable.skill_list(:parents).should have(2).items
481
+ @taggable.skill_list(:current).should have(3).items
482
+ @taggable.tag_list(:current, :children).should have(5).items
456
483
  end
484
+
457
485
  end
458
486
 
459
487
  describe "grouped_column_names_for method" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tagtical
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-21 00:00:00.000000000Z
12
+ date: 2011-07-22 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &2155967120 !ruby/object:Gem::Requirement
16
+ requirement: &2168459400 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - <=
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.5
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2155967120
24
+ version_requirements: *2168459400
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2155983780 !ruby/object:Gem::Requirement
27
+ requirement: &2168476040 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - <=
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.6.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2155983780
35
+ version_requirements: *2168476040
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sqlite3-ruby
38
- requirement: &2155983300 !ruby/object:Gem::Requirement
38
+ requirement: &2168475560 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2155983300
46
+ version_requirements: *2168475560
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: mysql
49
- requirement: &2155982820 !ruby/object:Gem::Requirement
49
+ requirement: &2168475080 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *2155982820
57
+ version_requirements: *2168475080
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: jeweler
60
- requirement: &2155982340 !ruby/object:Gem::Requirement
60
+ requirement: &2168474600 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *2155982340
68
+ version_requirements: *2168474600
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rcov
71
- requirement: &2155981860 !ruby/object:Gem::Requirement
71
+ requirement: &2168474120 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *2155981860
79
+ version_requirements: *2168474120
80
80
  description: Tagtical allows you do create subclasses for Tag and add additional functionality
81
81
  in an STI fashion. For example. You could do Tag::Color.find_by_name('blue').to_rgb.
82
82
  It also supports storing weights or relevance on the taggings.