tagtools 0.0.2 → 0.0.3
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/CHANGELOG +4 -0
- data/lib/tagtools.rb +347 -92
- data/rakefile +1 -1
- data/test/global_tags_test.rb +42 -0
- data/test/user_tags_test.rb +99 -0
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
== TagTools 0.0.3
|
2
|
+
* fixed a particularly nasty bug with tag queries on user-scoped tags
|
3
|
+
* added a mixin for tag classes
|
4
|
+
* improved the unit tests
|
1
5
|
== TagTools 0.0.2
|
2
6
|
* fixed a bug in delete_records for user tag collections
|
3
7
|
* added include? method to all tag collections
|
data/lib/tagtools.rb
CHANGED
@@ -21,7 +21,7 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
-
TAG_TOOLS_VERSION = "0.0.
|
24
|
+
TAG_TOOLS_VERSION = "0.0.3"
|
25
25
|
|
26
26
|
$:.unshift(File.dirname(__FILE__))
|
27
27
|
$:.unshift(File.dirname(__FILE__) + "/../../activerecord/lib")
|
@@ -539,6 +539,23 @@ module ActiveRecord #:nodoc:
|
|
539
539
|
undecorated_table_name(tag_class.name),
|
540
540
|
undecorated_table_name(user_class.name),
|
541
541
|
undecorated_table_name(item_class.name))
|
542
|
+
|
543
|
+
association_hash = {
|
544
|
+
:tag_class => tag_class,
|
545
|
+
:tag_foreign_key => tag_foreign_key,
|
546
|
+
:item_class => item_class,
|
547
|
+
:item_foreign_key => item_foreign_key,
|
548
|
+
:user_class => user_class,
|
549
|
+
:user_foreign_key => user_foreign_key,
|
550
|
+
:join_table => options[:join_table]
|
551
|
+
}
|
552
|
+
|
553
|
+
if tag_class.instance_variable_get("@tagged_classes").nil?
|
554
|
+
tag_class.instance_variable_set("@tagged_classes", [])
|
555
|
+
end
|
556
|
+
tagged_classes =
|
557
|
+
tag_class.instance_variable_get("@tagged_classes")
|
558
|
+
tagged_classes << association_hash
|
542
559
|
|
543
560
|
# Create the two collections
|
544
561
|
define_method(options[:collection]) do |*params|
|
@@ -579,8 +596,15 @@ module ActiveRecord #:nodoc:
|
|
579
596
|
singleton_class.module_eval do
|
580
597
|
define_method(:tag_query) do |*params|
|
581
598
|
query_options = params.first unless params.empty?
|
599
|
+
unless query_options.kind_of? Hash
|
600
|
+
raise "The first parameter must be a hash."
|
601
|
+
end
|
582
602
|
validate_options([:with_any_tags, :with_all_tags,
|
583
603
|
:without_tags, :user_id], query_options.keys)
|
604
|
+
if query_options.size == 0
|
605
|
+
raise "You must supply either the with_any_tags option, " +
|
606
|
+
"the with_all_tags option, or both."
|
607
|
+
end
|
584
608
|
with_any_tags = query_options[:with_any_tags]
|
585
609
|
unless with_any_tags.nil?
|
586
610
|
with_any_tags.collect! { |tag| tag.to_s }
|
@@ -616,57 +640,58 @@ module ActiveRecord #:nodoc:
|
|
616
640
|
|
617
641
|
with_all_tags_results = nil
|
618
642
|
if with_all_tags != nil && with_all_tags.size > 0
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
643
|
+
tag_name_condition = "#{tag_class.table_name}.name = '" +
|
644
|
+
with_all_tags.join(
|
645
|
+
"\' OR #{tag_class.table_name}.name=\'") + "'"
|
646
|
+
with_all_tags_sql = <<-SQL
|
647
|
+
SELECT #{item_class.table_name}.*
|
648
|
+
FROM #{options[:join_table]}, #{item_class.table_name},
|
649
|
+
#{tag_class.table_name}
|
650
|
+
WHERE #{options[:join_table]}.#{tag_foreign_key} =
|
651
|
+
#{tag_class.table_name}.#{tag_class.primary_key}
|
652
|
+
AND (#{tag_name_condition})
|
653
|
+
AND #{item_class.table_name}.#{item_class.primary_key} =
|
654
|
+
#{options[:join_table]}.#{item_foreign_key}
|
655
|
+
#{tagging_user_id_string}
|
656
|
+
GROUP BY #{group_by_string}
|
657
|
+
HAVING COUNT(
|
658
|
+
#{item_class.table_name}.#{item_class.primary_key}) >=
|
659
|
+
#{with_all_tags.size}
|
660
|
+
SQL
|
661
|
+
with_all_tags_results =
|
662
|
+
item_class.find_by_sql(with_all_tags_sql)
|
663
|
+
if tagging_user_id.nil?
|
664
|
+
for result in with_all_tags_results
|
665
|
+
result_tags = result.tags.map do |tag|
|
666
|
+
tag.name
|
667
|
+
end
|
668
|
+
if (result_tags & with_all_tags).size != with_all_tags.size
|
669
|
+
# Reject result
|
670
|
+
with_all_tags_results.delete(result)
|
671
|
+
end
|
672
|
+
end
|
640
673
|
end
|
641
674
|
end
|
642
675
|
|
643
676
|
with_any_tags_results = nil
|
644
677
|
if with_any_tags != nil && with_any_tags.size > 0
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
item_class.find_by_sql(with_any_tags_sql)
|
661
|
-
end
|
678
|
+
with_any_tags_sql = <<-SQL
|
679
|
+
SELECT #{item_class.table_name}.*
|
680
|
+
FROM #{options[:join_table]}, #{item_class.table_name},
|
681
|
+
#{tag_class.table_name}
|
682
|
+
WHERE #{tag_class.table_name}.name
|
683
|
+
IN ('#{with_any_tags.join('\', \'')}')
|
684
|
+
AND #{tag_class.table_name}.#{tag_class.primary_key} =
|
685
|
+
#{options[:join_table]}.#{tag_foreign_key}
|
686
|
+
AND #{item_class.table_name}.#{item_class.primary_key} =
|
687
|
+
#{options[:join_table]}.#{item_foreign_key}
|
688
|
+
#{tagging_user_id_string}
|
689
|
+
GROUP BY #{group_by_string}
|
690
|
+
SQL
|
691
|
+
with_any_tags_results =
|
692
|
+
item_class.find_by_sql(with_any_tags_sql)
|
662
693
|
end
|
663
694
|
|
664
|
-
if with_all_tags != nil && with_all_tags.size > 0
|
665
|
-
with_all_tags_query_thread.join
|
666
|
-
end
|
667
|
-
if with_any_tags != nil && with_any_tags.size > 0
|
668
|
-
with_any_tags_query_thread.join
|
669
|
-
end
|
670
695
|
if with_any_tags_results != nil &&
|
671
696
|
with_any_tags_results.size > 0 &&
|
672
697
|
with_all_tags_results != nil &&
|
@@ -679,11 +704,19 @@ module ActiveRecord #:nodoc:
|
|
679
704
|
with_all_tags_results.size > 0
|
680
705
|
results = with_all_tags_results
|
681
706
|
end
|
707
|
+
|
682
708
|
if without_tags != nil && without_tags.size > 0
|
683
709
|
for result in results
|
684
|
-
if
|
685
|
-
|
686
|
-
|
710
|
+
if tagging_user_id.nil?
|
711
|
+
if ((result.tags.map { |tag| tag.name }) &
|
712
|
+
without_tags).size > 0
|
713
|
+
results.delete(result)
|
714
|
+
end
|
715
|
+
else
|
716
|
+
if ((result.user_tags(tagging_user_id).map { |tag| tag.name }) &
|
717
|
+
without_tags).size > 0
|
718
|
+
results.delete(result)
|
719
|
+
end
|
687
720
|
end
|
688
721
|
end
|
689
722
|
end
|
@@ -780,6 +813,23 @@ module ActiveRecord #:nodoc:
|
|
780
813
|
undecorated_table_name(tag_class.name),
|
781
814
|
undecorated_table_name(item_class.name))
|
782
815
|
|
816
|
+
association_hash = {
|
817
|
+
:tag_class => tag_class,
|
818
|
+
:tag_foreign_key => tag_foreign_key,
|
819
|
+
:item_class => item_class,
|
820
|
+
:item_foreign_key => item_foreign_key,
|
821
|
+
:user_class => nil,
|
822
|
+
:user_foreign_key => nil,
|
823
|
+
:join_table => options[:join_table]
|
824
|
+
}
|
825
|
+
|
826
|
+
if tag_class.instance_variable_get("@tagged_classes").nil?
|
827
|
+
tag_class.instance_variable_set("@tagged_classes", [])
|
828
|
+
end
|
829
|
+
tagged_classes =
|
830
|
+
tag_class.instance_variable_get("@tagged_classes")
|
831
|
+
tagged_classes << association_hash
|
832
|
+
|
783
833
|
define_method(options[:collection]) do |*params|
|
784
834
|
force_reload = params.first unless params.empty?
|
785
835
|
association = instance_variable_get(
|
@@ -799,8 +849,15 @@ module ActiveRecord #:nodoc:
|
|
799
849
|
singleton_class.module_eval do
|
800
850
|
define_method(:tag_query) do |*params|
|
801
851
|
query_options = params.first unless params.empty?
|
852
|
+
unless query_options.kind_of? Hash
|
853
|
+
raise "The first parameter must be a hash."
|
854
|
+
end
|
802
855
|
validate_options([:with_any_tags, :with_all_tags,
|
803
|
-
:without_tags], query_options.keys)
|
856
|
+
:without_tags, :user_id], query_options.keys)
|
857
|
+
if query_options.size == 0
|
858
|
+
raise "You must supply either the with_any_tags option, " +
|
859
|
+
"the with_all_tags option, or both."
|
860
|
+
end
|
804
861
|
with_any_tags = query_options[:with_any_tags]
|
805
862
|
unless with_any_tags.nil?
|
806
863
|
with_any_tags.collect! { |tag| tag.to_s }
|
@@ -829,55 +886,45 @@ module ActiveRecord #:nodoc:
|
|
829
886
|
|
830
887
|
with_all_tags_results = nil
|
831
888
|
if with_all_tags != nil && with_all_tags.size > 0
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
item_class.find_by_sql(with_all_tags_sql)
|
852
|
-
end
|
889
|
+
tag_name_condition = "#{tag_class.table_name}.name = '" +
|
890
|
+
with_all_tags.join(
|
891
|
+
"\' OR #{tag_class.table_name}.name=\'") + "'"
|
892
|
+
with_all_tags_sql = <<-SQL
|
893
|
+
SELECT #{item_class.table_name}.*
|
894
|
+
FROM #{options[:join_table]}, #{item_class.table_name},
|
895
|
+
#{tag_class.table_name}
|
896
|
+
WHERE #{options[:join_table]}.#{tag_foreign_key} =
|
897
|
+
#{tag_class.table_name}.#{tag_class.primary_key}
|
898
|
+
AND (#{tag_name_condition})
|
899
|
+
AND #{item_class.table_name}.#{item_class.primary_key} =
|
900
|
+
#{options[:join_table]}.#{item_foreign_key}
|
901
|
+
GROUP BY #{group_by_string}
|
902
|
+
HAVING COUNT(
|
903
|
+
#{item_class.table_name}.#{item_class.primary_key}) =
|
904
|
+
#{with_all_tags.size}
|
905
|
+
SQL
|
906
|
+
with_all_tags_results =
|
907
|
+
item_class.find_by_sql(with_all_tags_sql)
|
853
908
|
end
|
854
909
|
|
855
910
|
with_any_tags_results = nil
|
856
911
|
if with_any_tags != nil && with_any_tags.size > 0
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
item_class.find_by_sql(with_any_tags_sql)
|
872
|
-
end
|
912
|
+
with_any_tags_sql = <<-SQL
|
913
|
+
SELECT #{item_class.table_name}.*
|
914
|
+
FROM #{options[:join_table]}, #{item_class.table_name},
|
915
|
+
#{tag_class.table_name}
|
916
|
+
WHERE #{tag_class.table_name}.name
|
917
|
+
IN ('#{with_any_tags.join('\', \'')}')
|
918
|
+
AND #{tag_class.table_name}.#{tag_class.primary_key} =
|
919
|
+
#{options[:join_table]}.#{tag_foreign_key}
|
920
|
+
AND #{item_class.table_name}.#{item_class.primary_key} =
|
921
|
+
#{options[:join_table]}.#{item_foreign_key}
|
922
|
+
GROUP BY #{group_by_string}
|
923
|
+
SQL
|
924
|
+
with_any_tags_results =
|
925
|
+
item_class.find_by_sql(with_any_tags_sql)
|
873
926
|
end
|
874
927
|
|
875
|
-
if with_all_tags != nil && with_all_tags.size > 0
|
876
|
-
with_all_tags_query_thread.join
|
877
|
-
end
|
878
|
-
if with_any_tags != nil && with_any_tags.size > 0
|
879
|
-
with_any_tags_query_thread.join
|
880
|
-
end
|
881
928
|
if with_any_tags_results != nil &&
|
882
929
|
with_any_tags_results.size > 0 &&
|
883
930
|
with_all_tags_results != nil &&
|
@@ -987,6 +1034,214 @@ module ActiveRecord #:nodoc:
|
|
987
1034
|
end
|
988
1035
|
end
|
989
1036
|
|
1037
|
+
# This module allows you to add additional generic functionality to your
|
1038
|
+
# Tag class by simply extending the TaggingHelpers module.
|
1039
|
+
#
|
1040
|
+
# Example:
|
1041
|
+
# class Tag < ActiveRecord::Base
|
1042
|
+
# extend TaggingHelpers
|
1043
|
+
# end
|
1044
|
+
module TaggingHelpers
|
1045
|
+
# Unlike the tag_query class method on tagged classes, this will search
|
1046
|
+
# across the entire tagged space, returning any tagged object, regardless
|
1047
|
+
# of type, that matches the query criteria.
|
1048
|
+
#
|
1049
|
+
# Options are:
|
1050
|
+
# * <tt>:with_all_tags</tt> - An array of strings, returns all tagged
|
1051
|
+
# objects that have all of the tags specified within the array.
|
1052
|
+
# * <tt>:with_any_tags</tt> - An array of strings, returns all tagged
|
1053
|
+
# objects that have any of the tags specified within the array.
|
1054
|
+
# * <tt>:without_tags</tt> - An array of strings, removes all tagged
|
1055
|
+
# objects that have any of the tags specified within the array from
|
1056
|
+
# the list of results that would have otherwise been returned.
|
1057
|
+
# Throws an error if used in the absence of of either of the other
|
1058
|
+
# two options.
|
1059
|
+
# * <tt>:user_id</tt> - An integer id for the user that this query
|
1060
|
+
# is specific to. Only tags that this user has created will be
|
1061
|
+
# taken into account with this query. Globally scoped tag associations
|
1062
|
+
# will be not be included in the results if this option is set.
|
1063
|
+
def tag_query(options = {})
|
1064
|
+
if self.class != Class
|
1065
|
+
raise "You must extend your tag class with the TaggingHelpers module."
|
1066
|
+
end
|
1067
|
+
unless options.kind_of? Hash
|
1068
|
+
raise "The options parameter must be a hash."
|
1069
|
+
end
|
1070
|
+
validate_options([:with_any_tags, :with_all_tags,
|
1071
|
+
:without_tags, :user_id], options.keys)
|
1072
|
+
if options.size == 0
|
1073
|
+
raise "You must supply either the with_any_tags option, " +
|
1074
|
+
"the with_all_tags option, or both."
|
1075
|
+
end
|
1076
|
+
with_any_tags = options[:with_any_tags]
|
1077
|
+
unless with_any_tags.nil?
|
1078
|
+
with_any_tags.collect! { |tag| tag.to_s }
|
1079
|
+
with_any_tags.uniq!
|
1080
|
+
end
|
1081
|
+
with_all_tags = options[:with_all_tags]
|
1082
|
+
unless with_all_tags.nil?
|
1083
|
+
with_all_tags.collect! { |tag| tag.to_s }
|
1084
|
+
with_all_tags.uniq!
|
1085
|
+
end
|
1086
|
+
without_tags = options[:without_tags]
|
1087
|
+
unless without_tags.nil?
|
1088
|
+
without_tags.collect! { |tag| tag.to_s }
|
1089
|
+
without_tags.uniq!
|
1090
|
+
end
|
1091
|
+
if without_tags != nil && with_any_tags == nil &&
|
1092
|
+
with_all_tags == nil
|
1093
|
+
raise(ActiveRecord::ActiveRecordError,
|
1094
|
+
"Cannot run this query, nothing to search for.")
|
1095
|
+
end
|
1096
|
+
tagging_user_id = options[:user_id]
|
1097
|
+
results = []
|
1098
|
+
|
1099
|
+
for association_hash in self.instance_variable_get("@tagged_classes")
|
1100
|
+
|
1101
|
+
# Load variables from the association_hash
|
1102
|
+
tag_class = association_hash[:tag_class]
|
1103
|
+
tag_foreign_key = association_hash[:tag_foreign_key]
|
1104
|
+
item_class = association_hash[:item_class]
|
1105
|
+
item_foreign_key = association_hash[:item_foreign_key]
|
1106
|
+
user_class = association_hash[:user_class]
|
1107
|
+
user_foreign_key = association_hash[:user_foreign_key]
|
1108
|
+
join_table = association_hash[:join_table]
|
1109
|
+
|
1110
|
+
# If they specified a user_id, and this association is a globally
|
1111
|
+
# scoped tag association, skip to the next association.
|
1112
|
+
if tagging_user_id != nil && user_class.nil?
|
1113
|
+
next
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
group_by_string = item_class.table_name + "." +
|
1117
|
+
item_class.column_names.join(
|
1118
|
+
", #{item_class.table_name}.")
|
1119
|
+
tagging_user_id_string = ""
|
1120
|
+
unless tagging_user_id.nil?
|
1121
|
+
tagging_user_id_string =
|
1122
|
+
"AND #{join_table}.#{user_foreign_key} = #{tagging_user_id}"
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
with_all_tags_results = nil
|
1126
|
+
if with_all_tags != nil && with_all_tags.size > 0
|
1127
|
+
tag_name_condition = "#{tag_class.table_name}.name = '" +
|
1128
|
+
with_all_tags.join(
|
1129
|
+
"\' OR #{tag_class.table_name}.name=\'") + "'"
|
1130
|
+
with_all_tags_sql = <<-SQL
|
1131
|
+
SELECT #{item_class.table_name}.*
|
1132
|
+
FROM #{join_table}, #{item_class.table_name},
|
1133
|
+
#{tag_class.table_name}
|
1134
|
+
WHERE #{join_table}.#{tag_foreign_key} =
|
1135
|
+
#{tag_class.table_name}.#{tag_class.primary_key}
|
1136
|
+
AND (#{tag_name_condition})
|
1137
|
+
AND #{item_class.table_name}.#{item_class.primary_key} =
|
1138
|
+
#{join_table}.#{item_foreign_key}
|
1139
|
+
#{tagging_user_id_string}
|
1140
|
+
GROUP BY #{group_by_string}
|
1141
|
+
HAVING COUNT(
|
1142
|
+
#{item_class.table_name}.#{item_class.primary_key}) >=
|
1143
|
+
#{with_all_tags.size}
|
1144
|
+
SQL
|
1145
|
+
with_all_tags_results =
|
1146
|
+
item_class.find_by_sql(with_all_tags_sql)
|
1147
|
+
if tagging_user_id.nil?
|
1148
|
+
for result in with_all_tags_results
|
1149
|
+
result_tags = result.tags.map do |tag|
|
1150
|
+
tag.name
|
1151
|
+
end
|
1152
|
+
if (result_tags & with_all_tags).size != with_all_tags.size
|
1153
|
+
# Reject result
|
1154
|
+
with_all_tags_results.delete(result)
|
1155
|
+
end
|
1156
|
+
end
|
1157
|
+
end
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
with_any_tags_results = nil
|
1161
|
+
if with_any_tags != nil && with_any_tags.size > 0
|
1162
|
+
with_any_tags_sql = <<-SQL
|
1163
|
+
SELECT #{item_class.table_name}.*
|
1164
|
+
FROM #{join_table}, #{item_class.table_name},
|
1165
|
+
#{tag_class.table_name}
|
1166
|
+
WHERE #{tag_class.table_name}.name
|
1167
|
+
IN ('#{with_any_tags.join('\', \'')}')
|
1168
|
+
AND #{tag_class.table_name}.#{tag_class.primary_key} =
|
1169
|
+
#{join_table}.#{tag_foreign_key}
|
1170
|
+
AND #{item_class.table_name}.#{item_class.primary_key} =
|
1171
|
+
#{join_table}.#{item_foreign_key}
|
1172
|
+
#{tagging_user_id_string}
|
1173
|
+
GROUP BY #{group_by_string}
|
1174
|
+
SQL
|
1175
|
+
with_any_tags_results =
|
1176
|
+
item_class.find_by_sql(with_any_tags_sql)
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
if with_any_tags_results != nil &&
|
1180
|
+
with_any_tags_results.size > 0 &&
|
1181
|
+
with_all_tags_results != nil &&
|
1182
|
+
with_all_tags_results.size > 0
|
1183
|
+
results.concat(with_all_tags_results & with_any_tags_results)
|
1184
|
+
elsif with_any_tags_results != nil &&
|
1185
|
+
with_any_tags_results.size > 0
|
1186
|
+
results.concat(with_any_tags_results)
|
1187
|
+
elsif with_all_tags_results != nil &&
|
1188
|
+
with_all_tags_results.size > 0
|
1189
|
+
results.concat(with_all_tags_results)
|
1190
|
+
end
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
if without_tags != nil && without_tags.size > 0
|
1194
|
+
for result in results
|
1195
|
+
if tagging_user_id.nil?
|
1196
|
+
if ((result.tags.map { |tag| tag.name }) &
|
1197
|
+
without_tags).size > 0
|
1198
|
+
results.delete(result)
|
1199
|
+
end
|
1200
|
+
else
|
1201
|
+
if ((result.user_tags(tagging_user_id).map { |tag| tag.name }) &
|
1202
|
+
without_tags).size > 0
|
1203
|
+
results.delete(result)
|
1204
|
+
end
|
1205
|
+
end
|
1206
|
+
end
|
1207
|
+
end
|
1208
|
+
return results
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
# Takes a string and converts it to a tag object, creating the tag object
|
1212
|
+
# if it doesn't yet exist.
|
1213
|
+
def create_tag(raw_tag)
|
1214
|
+
if self.class != Class
|
1215
|
+
raise "You must extend your tag class with the TaggingHelpers module."
|
1216
|
+
end
|
1217
|
+
return nil if raw_tag.nil?
|
1218
|
+
if raw_tag.kind_of? self
|
1219
|
+
return raw_tag
|
1220
|
+
end
|
1221
|
+
tag_object = self.find_by_name(raw_tag.to_s)
|
1222
|
+
if tag_object.nil?
|
1223
|
+
tag_object = self.new
|
1224
|
+
tag_object.name = raw_tag.to_s
|
1225
|
+
tag_object.save
|
1226
|
+
end
|
1227
|
+
return tag_object
|
1228
|
+
end
|
1229
|
+
|
1230
|
+
# Takes a string and converts it to a tag object, returning nil if it
|
1231
|
+
# doesn't yet exist.
|
1232
|
+
def get_tag(raw_tag)
|
1233
|
+
if self.class != Class
|
1234
|
+
raise "You must extend your tag class with the TaggingHelpers module."
|
1235
|
+
end
|
1236
|
+
return nil if raw_tag.nil?
|
1237
|
+
if raw_tag.kind_of? self
|
1238
|
+
return raw_tag
|
1239
|
+
end
|
1240
|
+
tag_object = self.find_by_name(raw_tag.to_s)
|
1241
|
+
return tag_object
|
1242
|
+
end
|
1243
|
+
end
|
1244
|
+
|
990
1245
|
ActiveRecord::Base.class_eval do
|
991
1246
|
include ActiveRecord::Acts::Taggable
|
992
1247
|
end
|
data/rakefile
CHANGED
data/test/global_tags_test.rb
CHANGED
@@ -31,6 +31,7 @@ rescue
|
|
31
31
|
end
|
32
32
|
|
33
33
|
class Tag < ActiveRecord::Base
|
34
|
+
extend TaggingHelpers
|
34
35
|
end
|
35
36
|
|
36
37
|
class Image < ActiveRecord::Base
|
@@ -44,6 +45,12 @@ class GlobalTagsTest < Test::Unit::TestCase
|
|
44
45
|
ActiveRecord::Base.connection.execute("DELETE FROM tags")
|
45
46
|
end
|
46
47
|
|
48
|
+
def teardown
|
49
|
+
ActiveRecord::Base.connection.execute("DELETE FROM images_tags")
|
50
|
+
ActiveRecord::Base.connection.execute("DELETE FROM images")
|
51
|
+
ActiveRecord::Base.connection.execute("DELETE FROM tags")
|
52
|
+
end
|
53
|
+
|
47
54
|
def test_add_tags_existing_record
|
48
55
|
ruby_on_rails = Image.new
|
49
56
|
ruby_on_rails.url = "http://www.rubyonrails.com/logo.gif"
|
@@ -142,4 +149,39 @@ class GlobalTagsTest < Test::Unit::TestCase
|
|
142
149
|
assert_equal(2,
|
143
150
|
ruby_on_rails.tags(true).size)
|
144
151
|
end
|
152
|
+
|
153
|
+
def test_tag_helpers
|
154
|
+
ruby_on_rails = Image.new
|
155
|
+
ruby_on_rails.url = "http://www.rubyonrails.com/logo.gif"
|
156
|
+
ruby_on_rails.save
|
157
|
+
ruby_on_rails.tags << "ruby"
|
158
|
+
ruby_on_rails.tags << "rails"
|
159
|
+
ruby_on_rails.tags << "framework"
|
160
|
+
red_handed = Image.new
|
161
|
+
red_handed.url = "http://redhanded.hobix.com/logo.gif"
|
162
|
+
red_handed.save
|
163
|
+
red_handed.tags << "ruby"
|
164
|
+
red_handed.tags << "cult"
|
165
|
+
|
166
|
+
tag = Tag.get_tag("ruby")
|
167
|
+
assert_equal("ruby", tag.name)
|
168
|
+
tag = Tag.get_tag("non-existant")
|
169
|
+
assert_equal(nil, tag)
|
170
|
+
tag = Tag.create_tag("ruby")
|
171
|
+
assert_equal("ruby", tag.name)
|
172
|
+
tag = Tag.create_tag("non-existant")
|
173
|
+
assert_equal("non-existant", tag.name)
|
174
|
+
|
175
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "cult"])
|
176
|
+
assert_equal(red_handed, results.first)
|
177
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "framework"])
|
178
|
+
assert_equal(ruby_on_rails, results.first)
|
179
|
+
results = Tag.tag_query(:with_any_tags => ["cult", "framework"])
|
180
|
+
assert(results.include?(ruby_on_rails))
|
181
|
+
assert(results.include?(red_handed))
|
182
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "framework"],
|
183
|
+
:without_tags => ["cult"])
|
184
|
+
assert_equal(ruby_on_rails, results.first)
|
185
|
+
assert(!results.include?(red_handed))
|
186
|
+
end
|
145
187
|
end
|
data/test/user_tags_test.rb
CHANGED
@@ -34,6 +34,7 @@ class User < ActiveRecord::Base
|
|
34
34
|
end
|
35
35
|
|
36
36
|
class Tag < ActiveRecord::Base
|
37
|
+
extend TaggingHelpers
|
37
38
|
end
|
38
39
|
|
39
40
|
class Bookmark < ActiveRecord::Base
|
@@ -48,6 +49,13 @@ class UserTagsTest < Test::Unit::TestCase
|
|
48
49
|
ActiveRecord::Base.connection.execute("DELETE FROM users")
|
49
50
|
ActiveRecord::Base.connection.execute("DELETE FROM tags")
|
50
51
|
end
|
52
|
+
|
53
|
+
def teardown
|
54
|
+
ActiveRecord::Base.connection.execute("DELETE FROM bookmarks_tags_users")
|
55
|
+
ActiveRecord::Base.connection.execute("DELETE FROM bookmarks")
|
56
|
+
ActiveRecord::Base.connection.execute("DELETE FROM users")
|
57
|
+
ActiveRecord::Base.connection.execute("DELETE FROM tags")
|
58
|
+
end
|
51
59
|
|
52
60
|
def test_add_tags_existing_record
|
53
61
|
some_guy = User.new
|
@@ -90,6 +98,9 @@ class UserTagsTest < Test::Unit::TestCase
|
|
90
98
|
some_guy = User.new
|
91
99
|
some_guy.name = "Joe Normal"
|
92
100
|
some_guy.save
|
101
|
+
some_other_guy = User.new
|
102
|
+
some_other_guy.name = "Joe Abnormal"
|
103
|
+
some_other_guy.save
|
93
104
|
ruby_on_rails = Bookmark.new
|
94
105
|
ruby_on_rails.url = "http://www.rubyonrails.com"
|
95
106
|
ruby_on_rails.save
|
@@ -101,17 +112,40 @@ class UserTagsTest < Test::Unit::TestCase
|
|
101
112
|
red_handed.save
|
102
113
|
red_handed.user_tags(some_guy.id) << "ruby"
|
103
114
|
red_handed.user_tags(some_guy.id) << "cult"
|
115
|
+
red_handed.user_tags(some_other_guy.id) << "spinach"
|
116
|
+
red_handed.user_tags(some_other_guy.id) << "turkey"
|
117
|
+
red_handed.user_tags(some_other_guy.id) << "atlantis"
|
118
|
+
red_handed.user_tags(some_other_guy.id) << "ruby"
|
119
|
+
|
104
120
|
results = Bookmark.tag_query(:with_all_tags => ["ruby", "cult"])
|
105
121
|
assert_equal(red_handed, results.first)
|
122
|
+
assert_equal(1, results.size)
|
106
123
|
results = Bookmark.tag_query(:with_all_tags => ["ruby", "framework"])
|
107
124
|
assert_equal(ruby_on_rails, results.first)
|
125
|
+
assert_equal(1, results.size)
|
108
126
|
results = Bookmark.tag_query(:with_any_tags => ["cult", "framework"])
|
109
127
|
assert(results.include?(ruby_on_rails))
|
110
128
|
assert(results.include?(red_handed))
|
129
|
+
assert_equal(2, results.size)
|
111
130
|
results = Bookmark.tag_query(:with_all_tags => ["ruby", "framework"],
|
112
131
|
:without_tags => ["cult"])
|
113
132
|
assert_equal(ruby_on_rails, results.first)
|
114
133
|
assert(!results.include?(red_handed))
|
134
|
+
assert_equal(1, results.size)
|
135
|
+
results = Bookmark.tag_query(:with_all_tags => ["ruby", "framework"],
|
136
|
+
:without_tags => ["cult"], :user_id => some_guy.id)
|
137
|
+
assert_equal(ruby_on_rails, results.first)
|
138
|
+
assert(!results.include?(red_handed))
|
139
|
+
assert_equal(1, results.size)
|
140
|
+
results = Bookmark.tag_query(:with_all_tags => ["spinach"],
|
141
|
+
:with_any_tags => ["ruby", "cult", "rails", "framework"],
|
142
|
+
:without_tags => ["cult"], :user_id => some_other_guy.id)
|
143
|
+
assert_equal(red_handed, results.first)
|
144
|
+
assert(!results.include?(ruby_on_rails))
|
145
|
+
assert_equal(1, results.size)
|
146
|
+
results = Bookmark.tag_query(:with_all_tags => ["ruby", "framework"],
|
147
|
+
:without_tags => ["cult"], :user_id => -1)
|
148
|
+
assert_equal(0, results.size)
|
115
149
|
end
|
116
150
|
|
117
151
|
def test_include
|
@@ -161,4 +195,69 @@ class UserTagsTest < Test::Unit::TestCase
|
|
161
195
|
assert_equal(2,
|
162
196
|
ruby_on_rails.user_tags(some_guy.id, true).size)
|
163
197
|
end
|
198
|
+
|
199
|
+
def test_tag_helpers
|
200
|
+
some_guy = User.new
|
201
|
+
some_guy.name = "Joe Normal"
|
202
|
+
some_guy.save
|
203
|
+
some_other_guy = User.new
|
204
|
+
some_other_guy.name = "Joe Abnormal"
|
205
|
+
some_other_guy.save
|
206
|
+
ruby_on_rails = Bookmark.new
|
207
|
+
ruby_on_rails.url = "http://www.rubyonrails.com"
|
208
|
+
ruby_on_rails.save
|
209
|
+
ruby_on_rails.user_tags(some_guy.id) << "ruby"
|
210
|
+
ruby_on_rails.user_tags(some_guy.id) << "rails"
|
211
|
+
ruby_on_rails.user_tags(some_guy.id) << "framework"
|
212
|
+
red_handed = Bookmark.new
|
213
|
+
red_handed.url = "http://redhanded.hobix.com"
|
214
|
+
red_handed.save
|
215
|
+
red_handed.user_tags(some_guy.id) << "ruby"
|
216
|
+
red_handed.user_tags(some_guy.id) << "cult"
|
217
|
+
red_handed.user_tags(some_other_guy.id) << "spinach"
|
218
|
+
red_handed.user_tags(some_other_guy.id) << "turkey"
|
219
|
+
red_handed.user_tags(some_other_guy.id) << "atlantis"
|
220
|
+
red_handed.user_tags(some_other_guy.id) << "ruby"
|
221
|
+
|
222
|
+
tag = Tag.get_tag("ruby")
|
223
|
+
assert_equal("ruby", tag.name)
|
224
|
+
tag = Tag.get_tag("non-existant")
|
225
|
+
assert_equal(nil, tag)
|
226
|
+
tag = Tag.create_tag("ruby")
|
227
|
+
assert_equal("ruby", tag.name)
|
228
|
+
tag = Tag.create_tag("non-existant")
|
229
|
+
assert_equal("non-existant", tag.name)
|
230
|
+
|
231
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "cult"])
|
232
|
+
assert_equal(red_handed, results.first)
|
233
|
+
assert_equal(1, results.size)
|
234
|
+
$foo = true
|
235
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "framework"])
|
236
|
+
$foo = false
|
237
|
+
assert_equal(ruby_on_rails, results.first)
|
238
|
+
assert_equal(1, results.size)
|
239
|
+
results = Tag.tag_query(:with_any_tags => ["cult", "framework"])
|
240
|
+
assert(results.include?(ruby_on_rails))
|
241
|
+
assert(results.include?(red_handed))
|
242
|
+
assert_equal(2, results.size)
|
243
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "framework"],
|
244
|
+
:without_tags => ["cult"])
|
245
|
+
assert_equal(ruby_on_rails, results.first)
|
246
|
+
assert(!results.include?(red_handed))
|
247
|
+
assert_equal(1, results.size)
|
248
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "framework"],
|
249
|
+
:without_tags => ["cult"], :user_id => some_guy.id)
|
250
|
+
assert_equal(ruby_on_rails, results.first)
|
251
|
+
assert(!results.include?(red_handed))
|
252
|
+
assert_equal(1, results.size)
|
253
|
+
results = Tag.tag_query(:with_all_tags => ["spinach"],
|
254
|
+
:with_any_tags => ["ruby", "cult", "rails", "framework"],
|
255
|
+
:without_tags => ["cult"], :user_id => some_other_guy.id)
|
256
|
+
assert_equal(red_handed, results.first)
|
257
|
+
assert(!results.include?(ruby_on_rails))
|
258
|
+
assert_equal(1, results.size)
|
259
|
+
results = Tag.tag_query(:with_all_tags => ["ruby", "framework"],
|
260
|
+
:without_tags => ["cult"], :user_id => -1)
|
261
|
+
assert_equal(0, results.size)
|
262
|
+
end
|
164
263
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: tagtools
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2005-09-
|
6
|
+
version: 0.0.3
|
7
|
+
date: 2005-09-21 00:00:00 -04:00
|
8
8
|
summary: Folksonomy system for Rails.
|
9
9
|
require_paths:
|
10
10
|
- lib
|