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
@@ -0,0 +1,462 @@
1
+ module Ruber
2
+
3
+ module RSpec
4
+
5
+ =begin rdoc
6
+ Filter model used by the RSpec output widget
7
+
8
+ It allows to choose whether to accept items corresponding to output to standard error or to reject
9
+ it. To find out if a given item corresponds to the output of standard error or
10
+ standard output, this model uses the data contained in a custom role in the output.
11
+ The index of this role is {RSpec::OutputWidget::OutputTypeRole}.
12
+ =end
13
+ class FilterModel < FilteredOutputWidget::FilterModel
14
+
15
+ slots 'toggle_display_stderr(bool)'
16
+
17
+ =begin rdoc
18
+ Whether output from standard error should be displayed or not
19
+ @return [Boolean]
20
+ =end
21
+ attr_reader :display_stderr
22
+
23
+ =begin rdoc
24
+ Create a new instance
25
+
26
+ The new instance is set not to show the output from standard error
27
+
28
+ @param [Qt::Object, nil] parent the parent object
29
+ =end
30
+ def initialize parent = nil
31
+ super
32
+ @display_stderr = false
33
+ end
34
+
35
+ =begin rdoc
36
+ Sets whether to display or ignore items corresponding to output to standard error
37
+
38
+ If this choice has changed, the model is invalidated.
39
+
40
+ @param [Boolean] val whether to display or ignore the output to standard error
41
+ @return [Boolean] _val_
42
+ =end
43
+ def display_stderr= val
44
+ old, @display_stderr = @display_stderr, val
45
+ invalidate if old != @display_stderr
46
+ @display_standard_error
47
+ end
48
+ alias_method :toggle_display_stderr, :display_stderr=
49
+
50
+ =begin rdoc
51
+ Override of {FilteredOutputWidget::FilterModel#filterAcceptsRow}
52
+
53
+ According to the value of {#display_stderr}, it can filter out items corresponding
54
+ to standard error. In all other respects, it behaves as the base class method.
55
+ @param [Integer] r the row number
56
+ @param [Qt::ModelIndex] parent the parent index
57
+ @return [Boolean] *true* if the row should be displayed and *false* otherwise
58
+ =end
59
+ def filterAcceptsRow r, parent
60
+ if !@display_stderr
61
+ idx = source_model.index(r,0,parent)
62
+ return false if idx.data(OutputWidget::OutputTypeRole).to_string == 'output1'
63
+ end
64
+ super
65
+ end
66
+
67
+ end
68
+
69
+ =begin rdoc
70
+ Tool widget used by the rspec plugin.
71
+
72
+ It displays the output from the spec program in a multi column tree. The name of
73
+ failing or pending examples are displayed in a full line; all other information,
74
+ such as the location of the example, the error message and so on are displayed
75
+ in child items.
76
+
77
+ While the examples are being run, a progress bar is shown.
78
+ =end
79
+ class ToolWidget < FilteredOutputWidget
80
+
81
+ slots :spec_started, 'spec_finished(int, QString)'
82
+
83
+ =begin rdoc
84
+ @param [Qt::Widget, nil] parent the parent widget
85
+ =end
86
+ def initialize parent = nil
87
+ super parent, :view => :tree, :filter => FilterModel.new
88
+ @toplevel_width = 0
89
+ @ignore_word_wrap_option = true
90
+ view.text_elide_mode = Qt::ElideNone
91
+ model.append_column [] if model.column_count < 2
92
+ @progress_bar = Qt::ProgressBar.new(self){|w| w.hide}
93
+ layout.add_widget @progress_bar, 2,0
94
+ view.header_hidden = true
95
+ view.header.resize_mode = Qt::HeaderView::ResizeToContents
96
+ connect Ruber[:rspec], SIGNAL(:process_started), self, SLOT(:spec_started)
97
+ connect Ruber[:rspec], SIGNAL('process_finished(int, QString)'), self, SLOT('spec_finished(int, QString)')
98
+ view.word_wrap = true
99
+ filter.connect(SIGNAL('rowsInserted(QModelIndex, int, int)')) do |par, st, en|
100
+ if !par.valid?
101
+ st.upto(en) do |i|
102
+ view.set_first_column_spanned i, par, true
103
+ end
104
+ end
105
+ end
106
+ #without these, the horizontal scrollbars won't be shown
107
+ connect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
108
+ connect view, SIGNAL('collapsed(QModelIndex)'), self, SLOT(:resize_columns)
109
+ setup_actions
110
+ end
111
+
112
+ =begin rdoc
113
+ Displays the data relative to an example in the widget
114
+
115
+ Actually, this method simply passes its argument to a more specific method, depending
116
+ on the data it contains.
117
+
118
+ @param [Hash] data a hash containing the data describing the results of running
119
+ the example. This hash must contain the @:type@ key, which tells which kind of
120
+ event the hash describes. The other entries change depending on the method which
121
+ will be called, which is determined according to the @:type@ entry:
122
+ * @:success@: {#display_successful_example}
123
+ * @:failure@: {#display_failed_example}
124
+ * @:pending@: {#display_pending_example}
125
+ * @:new_example@: {#change_current_example}
126
+ * @:start@: {#set_example_count}
127
+ * @:summary@: {#display_summary}
128
+ If the @:type@ entry doesn't have one of the previous values, the hash will be
129
+ converted to a string and displayed in the widget
130
+ =end
131
+ def display_example data
132
+ unless data.is_a?(Hash)
133
+ model.insert_lines data.to_s, :output, nil
134
+ return
135
+ end
136
+ case data[:type]
137
+ when :success then display_successful_example data
138
+ when :failure then display_failed_example data
139
+ when :pending then display_pending_example data
140
+ when :new_example then change_current_example data
141
+ when :start then set_example_count data
142
+ when :summary then display_summary data
143
+ else model.insert_lines data.to_s, :output, nil
144
+ end
145
+ end
146
+
147
+ def load_settings
148
+ super
149
+ compute_spanning_cols_size
150
+ resize_columns
151
+ end
152
+
153
+ =begin rdoc
154
+ Changes the current example
155
+
156
+ Currently, this only affects the tool tip displayed by the progress bar.
157
+
158
+ @param [Hash] data the data to use. It must contain the @:description@ entry,
159
+ which contains the text of the tool tip to use.
160
+ @return [nil]
161
+ =end
162
+ def change_current_example data
163
+ @progress_bar.tool_tip = data[:description]
164
+ nil
165
+ end
166
+
167
+ =begin rdoc
168
+ Sets the number of examples found by the spec program.
169
+
170
+ This is used to set the maximum value of the progress bar.
171
+
172
+ @param [Hash] data the data to use. It must contain the @:count@ entry,
173
+ which contains the number of examples
174
+ @return [nil]
175
+ =end
176
+ def set_example_count data
177
+ @progress_bar.maximum = data[:count]
178
+ nil
179
+ end
180
+
181
+
182
+ =begin rdoc
183
+ Updates the progress bar by incrementing its value by one
184
+
185
+ @param [Hash] data the data to use. Currently it's unused
186
+ @return [nil]
187
+ =end
188
+ def display_successful_example data
189
+ @progress_bar.value += 1
190
+ nil
191
+ end
192
+
193
+ =begin rdoc
194
+ Displays information about a failed example in the tool widget.
195
+
196
+ @param [Hash] data the data about the example.
197
+
198
+ @option data [String] :location the line number where the error occurred
199
+ @option data [String] :description the name of the failed example
200
+ @option data [String] :message the explaination of why the example failed
201
+ @option data [String] :exception the content of the exception
202
+ @option data [String] :backtrace the backtrace of the exception (a single new-line separated string)
203
+ @return [nil]
204
+ =end
205
+ def display_failed_example data
206
+ @progress_bar.value += 1
207
+ top = model.insert("[FAILURE] #{data[:description]}", :error, nil).first
208
+ model.insert ['From:', data[:location]], :message, nil, :parent => top
209
+ ex_label = model.insert('Exception:', :message, nil, :parent => top).first
210
+ exception_body = "#{data[:message]} (#{data[:exception]})".split_lines.delete_if{|l| l.strip.empty?}
211
+ #exception_body may contain more than one line and some of them may be empty
212
+ model.set exception_body.shift, :message, ex_label.row, :col => 1, :parent => top
213
+ exception_body.each do |l|
214
+ unless l.strip.empty?
215
+ model.set l, :message, top.row_count, :col => 1, :parent => top
216
+ end
217
+ end
218
+ backtrace = data[:backtrace].split_lines
219
+ back_label, back = model.insert(['Backtrace:', backtrace.shift], :message, nil, :parent => top)
220
+ backtrace.each do |l|
221
+ model.insert [nil, l], :message, nil, :parent => back_label
222
+ end
223
+ top_index = filter.map_from_source(top.index)
224
+ view.collapse top_index
225
+ view.set_first_column_spanned top_index.row, Qt::ModelIndex.new, true
226
+ view.expand filter.map_from_source(back_label.index)
227
+ nil
228
+ end
229
+
230
+ =begin rdoc
231
+ Displays information about a pending example in the tool widget
232
+
233
+ @param [Hash] data
234
+ @option data [String] :location the line number where the error occurred
235
+ @option data [String] :description the name of the failed example
236
+ @option data [String] :message the explaination of why the example failed
237
+ @return [nil]
238
+ =end
239
+ def display_pending_example data
240
+ @progress_bar.value += 1
241
+ top = model.insert("[PENDING] #{data[:description]}", :warning, nil)[0]
242
+ model.insert ['From:', data[:location]], :message, nil, :parent => top
243
+ model.insert ['Message: ', "#{data[:message]} (#{data[:exception]})"], :message, nil, :parent => top
244
+ nil
245
+ end
246
+
247
+ =begin rdoc
248
+ Displays a summary of the spec run in the tool widget
249
+
250
+ The summary is a single title line which contains the number or successful, pending
251
+ and failed example.
252
+
253
+ @param [Hash] data
254
+ @option data [Integer] :total the number of run examples
255
+ @option data [Integer] :passed the number of passed examples
256
+ @option data [Integer] :failed the number of failed examples
257
+ @option data [Integer] :pending the number of pending examples
258
+ @return [nil]
259
+ =end
260
+ def display_summary data
261
+ @progress_bar.hide
262
+ if data[:passed] == data[:total]
263
+ self.title = "[SUMMARY] All #{data[:total]} examples passed"
264
+ set_output_type model.index(0,0), :message_good
265
+ else
266
+ text = "[SUMMARY] Examples: #{data[:total]}"
267
+ text << " Failed: #{data[:failure]}" if data[:failure] > 0
268
+ text << " Pending: #{data[:pending]}" if data[:pending] > 0
269
+ text << " Passed: #{data[:passed]}"
270
+ self.title = text
271
+ type = data[:failure] > 0 ? :message_bad : :message
272
+ set_output_type model.index(0,0), type
273
+ end
274
+ nil
275
+ end
276
+
277
+ =begin rdoc
278
+ Override of {OutputWidget#title=}
279
+
280
+ It's needed to have the title element span all columns
281
+
282
+ @param [String] val the new title
283
+ =end
284
+ def title= val
285
+ super
286
+ model.item(0,0).tool_tip = val
287
+ view.set_first_column_spanned 0, Qt::ModelIndex.new, true
288
+ end
289
+
290
+ private
291
+
292
+ =begin rdoc
293
+ Resets the tool widget and sets the cursor to busy
294
+ @return [nil]
295
+ =end
296
+ def spec_started
297
+ @progress_bar.maximum = 0
298
+ @progress_bar.value = 0
299
+ @progress_bar.show
300
+ @progress_bar.tool_tip = ''
301
+ actions['show_stderr'].checked = false
302
+ self.cursor = Qt::Cursor.new(Qt::BusyCursor)
303
+ nil
304
+ end
305
+
306
+ =begin rdoc
307
+ Does the necessary cleanup for when spec finishes running
308
+
309
+ It hides the progress widget and restores the default cursor.
310
+
311
+ @param [Integer] code the exit code
312
+ @param [String] reason why the program exited
313
+ @return [nil]
314
+ =end
315
+ def spec_finished code, reason
316
+ @progress_bar.hide
317
+ @progress_bar.value = 0
318
+ @progress_bar.maximum = 100
319
+ self.set_focus
320
+ unset_cursor
321
+ unless reason == 'killed'
322
+ non_stderr_types = %w[message message_good message_bad warning error]
323
+ only_stderr = !model.item(0,0).text.match(/^\[SUMMARY\]/)
324
+ if only_stderr
325
+ 1.upto(model.row_count - 1) do |i|
326
+ if non_stderr_types.include? model.item(i,0).data(OutputWidget::OutputTypeRole).to_string
327
+ only_stderr = false
328
+ break
329
+ end
330
+ end
331
+ end
332
+ if only_stderr
333
+ actions['show_stderr'].checked = true
334
+ model.insert "spec wasn't able to run the examples", :message_bad, nil
335
+ end
336
+ end
337
+ compute_spanning_cols_size
338
+ auto_expand_items
339
+ nil
340
+ end
341
+
342
+ =begin rdoc
343
+ Expands items according to the @rspec/auto_expand@ option
344
+
345
+ If the option is @:expand_first@, the first failed example is expanded; if the
346
+ option is @:expand_all@, all failed or pending examples are expanded. If the option
347
+ is @:expand_none@, nothing is done
348
+ @return [nil]
349
+ =end
350
+ def auto_expand_items
351
+ if model.row_count > 1
352
+ case Ruber[:config][:rspec, :auto_expand]
353
+ when :expand_first
354
+ item = model.each_row.find{|items| items[0].has_children}
355
+ view.expand filter_model.map_from_source(item[0].index) if item
356
+ when :expand_all
357
+ without_resizing_columns do
358
+ model.each_row do |items|
359
+ view.expand filter_model.map_from_source(items[0].index)
360
+ end
361
+ end
362
+ resize_columns
363
+ end
364
+ end
365
+ nil
366
+ end
367
+
368
+ def compute_spanning_cols_size
369
+ metrics = view.font_metrics
370
+ @toplevel_width = source_model.each_row.map{|r| metrics.bounding_rect(r[0].text).width}.max || 0
371
+ end
372
+
373
+ def resize_columns
374
+ view.resize_column_to_contents 0
375
+ view.resize_column_to_contents 1
376
+ min_width = @toplevel_width - view.column_width(0) + 30
377
+ view.set_column_width 1, min_width if view.column_width(1) < min_width
378
+ end
379
+ slots :resize_columns
380
+
381
+ def without_resizing_columns
382
+ disconnect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
383
+ begin yield
384
+ ensure connect view, SIGNAL('expanded(QModelIndex)'), self, SLOT(:resize_columns)
385
+ end
386
+ end
387
+
388
+ =begin rdoc
389
+ Creates the additional actions.
390
+
391
+ It adds a single action, which allows the user to chose whether messages from
392
+ standard error should be displayed or not.
393
+
394
+ @return [nil]
395
+ =end
396
+ def setup_actions
397
+ action_list << nil << 'show_stderr'
398
+ a = KDE::ToggleAction.new 'S&how Standard Error', self
399
+ actions['show_stderr'] = a
400
+ a.checked = false
401
+ connect a, SIGNAL('toggled(bool)'), filter, SLOT('toggle_display_stderr(bool)')
402
+ end
403
+
404
+ =begin rdoc
405
+ Override of {OutputWidget#find_filename_in_index}
406
+
407
+ It works as the base class method, but, if it doesn't find a result in _idx_,
408
+ it looks for it in the parent indexes
409
+
410
+ @param [Qt::ModelIndex] idx the index where to look for a file name
411
+ @return [Array<String,Integer>,String,nil] see {OutputWidget#find_filename_in_index}
412
+ =end
413
+ def find_filename_in_index idx
414
+ res = super
415
+ unless res
416
+ idx = idx.parent while idx.parent.valid?
417
+ idx = idx.child(0,1)
418
+ res = super idx if idx.valid?
419
+ end
420
+ res
421
+ end
422
+
423
+ =begin rdoc
424
+ Override of {OutputWidget#text_for_clipboard}
425
+
426
+ @param [<Qt::ModelIndex>] idxs the selected indexes
427
+ @return [QString] the text to copy to the clipboard
428
+ =end
429
+ def text_for_clipboard idxs
430
+ order = {}
431
+ idxs.each do |i|
432
+ val = []
433
+ parent = i
434
+ while parent.parent.valid?
435
+ parent = parent.parent
436
+ val.unshift parent.row
437
+ end
438
+ val << [i.row, i.column]
439
+ order[val] = i
440
+ end
441
+ order = order.sort do |a, b|
442
+ a, b = a[0], b[0]
443
+ res = a[0..-2] <=> b[0..-2]
444
+ if res == 0 then a[-1] <=> b[-1]
445
+ else res
446
+ end
447
+ end
448
+ prev = order.shift[1]
449
+ text = prev.data.valid? ? prev.data.to_string : ''
450
+ order.each do |_, v|
451
+ text << ( (prev.parent == v.parent and prev.row == v.row) ? "\t" : "\n")
452
+ text << (v.data.valid? ? v.data.to_string : '')
453
+ prev = v
454
+ end
455
+ text
456
+ end
457
+
458
+ end
459
+
460
+ end
461
+
462
+ end