ruber 0.0.1.1
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/COPYING +339 -0
- data/INSTALL +137 -0
- data/LICENSE +8 -0
- data/bin/ruber +65 -0
- data/data/share/apps/ruber/core_components.yaml +31 -0
- data/data/share/apps/ruber/ruberui.rc +109 -0
- data/data/share/icons/ruber.png +0 -0
- data/data/share/pixmaps/ruby.png +0 -0
- data/icons/ruber-16.png +0 -0
- data/icons/ruber-32.png +0 -0
- data/icons/ruber-48.png +0 -0
- data/icons/ruber-8.png +0 -0
- data/lib/ruber/application/application.rb +288 -0
- data/lib/ruber/application/plugin.yaml +11 -0
- data/lib/ruber/component_manager.rb +899 -0
- data/lib/ruber/config/config.rb +82 -0
- data/lib/ruber/config/plugin.yaml +3 -0
- data/lib/ruber/document_project.rb +209 -0
- data/lib/ruber/documents/document_list.rb +416 -0
- data/lib/ruber/documents/plugin.yaml +4 -0
- data/lib/ruber/editor/document.rb +506 -0
- data/lib/ruber/editor/editor_view.rb +167 -0
- data/lib/ruber/editor/ktexteditor_wrapper.rb +202 -0
- data/lib/ruber/exception_widgets.rb +245 -0
- data/lib/ruber/external_program_plugin.rb +397 -0
- data/lib/ruber/filtered_output_widget.rb +342 -0
- data/lib/ruber/gui_states_handler.rb +231 -0
- data/lib/ruber/kde_config_option_backend.rb +167 -0
- data/lib/ruber/kde_sugar.rb +249 -0
- data/lib/ruber/main_window/choose_plugins_dlg.rb +353 -0
- data/lib/ruber/main_window/main_window.rb +524 -0
- data/lib/ruber/main_window/main_window_actions.rb +537 -0
- data/lib/ruber/main_window/main_window_internal.rb +239 -0
- data/lib/ruber/main_window/open_file_in_project_dlg.rb +212 -0
- data/lib/ruber/main_window/output_color_widget.rb +35 -0
- data/lib/ruber/main_window/plugin.yaml +58 -0
- data/lib/ruber/main_window/save_modified_files_dlg.rb +89 -0
- data/lib/ruber/main_window/status_bar.rb +156 -0
- data/lib/ruber/main_window/ui/choose_plugins_widget.rb +90 -0
- data/lib/ruber/main_window/ui/choose_plugins_widget.ui +77 -0
- data/lib/ruber/main_window/ui/main_window_settings_widget.rb +108 -0
- data/lib/ruber/main_window/ui/main_window_settings_widget.ui +89 -0
- data/lib/ruber/main_window/ui/new_project_widget.rb +119 -0
- data/lib/ruber/main_window/ui/new_project_widget.ui +178 -0
- data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +109 -0
- data/lib/ruber/main_window/ui/open_file_in_project_dlg.ui +168 -0
- data/lib/ruber/main_window/ui/output_color_widget.rb +241 -0
- data/lib/ruber/main_window/ui/output_color_widget.ui +204 -0
- data/lib/ruber/main_window/workspace.rb +442 -0
- data/lib/ruber/output_widget.rb +1093 -0
- data/lib/ruber/plugin.rb +264 -0
- data/lib/ruber/plugin_like.rb +589 -0
- data/lib/ruber/plugin_specification.rb +106 -0
- data/lib/ruber/plugin_specification_reader.rb +451 -0
- data/lib/ruber/project.rb +493 -0
- data/lib/ruber/project_backend.rb +105 -0
- data/lib/ruber/projects/plugin.yaml +11 -0
- data/lib/ruber/projects/project_files_list.rb +314 -0
- data/lib/ruber/projects/project_files_widget.rb +301 -0
- data/lib/ruber/projects/project_list.rb +314 -0
- data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +74 -0
- data/lib/ruber/projects/ui/project_files_rule_chooser_widget.ui +61 -0
- data/lib/ruber/projects/ui/project_files_widget.rb +117 -0
- data/lib/ruber/projects/ui/project_files_widget.ui +123 -0
- data/lib/ruber/qt_sugar.rb +673 -0
- data/lib/ruber/settings_container.rb +515 -0
- data/lib/ruber/settings_dialog.rb +244 -0
- data/lib/ruber/settings_dialog_manager.rb +503 -0
- data/lib/ruber/utils.rb +414 -0
- data/lib/ruber/yaml_option_backend.rb +159 -0
- data/outsider_files +15 -0
- data/plugins/autosave/autosave.rb +404 -0
- data/plugins/autosave/plugin.yaml +16 -0
- data/plugins/autosave/ui/autosave_config_widget.rb +83 -0
- data/plugins/autosave/ui/autosave_config_widget.ui +68 -0
- data/plugins/command/command.png +0 -0
- data/plugins/command/command.rb +74 -0
- data/plugins/command/plugin.yaml +11 -0
- data/plugins/find_in_files/find_in_files.rb +337 -0
- data/plugins/find_in_files/find_in_files_dlg.rb +411 -0
- data/plugins/find_in_files/find_in_files_ui.rc +11 -0
- data/plugins/find_in_files/find_in_files_widgets.rb +485 -0
- data/plugins/find_in_files/plugin.yaml +23 -0
- data/plugins/find_in_files/ui/config_widget.rb +58 -0
- data/plugins/find_in_files/ui/config_widget.ui +41 -0
- data/plugins/find_in_files/ui/find_in_files_widget.rb +260 -0
- data/plugins/find_in_files/ui/find_in_files_widget.ui +324 -0
- data/plugins/project_browser/plugin.yaml +10 -0
- data/plugins/project_browser/project_browser.rb +245 -0
- data/plugins/rake/plugin.yaml +39 -0
- data/plugins/rake/rake.png +0 -0
- data/plugins/rake/rake.rb +567 -0
- data/plugins/rake/rake_extension.rb +153 -0
- data/plugins/rake/rake_widgets.rb +615 -0
- data/plugins/rake/rakeui.rc +27 -0
- data/plugins/rake/ui/add_quick_task_widget.rb +71 -0
- data/plugins/rake/ui/add_quick_task_widget.ui +59 -0
- data/plugins/rake/ui/choose_task_widget.rb +77 -0
- data/plugins/rake/ui/choose_task_widget.ui +72 -0
- data/plugins/rake/ui/config_widget.rb +127 -0
- data/plugins/rake/ui/config_widget.ui +123 -0
- data/plugins/rake/ui/project_widget.rb +217 -0
- data/plugins/rake/ui/project_widget.ui +246 -0
- data/plugins/rspec/plugin.yaml +30 -0
- data/plugins/rspec/rspec.png +0 -0
- data/plugins/rspec/rspec.rb +945 -0
- data/plugins/rspec/rspec.svg +90 -0
- data/plugins/rspec/rspecui.rc +20 -0
- data/plugins/rspec/ruber_rspec_formatter.rb +312 -0
- data/plugins/rspec/ui/rspec_project_widget.rb +170 -0
- data/plugins/rspec/ui/rspec_project_widget.ui +193 -0
- data/plugins/ruby_development/plugin.yaml +27 -0
- data/plugins/ruby_development/ruby_development.png +0 -0
- data/plugins/ruby_development/ruby_development.rb +453 -0
- data/plugins/ruby_development/ruby_developmentui.rc +19 -0
- data/plugins/ruby_development/ui/project_widget.rb +112 -0
- data/plugins/ruby_development/ui/project_widget.ui +108 -0
- data/plugins/ruby_runner/config_widget.rb +116 -0
- data/plugins/ruby_runner/plugin.yaml +26 -0
- data/plugins/ruby_runner/project_widget.rb +62 -0
- data/plugins/ruby_runner/ruby.png +0 -0
- data/plugins/ruby_runner/ruby_interpretersui.rc +26 -0
- data/plugins/ruby_runner/ruby_runner.rb +411 -0
- data/plugins/ruby_runner/ui/config_widget.rb +92 -0
- data/plugins/ruby_runner/ui/config_widget.ui +91 -0
- data/plugins/ruby_runner/ui/project_widget.rb +60 -0
- data/plugins/ruby_runner/ui/project_widget.ui +48 -0
- data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +59 -0
- data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.ui +44 -0
- data/plugins/state/plugin.yaml +28 -0
- data/plugins/state/state.rb +520 -0
- data/plugins/state/ui/config_widget.rb +92 -0
- data/plugins/state/ui/config_widget.ui +89 -0
- data/plugins/syntax_checker/plugin.yaml +18 -0
- data/plugins/syntax_checker/syntax_checker.rb +662 -0
- data/ruber.desktop +10 -0
- data/spec/annotation_model_spec.rb +174 -0
- data/spec/common.rb +119 -0
- data/spec/component_manager_spec.rb +1259 -0
- data/spec/document_list_spec.rb +626 -0
- data/spec/document_project_spec.rb +373 -0
- data/spec/document_spec.rb +779 -0
- data/spec/editor_view_spec.rb +167 -0
- data/spec/external_program_plugin_spec.rb +676 -0
- data/spec/filtered_output_widget_spec.rb +642 -0
- data/spec/gui_states_handler_spec.rb +304 -0
- data/spec/kde_config_option_backend_spec.rb +214 -0
- data/spec/kde_sugar_spec.rb +101 -0
- data/spec/ktexteditor_wrapper_spec.rb +305 -0
- data/spec/output_widget_spec.rb +1703 -0
- data/spec/plugin_spec.rb +1393 -0
- data/spec/plugin_specification_reader_spec.rb +1765 -0
- data/spec/plugin_specification_spec.rb +401 -0
- data/spec/project_backend_spec.rb +172 -0
- data/spec/project_files_list_spec.rb +401 -0
- data/spec/project_list_spec.rb +511 -0
- data/spec/project_spec.rb +990 -0
- data/spec/qt_sugar_spec.rb +328 -0
- data/spec/settings_container_spec.rb +617 -0
- data/spec/settings_dialog_manager_spec.rb +773 -0
- data/spec/settings_dialog_spec.rb +419 -0
- data/spec/state_spec.rb +991 -0
- data/spec/utils_spec.rb +406 -0
- data/spec/workspace_spec.rb +869 -0
- data/spec/yaml_option_backend_spec.rb +246 -0
- metadata +284 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
require 'spec/common'
|
|
2
|
+
|
|
3
|
+
require 'ruber/settings_dialog'
|
|
4
|
+
require 'ruber/settings_container'
|
|
5
|
+
|
|
6
|
+
describe 'Ruber::SettingsDialog, when created' do
|
|
7
|
+
|
|
8
|
+
include FlexMock::ArgumentTypes
|
|
9
|
+
|
|
10
|
+
before do
|
|
11
|
+
@back = flexmock('backend'){|m| m.should_ignore_missing}
|
|
12
|
+
@cont = Object.new
|
|
13
|
+
@cont.extend Ruber::SettingsContainer
|
|
14
|
+
@cont.send :setup_container, @back
|
|
15
|
+
@widgets = [
|
|
16
|
+
OS.new({:caption => 'C1', :class_obj => Qt::CheckBox}),
|
|
17
|
+
OS.new({:caption => 'C2', :class_obj => Qt::LineEdit}),
|
|
18
|
+
OS.new({:caption => 'C2', :code => 'Qt::PushButton.new("test")'}),
|
|
19
|
+
OS.new({:caption => 'C1', :class_obj => Qt::RadioButton, :code => 'Qt::ComboBox.new'})
|
|
20
|
+
]
|
|
21
|
+
@mw = Qt::Widget.new
|
|
22
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).by_default.and_return @mw
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should set its title to the fourth argument, if given' do
|
|
26
|
+
dlg = Ruber::SettingsDialog.new @cont, {}, [], 'Title'
|
|
27
|
+
dlg.window_title.should == 'Title'
|
|
28
|
+
dlg = Ruber::SettingsDialog.new @cont, {}, []
|
|
29
|
+
dlg.window_title.should == KDE::Application.instance.application_name
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'should store the first argument in the @container instance variable' do
|
|
33
|
+
dlg = Ruber::SettingsDialog.new @cont, {}, []
|
|
34
|
+
dlg.instance_variable_get(:@container).should equal(@cont)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should create the widgets specified in the third argument and store it in the @pages instance variable, grouped by captions' do
|
|
38
|
+
@widgets.each{|w| @cont.add_widget w}
|
|
39
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
40
|
+
res = dlg.instance_variable_get(:@widgets)
|
|
41
|
+
res['C1'][0].should be_a(Qt::CheckBox)
|
|
42
|
+
res['C1'][1].should be_a(Qt::ComboBox)
|
|
43
|
+
res['C2'][0].should be_a(Qt::LineEdit)
|
|
44
|
+
res['C2'][1].should be_a(Qt::PushButton)
|
|
45
|
+
res['C2'][1].text.should == 'test'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'should add an @settings_dialog instance variable and set it to self for each widget it creates' do
|
|
49
|
+
@widgets.each{|w| @cont.add_widget w}
|
|
50
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
51
|
+
widgets = dlg.instance_variable_get(:@widgets).values.flatten
|
|
52
|
+
widgets.each{|w| w.instance_variable_get(:@settings_dialog).should equal(dlg)}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'should add a page for each caption and store the corresponding PageWidgetItems in the @page_items instance variable' do
|
|
56
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
57
|
+
dlg.instance_variable_get(:@page_items).size.should == 2
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'should create a page for each caption, in alphabetical order, with the widgets stored in a vertical layout, from first to last' do
|
|
61
|
+
@widgets.unshift @widgets.delete_at(1)
|
|
62
|
+
@widgets.each{|w| @cont.add_widget w}
|
|
63
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
64
|
+
items = dlg.instance_variable_get :@page_items
|
|
65
|
+
|
|
66
|
+
l = items[0].widget.layout
|
|
67
|
+
l.should be_a(Qt::VBoxLayout)
|
|
68
|
+
l.item_at(0).widget.should be_a(Qt::CheckBox)
|
|
69
|
+
l.item_at(1).widget.should be_a(Qt::ComboBox)
|
|
70
|
+
|
|
71
|
+
l = items[1].widget.layout
|
|
72
|
+
l.item_at(0).widget.should be_a(Qt::LineEdit)
|
|
73
|
+
l.item_at(1).widget.should be_a(Qt::PushButton)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'should use the first specified icon for each page' do
|
|
77
|
+
%w[xyz.png 123.png 456.png abc.png].each_with_index{|p, i| @widgets[i].pixmap = p}
|
|
78
|
+
@widgets.each{|w| @cont.add_widget w}
|
|
79
|
+
icons = [KDE::Icon.new( 'xyz.png'), KDE::Icon.new('123.png')]
|
|
80
|
+
flexmock(KDE::Icon).should_receive(:new).once.with('xyz.png').and_return(icons[0])
|
|
81
|
+
flexmock(KDE::Icon).should_receive(:new).once.with('123.png').and_return(icons[1])
|
|
82
|
+
flexmock(KDE::Icon).should_receive(:new).with('abc.png').never
|
|
83
|
+
flexmock(KDE::Icon).should_receive(:new).with('456.png').never
|
|
84
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
85
|
+
items = dlg.instance_variable_get :@page_items
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'should create an instance of the SettingsDialogManager class, passing it self, the widgets and the options' do
|
|
89
|
+
options = {
|
|
90
|
+
OS.new({:group => 'G1', :name => :o1, :default => 2}) => 3,
|
|
91
|
+
OS.new({:group => :G2, :name => :o2, :default => 'xyz'}) => 'abc'
|
|
92
|
+
}
|
|
93
|
+
@widgets.each{|w| @cont.add_widget w}
|
|
94
|
+
flexmock(Ruber::SettingsDialogManager).should_receive(:new).once.with(Ruber::SettingsDialog, options, on{|a| a.map(&:class) == [Qt::CheckBox, Qt::ComboBox, Qt::LineEdit, Qt::PushButton]})
|
|
95
|
+
dlg = Ruber::SettingsDialog.new @cont, options, @widgets
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe 'Ruber::SettingsDialog#read_settings' do
|
|
101
|
+
|
|
102
|
+
before do
|
|
103
|
+
@mw = Qt::Widget.new
|
|
104
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).by_default.and_return @mw
|
|
105
|
+
@back = flexmock('backend'){|m| m.should_ignore_missing}
|
|
106
|
+
@cont = Object.new
|
|
107
|
+
@cont.extend Ruber::SettingsContainer
|
|
108
|
+
@cont.send :setup_container, @back
|
|
109
|
+
@widgets = [
|
|
110
|
+
OS.new({:caption => 'C1', :class_obj => Qt::CheckBox}),
|
|
111
|
+
OS.new({:caption => 'C2', :class_obj => Qt::LineEdit}),
|
|
112
|
+
OS.new({:caption => 'C2', :code => 'Qt::PushButton.new("test")'}),
|
|
113
|
+
OS.new({:caption => 'C1', :class_obj => Qt::RadioButton, :code => 'Qt::ComboBox.new'})
|
|
114
|
+
]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'should call the read_settings method of each widget which provides it' do
|
|
118
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
119
|
+
widgets = dlg.instance_variable_get(:@widgets)
|
|
120
|
+
|
|
121
|
+
widgets['C1'][0].instance_eval do
|
|
122
|
+
def read_settings
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
flexmock(widgets['C1'][0]).should_receive(:read_settings).once
|
|
126
|
+
|
|
127
|
+
widgets['C1'][1].instance_eval do
|
|
128
|
+
def read_settings
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
flexmock(widgets['C1'][1]).should_receive(:read_settings).once
|
|
132
|
+
|
|
133
|
+
widgets['C2'][0].instance_eval do
|
|
134
|
+
def read_settings
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
flexmock(widgets['C2'][0]).should_receive(:read_settings).once
|
|
138
|
+
|
|
139
|
+
dlg.read_settings
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'should call the read_settings method of the option manager' do
|
|
143
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
144
|
+
flexmock(dlg.instance_variable_get(:@manager)).should_receive(:read_settings).once
|
|
145
|
+
dlg.read_settings
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
describe 'Ruber::SettingsDialog#store_settings' do
|
|
151
|
+
|
|
152
|
+
before do
|
|
153
|
+
@mw = Qt::Widget.new
|
|
154
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).by_default.and_return @mw
|
|
155
|
+
@back = flexmock('backend'){|m| m.should_ignore_missing}
|
|
156
|
+
@cont = Object.new
|
|
157
|
+
@cont.extend Ruber::SettingsContainer
|
|
158
|
+
@cont.send :setup_container, @back
|
|
159
|
+
@widgets = [
|
|
160
|
+
OS.new({:caption => 'C1', :class_obj => Qt::CheckBox}),
|
|
161
|
+
OS.new({:caption => 'C2', :class_obj => Qt::LineEdit}),
|
|
162
|
+
OS.new({:caption => 'C2', :code => 'Qt::PushButton.new("test")'}),
|
|
163
|
+
OS.new({:caption => 'C1', :class_obj => Qt::RadioButton, :code => 'Qt::ComboBox.new'})
|
|
164
|
+
]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'should call the store_settings method of each widget which provides it' do
|
|
168
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
169
|
+
widgets = dlg.instance_variable_get(:@widgets)
|
|
170
|
+
|
|
171
|
+
widgets['C1'][0].instance_eval do
|
|
172
|
+
def store_settings
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
flexmock(widgets['C1'][0]).should_receive(:store_settings).once
|
|
176
|
+
|
|
177
|
+
widgets['C1'][1].instance_eval do
|
|
178
|
+
def store_settings
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
flexmock(widgets['C1'][1]).should_receive(:store_settings).once
|
|
182
|
+
|
|
183
|
+
widgets['C2'][0].instance_eval do
|
|
184
|
+
def store_settings
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
flexmock(widgets['C2'][0]).should_receive(:store_settings).once
|
|
188
|
+
|
|
189
|
+
dlg.store_settings
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'should call the store_settings method of the option manager' do
|
|
193
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
194
|
+
flexmock(dlg.instance_variable_get(:@manager)).should_receive(:store_settings).once
|
|
195
|
+
dlg.store_settings
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'should call the "write" method of the container, after all the store_settings methods have been called' do
|
|
199
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
200
|
+
widgets = dlg.instance_variable_get(:@widgets)
|
|
201
|
+
widgets['C1'][0].instance_eval do
|
|
202
|
+
def store_settings
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
flexmock(dlg.instance_variable_get(:@manager)).should_receive(:store_settings).once.globally.ordered
|
|
206
|
+
flexmock(widgets['C1'][0]).should_receive(:store_settings).once.globally.ordered
|
|
207
|
+
flexmock(@cont).should_receive(:write).once.globally.ordered
|
|
208
|
+
dlg.store_settings
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it 'should be called when the Ok button is clicked' do
|
|
212
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
213
|
+
flexmock(dlg).should_receive(:store_settings).once
|
|
214
|
+
dlg.instance_eval{emit okClicked}
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it 'should be called when the Apply button is clicked' do
|
|
218
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
219
|
+
flexmock(dlg).should_receive(:store_settings).once
|
|
220
|
+
dlg.instance_eval{emit applyClicked}
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe 'Ruber::SettingsDialog#read_default_settings' do
|
|
226
|
+
|
|
227
|
+
before do
|
|
228
|
+
@mw = Qt::Widget.new
|
|
229
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).by_default.and_return @mw
|
|
230
|
+
@back = flexmock('backend'){|m| m.should_ignore_missing}
|
|
231
|
+
@cont = Object.new
|
|
232
|
+
@cont.extend Ruber::SettingsContainer
|
|
233
|
+
@cont.send :setup_container, @back
|
|
234
|
+
@widgets = [
|
|
235
|
+
OS.new({:caption => 'C1', :class_obj => Qt::CheckBox}),
|
|
236
|
+
OS.new({:caption => 'C2', :class_obj => Qt::LineEdit}),
|
|
237
|
+
OS.new({:caption => 'C2', :code => 'Qt::PushButton.new("test")'}),
|
|
238
|
+
OS.new({:caption => 'C1', :class_obj => Qt::RadioButton, :code => 'Qt::ComboBox.new'})
|
|
239
|
+
]
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'should call the read_default_settings method of each widget which provides it' do
|
|
243
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
244
|
+
widgets = dlg.instance_variable_get(:@widgets)
|
|
245
|
+
|
|
246
|
+
widgets['C1'][0].instance_eval do
|
|
247
|
+
def read_default_settings
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
flexmock(widgets['C1'][0]).should_receive(:read_default_settings).once
|
|
251
|
+
|
|
252
|
+
widgets['C1'][1].instance_eval do
|
|
253
|
+
def read_default_settings
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
flexmock(widgets['C1'][1]).should_receive(:read_default_settings).once
|
|
257
|
+
|
|
258
|
+
widgets['C2'][0].instance_eval do
|
|
259
|
+
def read_default_settings
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
flexmock(widgets['C2'][0]).should_receive(:read_default_settings).once
|
|
263
|
+
|
|
264
|
+
dlg.read_default_settings
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it 'should call the read_default_settings method of the option manager' do
|
|
268
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
269
|
+
flexmock(dlg.instance_variable_get(:@manager)).should_receive(:read_default_settings).once
|
|
270
|
+
dlg.read_default_settings
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it 'should be called when the Default button is clicked' do
|
|
274
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
275
|
+
flexmock(dlg).should_receive(:read_default_settings).once
|
|
276
|
+
dlg.instance_eval{emit defaultClicked}
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
describe 'Ruber::SettingsDialog#exec' do
|
|
282
|
+
|
|
283
|
+
before(:all) do
|
|
284
|
+
class ::KDE::PageDialog
|
|
285
|
+
def exec
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
after(:all) do
|
|
291
|
+
class ::KDE::PageDialog
|
|
292
|
+
undef_method :exec
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
before do
|
|
297
|
+
@mw = Qt::Widget.new
|
|
298
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).by_default.and_return @mw
|
|
299
|
+
@back = flexmock('backend'){|m| m.should_ignore_missing}
|
|
300
|
+
@cont = Object.new
|
|
301
|
+
@cont.extend Ruber::SettingsContainer
|
|
302
|
+
@cont.send :setup_container, @back
|
|
303
|
+
@widgets = [
|
|
304
|
+
OS.new({:caption => 'C1', :class_obj => Qt::CheckBox}),
|
|
305
|
+
OS.new({:caption => 'C2', :class_obj => Qt::LineEdit}),
|
|
306
|
+
OS.new({:caption => 'C2', :code => 'Qt::PushButton.new("test")'}),
|
|
307
|
+
OS.new({:caption => 'C1', :class_obj => Qt::RadioButton, :code => 'Qt::ComboBox.new'})
|
|
308
|
+
]
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it 'should call the read_settings method' do
|
|
312
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
313
|
+
flexmock(dlg).should_receive(:read_settings).once
|
|
314
|
+
dlg.exec
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
it 'should make the first page current' do
|
|
318
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
319
|
+
# It seems that comparing the objects themselves doesn't work, as they seem to
|
|
320
|
+
# have different object_id s. To avoid problems, we give a name to each
|
|
321
|
+
dlg.instance_variable_get(:@page_items).each_with_index{|w, i| w.object_name = i.to_s}
|
|
322
|
+
dlg.current_page = dlg.instance_variable_get(:@page_items)[1]
|
|
323
|
+
dlg.exec
|
|
324
|
+
dlg.current_page.object_name.should == '0'
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
it 'should give focus to the first widget in the page' do
|
|
328
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
329
|
+
flexmock(dlg.instance_variable_get(:@widgets)['C1'][0]).should_receive(:set_focus).once
|
|
330
|
+
dlg.exec
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it 'shouldn\'t attempt to make the first page current if there are no pages' do
|
|
334
|
+
dlg = Ruber::SettingsDialog.new @cont, [], []
|
|
335
|
+
lambda{dlg.exec}.should_not raise_error
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
describe 'Ruber::SettingsDialog#show' do
|
|
341
|
+
|
|
342
|
+
before(:all) do
|
|
343
|
+
class ::KDE::PageDialog
|
|
344
|
+
def show
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
after(:all) do
|
|
350
|
+
class ::KDE::PageDialog
|
|
351
|
+
undef_method :show
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
before do
|
|
356
|
+
@mw = Qt::Widget.new
|
|
357
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).by_default.and_return @mw
|
|
358
|
+
@back = flexmock('backend'){|m| m.should_ignore_missing}
|
|
359
|
+
@cont = Object.new
|
|
360
|
+
@cont.extend Ruber::SettingsContainer
|
|
361
|
+
@cont.send :setup_container, @back
|
|
362
|
+
@widgets = [
|
|
363
|
+
OS.new({:caption => 'C1', :class_obj => Qt::CheckBox}),
|
|
364
|
+
OS.new({:caption => 'C2', :class_obj => Qt::LineEdit}),
|
|
365
|
+
OS.new({:caption => 'C2', :code => 'Qt::PushButton.new("test")'}),
|
|
366
|
+
OS.new({:caption => 'C1', :class_obj => Qt::RadioButton, :code => 'Qt::ComboBox.new'})
|
|
367
|
+
]
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
it 'should call the read_settings method' do
|
|
371
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
372
|
+
flexmock(dlg).should_receive(:read_settings).once
|
|
373
|
+
dlg.show
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
it 'should make the first page current' do
|
|
377
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
378
|
+
# It seems that comparing the objects themselves doesn't work, as they seem to
|
|
379
|
+
# have different object_id s. To avoid problems, we give a name to each
|
|
380
|
+
dlg.instance_variable_get(:@page_items).each_with_index{|w, i| w.object_name = i.to_s}
|
|
381
|
+
dlg.current_page = dlg.instance_variable_get(:@page_items)[1]
|
|
382
|
+
dlg.show
|
|
383
|
+
dlg.current_page.object_name.should == '0'
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
it 'should give focus to the first widget in the page' do
|
|
387
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
388
|
+
flexmock(dlg.instance_variable_get(:@widgets)['C1'][0]).should_receive(:set_focus).once
|
|
389
|
+
dlg.show
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
describe 'SettingsDialog#widgets' do
|
|
395
|
+
|
|
396
|
+
it 'should return an array containing all the added widgets' do
|
|
397
|
+
@mw = Qt::Widget.new
|
|
398
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).by_default.and_return @mw
|
|
399
|
+
@back = flexmock('backend'){|m| m.should_ignore_missing}
|
|
400
|
+
@cont = Object.new
|
|
401
|
+
@cont.extend Ruber::SettingsContainer
|
|
402
|
+
@cont.send :setup_container, @back
|
|
403
|
+
@widgets = [
|
|
404
|
+
OS.new({:caption => 'C1', :class_obj => Qt::CheckBox}),
|
|
405
|
+
OS.new({:caption => 'C2', :class_obj => Qt::LineEdit}),
|
|
406
|
+
OS.new({:caption => 'C2', :code => 'Qt::PushButton.new("test")'}),
|
|
407
|
+
OS.new({:caption => 'C1', :class_obj => Qt::RadioButton, :code => 'Qt::ComboBox.new'})
|
|
408
|
+
]
|
|
409
|
+
dlg = Ruber::SettingsDialog.new @cont, [], @widgets
|
|
410
|
+
res = dlg.widgets
|
|
411
|
+
internal = dlg.instance_variable_get(:@widgets)
|
|
412
|
+
res.size.should == 4
|
|
413
|
+
res.should include(internal['C1'][0])
|
|
414
|
+
res.should include(internal['C1'][1])
|
|
415
|
+
res.should include(internal['C2'][0])
|
|
416
|
+
res.should include(internal['C2'][1])
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
end
|
data/spec/state_spec.rb
ADDED
|
@@ -0,0 +1,991 @@
|
|
|
1
|
+
require 'spec/common'
|
|
2
|
+
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
require 'ruber/plugin_specification'
|
|
7
|
+
require 'ruber/editor/document'
|
|
8
|
+
|
|
9
|
+
require 'plugins/state/state'
|
|
10
|
+
|
|
11
|
+
describe Ruber::State::Plugin do
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
#Needed because the Qt::Object connect method doesn't like @components not being a
|
|
15
|
+
#Qt::Object
|
|
16
|
+
class Ruber::State::Plugin
|
|
17
|
+
def connect *args
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
@components = flexmock('components'){|m| m.should_ignore_missing}
|
|
21
|
+
@config = flexmock('config'){|m| m.should_ignore_missing}
|
|
22
|
+
flexmock(Ruber).should_receive(:[]).with(:components).and_return(@components).by_default
|
|
23
|
+
flexmock(Ruber).should_receive(:[]).with(:app).and_return(KDE::Application.instance).by_default
|
|
24
|
+
flexmock(Ruber).should_receive(:[]).with(:config).and_return(@config).by_default
|
|
25
|
+
pdf = Ruber::PluginSpecification.full :name => :state
|
|
26
|
+
@plug = Ruber::State::Plugin.new pdf
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
after do
|
|
30
|
+
class Ruber::State::Plugin
|
|
31
|
+
remove_method :connect rescue nil
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'inherits Ruber::Plugin' do
|
|
36
|
+
Ruber::State::Plugin.ancestors.should include(Ruber::Plugin)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe '#when created' do
|
|
40
|
+
|
|
41
|
+
it 'sets the @force_restore_project_files instance variable to nil' do
|
|
42
|
+
@plug.instance_variables.should include(:@force_restore_project_files)
|
|
43
|
+
@plug.instance_variable_get(:@force_restore_project_files).should be_nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'sets the @force_restore_cursor_position instance variable to nil' do
|
|
47
|
+
@plug.instance_variables.should include(:@force_restore_cursor_position)
|
|
48
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should be_nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe '#delayed_initialize' do
|
|
54
|
+
|
|
55
|
+
before do
|
|
56
|
+
@documents = flexmock('documents')
|
|
57
|
+
@projects = flexmock('projects')
|
|
58
|
+
flexmock(KDE::Application.instance).should_receive(:starting?).and_return(true).by_default
|
|
59
|
+
flexmock(Ruber).should_receive(:[]).with(:docs).and_return(@documents).by_default
|
|
60
|
+
flexmock(Ruber).should_receive(:[]).with(:projects).and_return(@projects).by_default
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'calls the restore_last_state method if there\'s no open project and the only open document is pristine' do
|
|
64
|
+
doc = flexmock('doc', :pristine? => true)
|
|
65
|
+
@documents.should_receive(:to_a).once.and_return [doc]
|
|
66
|
+
@documents.should_receive(:[]).with(0).once.and_return doc
|
|
67
|
+
@projects.should_receive(:to_a).once.and_return []
|
|
68
|
+
flexmock(@plug).should_receive(:restore_last_state).once
|
|
69
|
+
@plug.send :delayed_initialize
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'doesn\'t call the restore_last_state method if there are open projects' do
|
|
73
|
+
prj = flexmock('project')
|
|
74
|
+
@projects.should_receive(:to_a).once.and_return [prj]
|
|
75
|
+
flexmock(@plug).should_receive(:restore_last_state).never
|
|
76
|
+
@plug.send :delayed_initialize
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'doesn\'t call the restore_last_state method if there is more than one open document' do
|
|
80
|
+
@documents.should_receive(:to_a).once.and_return 2.times.map{flexmock}
|
|
81
|
+
@projects.should_receive(:to_a).once.and_return []
|
|
82
|
+
flexmock(@plug).should_receive(:restore_last_state).never
|
|
83
|
+
@plug.send :delayed_initialize
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'doesn\'t call the restore_last_state method if there aren\'t open documents' do
|
|
87
|
+
@documents.should_receive(:to_a).once.and_return []
|
|
88
|
+
@projects.should_receive(:to_a).once.and_return []
|
|
89
|
+
flexmock(@plug).should_receive(:restore_last_state).never
|
|
90
|
+
@plug.send :delayed_initialize
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'doesn\'t call the restore_last_state method if the only open document isn\'t pristine' do
|
|
94
|
+
doc = flexmock('doc', :pristine? => false)
|
|
95
|
+
@documents.should_receive(:to_a).once.and_return [doc]
|
|
96
|
+
@documents.should_receive(:[]).with(0).once.and_return doc
|
|
97
|
+
@projects.should_receive(:to_a).once.and_return []
|
|
98
|
+
flexmock(@plug).should_receive(:restore_last_state).never
|
|
99
|
+
@plug.send :delayed_initialize
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'does nothing if the application is already running' do
|
|
103
|
+
doc = flexmock('doc', :pristine? => true)
|
|
104
|
+
@documents.should_receive(:to_a).and_return [doc]
|
|
105
|
+
@documents.should_receive(:[]).with(0).and_return doc
|
|
106
|
+
@projects.should_receive(:to_a).and_return []
|
|
107
|
+
flexmock(KDE::Application.instance).should_receive(:starting?).and_return false
|
|
108
|
+
flexmock(@plug).should_receive(:restore_last_state).never
|
|
109
|
+
@plug.send :delayed_initialize
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe '#gather_settings' do
|
|
115
|
+
|
|
116
|
+
before do
|
|
117
|
+
@projects = flexmock('projects') do |m|
|
|
118
|
+
m.should_receive(:projects).and_return([]).by_default
|
|
119
|
+
m.should_receive(:current).and_return(nil).by_default
|
|
120
|
+
end
|
|
121
|
+
@documents = flexmock('documents') do |m|
|
|
122
|
+
m.should_receive(:documents).and_return([]).by_default
|
|
123
|
+
m.should_receive(:current).and_return(nil).by_default
|
|
124
|
+
end
|
|
125
|
+
@mw = flexmock('main window'){|m| m.should_ignore_missing}
|
|
126
|
+
flexmock(Ruber).should_receive(:[]).with(:projects).and_return(@projects).by_default
|
|
127
|
+
flexmock(Ruber).should_receive(:[]).with(:docs).and_return(@documents).by_default
|
|
128
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@mw).by_default
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'stores a list with the project file of each open project under the :open_projects key' do
|
|
132
|
+
prjs = 5.times.map{|i| flexmock(i.to_s){|m| m.should_receive(:project_file).and_return i.to_s}}
|
|
133
|
+
@projects.should_receive(:projects).once.and_return(prjs)
|
|
134
|
+
@projects.should_receive(:current).once.and_return(nil)
|
|
135
|
+
@plug.send(:gather_settings).should have_entries(:open_projects => (0...5).map(&:to_s))
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'puts the file corresponding to the open project at the beginning of the :open_projects entry' do
|
|
139
|
+
prjs = 5.times.map{|i| flexmock(i.to_s, :project_file => i.to_s)}
|
|
140
|
+
@projects.should_receive(:projects).once.and_return(prjs)
|
|
141
|
+
@projects.should_receive(:current).once.and_return prjs[2]
|
|
142
|
+
@plug.send(:gather_settings).should have_entries(:open_projects => %w[2 0 1 3 4])
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it 'stores the project files in an arbitrary order if there\'s no active project' do
|
|
146
|
+
prjs = 5.times.map{|i| flexmock(i.to_s){|m| m.should_receive(:project_file).and_return i.to_s}}
|
|
147
|
+
@projects.should_receive(:projects).once.and_return(prjs)
|
|
148
|
+
@projects.should_receive(:current).once.and_return nil
|
|
149
|
+
@plug.send(:gather_settings).should have_entries(:open_projects => (0...5).map(&:to_s))
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'stores an empty array under the :open_projects key if there are no open projects' do
|
|
153
|
+
@plug.send(:gather_settings).should have_entries(:open_projects => [])
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it 'stores a list of the paths of the files associated with all open documents under the :open_files key' do
|
|
157
|
+
docs = 5.times.map{|i| flexmock(i.to_s){|m| m.should_receive(:path).and_return i.to_s}}
|
|
158
|
+
@documents.should_receive(:documents).once.and_return(docs)
|
|
159
|
+
@plug.send(:gather_settings).should have_entries(:open_documents => (0...5).map(&:to_s))
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it 'ignores documents which aren\'t associated with a file' do
|
|
163
|
+
docs = 5.times.map do |i|
|
|
164
|
+
flexmock(i.to_s) do |m|
|
|
165
|
+
m.should_receive(:path).and_return(i % 2 == 0 ? i.to_s : '')
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
@documents.should_receive(:documents).once.and_return(docs)
|
|
169
|
+
@plug.send(:gather_settings).should have_entries(:open_documents => %w[0 2 4])
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it 'stores an empty array under the :open_files key if there are no open documents or if no open document is associated with a file' do
|
|
173
|
+
docs = 5.times.map{flexmock(:path => '')}
|
|
174
|
+
@documents.should_receive(:documents).once.and_return(docs).once
|
|
175
|
+
@documents.should_receive(:documents).once.and_return([]).once
|
|
176
|
+
@plug.send(:gather_settings).should have_entries(:open_documents => [])
|
|
177
|
+
@plug.send(:gather_settings).should have_entries(:open_documents => [])
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it 'stores the path of the active document under the :active_document key' do
|
|
181
|
+
docs = 5.times.map{|i| flexmock(i.to_s){|m| m.should_receive(:path).and_return i.to_s}}
|
|
182
|
+
@documents.should_receive(:documents).once.and_return(docs)
|
|
183
|
+
@mw.should_receive(:current_document).once.and_return(docs[1])
|
|
184
|
+
@plug.send(:gather_settings).should have_entries(:active_document => "1")
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it 'stores nil under the :active_document key if there\'s no current document' do
|
|
188
|
+
@mw.should_receive(:current_document).once.and_return nil
|
|
189
|
+
@plug.send(:gather_settings).should have_entries(:active_document => nil)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'stores nil under the :active_document key if the current document isn\'t associated with a file' do
|
|
193
|
+
doc = flexmock('doc', :path => '')
|
|
194
|
+
@mw.should_receive(:current_document).once.and_return doc
|
|
195
|
+
@plug.send(:gather_settings).should have_entries(:active_document => nil)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
describe '#save_settings' do
|
|
201
|
+
|
|
202
|
+
it 'stores the value corresponding to the :open_projects key in the hash returned by gather_settings in the state/open_projects setting' do
|
|
203
|
+
flexmock(@plug).should_receive(:gather_settings).once.and_return(:open_projects => %w[x y z])
|
|
204
|
+
@config.should_receive(:[]=).with(:state, :open_projects, %w[x y z]).once
|
|
205
|
+
@config.should_receive(:[]=)
|
|
206
|
+
@plug.save_settings
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it 'stores the value corresponding to the :open_documents key in the hash returned by gather_settings in the state/open_documents setting' do
|
|
210
|
+
flexmock(@plug).should_receive(:gather_settings).once.and_return(:open_documents => %w[x y z])
|
|
211
|
+
@config.should_receive(:[]=).with(:state, :open_documents, %w[x y z]).once
|
|
212
|
+
@config.should_receive(:[]=)
|
|
213
|
+
@plug.save_settings
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it 'stores the value corresponding to the :active_document key in the hash returned by gather_settings in the state/active_document setting' do
|
|
217
|
+
flexmock(@plug).should_receive(:gather_settings).once.and_return(:active_document => 'x')
|
|
218
|
+
@config.should_receive(:[]=).with(:state, :active_document, 'x').once
|
|
219
|
+
@config.should_receive(:[]=)
|
|
220
|
+
@plug.save_settings
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe '#restore_cursor_position?' do
|
|
226
|
+
|
|
227
|
+
it 'returns the value of the state/restore_cursor_position config entry if the @force_restore_cursor_position instance variable is nil' do
|
|
228
|
+
@config.should_receive(:[]).with(:state, :restore_cursor_position).once.and_return(true)
|
|
229
|
+
@config.should_receive(:[]).with(:state, :restore_cursor_position).once.and_return(false)
|
|
230
|
+
@plug.instance_variable_set :@force_restore_cursor_position, nil
|
|
231
|
+
@plug.restore_cursor_position?.should == true
|
|
232
|
+
@plug.restore_cursor_position?.should == false
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it 'returns the value of the @force_restore_cursor_position instance variable if it is not nil' do
|
|
236
|
+
@config.should_receive(:[]).with(:state, :restore_cursor_position).never
|
|
237
|
+
@plug.instance_variable_set :@force_restore_cursor_position, true
|
|
238
|
+
@plug.restore_cursor_position?.should == true
|
|
239
|
+
@plug.instance_variable_set :@force_restore_cursor_position, false
|
|
240
|
+
@plug.restore_cursor_position?.should == false
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
describe '#restore_project_files?' do
|
|
246
|
+
|
|
247
|
+
it 'returns the value of the state/restore_project_files config entry if the @force_restore_project_files instance variable is nil' do
|
|
248
|
+
@config.should_receive(:[]).with(:state, :restore_project_files).once.and_return(true)
|
|
249
|
+
@config.should_receive(:[]).with(:state, :restore_project_files).once.and_return(false)
|
|
250
|
+
@plug.instance_variable_set :@force_restore_project_files, nil
|
|
251
|
+
@plug.restore_project_files?.should == true
|
|
252
|
+
@plug.restore_project_files?.should == false
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it 'returns the value of the @force_restore_project_files instance variable if it is not nil' do
|
|
256
|
+
@config.should_receive(:[]).with(:state, :restore_project_files).never
|
|
257
|
+
@plug.instance_variable_set :@force_restore_project_files, true
|
|
258
|
+
@plug.restore_project_files?.should == true
|
|
259
|
+
@plug.instance_variable_set :@force_restore_project_files, false
|
|
260
|
+
@plug.restore_project_files?.should == false
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
describe 'session_data' do
|
|
266
|
+
|
|
267
|
+
it 'returns a hash containing the hash returned by the gather_settings method under the "State" key' do
|
|
268
|
+
hash = {
|
|
269
|
+
:open_projects => %w[a b c],
|
|
270
|
+
:open_documents => %w[x y z],
|
|
271
|
+
:active_document => 'z'
|
|
272
|
+
}
|
|
273
|
+
flexmock(@plug).should_receive(:gather_settings).once.and_return hash
|
|
274
|
+
res = @plug.session_data
|
|
275
|
+
res['State'].should == hash
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
describe '#restore_session' do
|
|
281
|
+
|
|
282
|
+
it 'calls restore from within a with block with :restore_cursor_position and :restore_project_files set to true passing the hash contained in the State entry of the argument' do
|
|
283
|
+
hash = {
|
|
284
|
+
'State' => {
|
|
285
|
+
:open_projects => %w[a b c],
|
|
286
|
+
:open_documents => %w[x y z],
|
|
287
|
+
:active_document => 'z'
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
exp_hash = {
|
|
291
|
+
[:state, :open_projects] => %w[a b c],
|
|
292
|
+
[:state, :open_documents] => %w[x y z],
|
|
293
|
+
[:state, :active_document] => 'z'
|
|
294
|
+
}
|
|
295
|
+
default = {:open_projects => [], :open_documents => [], :active_document => nil}
|
|
296
|
+
flexmock(@plug).should_receive(:with).with({:restore_cursor_position => true, :restore_project_files => true, :force => true}, FlexMock.on{|a| a.call || a.is_a?(Proc)}).once
|
|
297
|
+
flexmock(@plug).should_receive(:restore).with(FlexMock.on{|a| a == exp_hash and a[:state, :open_projects] == %w[a b c]}).once
|
|
298
|
+
@plug.restore_session hash
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
describe '#with' do
|
|
304
|
+
|
|
305
|
+
describe ', when the @force_restore_cursor_position instance variable is nil' do
|
|
306
|
+
|
|
307
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to the :restore_cursor_position entry if the entry is a true value' do
|
|
308
|
+
restore_doc = nil
|
|
309
|
+
@plug.with(:restore_cursor_position => 'x'){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
310
|
+
restore_doc.should == 'x'
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to false if the :restore_cursor_position entry is given and is a false value' do
|
|
314
|
+
restore_doc = nil
|
|
315
|
+
@plug.with(:restore_cursor_position => false){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
316
|
+
restore_doc.should == false
|
|
317
|
+
restore_doc = nil
|
|
318
|
+
@plug.instance_variable_set :@force_restore_cursor_position, nil
|
|
319
|
+
@plug.with(:restore_cursor_position => nil){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
320
|
+
restore_doc.should == false
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it 'calls the block without changing the @force_restore_cursor_position instance variable if the :restore_cursor_position entry isn\'t given' do
|
|
324
|
+
restore_doc = true
|
|
325
|
+
@plug.with({}){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
326
|
+
restore_doc.should be_nil
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
it 'sets the @force_restore_cursor_position back to nil after executing the block, even if the block raises an exception' do
|
|
330
|
+
@plug.with(:restore_cursor_position => true){@plug.instance_variable_get(:@force_restore_cursor_position).should be_true}
|
|
331
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should be_nil
|
|
332
|
+
@plug.with(:restore_cursor_position => false){@plug.instance_variable_get(:@force_restore_cursor_position).should == false}
|
|
333
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should be_nil
|
|
334
|
+
begin @plug.with(:restore_cursor_position => true){raise Exception}
|
|
335
|
+
rescue Exception
|
|
336
|
+
end
|
|
337
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should be_nil
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
describe ', when the @force_restore_cursor_position instance variable is not nil' do
|
|
343
|
+
|
|
344
|
+
describe ' and the :force entry isn\'t true' do
|
|
345
|
+
|
|
346
|
+
it 'calls the block without changing the value of the @force_restore_cursor_position instance variable' do
|
|
347
|
+
restore = nil
|
|
348
|
+
@plug.instance_variable_set(:@force_restore_cursor_position, 'x')
|
|
349
|
+
@plug.with(:restore_cursor_position => 'y'){restore = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
350
|
+
restore.should == 'x'
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
describe ' and the :force entry is true' do
|
|
356
|
+
|
|
357
|
+
before do
|
|
358
|
+
@plug.instance_variable_set :@force_restore_cursor_position, 'y'
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to the :restore_cursor_position entry if the entry is a true value' do
|
|
362
|
+
restore_doc = nil
|
|
363
|
+
@plug.with(:restore_cursor_position => 'x', :force => true){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
364
|
+
restore_doc.should == 'x'
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to false if the :restore_cursor_position entry is given and is a false value' do
|
|
368
|
+
restore_doc = nil
|
|
369
|
+
@plug.with(:restore_cursor_position => false, :force => true){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
370
|
+
restore_doc.should == false
|
|
371
|
+
restore_doc = nil
|
|
372
|
+
@plug.instance_variable_set :@force_restore_cursor_position, nil
|
|
373
|
+
@plug.with(:restore_cursor_position => nil, :force => true){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
374
|
+
restore_doc.should == false
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
it 'calls the block without changing the @force_restore_cursor_position instance variable if the :restore_cursor_position entry isn\'t given' do
|
|
378
|
+
restore_doc = true
|
|
379
|
+
@plug.with({:force => true}){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
380
|
+
restore_doc.should == 'y'
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
it 'sets the @force_restore_cursor_position back to the original value after executing the block, even if the block raises an exception' do
|
|
384
|
+
@plug.with(:restore_cursor_position => true, :force => true){@plug.instance_variable_get(:@force_restore_cursor_position).should be_true}
|
|
385
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should == 'y'
|
|
386
|
+
@plug.with(:restore_cursor_position => false, :force => true){@plug.instance_variable_get(:@force_restore_cursor_position).should == false}
|
|
387
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should == 'y'
|
|
388
|
+
begin @plug.with(:restore_cursor_position => true, :force => true){raise Exception}
|
|
389
|
+
rescue Exception
|
|
390
|
+
end
|
|
391
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should == 'y'
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
describe ', when the @force_restore_cursor_position instance variable is nil' do
|
|
399
|
+
|
|
400
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to the :restore_cursor_position entry if the entry is a true value' do
|
|
401
|
+
restore_doc = nil
|
|
402
|
+
@plug.with(:restore_cursor_position => 'x'){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
403
|
+
restore_doc.should == 'x'
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to false if the :restore_cursor_position entry is given and is a false value' do
|
|
407
|
+
restore_doc = nil
|
|
408
|
+
@plug.with(:restore_cursor_position => false){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
409
|
+
restore_doc.should == false
|
|
410
|
+
restore_doc = nil
|
|
411
|
+
@plug.instance_variable_set :@force_restore_cursor_position, nil
|
|
412
|
+
@plug.with(:restore_cursor_position => nil){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
413
|
+
restore_doc.should == false
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
it 'calls the block without changing the @force_restore_cursor_position instance variable if the :restore_cursor_position entry isn\'t given' do
|
|
417
|
+
restore_doc = true
|
|
418
|
+
@plug.with({}){restore_doc = @plug.instance_variable_get(:@force_restore_cursor_position)}
|
|
419
|
+
restore_doc.should be_nil
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
it 'sets the @force_restore_cursor_position back to nil after executing the block, even if the block raises an exception' do
|
|
423
|
+
@plug.with(:restore_cursor_position => true){@plug.instance_variable_get(:@force_restore_cursor_position).should be_true}
|
|
424
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should be_nil
|
|
425
|
+
@plug.with(:restore_cursor_position => false){@plug.instance_variable_get(:@force_restore_cursor_position).should == false}
|
|
426
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should be_nil
|
|
427
|
+
begin @plug.with(:restore_cursor_position => true){raise Exception}
|
|
428
|
+
rescue Exception
|
|
429
|
+
end
|
|
430
|
+
@plug.instance_variable_get(:@force_restore_cursor_position).should be_nil
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
describe ', when the @force_restore_project_files instance variable is not nil' do
|
|
436
|
+
|
|
437
|
+
describe ' and the :force entry isn\'t true' do
|
|
438
|
+
|
|
439
|
+
it 'calls the block without changing the value of the @force_restore_project_files instance variable' do
|
|
440
|
+
restore = nil
|
|
441
|
+
@plug.instance_variable_set(:@force_restore_project_files, 'x')
|
|
442
|
+
@plug.with(:restore_project_files => 'y'){restore = @plug.instance_variable_get(:@force_restore_project_files)}
|
|
443
|
+
restore.should == 'x'
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
describe ' and the :force entry is true' do
|
|
449
|
+
|
|
450
|
+
before do
|
|
451
|
+
@plug.instance_variable_set :@force_restore_project_files, 'y'
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to the :restore_project_files entry if the entry is a true value' do
|
|
455
|
+
restore_prj = nil
|
|
456
|
+
@plug.with(:restore_project_files => 'x', :force => true){restore_prj = @plug.instance_variable_get(:@force_restore_project_files)}
|
|
457
|
+
restore_prj.should == 'x'
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
it 'calls the given block after setting the @force_restore_project_files instance variable to false if the :restore_project_files entry is given and is a false value' do
|
|
461
|
+
restore_prj = nil
|
|
462
|
+
@plug.with(:restore_project_files => false, :force => true){restore_prj = @plug.instance_variable_get(:@force_restore_project_files)}
|
|
463
|
+
restore_prj.should == false
|
|
464
|
+
restore_prj = nil
|
|
465
|
+
@plug.instance_variable_set :@force_restore_project_files, nil
|
|
466
|
+
@plug.with(:restore_project_files => nil, :force => true){restore_prj = @plug.instance_variable_get(:@force_restore_project_files)}
|
|
467
|
+
restore_prj.should == false
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
it 'calls the block without changing the @force_restore_project_files instance variable if the :restore_project_files entry isn\'t given' do
|
|
471
|
+
restore_prj = true
|
|
472
|
+
@plug.with({:force => true}){restore_prj = @plug.instance_variable_get(:@force_restore_project_files)}
|
|
473
|
+
restore_prj.should == 'y'
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
it 'sets the @force_restore_project_files back to the original value after executing the block, even if the block raises an exception' do
|
|
477
|
+
@plug.with(:restore_project_files => true, :force => true){@plug.instance_variable_get(:@force_restore_project_files).should be_true}
|
|
478
|
+
@plug.instance_variable_get(:@force_restore_project_files).should == 'y'
|
|
479
|
+
@plug.with(:restore_project_files => false, :force => true){@plug.instance_variable_get(:@force_restore_project_files).should == false}
|
|
480
|
+
@plug.instance_variable_get(:@force_restore_project_files).should == 'y'
|
|
481
|
+
begin @plug.with(:restore_project_files => true, :force => true){raise Exception}
|
|
482
|
+
rescue Exception
|
|
483
|
+
end
|
|
484
|
+
@plug.instance_variable_get(:@force_restore_project_files).should == 'y'
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
describe '#restore_document' do
|
|
494
|
+
|
|
495
|
+
it 'calls the document\'s state extension\'s restore method' do
|
|
496
|
+
ext = flexmock('extension'){|m| m.should_receive(:restore).once}
|
|
497
|
+
doc = flexmock('doc'){|m| m.should_receive(:extension).once.with(:state).and_return ext}
|
|
498
|
+
@plug.restore_document doc
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
describe '#restore_project' do
|
|
504
|
+
|
|
505
|
+
it 'calls the project\'s state extension\'s restore method' do
|
|
506
|
+
ext = flexmock('extension'){|m| m.should_receive(:restore).once}
|
|
507
|
+
prj = flexmock('prj'){|m| m.should_receive(:extension).once.with(:state).and_return ext}
|
|
508
|
+
@plug.restore_project prj
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
describe '#restore_projects' do
|
|
514
|
+
|
|
515
|
+
before do
|
|
516
|
+
@projects = flexmock('projects'){|m| m.should_ignore_missing}
|
|
517
|
+
flexmock(Ruber).should_receive(:[]).with(:projects).and_return(@projects).by_default
|
|
518
|
+
@mw = flexmock{|m| m.should_ignore_missing}
|
|
519
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@mw).by_default
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
it 'closes all projects' do
|
|
523
|
+
prjs = 3.times.map{|i| flexmock(i.to_s)}
|
|
524
|
+
prjs.each{|pr| @projects.should_receive(:close_project).with(pr).once}
|
|
525
|
+
@projects.should_receive(:to_a).once.and_return(prjs)
|
|
526
|
+
@plug.restore_projects
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
it 'uses the safe_open_project method of the main window to open the first entry of the state/open_projects setting' do
|
|
530
|
+
@config.should_receive(:[]).with(:state, :open_projects).once.and_return %w[/x/y/z.ruprj /a/b/c.ruprj]
|
|
531
|
+
prj = flexmock('project')
|
|
532
|
+
@mw.should_receive(:safe_open_project).once.with('/x/y/z.ruprj').and_return prj
|
|
533
|
+
@plug.restore_projects
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
it 'activates the project returned by safe_open_project' do
|
|
537
|
+
@config.should_receive(:[]).with(:state, :open_projects).once.and_return %w[/x/y/z.ruprj /a/b/c.ruprj]
|
|
538
|
+
prj = flexmock('project')
|
|
539
|
+
@mw.should_receive(:safe_open_project).once.with('/x/y/z.ruprj').and_return prj
|
|
540
|
+
@projects.should_receive(:current_project=).once.with(prj)
|
|
541
|
+
@plug.restore_projects
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
it 'doesn\'t attempt to activate the project if safe_open_project returned nil' do
|
|
545
|
+
@config.should_receive(:[]).with(:state, :open_projects).once.and_return %w[/x/y/z.ruprj /a/b/c.ruprj]
|
|
546
|
+
prj = flexmock('project')
|
|
547
|
+
@mw.should_receive(:safe_open_project).once.with('/x/y/z.ruprj').and_return nil
|
|
548
|
+
@projects.should_receive(:current_project=).never
|
|
549
|
+
lambda{@plug.restore_projects}.should_not raise_error
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
it 'does nothing if the state/open_projects setting is empty' do
|
|
553
|
+
@config.should_receive(:[]).with(:state, :open_projects).once.and_return []
|
|
554
|
+
prj = flexmock('project')
|
|
555
|
+
@projects.should_receive(:project).never
|
|
556
|
+
@projects.should_receive(:current_project=).never
|
|
557
|
+
@plug.restore_projects
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
it 'reads the settings from the argument, if given, rather than from the config object' do
|
|
561
|
+
@config.should_receive(:[]).never
|
|
562
|
+
h = {[:state, :open_projects] => ['/x/y/z.ruprj']}
|
|
563
|
+
def h.[] group, name
|
|
564
|
+
super [group, name]
|
|
565
|
+
end
|
|
566
|
+
prj = flexmock('project')
|
|
567
|
+
@mw.should_receive(:safe_open_project).once.with('/x/y/z.ruprj').and_return prj
|
|
568
|
+
@projects.should_receive(:current_project=).once.with(prj)
|
|
569
|
+
@plug.restore_projects h
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
describe '#restore_documents' do
|
|
575
|
+
|
|
576
|
+
before do
|
|
577
|
+
@mw = flexmock('main window'){|m| m.should_ignore_missing}
|
|
578
|
+
@docs = flexmock('documents'){|m| m.should_ignore_missing}
|
|
579
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@mw).by_default
|
|
580
|
+
flexmock(Ruber).should_receive(:[]).with(:docs).and_return(@docs).by_default
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
it 'closes all open documents' do
|
|
584
|
+
@docs.should_receive(:close_all).once
|
|
585
|
+
@plug.restore_documents
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
it 'creates a new document for each entry in the state/open_documents from within a block passed to the main window\'s without_activating method' do
|
|
589
|
+
files = %w[/x/y/f1.rb /a/b/f2.rb /f3.rb]
|
|
590
|
+
@config.should_receive(:[]).with(:state, :open_documents).once.and_return files
|
|
591
|
+
@config.should_receive(:[]).with(:state, :active_document)
|
|
592
|
+
files.each{|f| @mw.should_receive(:editor_for!).once.with(f).ordered}
|
|
593
|
+
@mw.should_receive(:without_activating).once.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
594
|
+
@plug.restore_documents
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
it 'activates the document corresponding to the file specified in the state/active_document setting' do
|
|
598
|
+
files = %w[/x/y/f1.rb /a/b/f2.rb /f3.rb]
|
|
599
|
+
@config.should_receive(:[]).with(:state, :open_documents).once.and_return files
|
|
600
|
+
@config.should_receive(:[]).with(:state, :active_document).once.and_return files[1]
|
|
601
|
+
3.times{|i| @mw.should_receive(:editor_for!).once.with(files[i])}
|
|
602
|
+
@mw.should_receive(:display_document).once.with(files[1])
|
|
603
|
+
@mw.should_receive(:without_activating).once.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
604
|
+
@plug.restore_documents
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
it 'it activates the last document if the state/active_document setting is nil or if it doesn\'t correspond to an existing document' do
|
|
608
|
+
files = %w[/x/y/f1.rb /a/b/f2.rb /f3.rb]
|
|
609
|
+
@config.should_receive(:[]).with(:state, :open_documents).twice.and_return files
|
|
610
|
+
@config.should_receive(:[]).with(:state, :active_document).once.and_return nil
|
|
611
|
+
@config.should_receive(:[]).with(:state, :active_document).once.and_return random_string
|
|
612
|
+
@mw.should_receive(:display_document).twice.with(files[-1])
|
|
613
|
+
@mw.should_receive(:without_activating).twice.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
614
|
+
@plug.restore_documents
|
|
615
|
+
@plug.restore_documents
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
it 'does nothing if the state/open_files entry is empty' do
|
|
619
|
+
@config.should_receive(:[]).with(:state, :open_documents).once.and_return []
|
|
620
|
+
lambda{@plug.restore_documents}.should_not raise_error
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
it 'reads the settings from the argument, if given, rather than from the config object' do
|
|
624
|
+
@config.should_receive(:[]).never
|
|
625
|
+
files = %w[/x/y/f1.rb /a/b/f2.rb /f3.rb]
|
|
626
|
+
files.each{|f| @mw.should_receive(:editor_for!).once.with(f).ordered}
|
|
627
|
+
@mw.should_receive(:without_activating).once.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
628
|
+
h = {[:state, :open_documents] => files, [:state, :active_document] => nil}
|
|
629
|
+
def h.[] group, name
|
|
630
|
+
super [group, name]
|
|
631
|
+
end
|
|
632
|
+
@plug.restore_documents h
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
describe 'restore' do
|
|
638
|
+
|
|
639
|
+
it 'calls the restore_projects method if the state/open_project setting is not empty' do
|
|
640
|
+
@config.should_receive(:[]).with(:state, :open_projects).and_return %w[/xyz/abc.ruprj]
|
|
641
|
+
flexmock(@plug).should_receive(:restore_projects).once.with(@config)
|
|
642
|
+
@plug.restore
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
it 'calls the restore_documents method if the state/open_projects setting is empty' do
|
|
646
|
+
@config.should_receive(:[]).with(:state, :open_projects).and_return []
|
|
647
|
+
flexmock(@plug).should_receive(:restore_documents).once.with(@config)
|
|
648
|
+
@plug.restore
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
it 'uses the argument, rather than the config object, if one is given' do
|
|
652
|
+
@config.should_receive(:[]).never
|
|
653
|
+
h = {[:state, :open_projects] => %w[/xyz/abc.ruprj]}
|
|
654
|
+
def h.[](group, name)
|
|
655
|
+
super [group, name]
|
|
656
|
+
end
|
|
657
|
+
flexmock(@plug).should_receive(:restore_projects).once.with(h)
|
|
658
|
+
@plug.restore h
|
|
659
|
+
h[[:state, :open_projects]] = []
|
|
660
|
+
flexmock(@plug).should_receive(:restore_documents).once.with(h)
|
|
661
|
+
@plug.restore h
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
describe 'restore_last_state' do
|
|
667
|
+
|
|
668
|
+
describe ', when the state/startup_behaviour option is :restore_all' do
|
|
669
|
+
|
|
670
|
+
it 'calls the restore method' do
|
|
671
|
+
@config.should_receive(:[]).with(:state, :startup_behaviour).once.and_return :restore_all
|
|
672
|
+
flexmock(@plug).should_receive(:restore).once
|
|
673
|
+
@plug.restore_last_state
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
describe ', when the state/startup_behaviour option is :restore_projects_only' do
|
|
679
|
+
|
|
680
|
+
it 'calls restore_project from within a with block with :restore_project_files set to false' do
|
|
681
|
+
@config.should_receive(:[]).with(:state, :startup_behaviour).once.and_return :restore_projects_only
|
|
682
|
+
flexmock(@plug).should_receive(:restore_projects).once
|
|
683
|
+
flexmock(@plug).should_receive(:with).once.with({:restore_project_files => false}, FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
684
|
+
@plug.restore_last_state
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
describe ', when the state/startup_behaviour option is :restore_documents_only' do
|
|
690
|
+
|
|
691
|
+
it 'calls restore_documents' do
|
|
692
|
+
@config.should_receive(:[]).with(:state, :startup_behaviour).once.and_return :restore_documents_only
|
|
693
|
+
flexmock(@plug).should_receive(:restore_documents).once
|
|
694
|
+
@plug.restore_last_state
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
describe ', when the state/startup_behaviour option is :restore_nothing' do
|
|
700
|
+
|
|
701
|
+
it 'does nothing' do
|
|
702
|
+
@config.should_receive(:[]).with(:state, :startup_behaviour).once.and_return :restore_nothing
|
|
703
|
+
flexmock(@plug).should_receive(:with).never
|
|
704
|
+
flexmock(@plug).should_receive(:restore_projects).never
|
|
705
|
+
flexmock(@plug).should_receive(:restore_documents).never
|
|
706
|
+
flexmock(@plug).should_receive(:restore).never
|
|
707
|
+
@plug.restore_last_state
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
describe Ruber::State::DocumentExtension do
|
|
717
|
+
|
|
718
|
+
it 'inherits from Qt::Object' do
|
|
719
|
+
Ruber::State::DocumentExtension.ancestors.should include(Qt::Object)
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
it 'includes the Ruber::Extension module' do
|
|
723
|
+
Ruber::State::DocumentExtension.ancestors.should include(Ruber::Extension)
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
before do
|
|
727
|
+
@components = flexmock{|m| m.should_ignore_missing}
|
|
728
|
+
flexmock(Ruber).should_receive(:[]).with(:components).and_return(@components).by_default
|
|
729
|
+
@doc = Ruber::Document.new nil, __FILE__
|
|
730
|
+
@ext = Ruber::State::DocumentExtension.new @doc.own_project
|
|
731
|
+
@doc.own_project.add_extension :state, @ext
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
describe ', when created' do
|
|
735
|
+
|
|
736
|
+
it 'connects the document\'s view_created(QObject*, QObject*) signal to its auto_restore slot' do
|
|
737
|
+
flexmock(@ext).should_receive(:auto_restore).once
|
|
738
|
+
@doc.create_view
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
describe '#restore' do
|
|
744
|
+
|
|
745
|
+
before do
|
|
746
|
+
#Needed to avoid the need of creating a mock State plugin
|
|
747
|
+
@doc.disconnect SIGNAL('view_created(QObject*, QObject*)'), @ext
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
it 'moves the cursor to the position stored in the document\'s project state/cursor_position setting' do
|
|
751
|
+
view = @doc.create_view
|
|
752
|
+
flexmock(@doc.own_project).should_receive(:[]).with(:state, :cursor_position).once.and_return([100, 20])
|
|
753
|
+
flexmock(@doc.view).should_receive(:go_to).with(100, 20).once
|
|
754
|
+
@ext.restore
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
it 'does nothing if the document doesn\'t have a view' do
|
|
758
|
+
lambda{@ext.restore}.should_not raise_error
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
describe '#save_settings' do
|
|
764
|
+
|
|
765
|
+
before do
|
|
766
|
+
#Needed to avoid the need of creating a mock State plugin
|
|
767
|
+
@doc.disconnect SIGNAL('view_created(QObject*, QObject*)'), @ext
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
it 'stores an array containing the cursor position in the document\'s project state/cursor_position setting' do
|
|
771
|
+
view = @doc.create_view
|
|
772
|
+
flexmock(@doc.own_project).should_receive(:[]=).with(:state, :cursor_position, [100, 20]).once
|
|
773
|
+
cur = KTextEditor::Cursor.new(100, 20)
|
|
774
|
+
flexmock(@doc.view).should_receive(:cursor_position).once.and_return cur
|
|
775
|
+
@ext.save_settings
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
it 'uses [0,0] as cursor position if the document doesn\'t have any view' do
|
|
779
|
+
flexmock(@doc.own_project).should_receive(:[]=).with(:state, :cursor_position, [0, 0]).once
|
|
780
|
+
lambda{@ext.save_settings}.should_not raise_error
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
describe 'auto_restore' do
|
|
786
|
+
|
|
787
|
+
before do
|
|
788
|
+
@plug = Object.new
|
|
789
|
+
@plug.instance_variable_set :@force_restore_cursor_position, nil
|
|
790
|
+
flexmock(Ruber).should_receive(:[]).with(:state).and_return(@plug).by_default
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
it 'calls the restore method if the State plugins wants the curesor position restored' do
|
|
794
|
+
flexmock(@plug).should_receive(:restore_cursor_position?).once.and_return true
|
|
795
|
+
flexmock(@ext).should_receive(:restore).once
|
|
796
|
+
@ext.send :auto_restore
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
it 'does noting if the State plugins doesn\'t want the curesor position restored' do
|
|
800
|
+
flexmock(@plug).should_receive(:restore_cursor_position?).once.and_return false
|
|
801
|
+
flexmock(@ext).should_receive(:restore).never
|
|
802
|
+
@ext.send :auto_restore
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
describe Ruber::State::ProjectExtension do
|
|
810
|
+
|
|
811
|
+
it 'inherits from Qt::Object' do
|
|
812
|
+
Ruber::State::ProjectExtension.ancestors.should include(Qt::Object)
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
it 'includes the Ruber::Extension module' do
|
|
816
|
+
Ruber::State::ProjectExtension.ancestors.should include(Ruber::Extension)
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
before do
|
|
820
|
+
@dir = File.join Dir.tmpdir, random_string(10)
|
|
821
|
+
FileUtils.mkdir @dir
|
|
822
|
+
@components = flexmock{|m| m.should_ignore_missing}
|
|
823
|
+
@projects = Qt::Object.new
|
|
824
|
+
flexmock(Ruber).should_receive(:[]).with(:components).and_return(@components).by_default
|
|
825
|
+
flexmock(Ruber).should_receive(:[]).with(:projects).and_return(@projects).by_default
|
|
826
|
+
@prj = Ruber::Project.new 'Test', File.join(@dir, 'test.ruprj')
|
|
827
|
+
@ext = Ruber::State::ProjectExtension.new @prj
|
|
828
|
+
@prj.add_extension :state, @ext
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
after do
|
|
832
|
+
FileUtils.rm_rf @dir
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
describe ', when created' do
|
|
836
|
+
|
|
837
|
+
it 'connects the project\'s activated() signal to its auto_restore slot' do
|
|
838
|
+
flexmock(@ext).should_receive(:auto_restore).once
|
|
839
|
+
@prj.activate
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
describe '#restore' do
|
|
845
|
+
|
|
846
|
+
before do
|
|
847
|
+
@mw = flexmock('main window'){|m| m.should_ignore_missing}
|
|
848
|
+
@config = flexmock('config')
|
|
849
|
+
@docs = flexmock('docs'){|m| m.should_ignore_missing}
|
|
850
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@mw).by_default
|
|
851
|
+
flexmock(Ruber).should_receive(:[]).with(:config).and_return(@config).by_default
|
|
852
|
+
flexmock(Ruber).should_receive(:[]).with(:docs).and_return(@docs).by_default
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
it 'calls the document list\'s close_all method' do
|
|
856
|
+
@docs.should_receive(:close_all).once
|
|
857
|
+
flexmock(@prj).should_receive(:[]).with(:state, :open_documents).once.and_return []
|
|
858
|
+
@ext.restore
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
it 'it calls the main_window\'s editor_for! for each entry in the project\'s state/open_documents setting from within a without_activating call' do
|
|
862
|
+
files = %w[/a.rb /b.rb /c.rb]
|
|
863
|
+
flexmock(@prj).should_receive(:[]).with(:state, :open_documents).once.and_return files
|
|
864
|
+
flexmock(@prj).should_receive(:[]).with(:state, :active_document).once.and_return nil
|
|
865
|
+
files.each{|f| @mw.should_receive(:editor_for!).with(f).once}
|
|
866
|
+
@mw.should_receive(:without_activating).once.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
867
|
+
@ext.restore
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
it 'activates the editor corresponding to the file in the project\'s state/active_document entry' do
|
|
871
|
+
files = %w[/a.rb /b.rb /c.rb]
|
|
872
|
+
flexmock(@prj).should_receive(:[]).with(:state, :open_documents).once.and_return files
|
|
873
|
+
flexmock(@prj).should_receive(:[]).with(:state, :active_document).once.and_return files[1]
|
|
874
|
+
@mw.should_receive(:without_activating).once.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
875
|
+
@mw.should_receive(:display_document).once.with files[1]
|
|
876
|
+
@ext.restore
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
it 'activates the editor corresponding to the last entry file in the project\'s state/open_documents entry if the state/active_documents entry is nil' do
|
|
880
|
+
files = %w[/a.rb /b.rb /c.rb]
|
|
881
|
+
editors = 3.times.map{|i| flexmock(i.to_s)}
|
|
882
|
+
flexmock(@prj).should_receive(:[]).with(:state, :open_documents).once.and_return files
|
|
883
|
+
flexmock(@prj).should_receive(:[]).with(:state, :active_document).once.and_return nil
|
|
884
|
+
@mw.should_receive(:without_activating).once.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
885
|
+
@mw.should_receive(:display_document).once.with files[-1]
|
|
886
|
+
@ext.restore
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
it 'activates the editor corresponding to the last entry file in the project\'s state/open_documents entry if the state/active_documents doesn\'t correspond to one of the open files' do
|
|
890
|
+
files = %w[/a.rb /b.rb /c.rb]
|
|
891
|
+
flexmock(@prj).should_receive(:[]).with(:state, :open_documents).once.and_return files
|
|
892
|
+
flexmock(@prj).should_receive(:[]).with(:state, :active_document).once.and_return '/d.rb'
|
|
893
|
+
@mw.should_receive(:without_activating).once.with(FlexMock.on{|a| a.call || a.is_a?(Proc)})
|
|
894
|
+
@mw.should_receive(:display_document).once.with files[-1]
|
|
895
|
+
@ext.restore
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
it 'doesn\'t open any editor if the project\'s state/open_documents entry is empty' do
|
|
899
|
+
files = []
|
|
900
|
+
flexmock(@prj).should_receive(:[]).with(:state, :open_documents).once.and_return files
|
|
901
|
+
flexmock(@prj).should_receive(:[]).with(:state, :active_document).and_return nil
|
|
902
|
+
@mw.should_receive(:editor_for!).never
|
|
903
|
+
@mw.should_receive(:editor_for).never
|
|
904
|
+
@mw.should_receive(:without_activating).never
|
|
905
|
+
@mw.should_receive(:activate_editor).never
|
|
906
|
+
@ext.restore
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
describe '#save_settings' do
|
|
912
|
+
|
|
913
|
+
before do
|
|
914
|
+
@mw = flexmock('main window'){|m| m.should_ignore_missing}
|
|
915
|
+
@docs = flexmock('docs'){|m| m.should_ignore_missing}
|
|
916
|
+
flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@mw).by_default
|
|
917
|
+
flexmock(Ruber).should_receive(:[]).with(:docs).and_return(@docs).by_default
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
it 'stores the paths of the open documents associated with a file in the project\'s state/open_documents entry' do
|
|
921
|
+
docs = %w[a b c].map{|i| flexmock(i.to_s, :path => "/#{i}")}
|
|
922
|
+
@docs.should_receive(:documents_with_file).once.and_return docs
|
|
923
|
+
flexmock(@prj).should_receive(:[]=).once.with :state, :open_documents, %w[a b c].map{|i| "/#{i}"}
|
|
924
|
+
flexmock(@prj).should_receive(:[]=)
|
|
925
|
+
@ext.save_settings
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
it 'stores an empty array in the project\'s state/open_documents entry if there\'s no open file or if none of them is associated with a document' do
|
|
929
|
+
@docs.should_receive(:documents_with_file).once.and_return []
|
|
930
|
+
flexmock(@prj).should_receive(:[]=).once.with :state, :open_documents, []
|
|
931
|
+
flexmock(@prj).should_receive(:[]=)
|
|
932
|
+
@ext.save_settings
|
|
933
|
+
end
|
|
934
|
+
|
|
935
|
+
it 'stores the path of the current document in the project\'s state/active_document entry' do
|
|
936
|
+
docs = %w[a b c].map{|i| flexmock(i.to_s, :path => "/#{i}")}
|
|
937
|
+
active = flexmock('doc', :path => '/b')
|
|
938
|
+
@docs.should_receive(:documents_with_file).once.and_return docs
|
|
939
|
+
@mw.should_receive(:current_document).once.and_return active
|
|
940
|
+
flexmock(@prj).should_receive(:[]=).once.with :state, :active_document, '/b'
|
|
941
|
+
flexmock(@prj).should_receive(:[]=)
|
|
942
|
+
@ext.save_settings
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
it 'stores nil in the project\'s state/active_document entry if there\'s no active document or the active document isn\'t associated with a file' do
|
|
946
|
+
docs = %w[a b c].map{|i| flexmock(i.to_s, :path => "/#{i}")}
|
|
947
|
+
active = flexmock('doc', :path => '')
|
|
948
|
+
@docs.should_receive(:documents_with_file).twice.and_return docs
|
|
949
|
+
@mw.should_receive(:current_document).once.and_return active
|
|
950
|
+
@mw.should_receive(:current_document).once.and_return nil
|
|
951
|
+
flexmock(@prj).should_receive(:[]=).twice.with :state, :active_document, nil
|
|
952
|
+
flexmock(@prj).should_receive(:[]=)
|
|
953
|
+
@ext.save_settings
|
|
954
|
+
@ext.save_settings
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
describe 'auto_restore' do
|
|
960
|
+
|
|
961
|
+
before do
|
|
962
|
+
@config = flexmock('config')
|
|
963
|
+
flexmock(Ruber).should_receive(:[]).with(:config).and_return(@config).by_default
|
|
964
|
+
@plug = Object.new
|
|
965
|
+
@plug.instance_variable_set :@force_restore_project_files, nil
|
|
966
|
+
flexmock(Ruber).should_receive(:[]).with(:state).and_return(@plug).by_default
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
it 'disconnects the project\'s activated() signal from the extension' do
|
|
970
|
+
flexmock(@plug).should_receive(:restore_project_files?).once.and_return false
|
|
971
|
+
@ext.send :auto_restore
|
|
972
|
+
flexmock(@ext).should_receive(:auto_restore).never
|
|
973
|
+
flexmock(@prj).instance_eval{emit activated}
|
|
974
|
+
end
|
|
975
|
+
|
|
976
|
+
it 'calls the restore method if the State plugins wants the project files restored' do
|
|
977
|
+
flexmock(@plug).should_receive(:restore_project_files?).once.and_return true
|
|
978
|
+
flexmock(@ext).should_receive(:restore).once
|
|
979
|
+
@ext.send :auto_restore
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
it 'does noting if the State plugins doesn\'t want the project_files restored' do
|
|
983
|
+
flexmock(@plug).should_receive(:restore_project_files?).once.and_return false
|
|
984
|
+
flexmock(@ext).should_receive(:restore).never
|
|
985
|
+
@ext.send :auto_restore
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
end
|