ruber 0.0.5 → 0.0.7

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 (83) hide show
  1. data/CHANGES +25 -0
  2. data/bin/ruber +0 -0
  3. data/data/share/apps/ruber/ruberui.rc +15 -1
  4. data/data/share/icons/{ruber.png → ruber-old.pgn} +0 -0
  5. data/lib/ruber/application/application.rb +216 -73
  6. data/lib/ruber/application/plugin.yaml +2 -2
  7. data/lib/ruber/document_project.rb +25 -5
  8. data/lib/ruber/documents/document_list.rb +11 -15
  9. data/lib/ruber/editor/document.rb +106 -50
  10. data/lib/ruber/editor/editor_view.rb +4 -2
  11. data/lib/ruber/external_program_plugin.rb +8 -0
  12. data/lib/ruber/kde_config_option_backend.rb +12 -4
  13. data/lib/ruber/kde_sugar.rb +35 -1
  14. data/lib/ruber/main_window/choose_plugins_dlg.rb +10 -10
  15. data/lib/ruber/main_window/hint_solver.rb +263 -0
  16. data/lib/ruber/main_window/main_window.rb +462 -206
  17. data/lib/ruber/main_window/main_window_actions.rb +228 -62
  18. data/lib/ruber/main_window/main_window_internal.rb +169 -115
  19. data/lib/ruber/main_window/plugin.yaml +13 -3
  20. data/lib/ruber/main_window/save_modified_files_dlg.rb +1 -1
  21. data/lib/ruber/main_window/ui/choose_plugins_widget.rb +1 -1
  22. data/lib/ruber/main_window/ui/main_window_settings_widget.rb +1 -1
  23. data/lib/ruber/main_window/ui/new_project_widget.rb +1 -1
  24. data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +1 -1
  25. data/lib/ruber/main_window/ui/output_color_widget.rb +1 -1
  26. data/lib/ruber/main_window/ui/workspace_settings_widget.rb +51 -0
  27. data/lib/ruber/main_window/ui/workspace_settings_widget.ui +28 -0
  28. data/lib/ruber/main_window/view_manager.rb +418 -0
  29. data/lib/ruber/main_window/workspace.png +0 -0
  30. data/lib/ruber/output_widget.rb +43 -37
  31. data/lib/ruber/pane.rb +621 -0
  32. data/lib/ruber/plugin_specification_reader.rb +8 -1
  33. data/lib/ruber/projects/project_files_list.rb +6 -0
  34. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +1 -1
  35. data/lib/ruber/projects/ui/project_files_widget.rb +1 -1
  36. data/lib/ruber/qt_sugar.rb +94 -4
  37. data/lib/ruber/utils.rb +16 -7
  38. data/lib/ruber/version.rb +2 -2
  39. data/plugins/autosave/autosave.rb +62 -1
  40. data/plugins/autosave/plugin.yaml +1 -0
  41. data/plugins/autosave/ui/autosave_config_widget.rb +37 -14
  42. data/plugins/autosave/ui/autosave_config_widget.ui +62 -12
  43. data/plugins/find_in_files/find_in_files_widgets.rb +1 -3
  44. data/plugins/find_in_files/ui/config_widget.rb +1 -1
  45. data/plugins/find_in_files/ui/find_in_files_widget.rb +1 -1
  46. data/plugins/rake/plugin.yaml +1 -1
  47. data/plugins/rake/ui/add_quick_task_widget.rb +1 -1
  48. data/plugins/rake/ui/choose_task_widget.rb +1 -1
  49. data/plugins/rake/ui/config_widget.rb +1 -1
  50. data/plugins/rake/ui/project_widget.rb +1 -1
  51. data/plugins/rspec/rspec.rb +14 -22
  52. data/plugins/rspec/ruber_rspec_formatter.rb +4 -1
  53. data/plugins/rspec/ui/rspec_project_widget.rb +1 -1
  54. data/plugins/ruby_development/plugin.yaml +7 -2
  55. data/plugins/ruby_development/ruby_development.rb +134 -13
  56. data/plugins/ruby_development/ui/config_widget.rb +66 -0
  57. data/plugins/ruby_development/ui/config_widget.ui +58 -0
  58. data/plugins/ruby_development/ui/project_widget.rb +1 -1
  59. data/plugins/ruby_runner/plugin.yaml +2 -2
  60. data/plugins/ruby_runner/ruby_runner.rb +15 -3
  61. data/plugins/ruby_runner/ui/config_widget.rb +1 -1
  62. data/plugins/ruby_runner/ui/project_widget.rb +1 -1
  63. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +1 -1
  64. data/plugins/state/plugin.yaml +6 -2
  65. data/plugins/state/state.rb +305 -81
  66. data/plugins/state/ui/config_widget.rb +1 -1
  67. data/spec/common.rb +11 -3
  68. data/spec/document_list_spec.rb +8 -8
  69. data/spec/document_project_spec.rb +98 -25
  70. data/spec/document_spec.rb +178 -152
  71. data/spec/editor_view_spec.rb +26 -5
  72. data/spec/framework.rb +5 -0
  73. data/spec/hint_solver_spec.rb +450 -0
  74. data/spec/kde_sugar_spec.rb +73 -6
  75. data/spec/output_widget_spec.rb +172 -156
  76. data/spec/pane_spec.rb +1165 -0
  77. data/spec/plugin_specification_reader_spec.rb +37 -1
  78. data/spec/project_files_list_spec.rb +30 -20
  79. data/spec/qt_sugar_spec.rb +269 -0
  80. data/spec/state_spec.rb +566 -353
  81. data/spec/utils_spec.rb +1 -1
  82. data/spec/view_manager_spec.rb +71 -0
  83. metadata +16 -4
@@ -53,7 +53,7 @@ module Ruber
53
53
  @reader.process_pdf({}).should eql(@info)
54
54
  end
55
55
 
56
- it 'should require all files obtained by joining the PluginSpecification\'s directory with the files returned by the read_required method, before calling the read_required method' do
56
+ it 'requires all files obtained by joining the PluginSpecification\'s directory with the files returned by the read_required method, before calling the read_required method' do
57
57
  @info.directory = '/xyz'
58
58
  flexmock(@reader).should_receive(:read_required).and_return %w[a b]
59
59
  flexmock(@reader).should_receive(:require).globally.ordered.once.with '/xyz/a'
@@ -61,6 +61,15 @@ module Ruber
61
61
  flexmock(@reader).should_receive(:read_ui_file).globally.ordered.once.and_return 'testui.rc'
62
62
  @reader.process_pdf({})
63
63
  end
64
+
65
+ it 'loads files returned by the read_required method rather than require them if they end in .rb' do
66
+ @info.directory = '/xyz'
67
+ flexmock(@reader).should_receive(:read_required).and_return %w[a b.rb]
68
+ flexmock(@reader).should_receive(:require).globally.ordered.once.with '/xyz/a'
69
+ flexmock(@reader).should_receive(:load).globally.ordered.once.with '/xyz/b.rb'
70
+ flexmock(@reader).should_receive(:read_ui_file).globally.ordered.once.and_return 'testui.rc'
71
+ @reader.process_pdf({})
72
+ end
64
73
 
65
74
  end
66
75
 
@@ -1651,6 +1660,33 @@ describe Ruber::PluginSpecificationReader do
1651
1660
 
1652
1661
  end
1653
1662
 
1663
+ context ', when reading the place' do
1664
+
1665
+ it 'puts the contents of the place entry of the argument in the :place entry of the returned hash' do
1666
+ @reader.send(:read_rules, {:place => [:local]})[:place].should == [:local]
1667
+ @reader.send(:read_rules, {'place' => [:remote]})[:place].should == [:remote]
1668
+ end
1669
+
1670
+ it 'converts the values :all and all to [:local, :remote]' do
1671
+ @reader.send(:read_rules, {:place => ['all']})[:place].should == [:local, :remote]
1672
+ @reader.send(:read_rules, {'place' => [:all]})[:place].should == [:local, :remote]
1673
+ end
1674
+
1675
+ it 'encloses the place entry of the argument in a array, unless it\'s already an array' do
1676
+ @reader.send(:read_rules, {:place => :local})[:place].should == [:local]
1677
+ end
1678
+
1679
+ it 'converts each entry of the place array to a symbol' do
1680
+ @reader.send(:read_rules, {:place => %w[local remote]})[:place].should == [:local, :remote]
1681
+ end
1682
+
1683
+ it 'uses [:local] as default value' do
1684
+ @reader.send(:read_rules, {})[:place].should == [:local]
1685
+ end
1686
+
1687
+ end
1688
+
1689
+
1654
1690
  describe ', when reading the mimetype' do
1655
1691
 
1656
1692
  it 'stores the contents of the mimetype entry of the argument in the returned value' do
@@ -131,49 +131,49 @@ describe 'Ruber::ProjectFilesList' do
131
131
  FileUtils.rm_f @dir
132
132
  end
133
133
 
134
- it 'should update the cache if it\'s not up to date' do
134
+ it 'updates the cache if it\'s not up to date' do
135
135
  @list.instance_variable_set :@up_to_date, false
136
136
  flexmock(@list).should_receive(:refresh).once
137
137
  @list.project_files
138
138
  end
139
139
 
140
- it 'should not update the cache if it\'s already up to date' do
140
+ it 'doesn\'t update the cache if it\'s already up to date' do
141
141
  @list.instance_variable_set :@up_to_date, true
142
142
  flexmock(@list).should_receive(:refresh).never
143
143
  @list.project_files
144
144
  end
145
145
 
146
- it 'should return an array containing all the files corresponding to include rules of type path unless they also correspond to an exclude rule of type path' do
146
+ it 'returns an array containing all the files corresponding to include rules of type path unless they also correspond to an exclude rule of type path' do
147
147
  @prj[:general, :project_files] = {:include => ['README', 'COPYING', 'f1.rb', 'd2/CHANGELOG', 'd2/f21.rb'], :exclude => ['COPYING', 'd2/f21.rb'], :extensions => []}
148
148
  @list.project_files(false).should =~ %w[README f1.rb d2/CHANGELOG]
149
149
  end
150
150
 
151
- it 'should not include in the returned array files which don\'t exist' do
151
+ it 'doesn\'t include in the returned array files which don\'t exist' do
152
152
  @prj[:general, :project_files] = {:include => ['README1', 'COPYING', 'f1.rb', 'd2/CHANGELOG', 'd2/f211.rb'], :exclude => ['COPYING'], :extensions => []}
153
153
  @list.project_files(false).should =~ %w[f1.rb d2/CHANGELOG]
154
154
  end
155
155
 
156
- it 'should skip include rules of type path corresponding to directories' do
156
+ it 'skips include rules of type path corresponding to directories' do
157
157
  @prj[:general, :project_files] = {:include => ['README', 'COPYING', 'f1.rb', 'd2/CHANGELOG', 'd2/f21.rb', 'd3'], :exclude => ['COPYING', 'd2/f21.rb'], :extensions => []}
158
158
  @list.project_files(false).should =~ %w[README f1.rb d2/CHANGELOG]
159
159
  end
160
160
 
161
- it 'should include all the files in the project directory which correspond to one of the extensions in the returned array, unless they match one of the exclude rule' do
161
+ it 'includes all the files in the project directory which correspond to one of the extensions in the returned array, unless they match one of the exclude rule' do
162
162
  @prj[:general, :project_files] = {:include => [], :exclude => ['COPYING', 'd2/f21.rb'], :extensions => %w[*.rb]}
163
163
  @list.project_files(false).should =~ %w[f1.rb d2/f22.rb d3/f31.rb d3/f32.rb]
164
164
  end
165
165
 
166
- it 'should include all the files in the project directory which match one of the include rules of type regexp and don\'t match any exclude rule' do
166
+ it 'includes all the files in the project directory which match one of the include rules of type regexp and don\'t match any exclude rule' do
167
167
  @prj[:general, :project_files] = {:include => [%r{d3/.*}, %r{.*\.yaml}], :exclude => [%r{d3/.*2.*}, %r{.*1.*\.rb}], :extensions => []}
168
168
  @list.project_files(false).should =~ %w[d2/f22.yaml f1.yaml d2/f21.yaml]
169
169
  end
170
170
 
171
- it 'should not include duplicate elements' do
171
+ it 'doesn\'t include duplicate elements' do
172
172
  @prj[:general, :project_files] = {:include => [%r{d2/.*}, 'f1.rb'], :exclude => [], :extensions => ['*.rb']}
173
173
  @list.project_files(false).should =~ %w[f1.rb d2/f21.rb d2/f22.rb d2/f21.yaml d2/f22.yaml d2/CHANGELOG d3/f31.rb d3/f32.rb]
174
174
  end
175
175
 
176
- it 'should return a deep copy of the cache object' do
176
+ it 'returns a deep copy of the cache object' do
177
177
  @prj[:general, :project_files] = {:include => [%r{d2/.*}, 'f1.rb'], :exclude => [], :extensions => ['*.rb']}
178
178
  old_cache = @list.instance_variable_get(:@project_files).deep_copy
179
179
  res = @list.project_files(false)
@@ -182,12 +182,12 @@ describe 'Ruber::ProjectFilesList' do
182
182
  @list.instance_variable_get(:@project_files).should == old_cache
183
183
  end
184
184
 
185
- it 'should return full paths if the argument is true' do
185
+ it 'returns full paths if the argument is true' do
186
186
  @prj[:general, :project_files] = {:include => [%r{d2/.*}, 'f1.rb'], :exclude => [], :extensions => ['*.rb']}
187
187
  @list.project_files(true).should =~ %w[f1.rb d2/f21.rb d2/f22.rb d2/f21.yaml d2/f22.yaml d2/CHANGELOG d3/f31.rb d3/f32.rb].map{|i| File.join @dir, i}
188
188
  end
189
189
 
190
- it 'should return the correct list if a file or directory is added or deleted after the file watcher has been created' do
190
+ it 'returns the correct list if a file or directory is added or deleted after the file watcher has been created' do
191
191
  @prj[:general, :project_files] = {:include => [], :exclude => [], :extensions => ['*.rb']}
192
192
  # Experiments show that KDE::DirWatch needs an event loop to work. Since we don't have one running, we'll have to make it emit the 'dirty' signal manually
193
193
  watcher = @list.instance_variable_get(:@watcher)
@@ -213,7 +213,7 @@ describe 'Ruber::ProjectFilesList' do
213
213
  watcher.instance_eval{emit dirty( @dir)}
214
214
  @list.project_files(false).should_not include("f1.rb")
215
215
  end
216
-
216
+
217
217
  end
218
218
 
219
219
  describe 'Ruber::ProjectFilesList#each' do
@@ -344,41 +344,41 @@ describe 'Ruber::ProjectFilesList' do
344
344
  @prj.add_extension :file_lister, @list
345
345
  end
346
346
 
347
- it 'should return true if the argument matches one of the exact include rules' do
347
+ it 'returns true if the argument matches one of the exact include rules' do
348
348
  @prj[:general, :project_files] = {:include => %w[./xyz ./abc ./123], :exclude => [], :extensions => ['*.rb']}
349
349
  @list.file_in_project?(File.join(@prj.project_dir, 'abc')).should be_true
350
350
  end
351
351
 
352
- it 'should return true if the argument matches one of the regexp include rules' do
352
+ it 'returns true if the argument matches one of the regexp include rules' do
353
353
  @prj[:general, :project_files] = {:include => [/a/, /x/], :exclude => [], :extensions => ['*.rb']}
354
354
  @list.file_in_project?(File.join(@prj.project_dir, 'xyz')).should be_true
355
355
  end
356
356
 
357
- it 'should return true if the argument matches one of the include extensions' do
357
+ it 'returns true if the argument matches one of the include extensions' do
358
358
  @prj[:general, :project_files] = {:include => [], :exclude => [], :extensions => ['*.rb', '*.yaml']}
359
359
  @list.file_in_project?(File.join(@prj.project_dir, 'abc.rb')).should be_true
360
360
  end
361
361
 
362
- it 'should return false if the file isn\'t in the project directory' do
362
+ it 'returns false if the file isn\'t in the project directory' do
363
363
  @prj[:general, :project_files] = {:include => %w[xyz abc 123], :exclude => [], :extensions => ['*.rb']}
364
364
  @list.file_in_project?('/usr/abc').should be_false
365
365
  end
366
366
 
367
- it 'should treat the argument as a path relative to the project directory if it isn\'t an absolute path' do
367
+ it 'treats the argument as a path relative to the project directory if it isn\'t an absolute path' do
368
368
  @prj[:general, :project_files] = {:include => %w[xyz abc 123], :exclude => [], :extensions => ['*.rb']}
369
369
  @list.file_in_project?('abc').should be_true
370
370
  end
371
371
 
372
- it 'should return false if the file doesn\'t match any include rule' do
372
+ it 'returns false if the file doesn\'t match any include rule' do
373
373
  @list.file_in_project?(File.join(@prj.project_dir, 'abc.rb')).should be_false
374
374
  end
375
375
 
376
- it 'should return false if the file matches one of the file exclude rules' do
376
+ it 'returns false if the file matches one of the file exclude rules' do
377
377
  @prj[:general, :project_files] = {:include => %w[xyz abc 123], :exclude => ['abc'], :extensions => ['*.rb']}
378
378
  @list.file_in_project?(File.join(@prj.project_dir, 'abc')).should be_false
379
379
  end
380
380
 
381
- it 'should return false if the file matches one of the exclude regexps' do
381
+ it 'returns false if the file matches one of the exclude regexps' do
382
382
  @prj[:general, :project_files] = {:include => [/a/], :exclude => [/a/], :extensions => []}
383
383
  @list.file_in_project?(File.join(@prj.project_dir, 'abc')).should be_false
384
384
  end
@@ -394,6 +394,16 @@ describe 'Ruber::ProjectFilesList' do
394
394
  @list.file_in_project?('xyz/').should be_nil
395
395
  end
396
396
 
397
+ it 'returns false if the path represents a remote URL' do
398
+ @prj[:general, :project_files] = {:include => [], :exclude => [], :extensions => ['*.rb']}
399
+ @list.file_in_project?("http://#{@dir}/abc.xyz.rb").should be_false
400
+ end
401
+
402
+ it 'works normally if the path represents a local url' do
403
+ @prj[:general, :project_files] = {:include => [], :exclude => [], :extensions => ['*.rb']}
404
+ @list.file_in_project?("file://#{@dir}/abc.xyz.rb").should be_true
405
+ end
406
+
397
407
  end
398
408
 
399
409
  end
@@ -326,3 +326,272 @@ describe Qt::Variant, '#to_bool' do
326
326
  end
327
327
 
328
328
  end
329
+
330
+ describe Qt::Layout do
331
+
332
+ it 'includes QtEnumerable' do
333
+ Qt::Layout.ancestors.should include(QtEnumerable)
334
+ end
335
+
336
+ describe '#each' do
337
+
338
+ it 'passes to the block each widget in turn if called with a block' do
339
+ #Since Qt::Layout is an abstract class, we fake calls to count and item_at,
340
+ #which are pure virtual, with mocks
341
+ w = Qt::Widget.new
342
+ layout = Qt::Layout.new w
343
+ w.layout = layout
344
+ widgets = [Qt::PushButton, Qt::VBoxLayout, Qt::CheckBox].map{|c| c.new}
345
+ res = []
346
+ flexmock(layout).should_receive(:count).once.and_return(3)
347
+ flexmock(layout).should_receive(:item_at).with(0).once.and_return(Qt::WidgetItem.new(widgets[0]))
348
+ flexmock(layout).should_receive(:item_at).with(1).once.and_return(widgets[1])
349
+ flexmock(layout).should_receive(:item_at).with(2).once.and_return(Qt::WidgetItem.new(widgets[2]))
350
+ layout.each{|w| res << w}
351
+ res.should == widgets
352
+ end
353
+
354
+ it 'returns an enumerator if no block is given' do
355
+ w = Qt::Widget.new
356
+ layout = Qt::Layout.new w
357
+ w.layout = layout
358
+ widgets = [Qt::PushButton, Qt::VBoxLayout, Qt::CheckBox].map{|c| c.new}
359
+ res = []
360
+ flexmock(layout).should_receive(:count).once.and_return(3)
361
+ flexmock(layout).should_receive(:item_at).with(0).once.and_return(Qt::WidgetItem.new(widgets[0]))
362
+ flexmock(layout).should_receive(:item_at).with(1).once.and_return(widgets[1])
363
+ flexmock(layout).should_receive(:item_at).with(2).once.and_return(Qt::WidgetItem.new(widgets[2]))
364
+ e = layout.each
365
+ e.each{|w| res << w}
366
+ res.should == widgets
367
+ end
368
+
369
+ end
370
+
371
+ end
372
+
373
+ shared_examples_for 'any box layout' do
374
+
375
+ it 'includes QtEnumerable' do
376
+ @layout.class.ancestors.should include(QtEnumerable)
377
+ end
378
+
379
+ it 'has an each method which passes to the block each widget in turn if called with a block' do
380
+ w = Qt::Widget.new
381
+ w.layout = @layout
382
+ widgets = [Qt::PushButton, Qt::VBoxLayout, Qt::CheckBox].map{|c| c.new}
383
+ widgets.each{|w| @layout.send w.is_a?(Qt::Widget) ? :add_widget : :add_layout, w}
384
+ res = []
385
+ @layout.each{|w| res << w}
386
+ res.should == widgets
387
+ end
388
+
389
+ it 'has an each method which returns an enumerator if no block is given' do
390
+ w = Qt::Widget.new
391
+ w.layout = @layout
392
+ widgets = [Qt::PushButton, Qt::VBoxLayout, Qt::CheckBox].map{|c| c.new}
393
+ res = []
394
+ widgets.each{|w| @layout.send w.is_a?(Qt::Widget) ? :add_widget : :add_layout, w}
395
+ e = @layout.each
396
+ e.each{|w| res << w}
397
+ res.should == widgets
398
+ end
399
+
400
+ end
401
+
402
+ describe Qt::BoxLayout do
403
+
404
+ before do
405
+ @layout = Qt::BoxLayout.new(Qt::Horizontal)
406
+ end
407
+
408
+ it_behaves_like 'any box layout'
409
+
410
+ end
411
+
412
+ describe Qt::VBoxLayout do
413
+
414
+ before do
415
+ @layout = Qt::VBoxLayout.new
416
+ end
417
+
418
+ it_behaves_like 'any box layout'
419
+
420
+ end
421
+
422
+ describe Qt::HBoxLayout do
423
+
424
+ before do
425
+ @layout = Qt::HBoxLayout.new
426
+ end
427
+
428
+ it_behaves_like 'any box layout'
429
+
430
+ end
431
+
432
+ describe Qt::StackedLayout do
433
+
434
+ before do
435
+ @layout = Qt::StackedLayout.new
436
+ end
437
+
438
+ it 'includes QtEnumerable' do
439
+ @layout.class.ancestors.should include(QtEnumerable)
440
+ end
441
+
442
+ it 'has an each method which passes to the block each widget in turn if called with a block' do
443
+ w = Qt::Widget.new
444
+ w.layout = @layout
445
+ widgets = [Qt::PushButton, Qt::LineEdit, Qt::CheckBox].map{|c| c.new}
446
+ widgets.each{|w| @layout.add_widget w}
447
+ res = []
448
+ @layout.each{|w| res << w}
449
+ res.should == widgets
450
+ end
451
+
452
+ it 'has an each method which returns an enumerator if no block is given' do
453
+ w = Qt::Widget.new
454
+ w.layout = @layout
455
+ widgets = [Qt::PushButton, Qt::LineEdit, Qt::CheckBox].map{|c| c.new}
456
+ res = []
457
+ widgets.each{|w| @layout.add_widget w}
458
+ e = @layout.each
459
+ e.each{|w| res << w}
460
+ res.should == widgets
461
+ end
462
+
463
+ end
464
+
465
+ describe Qt::FormLayout do
466
+
467
+ before do
468
+ @layout = Qt::FormLayout.new
469
+ end
470
+
471
+ it 'includes QtEnumerable' do
472
+ @layout.class.ancestors.should include(QtEnumerable)
473
+ end
474
+
475
+ it 'has an each method which passes to the block each widget in turn if called with a block' do
476
+ w = Qt::Widget.new
477
+ w.layout = @layout
478
+ widgets = [['l1', Qt::PushButton], ['l2', Qt::LineEdit], ['l3', Qt::CheckBox]].map{|c| [Qt::Label.new(c[0]), c[1].new]}
479
+ widgets.each{|w| @layout.add_row w[0], w[1]}
480
+ res = []
481
+ @layout.each{|w| res << w}
482
+ res.should == widgets.flatten
483
+ end
484
+
485
+ it 'has an each method which returns an enumerator if no block is given' do
486
+ w = Qt::Widget.new
487
+ w.layout = @layout
488
+ widgets = [['l1', Qt::PushButton], ['l2', Qt::LineEdit], ['l3', Qt::CheckBox]].map{|c| [Qt::Label.new(c[0]), c[1].new]}
489
+ widgets.each{|w| @layout.add_row w[0], w[1]}
490
+ res = []
491
+ e = @layout.each
492
+ e.each{|w| res << w}
493
+ res.should == widgets.flatten
494
+ end
495
+
496
+ end
497
+
498
+ describe Qt::GridLayout do
499
+
500
+ before do
501
+ @layout = Qt::GridLayout.new
502
+ end
503
+
504
+ it 'includes QtEnumerable' do
505
+ @layout.class.ancestors.should include(QtEnumerable)
506
+ end
507
+
508
+ it 'has an each method which passes to the block each widget in turn if called with a block' do
509
+ w = Qt::Widget.new
510
+ w.layout = @layout
511
+ widgets = [[Qt::TextEdit, Qt::HBoxLayout], [Qt::Label, Qt::LineEdit], [Qt::VBoxLayout, Qt::CheckBox]].map{|c1, c2| [c1.new, c2.new]}
512
+ add = lambda{|w, r, c|w.is_a?(Qt::Widget) ? @layout.add_widget(w, r, c) : @layout.add_layout(w, r, c) }
513
+ widgets.each_with_index do |w, r|
514
+ add.call w[0], r, 0
515
+ add.call w[1], r, 1
516
+ end
517
+ res = []
518
+ @layout.each{|w| res << w}
519
+ res.should == widgets.flatten
520
+ end
521
+
522
+ it 'has an each method which returns an enumerator if no block is given' do
523
+ w = Qt::Widget.new
524
+ w.layout = @layout
525
+ widgets = [[Qt::TextEdit, Qt::HBoxLayout], [Qt::Label, Qt::LineEdit], [Qt::VBoxLayout, Qt::CheckBox]].map{|c1, c2| [c1.new, c2.new]}
526
+ add = lambda{|w, r, c|w.is_a?(Qt::Widget) ? @layout.add_widget(w, r, c) : @layout.add_layout(w, r, c) }
527
+ widgets.each_with_index do |w, r|
528
+ add.call w[0], r, 0
529
+ add.call w[1], r, 1
530
+ end
531
+ res = []
532
+ e = @layout.each
533
+ e.each{|w| res << w}
534
+ res.should == widgets.flatten
535
+ end
536
+
537
+ it 'passes widgets spanning more than one row or column only once' do
538
+ w = Qt::Widget.new
539
+ w.layout = @layout
540
+ widgets = [[Qt::TextEdit, Qt::HBoxLayout], [Qt::LineEdit], [Qt::VBoxLayout, Qt::CheckBox]].map do |c1, c2|
541
+ c2 ? [c1.new, c2.new] : [c1.new]
542
+ end
543
+ add = lambda{|w, r, c, r1, c1|w.is_a?(Qt::Widget) ? @layout.add_widget(w, r, c, r1, c1) : @layout.add_layout(w, r, c, r1, c1) }
544
+ widgets.each_with_index do |w, r|
545
+ if w.size == 1
546
+ add.call w[0], r, 0, r, 1
547
+ else
548
+ add.call w[0], r, 0, r, 0
549
+ add.call w[1], r, 1, r, 1
550
+ end
551
+ end
552
+ res = []
553
+ @layout.each{|w| res << w}
554
+ res.should == widgets.flatten
555
+ end
556
+
557
+ end
558
+
559
+ describe Qt::Splitter do
560
+
561
+ it 'includes the QtEnumerable module' do
562
+ Qt::Splitter.ancestors.should include(QtEnumerable)
563
+ end
564
+
565
+ describe '#each' do
566
+
567
+ before do
568
+ @splitter = Qt::Splitter.new Qt::Vertical
569
+ end
570
+
571
+ it 'calls the block each widget in the splitter' do
572
+ widgets = [Qt::LineEdit, Qt::PushButton, Qt::Label].map{|cls| cls.new}
573
+ widgets.reverse_each{|w| @splitter.add_widget w}
574
+ res = []
575
+ @splitter.each{|w| res << w}
576
+ res.should == widgets.reverse
577
+ end
578
+
579
+ it 'returns an enumerator if no block is given' do
580
+ widgets = [Qt::LineEdit, Qt::PushButton, Qt::Label].map{|cls| cls.new}
581
+ widgets.reverse_each{|w| @splitter.add_widget w}
582
+ res = []
583
+ enum = @splitter.each
584
+ enum.should be_an(Enumerator)
585
+ enum.each{|w| res << w}
586
+ res.should == widgets.reverse
587
+ end
588
+
589
+ it 'returns self if a block has been given' do
590
+ widgets = [Qt::LineEdit, Qt::PushButton, Qt::Label].map{|cls| cls.new}
591
+ widgets.reverse_each{|w| @splitter.add_widget w}
592
+ @splitter.each{}.should == @splitter
593
+ end
594
+
595
+ end
596
+
597
+ end