ruber 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +42 -1
- data/lib/ruber/application/application.rb +25 -5
- data/lib/ruber/application/plugin.yaml +2 -10
- data/lib/ruber/component_manager.rb +2 -2
- data/lib/ruber/document_project.rb +5 -3
- data/lib/ruber/editor/document.rb +5 -4
- data/lib/ruber/editor/ktexteditor_wrapper.rb +1 -1
- data/lib/ruber/exception_widgets.rb +1 -1
- data/lib/ruber/main_window/main_window.rb +4 -3
- data/lib/ruber/main_window/main_window_actions.rb +2 -2
- data/lib/ruber/main_window/main_window_internal.rb +1 -1
- data/lib/ruber/output_widget.rb +17 -5
- data/lib/ruber/project.rb +34 -3
- data/lib/ruber/project_dir_scanner.rb +171 -0
- data/lib/ruber/settings_container.rb +7 -7
- data/lib/ruber/settings_dialog.rb +24 -24
- data/lib/ruber/version.rb +1 -1
- data/lib/ruber/world/environment.rb +1 -0
- data/lib/ruber/world/plugin.yaml +7 -2
- data/lib/ruber/{application → world}/project_files_widget.rb +0 -0
- data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.rb +2 -2
- data/lib/ruber/{application → world}/ui/project_files_rule_chooser_widget.ui +0 -0
- data/lib/ruber/{application → world}/ui/project_files_widget.rb +2 -2
- data/lib/ruber/{application → world}/ui/project_files_widget.ui +0 -0
- data/plugins/auto_end/auto_end.rb +21 -18
- data/plugins/autosave/autosave.rb +1 -1
- data/plugins/find_in_files/find_in_files.rb +1 -1
- data/plugins/irb/irb.png +0 -0
- data/plugins/irb/irb.rb +142 -0
- data/plugins/irb/irb.svg +240 -0
- data/plugins/irb/irb_controller.rb +541 -0
- data/plugins/irb/irbrc.rb +21 -0
- data/plugins/irb/plugin.yaml +19 -0
- data/plugins/irb/ui/irb_config_widget.rb +151 -0
- data/plugins/irb/ui/irb_config_widget.ui +123 -0
- data/plugins/irb/ui/irb_tool_widget.rb +97 -0
- data/plugins/irb/ui/irb_tool_widget.ui +86 -0
- data/plugins/project_browser/project_browser.rb +1 -1
- data/plugins/rspec/plugin.yaml +6 -3
- data/plugins/rspec/rspec.rb +172 -473
- data/plugins/rspec/tool_widget.rb +462 -0
- data/plugins/rspec/ui/rspec_project_widget.rb +58 -38
- data/plugins/rspec/ui/rspec_project_widget.ui +68 -64
- data/plugins/ruberri/class_formatter.rb +126 -0
- data/plugins/ruberri/method_formatter.rb +90 -0
- data/plugins/ruberri/plugin.yaml +13 -0
- data/plugins/ruberri/ruberri.rb +226 -0
- data/plugins/ruberri/search.rb +111 -0
- data/plugins/ruberri/ui/tool_widget.rb +73 -0
- data/plugins/ruberri/ui/tool_widget.ui +49 -0
- data/plugins/ruby_runner/ruby_runner.rb +2 -2
- data/plugins/ruby_syntax_checker/plugin.yaml +11 -0
- data/plugins/ruby_syntax_checker/ruby_syntax_checker.rb +147 -0
- data/plugins/syntax_checker/plugin.yaml +10 -6
- data/plugins/syntax_checker/syntax_checker.rb +216 -520
- data/plugins/syntax_checker/ui/config_widget.rb +61 -0
- data/plugins/syntax_checker/ui/config_widget.ui +44 -0
- data/plugins/yaml_syntax_checker/plugin.yaml +11 -0
- data/plugins/yaml_syntax_checker/yaml_syntax_checker.rb +62 -0
- data/ruber.desktop +0 -0
- data/spec/auto_end_spec.rb +224 -186
- data/spec/document_project_spec.rb +9 -1
- data/spec/document_spec.rb +9 -0
- data/spec/environment_spec.rb +12 -0
- data/spec/output_widget_spec.rb +69 -2
- data/spec/project_dir_scanner_spec.rb +195 -0
- data/spec/project_spec.rb +43 -73
- data/spec/ruby_syntax_checker_spec.rb +361 -0
- data/spec/syntax_checker_spec.rb +1132 -0
- data/spec/yaml_syntax_checker_spec.rb +130 -0
- metadata +232 -225
- data/lib/ruber/application/project_files_list.rb +0 -320
- 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.
|
77
|
+
@project.file_in_project? it.local_path
|
78
78
|
end
|
79
79
|
|
80
80
|
=begin rdoc
|
data/plugins/rspec/plugin.yaml
CHANGED
@@ -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:
|
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}
|
data/plugins/rspec/rspec.rb
CHANGED
@@ -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
|
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
|
-
|
150
|
-
|
151
|
-
|
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
|
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
|
342
|
-
|
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
|
-
|
347
|
-
doc
|
348
|
-
|
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
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
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
|
-
|
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
|
-
|
456
|
-
|
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
|
-
|
531
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
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
|
-
|
726
|
-
|
727
|
-
|
728
|
-
@
|
729
|
-
|
730
|
-
@
|
731
|
-
|
732
|
-
|
733
|
-
@
|
734
|
-
|
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
|
-
|
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
|
-
|
763
|
-
|
764
|
-
|
765
|
-
@
|
766
|
-
|
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
|
-
|
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
|
-
|
839
|
-
|
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
|
-
|
877
|
-
|
878
|
-
|
879
|
-
@
|
880
|
-
=
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
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
|
-
|
913
|
-
|
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
|
990
|
-
|
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<
|
686
|
+
@return [Array<Hash>] an array containing the patterns
|
996
687
|
=end
|
997
|
-
def
|
998
|
-
@ui.
|
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
|