acts_as_word_cloud 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/.document +5 -0
- data/.gitignore_new +7 -0
- data/.rspec +1 -0
- data/CHANGELOG +3 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +122 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/acts_as_word_cloud.gemspec +127 -0
- data/features/acts_as_word_cloud.feature +9 -0
- data/features/step_definitions/acts_as_word_cloud_steps.rb +0 -0
- data/features/support/env.rb +13 -0
- data/lib/acts_as_word_cloud/config.rb +31 -0
- data/lib/acts_as_word_cloud/engine.rb +4 -0
- data/lib/acts_as_word_cloud/railtie.rb +12 -0
- data/lib/acts_as_word_cloud/word_cloud.rb +227 -0
- data/lib/acts_as_word_cloud.rb +2 -0
- data/lib/generators/acts_as_word_cloud/install_generator.rb +23 -0
- data/lib/generators/acts_as_word_cloud/templates/config.rb +7 -0
- data/lib/model_methods_helper.rb +87 -0
- data/spec/acts_as_word_cloud_spec.rb +109 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/article.rb +9 -0
- data/spec/dummy/app/models/author.rb +7 -0
- data/spec/dummy/app/models/following.rb +5 -0
- data/spec/dummy/app/models/publisher.rb +7 -0
- data/spec/dummy/app/models/reader.rb +7 -0
- data/spec/dummy/app/models/site.rb +8 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +65 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20121107162154_create_system.rb +64 -0
- data/spec/dummy/db/schema.rb +81 -0
- data/spec/dummy/features/support/blueprints.rb +57 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/lib/model_methods_helper.rb +87 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/spec_helper.rb +21 -0
- metadata +211 -0
@@ -0,0 +1,227 @@
|
|
1
|
+
module ActsAsWordCloud
|
2
|
+
module WordCloud
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# args:
|
9
|
+
# using, takes an array of Symbols that refer to the methods we'll use on the model calling word_cloud
|
10
|
+
# excluded models, takes in Class names of models we want to ignore that are associated to model calling word_cloud
|
11
|
+
# skipped attributes, takes in Symbols referring to attributes that won't be pulled from model calling word_cloud
|
12
|
+
# depth level, takes in an Integer referring to how deep of a recursive search we'll make
|
13
|
+
# no_mixin_fields, is a default pre-set array of methods to use on models that do not include the mixin
|
14
|
+
#
|
15
|
+
def acts_as_word_cloud(args)
|
16
|
+
|
17
|
+
# getter/setter methods for the module
|
18
|
+
mattr_accessor :word_cloud_using unless respond_to? :word_cloud_using
|
19
|
+
mattr_accessor :word_cloud_excluded unless respond_to? :word_cloud_excluded
|
20
|
+
mattr_accessor :word_cloud_skipped unless respond_to? :word_cloud_skipped
|
21
|
+
mattr_accessor :word_cloud_depth unless respond_to? :word_cloud_depth
|
22
|
+
mattr_accessor :word_cloud_no_mixin_fields unless respond_to? :word_cloud_no_mixin_fields
|
23
|
+
|
24
|
+
# set empty arrays to allow |= on values
|
25
|
+
unless self.word_cloud_using.is_a?(Array)
|
26
|
+
self.word_cloud_using = []
|
27
|
+
end
|
28
|
+
unless self.word_cloud_excluded.is_a?(Array)
|
29
|
+
self.word_cloud_excluded = []
|
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
|
44
|
+
|
45
|
+
include ActsAsWordCloud::WordCloud::InstanceMethods
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module InstanceMethods
|
50
|
+
|
51
|
+
# collects associations on a model as long as they're not nil
|
52
|
+
#
|
53
|
+
# @param [Symbol] the association type to look in
|
54
|
+
# @returns [Array <Symbol>] association names under the passed in type
|
55
|
+
#
|
56
|
+
def word_cloud_get_associated(type)
|
57
|
+
self.class.reflect_on_all_associations(type).select {|r| self.send(r.name).present? }.collect { |r| r.name }
|
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 []
|
101
|
+
else
|
102
|
+
result = objects.flatten.reject { |n| n.respond_to?(:word_cloud) }
|
103
|
+
result.present? ? result : []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# goes through each object passed in trying the included methods for each of those objects
|
108
|
+
# keeps the first one to work and returns the value of that method called on the object
|
109
|
+
#
|
110
|
+
# @param [Array <Objects>] to look through for values
|
111
|
+
# @returns [Array <String>] values returned by method
|
112
|
+
#
|
113
|
+
def word_cloud_process_words(objects)
|
114
|
+
output = []
|
115
|
+
objects.each do |obj|
|
116
|
+
obj_calls = obj.word_cloud_using.select { |f| obj.respond_to?(f) }
|
117
|
+
if obj_calls.first.present?
|
118
|
+
output << obj.send(obj_calls.first)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
return output
|
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)
|
135
|
+
end
|
136
|
+
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
|
+
return output
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# returns values from methods specified in using option
|
155
|
+
# ignores string attributes that are listed in the skipped option
|
156
|
+
#
|
157
|
+
# @returns [Array <String>]
|
158
|
+
#
|
159
|
+
def word_cloud_get_valid_strings
|
160
|
+
output = []
|
161
|
+
ignore = []
|
162
|
+
|
163
|
+
self.word_cloud_using.each do |m|
|
164
|
+
output << self.send(m)
|
165
|
+
end
|
166
|
+
|
167
|
+
self.word_cloud_skipped.each do |s|
|
168
|
+
ignore << self.send(s)
|
169
|
+
end
|
170
|
+
|
171
|
+
# current model's string attributes
|
172
|
+
output += self.attributes.select {|k,v| v.class == String}.values
|
173
|
+
output -= ignore
|
174
|
+
|
175
|
+
return output
|
176
|
+
end
|
177
|
+
|
178
|
+
# finds string attributes on model
|
179
|
+
# processes associations on model, either fetching word_cloud results if they include mixin or default information if they don't
|
180
|
+
# if depth is said to something higher than one the word_cloud results on each associated model then makes more recursive calls (BFS)
|
181
|
+
#
|
182
|
+
# @params Integer, recursive depth for method; Symbol for the type of result (array or string)
|
183
|
+
# @returns [Array <String>] all processed values
|
184
|
+
#
|
185
|
+
def word_cloud( depth = self.word_cloud_depth, type = :string )
|
186
|
+
|
187
|
+
output = []
|
188
|
+
objects = []
|
189
|
+
no_mixin = []
|
190
|
+
|
191
|
+
# string attributes in current model
|
192
|
+
output = word_cloud_get_valid_strings
|
193
|
+
|
194
|
+
# objects on all associations collected
|
195
|
+
objects += self.word_cloud_associated_objects(:belongs_to)
|
196
|
+
objects += self.word_cloud_associated_objects(:has_one)
|
197
|
+
objects += self.word_cloud_associated_objects(:has_many)
|
198
|
+
|
199
|
+
# remove objects that have been explicitly excluded on current model
|
200
|
+
objects = word_cloud_exclude_words(objects)
|
201
|
+
# find associated models that do not include mixin
|
202
|
+
no_mixin = word_cloud_no_mixin(objects)
|
203
|
+
objects -= no_mixin
|
204
|
+
|
205
|
+
# process object using set methods for each model with mixin, or try preset general methods for models without
|
206
|
+
output += self.word_cloud_process_words(objects) + word_cloud_find_field(no_mixin)
|
207
|
+
|
208
|
+
# recursive step, if depth > 1, calls word cloud on objects array (which already excludes objects that don't have the mixin)
|
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(' ') )
|
214
|
+
else
|
215
|
+
if type == :array
|
216
|
+
output |= objects.collect { |o| o.word_cloud(depth-1, :array) }
|
217
|
+
return output.flatten.uniq
|
218
|
+
else
|
219
|
+
output |= objects.collect { |o| o.word_cloud(depth-1) }
|
220
|
+
return output.flatten.join(' ').split(' ').uniq.join(' ')
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
require 'active_record'
|
4
|
+
require 'rails/generators/active_record'
|
5
|
+
|
6
|
+
module ActsAsWordCloud
|
7
|
+
module Generators
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
9
|
+
include Rails::Generators::Migration
|
10
|
+
|
11
|
+
source_root File.expand_path(File.join(File.dirname(__FILE__), "templates"))
|
12
|
+
|
13
|
+
desc <<DESC
|
14
|
+
Description:
|
15
|
+
Copies over migrations and config for the normalizer.
|
16
|
+
DESC
|
17
|
+
|
18
|
+
def copy_config_file
|
19
|
+
copy_file "config.rb", "config/initializers/acts_as_word_cloud.rb"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
ActsAsWordCloud.configure do |config|
|
2
|
+
#the default setting for smallest recursive step for calling wordcloud on models
|
3
|
+
config.min_depth = 1
|
4
|
+
|
5
|
+
#methods whose values we'll attempt to get for models that don't include the mixin
|
6
|
+
config.no_mixin_fields = [:name, :title, :label]
|
7
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'find'
|
2
|
+
class ModelMethodsHelper
|
3
|
+
|
4
|
+
# finds or makes a model based on the given attributes
|
5
|
+
# @param [Constant] model_name The name of the model
|
6
|
+
# @param [Hash] attributes The attributes to find the model or add to the new one
|
7
|
+
def self.find_or_make_by_attributes(model_name, attributes)
|
8
|
+
instances = model_name.where(attributes)
|
9
|
+
if instances.empty?
|
10
|
+
return model_name.make(attributes)
|
11
|
+
else
|
12
|
+
return instances.first
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Uses the descendants_of method to determine the model structure
|
17
|
+
# Then tableizes and converts to symbol
|
18
|
+
#
|
19
|
+
# Load all models must be run for accurate descendants list
|
20
|
+
# it is now being called every time this method is called
|
21
|
+
# for now it works because this is only called one time when the authorization config is loaded on initialize
|
22
|
+
# if this ever changes, this code may need to be update (2-15-2012)
|
23
|
+
#
|
24
|
+
# @return [Array] Array with file names underscored and pluralized in the format [:users, :case_placements, :roles, :job_locations, ... ]
|
25
|
+
def self.get_model_symbol_array
|
26
|
+
# Old method:
|
27
|
+
# Major redesign of this method that finds namespaced models
|
28
|
+
# Finds all files in the given folder, tries to find the ruby files
|
29
|
+
# Then processes the names to get the names we need for the code
|
30
|
+
#
|
31
|
+
# @return [Array] Array with file names underscored and pluralized in the format [:users, :case_placements, :roles, :job_locations, ... ]
|
32
|
+
#model_array = []
|
33
|
+
#Find.find("#{Rails.root.to_s}/app/models") do |model_path|
|
34
|
+
# if model_path.match(/\.rb$/)
|
35
|
+
# model_path = model_path.gsub("#{Rails.root.to_s}/app/models/", "")
|
36
|
+
# model_path = model_path.gsub("/","_")
|
37
|
+
# model_path = model_path.gsub(/\.rb$/, "")
|
38
|
+
# model_array.push model_path.pluralize.to_sym
|
39
|
+
# end
|
40
|
+
#end
|
41
|
+
#return model_array
|
42
|
+
|
43
|
+
# new method
|
44
|
+
self.load_all_models
|
45
|
+
# returns the table name if there is one or tableizes the model name if not
|
46
|
+
# our permissions system generally uses table names for model permissions
|
47
|
+
return self.descendants_of(ActiveRecord::Base).map{ |m| m.abstract_class ? m.to_s.tableize.to_sym : m.table_name.to_sym }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Requires all models so that they are visible in the object space
|
51
|
+
# This is only necessary when we are not caching classes
|
52
|
+
def self.load_all_models
|
53
|
+
if !::Rails.application.config.cache_classes
|
54
|
+
Dir[Rails.root.join("app/models/**/*.rb")].each {|f| require f}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return a list of descendants of the given model.
|
59
|
+
#
|
60
|
+
# If direct is set to true, only return immediate descendants
|
61
|
+
# The load_all_models must be called before this is called or the result may not be correct
|
62
|
+
#
|
63
|
+
# @param [Constant] parent_class The parent class to look for descendants for
|
64
|
+
# @param [Boolean] direct Whether to look for all descendants or immediate descendants
|
65
|
+
# @return [Array] An array of class constants that satisfy the conditions of the parameters
|
66
|
+
def self.descendants_of(parent_class, direct = false)
|
67
|
+
classes = []
|
68
|
+
ObjectSpace.each_object(::Class).each do |klass|
|
69
|
+
if direct
|
70
|
+
classes << klass if klass.superclass == parent_class
|
71
|
+
else
|
72
|
+
classes << klass if klass < parent_class
|
73
|
+
end
|
74
|
+
end
|
75
|
+
return classes
|
76
|
+
end
|
77
|
+
|
78
|
+
# Convenience method to return the results of descendants_of with direct set to true
|
79
|
+
#
|
80
|
+
# The load_all_models must be called before this is called or the result may not be correct
|
81
|
+
#
|
82
|
+
# @param [Constant] parent_class The parent class to look for descendants for
|
83
|
+
# @return [Array] An array of class constants that satisfy the conditions of the parameters
|
84
|
+
def self.direct_descendants_of(parent_class)
|
85
|
+
return self.descendants_of(parent_class, true)
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "ActsAsWordCloud" do
|
4
|
+
before(:all) do
|
5
|
+
@lone_article = Article.make
|
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")
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "word_cloud" do
|
15
|
+
describe "class method use_word_cloud" do
|
16
|
+
it "should contain set or default values in attributes" do
|
17
|
+
@article.word_cloud_using.should == [:title]
|
18
|
+
@article.word_cloud_excluded.should == []
|
19
|
+
@article.word_cloud_depth.should == 1
|
20
|
+
@article.word_cloud_no_mixin_fields.should == [:name, :title, :label]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the right association models" do
|
25
|
+
@lone_article.word_cloud.should == [@lone_article.title, @lone_article.genre, @lone_article.content, @lone_article.author.name, @lone_article.publisher.name, @lone_article.site.domain ].join(' ')
|
26
|
+
@article.word_cloud.should == [@article.title, @article.genre, @article.content, @article.author.name, @article.publisher.name, @article.site.domain, @article.readers.first.username, "Following" ].join(' ')
|
27
|
+
|
28
|
+
@publisher2 = Publisher.make(:name => "publisher2", :location => "location2")
|
29
|
+
@site2 = Site.make( :name => "site2 name", :domain => "uff.us2", :genre => "site2 genre", :publisher => @publisher2)
|
30
|
+
@author2 = Author.make(:name => "author2", :genre => "author2 genre", :publisher => @publisher2, :site => @site2)
|
31
|
+
@article2 = Article.make(:title => "article2 title", :genre => "genre2", :content => "article2 text", :author => @author2, :publisher => @publisher2, :site => @site2)
|
32
|
+
@following2 = Following.make(:article => @article2, :reader => @reader , :special_name => "following2")
|
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 ]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "instance methods:" do
|
39
|
+
describe "word_cloud_associated_objects" do
|
40
|
+
it "should return correct models when called with belongs_to" do
|
41
|
+
@article.word_cloud_associated_objects(:belongs_to).should == [@article.author, @article.publisher, @article.site]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return correct models when called with has_many" do
|
45
|
+
@article.word_cloud_associated_objects(:has_many).should == [@article.followings, @article.readers]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "word_cloud_get_associated" do
|
50
|
+
it "should return collectoin of non-nil associated models" do
|
51
|
+
@article.word_cloud_get_associated(:belongs_to).should == [:author, :publisher, :site]
|
52
|
+
@lone_article.word_cloud_get_associated(:has_many).should == []
|
53
|
+
@article.word_cloud_get_associated(:has_many).should == [:followings, :readers]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "word_cloud_exclude_words" do
|
58
|
+
it "should not keep excluded models" do
|
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
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|