Class: Ruber::RSpec::ToolWidget

Inherits:
FilteredOutputWidget show all
Defined in:
plugins/rspec/rspec.rb,
plugins/rspec/tool_widget.rb

Overview

Tool widget used by the rspec plugin.

It displays the output from the spec program in a multi column tree. The name of failing or pending examples are displayed in a full line; all other information, such as the location of the example, the error message and so on are displayed in child items.

While the examples are being run, a progress bar is shown.

Constant Summary

Constants inherited from OutputWidget

IsTitleRole, OutputTypeRole

Instance Attribute Summary

Attributes inherited from FilteredOutputWidget

filter_model

Attributes inherited from OutputWidget

action_list, actions, auto_scroll, ignore_word_wrap_option, model, skip_first_file_in_title, view, working_dir

Instance Method Summary (collapse)

Methods inherited from FilteredOutputWidget

#clear_filter, #copy, #copy_selected, #create_filter_from_editor, #create_standard_actions, #ignore_filter, keyReleaseEvent, #maybe_open_file, #scroll_to, #show_editor

Methods inherited from OutputWidget

#clear_output, #copy, #copy_selected, #create_standard_actions, #create_widgets, #do_auto_scroll, #fill_menu, #find_filename_in_string, #has_title?, #hints, #maybe_open_file, #pinned_down?, #rows_changed, #scroll_to, #selection_changed, #set_color_for, #set_output_type, #setup_model, #show_menu, #update_index_color, #with_auto_scrolling

Methods included from GuiStatesHandler

#change_state, included, #initialize_states_handler, #register_action_handler, #remove_action_handler_for, #state

API for feature rspec

Constructor Details

- (ToolWidget) initialize(parent = nil)

A new instance of ToolWidget

Parameters:

  • parent (Qt::Widget, nil) (defaults to: nil)

    the parent widget



622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
# File 'plugins/rspec/rspec.rb', line 622

def initialize parent = nil
  super parent, :view => :tree, :filter => FilterModel.new
  @toplevel_width = 0
  @ignore_word_wrap_option = true
  view.text_elide_mode = Qt::ElideNone
  model.append_column [] if model.column_count < 2
  @progress_bar = Qt::ProgressBar.new(self){|w| w.hide}
  layout.add_widget @progress_bar, 2,0
  view.header_hidden = true
  view.header.resize_mode = Qt::HeaderView::ResizeToContents
  connect Ruber[:rspec], SIGNAL(:process_started), self, SLOT(:spec_started)
  connect Ruber[:rspec], SIGNAL('process_finished(int, QString)'), self, SLOT('spec_finished(int, QString)')
  view.word_wrap = true
  filter.connect(SIGNAL('rowsInserted(QModelIndex, int, int)')) do |par, st, en|
    if !par.valid?
      st.upto(en) do |i|
        view.set_first_column_spanned i, par, true
      end
    end
  end
  #without these, the horizontal scrollbars won't be shown
  connect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
  connect view, SIGNAL('collapsed(QModelIndex)'), self, SLOT(:resize_columns)
  setup_actions
end

Instance Method Details

- (nil) auto_expand_items (private)

Expands items according to the rspec/auto_expand option

If the option is :expand_first, the first failed example is expanded; if the option is :expand_all, all failed or pending examples are expanded. If the option is :expand_none, nothing is done

Returns:

  • (nil)


881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
# File 'plugins/rspec/rspec.rb', line 881

def auto_expand_items
  if model.row_count > 1
    case Ruber[:config][:rspec, :auto_expand]
    when :expand_first
      item = model.each_row.find{|items| items[0].has_children}
      view.expand filter_model.map_from_source(item[0].index) if item
    when :expand_all
      without_resizing_columns do
        model.each_row do |items|
          view.expand filter_model.map_from_source(items[0].index)
        end
      end
      resize_columns
    end
  end
  nil
end

- (nil) change_current_example(data)

Changes the current example

Currently, this only affects the tool tip displayed by the progress bar.

which contains the text of the tool tip to use.

Parameters:

  • data (Hash)

    the data to use. It must contain the :description entry,

Returns:

  • (nil)


694
695
696
697
# File 'plugins/rspec/rspec.rb', line 694

def change_current_example data
  @progress_bar.tool_tip = data[:description]
  nil
end

- (Object) compute_spanning_cols_size (private)



368
369
370
371
# File 'plugins/rspec/tool_widget.rb', line 368

def compute_spanning_cols_size
  metrics = view.font_metrics
  @toplevel_width = source_model.each_row.map{|r| metrics.bounding_rect(r[0].text).width}.max || 0
end

- (Object) display_example(data)

Displays the data relative to an example in the widget

Actually, this method simply passes its argument to a more specific method, depending on the data it contains.

the example. This hash must contain the :type key, which tells which kind of event the hash describes. The other entries change depending on the method which will be called, which is determined according to the :type entry:

Parameters:

  • data (Hash)

    a hash containing the data describing the results of running



669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
# File 'plugins/rspec/rspec.rb', line 669

def display_example data
  unless data.is_a?(Hash)
    model.insert_lines data.to_s, :output, nil
    return
  end
  case data[:type]
  when :success then display_successful_example data
  when :failure then display_failed_example data
  when :pending then display_pending_example data
  when :new_example then change_current_example data
  when :start then set_example_count data
  when :summary then display_summary data
  else model.insert_lines data.to_s, :output, nil
  end
end

- (nil) display_failed_example(data)

Displays information about a failed example in the tool widget.

Parameters:

  • data (Hash)

    the data about the example.

Options Hash (data):

  • :location (String)

    the line number where the error occurred

  • :description (String)

    the name of the failed example

  • :message (String)

    the explaination of why the example failed

  • :exception (String)

    the content of the exception

  • :backtrace (String)

    the backtrace of the exception (a single new-line separated string)

Returns:

  • (nil)


737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
# File 'plugins/rspec/rspec.rb', line 737

def display_failed_example data
  @progress_bar.value += 1
  top = model.insert("[FAILURE] #{data[:description]}", :error, nil).first
  model.insert ['From:', data[:location]], :message, nil, :parent => top
  ex_label = model.insert('Exception:', :message, nil, :parent => top).first
  exception_body = "#{data[:message]} (#{data[:exception]})".split_lines.delete_if{|l| l.strip.empty?}
  #exception_body may contain more than one line and some of them may be empty
  model.set exception_body.shift, :message, ex_label.row, :col => 1, :parent => top
  exception_body.each do |l|
    unless l.strip.empty?
      model.set l, :message, top.row_count, :col => 1, :parent => top
    end
  end
  backtrace = data[:backtrace].split_lines
  back_label, back = model.insert(['Backtrace:', backtrace.shift], :message, nil, :parent => top)
  backtrace.each do |l|
    model.insert [nil, l], :message, nil, :parent => back_label
  end
  top_index = filter.map_from_source(top.index)
  view.collapse top_index
  view.set_first_column_spanned top_index.row, Qt::ModelIndex.new, true
  view.expand filter.map_from_source(back_label.index)
  nil
end

- (nil) display_pending_example(data)

Displays information about a pending example in the tool widget

Parameters:

  • data (Hash)

Options Hash (data):

  • :location (String)

    the line number where the error occurred

  • :description (String)

    the name of the failed example

  • :message (String)

    the explaination of why the example failed

Returns:

  • (nil)


771
772
773
774
775
776
777
# File 'plugins/rspec/rspec.rb', line 771

def display_pending_example data
  @progress_bar.value += 1
  top = model.insert("[PENDING] #{data[:description]}", :warning, nil)[0]
  model.insert ['From:', data[:location]], :message, nil, :parent => top
  model.insert ['Message: ', "#{data[:message]} (#{data[:exception]})"], :message, nil, :parent => top
  nil
end

- (nil) display_successful_example(data)

Updates the progress bar by incrementing its value by one

Parameters:

  • data (Hash)

    the data to use. Currently it’s unused

Returns:

  • (nil)


720
721
722
723
# File 'plugins/rspec/rspec.rb', line 720

def display_successful_example data
  @progress_bar.value += 1
  nil
end

- (nil) display_summary(data)

Displays a summary of the spec run in the tool widget

The summary is a single title line which contains the number or successful, pending and failed example.

Parameters:

  • data (Hash)

Options Hash (data):

  • :total (Integer)

    the number of run examples

  • :passed (Integer)

    the number of passed examples

  • :failed (Integer)

    the number of failed examples

  • :pending (Integer)

    the number of pending examples

Returns:

  • (nil)


792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
# File 'plugins/rspec/rspec.rb', line 792

def display_summary data
  @progress_bar.hide
  if data[:passed] == data[:total]
    self.title = "[SUMMARY] All #{data[:total]} examples passed"
    set_output_type model.index(0,0), :message_good
  else
    text = "[SUMMARY]      Examples: #{data[:total]}"
    text << "      Failed: #{data[:failure]}" if data[:failure] > 0
    text << "      Pending: #{data[:pending]}" if data[:pending] > 0
    text << "      Passed: #{data[:passed]}"
    self.title = text
    type = data[:failure] > 0 ? :message_bad : :message
    set_output_type model.index(0,0), type
  end
  nil
end

- (Array<String,Integer>, ...) find_filename_in_index(idx) (private)

Override of OutputWidget#find_filename_in_index

It works as the base class method, but, if it doesn’t find a result in idx, it looks for it in the parent indexes

Parameters:

  • idx (Qt::ModelIndex)

    the index where to look for a file name

Returns:



921
922
923
924
925
926
927
928
929
# File 'plugins/rspec/rspec.rb', line 921

def find_filename_in_index idx
  res = super
  unless res
    idx = idx.parent while idx.parent.valid?
    idx = idx.child(0,1)
    res = super idx if idx.valid?
  end
  res
end

- (Object) load_settings



147
148
149
150
151
# File 'plugins/rspec/tool_widget.rb', line 147

def load_settings
  super
  compute_spanning_cols_size
  resize_columns
end

- (Object) resize_columns (private)



373
374
375
376
377
378
# File 'plugins/rspec/tool_widget.rb', line 373

def resize_columns
  view.resize_column_to_contents 0
  view.resize_column_to_contents 1
  min_width = @toplevel_width - view.column_width(0) + 30
  view.set_column_width 1, min_width if view.column_width(1) < min_width
end

Slot Signature:

resize_columns()

- (nil) set_example_count(data)

Sets the number of examples found by the spec program.

This is used to set the maximum value of the progress bar.

which contains the number of examples

Parameters:

  • data (Hash)

    the data to use. It must contain the :count entry,

Returns:

  • (nil)


708
709
710
711
# File 'plugins/rspec/rspec.rb', line 708

def set_example_count data
  @progress_bar.maximum = data[:count]
  nil
end

- (nil) setup_actions (private)

Creates the additional actions.

It adds a single action, which allows the user to chose whether messages from standard error should be displayed or not.

Returns:

  • (nil)


904
905
906
907
908
909
910
# File 'plugins/rspec/rspec.rb', line 904

def setup_actions
  action_list << nil << 'show_stderr'
  a = KDE::ToggleAction.new 'S&how Standard Error', self
  actions['show_stderr'] = a
  a.checked = false
  connect a, SIGNAL('toggled(bool)'), filter, SLOT('toggle_display_stderr(bool)')
end

- (nil) spec_finished(code, reason) (private)

Does the necessary cleanup for when spec finishes running

It hides the progress widget and restores the default cursor.

Parameters:

  • code (Integer)

    the exit code

  • reason (String)

    why the program exited

Returns:

  • (nil)


847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
# File 'plugins/rspec/rspec.rb', line 847

def spec_finished code, reason
  @progress_bar.hide
  @progress_bar.value = 0
  @progress_bar.maximum = 100
  self.set_focus
  unset_cursor
  unless reason == 'killed'
    non_stderr_types = %w[message message_good message_bad warning error]
    only_stderr = !model.item(0,0).text.match(/^\[SUMMARY\]/)
    if only_stderr
      1.upto(model.row_count - 1) do |i|
        if non_stderr_types.include? model.item(i,0).data(OutputWidget::OutputTypeRole).to_string
          only_stderr = false
          break
        end
      end
    end
    if only_stderr
      actions['show_stderr'].checked = true
      model.insert "spec wasn't able to run the examples", :message_bad, nil
    end
  end
  compute_spanning_cols_size
  auto_expand_items
  nil
end

Slot Signature:

spec_finished(int, QString)

- (nil) spec_started (private)

Resets the tool widget and sets the cursor to busy

Returns:

  • (nil)


828
829
830
831
832
833
834
835
836
# File 'plugins/rspec/rspec.rb', line 828

def spec_started
  @progress_bar.maximum = 0
  @progress_bar.value = 0
  @progress_bar.show
  @progress_bar.tool_tip = ''
  actions['show_stderr'].checked = false
  self.cursor = Qt::Cursor.new(Qt::BusyCursor)
  nil
end

Slot Signature:

spec_started()

- (QString) text_for_clipboard(idxs) (private)

Parameters:

  • idxs (<Qt::ModelIndex>)

    the selected indexes

Returns:

  • (QString)

    the text to copy to the clipboard



937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
# File 'plugins/rspec/rspec.rb', line 937

def text_for_clipboard idxs
  order = {}
  idxs.each do |i|
    val = []
    parent = i
    while parent.parent.valid?
      parent = parent.parent
      val.unshift parent.row
    end
    val << [i.row, i.column]
    order[val] = i
  end
  order = order.sort do |a, b|
    a, b = a[0], b[0]
    res = a[0..-2] <=>  b[0..-2]
    if res == 0 then a[-1] <=> b[-1]
    else res
    end
  end
  prev = order.shift[1]
  text = prev.data.valid? ? prev.data.to_string : ''
  order.each do |_, v|
    text << ( (prev.parent == v.parent and prev.row == v.row) ? "\t" : "\n") 
    text << (v.data.valid? ? v.data.to_string : '')
    prev = v
  end
  text
end

- (Object) title=(val)

Override of OutputWidget#title=

It’s needed to have the title element span all columns

Parameters:

  • val (String)

    the new title



816
817
818
819
820
# File 'plugins/rspec/rspec.rb', line 816

def title= val
  super
  model.item(0,0).tool_tip = val
  view.set_first_column_spanned 0, Qt::ModelIndex.new, true
end

- (Object) without_resizing_columns (private)



381
382
383
384
385
386
# File 'plugins/rspec/tool_widget.rb', line 381

def without_resizing_columns
  disconnect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
  begin yield
  ensure connect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
  end
end