tagtical 1.1.1 → 1.1.2

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 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.