comparison page kinda works
authorMarcel Hlopko <marcel.hlopko@gmail.com>
Sun, 23 Jun 2013 11:22:20 +0200
changeset 91 d430a8ac253d
parent 70 e9c892b1c82b
child 92 c61f1cae722c
comparison page kinda works
web/app/assets/javascripts/charts.js
web/app/assets/javascripts/compare.js
web/app/assets/stylesheets/compare.css.scss
web/app/controllers/compare_controller.rb
web/app/helpers/compare_helper.rb
web/app/helpers/settings/benchmark_infos_helper.rb
web/app/helpers/settings/language_implementations_helper.rb
web/app/models/compare_query.rb
web/app/models/language_implementation.rb
web/app/views/compare/index.html.erb
web/app/views/index/_compare_table.html.erb
web/app/views/index/_main_nav.html.erb
web/app/views/index/_timeline_table.html.erb
web/config/routes.rb
web/lib/calipel_form_builder.rb
web/test/controllers/compare_controller_test.rb
web/test/helpers/compare_helper_test.rb
web/vendor/assets/javascripts/flot/jquery.flot.threshold.min.js
--- a/web/app/assets/javascripts/charts.js	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/assets/javascripts/charts.js	Sun Jun 23 11:22:20 2013 +0200
@@ -381,7 +381,6 @@
  */
 function viewportResized() {
     refreshCharts();
-    convertMenu();
 }
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/assets/javascripts/compare.js	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/assets/stylesheets/compare.css.scss	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,3 @@
+// Place all the styles related to the Compare controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/controllers/compare_controller.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,20 @@
+class CompareController < ApplicationController
+  def index
+    @compare_query = CompareQuery.new
+    @implementations = []
+    @benchmark_info = nil
+  end
+
+  def filter
+    @compare_query = CompareQuery.new(compare_query_params)
+    @implementations = @compare_query.filtered_implementations
+    @benchmark_info = @compare_query.benchmark_info
+    render "index"
+  end
+
+  private
+
+  def compare_query_params
+    params.require(:compare_query).permit!
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/helpers/compare_helper.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,13 @@
+module CompareHelper
+
+  def comparing_impls_headline(impls)
+    if impls.empty?
+      "Nothing to compare"
+    elsif impls.size == 1
+      "Showing only #{impls.first.name}"
+    else
+      "Comparing #{impls.map(&:name)[0..-2].join(", ")} and #{impls[-1].name}"
+    end
+  end
+
+end
--- a/web/app/helpers/settings/benchmark_infos_helper.rb	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/helpers/settings/benchmark_infos_helper.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -4,4 +4,7 @@
     BenchmarkInfo.all
   end
 
+  def benchmark_options
+    all_benchmarks.map { |l| [l.name, l.id] }
+  end
 end
--- a/web/app/helpers/settings/language_implementations_helper.rb	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/helpers/settings/language_implementations_helper.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -5,7 +5,17 @@
   end
 
   def language_impls_options
-    all_language_implementations.map { |l| [l.name, l.id] }
+    all_language_implementations.map { |l| [l.name, l.id.to_s] }
+  end
+
+  def all_dates_when_performed(implOrImpls)
+    if implOrImpls.kind_of?(LanguageImplementation)
+      implOrImpls.all_dates_when_performed
+    elsif implOrImpls.kind_of?(Enumerable) || implOrImpls.kind_of?(ActiveRecord::Relation)
+      SortedSet.new(implOrImpls.map(&:all_dates_when_performed).flatten).to_a
+    else
+      raise "Unexpected argument type: #{implOrImpls.class}"
+    end
   end
   
 end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/models/compare_query.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,24 @@
+class CompareQuery
+  include ActiveModel::Model
+
+  attr_accessor :benchmark_id, :implementations
+
+  def initialize(*args)
+    super
+    @implementations ||= {}
+  end
+
+  def filtered_implementations
+    LanguageImplementation.where(id: impls_to_array_of_ids)
+  end
+
+  def benchmark_info
+    BenchmarkInfo.find(benchmark_id)
+  end
+
+  private
+
+  def impls_to_array_of_ids
+    implementations.keys
+  end
+end
--- a/web/app/models/language_implementation.rb	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/models/language_implementation.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -25,11 +25,7 @@
   end
 
   def all_dates_when_performed
-    result = Set.new
-    benchmark_batches.each do |batch|
-      result.add batch.performed_at
-    end
-    result
+    SortedSet.new(benchmark_batches.map(&:performed_at).flatten).to_a
   end
 
   def results_at(time)
@@ -39,4 +35,18 @@
     end
   end
 
+  def results_of(benchmark_info, time)
+    batch_with_given_date = benchmark_batches
+    .where(performed_at: time)
+    .first
+
+    if batch_with_given_date
+      batch_with_given_date
+      .benchmark_results(benchmark_info: benchmark_info)
+      .first
+    else
+      nil
+    end
+  end
+
 end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/views/compare/index.html.erb	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,31 @@
+<%= currently_at "compare" %>
+
+<div class="span3">
+  <div class="well">
+    <%= form_for @compare_query,
+      url: filter_compare_index_path,
+      builder: CalipelFormBuilder do |f| %> 
+      <%= f.fieldset_item "Comparing" do %>
+        <%= f.select_field_item :benchmark_id, benchmark_options %>
+        <%= f.checkboxes_item :implementations, language_impls_options %>
+        <%= f.submit_item "Compare" %>
+      <% end %>
+    <% end %>
+  </div>
+</div>
+
+<div class="span9">
+  <% unless @implementations.empty? %>
+    <h1>
+      Comparison for 
+      <%= @benchmark_info.name %>
+    </h1>
+    <p>
+      <%= comparing_impls_headline(@implementations) %>
+    </p>
+
+    <%= render "index/compare_table", 
+      impls: @implementations, 
+      benchmark_info: @benchmark_info %>
+  <% end %>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/app/views/index/_compare_table.html.erb	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,27 @@
+<% make_chart = true if local_assigns[:make_chart].nil? %>
+<div >
+  <div class="<%= make_chart ? "line-chart flot time-chart" : "" %>">
+    <table class="table table-condensed">
+      <thead>
+        <tr>
+          <th>Měsíc</th>
+          <% impls.each do |impl| %> 
+            <th><%= impl.name %></th>
+          <% end %>
+        </tr>
+      </thead>
+      <tbody>
+        <% all_dates_when_performed(impls).each do |date| %>
+          <tr>
+            <%= content_tag :th, 
+              (make_chart ? date_to_millis(date) : t(date)), 
+              'data-timestamp' => date_to_millis(date) %>
+            <% impls.each do |impl| %>
+              td><%= impl.results_of(benchmark_info, date).try(:min_duration) %></td>
+            <% end %>
+          </tr>
+        <% end %>
+      </tbody>
+    </table>
+  </div>
+</div>
--- a/web/app/views/index/_main_nav.html.erb	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/views/index/_main_nav.html.erb	Sun Jun 23 11:22:20 2013 +0200
@@ -19,6 +19,9 @@
             <%= nav_tab("results", 
                         current_tab: current_tab, 
                         class: "special") { link_to("Results", results_path) } %>
+            <%= nav_tab("compare", 
+                        current_tab: current_tab, 
+                        class: "special") { link_to("Compare", compare_index_path) } %>
             <%= nav_tab("about", 
                         current_tab: current_tab, 
                         class: "special") { link_to("About", about_path) } %>
--- a/web/app/views/index/_timeline_table.html.erb	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/app/views/index/_timeline_table.html.erb	Sun Jun 23 11:22:20 2013 +0200
@@ -11,7 +11,7 @@
         </tr>
       </thead>
       <tbody>
-        <% impl.all_dates_when_performed.each do |date| %>
+        <% all_dates_when_performed(impl).each do |date| %>
           <tr>
             <%= content_tag :th, 
               (make_chart ? date_to_millis(date) : t(date)), 
--- a/web/config/routes.rb	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/config/routes.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -23,6 +23,10 @@
     end
   end
 
+  resources :compare, only: :index do
+    post "filter", on: :collection
+  end
+
   namespace "settings" do
     resources :languages, except: [:new]    
     resources :language_implementations, except: [:new]    
--- a/web/lib/calipel_form_builder.rb	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/lib/calipel_form_builder.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -2,14 +2,17 @@
 
   def field_item(attribute, &block)
     @template.content_tag(:div, class: "control-group #{'error' if errors_present?(attribute)}") do
-      label_tag = label(attribute, class: "control-label")
       input = @template.content_tag(:div, class: "controls") do
         yield + errors_on(attribute)
       end
-      "#{label_tag}\n#{input}".html_safe
+      "#{label_item attribute}\n#{input}".html_safe
     end
   end
 
+  def label_item(attribute)
+    label(attribute, class: "control-label")
+  end
+
   def errors_on(attribute)
     if errors_present?(attribute)
       @template.content_tag("span",
@@ -44,6 +47,27 @@
     form_input_item(:file_field, attribute, *args)
   end
 
+  def checkboxes_item(attribute, options, *args)
+    #omg what just happened
+    @template.content_tag(:div, class: "control-group") do
+      @template.content_tag(:div, class: "controls") do
+        options.each do |opt|
+          @template.concat(
+            label("[#{attribute}][#{opt[1]}]", class: "checkbox") do
+              checkbox = @template.check_box_tag("#{@object_name}[#{attribute}][#{opt[1]}]",
+                                                       opt[1], 
+                                                         (true if 
+                                                          @object.public_send(attribute).include?(opt[1])))
+
+              @template.concat(checkbox)
+              @template.concat(opt[0])
+            end
+          )
+        end
+      end
+    end
+  end
+
   def select_field_item(attribute, options, *args)
     form_input_item(:select, attribute, options, *args)
   end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/controllers/compare_controller_test.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,9 @@
+require 'test_helper'
+
+class CompareControllerTest < ActionController::TestCase
+  test "should get index" do
+    get :index
+    assert_response :success
+  end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/helpers/compare_helper_test.rb	Sun Jun 23 11:22:20 2013 +0200
@@ -0,0 +1,4 @@
+require 'test_helper'
+
+class CompareHelperTest < ActionView::TestCase
+end
--- a/web/vendor/assets/javascripts/flot/jquery.flot.threshold.min.js	Sat Jun 22 15:02:47 2013 +0200
+++ b/web/vendor/assets/javascripts/flot/jquery.flot.threshold.min.js	Sun Jun 23 11:22:20 2013 +0200
@@ -40,4 +40,4 @@
 cleared and the special "originSeries" attribute set to the original series.
 You may need to check for this in hover events.
 
-*/(function(e){function n(t){function n(t,n,r,i,s){var o=r.pointsize,u,a,f,l,c,h=e.extend({},n);h.datapoints={points:[],pointsize:o,format:r.format},h.label=null,h.color=s,h.threshold=null,h.originSeries=n,h.data=[];var p=r.points,d=n.lines.show,v=[],m=[],g;for(u=0;u<p.length;u+=o){a=p[u],f=p[u+1],c=l,f<i?l=v:l=m;if(d&&c!=l&&a!=null&&u>0&&p[u-o]!=null){var y=a+(i-f)*(a-p[u-o])/(f-p[u-o+1]);c.push(y),c.push(i);for(g=2;g<o;++g)c.push(p[u+g]);l.push(null),l.push(null);for(g=2;g<o;++g)l.push(p[u+g]);l.push(y),l.push(i);for(g=2;g<o;++g)l.push(p[u+g])}l.push(a),l.push(f);for(g=2;g<o;++g)l.push(p[u+g])}r.points=m,h.datapoints.points=v;if(h.datapoints.points.length>0){var b=e.inArray(n,t.getData());t.getData().splice(b+1,0,h)}}function r(t,r,i){if(!r.threshold)return;r.threshold instanceof Array?(r.threshold.sort(function(e,t){return e.below-t.below}),e(r.threshold).each(function(e,o){n(t,r,i,o.below,o.color)})):n(t,r,i,r.threshold.below,r.threshold.color)}t.hooks.processDatapoints.push(r)}var t={series:{threshold:null}};e.plot.plugins.push({init:n,options:t,name:"threshold",version:"1.2"})})(jQuery);
\ No newline at end of file
+*/(function(e){function n(t){function n(t,n,r,i,s){var o=r.pointsize,u,a,f,l,c,h=e.extend({},n);h.datapoints={points:[],pointsize:o,format:r.format},h.label=null,h.color=s,h.threshold=null,h.originSeries=n,h.data=[];var p=r.points,d=n.lines.show,v=[],m=[],g;for(u=0;u<p.length;u+=o){a=p[u],f=p[u+1],c=l,f<i?l=v:l=m;if(d&&c!=l&&a!=null&&u>0&&p[u-o]!=null){var y=a+(i-f)*(a-p[u-o])/(f-p[u-o+1]);c.push(y),c.push(i);for(g=2;g<o;++g)c.push(p[u+g]);l.push(null),l.push(null);for(g=2;g<o;++g)l.push(p[u+g]);l.push(y),l.push(i);for(g=2;g<o;++g)l.push(p[u+g])}l.push(a),l.push(f);for(g=2;g<o;++g)l.push(p[u+g])}r.points=m,h.datapoints.points=v;if(h.datapoints.points.length>0){var b=e.inArray(n,t.getData());t.getData().splice(b+1,0,h)}}function r(t,r,i){if(!r.threshold)return;r.threshold instanceof Array?(r.threshold.sort(function(e,t){return e.below-t.below}),e(r.threshold).each(function(e,o){n(t,r,i,o.below,o.color)})):n(t,r,i,r.threshold.below,r.threshold.color)}t.hooks.processDatapoints.push(r)}var t={series:{threshold:null}};e.plot.plugins.push({init:n,options:t,name:"threshold",version:"1.2"})})(jQuery);