diff --git a/app/controllers/stats_controller.rb b/app/controllers/stats_controller.rb index cc0fe6cf..5512abad 100644 --- a/app/controllers/stats_controller.rb +++ b/app/controllers/stats_controller.rb @@ -552,49 +552,11 @@ class StatsController < ApplicationController end def get_stats_tags - # tag cloud code inspired by this article - # http://www.juixe.com/techknow/index.php/2006/07/15/acts-as-taggable-tag-cloud/ + tags = Stats::TagCloudQuery.new(current_user).result + @tag_cloud = Stats::TagCloud.new(tags) - levels=10 - # TODO: parameterize limit - - # Get the tag cloud for all tags for actions - query = "SELECT tags.id, name, count(*) AS count" - query << " FROM taggings, tags, todos" - query << " WHERE tags.id = tag_id" - query << " AND taggings.taggable_id = todos.id" - query << " AND todos.user_id="+current_user.id.to_s+" " - query << " AND taggings.taggable_type='Todo' " - query << " GROUP BY tags.id, tags.name" - query << " ORDER BY count DESC, name" - query << " LIMIT 100" - @tags_for_cloud = Tag.find_by_sql(query).sort_by { |tag| tag.name.downcase } - tag_counts = @tags_for_cloud.map(&:count) - max = tag_counts.max || 0 - @tags_min = tag_counts.min || 0 - - @tags_divisor = ((max - @tags_min) / levels) + 1 - - # Get the tag cloud for all tags for actions - query = "SELECT tags.id, tags.name AS name, count(*) AS count" - query << " FROM taggings, tags, todos" - query << " WHERE tags.id = tag_id" - query << " AND todos.user_id=? " - query << " AND taggings.taggable_type='Todo' " - query << " AND taggings.taggable_id=todos.id " - query << " AND (todos.created_at > ? OR " - query << " todos.completed_at > ?) " - query << " GROUP BY tags.id, tags.name" - query << " ORDER BY count DESC, name" - query << " LIMIT 100" - @tags_for_cloud_90days = Tag.find_by_sql( - [query, current_user.id, @cut_off_3months, @cut_off_3months] - ).sort_by { |tag| tag.name.downcase } - - tag_counts_90days = @tags_for_cloud_90days.map(&:count) - max_90days = tag_counts_90days.max || 0 - @tags_min_90days = tag_counts_90days.min || 0 - @tags_divisor_90days = ((max_90days - @tags_min_90days) / levels) + 1 + tags = Stats::TagCloudQuery.new(current_user, @cut_off_3months).result + @tag_cloud_90days = Stats::TagCloud.new(tags) end def get_ids_from (actions, week_from, week_to, at_end) diff --git a/app/models/stats/tag_cloud.rb b/app/models/stats/tag_cloud.rb new file mode 100644 index 00000000..ef03c8fc --- /dev/null +++ b/app/models/stats/tag_cloud.rb @@ -0,0 +1,38 @@ +# tag cloud code inspired by this article +# http://www.juixe.com/techknow/index.php/2006/07/15/acts-as-taggable-tag-cloud/ +module Stats + class TagCloud + + attr_reader :levels, :tags + def initialize(tags) + @levels = 10 + @tags = tags.sort_by { |tag| tag.name.downcase } + end + + def empty? + tags.empty? + end + + def font_size(tag) + (9 + 2*(tag.count-min)/divisor) + end + + private + + def max + @max ||= counts.max + end + + def min + @min ||= counts.min + end + + def divisor + @divisor ||= ((max - min) / levels) + 1 + end + + def counts + @counts ||= tags.map {|t| t.count} + end + end +end diff --git a/app/models/stats/tag_cloud_query.rb b/app/models/stats/tag_cloud_query.rb new file mode 100644 index 00000000..e754cc6c --- /dev/null +++ b/app/models/stats/tag_cloud_query.rb @@ -0,0 +1,38 @@ +module Stats + class TagCloudQuery + + attr_reader :user, :cutoff + def initialize(user, cutoff = nil) + @user = user + @cutoff = cutoff + end + + def result + Tag.find_by_sql(query_options) + end + + def query_options + options = [sql, user.id] + options += [cutoff, cutoff] if cutoff + options + end + + def sql + # TODO: parameterize limit + query = "SELECT tags.id, tags.name AS name, count(*) AS count" + query << " FROM taggings, tags, todos" + query << " WHERE tags.id = tag_id" + query << " AND todos.user_id=? " + query << " AND taggings.taggable_type='Todo' " + query << " AND taggings.taggable_id=todos.id " + if cutoff + query << " AND (todos.created_at > ? OR " + query << " todos.completed_at > ?) " + end + query << " GROUP BY tags.id, tags.name" + query << " ORDER BY count DESC, name" + query << " LIMIT 100" + end + + end +end diff --git a/app/views/stats/_tags.html.erb b/app/views/stats/_tags.html.erb index e1f53f83..98140297 100755 --- a/app/views/stats/_tags.html.erb +++ b/app/views/stats/_tags.html.erb @@ -1,34 +1,19 @@
-

<%= t('stats.tag_cloud_title') %>

-

<%= t('stats.tag_cloud_description') %>

- -

- <% if @tags_for_cloud.size < 1 +

<%= t("stats.tag_cloud#{key}_title") %>

+

<%= t("stats.tag_cloud#{key}_description") %>

+

+<% + if tag_cloud.empty? t('stats.no_tags_available') - else - @tags_for_cloud.each do |t| %> - <%= link_to t.name, tag_path(t.name), { - :style => "font-size: " + (9 + 2*(t.count.to_i-@tags_min)/@tags_divisor).to_s + "pt", - :title => t.count.to_s+" #{t('common.actions_midsentence', :count => t.count)}"} - -%> <% + else + tag_cloud.tags.each do |t| +%><%= + link_to t.name, tag_path(t.name), { + :style => "font-size: " + "#{tag_cloud.font_size(t)}pt", + :title => "#{t.count} #{t('common.actions_midsentence', :count => t.count)}"} +-%><% + end end - end-%> +-%>

- -
-

<%= t('stats.tag_cloud_90days_title') %>

-

<%= t('stats.tag_cloud_90days_description') %>

-

- <% if @tags_for_cloud_90days.size < 1 - t('stats.no_tags_available') - else - @tags_for_cloud_90days.each do |t| %> - <%= link_to t.name, tag_path(t.name), { - :style => "font-size: " + (9 + 2*(t.count.to_i-@tags_min_90days)/@tags_divisor_90days).to_s + "pt", - :title => t.count.to_s+" #{t('common.actions_midsentence', :count => t.count)}"} - -%> <% - end - end-%> -

-
\ No newline at end of file diff --git a/app/views/stats/index.html.erb b/app/views/stats/index.html.erb index 7470731e..0f44f2c3 100755 --- a/app/views/stats/index.html.erb +++ b/app/views/stats/index.html.erb @@ -15,7 +15,8 @@ <%= render :partial => 'projects' -%>

<%= t('stats.tags') %>

- <%= render :partial => 'tags' -%> + <%= render :partial => 'tags', :locals => {:tag_cloud => @tag_cloud, :key => ''} -%> + <%= render :partial => 'tags', :locals => {:tag_cloud => @tag_cloud_90days, :key => '_90days'} -%> <% else -%> @@ -23,4 +24,4 @@ <% end -%> - \ No newline at end of file + diff --git a/test/minimal_test_helper.rb b/test/minimal_test_helper.rb new file mode 100644 index 00000000..0c8ffc32 --- /dev/null +++ b/test/minimal_test_helper.rb @@ -0,0 +1,7 @@ +require 'simplecov' +SimpleCov.start 'rails' + +ENV["RAILS_ENV"] = "test" +require 'test/unit' + +$:.unshift File.dirname(File.dirname(__FILE__)) diff --git a/test/test_helper.rb b/test/test_helper.rb index 7efb8388..363777c2 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,7 +1,4 @@ -require 'simplecov' -SimpleCov.start 'rails' - -ENV["RAILS_ENV"] = "test" +require File.expand_path('../minimal_test_helper', __FILE__) require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' diff --git a/test/unit/tag_cloud_query_test.rb b/test/unit/tag_cloud_query_test.rb new file mode 100644 index 00000000..e0dc252e --- /dev/null +++ b/test/unit/tag_cloud_query_test.rb @@ -0,0 +1,31 @@ +require File.expand_path(File.dirname(__FILE__) + '/../test_helper') + +class TagCloudQueryTest < ActiveSupport::TestCase + + fixtures :tags, :taggings, :users + + def user + @user ||= User.find 1 + end + + def test_get_all_tags + tags = Stats::TagCloudQuery.new(user).result + assert_equal 2, tags.size + tags.sort_by! {|t| t.id} + tag = tags.first + assert_equal 3, tag.count + assert_equal "foo", tag.name + + tag = tags.last + assert_equal 1, tag.count + assert_equal "bar", tag.name + end + + def test_get_subset_of_tags + tags = Stats::TagCloudQuery.new(user, 1.week.ago).result + + assert_equal 1, tags.size + assert_equal 2, tags.first.count + assert_equal "foo", tags.first.name + end +end diff --git a/test/unit/tag_cloud_test.rb b/test/unit/tag_cloud_test.rb new file mode 100644 index 00000000..d40bcc51 --- /dev/null +++ b/test/unit/tag_cloud_test.rb @@ -0,0 +1,23 @@ +require File.expand_path(File.dirname(__FILE__) + '/../minimal_test_helper') +require 'app/models/stats/tag_cloud' + +class TagCloudTest < Test::Unit::TestCase + + FakeTag = Struct.new(:name, :count) + + def test_tags_get_sorted_alphabetically + tags = [FakeTag.new("bee", 1), FakeTag.new("See", 10), FakeTag.new("aye", 100)] + + assert_equal %w(aye bee See), Stats::TagCloud.new(tags).tags.map(&:name) + end + + def test_tag_font_size + tags = [FakeTag.new("bee", 1), FakeTag.new("See", 10), FakeTag.new("aye", 100)] + cloud = Stats::TagCloud.new(tags) + + assert_equal 9, cloud.font_size(FakeTag.new("whatever", 1)) + assert_equal 18, cloud.font_size(FakeTag.new("whatever", 50)) + assert_equal 28, cloud.font_size(FakeTag.new("whatever", 100)) + end + +end