This commit is contained in:
Matt Rogers 2013-03-01 16:49:53 -06:00
commit 8b0f3e986a
9 changed files with 159 additions and 77 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -1,34 +1,19 @@
<div class="stats_module">
<h3><%= t('stats.tag_cloud_title') %></h3>
<p><%= t('stats.tag_cloud_description') %></p>
<p>
<% if @tags_for_cloud.size < 1
<h3><%= t("stats.tag_cloud#{key}_title") %></h3>
<p><%= t("stats.tag_cloud#{key}_description") %></p>
<p>
<%
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-%>
-%>
</p>
</div>
<div class="stats_module">
<h3><%= t('stats.tag_cloud_90days_title') %></h3>
<p><%= t('stats.tag_cloud_90days_description') %></p>
<p>
<% 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-%>
</p>
</div>

View file

@ -15,7 +15,8 @@
<%= render :partial => 'projects' -%>
<h2><%= t('stats.tags') %></h2>
<%= 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 -%>
</div>
</div>

View file

@ -0,0 +1,7 @@
require 'simplecov'
SimpleCov.start 'rails'
ENV["RAILS_ENV"] = "test"
require 'test/unit'
$:.unshift File.dirname(File.dirname(__FILE__))

View file

@ -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'

View file

@ -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

View file

@ -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