acts_as_word_cloud 0.0.1 → 0.0.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/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
|