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 +1 -1
- data/lib/tagtical/tag.rb +10 -11
- data/lib/tagtical/tag_list.rb +26 -12
- data/lib/tagtical/taggable/cache.rb +2 -2
- data/lib/tagtical/taggable/core.rb +28 -14
- data/lib/tagtical/taggable.rb +10 -9
- data/spec/tagtical/tag_list_spec.rb +33 -4
- data/spec/tagtical/tag_spec.rb +2 -2
- data/spec/tagtical/taggable_spec.rb +34 -6
- metadata +14 -14
data/VERSION
CHANGED
@@ -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
|
-
|
238
|
-
|
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
|
241
|
+
if scopes.include?(:current)
|
243
242
|
sti_names << klass.sti_name
|
244
243
|
end
|
245
|
-
if
|
244
|
+
if scopes.include?(:children) && klass
|
246
245
|
sti_names.concat(klass.descendants.map(&:sti_name))
|
247
246
|
end
|
248
|
-
if
|
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
|
344
|
-
Array.wrap(input ||
|
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
|
-
|
376
|
-
options
|
374
|
+
scopes = convert_scope_options(args.presence || options[:scope])
|
375
|
+
[scopes, options]
|
377
376
|
end
|
378
377
|
|
379
378
|
end
|
data/lib/tagtical/tag_list.rb
CHANGED
@@ -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
|
-
|
127
|
-
[
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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.
|
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)[
|
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)[
|
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)[
|
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 |
|
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
|
-
|
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
|
-
|
315
|
+
self.class.find_tag_type!(input)
|
307
316
|
end
|
308
317
|
|
309
|
-
def
|
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
|
-
|
326
|
-
if
|
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)[
|
351
|
+
tag_list_cache_on(t)[[:current]] = new_tag_list if !new_tag_list.empty?
|
338
352
|
end
|
339
353
|
end
|
340
354
|
end
|
data/lib/tagtical/taggable.rb
CHANGED
@@ -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
|
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.
|
74
|
-
@tag_list.
|
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
|
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
|
data/spec/tagtical/tag_spec.rb
CHANGED
@@ -338,7 +338,7 @@ describe Tagtical::Tag do
|
|
338
338
|
end
|
339
339
|
end
|
340
340
|
|
341
|
-
describe "#
|
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(:
|
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)[
|
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 "
|
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(
|
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(:
|
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(
|
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.
|
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-
|
12
|
+
date: 2011-07-22 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
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: *
|
24
|
+
version_requirements: *2168459400
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
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: *
|
35
|
+
version_requirements: *2168476040
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sqlite3-ruby
|
38
|
-
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: *
|
46
|
+
version_requirements: *2168475560
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mysql
|
49
|
-
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: *
|
57
|
+
version_requirements: *2168475080
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: jeweler
|
60
|
-
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: *
|
68
|
+
version_requirements: *2168474600
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rcov
|
71
|
-
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: *
|
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.
|