spackle 0.0.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 (46) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +166 -0
  5. data/Rakefile +49 -0
  6. data/VERSION +1 -0
  7. data/bin/ruby-project-root +14 -0
  8. data/bin/spackle +14 -0
  9. data/bin/spackle-vim-load-quickfix +47 -0
  10. data/bin/spackle-vim-open +49 -0
  11. data/lib/spackle/commandline.rb +53 -0
  12. data/lib/spackle/configuration.rb +37 -0
  13. data/lib/spackle/error.rb +31 -0
  14. data/lib/spackle/helpers/ruby_project_root.rb +34 -0
  15. data/lib/spackle/output/base.rb +44 -0
  16. data/lib/spackle/output/vim_quickfix.rb +7 -0
  17. data/lib/spackle/output.rb +2 -0
  18. data/lib/spackle/spec/base_formatter.rb +22 -0
  19. data/lib/spackle/spec/spackle_formatter.rb +14 -0
  20. data/lib/spackle/spec.rb +1 -0
  21. data/lib/spackle.rb +104 -0
  22. data/spec/integration_spec.rb +84 -0
  23. data/spec/spackle/commandline_spec.rb +48 -0
  24. data/spec/spackle/configuration_spec.rb +43 -0
  25. data/spec/spackle/error_spec.rb +34 -0
  26. data/spec/spackle/output/base_spec.rb +53 -0
  27. data/spec/spackle/output/vim_quickfix_spec.rb +25 -0
  28. data/spec/spackle/spec/base_formatter_spec.rb +15 -0
  29. data/spec/spackle/spec/spackle_formatter_spec.rb +58 -0
  30. data/spec/spackle_error_fixture.rb +10 -0
  31. data/spec/spackle_spec.rb +203 -0
  32. data/spec/spec.opts +1 -0
  33. data/spec/spec_helper.rb +14 -0
  34. data/spec/test_app_helper.rb +55 -0
  35. data/support/vim/spackle.vim +17 -0
  36. data/test_app/lib/error_raiser.rb +7 -0
  37. data/test_app/lib/method_typo.rb +7 -0
  38. data/test_app/lib/missing_end.rb +7 -0
  39. data/test_app/lib/working_class.rb +7 -0
  40. data/test_app/spec/error_raiser_spec.rb +14 -0
  41. data/test_app/spec/failing_working_class_spec.rb +14 -0
  42. data/test_app/spec/method_typo_spec.rb +14 -0
  43. data/test_app/spec/missing_end_spec.rb +13 -0
  44. data/test_app/spec/passing_working_class_spec.rb +14 -0
  45. data/test_app/spec/spec_helper.rb +8 -0
  46. metadata +127 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Rick Lee-Morlang
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,166 @@
1
+ = Spackle
2
+
3
+ <em>Smoothing out the gaps between the Rubyist and the Ruby.</em>
4
+
5
+ Well, honestly, it only fills in the gaps between RSpec and Vim right now,
6
+ but that's a good start. Cucumber support is in the works, and perhaps a
7
+ few other surprises if I make the time.
8
+
9
+ Patches supporting other editors gladly accepted. Most people aren't very
10
+ editor-agnostic, but Spackle doesn't care! (Or, at least, it wouldn't if
11
+ you patched it with support for your amazing editor that's surely better
12
+ than mine.)
13
+
14
+ == Elevator Pitch
15
+
16
+ Spackle tells your editor about the errors in your code. No more need to
17
+ visually scan your test output for errors, filenames, and line numbers.
18
+ Just tell your editor to jump to the next error location.
19
+
20
+ == Features
21
+
22
+ * custom RSpec formatters that generate output compatible with
23
+ Vim's quickfix functionality
24
+ * a simple Vim plugin to allow a quickfix list to be loaded
25
+ from a file
26
+ * shell scripts to glue Spackle's output and Vim together
27
+ * easy to use?
28
+
29
+ == Quick Installation
30
+
31
+ gem install spackle --source http://gemcutter.org
32
+ spackle --install vim # described below
33
+ echo 'Spackle.configuration.set_defaults_for :vim' > ~/.spackle
34
+
35
+ == Configuration and Usage
36
+
37
+ For a tool that doesn't do a heck of alot, it's pretty configurable.
38
+ If it <b>could</b> do something else, it'd be easy to tell it how to do
39
+ it with either a <tt>.spackle</tt> file in your home directory, or a
40
+ <tt>.spackle</tt> file in your project's root directory.
41
+
42
+ If Spackle is useful to you, I'd love to hear about it.
43
+
44
+ === PATH
45
+
46
+ Spackle installs a few utility scripts in the bin directory where
47
+ executables are installed by your system's Rubygems. If you've installed
48
+ Spackle as root, this should be fine. If you've installed Spackle as a
49
+ regular user, you need to make sure the appropriate bin directory is
50
+ in your path.
51
+
52
+ To test your configuration, run +which spackle+ in your terminal. If
53
+ you don't see any output, your PATH variable is not correctly configured
54
+ for use with user-installed gems.
55
+
56
+ See your Rubygems documentation for more information about this.
57
+
58
+ === Spackle dotfile
59
+
60
+ Without a dotfile configured, Spackle won't do anything. This is so
61
+ you can make Spackle a dependency of your project and integrate it
62
+ into your code, yet leave its usage up to each individual developer.
63
+
64
+ Spackle reads its configuration from a <tt>.spackle</tt> file, which it looks
65
+ for in your home directory first, and in the root directory of your
66
+ project second. Spackle configuration in your project directory takes
67
+ precedence over any in your home directory, so you can override global
68
+ settings on a per-project basis if you like.
69
+
70
+ Example <tt>.spackle</tt> for Vim users.
71
+
72
+ Spackle.configure do |c|
73
+ c.set_defaults_for :vim
74
+ end
75
+
76
+ See Spackle::Configuration for more information.
77
+
78
+ === RSpec
79
+
80
+ Add to your spec_helper.rb:
81
+
82
+ require "spackle"
83
+ Spackle.init :with => :spec_formatter
84
+
85
+ Now whenever RSpec runs, Spackle will listen in to your test results and
86
+ relay information about any errors to your editor.
87
+
88
+ === Vim
89
+
90
+ Spackle needs a tiny Vim plugin installed to function properly with Vim.
91
+ Simply run +spackle install vim+ and Spackle will copy its plugin into
92
+ your <tt>.vim/plugins</tt> directory.
93
+
94
+ <b>Optional:</b>
95
+ Spackle also comes with a helper script for invoking Vim with a session
96
+ named after your project's parent directory. It's called <tt>spackle-vim-open</tt>.
97
+ If you'd like to use it, you'll probably want to add an alias to your
98
+ <tt>.profile</tt> or <tt>.bashrc</tt>. Example:
99
+
100
+ alias e='spackle-vim-open'
101
+
102
+ == Architecture
103
+
104
+ Spackle's architecture consists of three components.
105
+
106
+ NOTE: Some of this information looks forward to a future version of Spackle
107
+ that, at the moment, is fictional. So if you go looking for some of the things
108
+ referenced here and you can't find them, that's probably why. (Or it could be
109
+ an error in this document!)
110
+
111
+ Error Parser Adapters
112
+ * integrate with test harnesses like RSpec and Cucumber
113
+ * or integrate with Ruby's standard Error API
114
+ * or parse Ruby's standard backtrace output
115
+ * convert error output into a generic intermediary Spackle::Error format
116
+ * pass the errors to Spackle's core for reformatting and output
117
+ * found in Spackle::Spec, Spackle::Cucumber and Spackle::Ruby
118
+
119
+ Spackle Core
120
+ * glues all the pieces together
121
+ * loads user configuration
122
+ * tries to do as much as it can automagically
123
+ * tries to stay out of your way
124
+ * routes Spackle::Error objects from the Adapters, through an
125
+ Output Formatter, and finally to an output file
126
+ * triggers a callback after every test run that can send error
127
+ information to your editor
128
+
129
+ Output Formatters
130
+ * convert the generic Error format into an output-specific format
131
+ for your callback to handle
132
+ * found in Spackle::Output
133
+
134
+ Spackle's core configuration, tries to do as much automagically as it can,
135
+ and tries to stay out of the way. It aids the models by routing Errors to the
136
+ configured output formatter.
137
+
138
+ == Known Issues
139
+
140
+ * Spackle assumes you're using something UNIXy. If you're not, it likely
141
+ won't work. I have no interest in working on this, but I'll gladly
142
+ pull your patches.
143
+ * Spackle's current implementation only catches test failures from RSpec.
144
+ Other hooks are in the works.
145
+
146
+ == Credits
147
+
148
+ Spackle was inspired by https://wincent.com/blog/running-rspec-specs-from-inside-vim
149
+
150
+ == Note on Patches/Pull Requests
151
+
152
+ This section was generated by Jeweler's boilerplate, but it seems
153
+ pretty sensible.
154
+
155
+ * Fork the project.
156
+ * Make your feature addition or bug fix.
157
+ * Add tests for it. This is important so I don't break it in a
158
+ future version unintentionally.
159
+ * Commit, do not mess with rakefile, version, or history.
160
+ (if you want to have your own version, that is fine but
161
+ bump version in a commit by itself I can ignore when I pull)
162
+ * Send me a pull request. Bonus points for topic branches.
163
+
164
+ == Copyright
165
+
166
+ Copyright (c) 2009 Rick Lee-Morlang. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "spackle"
8
+ gem.summary = %Q{Spackle tells your editor about the errors in your code}
9
+ gem.description = %Q{
10
+ Spackle tells your editor about the errors in your code. No more need to
11
+ visually scan your test output for errors, filenames, and line numbers.
12
+ Just tell your editor to jump to the next error location.
13
+ }
14
+ gem.email = "rick@lee-morlang.com"
15
+ gem.homepage = "http://github.com/rleemorlang/spackle"
16
+ gem.authors = ["Rick Lee-Morlang"]
17
+ gem.add_development_dependency "rspec", ">= 1.2.9"
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
23
+ end
24
+
25
+ require 'spec/rake/spectask'
26
+ Spec::Rake::SpecTask.new(:spec) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.pattern = 'spec/**/*_spec.rb'
34
+ spec.rcov = true
35
+ end
36
+
37
+ task :spec => :check_dependencies
38
+
39
+ task :default => :spec
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "spackle #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ spackle_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(spackle_dir) unless $LOAD_PATH.include?(spackle_dir)
4
+
5
+ require 'spackle/helpers/ruby_project_root'
6
+
7
+ project_root = Spackle::Helpers::RubyProjectRoot.search Dir.pwd
8
+
9
+ if project_root.nil?
10
+ exit 1
11
+ else
12
+ puts project_root
13
+ end
14
+
data/bin/spackle ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ spackle_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(spackle_dir) unless $LOAD_PATH.include?(spackle_dir)
4
+
5
+ require 'spackle'
6
+ require 'spackle/commandline'
7
+
8
+ begin
9
+ Spackle::Commandline.parse ARGV
10
+ rescue => err
11
+ STDERR.puts err.message
12
+ exit 1
13
+ end
14
+
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+ spackle_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(spackle_dir) unless $LOAD_PATH.include?(spackle_dir)
4
+
5
+ require 'spackle/helpers/ruby_project_root'
6
+
7
+ # Load a Vim Quickfix file in an active vim session.
8
+ #
9
+ # Usage:
10
+ # spackle-vim-load-quickfix [servername] quickfix_file
11
+ #
12
+ # If servername is specified, try to use it as the vim
13
+ # server. Otherwise, assume the name for the vim server
14
+ # is the from ruby-project-root -basename, if
15
+ # successful. If no Ruby project root was found, use
16
+ # DEFAULT as the servername.
17
+ #
18
+ # If the server doesn't exist, we'll create a new
19
+ # gvim session.
20
+ #
21
+
22
+ def servername_from_arguments
23
+ ARGV.shift if ARGV.count == 2
24
+ end
25
+
26
+ def servername_from_project_root
27
+ project_root = Spackle::Helpers::RubyProjectRoot.search Dir.pwd
28
+ File.basename(project_root) if project_root
29
+ end
30
+
31
+ def servername
32
+ @servername ||= servername_from_arguments || servername_from_project_root || "DEFAULT"
33
+ end
34
+
35
+ def server_running?
36
+ !`gvim --serverlist`.grep(/#{servername}/i).empty?
37
+ end
38
+
39
+ unless server_running?
40
+ system %{gvim --servername #{servername}}
41
+ sleep 1
42
+ end
43
+
44
+ system %{gvim --servername #{servername} --remote-send "<ESC>" &> /dev/null}
45
+ system %{gvim --servername #{servername} --remote-expr "LoadSpackleQuickfix('#{ARGV.first}')" &> /dev/null}
46
+ system %{gvim --servername #{servername} --remote-send "<ESC><C-W>p" &> /dev/null}
47
+
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+ spackle_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(spackle_dir) unless $LOAD_PATH.include?(spackle_dir)
4
+
5
+ require 'spackle/helpers/ruby_project_root'
6
+
7
+ # Load a Vim Quickfix file in an active vim session.
8
+ #
9
+ # Usage:
10
+ # spackle-vim-load-quickfix [servername] quickfix_file
11
+ #
12
+ # If servername is specified, try to use it as the vim
13
+ # server. Otherwise, assume the name for the vim server
14
+ # is the from ruby-project-root -basename, if
15
+ # successful. If no Ruby project root was found, use
16
+ # DEFAULT as the servername.
17
+ #
18
+ # If the server doesn't exist, we'll create a new
19
+ # gvim session.
20
+ #
21
+
22
+ def servername_from_arguments
23
+ ARGV.count.times do |index|
24
+ if ARGV[index] == "--servername"
25
+ ARGV.delete_at index
26
+ return ARGV.delete_at_index
27
+ end
28
+ end
29
+ nil
30
+ end
31
+
32
+ def servername_from_project_root
33
+ project_root = Spackle::Helpers::RubyProjectRoot.search Dir.pwd
34
+ File.basename(project_root) if project_root
35
+ end
36
+
37
+ def servername
38
+ servername_from_arguments || servername_from_project_root || "DEFAULT"
39
+ end
40
+
41
+ def arguments
42
+ arguments = ['gvim', '--servername', servername]
43
+ unless ARGV.empty?
44
+ arguments << "--remote-silent"
45
+ arguments += ARGV
46
+ end
47
+ end
48
+
49
+ system *arguments
@@ -0,0 +1,53 @@
1
+ require 'optparse'
2
+ require 'fileutils'
3
+
4
+
5
+ module Spackle
6
+ class Commandline
7
+ class << self
8
+ def install(mod)
9
+ case mod.to_sym
10
+ when :vim
11
+ src = File.join(File.dirname(__FILE__), "/../../support/vim/spackle.vim")
12
+ dest = File.expand_path "~/.vim/plugin"
13
+ raise "No such directory #{dest} -- cannot install Vim plugin" unless File.directory?(dest)
14
+ FileUtils.copy src, dest
15
+ puts "spackle.vim installed in #{dest}"
16
+ else
17
+ raise "Unrecognized module '#{mod}' -- cannot install"
18
+ end
19
+ end
20
+
21
+ def show_error(message)
22
+ puts message
23
+ end
24
+
25
+ def parse(options)
26
+ opts = OptionParser.new do |opts|
27
+ opts.banner = "Usage: spackle --install vim\n" +
28
+ " spackle [rubyscript] [args_for_script]"
29
+
30
+ opts.separator " "
31
+ opts.separator "Options:"
32
+
33
+ opts.on("-i", "--install MODULE", "Install a Spackle module.", "Choices: vim") do |mod|
34
+ install(mod)
35
+ end
36
+
37
+ opts.on("-h", "--help", "-?", "this help screen") do
38
+ puts opts
39
+ exit
40
+ end
41
+ end
42
+
43
+ if options.empty?
44
+ puts opts
45
+ else
46
+ opts.parse!(options)
47
+ end
48
+
49
+ raise "Spackle's wrapper mode is not yet implement" unless options.empty?
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ module Spackle
2
+ class Configuration
3
+ # The command to invoke when Spackle finds errors. It will receive
4
+ # a single argument, being the path to the Spackle errors file.
5
+ # If left unspecified, no command is invoked.
6
+ attr_accessor :callback_command
7
+
8
+ # Where to store the Spackle error files. If unspecified, Spackle will
9
+ # default to /tmp
10
+ attr_accessor :tempdir
11
+
12
+ # Which ErrorFormatter class to use when formatting errors. Specified
13
+ # as a symbol or string matching a class in spackle/error_formatters.
14
+ # i.e. config.error_formatter = :vim_quickfix
15
+ attr_accessor :error_formatter
16
+
17
+ # Filename to use when writing the formatted Spackle results. If
18
+ # unspecified, defaults to a filename based on the name of your
19
+ # project's root directory, or "default.spackle" it can't figure out
20
+ # where your root directory is
21
+ attr_accessor :spackle_file
22
+
23
+ # Configure Spackle with defaults. Currently only accepts :vim as an
24
+ # argument.
25
+ def set_defaults_for(mode)
26
+ case mode.to_sym
27
+ when :vim
28
+ self.callback_command = "spackle-vim-load-quickfix"
29
+ self.error_formatter = :vim_quickfix
30
+ else
31
+ raise ArgumentError.new("unknown Spackle mode: '#{mode}'")
32
+ end
33
+ end
34
+
35
+
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ module Spackle
2
+ class BacktraceEntry
3
+ attr_reader :file, :line
4
+ def initialize(file, line)
5
+ @file, @line = file, line
6
+ end
7
+ end
8
+
9
+ class Error
10
+ attr_reader :message, :backtrace
11
+
12
+ def initialize(message)
13
+ @message = message
14
+ @backtrace = []
15
+ yield self if block_given?
16
+ end
17
+
18
+ def add_error(error_or_file, line = nil)
19
+ case error_or_file
20
+ when Error
21
+ @backtrace << error_or_file
22
+ when String
23
+ @backtrace << BacktraceEntry.new(error_or_file, line)
24
+ else
25
+ raise ArgumentError.new("unrecognized error input '#{error_or_file}'. Should be a filename or a Spackle::BacktraceEntry")
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+
@@ -0,0 +1,34 @@
1
+ module Spackle
2
+ module Helpers
3
+ module RubyProjectRoot
4
+ class << self
5
+ # Search recursively from the current working directory up for something
6
+ # that looks like the root directory of a Ruby project.
7
+ #
8
+ # Returns the path to the found project dir, if any. Nil otherwise.
9
+ #
10
+ # Stops looking when it reaches the top of the tree, or the user's
11
+ # home directory.
12
+ #
13
+ # Detects a project dir via any of:
14
+ # * a config/environment.rb file
15
+ # * a spec/spec_helper.rb file
16
+ # * a features/step_definitions directory
17
+ def search(directory)
18
+ directory = File.expand_path(directory)
19
+ while directory != '/'
20
+ return directory if is_project_dir?(directory)
21
+ directory = File.expand_path(directory + '/..')
22
+ end
23
+ nil
24
+ end
25
+
26
+ def is_project_dir?(path)
27
+ File.exists?(File.join(path, "config/environment.rb")) ||
28
+ File.exists?(File.join(path, "spec/spec_helper.rb")) ||
29
+ File.directory?(File.join(path, "features/step_definitions"))
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module Spackle::Output
2
+ # This is the foundation of all Spackle::Output classes, but by itself
3
+ # it does nothing.
4
+ #
5
+ # Using an Output class should be simple:
6
+ # (assuming errors is an Array of Spackle::Error objects)
7
+ # puts Spackle::Output::VimQuickfix.format(errors)
8
+ #
9
+ # The child class (VimQuickfix) only needs to implement the
10
+ # format_backtrace instance method.
11
+ #
12
+ # Spackle::Output::Base is responsible for things like:
13
+ # * iterating over the backtrace collection
14
+ # * making pathnames relative
15
+ # * limiting the number of errors that are output
16
+ # * filtering the backtrace output by filename
17
+ #
18
+ # Spackle::Output::Base interacts with Spackle's Configuration
19
+ #
20
+ # If you're writing your own Output class, it should be quite
21
+ # easy to override some of the Configuration handling if your
22
+ # class requires it.
23
+ #
24
+ class Base
25
+ attr_accessor :error
26
+ def initialize(error = nil)
27
+ self.error = error || Spackle.current_error
28
+ end
29
+
30
+ def formatted_lines
31
+ error.backtrace.map do |bt|
32
+ format_backtrace_line error.message, bt.file, bt.line
33
+ end
34
+ end
35
+
36
+ def format
37
+ formatted_lines.join("\n") + "\n"
38
+ end
39
+
40
+ def self.format(error = nil)
41
+ new(error || Spackle.current_error).format
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,7 @@
1
+ module Spackle::Output
2
+ class VimQuickfix < Base
3
+ def format_backtrace_line(message, file, line)
4
+ "%s:%d: %s" % [ file, line.to_i, message.gsub(/\n/, ' ') ]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ require 'spackle/output/base'
2
+ require 'spackle/output/vim_quickfix'
@@ -0,0 +1,22 @@
1
+ require 'spec/runner/formatter/base_formatter'
2
+
3
+ # This is just a slightly-refactored and cut down version of RSpec's
4
+ # BaseTextFormatter.
5
+
6
+ module Spackle::Spec
7
+ class BaseFormatter < ::Spec::Runner::Formatter::BaseFormatter
8
+ attr_reader :output, :options
9
+ attr_accessor :errors
10
+
11
+ def initialize(options, output)
12
+ # we ignore output, for now
13
+ Spackle.init
14
+ @options = options
15
+ self.errors = []
16
+ end
17
+
18
+ def close
19
+ Spackle.test_finished errors
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ require 'spackle/spec/base_formatter'
2
+
3
+ module Spackle::Spec
4
+ class SpackleFormatter < BaseFormatter
5
+ def example_failed(example, counter, failure)
6
+ error = Spackle::Error.new failure.exception.message
7
+ failure.exception.backtrace.each do |frame|
8
+ file, line = frame.match(/^([^:]+):([0-9]+)/)[1,2]
9
+ error.add_error file, line
10
+ end
11
+ self.errors << error
12
+ end
13
+ end
14
+ end
@@ -0,0 +1 @@
1
+ require 'spackle/spec/spackle_formatter'