spectator-emacs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +2 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.rdoc +4 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +54 -0
- data/LICENSE.txt +20 -0
- data/README.md +155 -0
- data/Rakefile +52 -0
- data/bin/spectator-emacs +40 -0
- data/lib/spectator/emacs/version.rb +6 -0
- data/lib/spectator/emacs.rb +460 -0
- data/spec/emacs_spec.rb +8 -0
- data/spec/lib/spectator/emacs_spec.rb +68 -0
- data/spec/spec_helper.rb +5 -0
- data/spectator-emacs.gemspec +44 -0
- metadata +238 -0
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-f RspecOrgFormatter
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-m markdown
|
data/ChangeLog.rdoc
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
spectator-emacs (0.1.0)
|
5
|
+
docopt
|
6
|
+
open4
|
7
|
+
rb-inotify (~> 0.8.8)
|
8
|
+
rspec
|
9
|
+
spectator (~> 1.2)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: http://rubygems.org/
|
13
|
+
specs:
|
14
|
+
diff-lcs (1.1.3)
|
15
|
+
docopt (0.5.0)
|
16
|
+
ffi (1.3.1)
|
17
|
+
json (1.7.6)
|
18
|
+
listen (0.7.2)
|
19
|
+
notify (0.4.0)
|
20
|
+
open4 (1.3.0)
|
21
|
+
rb-inotify (0.8.8)
|
22
|
+
ffi (>= 0.5.0)
|
23
|
+
rdoc (3.12)
|
24
|
+
json (~> 1.4)
|
25
|
+
redcarpet (2.2.2)
|
26
|
+
rspec (2.12.0)
|
27
|
+
rspec-core (~> 2.12.0)
|
28
|
+
rspec-expectations (~> 2.12.0)
|
29
|
+
rspec-mocks (~> 2.12.0)
|
30
|
+
rspec-core (2.12.2)
|
31
|
+
rspec-expectations (2.12.1)
|
32
|
+
diff-lcs (~> 1.1.3)
|
33
|
+
rspec-mocks (2.12.2)
|
34
|
+
rspec_org_formatter (0.2.2)
|
35
|
+
rspec (>= 2.6.0)
|
36
|
+
rubygems-tasks (0.2.3)
|
37
|
+
spectator (1.2.6)
|
38
|
+
listen
|
39
|
+
notify
|
40
|
+
term-ansicolor
|
41
|
+
term-ansicolor (1.0.7)
|
42
|
+
yard (0.8.3)
|
43
|
+
|
44
|
+
PLATFORMS
|
45
|
+
ruby
|
46
|
+
|
47
|
+
DEPENDENCIES
|
48
|
+
rdoc (~> 3.0)
|
49
|
+
redcarpet
|
50
|
+
rspec (~> 2.4)
|
51
|
+
rspec_org_formatter
|
52
|
+
rubygems-tasks (~> 0.2)
|
53
|
+
spectator-emacs!
|
54
|
+
yard
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Alessandro Piras
|
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.md
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
# spectator-emacs
|
2
|
+
|
3
|
+
* [Homepage](https://github.com/laynor/spectator-emacs#readme)
|
4
|
+
* [Issues](https://github.com/laynor/spectator-emacs/issues)
|
5
|
+
* [Documentation](http://rubydoc.info/gems/spectator-emacs/frames)
|
6
|
+
* Email [mailto:laynor at gmail.com]
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
`spectator-emacs` is a [Spectator][spectator]
|
11
|
+
extension that provides discreet notificatoins in the Emacs modeline,
|
12
|
+
via the [Enotify][enotify] Emacs notification
|
13
|
+
system.
|
14
|
+
|
15
|
+
The RSpec output is displayed in an emacs buffer, and using the
|
16
|
+
[RSpec Org Formatter][RSpecOrgFormatter],
|
17
|
+
they are nicely formatted as an org-mode file. Minimize your switching
|
18
|
+
from Emacs to the shell or the browser to just display the test
|
19
|
+
results!
|
20
|
+
|
21
|
+
If you hate growl-style popups and prefer a simple green/red
|
22
|
+
(customizable!) indicator on the modeline, spectator-emacs is for you.
|
23
|
+
|
24
|
+
## Features
|
25
|
+
|
26
|
+
* Notifications on the emacs modeline
|
27
|
+
* Short summary report on mouse-over in the modeline indicator
|
28
|
+
* Easily switch to the results buffer with just a click on the
|
29
|
+
modeline indicator
|
30
|
+
* Org formatted RSpec results with the aid of RSpec Org Formatter
|
31
|
+
* Summary extraction can be customized to work with different RSpec
|
32
|
+
output formats
|
33
|
+
* all the features offered by Spectator
|
34
|
+
|
35
|
+
## Install
|
36
|
+
```
|
37
|
+
$ gem install spectator-emacs
|
38
|
+
```
|
39
|
+
## Examples
|
40
|
+
|
41
|
+
To run `spectator-emacs`, just run it!
|
42
|
+
```
|
43
|
+
$ spectator-emacs
|
44
|
+
```
|
45
|
+
To customize it, create a .spectator-emacs file in your project root.
|
46
|
+
You can customize various aspects of how spectator-emacs works:
|
47
|
+
|
48
|
+
* Enotify host (default: localhost)
|
49
|
+
* Enotify port (default: 5000)
|
50
|
+
* The notification message that will appear on the emacs modeline
|
51
|
+
(default: 'F' for failures, 'P' for pending, 'S' for success)
|
52
|
+
* The notification faces used to display the icons in the modeline
|
53
|
+
(default: `enotify-success-face` for success,
|
54
|
+
`enotify-failure-face`for failures, `enotify-warning-face` for
|
55
|
+
success with pending examples)
|
56
|
+
* The Enotify slot id to register for notifications
|
57
|
+
|
58
|
+
An example `.spectator-emacs' file:
|
59
|
+
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
require 'spectator/emacs'
|
63
|
+
|
64
|
+
@runner = Spectator::ERunner.new(:enotify_port => 5001,
|
65
|
+
:notification_messages => {
|
66
|
+
:failure => "failure",
|
67
|
+
:success => "success",
|
68
|
+
:pending => "pending"
|
69
|
+
},
|
70
|
+
:slot_id => "project foobar"
|
71
|
+
:notification_face => {
|
72
|
+
:pending => :font_lock_warning_face,
|
73
|
+
# see the docs for detail on Symbol#keyword
|
74
|
+
:success => :success.keyword,
|
75
|
+
:failure => :failure
|
76
|
+
}) do |runner|
|
77
|
+
# This code will be executed before entering the main loop.
|
78
|
+
|
79
|
+
def format_summary(examples, failures, pending)
|
80
|
+
summary = "#{examples} examples"
|
81
|
+
summary << ", #{failures} failures" if failures > 0
|
82
|
+
summary << ", #{pending} pending" if pending > 0
|
83
|
+
summary << "."
|
84
|
+
summary
|
85
|
+
end
|
86
|
+
|
87
|
+
# The default summary extraction method works with
|
88
|
+
# the standard documentation formatter, or any formatter
|
89
|
+
# that puts the summary on the last line and with the
|
90
|
+
# same format of the documentation formatter.
|
91
|
+
# It uses the helper function
|
92
|
+
# Spectator::Spec#extract_rspec_stats, which can be
|
93
|
+
# useful if the summary is expressed with the same
|
94
|
+
# pattern but on a line other than the last.
|
95
|
+
# For example, the RSpecOrgFormatter puts the summary on
|
96
|
+
# the 6th-last line.
|
97
|
+
#
|
98
|
+
def extract_rspec_org_summary(output)
|
99
|
+
runner.extract_rspec_stats(output, -6)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Suppose rspec is using a custom formatter that
|
103
|
+
# puts the summary in a format in the last lines
|
104
|
+
# with a format like the following:
|
105
|
+
#
|
106
|
+
# Examples: 123
|
107
|
+
# Errors: 12
|
108
|
+
# Pending: 2
|
109
|
+
#
|
110
|
+
def runner.extract_rspec_summary(output)
|
111
|
+
summary_lines = summary[-3..-1]
|
112
|
+
examples = summary[-3].split(':')[1].to_i
|
113
|
+
errors = summary[-2].split(':')[1].to_i
|
114
|
+
pending = summary[-1].split(':')[1].to_i
|
115
|
+
stats = {
|
116
|
+
:examples => examples,
|
117
|
+
:failures => failures,
|
118
|
+
:pending => pending,
|
119
|
+
:summary => format_summary(examples, failures, pending)
|
120
|
+
}
|
121
|
+
stats.merge(:status => rspec_status(stats))
|
122
|
+
stats
|
123
|
+
end
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
## Requirements
|
130
|
+
|
131
|
+
`spectator-emacs` requires a working Emacs installation. You need to
|
132
|
+
install [Enotify][enotify], which can be found in the [MELPA][melpa]
|
133
|
+
repository.
|
134
|
+
|
135
|
+
You also need to load the `enotify-spectator-emacs` Enotify plugin.
|
136
|
+
|
137
|
+
Put this in your .emacs:
|
138
|
+
|
139
|
+
```lisp
|
140
|
+
(require 'enotify)
|
141
|
+
(enotify-minor-mode t)
|
142
|
+
(add-to-list 'load-path "path/to/enotify-spectator-emacs")
|
143
|
+
(require 'enotify-spectator-emacs)
|
144
|
+
```
|
145
|
+
|
146
|
+
## Copyright
|
147
|
+
|
148
|
+
Copyright (c) 2013 Alessandro Piras
|
149
|
+
|
150
|
+
See LICENSE.txt for details.
|
151
|
+
|
152
|
+
[enotify]:http://github.com/laynor/enotify
|
153
|
+
[spectator]:http://github.com/elia/spectator
|
154
|
+
[RSpecOrgFormatter]:http://github.org/laynor/rspec_org_formatter
|
155
|
+
[melpa]:http://melpa.milkbox.net/
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'yard'
|
7
|
+
$:.unshift 'lib'
|
8
|
+
begin
|
9
|
+
gem 'rubygems-tasks', '~> 0.2'
|
10
|
+
require 'rubygems/tasks'
|
11
|
+
|
12
|
+
Gem::Tasks.new
|
13
|
+
rescue LoadError => e
|
14
|
+
warn e.message
|
15
|
+
warn "Run `gem install rubygems-tasks` to install Gem::Tasks."
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
gem 'rdoc', '~> 3.0'
|
20
|
+
require 'rdoc/task'
|
21
|
+
|
22
|
+
RDoc::Task.new do |rdoc|
|
23
|
+
rdoc.title = "spectator-emacs"
|
24
|
+
end
|
25
|
+
rescue LoadError => e
|
26
|
+
warn e.message
|
27
|
+
warn "Run `gem install rdoc` to install 'rdoc/task'."
|
28
|
+
end
|
29
|
+
task :doc => :rdoc
|
30
|
+
|
31
|
+
begin
|
32
|
+
gem 'rspec', '~> 2.4'
|
33
|
+
require 'rspec/core/rake_task'
|
34
|
+
|
35
|
+
RSpec::Core::RakeTask.new
|
36
|
+
rescue LoadError => e
|
37
|
+
task :spec do
|
38
|
+
abort "Please run `gem install rspec` to install RSpec."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :spec
|
43
|
+
task :default => :spec
|
44
|
+
|
45
|
+
desc "Run spectator-emacs"
|
46
|
+
task :'spectator-emacs' do
|
47
|
+
load "bin/spectator-emacs"
|
48
|
+
end
|
49
|
+
|
50
|
+
## YARD stuff
|
51
|
+
YARD::Rake::YardocTask.new
|
52
|
+
CLOBBER.include('doc', '.yardoc')
|
data/bin/spectator-emacs
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/env/bin ruby
|
2
|
+
|
3
|
+
require 'spectator/emacs'
|
4
|
+
require 'docopt'
|
5
|
+
CONFIGFILE = '.spectator-emacs'
|
6
|
+
THISFILE = File.basename __FILE__
|
7
|
+
doc = <<DOCOPT
|
8
|
+
Listen to file changes and run RSpec, sending notifications to Emacs via Enotify.
|
9
|
+
|
10
|
+
Usage:
|
11
|
+
#{THISFILE} [--config <filename>]
|
12
|
+
#{THISFILE} -h | --help
|
13
|
+
#{THISFILE} --version
|
14
|
+
|
15
|
+
Options:
|
16
|
+
-h --help Show this screen.
|
17
|
+
--config <filename> Configuration file to read [default: .spectator-emacs]
|
18
|
+
--version Show version.
|
19
|
+
|
20
|
+
DOCOPT
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'pp'
|
24
|
+
args = Docopt::docopt(doc, :version => Spectator::Emacs::VERSION)
|
25
|
+
config_file = args['--config']
|
26
|
+
pp args
|
27
|
+
if File.exists? config_file
|
28
|
+
content = File.read(config_file)
|
29
|
+
eval(content) if not content.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
@runner ||= Spectator::ERunner.new
|
33
|
+
rescue Docopt::Exit => e
|
34
|
+
puts e.message
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# Local Variables:
|
39
|
+
# mode: ruby
|
40
|
+
# End:
|
@@ -0,0 +1,460 @@
|
|
1
|
+
require 'spectator/emacs/version'
|
2
|
+
require 'spectator'
|
3
|
+
require 'socket'
|
4
|
+
require 'open4'
|
5
|
+
|
6
|
+
class Object
|
7
|
+
# Returns a string representing the object as a lisp sexp.
|
8
|
+
def to_lisp
|
9
|
+
to_s
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Symbol
|
14
|
+
# Returns a string that represents the symbol as a lisp
|
15
|
+
# symbol. Underscores are converted to dashes.
|
16
|
+
#
|
17
|
+
# Example:
|
18
|
+
#
|
19
|
+
# ```
|
20
|
+
# :foo_bar.to_lisp => 'foo-bar'
|
21
|
+
# ```
|
22
|
+
def to_lisp
|
23
|
+
to_s.gsub "_", "-"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns a symbol with the same name prefixed by a colon. This is
|
27
|
+
# convenient when converting a symbol with the {#to_lisp} method.
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
#
|
31
|
+
# ```
|
32
|
+
# :foo_bar.keyword.to_lisp => ':foo-bar'
|
33
|
+
# ```
|
34
|
+
def keyword
|
35
|
+
if self[0] == ':'
|
36
|
+
self
|
37
|
+
else
|
38
|
+
":#{to_s}".to_sym
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class String
|
44
|
+
# Returns a string that represents a lisp string.
|
45
|
+
# This is basically just an alias for {String#inspect}
|
46
|
+
def to_lisp
|
47
|
+
inspect
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Array
|
52
|
+
# Returns a string that represents the array as a lisp list.
|
53
|
+
#
|
54
|
+
# Example:
|
55
|
+
#
|
56
|
+
# ```
|
57
|
+
# [:foo, 123, "bar"].to_lisp => '(foo 123 "bar")'
|
58
|
+
def to_lisp
|
59
|
+
sexp_array = map { |el| el.to_lisp }
|
60
|
+
"(#{sexp_array.join ' '})"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Hash
|
65
|
+
# Creates and returns a new hash tabke with the same keys and values
|
66
|
+
# and tags it to be rendered as an association list by the to_lisp
|
67
|
+
# method.
|
68
|
+
#
|
69
|
+
# For example, ```{:a => :b, :x => 1}``` would be rendered as
|
70
|
+
#
|
71
|
+
# ```
|
72
|
+
# ((a . b) (x . 1))
|
73
|
+
# ```
|
74
|
+
def as_alist
|
75
|
+
merge(:__render_as => :alist)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates and returns a new hash tabke with the same keys and values
|
79
|
+
# but tagged to be rendered as a flat list by the to_lisp method.
|
80
|
+
#
|
81
|
+
# For example, ```{:a => :b, :x => 1}``` would be rendered as
|
82
|
+
#
|
83
|
+
# ```
|
84
|
+
# (a b x 1)
|
85
|
+
# ```
|
86
|
+
def as_flat_list
|
87
|
+
merge(:__render_as => :flat )
|
88
|
+
end
|
89
|
+
|
90
|
+
# Creates and returns a new hash table with the same keys and values
|
91
|
+
# but tagged to be rendered as a property list by the to_lisp method.
|
92
|
+
# The keys must be symbols, and they will be rendered as keywords.
|
93
|
+
#
|
94
|
+
# For example, ```{:a => :b, :x => 1}``` would be rendered as
|
95
|
+
#
|
96
|
+
# ```
|
97
|
+
# (:a b :x 1)
|
98
|
+
# ```
|
99
|
+
def as_plist
|
100
|
+
merge(:__render_as => :plist)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns a symbol indicating how the hash will be rendered by the
|
104
|
+
# to_lisp method. The possible values are :flat, :alist, :plist.
|
105
|
+
def rendering_type
|
106
|
+
self[:__render_as] or :plist
|
107
|
+
end
|
108
|
+
|
109
|
+
# Renders the hash as a list, depending on how it has been tagged.
|
110
|
+
# If the hash has not been tagged, it will be rendered as a property
|
111
|
+
# list, see as_plist.
|
112
|
+
def to_lisp
|
113
|
+
def pjoin(string_list)
|
114
|
+
"(#{string_list.join ' '})"
|
115
|
+
end
|
116
|
+
h = self.clone
|
117
|
+
h.delete(:__render_as)
|
118
|
+
case rendering_type
|
119
|
+
when :alist
|
120
|
+
pjoin(h.map { |k, v| "(#{k.to_lisp} . #{v.to_lisp})" })
|
121
|
+
when :flat
|
122
|
+
pjoin(h.map { |k, v| "#{k.to_lisp} #{v.to_lisp}" })
|
123
|
+
when :plist
|
124
|
+
pjoin(h.map { |k, v| "#{k.keyword.to_lisp} #{v.to_lisp}" })
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
module Spectator
|
131
|
+
# This exception is thrown when an error occurs when trying to
|
132
|
+
# extract the rspec result summary (number of examples ran, number
|
133
|
+
# of failures, number of pending examples) from its output.
|
134
|
+
class SummaryExtractionError < RuntimeError
|
135
|
+
end
|
136
|
+
|
137
|
+
module Specs
|
138
|
+
# Summarizes the rspec results as one of `:failure, :pending, :success`.
|
139
|
+
#
|
140
|
+
# @param [Hash] rspec_stats A Hash table with keys ```:examples, :failures, :pending, :summary, :status```.
|
141
|
+
# See {#extract_rspec_summary} for details about the meaning of the key/value pairs in this table.
|
142
|
+
def rspec_status(rspec_stats)
|
143
|
+
if rspec_stats[:failures] > 0
|
144
|
+
:failure
|
145
|
+
elsif rspec_stats[:pending] > 0
|
146
|
+
:pending
|
147
|
+
else
|
148
|
+
:success
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Returns a hash that summarizes the rspec results.
|
153
|
+
#
|
154
|
+
# @param [String] output the rspec output
|
155
|
+
# @param [Integer] line_number the line number of the summary in the rspec
|
156
|
+
# output. It can be negative: -1 indicates the last line, -2
|
157
|
+
# indicates the second last line and so on.
|
158
|
+
# @return [Hash] a hash table with keys ```:examples, :failures, :pending, :summary, :status```.
|
159
|
+
#
|
160
|
+
# * **:examples** => number of examples ran
|
161
|
+
# * **:failures** => number of failed examples
|
162
|
+
# * **:pending** => number of pending examples ran
|
163
|
+
# * **:summary** => the summary string from which the above have been extracted
|
164
|
+
# * **:status** => one of ```:failure, :pending, :success```
|
165
|
+
def extract_rspec_stats(output, line_number)
|
166
|
+
summary_line = output.split("\n")[line_number]
|
167
|
+
summary_regex = /^(\d*)\sexamples?,\s(\d*)\s(errors?|failures?)[^\d]*((\d*)\spending)?/
|
168
|
+
matchdata = summary_line.match(summary_regex)
|
169
|
+
raise SummaryExtractionError.new if matchdata.nil?
|
170
|
+
_, examples, failures, _, pending = matchdata.to_a
|
171
|
+
stats = {:examples => examples.to_i, :failures => failures.to_i, :pending => pending.to_i, :summary => summary_line}
|
172
|
+
stats.merge(:status => rspec_status(stats))
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns a hash that summarizes the rspec results.
|
176
|
+
#
|
177
|
+
# Redefine this method if you are using a non standard rspec formatter,
|
178
|
+
# see the {file:README.md} for details.
|
179
|
+
# @param [String] output the rspec output
|
180
|
+
# @return [Hash] a hash table with keys ```:examples, :failures, :pending, :summary, :status```.
|
181
|
+
#
|
182
|
+
# * **`:examples`**: number of examples ran
|
183
|
+
# * **`:failures`**: number of failed examples
|
184
|
+
# * **`:pending`**: number of pending examples ran
|
185
|
+
# * **`:summary`**: the summary string from which the above have been extracted
|
186
|
+
# * **`:status`**: one of
|
187
|
+
#
|
188
|
+
# ```
|
189
|
+
# :success, :pending, :failure
|
190
|
+
# ```
|
191
|
+
def extract_rspec_summary(output)
|
192
|
+
begin
|
193
|
+
extract_rspec_stats output, @summary_line_number
|
194
|
+
rescue SummaryExtractionError
|
195
|
+
puts "--- Error while extracting summary with the default method.".red
|
196
|
+
print "--- Summary line number: ".yellow
|
197
|
+
@summary_line_number = STDIN.gets.to_i
|
198
|
+
extract_rspec_summary output
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Runs a command and returns a hash containing exit status,
|
203
|
+
# standard output and standard error contents.
|
204
|
+
#
|
205
|
+
# @return [Hash] a hash table with keys `:status, :stdout, :stderr`.
|
206
|
+
def run(cmd)
|
207
|
+
puts "=== running: #{cmd} ".ljust(terminal_columns, '=').cyan
|
208
|
+
pid, _, stdout, stderr = Open4::popen4 cmd
|
209
|
+
_, status = Process::waitpid2 pid
|
210
|
+
puts "===".ljust(terminal_columns, '=').cyan
|
211
|
+
{:status => status, :stdout => stdout.read.strip, :stderr => stderr.read.strip}
|
212
|
+
end
|
213
|
+
|
214
|
+
# Sends a notification to emacs via Enotify
|
215
|
+
#
|
216
|
+
# @param [String] rspec_output The rspec command output
|
217
|
+
# @param [Hash] stats A Hash table with keys ```:examples, :failures, :pending, :summary, :status```.
|
218
|
+
# See {#extract_rspec_summary} for details about the meaning of the key/value pairs in this table.
|
219
|
+
def rspec_send_results(rspec_output, stats)
|
220
|
+
begin
|
221
|
+
print "--- Sending notification to #{@enotify_host}:#{@enotify_port}" \
|
222
|
+
" through #{@enotify_slot_id}... ".cyan
|
223
|
+
enotify_notify rspec_output, stats
|
224
|
+
puts "Success!".green
|
225
|
+
rescue SocketError
|
226
|
+
puts "Failed!".red
|
227
|
+
enotify_connect
|
228
|
+
rspec_send_results rspec_output, stats
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Checks if the commands `bundle exec rspec` and `rspec` actually
|
233
|
+
# run the same program, and sets the `@bundle` instance variable
|
234
|
+
# accordingly.
|
235
|
+
#
|
236
|
+
# This is meant to speed up the execution of `rspec`.
|
237
|
+
def check_if_bundle_needed
|
238
|
+
if `bundle exec #{rspec_command} -v` == `#{rspec_command} -v`
|
239
|
+
@bundle = ""
|
240
|
+
else
|
241
|
+
@bundle = "bundle exec "
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Runs the `rspec` command with the given options, and notifies Emacs of the results.
|
246
|
+
#
|
247
|
+
# @param [String] options The command line arguments to pass to rspec.
|
248
|
+
def rspec(options)
|
249
|
+
unless options.empty?
|
250
|
+
results = run("#{@bundle}#{rspec_command} --failure-exit-code 99 #{options}")
|
251
|
+
status = results[:status].exitstatus
|
252
|
+
if status == 1
|
253
|
+
puts "An error occurred when running the tests".red
|
254
|
+
puts "RSpec output:"
|
255
|
+
puts "STDERR:"
|
256
|
+
puts results[:stderr]
|
257
|
+
puts "-" * 80
|
258
|
+
puts "STDOUT:"
|
259
|
+
puts results[:stdout]
|
260
|
+
else
|
261
|
+
begin
|
262
|
+
stats = extract_rspec_summary results[:stdout]
|
263
|
+
puts(stats[:summary].send(results[:status] == 0 ? :green : :red))
|
264
|
+
# enotify_notify results[:stdout], stats
|
265
|
+
rspec_send_results results[:stdout], stats
|
266
|
+
rescue StandardError => e
|
267
|
+
puts "ERROR extracting summary from rspec output: #{e}".red
|
268
|
+
puts e.backtrace
|
269
|
+
puts "RSpec output:"
|
270
|
+
puts "STDERR:"
|
271
|
+
puts results[:stderr]
|
272
|
+
puts "-" * 80
|
273
|
+
puts "STDOUT:"
|
274
|
+
puts results[:stdout]
|
275
|
+
print "Exit? (y/N)"
|
276
|
+
answer = STDIN.gets
|
277
|
+
abort "Execution aborted by the user" if answer.strip.downcase == 'y'
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# This module contains all the functions used to interact with the Enotify emacs mode-line notification system.
|
285
|
+
module Emacs
|
286
|
+
# Sends a message to the Enotify host.
|
287
|
+
#
|
288
|
+
# @param [Object] object the object to be serialized as a lisp
|
289
|
+
# object (with the {Object#to_lisp} method) and sent as a message.
|
290
|
+
def enotify_send(object)
|
291
|
+
sexp = object.to_lisp
|
292
|
+
@sock.puts "|#{sexp.length}|#{sexp}"
|
293
|
+
end
|
294
|
+
|
295
|
+
# Registers the slot named `@enotify_slot_id` with Enotify.
|
296
|
+
def enotify_register
|
297
|
+
enotify_send :register => @enotify_slot_id, :handler_fn => :enotify_rspec_result_message_handler
|
298
|
+
end
|
299
|
+
|
300
|
+
# Sends a notification to the enotify host with the RSpec results.
|
301
|
+
#
|
302
|
+
# @param [String] stdout the rspec command output.
|
303
|
+
# @param [Hash] stats the extracted summary of the results. For
|
304
|
+
# details, see the return value of
|
305
|
+
# {Spectator::Specs#extract_rspec_summary} for details.
|
306
|
+
def enotify_notify(stdout, stats)
|
307
|
+
#stats = extract_rspec_stats stdout
|
308
|
+
status = stats[:status]
|
309
|
+
message = {
|
310
|
+
:id => @enotify_slot_id,
|
311
|
+
:notification => {
|
312
|
+
:text => @notification_messages[status],
|
313
|
+
:face => @notification_face[status],
|
314
|
+
:help => format_tooltip(stats),
|
315
|
+
:mouse_1 => :enotify_rspec_mouse_1_handler
|
316
|
+
},
|
317
|
+
:data => stdout
|
318
|
+
}
|
319
|
+
|
320
|
+
enotify_send message
|
321
|
+
end
|
322
|
+
|
323
|
+
# Checks whether the string is made by whitespace characters.
|
324
|
+
#
|
325
|
+
# @param [String] string the string to be checked
|
326
|
+
# @return [Boolean] non nil if the string is blank, nil otherwise.
|
327
|
+
def blank_string?(string)
|
328
|
+
string =~ /\A\s*\n?\z/
|
329
|
+
end
|
330
|
+
|
331
|
+
# Interactively retries to connect to the Enotify host, asking a
|
332
|
+
# new *host:port* value.
|
333
|
+
def rescue_sock_error
|
334
|
+
print "--- Enter Enotify host [localhost:5000]: ".yellow
|
335
|
+
host_and_port = STDIN.gets.strip
|
336
|
+
if blank_string?(host_and_port)
|
337
|
+
@enotify_host, @enotify_port = ['localhost', @default_options[:enotify_port]]
|
338
|
+
else
|
339
|
+
@enotify_host, @enotify_port = host_and_port.split(/\s:\s/)
|
340
|
+
@enotify_port = @enotify_port.to_i
|
341
|
+
end
|
342
|
+
enotify_connect
|
343
|
+
end
|
344
|
+
|
345
|
+
# Creates a connection to the Enotify host.
|
346
|
+
def enotify_connect
|
347
|
+
begin
|
348
|
+
print "=== Connecting to emacs... ".cyan
|
349
|
+
@sock = TCPSocket.new(@enotify_host, @enotify_port)
|
350
|
+
enotify_register
|
351
|
+
puts "Success!".green
|
352
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
353
|
+
puts "Failed!".red
|
354
|
+
rescue_sock_error
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# Formats the text that will be used as a tooltip for the modeline
|
359
|
+
# *"icon"*.
|
360
|
+
#
|
361
|
+
# @param [Hash] stats the extracted summary of the results. For
|
362
|
+
# details, see the return value of
|
363
|
+
# {Spectator::Specs#extract_rspec_summary} for details.
|
364
|
+
def format_tooltip(stats)
|
365
|
+
t = Time.now
|
366
|
+
"#{t.year}-#{t.month}-#{t.day} -- #{t.hour}:#{t.min}:#{t.sec}\n" +
|
367
|
+
"#{stats[:examples]} examples, #{stats[:failures]} failures" +
|
368
|
+
((stats[:pending] > 0) ? ", #{stats[:pending]} pending.\n" : ".\n") +
|
369
|
+
"\nmouse-1: switch to rspec output buffer"
|
370
|
+
end
|
371
|
+
|
372
|
+
end
|
373
|
+
|
374
|
+
|
375
|
+
# This is the class that implements the main loop of spectator-emacs.
|
376
|
+
# To run spectator-emacs, just create a new ERunner object.
|
377
|
+
class ERunner < Runner
|
378
|
+
include Specs
|
379
|
+
include Emacs
|
380
|
+
# Creates a new instance of ERunner. This implements the main loop of `spectator-emacs`.
|
381
|
+
# See the {file:README.md} for examples on how to customize the default behavior.
|
382
|
+
# @param [Hash] options possible options are:
|
383
|
+
#
|
384
|
+
# ##### :enotify_port (Fixnum)
|
385
|
+
# the port the Enotify host is listening to.
|
386
|
+
# ##### :enotify_host`({String})
|
387
|
+
# the host name or IP address where Enotify is running.
|
388
|
+
# ##### :notification_messages ({Hash})
|
389
|
+
# a hash with keys `:success, :failure, :pending` containing the
|
390
|
+
# relative modeline *icons* strings.
|
391
|
+
# Defaults to `{:success => "S", :failure => "F", :pending => "P"}`.
|
392
|
+
# ##### :notification_face ({Hash})
|
393
|
+
# A hash table with keys `:success, :failure, :pending` containing
|
394
|
+
# the faces to apply to the notification *icon* in the Emacs modeline.
|
395
|
+
# Values must be {Symbol}s, like for example `:font_lock_constant_face`
|
396
|
+
# in order to use Emacs' `font-lock-warning-face`.
|
397
|
+
# Defaults to
|
398
|
+
#
|
399
|
+
# ```
|
400
|
+
# {:success => :\':success\', :failure => :\':failure\', :pending => :\':warning\'}
|
401
|
+
# ```
|
402
|
+
# @yield [ERunner] Gives a reference of the ERunner object just created to the block
|
403
|
+
# Use this block when you need to customize the behavior of spectator-emacs.
|
404
|
+
# For example, if you need a custom summary extraction method, you can create
|
405
|
+
# the runner object as follows in your `.spectator-emacs` script:
|
406
|
+
#
|
407
|
+
# ```ruby
|
408
|
+
# @runner = ERunner.new do |runner|
|
409
|
+
# def runner.extract_rspec_summary(output)
|
410
|
+
# ## your summary extraction code here
|
411
|
+
# ## ...
|
412
|
+
# end
|
413
|
+
# end
|
414
|
+
# ```
|
415
|
+
def initialize(options={}, &block)
|
416
|
+
@default_options = {
|
417
|
+
:enotify_port => 5000,
|
418
|
+
:enotify_host => 'localhost',
|
419
|
+
:notification_messages => {:failure => "F", :success => "S", :pending => "P"},
|
420
|
+
:notification_face => {
|
421
|
+
:failure => :failure.keyword,
|
422
|
+
:success => :success.keyword,
|
423
|
+
:pending => :warning.keyword
|
424
|
+
}
|
425
|
+
}
|
426
|
+
options = @default_options.merge options
|
427
|
+
@cli_args = ARGV.to_a
|
428
|
+
puts "======= OPTIONS ======="
|
429
|
+
options.each {|k, v| puts "#{k} => #{v}"}
|
430
|
+
@enotify_host = options[:enotify_host]
|
431
|
+
@enotify_port = options[:enotify_port]
|
432
|
+
@notification_messages = options[:notification_messages]
|
433
|
+
@notification_face = options[:notification_face]
|
434
|
+
@summary_line_number = options[:summary_line] || -1
|
435
|
+
@enotify_slot_id = options[:slot_id] ||
|
436
|
+
((File.basename Dir.pwd).split('_').map {|s| s.capitalize}).join.gsub('-','/')
|
437
|
+
check_if_bundle_needed
|
438
|
+
enotify_connect
|
439
|
+
yield self if block_given?
|
440
|
+
# TODO: load .spectator-emacs
|
441
|
+
# contents = File::read('.spectator-emacs')
|
442
|
+
# eval(contents)
|
443
|
+
super()
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
#####################################
|
448
|
+
# require 'spectator/emacs'
|
449
|
+
|
450
|
+
# Spectator::ERunner.new(:enotify_port => 5001, :enotify_host => 'localhost') do |runner|
|
451
|
+
# def runner.extract_rspec_stats(results, line)
|
452
|
+
# ## define new spec extraction routine
|
453
|
+
# ## it must return a hash like this one:
|
454
|
+
# ## {:examples => 10, # number of examples executed
|
455
|
+
# ## :failures => 4, # number of failures
|
456
|
+
# ## :pending => 1, # number of pending examples
|
457
|
+
# ## :status => :failure # one of :pending, :succes, :failure
|
458
|
+
# ## }
|
459
|
+
# end
|
460
|
+
# end
|
data/spec/emacs_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spectator/emacs'
|
2
|
+
|
3
|
+
describe 'Spectator' do
|
4
|
+
describe 'EmacsInteraction' do
|
5
|
+
describe "Lisp sexp helpers" do
|
6
|
+
describe "Symbol#keyword" do
|
7
|
+
it "should be present" do
|
8
|
+
:foobar.should respond_to(:keyword)
|
9
|
+
end
|
10
|
+
it "should add a ':' if the symbol name does not begin with ':'" do
|
11
|
+
:foobar.keyword.should == :':foobar'
|
12
|
+
end
|
13
|
+
it "should not add a ':' if the symbol name already begins with ':'" do
|
14
|
+
sym = :':foobar'
|
15
|
+
sym.keyword.should == sym
|
16
|
+
end
|
17
|
+
end
|
18
|
+
describe "Object#to_lisp" do
|
19
|
+
it "should correctly represent a number" do
|
20
|
+
20.times do
|
21
|
+
num = rand(1..1000)
|
22
|
+
num.to_lisp.should == "#{num}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should correctly represent a symbol" do
|
27
|
+
symbol = :foobar
|
28
|
+
symbol.to_lisp.should == "foobar"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should convert underscores to dashes when converting a symbol" do
|
32
|
+
symbol = :foo_bar
|
33
|
+
symbol.to_lisp.should == "foo-bar"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should correctly represent a string" do
|
37
|
+
"asdf\nfoobar".to_lisp.should == '"asdf\nfoobar"'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should correctly represent an array as a list" do
|
41
|
+
[1,2,3,4].to_lisp.should == '(1 2 3 4)'
|
42
|
+
[1,2, [3, 4], 5, 6].to_lisp.should == '(1 2 (3 4) 5 6)'
|
43
|
+
[:a, 1, :b, 2].to_lisp.should == '(a 1 b 2)'
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "Hash#to_lisp" do
|
47
|
+
before(:each) do
|
48
|
+
@hash = {:a => [1,2,3], :b => 1, :c => "asdf"}
|
49
|
+
end
|
50
|
+
it "should correctly represent a hash as a plist" do
|
51
|
+
@hash.as_plist.to_lisp.should == '(:a (1 2 3) :b 1 :c "asdf")'
|
52
|
+
end
|
53
|
+
it "should correctly represent a hash as an alist" do
|
54
|
+
@hash.as_alist.to_lisp.should == '((a . (1 2 3)) (b . 1) (c . "asdf"))'
|
55
|
+
end
|
56
|
+
it "should correctly represent a hash as a flat list" do
|
57
|
+
@hash.as_flat_list.to_lisp.should == '(a (1 2 3) b 1 c "asdf")'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe "ERunner" do
|
64
|
+
it "should inherit from Runner" do
|
65
|
+
Spectator::ERunner.superclass.should be(Spectator::Runner)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require File.expand_path('../lib/spectator/emacs/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "spectator-emacs"
|
7
|
+
gem.version = Spectator::Emacs::VERSION
|
8
|
+
gem.summary = %q{A Spectator monkey-patch that displays notifications on the emacs modeline.}
|
9
|
+
gem.description = <<-DESCRIPTION
|
10
|
+
spectator-emacs is a Spectator extension that provides discreet
|
11
|
+
notificatoins in the Emacs modeline, via the Enotify Emacs
|
12
|
+
notification system.
|
13
|
+
|
14
|
+
== Features ==
|
15
|
+
* Notifications on the emacs modeline
|
16
|
+
* Short summary report on mouse-over in the modeline indicator
|
17
|
+
* Easily switch to the results buffer with just a click on the
|
18
|
+
modeline indicator
|
19
|
+
* Org formatted RSpec results with the aid of RSpec Org Formatter
|
20
|
+
* Summary extraction can be customized to work with different RSpec
|
21
|
+
output formats
|
22
|
+
* all the features offered by Spectator
|
23
|
+
DESCRIPTION
|
24
|
+
gem.license = "MIT"
|
25
|
+
gem.authors = ["Alessandro Piras"]
|
26
|
+
gem.email = "laynor@gmail.com"
|
27
|
+
gem.homepage = "https://github.com/laynor/spectator-emacs#readme"
|
28
|
+
|
29
|
+
gem.files = `git ls-files`.split($/)
|
30
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
31
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
32
|
+
gem.require_paths = ['lib']
|
33
|
+
|
34
|
+
gem.add_development_dependency 'rdoc', '~> 3.0'
|
35
|
+
gem.add_development_dependency 'rspec', '~> 2.4'
|
36
|
+
gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
|
37
|
+
gem.add_development_dependency 'yard'
|
38
|
+
gem.add_development_dependency 'redcarpet'
|
39
|
+
gem.add_dependency 'rspec'
|
40
|
+
gem.add_dependency 'spectator', '~> 1.2'
|
41
|
+
gem.add_dependency 'open4'
|
42
|
+
gem.add_dependency 'rb-inotify', '~> 0.8.8'
|
43
|
+
gem.add_dependency 'docopt'
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spectator-emacs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alessandro Piras
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rdoc
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.4'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.4'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rubygems-tasks
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.2'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.2'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: yard
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: redcarpet
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: rspec
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: spectator
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.2'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.2'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: open4
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: rb-inotify
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 0.8.8
|
150
|
+
type: :runtime
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ~>
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 0.8.8
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: docopt
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :runtime
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
description: ! " spectator-emacs is a Spectator extension that provides discreet\n
|
175
|
+
\ notificatoins in the Emacs modeline, via the Enotify Emacs\n notification system.\n\n
|
176
|
+
\ == Features ==\n * Notifications on the emacs modeline\n * Short summary report
|
177
|
+
on mouse-over in the modeline indicator\n * Easily switch to the results buffer
|
178
|
+
with just a click on the\n modeline indicator\n * Org formatted RSpec results
|
179
|
+
with the aid of RSpec Org Formatter\n * Summary extraction can be customized to
|
180
|
+
work with different RSpec\n output formats\n * all the features offered by Spectator\n"
|
181
|
+
email: laynor@gmail.com
|
182
|
+
executables:
|
183
|
+
- spectator-emacs
|
184
|
+
extensions: []
|
185
|
+
extra_rdoc_files: []
|
186
|
+
files:
|
187
|
+
- .document
|
188
|
+
- .gitignore
|
189
|
+
- .rspec
|
190
|
+
- .yardopts
|
191
|
+
- ChangeLog.rdoc
|
192
|
+
- Gemfile
|
193
|
+
- Gemfile.lock
|
194
|
+
- LICENSE.txt
|
195
|
+
- README.md
|
196
|
+
- Rakefile
|
197
|
+
- bin/spectator-emacs
|
198
|
+
- lib/spectator/emacs.rb
|
199
|
+
- lib/spectator/emacs/version.rb
|
200
|
+
- spec/emacs_spec.rb
|
201
|
+
- spec/lib/spectator/emacs_spec.rb
|
202
|
+
- spec/spec_helper.rb
|
203
|
+
- spectator-emacs.gemspec
|
204
|
+
homepage: https://github.com/laynor/spectator-emacs#readme
|
205
|
+
licenses:
|
206
|
+
- MIT
|
207
|
+
post_install_message:
|
208
|
+
rdoc_options: []
|
209
|
+
require_paths:
|
210
|
+
- lib
|
211
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
212
|
+
none: false
|
213
|
+
requirements:
|
214
|
+
- - ! '>='
|
215
|
+
- !ruby/object:Gem::Version
|
216
|
+
version: '0'
|
217
|
+
segments:
|
218
|
+
- 0
|
219
|
+
hash: -2575753694497142155
|
220
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
|
+
none: false
|
222
|
+
requirements:
|
223
|
+
- - ! '>='
|
224
|
+
- !ruby/object:Gem::Version
|
225
|
+
version: '0'
|
226
|
+
segments:
|
227
|
+
- 0
|
228
|
+
hash: -2575753694497142155
|
229
|
+
requirements: []
|
230
|
+
rubyforge_project:
|
231
|
+
rubygems_version: 1.8.24
|
232
|
+
signing_key:
|
233
|
+
specification_version: 3
|
234
|
+
summary: A Spectator monkey-patch that displays notifications on the emacs modeline.
|
235
|
+
test_files:
|
236
|
+
- spec/emacs_spec.rb
|
237
|
+
- spec/lib/spectator/emacs_spec.rb
|
238
|
+
- spec/spec_helper.rb
|