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.
Files changed (166) hide show
  1. data/COPYING +339 -0
  2. data/INSTALL +137 -0
  3. data/LICENSE +8 -0
  4. data/bin/ruber +65 -0
  5. data/data/share/apps/ruber/core_components.yaml +31 -0
  6. data/data/share/apps/ruber/ruberui.rc +109 -0
  7. data/data/share/icons/ruber.png +0 -0
  8. data/data/share/pixmaps/ruby.png +0 -0
  9. data/icons/ruber-16.png +0 -0
  10. data/icons/ruber-32.png +0 -0
  11. data/icons/ruber-48.png +0 -0
  12. data/icons/ruber-8.png +0 -0
  13. data/lib/ruber/application/application.rb +288 -0
  14. data/lib/ruber/application/plugin.yaml +11 -0
  15. data/lib/ruber/component_manager.rb +899 -0
  16. data/lib/ruber/config/config.rb +82 -0
  17. data/lib/ruber/config/plugin.yaml +3 -0
  18. data/lib/ruber/document_project.rb +209 -0
  19. data/lib/ruber/documents/document_list.rb +416 -0
  20. data/lib/ruber/documents/plugin.yaml +4 -0
  21. data/lib/ruber/editor/document.rb +506 -0
  22. data/lib/ruber/editor/editor_view.rb +167 -0
  23. data/lib/ruber/editor/ktexteditor_wrapper.rb +202 -0
  24. data/lib/ruber/exception_widgets.rb +245 -0
  25. data/lib/ruber/external_program_plugin.rb +397 -0
  26. data/lib/ruber/filtered_output_widget.rb +342 -0
  27. data/lib/ruber/gui_states_handler.rb +231 -0
  28. data/lib/ruber/kde_config_option_backend.rb +167 -0
  29. data/lib/ruber/kde_sugar.rb +249 -0
  30. data/lib/ruber/main_window/choose_plugins_dlg.rb +353 -0
  31. data/lib/ruber/main_window/main_window.rb +524 -0
  32. data/lib/ruber/main_window/main_window_actions.rb +537 -0
  33. data/lib/ruber/main_window/main_window_internal.rb +239 -0
  34. data/lib/ruber/main_window/open_file_in_project_dlg.rb +212 -0
  35. data/lib/ruber/main_window/output_color_widget.rb +35 -0
  36. data/lib/ruber/main_window/plugin.yaml +58 -0
  37. data/lib/ruber/main_window/save_modified_files_dlg.rb +89 -0
  38. data/lib/ruber/main_window/status_bar.rb +156 -0
  39. data/lib/ruber/main_window/ui/choose_plugins_widget.rb +90 -0
  40. data/lib/ruber/main_window/ui/choose_plugins_widget.ui +77 -0
  41. data/lib/ruber/main_window/ui/main_window_settings_widget.rb +108 -0
  42. data/lib/ruber/main_window/ui/main_window_settings_widget.ui +89 -0
  43. data/lib/ruber/main_window/ui/new_project_widget.rb +119 -0
  44. data/lib/ruber/main_window/ui/new_project_widget.ui +178 -0
  45. data/lib/ruber/main_window/ui/open_file_in_project_dlg.rb +109 -0
  46. data/lib/ruber/main_window/ui/open_file_in_project_dlg.ui +168 -0
  47. data/lib/ruber/main_window/ui/output_color_widget.rb +241 -0
  48. data/lib/ruber/main_window/ui/output_color_widget.ui +204 -0
  49. data/lib/ruber/main_window/workspace.rb +442 -0
  50. data/lib/ruber/output_widget.rb +1093 -0
  51. data/lib/ruber/plugin.rb +264 -0
  52. data/lib/ruber/plugin_like.rb +589 -0
  53. data/lib/ruber/plugin_specification.rb +106 -0
  54. data/lib/ruber/plugin_specification_reader.rb +451 -0
  55. data/lib/ruber/project.rb +493 -0
  56. data/lib/ruber/project_backend.rb +105 -0
  57. data/lib/ruber/projects/plugin.yaml +11 -0
  58. data/lib/ruber/projects/project_files_list.rb +314 -0
  59. data/lib/ruber/projects/project_files_widget.rb +301 -0
  60. data/lib/ruber/projects/project_list.rb +314 -0
  61. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.rb +74 -0
  62. data/lib/ruber/projects/ui/project_files_rule_chooser_widget.ui +61 -0
  63. data/lib/ruber/projects/ui/project_files_widget.rb +117 -0
  64. data/lib/ruber/projects/ui/project_files_widget.ui +123 -0
  65. data/lib/ruber/qt_sugar.rb +673 -0
  66. data/lib/ruber/settings_container.rb +515 -0
  67. data/lib/ruber/settings_dialog.rb +244 -0
  68. data/lib/ruber/settings_dialog_manager.rb +503 -0
  69. data/lib/ruber/utils.rb +414 -0
  70. data/lib/ruber/yaml_option_backend.rb +159 -0
  71. data/outsider_files +15 -0
  72. data/plugins/autosave/autosave.rb +404 -0
  73. data/plugins/autosave/plugin.yaml +16 -0
  74. data/plugins/autosave/ui/autosave_config_widget.rb +83 -0
  75. data/plugins/autosave/ui/autosave_config_widget.ui +68 -0
  76. data/plugins/command/command.png +0 -0
  77. data/plugins/command/command.rb +74 -0
  78. data/plugins/command/plugin.yaml +11 -0
  79. data/plugins/find_in_files/find_in_files.rb +337 -0
  80. data/plugins/find_in_files/find_in_files_dlg.rb +411 -0
  81. data/plugins/find_in_files/find_in_files_ui.rc +11 -0
  82. data/plugins/find_in_files/find_in_files_widgets.rb +485 -0
  83. data/plugins/find_in_files/plugin.yaml +23 -0
  84. data/plugins/find_in_files/ui/config_widget.rb +58 -0
  85. data/plugins/find_in_files/ui/config_widget.ui +41 -0
  86. data/plugins/find_in_files/ui/find_in_files_widget.rb +260 -0
  87. data/plugins/find_in_files/ui/find_in_files_widget.ui +324 -0
  88. data/plugins/project_browser/plugin.yaml +10 -0
  89. data/plugins/project_browser/project_browser.rb +245 -0
  90. data/plugins/rake/plugin.yaml +39 -0
  91. data/plugins/rake/rake.png +0 -0
  92. data/plugins/rake/rake.rb +567 -0
  93. data/plugins/rake/rake_extension.rb +153 -0
  94. data/plugins/rake/rake_widgets.rb +615 -0
  95. data/plugins/rake/rakeui.rc +27 -0
  96. data/plugins/rake/ui/add_quick_task_widget.rb +71 -0
  97. data/plugins/rake/ui/add_quick_task_widget.ui +59 -0
  98. data/plugins/rake/ui/choose_task_widget.rb +77 -0
  99. data/plugins/rake/ui/choose_task_widget.ui +72 -0
  100. data/plugins/rake/ui/config_widget.rb +127 -0
  101. data/plugins/rake/ui/config_widget.ui +123 -0
  102. data/plugins/rake/ui/project_widget.rb +217 -0
  103. data/plugins/rake/ui/project_widget.ui +246 -0
  104. data/plugins/rspec/plugin.yaml +30 -0
  105. data/plugins/rspec/rspec.png +0 -0
  106. data/plugins/rspec/rspec.rb +945 -0
  107. data/plugins/rspec/rspec.svg +90 -0
  108. data/plugins/rspec/rspecui.rc +20 -0
  109. data/plugins/rspec/ruber_rspec_formatter.rb +312 -0
  110. data/plugins/rspec/ui/rspec_project_widget.rb +170 -0
  111. data/plugins/rspec/ui/rspec_project_widget.ui +193 -0
  112. data/plugins/ruby_development/plugin.yaml +27 -0
  113. data/plugins/ruby_development/ruby_development.png +0 -0
  114. data/plugins/ruby_development/ruby_development.rb +453 -0
  115. data/plugins/ruby_development/ruby_developmentui.rc +19 -0
  116. data/plugins/ruby_development/ui/project_widget.rb +112 -0
  117. data/plugins/ruby_development/ui/project_widget.ui +108 -0
  118. data/plugins/ruby_runner/config_widget.rb +116 -0
  119. data/plugins/ruby_runner/plugin.yaml +26 -0
  120. data/plugins/ruby_runner/project_widget.rb +62 -0
  121. data/plugins/ruby_runner/ruby.png +0 -0
  122. data/plugins/ruby_runner/ruby_interpretersui.rc +26 -0
  123. data/plugins/ruby_runner/ruby_runner.rb +411 -0
  124. data/plugins/ruby_runner/ui/config_widget.rb +92 -0
  125. data/plugins/ruby_runner/ui/config_widget.ui +91 -0
  126. data/plugins/ruby_runner/ui/project_widget.rb +60 -0
  127. data/plugins/ruby_runner/ui/project_widget.ui +48 -0
  128. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.rb +59 -0
  129. data/plugins/ruby_runner/ui/ruby_runnner_plugin_option_widget.ui +44 -0
  130. data/plugins/state/plugin.yaml +28 -0
  131. data/plugins/state/state.rb +520 -0
  132. data/plugins/state/ui/config_widget.rb +92 -0
  133. data/plugins/state/ui/config_widget.ui +89 -0
  134. data/plugins/syntax_checker/plugin.yaml +18 -0
  135. data/plugins/syntax_checker/syntax_checker.rb +662 -0
  136. data/ruber.desktop +10 -0
  137. data/spec/annotation_model_spec.rb +174 -0
  138. data/spec/common.rb +119 -0
  139. data/spec/component_manager_spec.rb +1259 -0
  140. data/spec/document_list_spec.rb +626 -0
  141. data/spec/document_project_spec.rb +373 -0
  142. data/spec/document_spec.rb +779 -0
  143. data/spec/editor_view_spec.rb +167 -0
  144. data/spec/external_program_plugin_spec.rb +676 -0
  145. data/spec/filtered_output_widget_spec.rb +642 -0
  146. data/spec/gui_states_handler_spec.rb +304 -0
  147. data/spec/kde_config_option_backend_spec.rb +214 -0
  148. data/spec/kde_sugar_spec.rb +101 -0
  149. data/spec/ktexteditor_wrapper_spec.rb +305 -0
  150. data/spec/output_widget_spec.rb +1703 -0
  151. data/spec/plugin_spec.rb +1393 -0
  152. data/spec/plugin_specification_reader_spec.rb +1765 -0
  153. data/spec/plugin_specification_spec.rb +401 -0
  154. data/spec/project_backend_spec.rb +172 -0
  155. data/spec/project_files_list_spec.rb +401 -0
  156. data/spec/project_list_spec.rb +511 -0
  157. data/spec/project_spec.rb +990 -0
  158. data/spec/qt_sugar_spec.rb +328 -0
  159. data/spec/settings_container_spec.rb +617 -0
  160. data/spec/settings_dialog_manager_spec.rb +773 -0
  161. data/spec/settings_dialog_spec.rb +419 -0
  162. data/spec/state_spec.rb +991 -0
  163. data/spec/utils_spec.rb +406 -0
  164. data/spec/workspace_spec.rb +869 -0
  165. data/spec/yaml_option_backend_spec.rb +246 -0
  166. metadata +284 -0
@@ -0,0 +1,373 @@
1
+ require 'spec/common'
2
+
3
+ require 'tempfile'
4
+
5
+ require 'ruber/editor/document'
6
+ require 'ruber/document_project'
7
+
8
+
9
+ class DocumentProjectSpecComponentManager < Qt::Object
10
+ extend Forwardable
11
+ signals 'component_loaded(QObject*)', 'unloading_component(QObject*)'
12
+ def_delegators :@data, :[], :<<
13
+ def_delegator :@data, :each, :each_component
14
+
15
+ def initialize parent = nil
16
+ super
17
+ @data = []
18
+ end
19
+
20
+ end
21
+
22
+
23
+ describe Ruber::DocumentProject::Backend do
24
+
25
+ it 'inherits Ruber::YamlSettingsBackend' do
26
+ Ruber::DocumentProject::Backend.ancestors.should include(Ruber::YamlSettingsBackend)
27
+ end
28
+
29
+ describe ', when created' do
30
+
31
+ it 'accepts a path as argument' do
32
+ lambda{Ruber::DocumentProject::Backend.new __FILE__}.should_not raise_error
33
+ end
34
+
35
+ it 'uses an empty string as file name if the path is empty' do
36
+ Ruber::DocumentProject::Backend.new('').file.should be_empty
37
+ end
38
+
39
+ it 'creates an hexdigest of the document name and uses it as the file name' do
40
+ path = "#{ENV['HOME']}/test.rb"
41
+ exp = '0e589e6c62cec2f5c41117ada4a28c52'
42
+ bk = Ruber::DocumentProject::Backend.new path
43
+ File.basename(bk.file).should == exp
44
+ end
45
+
46
+ it 'sets the directory of the associated file to $appdir/documents' do
47
+ path = "#{ENV['HOME']}/test.rb"
48
+ exp = File.join(ENV['HOME'], '.kde4/share/apps/test/documents')
49
+ bk = Ruber::DocumentProject::Backend.new path
50
+ File.dirname(bk.file).should == exp
51
+ end
52
+
53
+ it 'doesn\'t rise an exception if the file isn\'t a valid project file' do
54
+ path = "#{ENV['HOME']}/test.rb"
55
+ flexmock(File).should_receive(:exist?).once.and_return true
56
+ flexmock(File).should_receive(:read).once.and_return '{'
57
+ bk = nil
58
+ lambda{bk = Ruber::DocumentProject::Backend.new path}.should_not raise_error
59
+ bk.instance_variable_get(:@data).should == {}
60
+ end
61
+
62
+ it 'has no old files' do
63
+ Ruber::DocumentProject::Backend.new( __FILE__).instance_variable_get(:@old_files).should be_empty
64
+ end
65
+
66
+ end
67
+
68
+ describe "#write" do
69
+
70
+ before do
71
+ @dir = File.join Dir.tmpdir, 'ruber_project_document_option_backend'
72
+ FileUtils.mkdir @dir
73
+ @filename = File.join @dir, 'ruber_project_document_option_backend.yaml'
74
+ @doc = File.join(ENV['HOME'],'test.rb')
75
+ @back = Ruber::DocumentProject::Backend.new @doc
76
+ @back.instance_variable_set :@filename, @filename
77
+ end
78
+
79
+ after do
80
+ FileUtils.rm_rf @dir
81
+ end
82
+
83
+ it 'raises Errno::ENOENT if the backend isn\'t associated with a file' do
84
+ @back.instance_variable_set :@filename, ''
85
+ lambda do
86
+ @back.write({OS.new(:name => :o1, :group => :G1, :default => 3) => 5})
87
+ end.should raise_error(Errno::ENOENT)
88
+ end
89
+
90
+ it 'behaves as YamlSettingsBackend#write if there are options to be written' do
91
+ @back.instance_variable_set :@data, {:G1 => {:o1 => 1}}
92
+ @back.write({OS.new(:name => :o1, :group => :G1, :default => 3) => 5})
93
+ (YAML.load File.read(@filename)).should == {:G1 => {:o1 => 5}}
94
+ @back.instance_variable_get(:@data).should == {:G1 => {:o1 => 5}}
95
+ end
96
+
97
+ it 'doesn\'t write anything to file if the only option is the project name' do
98
+ @back.write( {OS.new(:name => :project_name, :group => :general, :default => nil) => @doc})
99
+ File.exist?(@filename).should be_false
100
+ end
101
+
102
+ it 'deletes the file when it exists and the only option to write would be the project name' do
103
+ `touch #{@filename}`
104
+ @back.write( {OS.new(:name => :project_name, :group => :general, :default => nil) => @doc})
105
+ File.exist?(@filename).should be_false
106
+ end
107
+
108
+ it 'deletes all the old files' do
109
+ files = %w[x y].map{|f| File.join @dir, f}
110
+ files.each do |f|
111
+ @back.instance_variable_get(:@old_files) << f
112
+ `touch #{f}`
113
+ end
114
+ @back.write({OS.new(:name => :o1, :group => :G1, :default => 3) => 5})
115
+ files.each{|f| File.exist?(f).should be_false}
116
+ end
117
+
118
+ it 'clears the list of old files' do
119
+ files = %w[x y].map{|f| File.join @dir, f}
120
+ @back.instance_variable_set(:@old_files, files)
121
+ @back.write({OS.new(:name => :o1, :group => :G1, :default => 3) => 5})
122
+ @back.instance_variable_get(:@old_files).should be_empty
123
+ end
124
+
125
+ end
126
+
127
+ describe "#document_path=" do
128
+
129
+ before do
130
+ @doc = File.join(ENV['HOME'],'test.rb')
131
+ @back = Ruber::DocumentProject::Backend.new @doc
132
+ end
133
+
134
+
135
+ it 'sets the project name to the argument' do
136
+ file = File.join(ENV['HOME'],'test1.rb')
137
+ @back.document_path = file
138
+ @back.instance_variable_get(:@data)[:general][:project_name].should == file
139
+ end
140
+
141
+ it 'changes the file name according to the argument' do
142
+ file = File.join(ENV['HOME'],'test1.rb')
143
+ exp = (Digest::MD5.new << file).hexdigest
144
+ @back.document_path = file
145
+ @back.file.should == File.join(KDE::Global.dirs.locate_local('appdata', 'documents/'), exp)
146
+ end
147
+
148
+ it 'adds the old file name to the list of old files, unless it was empty' do
149
+ file = File.join(ENV['HOME'],'test1.rb')
150
+ old = @back.file
151
+ @back.document_path = file
152
+ @back.instance_variable_get(:@old_files).should include(old)
153
+ @back = Ruber::DocumentProject::Backend.new ''
154
+ @back.document_path = file
155
+ @back.instance_variable_get(:@old_files).should be_empty
156
+ end
157
+
158
+ end
159
+
160
+ end
161
+
162
+ describe Ruber::DocumentProject do
163
+
164
+ include FlexMock::ArgumentTypes
165
+
166
+ before(:all) do
167
+
168
+ class Ruber::DocumentProject
169
+
170
+ def connect *args
171
+ super
172
+ end
173
+
174
+ alias_method :old_connect, :connect
175
+
176
+ def connect *args, &blk
177
+ @_connections ||= []
178
+ args << blk if blk
179
+ @_connections << args
180
+ end
181
+
182
+ end
183
+
184
+ end
185
+
186
+ after(:all) do
187
+
188
+ class Ruber::DocumentProject
189
+ alias_method :connect, :old_connect
190
+ end
191
+ end
192
+
193
+ it 'derives from AbstractProject' do
194
+ Ruber::DocumentProject.ancestors.should include(Ruber::AbstractProject)
195
+ end
196
+
197
+ def create_doc path
198
+ doc = Qt::Object.new
199
+ class << doc
200
+ attr_accessor :path
201
+ end
202
+ doc.path = path
203
+ doc
204
+ end
205
+
206
+ before do
207
+ @app = KDE::Application.instance
208
+ @comp = DocumentProjectSpecComponentManager.new
209
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp).by_default
210
+ flexmock(Ruber).should_receive(:[]).with(:app).and_return(@comp).by_default
211
+ end
212
+
213
+ describe ', when created' do
214
+
215
+ it 'accepts a document as parameter' do
216
+ doc = create_doc __FILE__
217
+ lambda{Ruber::DocumentProject.new doc}.should_not raise_error
218
+ end
219
+
220
+ it 'uses the document as parent' do
221
+ doc = create_doc __FILE__
222
+ prj = Ruber::DocumentProject.new doc
223
+ prj.parent.should equal(doc)
224
+ end
225
+
226
+ it 'uses Ruber::DocumentProject::Backend as backend and the file associated with the document as project name, if needed' do
227
+ doc = create_doc __FILE__
228
+ prj = Ruber::DocumentProject.new doc
229
+ prj.instance_variable_get(:@backend).should be_a(Ruber::DocumentProject::Backend)
230
+ prj.project_name.should == __FILE__
231
+ file = '/home/stefano/xyz/document_project_spec_data_.rb'
232
+ md5 = Digest::MD5.new
233
+ md5 << file
234
+ data_path = File.join ENV['HOME'], '.kde4/share/apps/test/documents', md5.hexdigest
235
+ File.open(data_path, 'w'){|f| YAML.dump( {:general => {:project_name => file}}, f)}
236
+ doc = create_doc file
237
+ prj = Ruber::DocumentProject.new doc
238
+ prj.project_name.should == file
239
+ FileUtils.rm_rf data_path
240
+ end
241
+
242
+ it 'doesn\'t raise an error if the document isn\'t associated with a file' do
243
+ doc = create_doc ''
244
+ prj = nil
245
+ lambda{prj = Ruber::DocumentProject.new doc}.should_not raise_error
246
+ prj.project_name.should be_empty
247
+ end
248
+
249
+ it 'connects the document\s "document_url_changed(QObject*)" signal with its "change_file()" slot' do
250
+ doc = create_doc File.join(ENV['HOME'], 'test.rb')
251
+ prj = Ruber::DocumentProject.new doc
252
+ prj.instance_variable_get(:@_connections).should include([doc, SIGNAL('document_url_changed(QObject*)'), prj, SLOT(:change_file)])
253
+ end
254
+
255
+ end
256
+
257
+ describe "#scope" do
258
+
259
+ it 'returns :document' do
260
+ doc = create_doc __FILE__
261
+ prj = Ruber::DocumentProject.new doc
262
+ prj.scope.should == :document
263
+ end
264
+
265
+ end
266
+
267
+ describe '#match_rule?' do
268
+
269
+ it 'returns false if the rule\'s scope doesn\'t include :document' do
270
+ doc = create_doc __FILE__
271
+ prj = Ruber::DocumentProject.new doc
272
+ o1 = OS.new(:file_extension => [], :scope => [:global], :mimetype => [])
273
+ flexmock(doc).should_receive(:file_type_match?).with([], []).and_return true
274
+ prj.match_rule?(o1).should be_false
275
+ end
276
+
277
+ it 'returns false if the document\'s file_type_match? method returns false' do
278
+ doc = create_doc __FILE__
279
+ prj = Ruber::DocumentProject.new doc
280
+ o1 = OS.new(:file_extension => ['*.rb'], :scope => [:document], :mimetype => [])
281
+ flexmock(doc).should_receive(:file_type_match?).once.with([], ['*.rb']).and_return false
282
+ prj.match_rule?(o1).should be_false
283
+ end
284
+
285
+ it 'returns true if both the mimetype and the file extension of the rule match those of the document and the rule\'s scope include :document' do
286
+ doc = create_doc __FILE__
287
+ prj = Ruber::DocumentProject.new doc
288
+ o1 = OS.new(:file_extension => ['*.rb'], :scope => [:document], :mimetype => [])
289
+ flexmock(doc).should_receive(:file_type_match?).once.with([], ['*.rb']).and_return true
290
+ prj.match_rule?(o1).should be_true
291
+ end
292
+
293
+ end
294
+
295
+ describe '#change_file' do
296
+
297
+ it 'changes the filename associated with the backend' do
298
+ file = File.join ENV['HOME'], 'test.rb'
299
+ new_file = File.join ENV['HOME'], 'test.rb1'
300
+ doc = create_doc file
301
+ prj = Ruber::DocumentProject.new doc
302
+ flexmock(prj.instance_variable_get(:@backend)).should_receive(:document_path=).once.with new_file
303
+ doc.path = new_file
304
+ prj.send :change_file
305
+ end
306
+
307
+ end
308
+
309
+ describe "#project_directory" do
310
+
311
+ before do
312
+ @app = KDE::Application.instance
313
+ @comp = DocumentProjectSpecComponentManager.new
314
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp).by_default
315
+ flexmock(Ruber).should_receive(:[]).with(:app).and_return(@comp).by_default
316
+ end
317
+
318
+ it 'returns the directory where the document is if the document is associated with a file' do
319
+ doc = create_doc __FILE__
320
+ prj = Ruber::DocumentProject.new doc
321
+ prj.project_directory.should == File.dirname(__FILE__)
322
+ end
323
+
324
+ it 'returns the current directory if the document is not associated with a file' do
325
+ doc = create_doc ''
326
+ prj = Ruber::DocumentProject.new doc
327
+ prj.project_directory.should == Dir.pwd
328
+ end
329
+
330
+ end
331
+
332
+ describe '#write' do
333
+
334
+ it 'calls the backend\'s write method' do
335
+ doc = create_doc __FILE__
336
+ prj = Ruber::DocumentProject.new doc
337
+ flexmock(prj.instance_variable_get(:@backend)).should_receive(:write).once
338
+ prj.write
339
+ end
340
+
341
+ it 'doesn\'t raise an exception if the document isn\'t associated with a file' do
342
+ doc = create_doc ''
343
+ prj = Ruber::DocumentProject.new doc
344
+ flexmock(prj.instance_variable_get(:@backend)).should_receive(:write).once.and_raise(Errno::ENOENT)
345
+ prj.write
346
+ end
347
+
348
+ it 'raises an exception if the backend raises Errno::ENOENT but the document is associated with a file' do
349
+ doc = create_doc __FILE__
350
+ prj = Ruber::DocumentProject.new doc
351
+ flexmock(prj.instance_variable_get(:@backend)).should_receive(:write).once.and_raise(Errno::ENOENT)
352
+ lambda{prj.write}.should raise_error(Errno::ENOENT)
353
+ end
354
+
355
+ end
356
+
357
+ describe '#files' do
358
+
359
+ it 'returns an array containing the path of the file if the document is associated with a file' do
360
+ doc = create_doc __FILE__
361
+ prj = Ruber::DocumentProject.new doc
362
+ prj.files.should == [__FILE__]
363
+ end
364
+
365
+ it 'returns an empty array if the document isn\'t associated with a path' do
366
+ doc = create_doc ''
367
+ prj = Ruber::DocumentProject.new doc
368
+ prj.files.should == []
369
+ end
370
+
371
+ end
372
+
373
+ end
@@ -0,0 +1,779 @@
1
+ require 'spec/common'
2
+
3
+ require 'tempfile'
4
+ require 'fileutils'
5
+ require 'flexmock/argument_types'
6
+ require 'facets/string/camelcase'
7
+
8
+ require 'ruber/editor/document'
9
+
10
+ class DocumentSpecComponentManager < Qt::Object
11
+ extend Forwardable
12
+ signals 'component_loaded(QObject*)', 'unloading_component(QObject*)'
13
+ def_delegators :@data, :[], :<<
14
+ def_delegator :@data, :each, :each_component
15
+
16
+ def initialize parent = nil
17
+ super
18
+ @data = []
19
+ end
20
+
21
+ end
22
+
23
+ describe Ruber::Document do
24
+
25
+ include FlexMock::ArgumentTypes
26
+
27
+ before do
28
+ @app = KDE::Application.instance
29
+ @w = Qt::Widget.new
30
+ @comp = DocumentSpecComponentManager.new
31
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp)
32
+ @doc = Ruber::Document.new @app
33
+ end
34
+
35
+ describe ', when created' do
36
+
37
+ it 'should load a KTextEditor::Document' do
38
+ @doc.instance_variable_get(:@doc).should be_instance_of(KTextEditor::Document)
39
+ end
40
+
41
+ it 'has an annotation model' do
42
+ @doc.interface('annotation_interface').annotation_model.should_not be_nil
43
+ end
44
+
45
+ it 'should not have a view' do
46
+ @doc.view.should be_nil
47
+ end
48
+
49
+ it 'should open a given file if new is called with a string or KDE::Url second argument' do
50
+ doc = Ruber::Document.new @app, __FILE__
51
+ doc.text.should == File.read(__FILE__)
52
+ doc.url.path.should == __FILE__
53
+ doc = Ruber::Document.new @app, KDE::Url.from_path(__FILE__)
54
+ doc.text.should == File.read(__FILE__)
55
+ doc.url.path.should == __FILE__
56
+ end
57
+
58
+ it 'creates a document project for itself, after opening the file (if given)' do
59
+ doc = Ruber::Document.new @app
60
+ prj = doc.instance_variable_get(:@project)
61
+ prj.should be_a(Ruber::DocumentProject)
62
+ prj.project_name.should be_empty
63
+ doc = Ruber::Document.new @app, __FILE__
64
+ prj = doc.instance_variable_get(:@project)
65
+ prj.should be_a(Ruber::DocumentProject)
66
+ prj.project_name.should == __FILE__
67
+ end
68
+
69
+
70
+ it 'should not be active' do
71
+ doc = Ruber::Document.new @app, __FILE__
72
+ doc.should_not be_active
73
+ end
74
+
75
+ end
76
+
77
+ describe '#own_project' do
78
+
79
+ it 'returns the DocumentProject associated with the document' do
80
+ doc = Ruber::Document.new @app, __FILE__
81
+ doc.own_project.project_name.should == __FILE__
82
+ end
83
+
84
+ end
85
+
86
+ describe '#project' do
87
+
88
+ before do
89
+ @list = flexmock
90
+ @prj = flexmock(:project_files => @list)
91
+ @projects = flexmock{|m| m.should_receive(:current).and_return(@prj).by_default}
92
+ flexmock(Ruber).should_receive(:[]).with(:projects).and_return(@projects)
93
+ @doc = Ruber::Document.new @app, __FILE__
94
+ end
95
+
96
+ it 'returns the current project if one exists and the document belongs to it' do
97
+ flexmock(@list).should_receive(:file_in_project?).with(__FILE__).and_return true
98
+ @doc.project.should == @prj
99
+ end
100
+
101
+ it 'returns the document project if the file associated with the document doesn\'t belong to the current project' do
102
+ flexmock(@list).should_receive(:file_in_project?).with(__FILE__).and_return false
103
+ @doc.project.should be_a(Ruber::DocumentProject)
104
+ end
105
+
106
+ it 'returns the document project if the document isn\'t associated with a file' do
107
+ @doc = Ruber::Document.new @app
108
+ @doc.project.should be_a(Ruber::DocumentProject)
109
+ end
110
+
111
+ it 'returns the document project if there isn\'t a project open' do
112
+ @projects.should_receive(:current).and_return nil
113
+ @doc.project.should be_a(Ruber::DocumentProject)
114
+ end
115
+
116
+ end
117
+
118
+ describe '#save' do
119
+
120
+ it 'calls document_save_as if the document has no filename' do
121
+ flexmock(@doc).should_receive(:document_save_as).once.and_return(true)
122
+ flexmock(@doc).should_receive(:document_save_as).once.and_return(false)
123
+ @doc.save.should be_true
124
+ @doc.save.should be_false
125
+ # tmp_file = File.join Dir.tmpdir, "ruber_document_test" + 3.times.map{rand(10)}.join.to_s
126
+ # flexmock(KDE::FileDialog).should_receive(:get_save_file_name).times(2).and_return(nil, tmp_file)
127
+ # @doc.text = 'test'
128
+ # @doc.save.should be_false
129
+ # @doc.save.should be_true
130
+ # File.exists?(tmp_file).should be_true
131
+ # File.read(tmp_file).should == 'test'
132
+ # FileUtils.rm tmp_file
133
+ end
134
+
135
+ describe ', when the document is associated with a file' do
136
+
137
+ it 'calls the document_save_as method if the document is read only' do
138
+ Tempfile.open('ruber_document_test') do |f|
139
+ f.write 'test'
140
+ f.flush
141
+ doc = Ruber::Document.new nil, f.path
142
+ flexmock(doc.send :internal).should_receive(:is_read_write).once.and_return false
143
+ flexmock(doc).should_receive(:document_save_as).once
144
+ doc.text += ' added'
145
+ doc.save
146
+ end
147
+ end
148
+
149
+ it 'calls its own project\'s save method' do
150
+ Tempfile.open('ruber_document_test') do |f|
151
+ f.write 'test'
152
+ f.flush
153
+ doc = Ruber::Document.new nil, f.path
154
+ flexmock(doc.own_project).should_receive(:save).once
155
+ doc.text += ' added'
156
+ doc.save
157
+ end
158
+ end
159
+
160
+ it 'saves the document if the document is associated with a file' do
161
+ Tempfile.open('ruber_document_test') do |f|
162
+ f.write 'test'
163
+ f.flush
164
+ doc = Ruber::Document.new nil, f.path
165
+ doc.text += ' added'
166
+ doc.save.should be_true
167
+ File.read( f.path ).should == 'test added'
168
+ end
169
+ end
170
+
171
+ end
172
+
173
+ end
174
+
175
+ it 'should allow to create a view if none exists' do
176
+ @doc.create_view(Qt::Widget.new).should_not be_nil
177
+ end
178
+
179
+ it 'should not allow to create a view if one already exists' do
180
+ @doc.create_view(Qt::Widget.new)
181
+ lambda{@doc.create_view(Qt::Widget.new)}.should raise_error(RuntimeError)
182
+ end
183
+
184
+ it 'should allow to get and change the text' do
185
+ txt="test text"
186
+ lambda{@doc.text="test text"}.should_not raise_error
187
+ @doc.text.should == txt
188
+ end
189
+
190
+ it 'should return the mimetype of the document' do
191
+ @doc.mime_type.should == 'text/plain'
192
+ @doc.open_url KDE::Url.from_path(__FILE__)
193
+ @doc.mime_type.should == 'application/x-ruby'
194
+ end
195
+
196
+ it 'should return the view attached to it (or nil) with the view method' do
197
+ @doc.view.should be_nil
198
+ @doc.create_view nil
199
+ @doc.view.should be_instance_of Ruber::EditorView
200
+ @doc.view.close
201
+ end
202
+
203
+ it 'should emit the "modified_changed(QObject*, bool)" signal when the modified status changes' do
204
+ m = flexmock
205
+ m.should_receive(:test).ordered.with(true, @doc)
206
+ m.should_receive(:test).ordered.with(false, @doc)
207
+ @doc.connect(SIGNAL('modified_changed(bool, QObject*)')){|mod, o| m.test mod, o}
208
+ d = @doc.instance_variable_get(:@doc)
209
+ d.instance_eval do
210
+ self.modified = true
211
+ emit modifiedChanged(self)
212
+ self.modified = false
213
+ emit modifiedChanged(self)
214
+ end
215
+
216
+ end
217
+
218
+ it 'should emit the "document_name_changed(QString, QObject*)" signal when the document name changes' do
219
+ m = flexmock
220
+ m.should_receive(:document_name_changed).twice
221
+ @doc.connect(SIGNAL('document_name_changed(QString, QObject*)')) do |str, obj|
222
+ obj.should == @doc
223
+ str.should == @doc.document_name
224
+ m.document_name_changed
225
+ end
226
+ @doc.open_url KDE::Url.from_path( __FILE__)
227
+ end
228
+
229
+ it 'should return the path of the file usgin the "path" method or an empty string if the document is not associated with a file' do
230
+ @doc.path.should == ''
231
+ @doc.open_url KDE::Url.from_path( __FILE__ )
232
+ @doc.path.should == __FILE__
233
+ end
234
+
235
+ it 'should return an empty string if the document is empty' do
236
+ @doc.text.should_not be_nil
237
+ end
238
+
239
+ it 'should tell whether it\'s associated with a file or not' do
240
+ @doc.should_not have_file
241
+ Ruber::Document.new(nil, __FILE__).should have_file
242
+ end
243
+
244
+ it 'should tell whether it\'s a pristine document' do
245
+ @doc.should be_pristine
246
+ @doc.text = "a"
247
+ @doc.should_not be_pristine
248
+ projects = flexmock(:current => nil)
249
+ config = flexmock{|m| m.should_receive(:[]).with(:general, :default_script_directory).and_return ENV['HOME']}
250
+ flexmock(Ruber).should_receive(:[]).with(:projects).and_return(projects)
251
+ flexmock(Ruber).should_receive(:[]).with(:config).and_return(config)
252
+ flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(Qt::Widget.new)
253
+ Tempfile.open('ruber_document_test') do |f|
254
+ res = OpenStruct.new(:file_names => [f.path], :encoding => @doc.encoding)
255
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).and_return(res)
256
+ flexmock(KDE::MessageBox).should_receive(:warning_continue_cancel).and_return KDE::MessageBox::Continue
257
+ @doc.save
258
+ @doc.should_not be_pristine
259
+ end
260
+ Ruber::Document.new(nil, __FILE__).should_not be_pristine
261
+ end
262
+
263
+ ["text_changed(QObject*)", "about_to_close(QObject*)", 'about_to_close(QObject*)',
264
+ 'about_to_reload(QObject*)', 'document_url_changed(QObject*)'].each do |sig|
265
+ sig_name = sig[0...sig.index('(')]
266
+ o_sig_name = sig_name.camelcase(false)
267
+ o_sig = sig.camelcase(false).sub('(QObject*','(KTextEditor::Document*')
268
+ it "should emit the \"#{sig}\" signal in response to the underlying KTextEditor::Document \"#{o_sig}\" signal" do
269
+ m = flexmock
270
+ m.should_receive( sig_name.to_sym).once.with(@doc.object_id)
271
+ @doc.connect(SIGNAL(sig)){|o| m.send(sig_name.to_sym, o.object_id)}
272
+ d = @doc.instance_variable_get(:@doc)
273
+ d.instance_eval "emit #{o_sig_name}( self)"
274
+ end
275
+ end
276
+
277
+ it 'should emit the "mode_changed(QObject*)" signal in response to the underlying KTextEditor::Document "modeChanged(KTextEditor::Document)" signal' do
278
+ m = flexmock
279
+ m.should_receive( :mode_changed).once.with(@doc.object_id)
280
+ @doc.connect(SIGNAL('mode_changed(QObject*)')){|o| m.mode_changed o.object_id}
281
+ @doc.mode = "Ruby"
282
+ end
283
+
284
+ it 'should emit the "highlighting_mode_changed(QObject*)" signal in response to the underlying KTextEditor::Document "highlightingModeChanged(KTextEditor::Document)" signal' do
285
+ m = flexmock
286
+ m.should_receive( :h_mode_changed).once.with(@doc.object_id)
287
+ @doc.connect(SIGNAL('highlighting_mode_changed(QObject*)')){|o| m.h_mode_changed o.object_id}
288
+ @doc.highlighting_mode = "Ruby"
289
+ end
290
+
291
+ it 'should emit the "text_modified(KTextEditor::Range, KTextEditor::Range, QObject*)" signal in response to the underlying KTextEditor::Document "textChanged(KTextEditor::Document*, KTextEditor::Range, KTextEditor::Range)" signal' do
292
+ m = flexmock
293
+ m.should_receive( :text_modified).once.with(@doc.object_id)
294
+ @doc.connect(SIGNAL('text_modified(KTextEditor::Range, KTextEditor::Range, QObject*)')){|_r1, _r2, o| m.text_modified o.object_id}
295
+ d = @doc.instance_variable_get(:@doc)
296
+ d.instance_eval{emit textChanged(self, KTextEditor::Range.new(0,0,0,5), KTextEditor::Range.new(0,0,1,1))}
297
+ end
298
+
299
+ it 'should emit the "text_inserted(KTextEditor::Range, QObject*)" signal in response to the underlying KTextEditor::Document "textInserted(KTextEditor::Document*, KTextEditor::Range)" signal' do
300
+ m = flexmock
301
+ m.should_receive( :text_inserted).once.with(@doc.object_id)
302
+ @doc.connect(SIGNAL('text_inserted(KTextEditor::Range, QObject*)')){|_, o| m.text_inserted o.object_id}
303
+ d = @doc.instance_variable_get(:@doc)
304
+ d.instance_eval{emit textInserted(self, KTextEditor::Range.new(0,0,0,5))}
305
+ end
306
+
307
+ it 'should emit the "text_removed(KTextEditor::Range, QObject*)" signal in response to the underlying KTextEditor::Document "textRemoved(KTextEditor::Document*, KTextEditor::Range)" signal' do
308
+ m = flexmock
309
+ m.should_receive( :text_removed).once.with(@doc.object_id)
310
+ @doc.connect(SIGNAL('text_removed(KTextEditor::Range, QObject*)')){|_, o| m.text_removed o.object_id}
311
+ d = @doc.instance_variable_get(:@doc)
312
+ d.instance_eval{emit textRemoved(self, KTextEditor::Range.new(0,0,0,5))}
313
+ end
314
+
315
+ it 'emits the "view_created(QObject*, QObject*)" signal after creating a view' do
316
+ m = flexmock
317
+ m.should_receive( :view_created).once.with(@doc.object_id)
318
+ @doc.connect(SIGNAL('view_created(QObject*, QObject*)'))do |_, o|
319
+ m.view_created o.object_id
320
+ @doc.view.should be_a(Ruber::EditorView)
321
+ end
322
+ @doc.create_view nil
323
+ @doc.view.close
324
+ end
325
+
326
+ it 'should return nil with the view method when a view has been closed' do
327
+ view = @doc.create_view
328
+ view.close
329
+ @doc.view.should be_nil
330
+ end
331
+
332
+ it 'should return true when close_url succeeds' do
333
+ doc = Ruber::Document.new nil, __FILE__
334
+ doc.close_url(false).should be_true
335
+ end
336
+
337
+ it 'should call the update_project method of each component, passing it its project, when the name of the document changes, but before emitting the document_name_changed signal' do
338
+ 3.times{@comp << flexmock{|m| m.should_receive(:update_project).once.with(Ruber::DocumentProject).globally.ordered} }
339
+ name_changed_rec = flexmock{|m| m.should_receive(:name_changed).once.globally.ordered}
340
+ internal = @doc.send :internal
341
+ @doc.connect(SIGNAL('document_name_changed(QString,QObject*)')){name_changed_rec.name_changed}
342
+ internal.instance_eval{emit documentNameChanged(self)}
343
+ end
344
+
345
+ after do
346
+ @doc.view.close if @doc.view
347
+ @doc.instance_variable_get(:@doc).closeUrl false
348
+ @doc.dispose
349
+ end
350
+
351
+ end
352
+
353
+ describe 'Ruber::Document#close' do
354
+
355
+ before do
356
+ @app = KDE::Application.instance
357
+ @w = Qt::Widget.new
358
+ @comp = DocumentSpecComponentManager.new
359
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp)
360
+ @doc = Ruber::Document.new @app
361
+ flexmock(@doc.instance_variable_get(:@project)).should_receive(:save).by_default
362
+ end
363
+
364
+ it 'should return immediately if ask is true and query_close returns false' do
365
+ doc = Ruber::Document.new nil, __FILE__
366
+ exp = doc.object_id
367
+ m = flexmock('test'){|mk| mk.should_receive(:document_closing).never}
368
+ doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
369
+ flexmock(doc).should_receive(:query_close).and_return false
370
+ doc.close
371
+ end
372
+
373
+ it 'calls the save method of the project after emitting the "closing" signal' do
374
+ @doc = Ruber::Document.new @app, __FILE__
375
+ m = flexmock{|mk| mk.should_receive(:document_closing).once.globally.ordered}
376
+ @doc.connect(SIGNAL('closing(QObject*)')){m.document_closing}
377
+ flexmock(@doc.instance_variable_get(:@project)).should_receive(:save).once.globally.ordered
378
+ @doc.close
379
+ end
380
+
381
+ it 'doesn\'t call the save method of the project if the document isn\'t associated with a file' do
382
+ flexmock(@doc.instance_variable_get(:@project)).should_receive(:save).never
383
+ @doc.close
384
+ end
385
+
386
+ it 'should call the "close_url", if closing is confirmed' do
387
+ doc = Ruber::Document.new nil, __FILE__
388
+ flexmock(doc).should_receive(:close_url).once.with(false)
389
+ doc.close
390
+ doc = Ruber::Document.new nil, __FILE__
391
+ flexmock(doc).should_receive(:close_url).once.with(false)
392
+ doc.close false
393
+ end
394
+
395
+ it 'should emit the "closing(QObject*)" signal if closing is confirmed' do
396
+ doc = Ruber::Document.new nil, __FILE__
397
+ exp = doc.object_id
398
+ m = flexmock('test'){|mk| mk.should_receive(:document_closing).once.with(exp)}
399
+ flexmock(doc).should_receive(:close_url).and_return true
400
+ doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
401
+ flexmock(doc).should_receive(:query_close).and_return true
402
+ doc.close
403
+ doc = Ruber::Document.new nil, __FILE__
404
+ exp1 = doc.object_id
405
+ m.should_receive(:document_closing).with(exp1).once
406
+ flexmock(doc).should_receive(:query_close)
407
+ doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
408
+ doc.close false
409
+ end
410
+
411
+ it 'should close the view, if there\'s one, after emitting the closing signal, if closing is confirmed' do
412
+ doc = Ruber::Document.new nil, __FILE__
413
+ v = doc.create_view
414
+ exp = doc.object_id
415
+ m = flexmock('test'){|mk| mk.should_receive(:document_closing).once.with(exp).globally.ordered}
416
+ flexmock(v).should_receive(:close).once.globally.ordered
417
+ flexmock(doc).should_receive(:close_url).and_return true
418
+ doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
419
+ flexmock(doc).should_receive(:query_close).and_return true
420
+ doc.close false
421
+ end
422
+
423
+ it 'calls the #save method of the project if the document path is not empty' do
424
+ doc = Ruber::Document.new nil, __FILE__
425
+ exp = doc.object_id
426
+ flexmock(doc).should_receive(:close_url).and_return true
427
+ flexmock(doc.instance_variable_get(:@project)).should_receive(:save).once
428
+ doc.close false
429
+ end
430
+
431
+ it 'doesn\'t call the #save method of the project if the document path is empty' do
432
+ doc = Ruber::Document.new nil
433
+ exp = doc.object_id
434
+ flexmock(doc).should_receive(:close_url).and_return true
435
+ flexmock(doc.instance_variable_get(:@project)).should_receive(:save).never
436
+ doc.close false
437
+ end
438
+
439
+ it 'calls the #close method of the project passing false' do
440
+ doc = Ruber::Document.new nil
441
+ exp = doc.object_id
442
+ flexmock(doc).should_receive(:close_url).and_return true
443
+ flexmock(doc.instance_variable_get(:@project)).should_receive(:close).with(false).once
444
+ doc.close false
445
+ end
446
+
447
+
448
+ it 'should disconnect any slot/block connected to it after emitting the closing signal if closing is confirmed' do
449
+ doc = Ruber::Document.new nil, __FILE__
450
+ exp = doc.object_id
451
+ flexmock(doc).should_receive(:close_url).and_return true
452
+ def doc.disconnect *args;end
453
+ m = flexmock{|mk| mk.should_receive(:document_closing).with(exp).once.globally.ordered}
454
+ doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
455
+ flexmock(doc).should_receive(:disconnect).with_no_args.once.globally.ordered
456
+ doc.close false
457
+ end
458
+
459
+ it 'should dispose of itself after emitting the closing signal, if closing is confirmed' do
460
+ doc = Ruber::Document.new nil, __FILE__
461
+ doc.close false
462
+ doc.should be_disposed
463
+ end
464
+
465
+ it 'should return true, if closing is confirmed and successful and false otherwise' do
466
+ doc = Ruber::Document.new nil, __FILE__
467
+ flexmock(doc).should_receive(:close_url).once.and_return true
468
+ doc.close( false).should be_true
469
+ doc = Ruber::Document.new nil, __FILE__
470
+ flexmock(doc).should_receive(:close_url).once.and_return false
471
+ doc.close( false).should be_false
472
+ flexmock(doc).should_receive(:query_close).once.and_return false
473
+ doc.close(true).should be_false
474
+ end
475
+
476
+ end
477
+
478
+ describe 'Ruber::Document#close_view' do
479
+
480
+ before do
481
+ @app = KDE::Application.instance
482
+ @w = Qt::Widget.new
483
+ @comp = DocumentSpecComponentManager.new
484
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp)
485
+ @doc = Ruber::Document.new @app
486
+ @view = @doc.create_view
487
+ end
488
+
489
+ it 'should call the "close" method' do
490
+ flexmock(@doc).should_receive(:close).once.with(true)
491
+ flexmock(@doc).should_receive(:close).once.with(false)
492
+ @doc.close_view @view, true
493
+ @doc.close_view @view, false
494
+ end
495
+
496
+ end
497
+
498
+
499
+ describe 'Ruber::Document#extension' do
500
+
501
+ before do
502
+ @app = KDE::Application.instance
503
+ @comp = DocumentSpecComponentManager.new
504
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return @comp
505
+ @doc = Ruber::Document.new @app
506
+ end
507
+
508
+ it 'calls the extension method of its project' do
509
+ ext = Qt::Object.new
510
+ flexmock(@doc.own_project).should_receive(:extension).once.with(:xyz).and_return ext
511
+ @doc.extension(:xyz).should equal(ext)
512
+ end
513
+
514
+ end
515
+
516
+ describe 'Ruber::Document#file_type_match?' do
517
+
518
+ before do
519
+ @app = KDE::Application.instance
520
+ @comp = DocumentSpecComponentManager.new
521
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return( @comp).by_default
522
+ @doc = Ruber::Document.new @app, __FILE__
523
+ end
524
+
525
+ it 'should return true if both arguments are empty' do
526
+ @doc.file_type_match?( [], []).should be_true
527
+ end
528
+
529
+ it 'should return true if one of the mimetypes match the document\'s mimetype, according to KDE::MimeType#=~' do
530
+ @doc.file_type_match?( %w[image/png application/x-ruby], []).should be_true
531
+ @doc.file_type_match?( %w[image/png =application/x-ruby], []).should be_true
532
+ @doc.file_type_match?( %w[image/png !application/x-ruby], []).should be_false
533
+ @doc.file_type_match?( %w[image/png =text/plain], []).should be_false
534
+ @doc.file_type_match?( %w[image/png !=text/plain], []).should be_true
535
+ end
536
+
537
+ it 'should return true if one of the file patterns specified in the second argument matches the path of the file and false otherwise if the first argument is empty' do
538
+ flexmock(@doc).should_receive(:path).and_return('xyz.rb')
539
+ @doc.file_type_match?([], %w[*.txt *.rb]).should be_true
540
+ @doc.file_type_match?([], %w[*.txt *.py]).should be_false
541
+ @doc.file_type_match?([], %w[*.txt xyz*]).should be_true
542
+ end
543
+
544
+ it 'should do pattern matching even if the file starts with a dot' do
545
+ flexmock(@doc).should_receive(:path).and_return('.xyz.rb')
546
+ @doc.file_type_match?([], %w[*.txt *.rb]).should be_true
547
+ @doc.file_type_match?([], %w[*.txt *.py]).should be_false
548
+ @doc.file_type_match?([], %w[*.txt .xyz*]).should be_true
549
+ end
550
+
551
+ it 'only considers the basename of the file for pattern matching, not the directory name' do
552
+ flexmock(@doc).should_receive(:path).and_return('/home/xyz.abc')
553
+ @doc.file_type_match?([], ['xyz.*']).should be_true
554
+ flexmock(File).should_receive(:fnmatch?).once.with('xyz.*', 'xyz.abc', Integer).and_return(true)
555
+ @doc.file_type_match?([], ['xyz.*'])
556
+ end
557
+
558
+ it 'should always return false when doing pattern matching if the document is not associated with a file' do
559
+ @doc = Ruber::Document.new @app
560
+ @doc.file_type_match?([], %w[*.txt *.rb]).should be_false
561
+ end
562
+
563
+ it 'should return true if at least the mime type or the file name matches and false if both don\'t match, if neither arguments is empty' do
564
+ @doc.file_type_match?(%w[image/png text/plain], %w[*.txt *.py]).should be_true
565
+ @doc.file_type_match?(%w[image/png text/x-python], %w[*.txt *.rb]).should be_true
566
+ @doc.file_type_match?(%w[image/png application/x-ruby], %w[*.txt *.rb]).should be_true
567
+ @doc.file_type_match?(%w[image/png =text/plain], %w[*.txt *.py]).should be_false
568
+ end
569
+
570
+ it 'should accept a single string for any of the arguments, treating empty strings as empty arrays' do
571
+ @doc.file_type_match?( '', '').should be_true
572
+ @doc.file_type_match?( '','*.rb').should be_true
573
+ @doc.file_type_match?( '','*.py').should be_false
574
+ @doc.file_type_match?('application/x-ruby', '').should be_true
575
+ @doc.file_type_match?('text/x-python', '').should be_false
576
+ @doc.file_type_match?('application/x-ruby', '*.py').should be_true
577
+ @doc.file_type_match?('text/x-python', '*.rb').should be_true
578
+ @doc.file_type_match?('text/x-python', '*.png').should be_false
579
+ end
580
+
581
+ end
582
+
583
+ describe 'Ruber::Document#document_save_as' do
584
+
585
+ before do
586
+ @app = KDE::Application.instance
587
+ @w = Qt::Widget.new
588
+ flexmock(Ruber).should_receive(:[]).with(:main_window).and_return(@w).by_default
589
+ @comp = DocumentSpecComponentManager.new
590
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp).by_default
591
+ @projects = flexmock{|m| m.should_receive(:current).and_return(nil).by_default}
592
+ flexmock(Ruber).should_receive(:[]).with(:projects).and_return(@projects).by_default
593
+ @config = flexmock('config')
594
+ @config.should_receive(:[]).with(:general, :default_script_directory).and_return('/').by_default
595
+ flexmock(Ruber).should_receive(:[]).with(:config).and_return(@config).by_default
596
+ @doc = Ruber::Document.new
597
+ #to avoid actually writing the file
598
+ flexmock(@doc.send :internal).should_receive(:saveAs).by_default
599
+ end
600
+
601
+ it 'calls KDE::EncodingFileDialog#get_save_file_name_and_encoding and saves the document with the url and encoding returned by it' do
602
+ # I can't use KDE::EncodingFileDialog::Result for testing because, in ruby,
603
+ # it doesn't allow to set its fields (in C++ it should work, but I didn't try)
604
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
605
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.and_return(res)
606
+ url = KDE::Url.new '/test.rb'
607
+ flexmock(@doc.send :internal).should_receive(:saveAs).once.with url
608
+ @doc.send :document_save_as
609
+ @doc.encoding.should == 'UTF-16'
610
+ end
611
+
612
+ it 'uses the document\'s URL as default directory if the document is associated with a file' do
613
+ flexmock(@doc).should_receive(:path).and_return '/test/xyz'
614
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
615
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.with(String, '/test/xyz', String, Qt::Widget, String).and_return(res)
616
+ @doc.send :document_save_as
617
+ end
618
+
619
+ it 'uses the current project\'s project directory as default directory if there is a current project' do
620
+ prj = flexmock(:project_directory => File.dirname(__FILE__))
621
+ @projects.should_receive(:current).once.and_return prj
622
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
623
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.with(String, File.dirname(__FILE__), String, Qt::Widget, String).and_return(res)
624
+ @doc.send :document_save_as
625
+ end
626
+
627
+ it 'uses UTF-8 as default encoding if running under ruby 1.9 and ISO-8859-1 if running under ruby 1.8' do
628
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
629
+ if RUBY_VERSION.include? '9'
630
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.with('UTF-8', String, String, Qt::Widget, String).and_return(res)
631
+ else
632
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.with('ISO-8859-1', String, String, Qt::Widget, String).and_return(res)
633
+ end
634
+ @doc.send :document_save_as
635
+ end
636
+
637
+ it 'does nothing if the user dismisses the dialog' do
638
+ res = OpenStruct.new(:file_names => [], :encoding => '')
639
+ flexmock(@doc.send :internal).should_receive(:encoding=).never
640
+ flexmock(@doc.send :internal).should_receive(:saveAs).never
641
+ flexmock(@doc.own_project).should_receive(:save).never
642
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.and_return(res)
643
+ @doc.send :document_save_as
644
+ res = OpenStruct.new(:file_names => [''], :encoding => '')
645
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.and_return(res)
646
+ @doc.send :document_save_as
647
+ end
648
+
649
+ it 'saves the document project' do
650
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
651
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.and_return(res)
652
+ flexmock(@doc.own_project).should_receive(:save).once
653
+ @doc.send :document_save_as
654
+ end
655
+
656
+ it 'returns the value returned by the internal KTextEditor::Document saveAs method' do
657
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
658
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).twice.and_return(res)
659
+ flexmock(@doc.send :internal).should_receive(:saveAs).once.and_return true
660
+ @doc.send(:document_save_as).should == true
661
+ flexmock(@doc.send :internal).should_receive(:saveAs).once.and_return false
662
+ @doc.send(:document_save_as).should == false
663
+ end
664
+
665
+ describe 'if the file already exists' do
666
+
667
+ it 'asks the user and does nothing and returns false if he chooses not to save the document' do
668
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
669
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.and_return(res)
670
+ flexmock(File).should_receive(:exist?).once.with('/test.rb').and_return true
671
+ flexmock(KDE::MessageBox).should_receive(:warning_continue_cancel).once.and_return KDE::MessageBox::Cancel
672
+ flexmock(@doc.send :internal).should_receive(:saveAs).never
673
+ flexmock(@doc.send :internal).should_receive(:encoding=).never
674
+ flexmock(@doc.own_project).should_receive(:save).never
675
+ @doc.send(:document_save_as).should == false
676
+ end
677
+
678
+ it 'asks the user and saves the file if he chooses not to overwrite the existin file' do
679
+ res = OpenStruct.new(:file_names => ['/test.rb'], :encoding => 'UTF-16')
680
+ flexmock(KDE::EncodingFileDialog).should_receive(:get_save_file_name_and_encoding).once.and_return(res)
681
+ flexmock(File).should_receive(:exist?).once.with('/test.rb').and_return true
682
+ flexmock(KDE::MessageBox).should_receive(:warning_continue_cancel).once.and_return KDE::MessageBox::Continue
683
+ flexmock(@doc.send :internal).should_receive(:saveAs).once.with KDE::Url.new('/test.rb')
684
+ flexmock(@doc.send :internal).should_receive(:encoding=).with('UTF-16').once
685
+ @doc.send :document_save_as
686
+ end
687
+
688
+ end
689
+
690
+ end
691
+
692
+ describe Ruber::Document do
693
+
694
+ before do
695
+ @app = KDE::Application.instance
696
+ @w = Qt::Widget.new
697
+ @comp = DocumentSpecComponentManager.new
698
+ flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp)
699
+ end
700
+
701
+ describe '#save_settings' do
702
+
703
+ it 'calls the #save method of the project if the document path is not empty' do
704
+ doc = Ruber::Document.new nil, __FILE__
705
+ exp = doc.object_id
706
+ flexmock(doc.own_project).should_receive(:save).once
707
+ doc.save_settings
708
+ end
709
+
710
+ it 'doesn\'t call the #save method of the project if the document path is empty' do
711
+ doc = Ruber::Document.new nil
712
+ flexmock(doc.own_project).should_receive(:save).never
713
+ doc.save_settings
714
+ end
715
+
716
+ end
717
+
718
+ # describe '#shutdown' do
719
+ #
720
+ # before do
721
+ # @app = KDE::Application.instance
722
+ # @w = Qt::Widget.new
723
+ # @comp = DocumentSpecComponentManager.new
724
+ # flexmock(Ruber).should_receive(:[]).with(:components).and_return(@comp)
725
+ # @doc = Ruber::Document.new @app
726
+ # end
727
+ #
728
+ # it 'calls the close_url method passing false' do
729
+ # doc = Ruber::Document.new nil, __FILE__
730
+ # flexmock(doc).should_receive(:close_url).once.with(false)
731
+ # doc.shutdown
732
+ # end
733
+ #
734
+ # it 'emits the "closing(QObject*)" signal' do
735
+ # doc = Ruber::Document.new nil, __FILE__
736
+ # exp = doc.object_id
737
+ # m = flexmock('test'){|mk| mk.should_receive(:document_closing).once.with(exp)}
738
+ # doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
739
+ # doc.shutdown
740
+ # end
741
+ #
742
+ # it 'closes the view, if there\'s one, after emitting the closing signal' do
743
+ # doc = Ruber::Document.new nil, __FILE__
744
+ # v = doc.create_view
745
+ # exp = doc.object_id
746
+ # m = flexmock('test'){|mk| mk.should_receive(:document_closing).once.with(exp).ordered}
747
+ # flexmock(v).should_receive(:close).once.globally.ordered
748
+ # doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
749
+ # doc.shutdown
750
+ # end
751
+ #
752
+ # it 'calls the #shutdown method of the project' do
753
+ # doc = Ruber::Document.new nil
754
+ # exp = doc.object_id
755
+ # flexmock(doc).should_receive(:close_url)
756
+ # flexmock(doc.own_project).should_receive(:shutdown).once
757
+ # doc.shutdown
758
+ # end
759
+ #
760
+ #
761
+ # it 'disconnects any slot/block connected to it after emitting the closing signal' do
762
+ # doc = Ruber::Document.new nil, __FILE__
763
+ # exp = doc.object_id
764
+ # def doc.disconnect *args;end
765
+ # m = flexmock{|mk| mk.should_receive(:document_closing).with(exp).once.ordered}
766
+ # doc.connect(SIGNAL('closing(QObject*)')){|d| m.document_closing d.object_id}
767
+ # flexmock(doc).should_receive(:disconnect).with_no_args.once.ordered
768
+ # doc.shutdown
769
+ # end
770
+ #
771
+ # it 'disposes of itself after emitting the closing signal' do
772
+ # doc = Ruber::Document.new nil, __FILE__
773
+ # doc.shutdown
774
+ # doc.should be_disposed
775
+ # end
776
+ #
777
+ # end
778
+
779
+ end