acts_as_word_cloud 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +8 -9
- data/README.rdoc +19 -87
- data/Rakefile +1 -4
- data/VERSION +1 -1
- data/acts_as_word_cloud.gemspec +13 -18
- data/lib/acts_as_word_cloud/config.rb +6 -2
- data/lib/acts_as_word_cloud/railtie.rb +1 -0
- data/lib/acts_as_word_cloud/word_cloud.rb +108 -188
- data/lib/generators/acts_as_word_cloud/templates/config.rb +9 -4
- data/spec/acts_as_word_cloud_spec.rb +162 -99
- data/spec/dummy/app/models/article.rb +7 -5
- data/spec/dummy/app/models/article_reader.rb +10 -0
- data/spec/dummy/app/models/author.rb +5 -2
- data/spec/dummy/app/models/publisher.rb +5 -4
- data/spec/dummy/app/models/reader.rb +7 -4
- data/spec/dummy/db/migrate/20121107162154_create_system.rb +2 -28
- data/spec/dummy/db/schema.rb +14 -44
- data/spec/integration_spec.rb +123 -0
- data/spec/spec_helper.rb +18 -3
- data/spec/{dummy/features/support → support}/blueprints.rb +6 -21
- metadata +13 -17
- data/features/acts_as_word_cloud.feature +0 -9
- data/features/step_definitions/acts_as_word_cloud_steps.rb +0 -0
- data/features/support/env.rb +0 -13
- data/lib/model_methods_helper.rb +0 -87
- data/spec/dummy/app/models/following.rb +0 -5
- data/spec/dummy/app/models/site.rb +0 -8
- data/spec/dummy/lib/model_methods_helper.rb +0 -87
@@ -5,223 +5,143 @@ module ActsAsWordCloud
|
|
5
5
|
end
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
8
|
+
# Sets up the word_cloud method and takes arguments that control what it returns
|
9
|
+
#
|
10
|
+
# @param [Hash] args
|
11
|
+
# @param args [Array] :included_methods An array of method symbols used to create this model's word cloud
|
12
|
+
# @param args [Array] :excluded_methods An array of method symbols used to remove data from the word cloud. This should be used to remove database fields from the word cloud.
|
13
|
+
# @param args [Array] :excluded_models An array of models whose data should not be included in the word cloud
|
14
|
+
# @param args [Integer] :depth_level How many levels of associations to include
|
15
|
+
# @param args [Symbol] :object_name_method How to name the object when included in the word cloud as an association
|
16
|
+
def acts_as_word_cloud(args = {})
|
16
17
|
|
17
18
|
# getter/setter methods for the module
|
18
|
-
mattr_accessor :
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
unless self.word_cloud_skipped.is_a?(Array)
|
32
|
-
self.word_cloud_skipped = []
|
33
|
-
end
|
34
|
-
unless self.word_cloud_no_mixin_fields.is_a?(Array)
|
35
|
-
self.word_cloud_no_mixin_fields = []
|
36
|
-
end
|
37
|
-
|
38
|
-
# default values if none set in the mixin call on the model
|
39
|
-
self.word_cloud_using |= args[:methods_to_use].present? ? args[:methods_to_use] : []
|
40
|
-
self.word_cloud_excluded |= args[:excluded_models].present? ? args[:excluded_models] : []
|
41
|
-
self.word_cloud_skipped |= args[:skipped_attributes].present? ? args[:skipped_attributes] : []
|
42
|
-
self.word_cloud_depth = args[:depth].present? ? args[:depth] : ActsAsWordCloud.config.min_depth
|
43
|
-
self.word_cloud_no_mixin_fields = [:name, :title, :label] #ActsAsWordCloud.config.no_mixin_fields
|
19
|
+
mattr_accessor :word_cloud_attributes unless respond_to? :word_cloud_attributes
|
20
|
+
allowed_options = [:included_methods, :excluded_methods, :excluded_models, :depth, :object_name_methods]
|
21
|
+
|
22
|
+
# set defaults
|
23
|
+
args[:included_methods] ||= []
|
24
|
+
args[:excluded_methods] ||= []
|
25
|
+
args[:excluded_models] ||= []
|
26
|
+
args[:depth] ||= ::ActsAsWordCloud.config.default_search_depth
|
27
|
+
# note that the user passes in object_name_method and it is turned into the array object_name_methods
|
28
|
+
args[:object_name_methods] = args[:object_name_method] ? [args[:object_name_method]] : ::ActsAsWordCloud.config.object_name_methods
|
29
|
+
|
30
|
+
self.word_cloud_attributes = args.keep_if { |key| allowed_options.include?(key) }
|
44
31
|
|
45
32
|
include ActsAsWordCloud::WordCloud::InstanceMethods
|
46
33
|
end
|
47
34
|
end
|
48
35
|
|
49
36
|
module InstanceMethods
|
50
|
-
|
51
|
-
#
|
52
|
-
#
|
53
|
-
# @
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
# goes through array of objects or arrays (in the case of has_many association)
|
61
|
-
#
|
62
|
-
# @param [Symbol] the association type to fetch objects from
|
63
|
-
# @returns [Array <Object>] that under association passed in
|
64
|
-
#
|
65
|
-
def word_cloud_associated_objects(type)
|
66
|
-
objects = []
|
67
|
-
associated = word_cloud_get_associated(type)
|
68
|
-
associated.each do |o|
|
69
|
-
if o.class == Array
|
70
|
-
nested_array = self.send(o)
|
71
|
-
nested_array.each do |a|
|
72
|
-
objects << a
|
73
|
-
end
|
74
|
-
else
|
75
|
-
objects << self.send(o)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
return objects
|
79
|
-
end
|
80
|
-
|
81
|
-
# removes objects that are in the list of objects to exclude
|
82
|
-
#
|
83
|
-
# @returns [Array <Object>] that are not in the excluded list
|
84
|
-
#
|
85
|
-
def word_cloud_exclude_words(objects)
|
86
|
-
if objects.nil?
|
87
|
-
return []
|
88
|
-
else
|
89
|
-
result = objects.flatten.reject { |x| self.word_cloud_excluded.include?(x.class) }
|
90
|
-
return result.present? ? result : []
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# removes objects that include word_cloud mixin
|
95
|
-
#
|
96
|
-
# @returns [Array <Object>] that don't include the mixin
|
97
|
-
#
|
98
|
-
def word_cloud_no_mixin(objects)
|
99
|
-
if objects.nil?
|
100
|
-
return []
|
37
|
+
# Uses recursive word cloud to find text attributes, associations and included methods on the model
|
38
|
+
#
|
39
|
+
# @param [Symbol] return_type Whether to return an array or string, defaulting to :string
|
40
|
+
# @return [Array<String> or String] All processed values
|
41
|
+
def word_cloud(return_type = :string)
|
42
|
+
output = recursive_word_cloud(self.word_cloud_attributes[:depth]).uniq.flatten
|
43
|
+
if return_type == :string
|
44
|
+
return output.join(' ')
|
101
45
|
else
|
102
|
-
|
103
|
-
result.present? ? result : []
|
46
|
+
return output
|
104
47
|
end
|
105
48
|
end
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
#
|
110
|
-
# @param [Array <Objects>] to look through for values
|
111
|
-
# @returns [Array <String>] values returned by method
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
# Finds all text attributes, associated objects, and included methods down to a specified depth
|
112
53
|
#
|
113
|
-
|
54
|
+
# @param [Integer] depth How many layers of associations to search
|
55
|
+
# @return [Array] The word cloud for the specified object and depth
|
56
|
+
def recursive_word_cloud(depth)
|
57
|
+
# prepare an array of strings to be used as an output
|
114
58
|
output = []
|
59
|
+
|
60
|
+
# list of database attributes and selected methods minus a list of excluded methods
|
61
|
+
output |= word_cloud_get_valid_strings
|
62
|
+
|
63
|
+
# array of objects for every association minus a list of excluded objects
|
64
|
+
objects = word_cloud_associated_objects
|
115
65
|
objects.each do |obj|
|
116
|
-
|
117
|
-
|
118
|
-
output
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
# goes through each of the default fields to call on models that don't include mixin
|
125
|
-
# and attempts to return the value of the first one to work, if none do return model class name
|
126
|
-
#
|
127
|
-
# @returns [String] value for object passed in
|
128
|
-
#
|
129
|
-
def word_cloud_apply_fields_to(no_mixin_model)
|
130
|
-
# fields that should be tried on models that don't have the mixin, set with other attributes
|
131
|
-
fields = self.word_cloud_no_mixin_fields
|
132
|
-
fields.each do |f|
|
133
|
-
if no_mixin_model.respond_to?(f)
|
134
|
-
return no_mixin_model.send(f)
|
66
|
+
if obj.respond_to?(:recursive_word_cloud) && depth > 1
|
67
|
+
# if the object has a word cloud mixin and we can recurse
|
68
|
+
output |= obj.recursive_word_cloud(depth - 1)
|
69
|
+
else
|
70
|
+
# otherwise get the default name for the object
|
71
|
+
output |= [self.word_cloud_object_name(obj)]
|
135
72
|
end
|
136
73
|
end
|
137
|
-
return no_mixin_model.class.name
|
138
|
-
end
|
139
|
-
|
140
|
-
# goes through models that don't include mixin trying to find a relevant value for each
|
141
|
-
#
|
142
|
-
# @returns [Array <String>] of values for objects passed in
|
143
|
-
#
|
144
|
-
def word_cloud_find_field(no_mixin)
|
145
|
-
output = []
|
146
|
-
flag = 0
|
147
|
-
no_mixin.each do |n|
|
148
|
-
output << word_cloud_apply_fields_to(n)
|
149
|
-
end
|
150
74
|
return output
|
151
|
-
end
|
152
|
-
|
153
|
-
|
154
|
-
#
|
155
|
-
# ignores string attributes that are listed in the skipped option
|
75
|
+
end
|
76
|
+
|
77
|
+
# returns values from methods specified in included_methods option
|
78
|
+
# ignores string attributes that are listed in the excluded_methods option
|
156
79
|
#
|
157
|
-
#
|
80
|
+
# Note that his uses content_columns to read the database data.
|
81
|
+
# At some point, we may want to increase the types that are allowed or use a blacklist instead of a whitelist
|
158
82
|
#
|
83
|
+
# @return [Array <String>] The database fields and included methods with excluded methods removed
|
159
84
|
def word_cloud_get_valid_strings
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
self.
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
self.word_cloud_skipped.each do |s|
|
168
|
-
ignore << self.send(s)
|
169
|
-
end
|
85
|
+
# database fields
|
86
|
+
string_attributes = self.class.content_columns.collect { |c| c.name.to_sym if c.type == :string || c.type == :text }.compact
|
87
|
+
# included methods
|
88
|
+
methods = self.word_cloud_attributes[:included_methods] | string_attributes
|
89
|
+
# excluded methods
|
90
|
+
methods -= self.word_cloud_attributes[:excluded_methods]
|
170
91
|
|
171
|
-
|
172
|
-
output += self.attributes.select {|k,v| v.class == String}.values
|
173
|
-
output -= ignore
|
174
|
-
|
175
|
-
return output
|
92
|
+
return methods.map { |m| self.send(m) }
|
176
93
|
end
|
177
94
|
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
# @params Integer, recursive depth for method; Symbol for the type of result (array or string)
|
183
|
-
# @returns [Array <String>] all processed values
|
95
|
+
# Gets a list of objects associated to the calling object
|
96
|
+
# Uses rails reflect_on_all_associations methods. Only pulls from belongs_to, has_one, and has_many for now.
|
97
|
+
# Each association should return nil, a single object, or an array of objects
|
184
98
|
#
|
185
|
-
|
186
|
-
|
187
|
-
output = []
|
99
|
+
# @return [Array] List of models associated to the calling object
|
100
|
+
def word_cloud_associated_objects
|
188
101
|
objects = []
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
102
|
+
# get associations
|
103
|
+
[:belongs_to, :has_one, :has_many].each do |association_type|
|
104
|
+
word_cloud_association_names_by_type(association_type).each do |association|
|
105
|
+
objects << self.send(association)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
objects.flatten!
|
109
|
+
# remove excluded associations
|
110
|
+
objects = objects.delete_if { |o| self.word_cloud_attributes[:excluded_models].include?(o.class) }
|
111
|
+
return objects
|
112
|
+
end
|
113
|
+
|
114
|
+
# @return [Array <Symbol>] Collect the names of associations of a specific typeI
|
115
|
+
def word_cloud_association_names_by_type(type)
|
116
|
+
self.class.reflect_on_all_associations(type).collect(&:name)
|
117
|
+
end
|
193
118
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
if depth < 1
|
210
|
-
return "depth for word cloud can't be less than 0"
|
211
|
-
elsif depth == 1
|
212
|
-
# recursive steps got a bit more complicated with :array/:string addition, that last line gets rid of duplicate results in the 'long' strings being returned
|
213
|
-
return ( type == :array ? output.uniq : output.uniq.join(' ') )
|
119
|
+
# Name an object that is included in the word cloud
|
120
|
+
#
|
121
|
+
# When the depth level is low or an included gem does not use the word cloud mixin
|
122
|
+
# use a special rule to determine the name of the object. The word cloud attribute
|
123
|
+
# object_name_methods is used for objects that use the word cloud. Otherwise, the
|
124
|
+
# default config option is used. If none of the methods are found on the object, an
|
125
|
+
# empty string is returned.
|
126
|
+
#
|
127
|
+
# @param [ActiveRecord::Base] object The object to name
|
128
|
+
# @param [String] The name of the object or a blank string
|
129
|
+
def word_cloud_object_name(object)
|
130
|
+
output = ""
|
131
|
+
method_list = []
|
132
|
+
if object.respond_to?(:word_cloud_attributes)
|
133
|
+
method_list = object.word_cloud_attributes[:object_name_methods]
|
214
134
|
else
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
output
|
220
|
-
|
135
|
+
method_list = ::ActsAsWordCloud.config.object_name_methods
|
136
|
+
end
|
137
|
+
method_list.each do |method|
|
138
|
+
if object.respond_to?(method)
|
139
|
+
output = object.send(method)
|
140
|
+
break
|
221
141
|
end
|
222
142
|
end
|
223
|
-
|
143
|
+
return output
|
144
|
+
end
|
224
145
|
end
|
225
146
|
end
|
226
147
|
end
|
227
|
-
|
@@ -1,7 +1,12 @@
|
|
1
1
|
ActsAsWordCloud.configure do |config|
|
2
|
-
#
|
3
|
-
|
2
|
+
# The default recursion depth when looking at data in associations.
|
3
|
+
# A min_depth of 1 will look at all fields on the current model and the name of each association.
|
4
|
+
# A min_depth of 2 will look at all fields on the current model, all fields on the associations, and all names of the association's associations
|
5
|
+
# config.default_search_depth = 1
|
4
6
|
|
5
|
-
#
|
6
|
-
|
7
|
+
# This option is useful when associations do not use the acts_as_word_cloud mixin.
|
8
|
+
# When word_cloud is called, the system tries to guess a reasonable name for the associated models.
|
9
|
+
# It calls the methods in order meaning it will look for name first.
|
10
|
+
# Make sure that the final method in this list is on every model
|
11
|
+
# config.default_object_names = [:name, :title, :label, :to_s]
|
7
12
|
end
|
@@ -1,109 +1,172 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "ActsAsWordCloud" do
|
4
|
-
before(:
|
5
|
-
@
|
6
|
-
@publisher = Publisher.make(:name => "publisher", :location => "location")
|
7
|
-
@site = Site.make( :name => "site name", :domain => "uff.us", :genre => "site genre", :publisher => @publisher)
|
8
|
-
@author = Author.make(:name => "author", :genre => "author genre", :publisher => @publisher, :site => @site)
|
9
|
-
@article = Article.make(:title => "article title", :genre => "genre", :content => "article text", :author => @author, :publisher => @publisher, :site => @site)
|
10
|
-
@reader = Reader.make(:username => "reader", :site => @site)
|
11
|
-
@following = Following.make(:article => @article, :reader => @reader, :special_name => "following1")
|
4
|
+
before(:each) do
|
5
|
+
@article = Article.new
|
12
6
|
end
|
13
|
-
|
7
|
+
|
14
8
|
describe "word_cloud" do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should return
|
25
|
-
@
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@reader.word_cloud(2, :array).should == [@reader.username, @reader.site.domain, @article.title, @article2.title, "Following", @site.name, @site.genre, @site.publisher.name, @site.authors.first.name, @article.genre, @article.content, @article2.genre, @article2.content, @article2.author.name, @article2.publisher.name, @article2.site.domain ]
|
9
|
+
before(:each) do
|
10
|
+
@article.stub(:recursive_word_cloud).and_return([])
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should call recursive_word_cloud" do
|
14
|
+
@article.should_receive(:recursive_word_cloud).and_return([])
|
15
|
+
@article.word_cloud
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return a string by default" do
|
19
|
+
@article.word_cloud.should be_a_kind_of String
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return a string if :string is passed as an argument" do
|
23
|
+
@article.word_cloud(:string).should be_a_kind_of String
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return an array if :array is passed as an argument" do
|
27
|
+
@article.word_cloud(:array).should be_a_kind_of Array
|
35
28
|
end
|
36
29
|
end
|
37
|
-
|
38
|
-
describe "
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
30
|
+
|
31
|
+
describe "recursive_word_cloud" do
|
32
|
+
before(:each) do
|
33
|
+
@article.stub(:word_cloud_get_valid_strings).and_return([])
|
34
|
+
@article.stub(:word_cloud_associated_objects).and_return([])
|
35
|
+
end
|
36
|
+
it "should call word_cloud_get_valid_strings" do
|
37
|
+
@article.should_receive(:word_cloud_get_valid_strings).and_return([])
|
38
|
+
@article.send(:recursive_word_cloud, 1)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should call word_cloud_associated_objects" do
|
42
|
+
@article.should_receive(:word_cloud_associated_objects).and_return([])
|
43
|
+
@article.send(:recursive_word_cloud, 1)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should call rescursive_word_cloud on an associated object if the depth is more than 1" do
|
47
|
+
object_with_word_cloud = mock(Author)
|
48
|
+
object_with_word_cloud.should_receive(:recursive_word_cloud).with(1).and_return([])
|
49
|
+
|
50
|
+
@article.stub(:word_cloud_associated_objects).and_return([object_with_word_cloud])
|
51
|
+
@article.send(:recursive_word_cloud, 2)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should call word_cloud_object_name on an associated object if the depth is 1 or less" do
|
55
|
+
object_with_word_cloud = mock(Author)
|
56
|
+
object_with_word_cloud.stub(:recursive_word_cloud).and_return([])
|
57
|
+
@article.stub(:word_cloud_associated_objects).and_return([object_with_word_cloud])
|
58
|
+
|
59
|
+
@article.should_receive(:word_cloud_object_name).with(object_with_word_cloud)
|
60
|
+
@article.send(:recursive_word_cloud, 1)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should call word_cloud_object_name on an associated object if the object does not have the word cloud mixin" do
|
64
|
+
object_without_word_cloud = mock(Author)
|
65
|
+
@article.stub(:word_cloud_associated_objects).and_return([object_without_word_cloud])
|
66
|
+
|
67
|
+
@article.should_receive(:word_cloud_object_name).with(object_without_word_cloud)
|
68
|
+
@article.send(:recursive_word_cloud, 2)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return an array of strings" do
|
72
|
+
@article.stub(:word_cloud_get_valid_strings).and_return(["hello"])
|
73
|
+
results = @article.send(:recursive_word_cloud, 1)
|
74
|
+
results.should be_a_kind_of Array
|
75
|
+
results.each { |r| r.should be_a_kind_of String }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "word_cloud_get_valid_strings" do
|
80
|
+
before(:each) do
|
81
|
+
@article.word_cloud_attributes[:included_methods] = [:sample_method]
|
82
|
+
@article.word_cloud_attributes[:excluded_methods] = [:sample_method]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should read the database structure and return text and string fields only" do
|
86
|
+
@article.should_receive(:title)
|
87
|
+
@article.should_receive(:content)
|
88
|
+
@article.should_not_receive(:created_at)
|
89
|
+
@article.send(:word_cloud_get_valid_strings)
|
47
90
|
end
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
@article.stub!(:word_cloud_excluded).and_return([Publisher])
|
60
|
-
objects = @article.word_cloud_associated_objects(:belongs_to)
|
61
|
-
@article.word_cloud_exclude_words(objects).should == [@article.author, @article.site]
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "word_cloud_no_mixin" do
|
66
|
-
it "should only have models that don't have the mixin" do
|
67
|
-
objects = @article.word_cloud_associated_objects(:has_many)
|
68
|
-
@article.word_cloud_no_mixin(objects).should == @article.followings
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
describe "word_cloud_process_words" do
|
73
|
-
it "should return result of first included method to work on objects with mixin" do
|
74
|
-
objects = []
|
75
|
-
objects += @article.word_cloud_associated_objects(:belongs_to)
|
76
|
-
objects += @article.word_cloud_associated_objects(:has_many)
|
77
|
-
objects = @article.word_cloud_exclude_words(objects)
|
78
|
-
no_mixin = @article.word_cloud_no_mixin(objects)
|
79
|
-
objects -= no_mixin
|
80
|
-
@article.word_cloud_process_words(objects).should == [@article.author.name, @article.publisher.name, @article.site.domain, @article.readers.first.username]
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
describe "word_cloud_apply_fields_to" do
|
85
|
-
it "return the value found in the first method to work on object passed in, if there's none return class name" do
|
86
|
-
@article.word_cloud_apply_fields_to(@article.followings.first).should == "Following"
|
87
|
-
@article.stub!(:word_cloud_no_mixin_fields).and_return([:special_name])
|
88
|
-
@article.word_cloud_apply_fields_to(@article.followings.first).should == @article.followings.first.special_name
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe "word_cloud_find_field" do
|
93
|
-
it "should return result of first included method to work on objects with mixin or their class names" do
|
94
|
-
@article.word_cloud_find_field(@article.followings).should == ["Following"]
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
describe "word_cloud_get_valid_strings" do
|
99
|
-
it "should return used methods on model and string attributes not in skipped list" do
|
100
|
-
@article.stub!(:word_cloud_skipped).and_return([:title, :content])
|
101
|
-
@article.word_cloud_get_valid_strings.should_not include "article title"
|
102
|
-
@article.word_cloud_get_valid_strings.should_not include "article text"
|
103
|
-
@article.word_cloud_get_valid_strings.should include "genre"
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
91
|
+
|
92
|
+
it "should add included methods to the output and call them" do
|
93
|
+
@article.word_cloud_attributes[:excluded_methods] = []
|
94
|
+
@article.should_receive(:sample_method)
|
95
|
+
@article.send(:word_cloud_get_valid_strings)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should remove excluded methods from the output and not call them" do
|
99
|
+
@article.should_not_receive(:sample_method)
|
100
|
+
@article.send(:word_cloud_get_valid_strings)
|
101
|
+
end
|
107
102
|
end
|
108
|
-
end
|
109
103
|
|
104
|
+
describe "word_cloud_associated_objects" do
|
105
|
+
before(:each) do
|
106
|
+
@article.stub(:word_cloud_association_names_by_type).and_return([])
|
107
|
+
end
|
108
|
+
it "should get objects in belongs to, has ony, and has many relationships" do
|
109
|
+
@article.should_receive(:word_cloud_association_names_by_type).with(:belongs_to).and_return([])
|
110
|
+
@article.should_receive(:word_cloud_association_names_by_type).with(:has_one).and_return([])
|
111
|
+
@article.should_receive(:word_cloud_association_names_by_type).with(:has_many).and_return([])
|
112
|
+
@article.send(:word_cloud_associated_objects)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should remove objects that are included in excluded_models" do
|
116
|
+
author = Author.new
|
117
|
+
@article.stub(:author).and_return(author)
|
118
|
+
@article.stub(:word_cloud_association_names_by_type).with(:belongs_to).and_return([:author])
|
119
|
+
@article.word_cloud_attributes[:excluded_models] = [Author]
|
120
|
+
@article.send(:word_cloud_associated_objects).should be_empty
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should return an array of rails models" do
|
124
|
+
author = Author.new
|
125
|
+
@article.stub(:author).and_return(author)
|
126
|
+
@article.stub(:word_cloud_association_names_by_type).with(:belongs_to).and_return([:author])
|
127
|
+
@article.word_cloud_attributes[:excluded_models] = []
|
128
|
+
@article.send(:word_cloud_associated_objects).should == [author]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "word_cloud_association_names_by_type" do
|
133
|
+
# this one is tough to test because we are just calling a single rails method
|
134
|
+
it "should return an array of symbols" do
|
135
|
+
associations = @article.send(:word_cloud_association_names_by_type, :belongs_to)
|
136
|
+
associations.should be_a_kind_of Array
|
137
|
+
associations.each { |a| a.should be_a_kind_of Symbol }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "word_cloud_object_name" do
|
142
|
+
it "should use the object's word cloud attribute for object name if set" do
|
143
|
+
@article.word_cloud_attributes[:object_name_methods] = [:hello]
|
144
|
+
@article.should_receive(:hello).and_return("hello")
|
145
|
+
@article.send(:word_cloud_object_name, @article).should == "hello"
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should call each member of the method list until it finds one that is runnable on the object" do
|
149
|
+
publisher = Publisher.new
|
150
|
+
|
151
|
+
ActsAsWordCloud.config.should_receive(:object_name_methods).and_return([:hello, :world])
|
152
|
+
publisher.stub(:respond_to?).with(:word_cloud_attributes).and_return(false)
|
153
|
+
|
154
|
+
publisher.stub(:respond_to?).with(:hello).and_return(false)
|
155
|
+
publisher.should_not_receive(:hello)
|
156
|
+
|
157
|
+
publisher.stub(:respond_to?).with(:world).and_return(true)
|
158
|
+
publisher.should_receive(:world).and_return("world")
|
159
|
+
|
160
|
+
@article.send(:word_cloud_object_name, publisher).should == "world"
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should return an empty string if no methods are found" do
|
164
|
+
publisher = Publisher.new
|
165
|
+
|
166
|
+
ActsAsWordCloud.config.should_receive(:object_name_methods).and_return([])
|
167
|
+
publisher.stub(:respond_to?).with(:word_cloud_attributes).and_return(false)
|
168
|
+
|
169
|
+
@article.send(:word_cloud_object_name, publisher).should == ""
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
class Article < ActiveRecord::Base
|
2
|
-
acts_as_word_cloud :
|
2
|
+
acts_as_word_cloud :included_methods => [:truncated_title], :excluded_methods => [:genre], :excluded_models => [ArticleReader, Reader], :depth => 2, :object_name_method => :title
|
3
3
|
|
4
4
|
belongs_to :author
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
has_many :article_readers
|
6
|
+
has_many :readers, :through => :article_readers
|
7
|
+
|
8
|
+
def truncated_title
|
9
|
+
title[0..5] if title
|
10
|
+
end
|
9
11
|
end
|