mongoid_taggable_with_context 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +58 -31
- data/Rakefile +11 -13
- data/lib/mongoid/taggable_with_context.rb +76 -94
- data/lib/mongoid/taggable_with_context/aggregation_strategy/map_reduce.rb +10 -10
- data/lib/mongoid/taggable_with_context/aggregation_strategy/real_time.rb +7 -8
- data/lib/mongoid/taggable_with_context/group_by/aggregation_strategy/real_time.rb +2 -2
- data/lib/mongoid/taggable_with_context/group_by/taggable_with_context.rb +13 -14
- data/lib/mongoid/taggable_with_context/version.rb +6 -0
- data/lib/mongoid_taggable_with_context.rb +2 -1
- data/mongoid_taggable_with_context.gemspec +6 -11
- data/spec/mongoid_taggable_with_context_spec.rb +44 -43
- metadata +26 -39
- data/VERSION +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 44ee2f3be92cc68b84183d7f2a192da8e71421c2
|
4
|
+
data.tar.gz: ec2e8f34ce303a3713d8fdda04bc1f3a61c33181
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b62f2358559426336e8bdc989ef7230b54483a50f128a4634afe9126325ea0f51c3de56bb940dcfc48fbeca083b21952c9652566b5d2b20a40288a19218a12f
|
7
|
+
data.tar.gz: 1ae4c6c1ff1bb80011a61275d9f9945b7564a7d2270570ee86bbf9007a457ca56d52f66ee2be7b707cfb74e3a428c3aeb82245545c3966a11b8a9fb4f8f45901
|
data/README.md
CHANGED
@@ -28,10 +28,51 @@ or in Gemfile:
|
|
28
28
|
gem 'mongoid_taggable_with_context'
|
29
29
|
```
|
30
30
|
|
31
|
-
Basic Usage
|
32
|
-
-----------
|
33
31
|
|
34
|
-
|
32
|
+
The "taggable" Macro Function
|
33
|
+
-----------------------------
|
34
|
+
|
35
|
+
Use the `taggable` macro function in your model to
|
36
|
+
declare a tags field. Specify `field name`
|
37
|
+
for tags, and `options` for tagging behavior.
|
38
|
+
|
39
|
+
Example:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
class Article
|
43
|
+
include Mongoid::Document
|
44
|
+
include Mongoid::TaggableWithContext
|
45
|
+
taggable :keywords, separator: ' ', default: ['foobar']
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
* `@param [ Symbol ] field`
|
50
|
+
|
51
|
+
(Optional) The name of the field for tags. Defaults to "tags"
|
52
|
+
|
53
|
+
|
54
|
+
* `@param [ Hash ] options`
|
55
|
+
|
56
|
+
(Optional) Options for taggable behavior.
|
57
|
+
|
58
|
+
|
59
|
+
* `@option [ String ] :separator`
|
60
|
+
|
61
|
+
The delimiter used when converting the tags to and from String format. Defaults to " "
|
62
|
+
|
63
|
+
|
64
|
+
* `@option [ <various> ] :default, :as, :localize, etc.`
|
65
|
+
|
66
|
+
Options for Mongoid #field method will be automatically passed
|
67
|
+
to the underlying Array field (with the exception of `:type`,
|
68
|
+
which is coerced to `Array`).
|
69
|
+
|
70
|
+
|
71
|
+
Example Usage
|
72
|
+
-------------
|
73
|
+
|
74
|
+
To make a document taggable you need to include Mongoid::TaggableOnContext
|
75
|
+
into your document and call the *taggable* macro with optional arguments:
|
35
76
|
|
36
77
|
```ruby
|
37
78
|
class Post
|
@@ -49,15 +90,15 @@ class Post
|
|
49
90
|
# #tags_string method returns a separated string
|
50
91
|
taggable
|
51
92
|
|
52
|
-
# tagging for 'interests' context.
|
53
|
-
# This creates #interests, #interests=, #interests_string instance methods
|
54
|
-
# The tags will be persisted in a database field called 'interest_array'
|
55
|
-
taggable :interests, :field => :interest_array
|
56
|
-
|
57
93
|
# tagging for 'skills' context.
|
58
|
-
# This creates #skills, #skills=, #
|
94
|
+
# This creates #skills, #skills=, #skills_string instance methods
|
59
95
|
# changing tag separator to "," (Default is " ")
|
60
|
-
taggable :skills, :
|
96
|
+
taggable :skills, separator: ','
|
97
|
+
|
98
|
+
# aliased context tagging.
|
99
|
+
# This creates #interests, #interests=, #interests_string instance methods
|
100
|
+
# The tags will be stored in a database field called 'ints'
|
101
|
+
taggable :ints, as: :interests
|
61
102
|
end
|
62
103
|
```
|
63
104
|
|
@@ -91,6 +132,7 @@ Then in your form, for example:
|
|
91
132
|
<% end %>
|
92
133
|
```
|
93
134
|
|
135
|
+
|
94
136
|
Aggregation Strategies
|
95
137
|
----------------------
|
96
138
|
|
@@ -117,8 +159,8 @@ class Post
|
|
117
159
|
field :content
|
118
160
|
|
119
161
|
taggable
|
120
|
-
taggable :
|
121
|
-
taggable :
|
162
|
+
taggable :skills, separator: ','
|
163
|
+
taggable :ints, as: interests
|
122
164
|
end
|
123
165
|
```
|
124
166
|
|
@@ -137,9 +179,9 @@ Post.skills_with_weight
|
|
137
179
|
Here is how to use these methods in more detail:
|
138
180
|
|
139
181
|
```ruby
|
140
|
-
Post.create!(:
|
141
|
-
Post.create!(:
|
142
|
-
Post.create!(:
|
182
|
+
Post.create!(tags: "food,ant,bee")
|
183
|
+
Post.create!(tags: "juice,food,bee,zip")
|
184
|
+
Post.create!(tags: "honey,strip,food")
|
143
185
|
|
144
186
|
Post.tags # will retrieve ["ant", "bee", "food", "honey", "juice", "strip", "zip"]
|
145
187
|
Post.tags_with_weight # will retrieve:
|
@@ -154,22 +196,6 @@ Post.tags_with_weight # will retrieve:
|
|
154
196
|
# ]
|
155
197
|
```
|
156
198
|
|
157
|
-
Changing default separator
|
158
|
-
--------------------------
|
159
|
-
|
160
|
-
To change the default separator you may pass a *separator* argument to the macro:
|
161
|
-
|
162
|
-
```ruby
|
163
|
-
class Post
|
164
|
-
include Mongoid::Document
|
165
|
-
include Mongoid::TaggableWithContext
|
166
|
-
|
167
|
-
field :title
|
168
|
-
field :content
|
169
|
-
|
170
|
-
taggable :separator => ',' # tags will be delineated by comma instead of space
|
171
|
-
end
|
172
|
-
```
|
173
199
|
|
174
200
|
Contributing to mongoid_taggable_with_context
|
175
201
|
-----------------------------------------------
|
@@ -182,6 +208,7 @@ Contributing to mongoid_taggable_with_context
|
|
182
208
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
183
209
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
184
210
|
|
211
|
+
|
185
212
|
Copyright
|
186
213
|
---------
|
187
214
|
|
data/Rakefile
CHANGED
@@ -1,23 +1,21 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler'
|
3
|
-
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'rake'
|
3
|
+
Bundler.setup
|
11
4
|
|
5
|
+
require 'rake'
|
12
6
|
require 'jeweler'
|
7
|
+
|
8
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
9
|
+
require 'mongoid/taggable_with_context/version'
|
10
|
+
|
13
11
|
Jeweler::Tasks.new do |gem|
|
14
12
|
gem.name = "mongoid_taggable_with_context"
|
15
|
-
gem.homepage = "http://github.com/
|
13
|
+
gem.homepage = "http://github.com/lgs/mongoid_taggable_with_context"
|
16
14
|
gem.license = "MIT"
|
17
15
|
gem.summary = %Q{Mongoid taggable behaviour}
|
18
|
-
gem.description = %Q{
|
19
|
-
gem.
|
20
|
-
gem.
|
16
|
+
gem.description = %Q{Add multiple tag fields on Mongoid documents with aggregation capability.}
|
17
|
+
gem.authors = ["Aaron Qian", "Luca G. Soave", "John Shields", "Wilker Lucio", "Ches Martin"]
|
18
|
+
gem.version = Mongoid::TaggableWithContext::VERSION
|
21
19
|
end
|
22
20
|
Jeweler::RubygemsDotOrgTasks.new
|
23
21
|
|
@@ -28,7 +26,7 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
28
26
|
spec.rspec_opts = "--color --format progress"
|
29
27
|
end
|
30
28
|
|
31
|
-
task :
|
29
|
+
task default: :spec
|
32
30
|
|
33
31
|
require 'yard'
|
34
32
|
YARD::Rake::YardocTask.new
|
@@ -2,23 +2,18 @@ module Mongoid::TaggableWithContext
|
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
4
|
class AggregationStrategyMissing < Exception; end
|
5
|
+
class InvalidTagsFormat < Exception; end
|
5
6
|
|
6
|
-
|
7
|
+
DEFAULT_FIELD = :tags
|
8
|
+
DEFAULT_SEPARATOR = ' '
|
7
9
|
|
8
10
|
included do
|
9
11
|
class_attribute :taggable_with_context_options
|
10
|
-
class_attribute :database_field_to_context_hash
|
11
12
|
self.taggable_with_context_options = {}
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
delegate "get_tag_separator_for", :to => 'self.class'
|
17
|
-
delegate "format_tags_for_write", :to => 'self.class'
|
18
|
-
delegate "tag_contexts", :to => 'self.class'
|
19
|
-
delegate "tag_options_for", :to => 'self.class'
|
20
|
-
delegate "tag_database_fields", :to => 'self.class'
|
21
|
-
delegate "database_field_to_context_hash", :to => 'self.class'
|
13
|
+
end
|
14
|
+
|
15
|
+
def tags_string_for(context)
|
16
|
+
self.read_attribute(context).join(self.class.get_tag_separator_for(context))
|
22
17
|
end
|
23
18
|
|
24
19
|
module ClassMethods
|
@@ -29,85 +24,82 @@ module Mongoid::TaggableWithContext
|
|
29
24
|
#
|
30
25
|
# class Article
|
31
26
|
# include Mongoid::Document
|
32
|
-
# include Mongoid::
|
33
|
-
# taggable :keywords, :
|
27
|
+
# include Mongoid::TaggableWithContext
|
28
|
+
# taggable :keywords, separator: ' ', default: ['foobar']
|
34
29
|
# end
|
35
30
|
#
|
36
31
|
# @param [ Symbol ] field The name of the field for tags.
|
37
32
|
# @param [ Hash ] options Options for taggable behavior.
|
38
33
|
#
|
39
|
-
# @option options [ String ] :separator
|
40
|
-
#
|
41
|
-
# @option options [
|
42
|
-
#
|
43
|
-
#
|
44
|
-
# @option options [ String ] :default_type The default type of the tag.
|
45
|
-
# Each tag can optionally have a tag type. The default type is nil
|
34
|
+
# @option options [ String ] :separator
|
35
|
+
# The delimiter used when converting the tags to and from String format. Defaults to ' '
|
36
|
+
# @option options [ <various> ] :default, :as, :localize, etc.
|
37
|
+
# Options for Mongoid #field method will be automatically passed
|
38
|
+
# to the underlying Array field
|
46
39
|
def taggable(*args)
|
47
40
|
# init variables
|
48
41
|
options = args.extract_options!
|
49
|
-
|
50
|
-
options
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
|
43
|
+
raise 'taggable :field option has been removed as of version 1.1.0. Please use the syntax "taggable <database_name>, as: <tag_name>"' if options[:field]
|
44
|
+
raise 'taggable :string_method option has been removed as of version 1.1.0. Please define an alias to "<tags>_string"' if options[:string_method]
|
45
|
+
|
46
|
+
# db_field: the field name stored in the database
|
47
|
+
options[:db_field] = args.present? ? args.shift.to_sym : DEFAULT_FIELD
|
48
|
+
|
49
|
+
# field: the field name used to identify the tags. :field will
|
50
|
+
# be identical to :db_field unless the :as option is specified
|
51
|
+
options[:field] = options[:as] || options[:db_field]
|
52
|
+
|
53
|
+
options.reverse_merge!(separator: DEFAULT_SEPARATOR)
|
56
54
|
|
57
55
|
# register / update settings
|
58
|
-
self.taggable_with_context_options[
|
59
|
-
self.database_field_to_context_hash[database_field] = tags_name
|
56
|
+
self.taggable_with_context_options[options[:field]] = options
|
60
57
|
|
61
58
|
# setup fields & indexes
|
62
|
-
field
|
59
|
+
field options[:db_field], mongoid_field_options(options)
|
63
60
|
|
64
|
-
index({
|
61
|
+
index({ options[:field] => 1 }, { background: true })
|
65
62
|
|
66
63
|
# singleton methods
|
67
|
-
class_eval
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
set_tag_separator_for(:"#{tags_name}", value)
|
85
|
-
end
|
86
|
-
|
87
|
-
def #{tags_name}_tagged_with(tags)
|
88
|
-
tagged_with(:"#{tags_name}", tags)
|
89
|
-
end
|
64
|
+
self.class.class_eval do
|
65
|
+
# retrieve all tags ever created for the model
|
66
|
+
define_method options[:field] do
|
67
|
+
tags_for(options[:field])
|
68
|
+
end
|
69
|
+
|
70
|
+
# retrieve all tags ever created for the model with weights
|
71
|
+
define_method :"#{options[:field]}_with_weight" do
|
72
|
+
tags_with_weight_for(options[:field])
|
73
|
+
end
|
74
|
+
|
75
|
+
define_method :"#{options[:field]}_separator" do
|
76
|
+
get_tag_separator_for(options[:field])
|
77
|
+
end
|
78
|
+
|
79
|
+
define_method :"#{options[:field]}_tagged_with" do |tags|
|
80
|
+
tagged_with(options[:field], tags)
|
90
81
|
end
|
91
|
-
|
82
|
+
end
|
92
83
|
|
93
|
-
#
|
94
|
-
class_eval
|
95
|
-
|
96
|
-
|
84
|
+
#instance methods
|
85
|
+
class_eval do
|
86
|
+
define_method :"#{options[:field]}_string" do
|
87
|
+
tags_string_for(options[:field])
|
97
88
|
end
|
98
|
-
|
99
|
-
|
89
|
+
|
90
|
+
define_method :"#{options[:field]}=" do |value|
|
91
|
+
write_attribute(options[:field], self.class.format_tags_for(options[:field], value))
|
100
92
|
end
|
101
|
-
|
93
|
+
end
|
102
94
|
end
|
103
95
|
|
104
96
|
def tag_contexts
|
105
97
|
self.taggable_with_context_options.keys
|
106
98
|
end
|
107
|
-
|
99
|
+
|
108
100
|
def tag_database_fields
|
109
101
|
self.taggable_with_context_options.keys.map do |context|
|
110
|
-
tag_options_for(context)[:
|
102
|
+
tag_options_for(context)[:db_field]
|
111
103
|
end
|
112
104
|
end
|
113
105
|
|
@@ -127,9 +119,6 @@ module Mongoid::TaggableWithContext
|
|
127
119
|
self.taggable_with_context_options[context][:separator]
|
128
120
|
end
|
129
121
|
|
130
|
-
def set_tag_separator_for(context, value)
|
131
|
-
self.taggable_with_context_options[context][:separator] = value.nil? ? TAGGABLE_DEFAULT_SEPARATOR : value.to_s
|
132
|
-
end
|
133
122
|
|
134
123
|
# Find documents tagged with all tags passed as a parameter, given
|
135
124
|
# as an Array or a String using the configured separator.
|
@@ -143,39 +132,32 @@ module Mongoid::TaggableWithContext
|
|
143
132
|
# @param [ Array<String, Symbol>, String ] :tags Tags to match.
|
144
133
|
# @return [ Criteria ] A new criteria.
|
145
134
|
def tagged_with(context, tags)
|
146
|
-
tags =
|
147
|
-
|
148
|
-
all_in(
|
135
|
+
tags = format_tags_for(context, tags)
|
136
|
+
field = tag_options_for(context)[:field]
|
137
|
+
all_in(field => tags)
|
149
138
|
end
|
150
139
|
|
151
140
|
# Helper method to convert a a tag input value of unknown type
|
152
141
|
# to a formatted array.
|
153
|
-
def
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
142
|
+
def format_tags_for(context, value)
|
143
|
+
# 0) Tags must be an array or a string
|
144
|
+
raise InvalidTagsFormat unless value.is_a?(Array) || value.is_a?(String)
|
145
|
+
# 1) convert String to Array
|
146
|
+
value = value.split(get_tag_separator_for(context)) if value.is_a? String
|
147
|
+
# 2) remove all nil values
|
148
|
+
# 3) strip all white spaces. Could leave blank strings (e.g. foo, , bar, baz)
|
149
|
+
# 4) remove all blank strings
|
150
|
+
# 5) remove duplicate
|
151
|
+
value.compact.map(&:strip).reject(&:blank?).uniq
|
159
152
|
end
|
160
153
|
|
161
|
-
|
162
|
-
# configured tag separator.
|
163
|
-
def convert_string_to_array(str = "", separator = TAGGABLE_DEFAULT_SEPARATOR)
|
164
|
-
clean_up_array(str.split(separator))
|
165
|
-
end
|
154
|
+
protected
|
166
155
|
|
167
|
-
|
168
|
-
|
169
|
-
|
156
|
+
# Prepares valid Mongoid option keys from the taggable options
|
157
|
+
# @param [ Hash ] :options The taggable options hash.
|
158
|
+
# @return [ Hash ] A options hash for the Mongoid #field method.
|
159
|
+
def mongoid_field_options(options = {})
|
160
|
+
options.slice(*::Mongoid::Fields::Validators::Macro::OPTIONS).merge!(type: Array)
|
170
161
|
end
|
171
|
-
|
172
|
-
def clean_up_array(ary = [])
|
173
|
-
# 0). remove all nil values
|
174
|
-
# 1). strip all white spaces. Could leave blank strings (e.g. foo, , bar, baz)
|
175
|
-
# 2). remove all blank strings
|
176
|
-
# 3). remove duplicate
|
177
|
-
ary.compact.map(&:strip).reject(&:blank?).uniq
|
178
|
-
end
|
179
|
-
|
180
162
|
end
|
181
163
|
end
|
@@ -2,9 +2,9 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
2
2
|
module MapReduce
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
included do
|
5
|
-
set_callback :save, :after, :map_reduce_all_contexts!, :
|
5
|
+
set_callback :save, :after, :map_reduce_all_contexts!, if: :tags_changed?
|
6
6
|
set_callback :destroy, :after, :map_reduce_all_contexts!
|
7
|
-
delegate :aggregation_collection_for, :
|
7
|
+
delegate :aggregation_collection_for, to: "self.class"
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods
|
@@ -19,13 +19,13 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def tags_for(context, conditions={})
|
22
|
-
aggregation_database_collection_for(context).find({:
|
22
|
+
aggregation_database_collection_for(context).find({value: {"$gt" => 0 }}).sort(_id: 1).to_a.map{ |t| t["_id"] }
|
23
23
|
end
|
24
24
|
|
25
25
|
# retrieve the list of tag with weight(count), this is useful for
|
26
26
|
# creating tag clouds
|
27
27
|
def tags_with_weight_for(context, conditions={})
|
28
|
-
aggregation_database_collection_for(context).find({:
|
28
|
+
aggregation_database_collection_for(context).find({value: {"$gt" => 0 }}).sort(_id: 1).to_a.map{ |t| [t["_id"], t["value"].to_i] }
|
29
29
|
end
|
30
30
|
|
31
31
|
end
|
@@ -33,7 +33,7 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
33
33
|
protected
|
34
34
|
|
35
35
|
def changed_tag_arrays
|
36
|
-
tag_database_fields & changes.keys.map(&:to_sym)
|
36
|
+
self.class.tag_database_fields & changes.keys.map(&:to_sym)
|
37
37
|
end
|
38
38
|
|
39
39
|
def tags_changed?
|
@@ -41,19 +41,19 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def map_reduce_all_contexts!
|
44
|
-
tag_contexts.each do |context|
|
44
|
+
self.class.tag_contexts.each do |context|
|
45
45
|
map_reduce_context!(context)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def map_reduce_context!(context)
|
50
|
-
|
50
|
+
db_field = self.class.tag_options_for(context)[:db_field]
|
51
51
|
|
52
52
|
map = <<-END
|
53
53
|
function() {
|
54
|
-
if (!this.#{
|
55
|
-
for (index in this.#{
|
56
|
-
emit(this.#{
|
54
|
+
if (!this.#{db_field})return;
|
55
|
+
for (index in this.#{db_field})
|
56
|
+
emit(this.#{db_field}[index], 1);
|
57
57
|
}
|
58
58
|
END
|
59
59
|
|
@@ -23,13 +23,13 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def tags_for(context, conditions={})
|
26
|
-
aggregation_database_collection_for(context).find({:
|
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] }
|
27
27
|
end
|
28
28
|
|
29
29
|
# retrieve the list of tag with weight(count), this is useful for
|
30
30
|
# creating tag clouds
|
31
31
|
def tags_with_weight_for(context, conditions={})
|
32
|
-
aggregation_database_collection_for(context).find({:
|
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
33
|
end
|
34
34
|
|
35
35
|
def recalculate_all_context_tag_weights!
|
@@ -75,8 +75,7 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
75
75
|
{self.class.tag_name_attribute.to_sym => tag}
|
76
76
|
end
|
77
77
|
|
78
|
-
def update_tags_aggregation(
|
79
|
-
context = database_field_to_context_hash[database_field]
|
78
|
+
def update_tags_aggregation(context, old_tags=[], new_tags=[])
|
80
79
|
coll = self.class.aggregation_database_collection_for(context)
|
81
80
|
|
82
81
|
old_tags ||= []
|
@@ -87,10 +86,10 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
87
86
|
|
88
87
|
|
89
88
|
tags_removed.each do |tag|
|
90
|
-
coll.find(get_conditions(context, tag)).upsert({'$inc' => {:
|
89
|
+
coll.find(get_conditions(context, tag)).upsert({'$inc' => {value: -1}})
|
91
90
|
end
|
92
91
|
tags_added.each do |tag|
|
93
|
-
coll.find(get_conditions(context, tag)).upsert({'$inc' => {:
|
92
|
+
coll.find(get_conditions(context, tag)).upsert({'$inc' => {value: 1}})
|
94
93
|
end
|
95
94
|
#coll.find({_id: {"$in" => tags_removed}}).update({'$inc' => {:value => -1}}, [:upsert])
|
96
95
|
#coll.find({_id: {"$in" => tags_added}}).update({'$inc' => {:value => 1}}, [:upsert])
|
@@ -98,7 +97,7 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
98
97
|
|
99
98
|
def update_tags_aggregations_on_save
|
100
99
|
indifferent_changes = HashWithIndifferentAccess.new changes
|
101
|
-
tag_database_fields.each do |field|
|
100
|
+
self.class.tag_database_fields.each do |field|
|
102
101
|
next if indifferent_changes[field].nil?
|
103
102
|
|
104
103
|
old_tags, new_tags = indifferent_changes[field]
|
@@ -107,7 +106,7 @@ module Mongoid::TaggableWithContext::AggregationStrategy
|
|
107
106
|
end
|
108
107
|
|
109
108
|
def update_tags_aggregations_on_destroy
|
110
|
-
tag_database_fields.each do |field|
|
109
|
+
self.class.tag_database_fields.each do |field|
|
111
110
|
old_tags = send field
|
112
111
|
new_tags = []
|
113
112
|
update_tags_aggregation(field, old_tags, new_tags)
|
@@ -35,7 +35,7 @@ module Mongoid::TaggableWithContext::GroupBy::AggregationStrategy
|
|
35
35
|
|
36
36
|
protected
|
37
37
|
def query(context, group_by)
|
38
|
-
aggregation_database_collection_for(context).find({:
|
38
|
+
aggregation_database_collection_for(context).find({value: {"$gt" => 0 }, group_by_field: group_by}).sort(tag_name_attribute.to_sym => 1)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -45,7 +45,7 @@ module Mongoid::TaggableWithContext::GroupBy::AggregationStrategy
|
|
45
45
|
conditions = {self.class.tag_name_attribute.to_sym => tag}
|
46
46
|
group_by_field = self.class.get_tag_group_by_field_for(context)
|
47
47
|
if group_by_field
|
48
|
-
conditions.merge!({:
|
48
|
+
conditions.merge!({group_by_field: self.send(group_by_field)})
|
49
49
|
end
|
50
50
|
conditions
|
51
51
|
end
|
@@ -7,24 +7,23 @@ module Mongoid::TaggableWithContext::GroupBy
|
|
7
7
|
def taggable(*args)
|
8
8
|
super(*args)
|
9
9
|
args.extract_options!
|
10
|
-
tags_field =
|
11
|
-
self.taggable_with_context_options[tags_field].reverse_merge!(:
|
10
|
+
tags_field = args.present? ? args.shift.to_sym : :tags
|
11
|
+
self.taggable_with_context_options[tags_field].reverse_merge!(group_by_field: nil)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
# singleton methods
|
14
|
+
self.class.class_eval do
|
15
|
+
define_method tags_field do |group_by = nil|
|
16
|
+
tags_for(tags_field, group_by)
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
define_method :"#{tags_field}_with_weight" do |group_by = nil|
|
20
|
+
tags_with_weight_for(tags_field, group_by)
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
23
|
+
define_method :"#{tags_field}_group_by_field" do
|
24
|
+
get_tag_group_by_field_for(tags_field)
|
26
25
|
end
|
27
|
-
|
26
|
+
end
|
28
27
|
end
|
29
28
|
|
30
29
|
def tags_for(context, group_by, conditions={})
|
@@ -4,4 +4,5 @@ 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
5
|
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/aggregation_strategy/real_time')
|
6
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')
|
7
|
+
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/group_by/aggregation_strategy/real_time')
|
8
|
+
require File.join(File.dirname(__FILE__), 'mongoid/taggable_with_context/version')
|
@@ -1,17 +1,16 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in
|
3
|
+
# Instead, edit Jeweler::Tasks in rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "mongoid_taggable_with_context"
|
8
|
-
s.version = "1.0
|
8
|
+
s.version = "1.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["Aaron Qian"
|
12
|
-
s.date = "2013-
|
13
|
-
s.description = "
|
14
|
-
s.email = ["aq1018@gmail.com"]
|
11
|
+
s.authors = ["Aaron Qian", "Luca G. Soave", "John Shields", "Wilker Lucio", "Ches Martin"]
|
12
|
+
s.date = "2013-05-18"
|
13
|
+
s.description = "Add multiple tag fields on Mongoid documents with aggregation capability."
|
15
14
|
s.extra_rdoc_files = [
|
16
15
|
"LICENSE.txt",
|
17
16
|
"README.md"
|
@@ -23,13 +22,13 @@ Gem::Specification.new do |s|
|
|
23
22
|
"LICENSE.txt",
|
24
23
|
"README.md",
|
25
24
|
"Rakefile",
|
26
|
-
"VERSION",
|
27
25
|
"init.rb",
|
28
26
|
"lib/mongoid/taggable_with_context.rb",
|
29
27
|
"lib/mongoid/taggable_with_context/aggregation_strategy/map_reduce.rb",
|
30
28
|
"lib/mongoid/taggable_with_context/aggregation_strategy/real_time.rb",
|
31
29
|
"lib/mongoid/taggable_with_context/group_by/aggregation_strategy/real_time.rb",
|
32
30
|
"lib/mongoid/taggable_with_context/group_by/taggable_with_context.rb",
|
31
|
+
"lib/mongoid/taggable_with_context/version.rb",
|
33
32
|
"lib/mongoid_taggable_with_context.rb",
|
34
33
|
"mongoid_taggable_with_context.gemspec",
|
35
34
|
"spec/mongoid_taggable_with_context_spec.rb",
|
@@ -40,10 +39,6 @@ Gem::Specification.new do |s|
|
|
40
39
|
s.require_paths = ["lib"]
|
41
40
|
s.rubygems_version = "1.8.24"
|
42
41
|
s.summary = "Mongoid taggable behaviour"
|
43
|
-
s.test_files = [
|
44
|
-
"spec/mongoid_taggable_with_context_spec.rb",
|
45
|
-
"spec/spec_helper.rb"
|
46
|
-
]
|
47
42
|
|
48
43
|
if s.respond_to? :specification_version then
|
49
44
|
s.specification_version = 3
|
@@ -6,7 +6,7 @@ class MyModel
|
|
6
6
|
|
7
7
|
taggable
|
8
8
|
taggable :artists
|
9
|
-
taggable :albums, :
|
9
|
+
taggable :albums, default: []
|
10
10
|
end
|
11
11
|
|
12
12
|
class M1
|
@@ -15,7 +15,7 @@ class M1
|
|
15
15
|
include Mongoid::TaggableWithContext::AggregationStrategy::MapReduce
|
16
16
|
|
17
17
|
taggable
|
18
|
-
taggable :artists
|
18
|
+
taggable :a, as: :artists
|
19
19
|
end
|
20
20
|
|
21
21
|
class M2
|
@@ -32,8 +32,8 @@ class M3
|
|
32
32
|
include Mongoid::TaggableWithContext::GroupBy::AggregationStrategy::RealTime
|
33
33
|
|
34
34
|
field :user
|
35
|
-
taggable :
|
36
|
-
taggable :artists, :
|
35
|
+
taggable group_by_field: :user
|
36
|
+
taggable :artists, group_by_field: :user
|
37
37
|
end
|
38
38
|
|
39
39
|
describe Mongoid::TaggableWithContext do
|
@@ -119,35 +119,11 @@ describe Mongoid::TaggableWithContext do
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
-
context "changing separator" do
|
123
|
-
before :all do
|
124
|
-
MyModel.tags_separator = ";"
|
125
|
-
end
|
126
|
-
|
127
|
-
after :all do
|
128
|
-
MyModel.tags_separator = " "
|
129
|
-
end
|
130
|
-
|
131
|
-
before :each do
|
132
|
-
@m = MyModel.new
|
133
|
-
end
|
134
|
-
|
135
|
-
it "should split with custom separator" do
|
136
|
-
@m.tags = "some;other;separator"
|
137
|
-
@m.tags.should == %w[some other separator]
|
138
|
-
end
|
139
|
-
|
140
|
-
it "should join string with custom separator" do
|
141
|
-
@m.tags = %w[some other sep]
|
142
|
-
@m.tags_string.should == "some;other;sep"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
122
|
context "tagged_with" do
|
147
123
|
before :each do
|
148
|
-
@m1 = MyModel.create!(:
|
149
|
-
@m2 = MyModel.create!(:
|
150
|
-
@m3 = MyModel.create!(:
|
124
|
+
@m1 = MyModel.create!(tags: "food ant bee", artists: "jeff greg mandy aaron andy")
|
125
|
+
@m2 = MyModel.create!(tags: "juice food bee zip", artists: "grant andrew andy")
|
126
|
+
@m3 = MyModel.create!(tags: "honey strip food", artists: "mandy aaron andy")
|
151
127
|
end
|
152
128
|
|
153
129
|
it "should retrieve a list of documents" do
|
@@ -181,9 +157,9 @@ describe Mongoid::TaggableWithContext do
|
|
181
157
|
|
182
158
|
context "on create directly" do
|
183
159
|
before :each do
|
184
|
-
klass.create!(:
|
185
|
-
klass.create!(:
|
186
|
-
klass.create!(:
|
160
|
+
klass.create!(user: "user1", tags: "food ant bee", artists: "jeff greg mandy aaron andy")
|
161
|
+
klass.create!(user: "user1", tags: "juice food bee zip", artists: "grant andrew andy")
|
162
|
+
klass.create!(user: "user2", tags: "honey strip food", artists: "mandy aaron andy")
|
187
163
|
end
|
188
164
|
|
189
165
|
it "should retrieve the list of all saved tags distinct and ordered" do
|
@@ -262,9 +238,9 @@ describe Mongoid::TaggableWithContext do
|
|
262
238
|
|
263
239
|
context "on create then update" do
|
264
240
|
before :each do
|
265
|
-
m1 = klass.create!(:
|
266
|
-
m2 = klass.create!(:
|
267
|
-
m3 = klass.create!(:
|
241
|
+
m1 = klass.create!(user: "user1", tags: "food ant bee", artists: "jeff greg mandy aaron andy")
|
242
|
+
m2 = klass.create!(user: "user1", tags: "juice food bee zip", artists: "grant andrew andy")
|
243
|
+
m3 = klass.create!(user: "user2", tags: "honey strip food", artists: "mandy aaron andy")
|
268
244
|
|
269
245
|
m1.tags = m1.tags + %w[honey strip shoe]
|
270
246
|
m1.save!
|
@@ -305,9 +281,9 @@ describe Mongoid::TaggableWithContext do
|
|
305
281
|
|
306
282
|
context "on create, update, then destroy" do
|
307
283
|
before :each do
|
308
|
-
m1 = klass.create!(:
|
309
|
-
m2 = klass.create!(:
|
310
|
-
m3 = klass.create!(:
|
284
|
+
m1 = klass.create!(user: "user1", tags: "food ant bee", artists: "jeff greg mandy aaron andy")
|
285
|
+
m2 = klass.create!(user: "user1", tags: "juice food bee zip", artists: "grant andrew andy")
|
286
|
+
m3 = klass.create!(user: "user2", tags: "honey strip food", artists: "mandy aaron andy")
|
311
287
|
|
312
288
|
m1.tags = m1.tags + %w[honey strip shoe] - %w[food]
|
313
289
|
m1.save!
|
@@ -377,6 +353,10 @@ describe Mongoid::TaggableWithContext do
|
|
377
353
|
let(:klass) { M3 }
|
378
354
|
it_should_behave_like "aggregation"
|
379
355
|
|
356
|
+
it "should have artists_group_by_field value :user" do
|
357
|
+
klass.artists_group_by_field.should == :user
|
358
|
+
end
|
359
|
+
|
380
360
|
it "should generate the tags aggregation collection name correctly" do
|
381
361
|
klass.aggregation_collection_for(:tags).should == "m3s_tags_aggregation"
|
382
362
|
end
|
@@ -387,9 +367,9 @@ describe Mongoid::TaggableWithContext do
|
|
387
367
|
|
388
368
|
context "for groupings" do
|
389
369
|
before :each do
|
390
|
-
klass.create!(:
|
391
|
-
klass.create!(:
|
392
|
-
klass.create!(:
|
370
|
+
klass.create!(user: "user1", tags: "food ant bee", artists: "jeff greg mandy aaron andy")
|
371
|
+
klass.create!(user: "user1", tags: "juice food bee zip", artists: "grant andrew andy")
|
372
|
+
klass.create!(user: "user2", tags: "honey strip food", artists: "mandy aaron andy")
|
393
373
|
end
|
394
374
|
|
395
375
|
it "should retrieve the list of all saved tags distinct and ordered" do
|
@@ -433,4 +413,25 @@ describe Mongoid::TaggableWithContext do
|
|
433
413
|
end
|
434
414
|
end
|
435
415
|
end
|
416
|
+
|
417
|
+
context "removed options" do
|
418
|
+
it "should throw error if :field option is specified" do
|
419
|
+
expect do
|
420
|
+
class Invalid
|
421
|
+
include Mongoid::Document
|
422
|
+
include Mongoid::TaggableWithContext
|
423
|
+
taggable field: :foobar
|
424
|
+
end
|
425
|
+
end.to raise_error
|
426
|
+
end
|
427
|
+
it "should throw error if :string_method option is specified" do
|
428
|
+
expect do
|
429
|
+
class Invalid
|
430
|
+
include Mongoid::Document
|
431
|
+
include Mongoid::TaggableWithContext
|
432
|
+
taggable string_method: :foobar
|
433
|
+
end
|
434
|
+
end.to raise_error
|
435
|
+
end
|
436
|
+
end
|
436
437
|
end
|
metadata
CHANGED
@@ -1,115 +1,105 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_taggable_with_context
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
5
|
-
prerelease:
|
4
|
+
version: 1.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Aaron Qian
|
8
|
+
- Luca G. Soave
|
9
|
+
- John Shields
|
10
|
+
- Wilker Lucio
|
11
|
+
- Ches Martin
|
9
12
|
autorequire:
|
10
13
|
bindir: bin
|
11
14
|
cert_chain: []
|
12
|
-
date: 2013-
|
15
|
+
date: 2013-05-18 00:00:00.000000000 Z
|
13
16
|
dependencies:
|
14
17
|
- !ruby/object:Gem::Dependency
|
15
18
|
name: mongoid
|
16
19
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
20
|
requirements:
|
19
|
-
- -
|
21
|
+
- - '>='
|
20
22
|
- !ruby/object:Gem::Version
|
21
23
|
version: 3.0.0
|
22
24
|
type: :runtime
|
23
25
|
prerelease: false
|
24
26
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
27
|
requirements:
|
27
|
-
- -
|
28
|
+
- - '>='
|
28
29
|
- !ruby/object:Gem::Version
|
29
30
|
version: 3.0.0
|
30
31
|
- !ruby/object:Gem::Dependency
|
31
32
|
name: database_cleaner
|
32
33
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - '>='
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: '0'
|
38
38
|
type: :development
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
41
|
requirements:
|
43
|
-
- -
|
42
|
+
- - '>='
|
44
43
|
- !ruby/object:Gem::Version
|
45
44
|
version: '0'
|
46
45
|
- !ruby/object:Gem::Dependency
|
47
46
|
name: rspec
|
48
47
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
48
|
requirements:
|
51
|
-
- -
|
49
|
+
- - '>='
|
52
50
|
- !ruby/object:Gem::Version
|
53
51
|
version: '0'
|
54
52
|
type: :development
|
55
53
|
prerelease: false
|
56
54
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
55
|
requirements:
|
59
|
-
- -
|
56
|
+
- - '>='
|
60
57
|
- !ruby/object:Gem::Version
|
61
58
|
version: '0'
|
62
59
|
- !ruby/object:Gem::Dependency
|
63
60
|
name: yard
|
64
61
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
62
|
requirements:
|
67
|
-
- -
|
63
|
+
- - '>='
|
68
64
|
- !ruby/object:Gem::Version
|
69
65
|
version: '0'
|
70
66
|
type: :development
|
71
67
|
prerelease: false
|
72
68
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
69
|
requirements:
|
75
|
-
- -
|
70
|
+
- - '>='
|
76
71
|
- !ruby/object:Gem::Version
|
77
72
|
version: '0'
|
78
73
|
- !ruby/object:Gem::Dependency
|
79
74
|
name: bundler
|
80
75
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
76
|
requirements:
|
83
|
-
- -
|
77
|
+
- - '>='
|
84
78
|
- !ruby/object:Gem::Version
|
85
79
|
version: 1.0.0
|
86
80
|
type: :development
|
87
81
|
prerelease: false
|
88
82
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
83
|
requirements:
|
91
|
-
- -
|
84
|
+
- - '>='
|
92
85
|
- !ruby/object:Gem::Version
|
93
86
|
version: 1.0.0
|
94
87
|
- !ruby/object:Gem::Dependency
|
95
88
|
name: jeweler
|
96
89
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
90
|
requirements:
|
99
|
-
- -
|
91
|
+
- - '>='
|
100
92
|
- !ruby/object:Gem::Version
|
101
93
|
version: '0'
|
102
94
|
type: :development
|
103
95
|
prerelease: false
|
104
96
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
97
|
requirements:
|
107
|
-
- -
|
98
|
+
- - '>='
|
108
99
|
- !ruby/object:Gem::Version
|
109
100
|
version: '0'
|
110
|
-
description:
|
111
|
-
email:
|
112
|
-
- aq1018@gmail.com
|
101
|
+
description: Add multiple tag fields on Mongoid documents with aggregation capability.
|
102
|
+
email:
|
113
103
|
executables: []
|
114
104
|
extensions: []
|
115
105
|
extra_rdoc_files:
|
@@ -122,13 +112,13 @@ files:
|
|
122
112
|
- LICENSE.txt
|
123
113
|
- README.md
|
124
114
|
- Rakefile
|
125
|
-
- VERSION
|
126
115
|
- init.rb
|
127
116
|
- lib/mongoid/taggable_with_context.rb
|
128
117
|
- lib/mongoid/taggable_with_context/aggregation_strategy/map_reduce.rb
|
129
118
|
- lib/mongoid/taggable_with_context/aggregation_strategy/real_time.rb
|
130
119
|
- lib/mongoid/taggable_with_context/group_by/aggregation_strategy/real_time.rb
|
131
120
|
- lib/mongoid/taggable_with_context/group_by/taggable_with_context.rb
|
121
|
+
- lib/mongoid/taggable_with_context/version.rb
|
132
122
|
- lib/mongoid_taggable_with_context.rb
|
133
123
|
- mongoid_taggable_with_context.gemspec
|
134
124
|
- spec/mongoid_taggable_with_context_spec.rb
|
@@ -136,29 +126,26 @@ files:
|
|
136
126
|
homepage: http://github.com/lgs/mongoid_taggable_with_context
|
137
127
|
licenses:
|
138
128
|
- MIT
|
129
|
+
metadata: {}
|
139
130
|
post_install_message:
|
140
131
|
rdoc_options: []
|
141
132
|
require_paths:
|
142
133
|
- lib
|
143
134
|
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
-
none: false
|
145
135
|
requirements:
|
146
|
-
- -
|
136
|
+
- - '>='
|
147
137
|
- !ruby/object:Gem::Version
|
148
138
|
version: '0'
|
149
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
|
-
none: false
|
151
140
|
requirements:
|
152
|
-
- -
|
141
|
+
- - '>='
|
153
142
|
- !ruby/object:Gem::Version
|
154
143
|
version: '0'
|
155
144
|
requirements: []
|
156
145
|
rubyforge_project:
|
157
|
-
rubygems_version:
|
146
|
+
rubygems_version: 2.0.3
|
158
147
|
signing_key:
|
159
148
|
specification_version: 3
|
160
149
|
summary: Mongoid taggable behaviour
|
161
|
-
test_files:
|
162
|
-
- spec/mongoid_taggable_with_context_spec.rb
|
163
|
-
- spec/spec_helper.rb
|
150
|
+
test_files: []
|
164
151
|
has_rdoc:
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.0.0
|