git-approvals 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.pryrc ADDED
@@ -0,0 +1,2 @@
1
+ $: << './lib'
2
+ require 'git-approvals'
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git-approvals.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec' do
2
+ watch( %r{^spec/.+_spec\.rb$} )
3
+ watch( %r{^lib/(.+)\.rb$} ){ |m| "spec/#{m[1]}_spec.rb" }
4
+ watch( 'spec/spec_helper.rb' ){ 'spec' }
5
+ watch( 'Gemfile.lock' ){ 'spec' }
6
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jeremy Ruppel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # Git::Approvals
2
+
3
+ Simple git-powered approval tests.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'git-approvals'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install git-approvals
18
+
19
+ ## Usage
20
+
21
+ > TODO describe standalone usage
22
+
23
+ ### With RSpec
24
+
25
+ In your spec_helper.rb or wherever, simply `require 'rspec/approvals'`.
26
+ Now you can use the `verify` expectation in your specs:
27
+
28
+ `spec/foo_spec.rb`
29
+
30
+ ``` ruby
31
+ require 'spec_helper'
32
+
33
+ describe Foo do
34
+
35
+ example 'bar' do
36
+ verify { Foo.bar }
37
+ end
38
+ end
39
+ ```
40
+
41
+ The result of `Foo.bar` will be written to `spec/foo_spec/foo/bar.txt`.
42
+ The test will fail because the file is not checked in to your git repo,
43
+ meaning you haven't approved it yet, so add it to approve it:
44
+
45
+ `git add spec/foo_spec/foo_bar.txt`
46
+
47
+ Another test run shows that the test now passes. On the next test run, the
48
+ same file will be written out. If git says the file has changed, the
49
+ test will fail.
50
+
51
+ ## Contributing
52
+
53
+ 1. Fork it
54
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
55
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
56
+ 4. Push to the branch (`git push origin my-new-feature`)
57
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git/approvals/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git-approvals"
8
+ spec.version = Git::Approvals::VERSION
9
+ spec.authors = ["Jeremy Ruppel"]
10
+ spec.email = ["jeremy.ruppel@gmail.com"]
11
+ spec.description = %q{Simple git-powered approval tests. With RSpec integration.}
12
+ spec.summary = %q{Simple git-powered approval tests.}
13
+ spec.homepage = 'https://github.com/jeremyruppel/git-approvals'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'awesome_print', '1.1.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'rspec', '~> 2.13.0'
25
+ spec.add_development_dependency 'guard-rspec', '~> 2.5.2'
26
+ spec.add_development_dependency 'rb-fsevent', '~> 0.9'
27
+ spec.add_development_dependency 'pry'
28
+ spec.add_development_dependency 'rake'
29
+ end
@@ -0,0 +1,66 @@
1
+ require 'open3'
2
+
3
+ module Git
4
+ module Approvals
5
+ class Approval
6
+
7
+ FORMATTERS = {
8
+ :txt => lambda { |object|
9
+ require 'awesome_print'
10
+ object.awesome_inspect :plain => true, :indent => 2
11
+ },
12
+ :json => lambda { |string|
13
+ require 'json'
14
+ JSON.pretty_generate JSON.parse( string )
15
+ }
16
+ }
17
+
18
+ def initialize( path, options={} ) # :nodoc:
19
+ @path, @options = path, options
20
+
21
+ # rewrite the extension for the file based on the format
22
+ @path.chomp! File.extname( @path )
23
+ @path << '.' << format.to_s
24
+ end
25
+ attr_reader :path, :options
26
+
27
+ ##
28
+ #
29
+ def diff( string, &block )
30
+ # Make sure the directory of the file exists.
31
+ FileUtils.mkdir_p File.dirname( path )
32
+
33
+ # Write the new string to the file.
34
+ File.open path, 'w' do |f|
35
+ f << FORMATTERS[ format ][ string ]
36
+ end
37
+
38
+ # If the file hasn't been checked in, raise an error.
39
+ sh "git ls-files #{path} --error-unmatch" do |err|
40
+ raise Errno::ENOENT, path
41
+ end
42
+
43
+ # If the file has changed, call the block.
44
+ sh "git diff --exit-code #{path}" do |err|
45
+ block.call err
46
+ end
47
+ end
48
+
49
+ ##
50
+ # Shells out the given command. If the command exits with success,
51
+ # does nothing. If the command does not exit with success, yields
52
+ # the error output to the block.
53
+ def sh( cmd )
54
+ out, cmd = Open3.capture2e cmd
55
+ yield out if !cmd.success?
56
+ end
57
+
58
+ ##
59
+ # The format of this approval. Determines the file extension
60
+ # and also the formatter to use when writing the approval file.
61
+ def format
62
+ options[ :format ] || :txt
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,17 @@
1
+ module Git
2
+ module Approvals
3
+ module Utils
4
+
5
+ ##
6
+ # Converts a string into a string that can be used as a filename.
7
+ def filenamify( string )
8
+ string
9
+ .gsub( /([a-z])([A-Z])/, '\1_\2' )
10
+ .gsub( /\W+/, '_' )
11
+ .gsub( /^_|_$/, '' )
12
+ .downcase
13
+ end
14
+ module_function :filenamify
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module Git
2
+ module Approvals
3
+ VERSION = '0.1.2'
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require 'git/approvals/version'
2
+
3
+ module Git
4
+ module Approvals
5
+ autoload :Approval, 'git/approvals/approval'
6
+ autoload :Utils, 'git/approvals/utils'
7
+ end
8
+ end
@@ -0,0 +1 @@
1
+ require 'git/approvals'
@@ -0,0 +1,44 @@
1
+ require 'git-approvals'
2
+
3
+ module RSpec
4
+ module Approvals
5
+
6
+ ##
7
+ # Verifies that the result of the block is the same as the approved
8
+ # version.
9
+ def verify( options={}, &block )
10
+ approval = Git::Approvals::Approval.new( approval_path, options )
11
+ approval.diff( block.call ) do |err|
12
+ ::RSpec::Expectations.fail_with err
13
+ end
14
+ rescue Errno::ENOENT => e
15
+ ::RSpec::Expectations.fail_with e.message
16
+ EOS
17
+ end
18
+
19
+ ##
20
+ # The path to the approval for this example
21
+ def approval_path
22
+ File.join approval_directory, approval_filename
23
+ end
24
+
25
+ ##
26
+ # The approval filename
27
+ def approval_filename
28
+ parts = [ example, *example.example_group.parent_groups ].map do |ex|
29
+ Git::Approvals::Utils.filenamify ex.description
30
+ end
31
+ File.join parts.to_a.reverse
32
+ end
33
+
34
+ ##
35
+ # The directory containing this spec's approvals
36
+ def approval_directory
37
+ example.file_path.sub /\.rb$/, ''
38
+ end
39
+ end
40
+
41
+ ##
42
+ #
43
+ configure { |config| config.include RSpec::Approvals }
44
+ end
@@ -0,0 +1,5 @@
1
+ [
2
+ [0] :foo,
3
+ [1] :bar,
4
+ [2] :baz
5
+ ]
@@ -0,0 +1,4 @@
1
+ {
2
+ "foo": "bar",
3
+ "baz": "quux"
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ :foo => "bar",
3
+ :baz => "quux"
4
+ }
@@ -0,0 +1 @@
1
+ "IT WERKS"
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Git::Approvals::Approval do
4
+
5
+ describe 'initialize' do
6
+ subject { described_class.new './foo/bar.txt' }
7
+
8
+ its( :path ){ should == './foo/bar.txt' }
9
+ its( :options ){ should == { } }
10
+ end
11
+
12
+ describe '#diff' do
13
+ subject { described_class.new './foo/bar.txt' }
14
+
15
+ before { FileUtils.stub :mkdir_p => true }
16
+ before { File.stub :open => true }
17
+
18
+ it 'raises an exception when the file is not checked in' do
19
+ Open3.should_receive( :capture2e ).with( 'git ls-files ./foo/bar.txt --error-unmatch' ) do
20
+ [ '', double( 'status', :success? => false ) ]
21
+ end
22
+ expect { |block| subject.diff '', &block }.to raise_error( Errno::ENOENT, 'No such file or directory - ./foo/bar.txt' )
23
+ end
24
+ it 'calls the block when the file has been changed' do
25
+ Open3.should_receive( :capture2e ).with( 'git ls-files ./foo/bar.txt --error-unmatch' ) do
26
+ [ '', double( 'status', :success? => true ) ]
27
+ end
28
+ Open3.should_receive( :capture2e ).with( 'git diff --exit-code ./foo/bar.txt' ) do
29
+ [ 'error verbatim', double( 'status', :success? => false ) ]
30
+ end
31
+ expect { |block| subject.diff '', &block }.to yield_with_args( 'error verbatim' )
32
+ end
33
+ it 'does nothing when the file has not been changed' do
34
+ Open3.should_receive( :capture2e ).with( 'git ls-files ./foo/bar.txt --error-unmatch' ) do
35
+ [ '', double( 'status', :success? => true ) ]
36
+ end
37
+ Open3.should_receive( :capture2e ).with( 'git diff --exit-code ./foo/bar.txt' ) do
38
+ [ '', double( 'status', :success? => true ) ]
39
+ end
40
+ expect { |block| subject.diff '', &block }.not_to yield_control
41
+ end
42
+ end
43
+
44
+ describe 'extensions' do
45
+ it 'leaves the extension if specified' do
46
+ approval = described_class.new './foo/bar.txt'
47
+ approval.path.should == './foo/bar.txt'
48
+ end
49
+ it 'uses the format extension if provided' do
50
+ approval = described_class.new './foo/bar.baz', :format => :txt
51
+ approval.path.should == './foo/bar.txt'
52
+ end
53
+ end
54
+
55
+ describe 'formats' do
56
+ it 'formats strings' do
57
+ approval = described_class.new './spec/fixtures/string.txt'
58
+ approval.diff( 'IT WERKS' ){ |diff| fail diff }
59
+ end
60
+ it 'formats arrays' do
61
+ approval = described_class.new './spec/fixtures/array.txt'
62
+ approval.diff( [ :foo, :bar, :baz ] ){ |diff| fail diff }
63
+ end
64
+ it 'formats hashes' do
65
+ approval = described_class.new './spec/fixtures/hash.txt'
66
+ approval.diff( { :foo => 'bar', :baz => 'quux' } ){ |diff| fail diff }
67
+ end
68
+ it 'formats json' do
69
+ approval = described_class.new './spec/fixtures/hash.json', :format => :json
70
+ approval.diff( '{"foo":"bar","baz":"quux"}' ){ |diff| fail diff }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Git::Approvals::Utils do
4
+
5
+ describe '#filenameify' do
6
+ {
7
+ 'Foo' => 'foo',
8
+ 'Foo Bar' => 'foo_bar',
9
+ 'FooBar' => 'foo_bar',
10
+ '#foo' => 'foo',
11
+ 'foo#' => 'foo'
12
+ }.each do |original, filename|
13
+ it 'converts "%s" to "%s"' % [ original, filename ] do
14
+ described_class.filenamify( original ).should == filename
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'rspec/approvals'
3
+
4
+ describe 'RSpec integration' do
5
+
6
+ it 'provides the correct approval directory' do
7
+ approval_directory.should == './spec/rspec/approvals_spec'
8
+ end
9
+ it 'provides the correct approval filename' do
10
+ approval_filename.should == 'rspec_integration/provides_the_correct_approval_filename'
11
+ end
12
+ it 'provides the correct approval path' do
13
+ approval_path.should == './spec/rspec/approvals_spec/rspec_integration/provides_the_correct_approval_path'
14
+ end
15
+
16
+ describe '#verify' do
17
+ # make sure to clean up any failed fixtures
18
+ after { `git checkout #{approval_directory}` }
19
+
20
+ it 'passes when unchanged' do
21
+ verify { 'IT WERKS' }
22
+ end
23
+ it 'fails when changed' do
24
+ expect { verify { 'IT BROKE' } }.to raise_error( RSpec::Expectations::ExpectationNotMetError )
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ require 'git-approvals'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ # Run specs in random order to surface order dependencies. If you find an
9
+ # order dependency and want to debug it, you can fix the order by providing
10
+ # the seed, which is printed after each run.
11
+ # --seed 1234
12
+ config.order = 'random'
13
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-approvals
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeremy Ruppel
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: awesome_print
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - '='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.1.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.1.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.3'
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: '1.3'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.13.0
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: 2.13.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: guard-rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.5.2
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: 2.5.2
78
+ - !ruby/object:Gem::Dependency
79
+ name: rb-fsevent
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '0.9'
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.9'
94
+ - !ruby/object:Gem::Dependency
95
+ name: pry
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
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: rake
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: Simple git-powered approval tests. With RSpec integration.
127
+ email:
128
+ - jeremy.ruppel@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - .pryrc
135
+ - .rspec
136
+ - Gemfile
137
+ - Guardfile
138
+ - LICENSE.txt
139
+ - README.md
140
+ - Rakefile
141
+ - git-approvals.gemspec
142
+ - lib/git-approvals.rb
143
+ - lib/git/approvals.rb
144
+ - lib/git/approvals/approval.rb
145
+ - lib/git/approvals/utils.rb
146
+ - lib/git/approvals/version.rb
147
+ - lib/rspec/approvals.rb
148
+ - spec/fixtures/array.txt
149
+ - spec/fixtures/hash.json
150
+ - spec/fixtures/hash.txt
151
+ - spec/fixtures/string.txt
152
+ - spec/git/approvals/approval_spec.rb
153
+ - spec/git/approvals/utils_spec.rb
154
+ - spec/rspec/approvals_spec.rb
155
+ - spec/rspec/approvals_spec/rspec_integration/verify/fails_when_changed.txt
156
+ - spec/rspec/approvals_spec/rspec_integration/verify/passes_when_unchanged.txt
157
+ - spec/spec_helper.rb
158
+ homepage: https://github.com/jeremyruppel/git-approvals
159
+ licenses:
160
+ - MIT
161
+ post_install_message:
162
+ rdoc_options: []
163
+ require_paths:
164
+ - lib
165
+ required_ruby_version: !ruby/object:Gem::Requirement
166
+ none: false
167
+ requirements:
168
+ - - ! '>='
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ none: false
173
+ requirements:
174
+ - - ! '>='
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubyforge_project:
179
+ rubygems_version: 1.8.23
180
+ signing_key:
181
+ specification_version: 3
182
+ summary: Simple git-powered approval tests.
183
+ test_files:
184
+ - spec/fixtures/array.txt
185
+ - spec/fixtures/hash.json
186
+ - spec/fixtures/hash.txt
187
+ - spec/fixtures/string.txt
188
+ - spec/git/approvals/approval_spec.rb
189
+ - spec/git/approvals/utils_spec.rb
190
+ - spec/rspec/approvals_spec.rb
191
+ - spec/rspec/approvals_spec/rspec_integration/verify/fails_when_changed.txt
192
+ - spec/rspec/approvals_spec/rspec_integration/verify/passes_when_unchanged.txt
193
+ - spec/spec_helper.rb
194
+ has_rdoc: