Class: Ruber::RSpec::Plugin
- Inherits:
-
Ruber::RubyRunner::RubyRunnerPlugin
- Object
- Qt::Object
- Plugin
- GuiPlugin
- ExternalProgramPlugin
- Ruber::RubyRunner::RubyRunnerPlugin
- Ruber::RSpec::Plugin
- Defined in:
- plugins/rspec/rspec.rb
Overview
Plugin object for the RSpec plugin
Constant Summary
- STARTING_DELIMITER =
The starting delimiter of the data written by the formatter
/^####%%%%####KRUBY_BEGIN$/
- ENDING_DELIMITER =
The ending delimiter of the data written by the formatter
/^####%%%%####KRUBY_END$/
- SWITCH_BEHAVIOUR =
Symbolic values associated with the
rspec/switch_behaviour
settings [:new_tab, :horizontal, :vertical]
Constants inherited from Plugin
Instance Attribute Summary
Attributes inherited from ExternalProgramPlugin
Attributes included from PluginLike
Class Method Summary (collapse)
-
+ (String) find_default_executable
Finds the rspec program to use by default.
Instance Method Summary (collapse)
-
- (nil) change_switch_name(doc)
slot
private
Changes the text of the
Switch to spec
action depending on whether the given document is a spec or code file. -
- (Boolean?) code_file?(file, prj = Ruber[:world].active_project)
Whether or not file is a code file for a given project.
-
- (nil) delayed_initialize
private
Override of PluginLike#delayed_initialize.
-
- (Object) display_exit_message(code, reason)
private
Override of ExternalProgramPlugin#display_exit_message.
-
- (String) file_for_spec(prj, file)
private
The name of the code file associated with a given spec file.
-
- (Plugin) initialize(psf)
constructor
the plugin.
- - (Object) load_settings
-
- (Hash) options(prj)
private
Collects all the options relative to this plugin from a project.
-
- (<Hash, String>) parse_spec_output(str)
private
Parses the output of the spec command.
-
- (nil) process_standard_error(lines)
private
Override of ExternalProgramPlugin#process_standard_error.
-
- (nil) process_standard_output(lines)
private
Override of ExternalProgramPlugin#process_standard_output.
-
- (nil) run_all
slot
private
Runs all the specs for the project.
-
- (Boolean) run_current(what = :all)
slot
private
Runs the specs corresponding to the current file.
-
- (Boolean) run_current_document
slot
private
Runs the specs corresponding to the current file.
-
- (Boolean) run_current_line
slot
private
Runs the example(s) in the current line.
-
- (Boolean) run_rspec(files, opts, autosave_opts = {}, &blk)
Runs rspec for the given files.
-
- (Boolean) run_rspec_for(origin, opts, autosave_opts = {}, &blk)
private
Runs the spec command for the given object.
-
- (Boolean?) spec_file?(file, prj = Ruber[:world].active_project)
Whether or not a file is a spec file for a given project.
- - (Object) spec_for_pattern(pattern, file)
-
- (<String>) specs_for_file(opts, file)
private
Determines all possible specs files associated with a code file.
-
- (EditorView?) switch
slot
private
Slot associated with the
Switch
action.
Methods inherited from Ruber::RubyRunner::RubyRunnerPlugin
#interpreter_for, #option_for, #ruby_command_for
Methods inherited from ExternalProgramPlugin
#do_stderr, #do_stdout, #failed_to_start, #run_process, #shutdown, #slot_process_finished, #stop_process
Methods inherited from GuiPlugin
#action_collection, #execute_action, #register_action_handler, #setup_actions, #unload
Methods inherited from Plugin
Methods included from PluginLike
#add_extensions_to_project, #add_options_to_project, #add_widgets_to_project, #create_tool_widget, #initialize_plugin, #plugin_name, #query_close, #register_options, #register_with_project, #remove_extensions_from_project, #remove_from_project, #remove_options_from_project, #remove_widgets_from_project, #restore_session, #save_settings, #session_data, #setup_action, #setup_actions, #shutdown, #unload, #update_project
Signal Summary
API for feature rspec
Methods API
Constructor Details
- (Plugin) initialize(psf)
the plugin
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'plugins/rspec/rspec.rb', line 110 def initialize psf super psf, :rspec, {:scope => [:global]}, nil, false Ruber[:autosave].register_plugin self, true @formatter = File.join File.dirname(__FILE__), 'ruber_rspec_formatter' self.connect(SIGNAL('process_finished(int, QString)')){Ruber[:main_window].set_state 'rspec_running', false} Ruber[:main_window].set_state 'rspec_running', false switch_prc = Proc.new{|states| states['active_project_exists'] and states['current_document']} register_action_handler 'rspec-switch', &switch_prc register_action_handler 'rspec-run_all' do |states| states['active_project_exists'] and !states['rspec_running'] end current_prc = Proc.new do |states| states['active_project_exists'] and states['current_document'] and !states['rspec_running'] end register_action_handler 'rspec-run_current', ¤t_prc register_action_handler 'rspec-run_current_line', ¤t_prc connect Ruber[:main_window], SIGNAL('current_document_changed(QObject*)'), self, SLOT('change_switch_name(QObject*)') Ruber[:components].connect(SIGNAL('feature_loaded(QString, QObject*)')) do |f, o| o.register_plugin self, true if f == 'autosave' end @output_widget = @widget end |
Class Method Details
+ (String) find_default_executable
Finds the rspec program to use by default
It looks for an executable called rspec
or spec
(this is to support both RSpec
1 and 2) in PATH
(using the which
command).
if no rspec program was found
95 96 97 98 99 100 101 |
# File 'plugins/rspec/rspec.rb', line 95 def self.find_default_executable path = Open3.popen3('which rspec'){|stdin, stdout, stderr| stdout.read}.strip if path.empty? path = Open3.popen3('which spec'){|stdin, stdout, stderr| stdout.read}.strip end path end |
Instance Method Details
- (nil) change_switch_name(doc) (private)
Changes the text of the Switch to spec
action depending on whether the given
document is a spec or code file
This method is usually called in response to the MainWindow#current_document_changed signal.
529 530 531 532 533 534 535 536 537 |
# File 'plugins/rspec/rspec.rb', line 529 def change_switch_name doc prj = Ruber[:world].active_project return unless doc and prj if prj.extension(:rspec).spec_file? doc.path then text = 'Switch to &Code' else text = 'Switch to &Spec' end action_collection.action('rspec-switch').text = i18n(text) nil end |
Slot Signature:
change_switch_name(QObject*)
- (Boolean?) code_file?(file, prj = Ruber[:world].active_project)
Whether or not file is a code file for a given project
It uses the rspec/spec_directory
and rspec/spec_pattern
options from the project
to find out whether the file is a spec file or not.
166 167 168 169 |
# File 'plugins/rspec/rspec.rb', line 166 def code_file? file, prj = Ruber[:world].active_project return nil unless prj prj.extension(:rspec).code_file? file end |
- (nil) delayed_initialize (private)
Override of PluginLike#delayed_initialize
It sets the text of the Switch
action depending on whether the current document
(if any) is or not a spec file.
This can’t be done from the #initialize method because project options haven’t already been added when that method is called.
236 237 238 239 240 |
# File 'plugins/rspec/rspec.rb', line 236 def delayed_initialize doc = Ruber[:main_window].current_document change_switch_name doc if doc nil end |
- (Object) display_exit_message(code, reason) (private)
Override of ExternalProgramPlugin#display_exit_message
It works as the base class’s method except when the program exits successfully, in which case it does nothing.
See ExternalProgramPlugin#display_exit_message for the meaning of the parameters
514 515 516 |
# File 'plugins/rspec/rspec.rb', line 514 def code, reason super unless reason.empty? end |
- (String) file_for_spec(prj, file) (private)
The name of the code file associated with a given spec file
To find out which code file is associated with the given spec file, this method
takes all the project files and constructs the file names of all the specs associated
to them according to the rspec/spec_pattern
project option. As soon as one of
the generated file names matches the given spec file, the generating file is returned.
to the settings contained in prj.
498 499 500 501 502 |
# File 'plugins/rspec/rspec.rb', line 498 def file_for_spec prj, file pattern = prj[:spec_pattern] opts = prj prj.project_files.abs.find{|f| specs_for_file( opts, f).include? file} end |
- (Object) load_settings
240 241 242 243 |
# File 'plugins/rspec/rspec.rb', line 240 def load_settings super emit settings_changed end |
- (Hash) options(prj) (private)
Collects all the options relative to this plugin from a project
Note: never use destructive methods on the values contained in this hash. Doing so will change the options stored in the project, which most likely isn’t what you want. If you need to change the options, make duplicates of the values
between options and entries in this hash is the following:
:rspec/executable
→:spec
:rspec/options
→:spec_options
:rspec/spec_directory
→:specs_dir
:rspec/spec_files
→:filter
:rspec/spec_pattern
→:pattern
:rspec/full_backtraces
→:full_backtraces
Besides, the above entries, the hash also contains a :dir
entry which contains
the project directory.
428 429 430 431 432 433 434 435 436 437 |
# File 'plugins/rspec/rspec.rb', line 428 def prj res = {} res[:spec] = prj[:rspec, :executable] res[:spec_options] = prj[:rspec, :options] res[:specs_dir] = prj[:rspec, :spec_directory, :absolute] res[:filter] = prj[:rspec, :spec_files] res[:dir] = prj.project_directory res[:full_backtraces] = prj[:rspec, :full_backtraces] res end |
- (<Hash, String>) parse_spec_output(str) (private)
Parses the output of the spec command
This method only works if the Ruber rspec formatter is used.
The output is split according in regions between STARTING_DELIMITER and ENDING_DELIMITER. All text inside these regions is considered the YAML dump of a hash and converted back to a hash. All text which is not between a pair of delimiters, as well as the text which can’t be converted by YAML is left as is parsed by YAML is stored as a hash, while the rest is stored as strings. Order is preserved.
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'plugins/rspec/rspec.rb', line 287 def parse_spec_output str sc = StringScanner.new str res = [] until sc.eos? match = sc.scan_until(STARTING_DELIMITER) || sc.rest found = match.sub!(STARTING_DELIMITER, '') res << match if found yaml = sc.scan_until(ENDING_DELIMITER) || sc.rest yaml.sub! ENDING_DELIMITER, '' res << (YAML.load(yaml) rescue yaml) else sc.terminate end end res end |
- (nil) process_standard_error(lines) (private)
Override of ExternalProgramPlugin#process_standard_error
267 268 269 270 |
# File 'plugins/rspec/rspec.rb', line 267 def process_standard_error lines @widget.model.insert_lines lines, :output1, nil nil end |
- (nil) process_standard_output(lines) (private)
Override of ExternalProgramPlugin#process_standard_output
It parses the output from the spec program (generated with the Ruber rspec formatter) and displays the data it contains appropriately.
252 253 254 255 256 257 258 259 260 |
# File 'plugins/rspec/rspec.rb', line 252 def process_standard_output lines items = parse_spec_output lines.join "\n" items.each do |it| if it.is_a? String then @widget.model.insert_lines it, :output, nil else @widget.display_example it end end nil end |
- (nil) run_all (private)
Runs all the specs for the project.
308 309 310 311 312 313 314 315 316 317 318 |
# File 'plugins/rspec/rspec.rb', line 308 def run_all prj = Ruber[:world].active_project unless prj KDE::MessageBox.error nil, "You must have an open project to choose this entry.\nYOU SHOULD NEVER SEE THIS MESSAGE" return end opts = prj opts[:files] = Dir.glob File.join(opts[:specs_dir], '**', opts[:filter]) run_rspec_for prj, opts, :files => :project_files, :on_failure => :ask, :message => 'Do you want to run the tests all the same?' nil end |
Slot Signature:
run_all()
- (Boolean) run_current(what = :all) (private)
Runs the specs corresponding to the current file
If the current file is a code file, the corresponding spec file will be run. If it is a spec file, the file itself will be run.
To decide whether the current file is a spec or a code file, this method uses
the patters stored in the rspec/spec_pattern
project setting to build the names
of the spec files associated with the current file, which is assumed to be a code
file. If none of these files exist, then the current file is treated as a spec file,
otherwise one of the spec files thus generated is run.
Note: the way this method works implies that if it is called on a code file which doesn’t have an associated spec file, rspec will be run on that file, which, most likely, will cause it to fail.
(including the case when the process was already running or autosaving failed)
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'plugins/rspec/rspec.rb', line 339 def run_current what = :all prj = Ruber[:world].active_project unless prj KDE::MessageBox.error nil, "You must have an open project to choose this entry.\nYOU SHOULD NEVER SEE THIS MESSAGE" return end opts = prj view = Ruber[:main_window].active_editor doc = view.document unless doc.url.local_file? KDE::MessageBox.sorry nil, 'You can\'t run rspec for remote files' return end unless doc KDE::MessageBox.error nil, "You must have an open editor to choose this entry.\nYOU SHOULD NEVER SEE THIS MESSAGE" return end files = specs_for_file opts, doc.path files.reject!{|f| !File.exist? f} opts[:files] = files.empty? ? [doc.path] : files if what == :current_line line = view.cursor_position.line + 1 opts[:spec_options] += ["-l", line.to_s] end run_rspec_for prj, opts, :files => :documents_with_file, :on_failure => :ask, :message => 'Do you want to run the tests all the same?' end |
Slot Signature:
run_current()
- (Boolean) run_current_document (private)
Runs the specs corresponding to the current file
If the current file is a code file, the corresponding spec file will be run. If it is a spec file, the file itself will be run.
To decide whether the current file is a spec or a code file, this method uses
the patters stored in the rspec/spec_pattern
project setting to build the names
of the spec files associated with the current file, which is assumed to be a code
file. If none of these files exist, then the current file is treated as a spec file,
otherwise one of the spec files thus generated is run.
Note: the way this method works implies that if it is called on a code file which doesn’t have an associated spec file, rspec will be run on that file, which, most likely, will cause it to fail.
(including the case when the process was already running or autosaving failed)
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'plugins/rspec/rspec.rb', line 372 def run_current_document doc = Ruber[:world].active_document unless doc raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active document" end prj = Ruber[:world].active_project unless doc raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active project" end opts = prj ext = prj.extension(:rspec) if doc.path.empty? KDE::MessageBox.sorry nil, KDE.i18n("You must save the document to a file before running rspec on it") return elsif ext.spec_file? doc.path opts[:files] = [doc.path] elsif ext.code_file?(doc.path) opts[:files] = ext.specs_for_code doc.path end run_rspec_for prj, opts, :files => :documents_with_file, :on_failure => :ask, :message => 'Do you want to run the tests all the same?' end |
Slot Signature:
run_current_document()
- (Boolean) run_current_line (private)
Runs the example(s) in the current line
Similar to #run_current, but tells spec to run only the example or example group corresponding to the line where the cursor is (using spec’s -l option). Besides, unlike #run_current, this method can only be called when the current file is the example file, not the source.
(including the case when the process was already running or autosaving failed)
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'plugins/rspec/rspec.rb', line 378 def run_current_line doc = Ruber[:world].active_document unless doc raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active document" end prj = Ruber[:world].active_project unless doc raise "It shouldn't be possible to call #{self.class}#run_current_document when there's no active project" end opts = prj ext = prj.extension(:rspec) if doc.path.empty? KDE::MessageBox.sorry nil, KDE.i18n("You must save the document to a file before running rspec on it") return elsif ext.spec_file? doc.path view = Ruber[:main_window].active_editor elsif ext.code_file?(doc.path) specs = ext.specs_for_code doc.path view = Ruber[:world].active_environment.views.find do |v| specs.include? v.document.path end unless view KDE::MessageBox.sorry nil, KDE.i18n('You don\'t have any spec file for %s opened. Without it it\'s impossible to find out what the current line is', doc.path) return end doc = view.document end opts[:files] = [view.document.path] line = view.cursor_position.line + 1 opts[:spec_options] += ["-l", line.to_s] run_rspec_for prj, opts, :files => :documents_with_file, :on_failure => :ask, :message => 'Do you want to run the tests all the same?' end |
Slot Signature:
run_current_line()
- (Boolean) run_rspec(files, opts, autosave_opts = {}, &blk)
Runs rspec for the given files
The output of spec is displayed in the associated output widget.
Files are autosaved before running rspec.
If spec is already running, or if autosaving fails, noting is done.
passed to autosave
to use the options to pass to the ruby interpreter program to the spec program
It has the same meaning as second parameter to Autosave::AutosavePlugin#autosave. If it’s nil, autosave won’t be used as first argument to Autosave::AutosavePlugin#autosave (including the case when the process was already running or autosaving failed)
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'plugins/rspec/rspec.rb', line 192 def run_rspec files, opts, autosave_opts = {}, &blk default_opts = { :ruby => Ruber[:config][:ruby, :ruby], :ruby_options => Ruber[:config][:ruby, :ruby_options], :spec => 'spec', :spec_options => [], :dir => '.' } opts = default_opts.merge opts return false if @process.state != Qt::Process::NotRunning @widget.clear_output files = files.select{|f| File.exist? f} if autosave_opts[:files] plug = autosave_opts[:plugin] || self what = autosave_opts[:files] return false unless Ruber[:autosave].autosave plug, what, autosave_opts, &blk end full_backtraces = opts[:full_backtraces] ? %w[-b] : [] args = [opts[:spec]] + %W[-r #{@formatter} -f Ruber::RSpec::Formatter] + opts[:spec_options] + full_backtraces + files @widget.working_directory = opts[:dir] @display_standard_error = opts[:stderr] Ruber[:main_window].activate_tool(@widget) Ruber[:main_window].change_state 'rspec_running', true title = ([opts[:spec].split('/')[-1]] + opts[:spec_options]+ full_backtraces + files).join ' ' run_process opts[:ruby], opts[:dir], opts[:ruby_options] + args, title @widget.model.item(0,0).tool_tip = ([opts[:ruby]] + opts[:ruby_options] + args).join " " true end |
- (Boolean) run_rspec_for(origin, opts, autosave_opts = {}, &blk) (private)
Runs the spec command for the given object
It works like RubyRunner::RubyRunnerPlugin#ruby_command_for but already takes care of the user’s settings regarding the path of the spec program.
of RubyRunner::RubyRunnerPlugin#option_for meaning as the opts argument to #run_rspec, but can also contain an additional entry (see below) (including the case when the process was already running or autosaving failed)
401 402 403 404 405 406 |
# File 'plugins/rspec/rspec.rb', line 401 def run_rspec_for origin, opts, autosave_opts = {}, &blk process.kill ruby, *cmd = ruby_command_for origin, opts[:dir] opts = {:ruby => ruby, :ruby_options => cmd}.merge opts run_rspec opts[:files], opts, autosave_opts, &blk end |
- (Boolean?) spec_file?(file, prj = Ruber[:world].active_project)
Whether or not a file is a spec file for a given project
It uses the rspec/spec_directory
and rspec/spec_pattern
options from the project
to find out whether the file is a spec file or not.
147 148 149 150 |
# File 'plugins/rspec/rspec.rb', line 147 def spec_file? file, prj = Ruber[:world].active_project return nil unless prj prj.extension(:rspec).spec_file? file end |
- (Object) spec_for_pattern(pattern, file)
245 246 247 248 249 250 251 252 253 254 |
# File 'plugins/rspec/rspec.rb', line 245 def spec_for_pattern pattern, file spec = pattern[:spec].gsub(/%f/, File.basename(file, '.rb')) dir = File.dirname(file) dir_parts = dir.split '/' spec.gsub! %r{%d\d+} do |str| dir_parts[str[2..-1].to_i-1] || '' end spec.gsub! %r{%d}, dir spec end |
- (<String>) specs_for_file(opts, file) (private)
Determines all possible specs files associated with a code file
The names of the possible spec files are obtained replacing the %f
tag in each
entry of the rspec/pattern
setting with the name of the file (without checking
whether the files actually exist).
479 480 481 482 483 |
# File 'plugins/rspec/rspec.rb', line 479 def specs_for_file opts, file file = File.basename file, '.rb' res = opts[:pattern].map{|i| File.join opts[:specs_dir], i.gsub('%f', file)} res end |
- (EditorView?) switch (private)
this method assumes that both the current project and a current document exist
Slot associated with the Switch
action
Displays the spec or code file associated with the current document, according to whether the current document is a code or spec file respectively.
It does nothing if the file corresponding to the current document isn’t found
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 |
# File 'plugins/rspec/rspec.rb', line 452 def switch file = Ruber[:main_window].current_document.path prj = Ruber[:world].active_project ext = prj.extension(:rspec) if ext.spec_file? file then ;switch_to = ext.code_for_spec file else switch_to = ext.specs_for_code(file)[0] end if switch_to and File.exist? switch_to behaviour = Ruber[:config][:rspec, :switch_behaviour] if behaviour != :new_tab hints = {:strategy => :current_tab, :existing => :current_tab, :split => SWITCH_BEHAVIOUR[behaviour], :new => :current_tab} else hints = {} end Ruber[:main_window].display_document switch_to, hints end end |
Slot Signature:
switch()
Signal Details
- settings_changed