selfie_formatter 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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/example.gif +0 -0
- data/lib/imagesnap +0 -0
- data/lib/selfie.rb +7 -0
- data/lib/selfie/camera.rb +61 -0
- data/lib/selfie/cursor.rb +49 -0
- data/lib/selfie/iterm2/image.rb +47 -0
- data/lib/selfie/version.rb +3 -0
- data/lib/selfie_formatter.rb +193 -0
- data/selfie_formatter.gemspec +30 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 40373d4d7ab3ef4ab64d87bd40dccdacb111fe37
|
4
|
+
data.tar.gz: 15a59ad88f51a8fa3c0938a7b12aa22c66adc70e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 05ef8afcc20dda9caaa4b427b861ea0f87f093a53df828a6f9c56bea2bbc7a71d2997f3d851d77b70d05939f669b8f25541c7c8a2354dd74bfa10d3a943c52f1
|
7
|
+
data.tar.gz: 4fba84dc01175dab9f59a7e8f20c174f34065679d9e8e4cb6bab7885d80081590f2de3f0071be5409b2cf131e09de7816ce91184f11e1b8da3ada263b06f1e2a
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Skye Shaw (sshaw)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# The RSpec Selfie Formatter
|
2
|
+
|
3
|
+
An RSpec Formatter for the new generation of programmers.
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
The Selfie Formatter takes photos of you while your tests run and uses them to track
|
8
|
+
progress and format the results.
|
9
|
+
|
10
|
+
Currently only works on OS X with iTerm2 >= 3.0. **Warning** see [known issues](#known-issues).
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
ImageMagick is required
|
15
|
+
|
16
|
+
```
|
17
|
+
brew install imagemagick --with-fontconfig
|
18
|
+
```
|
19
|
+
|
20
|
+
Then
|
21
|
+
|
22
|
+
```
|
23
|
+
gem install selfie_formatter
|
24
|
+
```
|
25
|
+
|
26
|
+
Or, in your `Gemfile`
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem "selfie_formatter", :group => "test"
|
30
|
+
```
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
```
|
35
|
+
rspec -f SelfieFormatter
|
36
|
+
```
|
37
|
+
|
38
|
+
## Known Issues
|
39
|
+
|
40
|
+
1. Photos are taken via [imagesnap](https://github.com/rharder/imagesnap), which is a fine program but can quickly eat up memory.
|
41
|
+
Upwards of 500 MB after 10 or 15 seconds.
|
42
|
+
|
43
|
+
1. Photos are taken every 300ms. Unused photos are cleaned up after every test completes but if a single test takes a while to
|
44
|
+
complete photos can start to eat up disk space.
|
45
|
+
|
46
|
+
1. Spec numbers are added to the top left of each image. They will not show up if the background is dark.
|
47
|
+
|
48
|
+
At some point I may write something that does not [fake the `Camera` interface via `fork`](https://github.com/sshaw/selfie_formatter/blob/34f1999391695ce7633d79638a0903e1eb612e9e/lib/selfie/camera.rb). [imagesnap](https://github.com/rharder/imagesnap) and [CaptureCamera](https://github.com/fernyb/CaptureCamera) are good starting points.
|
49
|
+
|
50
|
+
## License
|
51
|
+
|
52
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/example.gif
ADDED
Binary file
|
data/lib/imagesnap
ADDED
Binary file
|
data/lib/selfie.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Selfie
|
2
|
+
class Camera
|
3
|
+
CAPTURE_COMMAND = File.expand_path("../../imagesnap", __FILE__) << " -qw 0.8 -t 0.3"
|
4
|
+
|
5
|
+
def initialize(outdir, options = {})
|
6
|
+
@outdir = outdir
|
7
|
+
@glob = File.join(@outdir, "snapshot-*.jpg")
|
8
|
+
@captured = []
|
9
|
+
@pid = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
# The camera interface we'd like to have (and may at some point).
|
13
|
+
# Until then, we fake it.
|
14
|
+
def on
|
15
|
+
return false if @pid
|
16
|
+
|
17
|
+
# TODO: signals
|
18
|
+
begin
|
19
|
+
@pid = spawn(CAPTURE_COMMAND, :chdir => @outdir, [:out, :err] => File::NULL)
|
20
|
+
rescue SystemCallError => e
|
21
|
+
raise Error, "cannot spawn photo capture process: #{e}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Wait for camera to warm up, -w option is not enough :(
|
25
|
+
sleep 2.5
|
26
|
+
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def off
|
31
|
+
return false unless @pid
|
32
|
+
|
33
|
+
begin
|
34
|
+
Process.kill("TERM", @pid)
|
35
|
+
Process.wait(@pid)
|
36
|
+
rescue Errno::ESRCH, Errno::ECHILD
|
37
|
+
# kill, wait cannot find pid
|
38
|
+
end
|
39
|
+
|
40
|
+
# final cleanup
|
41
|
+
FileUtils.rm_f(Dir[@glob] - @captured)
|
42
|
+
|
43
|
+
@pid = nil
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
# Some hacks to make it seem like capture() takes a picture
|
48
|
+
# without accumulating a ton of unused images.
|
49
|
+
def capture
|
50
|
+
sleep 0.2
|
51
|
+
|
52
|
+
images = Dir[@glob]
|
53
|
+
return if images.none? || images.last == @captured.last
|
54
|
+
|
55
|
+
@captured << images.last
|
56
|
+
FileUtils.rm_f(images - @captured)
|
57
|
+
|
58
|
+
@captured.last
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "tty-cursor"
|
2
|
+
|
3
|
+
module Selfie
|
4
|
+
class Cursor
|
5
|
+
include TTY::Cursor
|
6
|
+
|
7
|
+
def initialize(output)
|
8
|
+
raise ArgumentError, "output must be a terminal" unless output.tty?
|
9
|
+
@output = output
|
10
|
+
@settings = `stty -g 2>/dev/null`
|
11
|
+
end
|
12
|
+
|
13
|
+
%w[up down forward back move_to hide show clear_screen].each do |name|
|
14
|
+
define_method(name) { |*n| @output << super(*n) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# Calculates how many columns and rows the code in the given block moved the cursor
|
18
|
+
def distance
|
19
|
+
raise ArgumentError, "block required" unless block_given?
|
20
|
+
|
21
|
+
beg_pos = position
|
22
|
+
yield
|
23
|
+
end_pos = position
|
24
|
+
return unless end_pos && beg_pos
|
25
|
+
|
26
|
+
# width, height
|
27
|
+
[ end_pos[1] - beg_pos[1], end_pos[0] - beg_pos[0] ]
|
28
|
+
end
|
29
|
+
|
30
|
+
def position
|
31
|
+
# TODO: use terminos instead?
|
32
|
+
`stty -echo -icanon -cread`
|
33
|
+
@output << current
|
34
|
+
|
35
|
+
position = ""
|
36
|
+
while ch = $stdin.getc
|
37
|
+
position << ch
|
38
|
+
break if ch == "R"
|
39
|
+
end
|
40
|
+
|
41
|
+
return unless position =~ %r|\[(\d+)\;(\d+)|
|
42
|
+
|
43
|
+
[ $1.to_i, $2.to_i ]
|
44
|
+
ensure
|
45
|
+
# TODO: restore if killed..?
|
46
|
+
`stty -g #@settings`
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "base64"
|
2
|
+
|
3
|
+
module Selfie
|
4
|
+
module ITerm2
|
5
|
+
class Image
|
6
|
+
attr :path
|
7
|
+
|
8
|
+
def initialize(path, options = {})
|
9
|
+
@path = path
|
10
|
+
@options = options.dup
|
11
|
+
@options[:inline] = 1
|
12
|
+
@image = Base64.encode64(File.read(path))
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s(options = {})
|
16
|
+
sprintf("%s1337;File=%s:%s%s", start_esc, format_options(options), @image, end_esc)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def screen_tty?
|
22
|
+
$stdout.tty? && ENV.include?("TERM") && ENV["TERM"].start_with?("screen")
|
23
|
+
end
|
24
|
+
|
25
|
+
# From imgls: https://raw.githubusercontent.com/gnachman/iTerm2/master/tests/imgls
|
26
|
+
def start_esc
|
27
|
+
@screen == true ? "\ePtmux;\e\e]" : "\e]"
|
28
|
+
end
|
29
|
+
|
30
|
+
def end_esc
|
31
|
+
@screen == true ? "\a\e\\" : "\a"
|
32
|
+
end
|
33
|
+
# --
|
34
|
+
|
35
|
+
def format_options(options)
|
36
|
+
@options.merge(options).map do |name, value|
|
37
|
+
if name == :preserve_aspect_ratio
|
38
|
+
name = "preserveAspectRatio"
|
39
|
+
value = value == false ? 0 : 1
|
40
|
+
end
|
41
|
+
|
42
|
+
sprintf "%s=%s", name, value
|
43
|
+
end.join(";")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require "rspec"
|
2
|
+
|
3
|
+
# This is needed by the Reporter. RSpec doesn't require it.
|
4
|
+
require "rspec/core/formatters/console_codes"
|
5
|
+
|
6
|
+
require "fileutils"
|
7
|
+
require "mini_magick"
|
8
|
+
|
9
|
+
require "selfie"
|
10
|
+
|
11
|
+
class SelfieFormatter
|
12
|
+
include Selfie
|
13
|
+
|
14
|
+
DEFAULT_COLUMNS = 80
|
15
|
+
|
16
|
+
RSpec::Core::Formatters.register self, :dump_summary, :dump_failures, :dump_pending, :close, :example_passed, :example_failed, :example_pending, :start, :stop
|
17
|
+
|
18
|
+
def self.output_directory
|
19
|
+
@output_directory ||= RSpec.configuration.selfie_output_directory || File.join(Dir.pwd, "selfies")
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.output_directory=(path)
|
23
|
+
@output_directory = path
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(output, options = {})
|
27
|
+
raise ArgumentError, "can only render to a terminal" unless output.tty?
|
28
|
+
|
29
|
+
@output = output
|
30
|
+
@options = options
|
31
|
+
@cursor = Cursor.new(@output)
|
32
|
+
@camera = Camera.new(photo_dir)
|
33
|
+
|
34
|
+
@columns = `stty size 2>/dev/null`.split(" ").last.to_i
|
35
|
+
@columns = DEFAULT_COLUMNS if @columns == 0
|
36
|
+
|
37
|
+
@offset = 1
|
38
|
+
@spec_count = 0
|
39
|
+
|
40
|
+
@failed = {}
|
41
|
+
@pending = {}
|
42
|
+
|
43
|
+
@main_img_height = nil
|
44
|
+
@main_img_width = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def start(notification)
|
48
|
+
@camera.on
|
49
|
+
@cursor.hide
|
50
|
+
@cursor.clear_screen
|
51
|
+
@cursor.move_to(0, 0)
|
52
|
+
end
|
53
|
+
|
54
|
+
def stop(notification)
|
55
|
+
@camera.off
|
56
|
+
|
57
|
+
# Make sure we move down past the "film strip" before the summary is printed
|
58
|
+
pos = @cursor.position
|
59
|
+
if pos && pos[1] != 1
|
60
|
+
@cursor.down(@main_img_height)
|
61
|
+
end
|
62
|
+
|
63
|
+
@output << "\n\n"
|
64
|
+
end
|
65
|
+
|
66
|
+
def close(n)
|
67
|
+
@cursor.show
|
68
|
+
@output.flush
|
69
|
+
end
|
70
|
+
|
71
|
+
def example_passed(notification)
|
72
|
+
image = capture("green")
|
73
|
+
display_progess(image) if image
|
74
|
+
end
|
75
|
+
|
76
|
+
def example_failed(notification)
|
77
|
+
image = capture("red")
|
78
|
+
return unless image
|
79
|
+
|
80
|
+
@failed[notification.example] = image
|
81
|
+
display_progess(image)
|
82
|
+
end
|
83
|
+
|
84
|
+
def example_pending(notification)
|
85
|
+
image = capture("yellow")
|
86
|
+
return unless image
|
87
|
+
|
88
|
+
@pending[notification.example] = image
|
89
|
+
display_progess(image)
|
90
|
+
end
|
91
|
+
|
92
|
+
def dump_pending(notification)
|
93
|
+
if notification.pending_notifications.any?
|
94
|
+
@output << "\nPending:\n"
|
95
|
+
dump_notifications(notification.pending_notifications, @pending)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def dump_failures(notification)
|
100
|
+
if notification.failure_notifications.any?
|
101
|
+
@output << "\nFailures:\n"
|
102
|
+
dump_notifications(notification.failure_notifications, @failed)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def dump_summary(summary)
|
107
|
+
@output.puts summary.fully_formatted
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def dump_notifications(notifications, images)
|
113
|
+
notifications.each_with_index do |notification, i|
|
114
|
+
notice = notification.fully_formatted(i + 1)
|
115
|
+
if images[notification.example]
|
116
|
+
# Replace the example's number with its photo
|
117
|
+
notice.sub!(%r|\A\s*\d+\)\s+(.+)$|, "\n%s\\1\n" % images[notification.example].to_s(:width => 12))
|
118
|
+
end
|
119
|
+
|
120
|
+
@output << notice
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def photo_dir
|
125
|
+
path = File.join(SelfieFormatter.output_directory, Time.now.strftime("%Y-%m-%d-%H%M%S"))
|
126
|
+
FileUtils.mkdir_p(path)
|
127
|
+
path
|
128
|
+
end
|
129
|
+
|
130
|
+
def capture(color)
|
131
|
+
@spec_count += 1
|
132
|
+
|
133
|
+
path = @camera.capture
|
134
|
+
return unless path
|
135
|
+
|
136
|
+
transform(path, color)
|
137
|
+
ITerm2::Image.new(path)
|
138
|
+
end
|
139
|
+
|
140
|
+
def transform(path, color)
|
141
|
+
# TODO: options
|
142
|
+
# TODO: put number in a white box
|
143
|
+
image = MiniMagick::Image.new(path)
|
144
|
+
image.combine_options do |i|
|
145
|
+
i.resize "250x250>"
|
146
|
+
i.border "4x4"
|
147
|
+
i.bordercolor color
|
148
|
+
i.pointsize '26'
|
149
|
+
i.weight 'Bold'
|
150
|
+
# for 26 point
|
151
|
+
# count isn't available on Notification -of something?!
|
152
|
+
i.annotate "+10+30", @spec_count.to_s
|
153
|
+
# for 32 point
|
154
|
+
#i.annotate "+15+40", "#1000"
|
155
|
+
end
|
156
|
+
rescue MiniMagick::Error => e
|
157
|
+
raise Error, "image transformation failed: #{e}"
|
158
|
+
end
|
159
|
+
|
160
|
+
def display_progess(image)
|
161
|
+
# TODO: subclass?
|
162
|
+
# if SelfieFormatter.film_strip?
|
163
|
+
film_strip_formatter(image)
|
164
|
+
end
|
165
|
+
|
166
|
+
def film_strip_formatter(image)
|
167
|
+
output_image(image)
|
168
|
+
adjust_cursor
|
169
|
+
end
|
170
|
+
|
171
|
+
def output_image(image)
|
172
|
+
str = image.to_s
|
173
|
+
if @main_img_height && @main_img_width
|
174
|
+
@output << str
|
175
|
+
else
|
176
|
+
@main_img_width, @main_img_height = @cursor.distance { @output << str }
|
177
|
+
raise Error, "formatting failed: cannot determine cursor position" unless @main_img_width && @main_img_height
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def adjust_cursor
|
182
|
+
# Check if the next image fits on the current row
|
183
|
+
@offset += 1
|
184
|
+
if @offset * @main_img_width <= @columns
|
185
|
+
@cursor.up(@main_img_height)
|
186
|
+
else
|
187
|
+
@offset = 1
|
188
|
+
@output << "\n"
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
RSpec.configuration.add_setting :selfie_output_directory
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'selfie/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "selfie_formatter"
|
8
|
+
spec.version = Selfie::VERSION
|
9
|
+
spec.authors = ["Skye Shaw"]
|
10
|
+
spec.email = ["skye.shaw@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "RSpec Formatter that takes photos of you while your tests run and uses them to track progress and format the results."
|
13
|
+
spec.description =<<-DESC
|
14
|
+
An RSpec Formatter for the new generation for programmers.
|
15
|
+
Selfie Formatter takes photos of you while your tests run and uses them to track progress and format the results.
|
16
|
+
Currently only works on OS X with iTerm2 >= 3.0.
|
17
|
+
DESC
|
18
|
+
|
19
|
+
spec.homepage = "https://github.com/sshaw/selfie_formatter"
|
20
|
+
spec.license = "MIT"
|
21
|
+
|
22
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_dependency "rspec", "~> 3.0"
|
26
|
+
spec.add_dependency "mini_magick", "~> 4.0"
|
27
|
+
spec.add_dependency "tty-cursor", "~> 0.3"
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: selfie_formatter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Skye Shaw
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mini_magick
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-cursor
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
description: |2
|
84
|
+
An RSpec Formatter for the new generation for programmers.
|
85
|
+
Selfie Formatter takes photos of you while your tests run and uses them to track progress and format the results.
|
86
|
+
Currently only works on OS X with iTerm2 >= 3.0.
|
87
|
+
email:
|
88
|
+
- skye.shaw@gmail.com
|
89
|
+
executables: []
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- ".gitignore"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- example.gif
|
98
|
+
- lib/imagesnap
|
99
|
+
- lib/selfie.rb
|
100
|
+
- lib/selfie/camera.rb
|
101
|
+
- lib/selfie/cursor.rb
|
102
|
+
- lib/selfie/iterm2/image.rb
|
103
|
+
- lib/selfie/version.rb
|
104
|
+
- lib/selfie_formatter.rb
|
105
|
+
- selfie_formatter.gemspec
|
106
|
+
homepage: https://github.com/sshaw/selfie_formatter
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.4.8
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: RSpec Formatter that takes photos of you while your tests run and uses them
|
130
|
+
to track progress and format the results.
|
131
|
+
test_files: []
|
132
|
+
has_rdoc:
|