approvals 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.
- 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
|