approvals 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/License.txt +22 -0
- data/README.md +133 -0
- data/Rakefile +1 -0
- data/TODO +2 -0
- data/approvals.gemspec +23 -0
- data/bin/approvals +9 -0
- data/lib/approvals.rb +24 -0
- data/lib/approvals/approval.rb +97 -0
- data/lib/approvals/configuration.rb +24 -0
- data/lib/approvals/dsl.rb +7 -0
- data/lib/approvals/error.rb +5 -0
- data/lib/approvals/extensions/rspec.rb +11 -0
- data/lib/approvals/extensions/rspec/dsl.rb +9 -0
- data/lib/approvals/extensions/rspec/example.rb +17 -0
- data/lib/approvals/extensions/rspec/example_group.rb +15 -0
- data/lib/approvals/namers/default_namer.rb +20 -0
- data/lib/approvals/namers/rspec_namer.rb +27 -0
- data/lib/approvals/reporters.rb +3 -0
- data/lib/approvals/reporters/first_working_reporter.rb +21 -0
- data/lib/approvals/reporters/image_reporter.rb +16 -0
- data/lib/approvals/reporters/image_reporter/html_image_reporter.rb +35 -0
- data/lib/approvals/reporters/image_reporter/image_magick_reporter.rb +20 -0
- data/lib/approvals/utilities.rb +4 -0
- data/lib/approvals/utilities/cli.rb +28 -0
- data/lib/approvals/utilities/dotfile.rb +38 -0
- data/lib/approvals/utilities/executable.rb +14 -0
- data/lib/approvals/utilities/scrubber.rb +43 -0
- data/lib/approvals/utilities/system_command.rb +13 -0
- data/lib/approvals/writer.rb +26 -0
- data/lib/approvals/writers.rb +5 -0
- data/lib/approvals/writers/array_writer.rb +15 -0
- data/lib/approvals/writers/html_writer.rb +15 -0
- data/lib/approvals/writers/json_writer.rb +17 -0
- data/lib/approvals/writers/text_writer.rb +22 -0
- data/lib/approvals/writers/xml_writer.rb +15 -0
- data/spec/approvals_spec.rb +64 -0
- data/spec/configuration_spec.rb +27 -0
- data/spec/extensions/rspec_approvals_spec.rb +49 -0
- data/spec/fixtures/approvals/approvals_verifies_a_complex_object.approved.txt +1 -0
- data/spec/fixtures/approvals/approvals_verifies_a_string.approved.txt +1 -0
- data/spec/fixtures/approvals/approvals_verifies_an_array.approved.txt +4 -0
- data/spec/fixtures/approvals/approvals_verifies_an_executable.approved.txt +1 -0
- data/spec/fixtures/approvals/approvals_verifies_html.approved.html +11 -0
- data/spec/fixtures/approvals/approvals_verifies_json.approved.json +7 -0
- data/spec/fixtures/approvals/approvals_verifies_xml.approved.xml +9 -0
- data/spec/fixtures/approvals/verifications_a_string.approved.txt +1 -0
- data/spec/fixtures/approvals/verifies_a_complex_object.approved.txt +1 -0
- data/spec/fixtures/approvals/verifies_a_string.approved.txt +1 -0
- data/spec/fixtures/approvals/verifies_an_array.approved.txt +4 -0
- data/spec/fixtures/approvals/verifies_an_executable.approved.txt +1 -0
- data/spec/fixtures/approvals/verifies_html.approved.html +11 -0
- data/spec/fixtures/approvals/verifies_json.approved.json +7 -0
- data/spec/fixtures/approvals/verifies_xml.approved.xml +9 -0
- data/spec/fixtures/one.png +0 -0
- data/spec/fixtures/two.png +0 -0
- data/spec/namers/default_namer_spec.rb +35 -0
- data/spec/namers/rspec_namer_spec.rb +31 -0
- data/spec/namers_spec.rb +16 -0
- data/spec/reporters/first_working_reporter_spec.rb +29 -0
- data/spec/reporters/html_image_reporter_spec.rb +22 -0
- data/spec/reporters/image_magick_reporter_spec.rb +16 -0
- data/spec/utilities/dotfile_spec.rb +22 -0
- data/spec/utilities/executable_spec.rb +15 -0
- data/spec/utilities/scrubber_spec.rb +24 -0
- data/spec/utilities/system_command_spec.rb +13 -0
- metadata +147 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Approvals
|
2
|
+
module Namers
|
3
|
+
class DefaultNamer
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
def initialize(name = nil)
|
7
|
+
raise ArgumentError.new("DefaultNamer: You must specify a name") if name.nil?
|
8
|
+
@name = normalize(name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def normalize(string)
|
12
|
+
string.strip.squeeze(" ").gsub(/[\ :-]+/, '_').gsub(/[\W]/, '').downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def output_dir
|
16
|
+
@output_dir ||= Approvals.configuration.approvals_path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Approvals
|
2
|
+
module Namers
|
3
|
+
class RSpecNamer
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
def initialize(example)
|
7
|
+
@name = normalize example.full_description
|
8
|
+
end
|
9
|
+
|
10
|
+
def normalize(string)
|
11
|
+
string.strip.squeeze(" ").gsub(/[\ :-]+/, '_').gsub(/[\W]/, '').downcase
|
12
|
+
end
|
13
|
+
|
14
|
+
def output_dir
|
15
|
+
unless @output_dir
|
16
|
+
begin
|
17
|
+
@output_dir = ::RSpec.configuration.approvals_path
|
18
|
+
rescue NoMethodError => e
|
19
|
+
end
|
20
|
+
@output_dir ||= 'spec/fixtures/approvals/'
|
21
|
+
end
|
22
|
+
@output_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Approvals
|
2
|
+
module Reporters
|
3
|
+
class FirstWorkingReporter
|
4
|
+
|
5
|
+
attr_accessor :reporters
|
6
|
+
def initialize(*reporters)
|
7
|
+
self.reporters = reporters
|
8
|
+
end
|
9
|
+
|
10
|
+
def working_in_this_environment?
|
11
|
+
reporters.any?(&:working_in_this_environment?)
|
12
|
+
end
|
13
|
+
|
14
|
+
def report(received, approved)
|
15
|
+
reporter = reporters.find(&:working_in_this_environment?)
|
16
|
+
reporter.report(received, approved) unless reporter.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'approvals/reporters/image_reporter/image_magick_reporter'
|
2
|
+
require 'approvals/reporters/image_reporter/html_image_reporter'
|
3
|
+
|
4
|
+
module Approvals
|
5
|
+
module Reporters
|
6
|
+
|
7
|
+
class ImageReporter < FirstWorkingReporter
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super(ImageMagickReporter.instance, HtmlImageReporter.instance)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Approvals
|
2
|
+
module Reporters
|
3
|
+
class HtmlImageReporter
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def working_in_this_environment?
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
def report(received, approved)
|
11
|
+
display html(received, approved)
|
12
|
+
end
|
13
|
+
|
14
|
+
def html(received, approved)
|
15
|
+
template(File.expand_path(received), File.expand_path(approved))
|
16
|
+
end
|
17
|
+
|
18
|
+
def display(page)
|
19
|
+
filename = "#{Approvals.tmp_path}tmp-#{rand(Time.now.to_i)}.html"
|
20
|
+
File.open(filename, 'w') do |file|
|
21
|
+
file.write page
|
22
|
+
end
|
23
|
+
system("open #{filename}")
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def template(received, approved)
|
28
|
+
<<-HTML.gsub(/^\ {8}/, '').chomp
|
29
|
+
<html><head><title>Approval</title></head><body><center><table style="text-align: center;" border="1"><tr><td><img src="file://#{received}"></td><td><img src="file://#{approved}"></td></tr><tr><td>received</td><td>approved</td></tr></table></center></body></html>
|
30
|
+
HTML
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Approvals
|
2
|
+
module Reporters
|
3
|
+
class ImageMagickReporter
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def working_in_this_environment?
|
7
|
+
SystemCommand.exists? "compare"
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_command_line(received, approved)
|
11
|
+
"compare #{received} #{approved} -compose Src x:"
|
12
|
+
end
|
13
|
+
|
14
|
+
def report(received, approved)
|
15
|
+
system(create_command_line(received, approved))
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Approvals
|
2
|
+
class CLI < Thor
|
3
|
+
|
4
|
+
desc "verify", "Go through all failing approvals with a diff tool"
|
5
|
+
method_option :diff, :type => :string, :default => 'vimdiff', :aliases => '-d', :desc => 'The difftool to use'
|
6
|
+
method_option :ask, :type => :boolean, :default => false, :aliases => "-a", :desc => 'Offer to approve the received file for you.'
|
7
|
+
def verify
|
8
|
+
|
9
|
+
approvals = File.read('.approvals').split("\n")
|
10
|
+
|
11
|
+
rejected = []
|
12
|
+
approvals.each do |approval|
|
13
|
+
system("#{options[:diff]} #{approval}")
|
14
|
+
|
15
|
+
if options[:ask] && yes?("Approve?")
|
16
|
+
system("mv #{approval}")
|
17
|
+
else
|
18
|
+
rejected << approval
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
File.open('.approvals', 'w') do |f|
|
23
|
+
f.write rejected.join("\n")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Approvals
|
2
|
+
|
3
|
+
class Dotfile
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def reset
|
7
|
+
File.delete(path) if File.exists?(path)
|
8
|
+
touch
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
'.approvals'
|
13
|
+
end
|
14
|
+
|
15
|
+
def touch
|
16
|
+
FileUtils.touch(path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def append(text)
|
20
|
+
unless includes?(text)
|
21
|
+
write text
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def includes?(text)
|
26
|
+
system("cat #{path} | grep -q \"^#{text}$\"")
|
27
|
+
end
|
28
|
+
|
29
|
+
def write(text)
|
30
|
+
File.open(path, 'a+') do |f|
|
31
|
+
f.write "#{text}\n"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Approvals
|
2
|
+
class Scrubber
|
3
|
+
def initialize(string, hash = nil)
|
4
|
+
@hash = hash
|
5
|
+
@string = scrub(string)
|
6
|
+
end
|
7
|
+
|
8
|
+
def hash
|
9
|
+
@hash ||= {
|
10
|
+
'current_dir' => File.expand_path('.')
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def scrub(string)
|
15
|
+
hash.each do |key, value|
|
16
|
+
string = string.gsub(value, wrap(key))
|
17
|
+
end
|
18
|
+
string
|
19
|
+
end
|
20
|
+
|
21
|
+
def unscrub(string = @string)
|
22
|
+
hash.each do |key, value|
|
23
|
+
string = string.gsub(wrap(key), value)
|
24
|
+
end
|
25
|
+
string
|
26
|
+
end
|
27
|
+
|
28
|
+
def wrap(string)
|
29
|
+
"{{#{string}}}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
@string
|
34
|
+
end
|
35
|
+
|
36
|
+
#def to_executable(&block)
|
37
|
+
# Approvals::Executable.new(@string) do |scrubbed|
|
38
|
+
# block.call(unscrub(scrubbed))
|
39
|
+
# end
|
40
|
+
#end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'approvals/writers/text_writer'
|
2
|
+
require 'approvals/writers/array_writer'
|
3
|
+
require 'approvals/writers/html_writer'
|
4
|
+
require 'approvals/writers/xml_writer'
|
5
|
+
require 'approvals/writers/json_writer'
|
6
|
+
|
7
|
+
module Approvals
|
8
|
+
module Writer
|
9
|
+
extend Writers
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def for(format)
|
13
|
+
case format
|
14
|
+
when :json then JsonWriter.instance
|
15
|
+
when :xml then XmlWriter.instance
|
16
|
+
when :html then HtmlWriter.instance
|
17
|
+
when :hash then HashWriter.instance
|
18
|
+
when :array then ArrayWriter.instance
|
19
|
+
else
|
20
|
+
TextWriter.instance
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Approvals
|
2
|
+
module Writers
|
3
|
+
class TextWriter
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def extension
|
7
|
+
'txt'
|
8
|
+
end
|
9
|
+
|
10
|
+
def write(data, path)
|
11
|
+
File.open(path, 'w') do |f|
|
12
|
+
f.write format(data)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(data)
|
17
|
+
data.inspect
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'approvals'
|
2
|
+
require 'approvals/namers/rspec_namer'
|
3
|
+
|
4
|
+
describe Approvals do
|
5
|
+
|
6
|
+
let(:namer) { Approvals::Namers::RSpecNamer.new(self.example) }
|
7
|
+
|
8
|
+
it "fails" do
|
9
|
+
->{ Approvals.verify "this one doesn't exist", :namer => namer }.should raise_error Approvals::ApprovalError
|
10
|
+
end
|
11
|
+
|
12
|
+
it "verifies a string" do
|
13
|
+
string = "We have, I fear, confused power with greatness."
|
14
|
+
Approvals.verify string, :namer => namer
|
15
|
+
end
|
16
|
+
|
17
|
+
it "verifies an array" do
|
18
|
+
array = [
|
19
|
+
"abc",
|
20
|
+
123,
|
21
|
+
:zomg_fooooood,
|
22
|
+
%w(cheese burger ribs steak bacon)
|
23
|
+
]
|
24
|
+
Approvals.verify array, :namer => namer
|
25
|
+
end
|
26
|
+
|
27
|
+
it "verifies a complex object" do
|
28
|
+
hello = Object.new
|
29
|
+
def hello.to_s
|
30
|
+
"Hello, World!"
|
31
|
+
end
|
32
|
+
|
33
|
+
def hello.inspect
|
34
|
+
"#<The World Says: Hello!>"
|
35
|
+
end
|
36
|
+
|
37
|
+
Approvals.verify hello, :namer => namer
|
38
|
+
end
|
39
|
+
|
40
|
+
it "verifies html" do
|
41
|
+
html = <<-HTML
|
42
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"><html><head><title>Approval</title></head><body><h1>An Approval</h1><p>It has a paragraph</p></body></html>
|
43
|
+
HTML
|
44
|
+
Approvals.verify html, :format => :html, :namer => namer
|
45
|
+
end
|
46
|
+
|
47
|
+
it "verifies xml" do
|
48
|
+
xml = "<xml char=\"kiddo\"><node><content name='beatrice' /></node><node aliases='5'><content /></node></xml>"
|
49
|
+
Approvals.verify xml, :format => :xml, :namer => namer
|
50
|
+
end
|
51
|
+
|
52
|
+
it "verifies json" do
|
53
|
+
json = '{"pet":{"species":"turtle","color":"green","name":"Anthony"}}'
|
54
|
+
Approvals.verify json, :format => :json, :namer => namer
|
55
|
+
end
|
56
|
+
|
57
|
+
it "verifies an executable" do
|
58
|
+
executable = Approvals::Executable.new('SELECT 1') do |command|
|
59
|
+
puts "your slip is showing (#{command})"
|
60
|
+
end
|
61
|
+
|
62
|
+
Approvals.verify executable, :namer => namer
|
63
|
+
end
|
64
|
+
end
|