ruber 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
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