Class: Ruber::RSpec::ToolWidget

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

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

[View source]

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)
[View source]

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)
[View source]

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)

[View source]

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

[View source]

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)
[View source]

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)
[View source]

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)
[View source]

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)
[View source]

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:

[View source]

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

[View source]

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)

[View source]

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)
[View source]

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)
[View source]

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)
[View source]

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)
[View source]

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

[View source]

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

[View source]

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)

[View source]

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