ruber 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/CHANGES +42 -1
  2. data/lib/ruber/application/application.rb +25 -5
  3. data/lib/ruber/application/plugin.yaml +2 -10
  4. data/lib/ruber/component_manager.rb +2 -2
  5. data/lib/ruber/document_project.rb +5 -3
  6. data/lib/ruber/editor/document.rb +5 -4
  7. data/lib/ruber/editor/ktexteditor_wrapper.rb +1 -1
  8. data/lib/ruber/exception_widgets.rb +1 -1
  9. data/lib/ruber/main_window/main_window.rb +4 -3
  10. data/lib/ruber/main_window/main_window_actions.rb +2 -2
  11. data/lib/ruber/main_window/main_window_internal.rb +1 -1
  12. data/lib/ruber/output_widget.rb +17 -5
  13. data/lib/ruber/project.rb +34 -3
  14. data/lib/ruber/project_dir_scanner.rb +171 -0
  15. data/lib/ruber/settings_container.rb +7 -7
  16. data/lib/ruber/settings_dialog.rb +24 -24
  17. data/lib/ruber/version.rb +1 -1
  18. data/lib/ruber/world/environment.rb +1 -0
  19. data/lib/ruber/world/plugin.yaml +7 -2
  20. data/lib/ruber/{application → world}/project_files_widget.rb +0 -0
  21. data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.rb +2 -2
  22. data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.ui +0 -0
  23. data/lib/ruber/{application → world}/ui/project_files_widget.rb +2 -2
  24. data/lib/ruber/{application → world}/ui/project_files_widget.ui +0 -0
  25. data/plugins/auto_end/auto_end.rb +21 -18
  26. data/plugins/autosave/autosave.rb +1 -1
  27. data/plugins/find_in_files/find_in_files.rb +1 -1
  28. data/plugins/irb/irb.png +0 -0
  29. data/plugins/irb/irb.rb +142 -0
  30. data/plugins/irb/irb.svg +240 -0
  31. data/plugins/irb/irb_controller.rb +541 -0
  32. data/plugins/irb/irbrc.rb +21 -0
  33. data/plugins/irb/plugin.yaml +19 -0
  34. data/plugins/irb/ui/irb_config_widget.rb +151 -0
  35. data/plugins/irb/ui/irb_config_widget.ui +123 -0
  36. data/plugins/irb/ui/irb_tool_widget.rb +97 -0
  37. data/plugins/irb/ui/irb_tool_widget.ui +86 -0
  38. data/plugins/project_browser/project_browser.rb +1 -1
  39. data/plugins/rspec/plugin.yaml +6 -3
  40. data/plugins/rspec/rspec.rb +172 -473
  41. data/plugins/rspec/tool_widget.rb +462 -0
  42. data/plugins/rspec/ui/rspec_project_widget.rb +58 -38
  43. data/plugins/rspec/ui/rspec_project_widget.ui +68 -64
  44. data/plugins/ruberri/class_formatter.rb +126 -0
  45. data/plugins/ruberri/method_formatter.rb +90 -0
  46. data/plugins/ruberri/plugin.yaml +13 -0
  47. data/plugins/ruberri/ruberri.rb +226 -0
  48. data/plugins/ruberri/search.rb +111 -0
  49. data/plugins/ruberri/ui/tool_widget.rb +73 -0
  50. data/plugins/ruberri/ui/tool_widget.ui +49 -0
  51. data/plugins/ruby_runner/ruby_runner.rb +2 -2
  52. data/plugins/ruby_syntax_checker/plugin.yaml +11 -0
  53. data/plugins/ruby_syntax_checker/ruby_syntax_checker.rb +147 -0
  54. data/plugins/syntax_checker/plugin.yaml +10 -6
  55. data/plugins/syntax_checker/syntax_checker.rb +216 -520
  56. data/plugins/syntax_checker/ui/config_widget.rb +61 -0
  57. data/plugins/syntax_checker/ui/config_widget.ui +44 -0
  58. data/plugins/yaml_syntax_checker/plugin.yaml +11 -0
  59. data/plugins/yaml_syntax_checker/yaml_syntax_checker.rb +62 -0
  60. data/ruber.desktop +0 -0
  61. data/spec/auto_end_spec.rb +224 -186
  62. data/spec/document_project_spec.rb +9 -1
  63. data/spec/document_spec.rb +9 -0
  64. data/spec/environment_spec.rb +12 -0
  65. data/spec/output_widget_spec.rb +69 -2
  66. data/spec/project_dir_scanner_spec.rb +195 -0
  67. data/spec/project_spec.rb +43 -73
  68. data/spec/ruby_syntax_checker_spec.rb +361 -0
  69. data/spec/syntax_checker_spec.rb +1132 -0
  70. data/spec/yaml_syntax_checker_spec.rb +130 -0
  71. metadata +232 -225
  72. data/lib/ruber/application/project_files_list.rb +0 -320
  73. data/spec/project_files_list_spec.rb +0 -411
@@ -74,7 +74,7 @@ otherwise
74
74
  return true if @project.nil? or !@do_filtering
75
75
  it = source_model.item_for_index source_model.index(row,0,parent)
76
76
  return true if it.dir?
77
- @project.project_files.file_in_project? it.local_path
77
+ @project.file_in_project? it.local_path
78
78
  end
79
79
 
80
80
  =begin rdoc
@@ -7,7 +7,7 @@ about:
7
7
  bug_address: http://github.com/stcrocco/ruber/issues
8
8
  icon: rspec.png
9
9
  class: Ruber::RSpec::Plugin
10
- require: rspec
10
+ require: [rspec, tool_widget]
11
11
  deps: [ruby_development, autosave]
12
12
  ui_file: rspecui.rc
13
13
  config_options:
@@ -20,16 +20,19 @@ project_widgets:
20
20
  - {caption: RSpec, class: 'Ruber::RSpec::ProjectWidget', pixmap: rspec.png}
21
21
  project_options:
22
22
  rspec:
23
+ code_directory: {default: "File.join('lib', self[:general, :project_name].downcase.sub(/\s+/, '_'))", relative_path: true}
23
24
  executable: {default: 'Ruber::RSpec::Plugin.find_default_executable'}
24
25
  options: {default: []}
25
26
  spec_directory: {relative_path: true, default: spec}
27
+ patterns: {default: [{:code: **/*.rb, :spec: %f_spec.rb}]}
26
28
  spec_files: {default: '*_spec.rb'}
27
- spec_pattern: {default: ['%f_spec.rb']}
28
29
  full_backtraces: {default: true}
30
+ extensions:
31
+ rspec: {class: Ruber::RSpec::ProjectExtension}
29
32
  tool_widgets: {class: 'Ruber::RSpec::ToolWidget', pixmap: rspec.png, caption: RSpec}
30
33
  actions:
31
34
  rspec-switch: {text: 'Switch to &Spec', shortcut: 'Shift+F12', slot: switch(), states: [active_project_exists, current_document]}
32
35
  rspec-run_all: {text: Run &Project Specs, shortcut: 'Alt+Shift+R, P', slot: run_all(), states: [active_project_exists, rspec_running]}
33
- rspec-run_current: {text: Run Specs for &Current File, shortcut: 'Alt+Shift+R, C', slot: run_current(), states: [active_project_exists, current_document, rspec_running]}
36
+ rspec-run_current: {text: Run Specs for &Current File, shortcut: 'Alt+Shift+R, C', slot: run_current_document(), states: [active_project_exists, current_document, rspec_running]}
34
37
  rspec-run_current_line: {text: Run Current Spec, shortcut: 'Alt+Shift+R, L', slot: run_current_line(), states: [active_project_exists, current_document, rspec_running]}
35
38
  rspec-stop: {text: S&top, shortcut: Esc, icon: process-stop, slot: stop_process(), state: rspec_running}
@@ -84,6 +84,8 @@ Symbolic values associated with the @rspec/switch_behaviour@ settings
84
84
  =end
85
85
  SWITCH_BEHAVIOUR = [:new_tab, :horizontal, :vertical]
86
86
 
87
+ signals :settings_changed
88
+
87
89
  =begin rdoc
88
90
  Finds the rspec program to use by default
89
91
 
@@ -133,7 +135,7 @@ the plugin
133
135
  end
134
136
 
135
137
  =begin rdoc
136
- Whether a file is a spec file or a code file for a given project
138
+ Whether or not a file is a spec file for a given project
137
139
 
138
140
  It uses the @rspec/spec_directory@ and @rspec/spec_pattern@ options from the project
139
141
  to find out whether the file is a spec file or not.
@@ -146,9 +148,24 @@ to find out whether the file is a spec file or not.
146
148
  =end
147
149
  def spec_file? file, prj = Ruber[:world].active_project
148
150
  return nil unless prj
149
- dir = prj[:rspec, :spec_directory, :absolute]
150
- return false unless file.start_with? dir
151
- File.fnmatch File.join(dir, prj[:rspec, :spec_files]), file
151
+ prj.extension(:rspec).spec_file? file
152
+ end
153
+
154
+ =begin rdoc
155
+ Whether or not file is a code file for a given project
156
+
157
+ It uses the @rspec/spec_directory@ and @rspec/spec_pattern@ options from the project
158
+ to find out whether the file is a spec file or not.
159
+
160
+ @param [String] file the file to test
161
+ @param [Project,nil] prj the project _file_ could be a spec for. If *nil*, the
162
+ current project, if any, will be used
163
+ @return [Boolean,nil] wheter or not _file_ is a spec file for the given project
164
+ or *nil* if no project was specified and there's no open project
165
+ =end
166
+ def code_file? file, prj = Ruber[:world].active_project
167
+ return nil unless prj
168
+ prj.extension(:rspec).code_file? file
152
169
  end
153
170
 
154
171
  =begin rdoc
@@ -220,6 +237,22 @@ as first argument to {Autosave::AutosavePlugin#autosave}
220
237
  true
221
238
  end
222
239
 
240
+ def load_settings
241
+ super
242
+ emit settings_changed
243
+ end
244
+
245
+ def spec_for_pattern pattern, file
246
+ spec = pattern[:spec].gsub(/%f/, File.basename(file, '.rb'))
247
+ dir = File.dirname(file)
248
+ dir_parts = dir.split '/'
249
+ spec.gsub! %r{%d\d+} do |str|
250
+ dir_parts[str[2..-1].to_i-1] || ''
251
+ end
252
+ spec.gsub! %r{%d}, dir
253
+ spec
254
+ end
255
+
223
256
  private
224
257
 
225
258
  =begin rdoc
@@ -312,7 +345,7 @@ Runs all the specs for the project.
312
345
  return
313
346
  end
314
347
  opts = options prj
315
- opts[:files] = Dir.glob File.join(opts[:specs_dir], opts[:filter])
348
+ opts[:files] = Dir.glob File.join(opts[:specs_dir], '**', opts[:filter])
316
349
  run_rspec_for prj, opts, :files => :project_files, :on_failure => :ask, :message => 'Do you want to run the tests all the same?'
317
350
  nil
318
351
  end
@@ -335,34 +368,30 @@ which, most likely, will cause it to fail.
335
368
 
336
369
  @return [Boolean] *true* if the spec program is started and *false* otherwise
337
370
  (including the case when the process was already running or autosaving failed)
338
- =end
339
- def run_current what = :all
371
+ =end
372
+ def run_current_document
373
+ doc = Ruber[:world].active_document
374
+ unless doc
375
+ raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active document"
376
+ end
340
377
  prj = Ruber[:world].active_project
341
- unless prj
342
- KDE::MessageBox.error nil, "You must have an open project to choose this entry.\nYOU SHOULD NEVER SEE THIS MESSAGE"
343
- return
378
+ unless doc
379
+ raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active project"
344
380
  end
345
381
  opts = options prj
346
- view = Ruber[:main_window].active_editor
347
- doc = view.document
348
- unless doc.url.local_file?
349
- KDE::MessageBox.sorry nil, 'You can\'t run rspec for remote files'
350
- return
351
- end
352
- unless doc
353
- KDE::MessageBox.error nil, "You must have an open editor to choose this entry.\nYOU SHOULD NEVER SEE THIS MESSAGE"
382
+ ext = prj.extension(:rspec)
383
+ if doc.path.empty?
384
+ KDE::MessageBox.sorry nil, KDE.i18n("You must save the document to a file before running rspec on it")
354
385
  return
355
- end
356
- files = specs_for_file opts, doc.path
357
- files.reject!{|f| !File.exist? f}
358
- opts[:files] = files.empty? ? [doc.path] : files
359
- if what == :current_line
360
- line = view.cursor_position.line + 1
361
- opts[:spec_options] += ["-l", line.to_s]
386
+ elsif ext.spec_file? doc.path
387
+ opts[:files] = [doc.path]
388
+ elsif ext.code_file?(doc.path)
389
+ opts[:files] = ext.specs_for_code doc.path
362
390
  end
363
391
  run_rspec_for prj, opts, :files => :documents_with_file, :on_failure => :ask,
364
392
  :message => 'Do you want to run the tests all the same?'
365
393
  end
394
+ slots :run_current_document
366
395
 
367
396
  =begin rdoc
368
397
  Runs the example(s) in the current line
@@ -376,7 +405,37 @@ current file is the example file, not the source.
376
405
  (including the case when the process was already running or autosaving failed)
377
406
  =end
378
407
  def run_current_line
379
- run_current :current_line
408
+ doc = Ruber[:world].active_document
409
+ unless doc
410
+ raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active document"
411
+ end
412
+ prj = Ruber[:world].active_project
413
+ unless doc
414
+ raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active project"
415
+ end
416
+ opts = options prj
417
+ ext = prj.extension(:rspec)
418
+ if doc.path.empty?
419
+ KDE::MessageBox.sorry nil, KDE.i18n("You must save the document to a file before running rspec on it")
420
+ return
421
+ elsif ext.spec_file? doc.path
422
+ view = Ruber[:main_window].active_editor
423
+ elsif ext.code_file?(doc.path)
424
+ specs = ext.specs_for_code doc.path
425
+ view = Ruber[:world].active_environment.views.find do |v|
426
+ specs.include? v.document.path
427
+ end
428
+ unless view
429
+ KDE::MessageBox.sorry nil, KDE.i18n('You don\'t have any spec file for %s opened. Without it it\'s impossible to find out what the current line is', doc.path)
430
+ return
431
+ end
432
+ doc = view.document
433
+ end
434
+ opts[:files] = [view.document.path]
435
+ line = view.cursor_position.line + 1
436
+ opts[:spec_options] += ["-l", line.to_s]
437
+ run_rspec_for prj, opts, :files => :documents_with_file, :on_failure => :ask,
438
+ :message => 'Do you want to run the tests all the same?'
380
439
  end
381
440
 
382
441
  =begin rdoc
@@ -431,7 +490,6 @@ the project directory.
431
490
  res[:spec_options] = prj[:rspec, :options]
432
491
  res[:specs_dir] = prj[:rspec, :spec_directory, :absolute]
433
492
  res[:filter] = prj[:rspec, :spec_files]
434
- res[:pattern] = prj[:rspec, :spec_pattern]
435
493
  res[:dir] = prj.project_directory
436
494
  res[:full_backtraces] = prj[:rspec, :full_backtraces]
437
495
  res
@@ -452,8 +510,9 @@ It does nothing if the file corresponding to the current document isn't found
452
510
  def switch
453
511
  file = Ruber[:main_window].current_document.path
454
512
  prj = Ruber[:world].active_project
455
- if spec_file? file, prj then switch_to = file_for_spec prj, file
456
- else switch_to = specs_for_file(options(prj), file)[0]
513
+ ext = prj.extension(:rspec)
514
+ if ext.spec_file? file then ;switch_to = ext.code_for_spec file
515
+ else switch_to = ext.specs_for_code(file)[0]
457
516
  end
458
517
  if switch_to and File.exist? switch_to
459
518
  behaviour = Ruber[:config][:rspec, :switch_behaviour]
@@ -466,41 +525,6 @@ It does nothing if the file corresponding to the current document isn't found
466
525
  end
467
526
  slots :switch
468
527
 
469
- =begin rdoc
470
- Determines all possible specs files associated with a code file
471
-
472
- The names of the possible spec files are obtained replacing the @%f@ tag in each
473
- entry of the @rspec/pattern@ setting with the name of the file (without checking
474
- whether the files actually exist).
475
-
476
- @param [String] file the name of the code file
477
- @return [<String>] the names of the possible spec file associated with _file_
478
- =end
479
- def specs_for_file opts, file
480
- file = File.basename file, '.rb'
481
- res = opts[:pattern].map{|i| File.join opts[:specs_dir], i.gsub('%f', file)}
482
- res
483
- end
484
-
485
- =begin rdoc
486
- The name of the code file associated with a given spec file
487
-
488
- To find out which code file is associated with the given spec file, this method
489
- takes all the project files and constructs the file names of all the specs associated
490
- to them according to the @rspec/spec_pattern@ project option. As soon as one of
491
- the generated file names matches the given spec file, the generating file is returned.
492
-
493
- @param [Ruber::AbstractProject] prj the project containing the settings to use
494
- @param [String] file the name of the spec file to find the code file for
495
- @return [String] the absolute path of a file _file_ is a spec of, according
496
- to the settings contained in _prj_.
497
- =end
498
- def file_for_spec prj, file
499
- pattern = prj[:spec_pattern]
500
- opts = options prj
501
- prj.project_files.abs.find{|f| specs_for_file( opts, f).include? file}
502
- end
503
-
504
528
  =begin rdoc
505
529
  Override of {ExternalProgramPlugin#display_exit_message}
506
530
 
@@ -527,8 +551,9 @@ signal.
527
551
  @return [nil]
528
552
  =end
529
553
  def change_switch_name doc
530
- return unless doc
531
- if spec_file? doc.path then text = 'Switch to &Code'
554
+ prj = Ruber[:world].active_project
555
+ return unless doc and prj
556
+ if prj.extension(:rspec).spec_file? doc.path then text = 'Switch to &Code'
532
557
  else text = 'Switch to &Spec'
533
558
  end
534
559
  action_collection.action('rspec-switch').text = i18n(text)
@@ -538,431 +563,73 @@ signal.
538
563
 
539
564
  end
540
565
 
541
- =begin rdoc
542
- Filter model used by the RSpec output widget
543
-
544
- It allows to choose whether to accept items corresponding to output to standard error or to reject
545
- it. To find out if a given item corresponds to the output of standard error or
546
- standard output, this model uses the data contained in a custom role in the output.
547
- The index of this role is {RSpec::OutputWidget::OutputTypeRole}.
548
- =end
549
- class FilterModel < FilteredOutputWidget::FilterModel
550
-
551
- slots 'toggle_display_stderr(bool)'
552
-
553
- =begin rdoc
554
- Whether output from standard error should be displayed or not
555
- @return [Boolean]
556
- =end
557
- attr_reader :display_stderr
558
-
559
- =begin rdoc
560
- Create a new instance
561
-
562
- The new instance is set not to show the output from standard error
563
-
564
- @param [Qt::Object, nil] parent the parent object
565
- =end
566
- def initialize parent = nil
567
- super
568
- @display_stderr = false
569
- end
570
-
571
- =begin rdoc
572
- Sets whether to display or ignore items corresponding to output to standard error
573
-
574
- If this choice has changed, the model is invalidated.
575
-
576
- @param [Boolean] val whether to display or ignore the output to standard error
577
- @return [Boolean] _val_
578
- =end
579
- def display_stderr= val
580
- old, @display_stderr = @display_stderr, val
581
- invalidate if old != @display_stderr
582
- @display_standard_error
583
- end
584
- alias_method :toggle_display_stderr, :display_stderr=
585
-
586
- =begin rdoc
587
- Override of {FilteredOutputWidget::FilterModel#filterAcceptsRow}
588
-
589
- According to the value of {#display_stderr}, it can filter out items corresponding
590
- to standard error. In all other respects, it behaves as the base class method.
591
- @param [Integer] r the row number
592
- @param [Qt::ModelIndex] parent the parent index
593
- @return [Boolean] *true* if the row should be displayed and *false* otherwise
594
- =end
595
- def filterAcceptsRow r, parent
596
- if !@display_stderr
597
- idx = source_model.index(r,0,parent)
598
- return false if idx.data(OutputWidget::OutputTypeRole).to_string == 'output1'
599
- end
600
- super
601
- end
602
-
603
- end
604
566
 
605
- =begin rdoc
606
- Tool widget used by the rspec plugin.
607
-
608
- It displays the output from the spec program in a multi column tree. The name of
609
- failing or pending examples are displayed in a full line; all other information,
610
- such as the location of the example, the error message and so on are displayed
611
- in child items.
612
-
613
- While the examples are being run, a progress bar is shown.
614
- =end
615
- class ToolWidget < FilteredOutputWidget
616
-
617
- slots :spec_started, 'spec_finished(int, QString)'
618
-
619
- =begin rdoc
620
- @param [Qt::Widget, nil] parent the parent widget
621
- =end
622
- def initialize parent = nil
623
- super parent, :view => :tree, :filter => FilterModel.new
624
- @ignore_word_wrap_option = true
625
- view.text_elide_mode = Qt::ElideNone
626
- model.append_column [] if model.column_count < 2
627
- @progress_bar = Qt::ProgressBar.new(self){|w| w.hide}
628
- layout.add_widget @progress_bar, 2,0
629
- view.header_hidden = true
630
- view.header.resize_mode = Qt::HeaderView::ResizeToContents
631
- connect Ruber[:rspec], SIGNAL(:process_started), self, SLOT(:spec_started)
632
- connect Ruber[:rspec], SIGNAL('process_finished(int, QString)'), self, SLOT('spec_finished(int, QString)')
633
- filter.connect(SIGNAL('rowsInserted(QModelIndex, int, int)')) do |par, st, en|
634
- if !par.valid?
635
- st.upto(en) do |i|
636
- view.set_first_column_spanned i, par, true
637
- end
638
- end
639
- end
640
- #without this, the horizontal scrollbars won't be shown
641
- view.connect(SIGNAL('expanded(QModelIndex)')) do |_|
642
- view.resize_column_to_contents 1
643
- end
644
- view.connect(SIGNAL('collapsed(QModelIndex)')) do |_|
645
- view.resize_column_to_contents 1
646
- end
647
- setup_actions
648
- end
649
-
650
- =begin rdoc
651
- Displays the data relative to an example in the widget
652
-
653
- Actually, this method simply passes its argument to a more specific method, depending
654
- on the data it contains.
655
-
656
- @param [Hash] data a hash containing the data describing the results of running
657
- the example. This hash must contain the @:type@ key, which tells which kind of
658
- event the hash describes. The other entries change depending on the method which
659
- will be called, which is determined according to the @:type@ entry:
660
- * @:success@: {#display_successful_example}
661
- * @:failure@: {#display_failed_example}
662
- * @:pending@: {#display_pending_example}
663
- * @:new_example@: {#change_current_example}
664
- * @:start@: {#set_example_count}
665
- * @:summary@: {#display_summary}
666
- If the @:type@ entry doesn't have one of the previous values, the hash will be
667
- converted to a string and displayed in the widget
668
- =end
669
- def display_example data
670
- unless data.is_a?(Hash)
671
- model.insert_lines data.to_s, :output, nil
672
- return
673
- end
674
- case data[:type]
675
- when :success then display_successful_example data
676
- when :failure then display_failed_example data
677
- when :pending then display_pending_example data
678
- when :new_example then change_current_example data
679
- when :start then set_example_count data
680
- when :summary then display_summary data
681
- else model.insert_lines data.to_s, :output, nil
682
- end
683
- end
567
+ class ProjectExtension < Qt::Object
684
568
 
685
- =begin rdoc
686
- Changes the current example
687
-
688
- Currently, this only affects the tool tip displayed by the progress bar.
689
-
690
- @param [Hash] data the data to use. It must contain the @:description@ entry,
691
- which contains the text of the tool tip to use.
692
- @return [nil]
693
- =end
694
- def change_current_example data
695
- @progress_bar.tool_tip = data[:description]
696
- nil
697
- end
569
+ include Ruber::Extension
698
570
 
699
- =begin rdoc
700
- Sets the number of examples found by the spec program.
701
-
702
- This is used to set the maximum value of the progress bar.
703
-
704
- @param [Hash] data the data to use. It must contain the @:count@ entry,
705
- which contains the number of examples
706
- @return [nil]
707
- =end
708
- def set_example_count data
709
- @progress_bar.maximum = data[:count]
710
- nil
711
- end
712
-
713
-
714
- =begin rdoc
715
- Updates the progress bar by incrementing its value by one
716
-
717
- @param [Hash] data the data to use. Currently it's unused
718
- @return [nil]
719
- =end
720
- def display_successful_example data
721
- @progress_bar.value += 1
722
- nil
571
+ def initialize prj
572
+ super
573
+ @project = prj
574
+ @categories = {}
575
+ connect Ruber[:rspec], SIGNAL(:settings_changed), self, SLOT(:clear)
723
576
  end
724
577
 
725
- =begin rdoc
726
- Displays information about a failed example in the tool widget.
727
-
728
- @param [Hash] data the data about the example.
729
-
730
- @option data [String] :location the line number where the error occurred
731
- @option data [String] :description the name of the failed example
732
- @option data [String] :message the explaination of why the example failed
733
- @option data [String] :exception the content of the exception
734
- @option data [String] :backtrace the backtrace of the exception (a single new-line separated string)
735
- @return [nil]
736
- =end
737
- def display_failed_example data
738
- @progress_bar.value += 1
739
- top = model.insert("[FAILURE] #{data[:description]}", :error, nil).first
740
- model.insert ['From:', data[:location]], :message, nil, :parent => top
741
- ex_label = model.insert('Exception:', :message, nil, :parent => top).first
742
- exception_body = "#{data[:message]} (#{data[:exception]})".split_lines.delete_if{|l| l.strip.empty?}
743
- #exception_body may contain more than one line and some of them may be empty
744
- model.set exception_body.shift, :message, ex_label.row, :col => 1, :parent => top
745
- exception_body.each do |l|
746
- unless l.strip.empty?
747
- model.set l, :message, top.row_count, :col => 1, :parent => top
578
+ def specs_for_code file
579
+ return [] unless @project.file_in_project? file
580
+ return [] unless code_file? file
581
+ file.sub(@project.project_directory + '/', '')
582
+ res = []
583
+ @project[:rspec, :patterns].each do |pn|
584
+ if File.fnmatch pn[:code], file
585
+ basename = Ruber[:rspec].spec_for_pattern pn, file
586
+ spec = File.join(@project.project_directory, @project[:rspec, :spec_directory], basename)
587
+ res << spec
748
588
  end
749
589
  end
750
- backtrace = data[:backtrace].split_lines
751
- back_label, back = model.insert(['Backtrace:', backtrace.shift], :message, nil, :parent => top)
752
- backtrace.each do |l|
753
- model.insert [nil, l], :message, nil, :parent => back_label
754
- end
755
- top_index = filter.map_from_source(top.index)
756
- view.collapse top_index
757
- view.set_first_column_spanned top_index.row, Qt::ModelIndex.new, true
758
- view.expand filter.map_from_source(back_label.index)
759
- nil
590
+ res.select{|f| File.exist? f}
760
591
  end
761
592
 
762
- =begin rdoc
763
- Displays information about a pending example in the tool widget
764
-
765
- @param [Hash] data
766
- @option data [String] :location the line number where the error occurred
767
- @option data [String] :description the name of the failed example
768
- @option data [String] :message the explaination of why the example failed
769
- @return [nil]
770
- =end
771
- def display_pending_example data
772
- @progress_bar.value += 1
773
- top = model.insert("[PENDING] #{data[:description]}", :warning, nil)[0]
774
- model.insert ['From:', data[:location]], :message, nil, :parent => top
775
- model.insert ['Message: ', "#{data[:message]} (#{data[:exception]})"], :message, nil, :parent => top
776
- nil
777
- end
778
-
779
- =begin rdoc
780
- Displays a summary of the spec run in the tool widget
781
-
782
- The summary is a single title line which contains the number or successful, pending
783
- and failed example.
784
-
785
- @param [Hash] data
786
- @option data [Integer] :total the number of run examples
787
- @option data [Integer] :passed the number of passed examples
788
- @option data [Integer] :failed the number of failed examples
789
- @option data [Integer] :pending the number of pending examples
790
- @return [nil]
791
- =end
792
- def display_summary data
793
- @progress_bar.hide
794
- if data[:passed] == data[:total]
795
- self.title = "[SUMMARY] All #{data[:total]} examples passed"
796
- set_output_type model.index(0,0), :message_good
797
- else
798
- text = "[SUMMARY] Examples: #{data[:total]}"
799
- text << " Failed: #{data[:failure]}" if data[:failure] > 0
800
- text << " Pending: #{data[:pending]}" if data[:pending] > 0
801
- text << " Passed: #{data[:passed]}"
802
- self.title = text
803
- type = data[:failure] > 0 ? :message_bad : :message
804
- set_output_type model.index(0,0), type
593
+ def code_for_spec file
594
+ return nil unless @project.file_in_project? file
595
+ return nil unless spec_file? file
596
+ @project.project_files.find do |f|
597
+ specs_for_code(f).include? file
805
598
  end
806
- nil
807
- end
808
-
809
- =begin rdoc
810
- Override of {OutputWidget#title=}
811
-
812
- It's needed to have the title element span all columns
813
-
814
- @param [String] val the new title
815
- =end
816
- def title= val
817
- super
818
- model.item(0,0).tool_tip = val
819
- view.set_first_column_spanned 0, Qt::ModelIndex.new, true
820
599
  end
821
600
 
822
- private
823
-
824
- =begin rdoc
825
- Resets the tool widget and sets the cursor to busy
826
- @return [nil]
827
- =end
828
- def spec_started
829
- @progress_bar.maximum = 0
830
- @progress_bar.value = 0
831
- @progress_bar.show
832
- @progress_bar.tool_tip = ''
833
- actions['show_stderr'].checked = false
834
- self.cursor = Qt::Cursor.new(Qt::BusyCursor)
835
- nil
601
+ def code_file? file
602
+ category(file) == :code
836
603
  end
837
604
 
838
- =begin rdoc
839
- Does the necessary cleanup for when spec finishes running
840
-
841
- It hides the progress widget and restores the default cursor.
842
-
843
- @param [Integer] code the exit code
844
- @param [String] reason why the program exited
845
- @return [nil]
846
- =end
847
- def spec_finished code, reason
848
- @progress_bar.hide
849
- @progress_bar.value = 0
850
- @progress_bar.maximum = 100
851
- self.set_focus
852
- unset_cursor
853
- unless reason == 'killed'
854
- non_stderr_types = %w[message message_good message_bad warning error]
855
- only_stderr = !model.item(0,0).text.match(/^\[SUMMARY\]/)
856
- if only_stderr
857
- 1.upto(model.row_count - 1) do |i|
858
- if non_stderr_types.include? model.item(i,0).data(OutputWidget::OutputTypeRole).to_string
859
- only_stderr = false
860
- break
861
- end
862
- end
863
- end
864
- if only_stderr
865
- actions['show_stderr'].checked = true
866
- model.insert "spec wasn't able to run the examples", :message_bad, nil
867
- end
868
- end
869
- auto_expand_items
870
- nil
605
+ def spec_file? file
606
+ category(file) == :spec
871
607
  end
872
-
873
- =begin rdoc
874
- Expands items according to the @rspec/auto_expand@ option
875
608
 
876
- If the option is @:expand_first@, the first failed example is expanded; if the
877
- option is @:expand_all@, all failed or pending examples are expanded. If the option
878
- is @:expand_none@, nothing is done
879
- @return [nil]
880
- =end
881
- def auto_expand_items
882
- if model.row_count > 1
883
- case Ruber[:config][:rspec, :auto_expand]
884
- when :expand_first
885
- item = model.each_row.find{|items| items[0].has_children}
886
- view.expand filter_model.map_from_source(item[0].index) if item
887
- when :expand_all
888
- model.each_row do |items|
889
- view.expand filter_model.map_from_source(items[0].index)
609
+ def category file
610
+ cat = @categories[file]
611
+ return cat if cat
612
+ spec_dir = @project[:rspec, :spec_directory, :abs]
613
+ code_dir = @project[:rspec, :code_directory, :abs]
614
+ if @project.file_in_project? file
615
+ if file.start_with? spec_dir
616
+ if File.fnmatch @project[:rspec, :spec_files], file.sub(spec_dir + '/', '')
617
+ @categories[file] = :spec
618
+ else @categories[file] = :unknown
890
619
  end
620
+ elsif file.start_with?(code_dir) and @project.file_in_project?(file)
621
+ @categories[file] = :code
622
+ else @categories[file] = :unknown
891
623
  end
624
+ else @categories[file] = :unknown
892
625
  end
893
- nil
894
- end
895
-
896
- =begin rdoc
897
- Creates the additional actions.
898
-
899
- It adds a single action, which allows the user to chose whether messages from
900
- standard error should be displayed or not.
901
-
902
- @return [nil]
903
- =end
904
- def setup_actions
905
- action_list << nil << 'show_stderr'
906
- a = KDE::ToggleAction.new 'S&how Standard Error', self
907
- actions['show_stderr'] = a
908
- a.checked = false
909
- connect a, SIGNAL('toggled(bool)'), filter, SLOT('toggle_display_stderr(bool)')
910
626
  end
911
627
 
912
- =begin rdoc
913
- Override of {OutputWidget#find_filename_in_index}
914
-
915
- It works as the base class method, but, if it doesn't find a result in _idx_,
916
- it looks for it in the parent indexes
917
-
918
- @param [Qt::ModelIndex] idx the index where to look for a file name
919
- @return [Array<String,Integer>,String,nil] see {OutputWidget#find_filename_in_index}
920
- =end
921
- def find_filename_in_index idx
922
- res = super
923
- unless res
924
- idx = idx.parent while idx.parent.valid?
925
- idx = idx.child(0,1)
926
- res = super idx if idx.valid?
927
- end
928
- res
628
+ def clear
629
+ @categories.clear
929
630
  end
631
+ slots :clear
930
632
 
931
- =begin rdoc
932
- Override of {OutputWidget#text_for_clipboard}
933
-
934
- @param [<Qt::ModelIndex>] idxs the selected indexes
935
- @return [QString] the text to copy to the clipboard
936
- =end
937
- def text_for_clipboard idxs
938
- order = {}
939
- idxs.each do |i|
940
- val = []
941
- parent = i
942
- while parent.parent.valid?
943
- parent = parent.parent
944
- val.unshift parent.row
945
- end
946
- val << [i.row, i.column]
947
- order[val] = i
948
- end
949
- order = order.sort do |a, b|
950
- a, b = a[0], b[0]
951
- res = a[0..-2] <=> b[0..-2]
952
- if res == 0 then a[-1] <=> b[-1]
953
- else res
954
- end
955
- end
956
- prev = order.shift[1]
957
- text = prev.data.valid? ? prev.data.to_string : ''
958
- order.each do |_, v|
959
- text << ( (prev.parent == v.parent and prev.row == v.row) ? "\t" : "\n")
960
- text << (v.data.valid? ? v.data.to_string : '')
961
- prev = v
962
- end
963
- text
964
- end
965
-
966
633
  end
967
634
 
968
635
  =begin rdoc
@@ -977,8 +644,26 @@ Project widget for the RSpec frontend plugin
977
644
  super
978
645
  @ui = Ui::RSpecProjectWidget.new
979
646
  @ui.setupUi self
647
+ view = @ui._rspec__patterns
648
+ mod = Qt::StandardItemModel.new
649
+ view.model = mod
650
+ mod.horizontal_header_labels = ['Code file', 'Spec file']
651
+ @ui.add_pattern.connect(SIGNAL(:clicked)) do
652
+ row = [Qt::StandardItem.new, Qt::StandardItem.new]
653
+ mod.append_row row
654
+ view.current_index = row[0].index
655
+ view.edit row[0].index
656
+ end
657
+ @ui.remove_pattern.connect(SIGNAL(:clicked)) do
658
+ sel = view.selection_model.selected_indexes
659
+ mod.remove_row sel[0].row
660
+ end
661
+ view.selection_model.connect(SIGNAL('selectionChanged(QItemSelection,QItemSelection)')) do
662
+ @ui.remove_pattern.enabled = view.selection_model.has_selection
663
+ end
980
664
  end
981
665
 
666
+
982
667
  private
983
668
 
984
669
  =begin rdoc
@@ -986,16 +671,30 @@ Sets the text of the pattern widget
986
671
  @param [Array<String>] the pattern to use. They'll be joined with commas to create
987
672
  the text to put in the widget
988
673
  =end
989
- def pattern= value
990
- value.join ', '
674
+ def patterns= value
675
+ view = @ui._rspec__patterns
676
+ value.each do |h|
677
+ row = [Qt::StandardItem.new(h[:code]),
678
+ Qt::StandardItem.new(h[:spec])]
679
+ view.model.append_row row
680
+ end
681
+ 2.times{|i| view.resize_column_to_contents i}
991
682
  end
992
683
 
993
684
  =begin rdoc
994
685
  Parses the content of the pattern widget
995
- @return [Array<String>] an array containing the patterns
686
+ @return [Array<Hash>] an array containing the patterns
996
687
  =end
997
- def pattern
998
- @ui._rspec__spec_pattern.text.split(/;\s*/)
688
+ def patterns
689
+ mod = @ui._rspec__patterns.model
690
+ mod.each_row.map do |cols|
691
+ code = cols[0].text
692
+ {:code => code, :spec => cols[1].text, :glob => text_glob?(code)}
693
+ end
694
+ end
695
+
696
+ def text_glob? text
697
+ text=~ /[*?{}\[\]]/
999
698
  end
1000
699
 
1001
700
  =begin rdoc