mongoid_taggable_with_context 0.8.1 → 0.8.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/Gemfile +3 -3
- data/VERSION +1 -1
- data/lib/mongoid/taggable_with_context.rb +28 -12
- data/lib/mongoid/taggable_with_context/aggregation_strategy/map_reduce.rb +11 -7
- data/lib/mongoid/taggable_with_context/aggregation_strategy/real_time.rb +65 -15
- data/lib/mongoid/taggable_with_context/group_by/aggregation_strategy/real_time.rb +53 -0
- data/lib/mongoid/taggable_with_context/group_by/taggable_with_context.rb +43 -0
- data/lib/mongoid_taggable_with_context.rb +3 -1
- data/mongoid_taggable_with_context.gemspec +8 -12
- data/spec/mongoid_taggable_with_context_spec.rb +124 -17
- data/spec/spec_helper.rb +2 -2
- metadata +39 -32
data/Gemfile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
source 'http://rubygems.org'
|
2
2
|
|
3
|
-
gem 'mongoid', '>=
|
3
|
+
gem 'mongoid', '>= 3.0.0'
|
4
4
|
|
5
5
|
# Add dependencies to develop your gem here.
|
6
6
|
# Include everything needed to run rake, tests, features, etc.
|
7
7
|
group :development do
|
8
8
|
gem 'database_cleaner'
|
9
|
-
gem 'bson'
|
10
|
-
gem 'bson_ext'
|
9
|
+
#gem 'bson'
|
10
|
+
#gem 'bson_ext'
|
11
11
|
gem 'rspec'
|
12
12
|
gem 'yard'
|
13
13
|
gem 'bundler', '>= 1.0.0'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.8.
|
1
|
+
0.8.2
|
@@ -3,6 +3,8 @@ module Mongoid::TaggableWithContext
|
|
3
3
|
|
4
4
|
class AggregationStrategyMissing < Exception; end
|
5
5
|
|
6
|
+
TAGGABLE_DEFAULT_SEPARATOR = ' '
|
7
|
+
|
6
8
|
included do
|
7
9
|
class_attribute :taggable_with_context_options
|
8
10
|
class_attribute :context_array_to_context_hash
|
@@ -12,6 +14,7 @@ module Mongoid::TaggableWithContext
|
|
12
14
|
delegate "convert_array_to_string", :to => 'self.class'
|
13
15
|
delegate "clean_up_array", :to => 'self.class'
|
14
16
|
delegate "get_tag_separator_for", :to => 'self.class'
|
17
|
+
delegate "format_tags_for_write", :to => 'self.class'
|
15
18
|
delegate "tag_contexts", :to => 'self.class'
|
16
19
|
delegate "tag_options_for", :to => 'self.class'
|
17
20
|
delegate "tag_array_attributes", :to => 'self.class'
|
@@ -45,7 +48,7 @@ module Mongoid::TaggableWithContext
|
|
45
48
|
options = args.extract_options!
|
46
49
|
tags_field = (args.blank? ? :tags : args.shift).to_sym
|
47
50
|
options.reverse_merge!(
|
48
|
-
:separator =>
|
51
|
+
:separator => TAGGABLE_DEFAULT_SEPARATOR,
|
49
52
|
:array_field => "#{tags_field}_array".to_sym
|
50
53
|
)
|
51
54
|
tags_array_field = options[:array_field]
|
@@ -55,8 +58,11 @@ module Mongoid::TaggableWithContext
|
|
55
58
|
self.context_array_to_context_hash[options[:array_field]] = tags_field
|
56
59
|
|
57
60
|
# setup fields & indexes
|
58
|
-
field tags_array_field, :type => Array, :default => []
|
59
|
-
index tags_array_field
|
61
|
+
field tags_array_field, :type => Array, :default => options[:default]
|
62
|
+
# deprecated: index tags_array_field
|
63
|
+
# Invalid index specification on Category: tags_array, {}
|
64
|
+
|
65
|
+
index({ tags_array_field => 1 }, { background: true })
|
60
66
|
|
61
67
|
# singleton methods
|
62
68
|
class_eval <<-END
|
@@ -90,12 +96,10 @@ module Mongoid::TaggableWithContext
|
|
90
96
|
def #{tags_field}
|
91
97
|
convert_array_to_string(#{tags_array_field}, get_tag_separator_for(:"#{tags_field}"))
|
92
98
|
end
|
93
|
-
def #{tags_field}=(
|
94
|
-
write_attribute(:#{tags_array_field},
|
95
|
-
end
|
96
|
-
def #{tags_array_field}=(ary)
|
97
|
-
write_attribute(:#{tags_array_field}, clean_up_array(ary))
|
99
|
+
def #{tags_field}=(value)
|
100
|
+
write_attribute(:#{tags_array_field}, format_tags_for_write(value, get_tag_separator_for(:"#{tags_field}")))
|
98
101
|
end
|
102
|
+
alias_method :#{tags_array_field}=, :#{tags_field}=
|
99
103
|
END
|
100
104
|
end
|
101
105
|
|
@@ -126,7 +130,7 @@ module Mongoid::TaggableWithContext
|
|
126
130
|
end
|
127
131
|
|
128
132
|
def set_tag_separator_for(context, value)
|
129
|
-
self.taggable_with_context_options[context][:separator] = value.nil? ?
|
133
|
+
self.taggable_with_context_options[context][:separator] = value.nil? ? TAGGABLE_DEFAULT_SEPARATOR : value.to_s
|
130
134
|
end
|
131
135
|
|
132
136
|
# Find documents tagged with all tags passed as a parameter, given
|
@@ -146,14 +150,25 @@ module Mongoid::TaggableWithContext
|
|
146
150
|
all_in(array_field => tags)
|
147
151
|
end
|
148
152
|
|
153
|
+
# Helper method to convert a a tag input value of unknown type
|
154
|
+
# to a formatted array.
|
155
|
+
def format_tags_for_write(value, separator = TAGGABLE_DEFAULT_SEPARATOR)
|
156
|
+
if value.is_a? Array
|
157
|
+
clean_up_array(value)
|
158
|
+
else
|
159
|
+
convert_string_to_array(value, separator)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
149
163
|
# Helper method to convert a String to an Array based on the
|
150
164
|
# configured tag separator.
|
151
|
-
def convert_string_to_array(str = "", separator =
|
165
|
+
def convert_string_to_array(str = "", separator = TAGGABLE_DEFAULT_SEPARATOR)
|
152
166
|
clean_up_array(str.split(separator))
|
153
167
|
end
|
154
168
|
|
155
|
-
def convert_array_to_string(ary = [], separator =
|
156
|
-
ary.join(separator)
|
169
|
+
def convert_array_to_string(ary = [], separator = TAGGABLE_DEFAULT_SEPARATOR)
|
170
|
+
#ary.join(separator)
|
171
|
+
(ary || []).join(separator)
|
157
172
|
end
|
158
173
|
|
159
174
|
def clean_up_array(ary = [])
|
@@ -163,5 +178,6 @@ module Mongoid::TaggableWithContext
|
|
163
178
|
# 3). remove duplicate
|
164
179
|
ary.compact.map(&:strip).reject(&:blank?).uniq
|
165
180
|
end
|
181
|
+
|
166
182
|
end
|
167
183
|
end
|
@@ -9,21 +9,25 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
# Collection name for storing results of tag count aggregation
|
12
|
+
|
13
|
+
def aggregation_database_collection_for(context)
|
14
|
+
(@aggregation_database_collection ||= {})[context] ||= Moped::Collection.new(self.collection.database, aggregation_collection_for(context))
|
15
|
+
end
|
16
|
+
|
12
17
|
def aggregation_collection_for(context)
|
13
18
|
"#{collection_name}_#{context}_aggregation"
|
14
19
|
end
|
15
|
-
|
20
|
+
|
16
21
|
def tags_for(context, conditions={})
|
17
|
-
|
18
|
-
db.collection(aggregation_collection_for(context)).find({:value => {"$gt" => 0 }}, conditions).to_a.map{ |t| t["_id"] }
|
22
|
+
aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(_id: 1).to_a.map{ |t| t["_id"] }
|
19
23
|
end
|
20
24
|
|
21
25
|
# retrieve the list of tag with weight(count), this is useful for
|
22
26
|
# creating tag clouds
|
23
27
|
def tags_with_weight_for(context, conditions={})
|
24
|
-
|
25
|
-
db.collection(aggregation_collection_for(context)).find({:value => {"$gt" => 0 }}, conditions).to_a.map{ |t| [t["_id"], t["value"].to_i] }
|
28
|
+
aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(_id: 1).to_a.map{ |t| [t["_id"], t["value"].to_i] }
|
26
29
|
end
|
30
|
+
|
27
31
|
end
|
28
32
|
|
29
33
|
protected
|
@@ -61,7 +65,7 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
61
65
|
}
|
62
66
|
END
|
63
67
|
|
64
|
-
|
68
|
+
self.class.map_reduce(map, reduce).out(replace: aggregation_collection_for(context)).time
|
65
69
|
end
|
66
70
|
end
|
67
|
-
end
|
71
|
+
end
|
@@ -1,57 +1,107 @@
|
|
1
1
|
module Mongoid::TaggableWithContext::AggregationStrategy
|
2
2
|
module RealTime
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
|
4
|
+
|
5
5
|
included do
|
6
6
|
set_callback :save, :after, :update_tags_aggregations_on_save
|
7
7
|
set_callback :destroy, :after, :update_tags_aggregations_on_destroy
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
+
def tag_name_attribute
|
12
|
+
"_id"
|
13
|
+
end
|
14
|
+
|
11
15
|
# Collection name for storing results of tag count aggregation
|
16
|
+
|
17
|
+
def aggregation_database_collection_for(context)
|
18
|
+
(@aggregation_database_collection ||= {})[context] ||= Moped::Collection.new(self.collection.database, aggregation_collection_for(context))
|
19
|
+
end
|
20
|
+
|
12
21
|
def aggregation_collection_for(context)
|
13
22
|
"#{collection_name}_#{context}_aggregation"
|
14
23
|
end
|
15
|
-
|
24
|
+
|
16
25
|
def tags_for(context, conditions={})
|
17
|
-
|
18
|
-
db.collection(aggregation_collection_for(context)).find({:value => {"$gt" => 0 }}, conditions).to_a.map{ |t| t["_id"] }
|
26
|
+
aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(tag_name_attribute.to_sym => 1).to_a.map{ |t| t[tag_name_attribute] }
|
19
27
|
end
|
20
28
|
|
21
29
|
# retrieve the list of tag with weight(count), this is useful for
|
22
30
|
# creating tag clouds
|
23
31
|
def tags_with_weight_for(context, conditions={})
|
24
|
-
|
25
|
-
|
32
|
+
aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }}).sort(tag_name_attribute.to_sym => 1).to_a.map{ |t| [t[tag_name_attribute], t["value"].to_i] }
|
33
|
+
end
|
34
|
+
|
35
|
+
def recalculate_all_context_tag_weights!
|
36
|
+
tag_contexts.each do |context|
|
37
|
+
recalculate_tag_weights!(context)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def recalculate_tag_weights!(context)
|
42
|
+
field = tag_options_for(context)[:array_field]
|
43
|
+
|
44
|
+
map = <<-END
|
45
|
+
function() {
|
46
|
+
if (!this.#{field})return;
|
47
|
+
for (index in this.#{field})
|
48
|
+
emit(this.#{field}[index], 1);
|
49
|
+
}
|
50
|
+
END
|
51
|
+
|
52
|
+
reduce = <<-END
|
53
|
+
function(key, values) {
|
54
|
+
var count = 0;
|
55
|
+
for (index in values) count += values[index];
|
56
|
+
return count;
|
57
|
+
}
|
58
|
+
END
|
59
|
+
|
60
|
+
self.map_reduce(map, reduce).out(replace: aggregation_collection_for(context)).time
|
61
|
+
end
|
62
|
+
|
63
|
+
# adapted from https://github.com/jesuisbonbon/mongoid_taggable/commit/42feddd24dedd66b2b6776f9694d1b5b8bf6903d
|
64
|
+
def tags_autocomplete(context, criteria, options={})
|
65
|
+
result = aggregation_database_collection_for(context).find({tag_name_attribute.to_sym => /^#{criteria}/})
|
66
|
+
result = result.sort(value: -1) if options[:sort_by_count] == true
|
67
|
+
result = result.limit(options[:max]) if options[:max] > 0
|
68
|
+
result.to_a.map{ |r| [r[tag_name_attribute], r["value"]] }
|
26
69
|
end
|
27
70
|
end
|
28
|
-
|
71
|
+
|
29
72
|
protected
|
73
|
+
|
74
|
+
def get_conditions(context, tag)
|
75
|
+
{self.class.tag_name_attribute.to_sym => tag}
|
76
|
+
end
|
30
77
|
|
31
78
|
def update_tags_aggregation(context_array_field, old_tags=[], new_tags=[])
|
32
79
|
context = context_array_to_context_hash[context_array_field]
|
33
|
-
coll = self.class.
|
80
|
+
coll = self.class.aggregation_database_collection_for(context)
|
34
81
|
|
35
82
|
old_tags ||= []
|
36
83
|
new_tags ||= []
|
37
84
|
unchanged_tags = old_tags & new_tags
|
38
85
|
tags_removed = old_tags - unchanged_tags
|
39
86
|
tags_added = new_tags - unchanged_tags
|
87
|
+
|
40
88
|
|
41
89
|
tags_removed.each do |tag|
|
42
|
-
coll.
|
90
|
+
coll.find(get_conditions(context, tag)).upsert({'$inc' => {:value => -1}})
|
43
91
|
end
|
44
|
-
|
45
92
|
tags_added.each do |tag|
|
46
|
-
coll.
|
47
|
-
end
|
93
|
+
coll.find(get_conditions(context, tag)).upsert({'$inc' => {:value => 1}})
|
94
|
+
end
|
95
|
+
#coll.find({_id: {"$in" => tags_removed}}).update({'$inc' => {:value => -1}}, [:upsert])
|
96
|
+
#coll.find({_id: {"$in" => tags_added}}).update({'$inc' => {:value => 1}}, [:upsert])
|
48
97
|
end
|
49
98
|
|
50
99
|
def update_tags_aggregations_on_save
|
100
|
+
indifferent_changes = HashWithIndifferentAccess.new changes
|
51
101
|
tag_array_attributes.each do |context_array|
|
52
|
-
next if
|
102
|
+
next if indifferent_changes[context_array].nil?
|
53
103
|
|
54
|
-
old_tags, new_tags =
|
104
|
+
old_tags, new_tags = indifferent_changes[context_array]
|
55
105
|
update_tags_aggregation(context_array, old_tags, new_tags)
|
56
106
|
end
|
57
107
|
end
|
@@ -64,4 +114,4 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
64
114
|
end
|
65
115
|
end
|
66
116
|
end
|
67
|
-
end
|
117
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Mongoid::TaggableWithContext::GroupBy::AggregationStrategy
|
2
|
+
module RealTime
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include Mongoid::TaggableWithContext::GroupBy::TaggableWithContext
|
5
|
+
include Mongoid::TaggableWithContext::AggregationStrategy::RealTime
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def tag_name_attribute
|
9
|
+
"_name"
|
10
|
+
end
|
11
|
+
|
12
|
+
def tags_for(context, group_by, conditions={})
|
13
|
+
results = if group_by
|
14
|
+
query(context, group_by).to_a.map{ |t| t[tag_name_attribute] }
|
15
|
+
else
|
16
|
+
super(context, conditions)
|
17
|
+
end
|
18
|
+
results.uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
def tags_with_weight_for(context, group_by, conditions={})
|
22
|
+
results = if group_by
|
23
|
+
query(context, group_by).to_a.map{ |t| [t[tag_name_attribute], t["value"].to_i] }
|
24
|
+
else
|
25
|
+
super(context, conditions)
|
26
|
+
end
|
27
|
+
|
28
|
+
tag_hash = {}
|
29
|
+
results.each do |tag, weight|
|
30
|
+
tag_hash[tag] ||= 0
|
31
|
+
tag_hash[tag] += weight
|
32
|
+
end
|
33
|
+
tag_hash.to_a
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
def query(context, group_by)
|
38
|
+
aggregation_database_collection_for(context).find({:value => {"$gt" => 0 }, :group_by_field => group_by}).sort(tag_name_attribute.to_sym => 1)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def get_conditions(context, tag)
|
45
|
+
conditions = {self.class.tag_name_attribute.to_sym => tag}
|
46
|
+
group_by_field = self.class.get_tag_group_by_field_for(context)
|
47
|
+
if group_by_field
|
48
|
+
conditions.merge!({:group_by_field => self.send(group_by_field)})
|
49
|
+
end
|
50
|
+
conditions
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Mongoid::TaggableWithContext::GroupBy
|
2
|
+
module TaggableWithContext
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include Mongoid::TaggableWithContext
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def taggable(*args)
|
8
|
+
super(*args)
|
9
|
+
args.extract_options!
|
10
|
+
tags_field = (args.blank? ? :tags : args.shift).to_sym
|
11
|
+
self.taggable_with_context_options[tags_field].reverse_merge!(:group_by_field => nil)
|
12
|
+
|
13
|
+
class_eval <<-END
|
14
|
+
class << self
|
15
|
+
def #{tags_field}(group_by=nil)
|
16
|
+
tags_for(:"#{tags_field}", group_by)
|
17
|
+
end
|
18
|
+
|
19
|
+
def #{tags_field}_with_weight(group_by=nil)
|
20
|
+
tags_with_weight_for(:"#{tags_field}", group_by)
|
21
|
+
end
|
22
|
+
|
23
|
+
def #{tags_field}_group_by_field
|
24
|
+
get_tag_group_by_field_for(:"#{tags_field}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
END
|
28
|
+
end
|
29
|
+
|
30
|
+
def tags_for(context, group_by, conditions={})
|
31
|
+
raise AggregationStrategyMissing
|
32
|
+
end
|
33
|
+
|
34
|
+
def tags_with_weight_for(context, group_by, conditions={})
|
35
|
+
raise AggregationStrategyMissing
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_tag_group_by_field_for(context)
|
39
|
+
self.taggable_with_context_options[context][:group_by_field]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -2,4 +2,6 @@ require 'active_support/concern'
|
|
2
2
|
|
3
3
|
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context')
|
4
4
|
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/aggregation_strategy/map_reduce')
|
5
|
-
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/aggregation_strategy/real_time')
|
5
|
+
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/aggregation_strategy/real_time')
|
6
|
+
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/group_by/taggable_with_context')
|
7
|
+
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/group_by/aggregation_strategy/real_time')
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "mongoid_taggable_with_context"
|
8
|
-
s.version = "0.8.
|
8
|
+
s.version = "0.8.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Aaron Qian"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-09-01"
|
13
13
|
s.description = "It provides some helpers to create taggable documents with context."
|
14
14
|
s.email = "aq1018@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -28,6 +28,8 @@ Gem::Specification.new do |s|
|
|
28
28
|
"lib/mongoid/taggable_with_context.rb",
|
29
29
|
"lib/mongoid/taggable_with_context/aggregation_strategy/map_reduce.rb",
|
30
30
|
"lib/mongoid/taggable_with_context/aggregation_strategy/real_time.rb",
|
31
|
+
"lib/mongoid/taggable_with_context/group_by/aggregation_strategy/real_time.rb",
|
32
|
+
"lib/mongoid/taggable_with_context/group_by/taggable_with_context.rb",
|
31
33
|
"lib/mongoid_taggable_with_context.rb",
|
32
34
|
"mongoid_taggable_with_context.gemspec",
|
33
35
|
"spec/mongoid_taggable_with_context_spec.rb",
|
@@ -36,7 +38,7 @@ Gem::Specification.new do |s|
|
|
36
38
|
s.homepage = "http://github.com/aq1018/mongoid_taggable_with_context"
|
37
39
|
s.licenses = ["MIT"]
|
38
40
|
s.require_paths = ["lib"]
|
39
|
-
s.rubygems_version = "1.8.
|
41
|
+
s.rubygems_version = "1.8.24"
|
40
42
|
s.summary = "Mongoid taggable behaviour"
|
41
43
|
s.test_files = [
|
42
44
|
"spec/mongoid_taggable_with_context_spec.rb",
|
@@ -47,29 +49,23 @@ Gem::Specification.new do |s|
|
|
47
49
|
s.specification_version = 3
|
48
50
|
|
49
51
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
-
s.add_runtime_dependency(%q<mongoid>, [">=
|
52
|
+
s.add_runtime_dependency(%q<mongoid>, [">= 3.0.0"])
|
51
53
|
s.add_development_dependency(%q<database_cleaner>, [">= 0"])
|
52
|
-
s.add_development_dependency(%q<bson>, [">= 0"])
|
53
|
-
s.add_development_dependency(%q<bson_ext>, [">= 0"])
|
54
54
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
55
55
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
56
56
|
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
57
57
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
58
58
|
else
|
59
|
-
s.add_dependency(%q<mongoid>, [">=
|
59
|
+
s.add_dependency(%q<mongoid>, [">= 3.0.0"])
|
60
60
|
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
61
|
-
s.add_dependency(%q<bson>, [">= 0"])
|
62
|
-
s.add_dependency(%q<bson_ext>, [">= 0"])
|
63
61
|
s.add_dependency(%q<rspec>, [">= 0"])
|
64
62
|
s.add_dependency(%q<yard>, [">= 0"])
|
65
63
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
66
64
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
67
65
|
end
|
68
66
|
else
|
69
|
-
s.add_dependency(%q<mongoid>, [">=
|
67
|
+
s.add_dependency(%q<mongoid>, [">= 3.0.0"])
|
70
68
|
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
71
|
-
s.add_dependency(%q<bson>, [">= 0"])
|
72
|
-
s.add_dependency(%q<bson_ext>, [">= 0"])
|
73
69
|
s.add_dependency(%q<rspec>, [">= 0"])
|
74
70
|
s.add_dependency(%q<yard>, [">= 0"])
|
75
71
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
@@ -6,6 +6,7 @@ class MyModel
|
|
6
6
|
|
7
7
|
taggable
|
8
8
|
taggable :artists
|
9
|
+
taggable :albums, :default => []
|
9
10
|
end
|
10
11
|
|
11
12
|
class M1
|
@@ -26,7 +27,31 @@ class M2
|
|
26
27
|
taggable :artists
|
27
28
|
end
|
28
29
|
|
30
|
+
class M3
|
31
|
+
include Mongoid::Document
|
32
|
+
include Mongoid::TaggableWithContext::GroupBy::AggregationStrategy::RealTime
|
33
|
+
|
34
|
+
field :user
|
35
|
+
taggable :group_by_field => :user
|
36
|
+
taggable :artists, :group_by_field => :user
|
37
|
+
end
|
38
|
+
|
29
39
|
describe Mongoid::TaggableWithContext do
|
40
|
+
|
41
|
+
context "default field value" do
|
42
|
+
before :each do
|
43
|
+
@m = MyModel.new
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should be nil for artists" do
|
47
|
+
@m.changes['artists'].should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be array for albums" do
|
51
|
+
@m.changes['albums_array'].should eql([nil, []])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
30
55
|
context "saving tags from plain text" do
|
31
56
|
before :each do
|
32
57
|
@m = MyModel.new
|
@@ -63,12 +88,12 @@ describe Mongoid::TaggableWithContext do
|
|
63
88
|
end
|
64
89
|
|
65
90
|
it "should remove repeated tags from array" do
|
66
|
-
@m.
|
91
|
+
@m.tags = %w[some new tags some new tags]
|
67
92
|
@m.tags.should == "some new tags"
|
68
93
|
end
|
69
94
|
|
70
95
|
it "should remove nil tags from array" do
|
71
|
-
@m.
|
96
|
+
@m.tags = ["some", nil, "new", nil, "tags"]
|
72
97
|
@m.tags.should == "some new tags"
|
73
98
|
end
|
74
99
|
end
|
@@ -79,17 +104,28 @@ describe Mongoid::TaggableWithContext do
|
|
79
104
|
end
|
80
105
|
|
81
106
|
it "should remove repeated tags from array" do
|
82
|
-
@m.
|
83
|
-
@m.tags_array == %w[some new tags]
|
107
|
+
@m.tags = %w[some new tags some new tags]
|
108
|
+
@m.tags_array.should == %w[some new tags]
|
84
109
|
end
|
85
110
|
|
86
111
|
it "should remove nil tags from array" do
|
87
|
-
@m.
|
112
|
+
@m.tags = ["some", nil, "new", nil, "tags"]
|
88
113
|
@m.tags_array.should == %w[some new tags]
|
89
114
|
end
|
90
115
|
|
91
116
|
it "should remove empty strings from array" do
|
92
|
-
@m.
|
117
|
+
@m.tags = ["some", "", "new", "", "tags"]
|
118
|
+
@m.tags_array.should == %w[some new tags]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "saving tags from array using tags_array alias method" do
|
123
|
+
before :each do
|
124
|
+
@m = MyModel.new
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should remove nil tags from array" do
|
128
|
+
@m.tags_array = ["some", nil, "new", nil, "tags"]
|
93
129
|
@m.tags_array.should == %w[some new tags]
|
94
130
|
end
|
95
131
|
end
|
@@ -143,12 +179,22 @@ describe Mongoid::TaggableWithContext do
|
|
143
179
|
end
|
144
180
|
|
145
181
|
shared_examples_for "aggregation" do
|
146
|
-
context "
|
182
|
+
context "retrieving index" do
|
183
|
+
context "when there's no tags'" do
|
184
|
+
it "should return an empty array" do
|
185
|
+
klass.tags.should == []
|
186
|
+
klass.artists.should == []
|
187
|
+
|
188
|
+
klass.tags_with_weight.should == []
|
189
|
+
klass.artists_with_weight == []
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
147
193
|
context "on create directly" do
|
148
194
|
before :each do
|
149
|
-
klass.create!(:tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
|
150
|
-
klass.create!(:tags => "juice food bee zip", :artists => "grant andrew andy")
|
151
|
-
klass.create!(:tags => "honey strip food", :artists => "mandy aaron andy")
|
195
|
+
klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
|
196
|
+
klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
|
197
|
+
klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
|
152
198
|
end
|
153
199
|
|
154
200
|
it "should retrieve the list of all saved tags distinct and ordered" do
|
@@ -227,9 +273,9 @@ describe Mongoid::TaggableWithContext do
|
|
227
273
|
|
228
274
|
context "on create then update" do
|
229
275
|
before :each do
|
230
|
-
m1 = klass.create!(:tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
|
231
|
-
m2 = klass.create!(:tags => "juice food bee zip", :artists => "grant andrew andy")
|
232
|
-
m3 = klass.create!(:tags => "honey strip food", :artists => "mandy aaron andy")
|
276
|
+
m1 = klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
|
277
|
+
m2 = klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
|
278
|
+
m3 = klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
|
233
279
|
|
234
280
|
m1.tags_array = m1.tags_array + %w[honey strip shoe]
|
235
281
|
m1.save!
|
@@ -270,9 +316,9 @@ describe Mongoid::TaggableWithContext do
|
|
270
316
|
|
271
317
|
context "on create, update, then destroy" do
|
272
318
|
before :each do
|
273
|
-
m1 = klass.create!(:tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
|
274
|
-
m2 = klass.create!(:tags => "juice food bee zip", :artists => "grant andrew andy")
|
275
|
-
m3 = klass.create!(:tags => "honey strip food", :artists => "mandy aaron andy")
|
319
|
+
m1 = klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
|
320
|
+
m2 = klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
|
321
|
+
m3 = klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
|
276
322
|
|
277
323
|
m1.tags_array = m1.tags_array + %w[honey strip shoe] - %w[food]
|
278
324
|
m1.save!
|
@@ -337,4 +383,65 @@ describe Mongoid::TaggableWithContext do
|
|
337
383
|
klass.aggregation_collection_for(:artists).should == "m2s_artists_aggregation"
|
338
384
|
end
|
339
385
|
end
|
340
|
-
|
386
|
+
|
387
|
+
context "realtime aggregation group by" do
|
388
|
+
let(:klass) { M3 }
|
389
|
+
it_should_behave_like "aggregation"
|
390
|
+
|
391
|
+
it "should generate the tags aggregation collection name correctly" do
|
392
|
+
klass.aggregation_collection_for(:tags).should == "m3s_tags_aggregation"
|
393
|
+
end
|
394
|
+
|
395
|
+
it "should generate the artists aggregation collection name correctly" do
|
396
|
+
klass.aggregation_collection_for(:artists).should == "m3s_artists_aggregation"
|
397
|
+
end
|
398
|
+
|
399
|
+
context "for groupings" do
|
400
|
+
before :each do
|
401
|
+
klass.create!(:user => "user1", :tags => "food ant bee", :artists => "jeff greg mandy aaron andy")
|
402
|
+
klass.create!(:user => "user1", :tags => "juice food bee zip", :artists => "grant andrew andy")
|
403
|
+
klass.create!(:user => "user2", :tags => "honey strip food", :artists => "mandy aaron andy")
|
404
|
+
end
|
405
|
+
|
406
|
+
it "should retrieve the list of all saved tags distinct and ordered" do
|
407
|
+
klass.tags("user1").should == %w[ant bee food juice zip]
|
408
|
+
klass.tags("user2").should == %w[food honey strip]
|
409
|
+
|
410
|
+
klass.artists("user1").should == %w[aaron andrew andy grant greg jeff mandy]
|
411
|
+
klass.artists("user2").should == %w[aaron andy mandy]
|
412
|
+
end
|
413
|
+
|
414
|
+
it "should retrieve a list of tags with weight" do
|
415
|
+
klass.tags_with_weight("user1").should == [
|
416
|
+
['ant', 1],
|
417
|
+
['bee', 2],
|
418
|
+
['food', 2],
|
419
|
+
['juice', 1],
|
420
|
+
['zip', 1]
|
421
|
+
]
|
422
|
+
|
423
|
+
klass.tags_with_weight("user2").should == [
|
424
|
+
['food', 1],
|
425
|
+
['honey', 1],
|
426
|
+
['strip', 1]
|
427
|
+
]
|
428
|
+
|
429
|
+
klass.artists_with_weight("user1").should == [
|
430
|
+
['aaron', 1],
|
431
|
+
['andrew', 1],
|
432
|
+
['andy', 2],
|
433
|
+
['grant', 1],
|
434
|
+
['greg', 1],
|
435
|
+
['jeff', 1],
|
436
|
+
['mandy', 1]
|
437
|
+
]
|
438
|
+
|
439
|
+
klass.artists_with_weight("user2").should == [
|
440
|
+
['aaron', 1],
|
441
|
+
['andy', 1],
|
442
|
+
['mandy', 1]
|
443
|
+
]
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_taggable_with_context
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,27 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: mongoid
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 3.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.0.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: database_cleaner
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,21 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: bson
|
38
|
-
requirement: &22100100 !ruby/object:Gem::Requirement
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
41
|
none: false
|
40
42
|
requirements:
|
41
43
|
- - ! '>='
|
42
44
|
- !ruby/object:Gem::Version
|
43
45
|
version: '0'
|
44
|
-
type: :development
|
45
|
-
prerelease: false
|
46
|
-
version_requirements: *22100100
|
47
46
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
49
|
-
requirement:
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
50
49
|
none: false
|
51
50
|
requirements:
|
52
51
|
- - ! '>='
|
@@ -54,21 +53,15 @@ dependencies:
|
|
54
53
|
version: '0'
|
55
54
|
type: :development
|
56
55
|
prerelease: false
|
57
|
-
version_requirements:
|
58
|
-
- !ruby/object:Gem::Dependency
|
59
|
-
name: rspec
|
60
|
-
requirement: &22097660 !ruby/object:Gem::Requirement
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
57
|
none: false
|
62
58
|
requirements:
|
63
59
|
- - ! '>='
|
64
60
|
- !ruby/object:Gem::Version
|
65
61
|
version: '0'
|
66
|
-
type: :development
|
67
|
-
prerelease: false
|
68
|
-
version_requirements: *22097660
|
69
62
|
- !ruby/object:Gem::Dependency
|
70
63
|
name: yard
|
71
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
72
65
|
none: false
|
73
66
|
requirements:
|
74
67
|
- - ! '>='
|
@@ -76,10 +69,15 @@ dependencies:
|
|
76
69
|
version: '0'
|
77
70
|
type: :development
|
78
71
|
prerelease: false
|
79
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
80
78
|
- !ruby/object:Gem::Dependency
|
81
79
|
name: bundler
|
82
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
83
81
|
none: false
|
84
82
|
requirements:
|
85
83
|
- - ! '>='
|
@@ -87,10 +85,15 @@ dependencies:
|
|
87
85
|
version: 1.0.0
|
88
86
|
type: :development
|
89
87
|
prerelease: false
|
90
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.0.0
|
91
94
|
- !ruby/object:Gem::Dependency
|
92
95
|
name: jeweler
|
93
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
94
97
|
none: false
|
95
98
|
requirements:
|
96
99
|
- - ! '>='
|
@@ -98,7 +101,12 @@ dependencies:
|
|
98
101
|
version: '0'
|
99
102
|
type: :development
|
100
103
|
prerelease: false
|
101
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
102
110
|
description: It provides some helpers to create taggable documents with context.
|
103
111
|
email: aq1018@gmail.com
|
104
112
|
executables: []
|
@@ -118,6 +126,8 @@ files:
|
|
118
126
|
- lib/mongoid/taggable_with_context.rb
|
119
127
|
- lib/mongoid/taggable_with_context/aggregation_strategy/map_reduce.rb
|
120
128
|
- lib/mongoid/taggable_with_context/aggregation_strategy/real_time.rb
|
129
|
+
- lib/mongoid/taggable_with_context/group_by/aggregation_strategy/real_time.rb
|
130
|
+
- lib/mongoid/taggable_with_context/group_by/taggable_with_context.rb
|
121
131
|
- lib/mongoid_taggable_with_context.rb
|
122
132
|
- mongoid_taggable_with_context.gemspec
|
123
133
|
- spec/mongoid_taggable_with_context_spec.rb
|
@@ -135,9 +145,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
145
|
- - ! '>='
|
136
146
|
- !ruby/object:Gem::Version
|
137
147
|
version: '0'
|
138
|
-
segments:
|
139
|
-
- 0
|
140
|
-
hash: -3234920624644795753
|
141
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
149
|
none: false
|
143
150
|
requirements:
|
@@ -146,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
153
|
version: '0'
|
147
154
|
requirements: []
|
148
155
|
rubyforge_project:
|
149
|
-
rubygems_version: 1.8.
|
156
|
+
rubygems_version: 1.8.24
|
150
157
|
signing_key:
|
151
158
|
specification_version: 3
|
152
159
|
summary: Mongoid taggable behaviour
|