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.
- 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
|