From 946d54450cc1652af4ef42120d08c09275a66d4c Mon Sep 17 00:00:00 2001 From: Bruce Williams Date: Wed, 1 Oct 2008 16:57:00 -0500 Subject: [PATCH] Extract core functionality --- Rakefile | 1 + lib/fiveruns_tuneup_core.rb | 393 ------------------------------------ lib/fiveruns_tuneup_merb.rb | 3 +- 3 files changed, 2 insertions(+), 395 deletions(-) delete mode 100644 lib/fiveruns_tuneup_core.rb diff --git a/Rakefile b/Rakefile index 7225f13..8fad89c 100644 --- a/Rakefile +++ b/Rakefile @@ -24,6 +24,7 @@ spec = Gem::Specification.new do |s| s.author = AUTHOR s.email = EMAIL s.homepage = HOMEPAGE + s.add_dependency('fiveruns_tuneup_core') s.add_dependency('merb-slices', '>= 0.9.5') s.require_path = 'lib' s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec,app,public,stubs}/**/*") diff --git a/lib/fiveruns_tuneup_core.rb b/lib/fiveruns_tuneup_core.rb deleted file mode 100644 index 20e6a16..0000000 --- a/lib/fiveruns_tuneup_core.rb +++ /dev/null @@ -1,393 +0,0 @@ -require 'erb' - -module Fiveruns - - module Tuneup - - class CalculationError < ::RuntimeError; end - - class << self - attr_accessor :javascripts_path - attr_accessor :stylesheets_path - end - - def self.record(&block) - Step.reset! - root = RootStep.new - root.record(&block) - root - end - - def self.step(name, layer, extras = {}, &block) - trace = format_caller(caller) - Step.new(name, layer, extras.merge('Caller' => trace), nil).record(&block) - end - - def self.insert_panel(body, run) - return body unless run - tag = body[/(]*>)/i, 1] - return body unless tag - panel = Panel.new(run) - body.sub(/<\/head>/i, head << '').sub(tag, tag + panel.to_html) - end - - def self.head - %( - - - ) - end - - def self.format_caller(trace) - valid_lines = trace.reject { |line| line =~ /fiveruns_tuneup/ }[0,5] - linked_lines = valid_lines.map { |line| editor_link_line(line) } - '
%s
' % linked_lines.join("\n") - end - - def self.strip_root(text) - pattern = /^#{Regexp.quote Merb.root}\/?/o - if text =~ pattern - result = text.sub(pattern, '') - in_app = result !~ /^gems\// - [in_app, result] - else - [false, text] - end - end - - # TODO: Refactor - def self.editor_link_line(line) - filename, number, extra = line.match(/^(.+?):(\d+)(?::in\b(.*?))?/)[1, 2] - in_app, line = strip_root(line) - name = if line.size > 87 - "…#{CGI.escapeHTML line.sub(/^.*?(.{84})$/, '\1')}" - else - line - end - name = if in_app - if name =~ /`/ - name.sub(/^(.*?)\s+`(.*?)'$/, %q(\1 `\2')) - else - %(#{name}) - end - else - name.sub(/([^\/\\]+\.\S+:\d+:in)\s+`(.*?)'$/, %q(\1 `\2')) - end - %(%s%s) % [CGI.escapeHTML(line), filename, number, name, extra] - end - - module Templating - - def h(text) - CGI.escapeHTML(text) - end - - def to_html - ERB.new(template).result(binding) - end - - end - - class RootStep - include Templating - attr_reader :children, :bar - attr_accessor :time, :parent - def initialize(time = nil) - @time = time - @children = [] - @bar = Bar.new(self) - end - - def root - parent ? parent.root : self - end - - def record - start = Time.now - result = Step.inside(self) { yield } - @time = Time.now - start - result - end - def disparity - result = time - children.inject(0) { |sum, child| sum + child.time } - if result < 0 - raise CalculationError, "Child steps exceed parent step size" - end - result - end - def add_child(child) - child.parent = self - children << child - end - def format_time(time) - '%.1fms' % (time * 1000) - end - def layer_portions - children.first.layer_portions - end - def to_json - {:children => children, :time => time}.to_json - end - - def proportion - time / root.time - end - - def template - %( -
- <%= bar.to_html %> - <%= (time * 1000).to_i %> ms -
- ) - end - - end - - class Step < RootStep - - def self.stack - @stack ||= [] - end - - def self.reset! - stack.clear - end - - def self.inside(step) - unless stack.empty? - stack.last.add_child(step) - end - stack << step - result = yield - stack.pop - result - end - - attr_reader :name, :layer, :extras - def initialize(name, layer, raw_extras = {}, time = nil) - super(time) - @name = name - @layer = layer - @extras = build_extras(raw_extras) - end - - def children_with_disparity - return children if children.empty? - layer_name = layer if respond_to?(:layer) - extra_step = DisparityStep.new(layer_name, disparity) - extra_step.parent = parent - children + [extra_step] - end - - def layer_portions - @layer_portions ||= begin - result = {:model => 0, :view => 0, :controller => 0} - if children.empty? - result[layer] = 1 - else - times = children.inject({}) do |totals, child| - totals[child.layer] ||= 0 - totals[child.layer] += child.time - totals - end - times[layer] ||= 0 - times[layer] += disparity - times.inject(result) do |all, (l, t)| - result[l] = t / time - result - end - end - result - end - end - - def to_json - {:children => children_with_disparity, :time => time}.to_json - end - - private - - def build_extras(raw_extras) - raw_extras.sort_by { |k, v| k.to_s }.map do |name, data| - data = data.is_a?(Array) ? data : [data] - Extra.new(name, *data ) - end - end - - def template - %( -
  • -
      -
    • - <%= '%.1f' % (time * 1000) %> ms - <%=h name %> - (?) -
    • -
    • <%= bar.to_html %>
    • -
    • -
    -
    -
    -
    - <% extras.each do |extra| %> - <%= extra.to_html %> - <% end %> -
    -
    -
    - <%= html_children %> -
  • - ) - end - - private - - def html_class - %W(fiveruns_tuneup_step #{'with_children' if children.any?} #{'tuneup-opened' if root.children.first.object_id == self.object_id}).compact.join(' ') - end - - def html_children - return unless children.any? - %() % children_with_disparity.map { |child| child.to_html }.join - end - - class Extra - include Templating - - attr_reader :name, :content, :extended - def initialize(name, content, extended = {}) - @name = name - @content = content - @extended = extended - end - - private - - def template - %( -
    <%= h name %>
    -
    - <%= content %> - <% if extended.any? %> - <% extended.each do |name, value| %> -
    <%= value %>
    - <% end %> - <% end %> -
    - ) - end - - end - - end - - class DisparityStep < Step - - def initialize(layer_name, disparity) - super '(Other)', layer_name, {}, disparity - @extras = build_extras description - end - - private - - def description - { - 'What is this?' => %( -

    - Other is the amount of time spent executing - code that TuneUp doesn't wrap to extract more information. - To reduce overhead and make the listing more - manageable, we don't generate steps for every operation. -

    -

    #{layer_description}

    - ) - } - end - - def layer_description - case layer - when :model - "In the model layer, this is probably ORM overhead (out of your control)." - when :view - "In the view layer, this is probably framework overhead during render (out of your control)." - when :controller - %( - In the controller layer, this is probably framework overhead during action execution (out of your control), - or time spent executing your code in the action (calls to private methods, libraries, etc). - ) - end - end - - end - - class Bar - include Templating - - attr_reader :step - def initialize(step) - @step = step - end - - private - - def template - %( - - ) - end - - def component(layer) - width = width_of(layer) - %( -
  • #{layer.to_s[0,1].capitalize if width >= 12}
  • - ) - end - - def width_of(layer) - portion = step.layer_portions[layer.to_sym] - result = portion * 200 * step.proportion - result < 1 && portion != 0 ? 1 : result - end - - end - - class Panel - include Templating - - attr_reader :root - def initialize(root) - @root = root - end - - private - - def template - %( -

    FiveRuns TuneUp

    -
    -
    - <%= root.to_html %> - <%# In later version... %> - -
    -
      - <% root.children.each do |child| %> - <%= child.to_html %> - <% end %> -
    • -
    -
    -
    - ) - end - - end - - end - -end \ No newline at end of file diff --git a/lib/fiveruns_tuneup_merb.rb b/lib/fiveruns_tuneup_merb.rb index d390413..c54b60f 100644 --- a/lib/fiveruns_tuneup_merb.rb +++ b/lib/fiveruns_tuneup_merb.rb @@ -2,11 +2,10 @@ $:.unshift File.dirname(__FILE__) - load_dependency 'merb-slices' Merb::Plugins.add_rakefiles "fiveruns_tuneup_merb/merbtasks", "fiveruns_tuneup_merb/slicetasks", "fiveruns_tuneup_merb/spectasks" - require File.dirname(__FILE__) / 'fiveruns_tuneup_core' + require 'fiveruns_tuneup_core' require File.dirname(__FILE__) / 'fiveruns_tuneup_merb' / 'instrumentation' # Register the Slice for the current host application