git-approvals 0.2.2 → 0.3.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.
@@ -18,10 +18,12 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'awesome_print', '1.1.0'
21
+ spec.add_dependency 'tilt', '~> 1.4.1'
22
22
 
23
23
  # soft dependencies
24
- spec.add_development_dependency 'uglifier', '~> 2.1.1'
24
+ spec.add_development_dependency 'awesome_print', '~> 1.1.0'
25
+ spec.add_development_dependency 'uglifier', '~> 2.1.1'
26
+ spec.add_development_dependency 'sass', '~> 3.2.9'
25
27
 
26
28
  spec.add_development_dependency 'bundler', '~> 1.3'
27
29
  spec.add_development_dependency 'rspec', '~> 2.13.0'
@@ -1,106 +1,46 @@
1
1
  require 'open3'
2
+ require 'pathname'
3
+ require 'tilt'
2
4
 
3
5
  module Git
4
6
  module Approvals
5
- ##
6
- # The base class for approval errors.
7
- class ApprovalError < StandardError; end
8
-
9
- ##
10
- # Raised when an unregistered formatter is requested.
11
- class UnknownFormat < ApprovalError
12
- def initialize( name )
13
- super "There is no registered formatter named '#{name}'."
14
- end
15
- end
16
-
17
- ##
18
- # Raised when a formatter's soft dependencies are missing.
19
- class MissingSoftDependency < ApprovalError
20
- def initialize( name, dependency )
21
- super <<-EOS
22
- The format '#{name}' requires #{dependency}.
23
- To use this formatter, make sure to load the dependency:
24
-
25
- require '#{dependency}'
26
- EOS
27
- end
28
- end
29
7
 
30
8
  ##
31
9
  #
32
- class Approval
33
-
34
- class << self
35
-
36
- ##
37
- # Registers a new formatter block by name. The block
38
- # is expected to return a deterministic string
39
- # representation of an object.
40
- def register_formatter( name, &block )
41
- formatters[ name.to_sym ] = block
42
- end
43
-
44
- ##
45
- # Looks up the formatter named `name` and attempts to
46
- # format `object`. Raises a helpful error message if
47
- # a formatter's soft dependency cannot be loaded.
48
- def format( name, object )
49
- formatters[ name ][ object ]
50
- rescue NoMethodError => e
51
- raise UnknownFormat, name
52
- rescue LoadError => e
53
- raise MissingSoftDependency.new name,
54
- e.message[ /^cannot load such file -- (.*)$/, 1 ]
55
- end
10
+ class Approval < Pathname
56
11
 
57
- protected
12
+ def initialize( path, options={} ) # :nodoc:
13
+ @options = options
58
14
 
59
- ##
60
- # The hash of registered formatters by name.
61
- def formatters
62
- @formatters ||= { }
63
- end
64
- end
15
+ path = Pathname( path )
16
+ path = munge_format( path )
17
+ path = munge_filename( path )
65
18
 
66
- ##
67
- # The `txt` format requires the `awesome_print` gem.
68
- # It is suitable for formatting most native ruby types.
69
- register_formatter :txt do |object|
70
- require 'awesome_print'
71
- object.awesome_inspect :plain => true, :indent => -2
19
+ super path.to_path
72
20
  end
21
+ attr_reader :options
73
22
 
74
23
  ##
75
- # The `json` format requires the `json` library.
76
- # It is suitable for formatting JSON strings.
77
- register_formatter :json do |object|
78
- require 'json'
79
- JSON.pretty_generate JSON.parse( object )
24
+ # Makes sure the given pathname has an extension.
25
+ def munge_format( path )
26
+ ext = [ options[ :format ], path.extname, 'txt' ].detect do |arg|
27
+ !arg.nil? && !arg.empty?
28
+ end
29
+ ext = ext.to_s
30
+ ext = '.' + ext unless ext.start_with?( '.' )
31
+ path.sub_ext ext
80
32
  end
81
33
 
82
34
  ##
83
- # The `js` format requires the `uglifier` gem.
84
- # It is suitable for formatting javascript.
85
- register_formatter :js do |object|
86
- require 'uglifier'
87
- Uglifier.compile object,
88
- :output => {
89
- :beautify => true,
90
- :indent_level => 2,
91
- :comments => :all,
92
- :space_colon => true
93
- }
94
- end
95
-
96
- def initialize( path, options={} ) # :nodoc:
97
- @path, @options = path, options
98
-
99
- # rewrite the extension for the file based on the format
100
- @path.chomp! File.extname( @path )
101
- @path << '.' << format.to_s
35
+ # Makes sure the given pathname has the correct filename.
36
+ def munge_filename( path )
37
+ if filename = options[ :filename ]
38
+ dir, base = path.split
39
+ dir.join( filename + base.extname )
40
+ else
41
+ path
42
+ end
102
43
  end
103
- attr_reader :path, :options
104
44
 
105
45
  ##
106
46
  # Diffs the given string with this approval file. If the
@@ -109,20 +49,20 @@ EOS
109
49
  # called if the diff fails, meaning there are differences.
110
50
  def diff( string, &block )
111
51
  # Make sure the directory of the file exists.
112
- FileUtils.mkdir_p File.dirname( path )
52
+ dirname.mkpath
113
53
 
114
54
  # Write the new string to the file.
115
- File.open path, 'w' do |f|
116
- f << self.class.format( format, string )
55
+ open 'w' do |f|
56
+ f << Tilt.new( to_path ).render( string )
117
57
  end
118
58
 
119
59
  # If the file hasn't been checked in, raise an error.
120
- sh "git ls-files #{path} --error-unmatch" do |err|
121
- raise Errno::ENOENT, path
60
+ sh "git ls-files #{to_path} --error-unmatch" do |err|
61
+ raise Errno::ENOENT, to_path
122
62
  end
123
63
 
124
64
  # If the file has changed, call the block.
125
- sh "git diff --exit-code #{path}" do |err|
65
+ sh "git diff --exit-code #{to_path}" do |err|
126
66
  block.call err
127
67
  end
128
68
  end
@@ -135,13 +75,13 @@ EOS
135
75
  out, cmd = Open3.capture2e cmd
136
76
  yield out if !cmd.success?
137
77
  end
138
-
139
- ##
140
- # The format of this approval. Determines the file extension
141
- # and also the formatter to use when writing the approval file.
142
- def format
143
- options[ :format ] || :txt
144
- end
145
78
  end
79
+
80
+ ##
81
+ # Register all formatters as tilt templates.
82
+ Tilt.register AwesomePrintFormatter, 'txt'
83
+ Tilt.register JSONFormatter, 'json'
84
+ Tilt.register UglifierFormatter, 'js'
85
+ Tilt.register SassFormatter, 'css'
146
86
  end
147
87
  end
@@ -0,0 +1,28 @@
1
+ require 'tilt'
2
+
3
+ module Git
4
+ module Approvals
5
+ class AwesomePrintFormatter < Tilt::Template
6
+
7
+ def self.engine_initialized?
8
+ defined?(::AwesomePrint)
9
+ end
10
+
11
+ def initialize_engine
12
+ require_template_library 'awesome_print'
13
+ end
14
+
15
+ def prepare
16
+ end
17
+
18
+ def evaluate( context, locals, &block )
19
+ # TODO use locals as options to the formatter
20
+ # TODO require awesome_print/inspector to not pollute kernel, etc
21
+ context.awesome_inspect \
22
+ :plain => true,
23
+ :indent => -2
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,24 @@
1
+ require 'tilt'
2
+
3
+ module Git
4
+ module Approvals
5
+ class JSONFormatter < Tilt::Template
6
+
7
+ def self.engine_initialized?
8
+ defined?(::JSON)
9
+ end
10
+
11
+ def initialize_engine
12
+ require_template_library 'json'
13
+ end
14
+
15
+ def prepare
16
+ end
17
+
18
+ def evaluate( context, locals, &block )
19
+ # TODO use locals as options to the formatter
20
+ ::JSON.pretty_generate( ::JSON.parse( context ) )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,50 @@
1
+ require 'git-approvals'
2
+
3
+ begin
4
+ gem 'rspec-core', '>= 2.12.0'
5
+ rescue Gem::LoadError => e
6
+ raise 'rspec/approvals requires rspec-core >= 2.12.0. Please upgrade rspec.'
7
+ end
8
+
9
+ module RSpec
10
+ module Approvals
11
+
12
+ ##
13
+ # Verifies that the result of the block is the same as the approved
14
+ # version.
15
+ def verify( options={}, &block )
16
+ approval = Git::Approvals::Approval.new( approval_path, options )
17
+ approval.diff( block.call ) do |err|
18
+ ::RSpec::Expectations.fail_with err
19
+ end
20
+ rescue Errno::ENOENT => e
21
+ ::RSpec::Expectations.fail_with e.message
22
+ EOS
23
+ end
24
+
25
+ ##
26
+ # The path to the approval for this example
27
+ def approval_path
28
+ File.join approval_directory, approval_filename
29
+ end
30
+
31
+ ##
32
+ # The approval filename
33
+ def approval_filename
34
+ parts = [ example, *example.example_group.parent_groups ].map do |ex|
35
+ Git::Approvals::Utils.filenamify ex.description
36
+ end
37
+ File.join parts.to_a.reverse
38
+ end
39
+
40
+ ##
41
+ # The directory containing this spec's approvals
42
+ def approval_directory
43
+ example.file_path.sub /\.rb$/, ''
44
+ end
45
+ end
46
+
47
+ ##
48
+ #
49
+ configure { |config| config.include RSpec::Approvals }
50
+ end
@@ -0,0 +1,29 @@
1
+ require 'tilt'
2
+
3
+ module Git
4
+ module Approvals
5
+ class SassFormatter < Tilt::Template
6
+
7
+ def self.engine_initialized?
8
+ defined?(::Sass::Engine)
9
+ end
10
+
11
+ def initialize_engine
12
+ require_template_library 'sass'
13
+ end
14
+
15
+ def prepare
16
+ end
17
+
18
+ def evaluate( context, locals, &block )
19
+ # TODO use locals as options to the formatter
20
+ ::Sass::Engine.new( context, {
21
+ :syntax => :scss,
22
+ :cache => false,
23
+ :read_cache => false,
24
+ :style => :expanded
25
+ } ).render
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ require 'tilt'
2
+
3
+ module Git
4
+ module Approvals
5
+ class UglifierFormatter < Tilt::Template
6
+
7
+ def self.engine_initialized?
8
+ defined?(::Uglifier)
9
+ end
10
+
11
+ def initialize_engine
12
+ require_template_library 'uglifier'
13
+ end
14
+
15
+ def prepare
16
+ end
17
+
18
+ def evaluate( context, locals, &block )
19
+ # TODO use locals as options to the formatter
20
+ ::Uglifier.compile context,
21
+ :output => {
22
+ :beautify => true,
23
+ :indent_level => 2,
24
+ :comments => :all,
25
+ :space_colon => true
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  module Git
2
2
  module Approvals
3
- VERSION = '0.2.2'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
data/lib/git/approvals.rb CHANGED
@@ -2,7 +2,11 @@ require 'git/approvals/version'
2
2
 
3
3
  module Git
4
4
  module Approvals
5
- autoload :Approval, 'git/approvals/approval'
6
- autoload :Utils, 'git/approvals/utils'
5
+ autoload :Approval, 'git/approvals/approval'
6
+ autoload :AwesomePrintFormatter, 'git/approvals/awesome_print_formatter.rb'
7
+ autoload :JSONFormatter, 'git/approvals/json_formatter.rb'
8
+ autoload :SassFormatter, 'git/approvals/sass_formatter.rb'
9
+ autoload :UglifierFormatter, 'git/approvals/uglifier_formatter.rb'
10
+ autoload :Utils, 'git/approvals/utils'
7
11
  end
8
12
  end
@@ -1,50 +1 @@
1
- require 'git-approvals'
2
-
3
- begin
4
- gem 'rspec-core', '>= 2.12.0'
5
- rescue Gem::LoadError => e
6
- raise 'rspec/approvals requires rspec-core >= 2.12.0. Please upgrade rspec.'
7
- end
8
-
9
- module RSpec
10
- module Approvals
11
-
12
- ##
13
- # Verifies that the result of the block is the same as the approved
14
- # version.
15
- def verify( options={}, &block )
16
- approval = Git::Approvals::Approval.new( approval_path, options )
17
- approval.diff( block.call ) do |err|
18
- ::RSpec::Expectations.fail_with err
19
- end
20
- rescue Errno::ENOENT => e
21
- ::RSpec::Expectations.fail_with e.message
22
- EOS
23
- end
24
-
25
- ##
26
- # The path to the approval for this example
27
- def approval_path
28
- File.join approval_directory, approval_filename
29
- end
30
-
31
- ##
32
- # The approval filename
33
- def approval_filename
34
- parts = [ example, *example.example_group.parent_groups ].map do |ex|
35
- Git::Approvals::Utils.filenamify ex.description
36
- end
37
- File.join parts.to_a.reverse
38
- end
39
-
40
- ##
41
- # The directory containing this spec's approvals
42
- def approval_directory
43
- example.file_path.sub /\.rb$/, ''
44
- end
45
- end
46
-
47
- ##
48
- #
49
- configure { |config| config.include RSpec::Approvals }
50
- end
1
+ require 'git/approvals/rspec'
@@ -0,0 +1,3 @@
1
+ html, body {
2
+ font-family: "Helvetica Neue";
3
+ }
@@ -2,13 +2,28 @@ require 'spec_helper'
2
2
 
3
3
  describe Git::Approvals::Approval do
4
4
 
5
- describe 'initialize' do
5
+ describe '#initialize' do
6
6
  subject { described_class.new './foo/bar.txt' }
7
7
 
8
- its( :path ){ should == './foo/bar.txt' }
8
+ its( :to_path ){ should == './foo/bar.txt' }
9
9
  its( :options ){ should == { } }
10
10
  end
11
11
 
12
+ describe '#options' do
13
+ describe ':format' do
14
+ it 'replaces the extension' do
15
+ subject = described_class.new 'foo/bar.txt', :format => :json
16
+ subject.to_path.should == 'foo/bar.json'
17
+ end
18
+ end
19
+ describe ':filename' do
20
+ it 'replaces the filename' do
21
+ subject = described_class.new 'foo/bar.txt', :filename => 'baz'
22
+ subject.to_path.should == 'foo/baz.txt'
23
+ end
24
+ end
25
+ end
26
+
12
27
  describe '#diff' do
13
28
  subject { described_class.new './foo/bar.txt' }
14
29
 
@@ -41,17 +56,6 @@ describe Git::Approvals::Approval do
41
56
  end
42
57
  end
43
58
 
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
59
  describe 'formats' do
56
60
  it 'formats strings' do
57
61
  approval = described_class.new './spec/fixtures/string.txt'
@@ -66,15 +70,22 @@ describe Git::Approvals::Approval do
66
70
  approval.diff( { :foo => 'bar', :quux => 'bar' } ){ |diff| fail diff }
67
71
  end
68
72
  it 'formats json' do
69
- approval = described_class.new './spec/fixtures/hash.json', :format => :json
73
+ approval = described_class.new './spec/fixtures/hash.json'
70
74
  approval.diff( '{"foo":"bar","baz":"quux"}' ){ |diff| fail diff }
71
75
  end
72
76
  it 'formats javascript' do
73
- approval = described_class.new './spec/fixtures/asset.js', :format => :js
77
+ approval = described_class.new './spec/fixtures/asset.js'
74
78
  approval.diff( <<-EOS ){ |diff| fail diff }
75
79
  // Comments are preserved
76
80
  (function(){return {status:"IT WERKS"};})();
77
81
  EOS
78
82
  end
83
+ it 'formats css' do
84
+ approval = described_class.new './spec/fixtures/asset.css'
85
+ approval.diff( <<-EOS ){ |diff| fail diff }
86
+ // Comments are preserved
87
+ html,body{font-family:"Helvetica Neue";}
88
+ EOS
89
+ end
79
90
  end
80
91
  end
@@ -4,13 +4,13 @@ require 'rspec/approvals'
4
4
  describe 'RSpec integration' do
5
5
 
6
6
  it 'provides the correct approval directory' do
7
- approval_directory.should == './spec/rspec/approvals_spec'
7
+ approval_directory.should == './spec/git/approvals/rspec_spec'
8
8
  end
9
9
  it 'provides the correct approval filename' do
10
10
  approval_filename.should == 'rspec_integration/provides_the_correct_approval_filename'
11
11
  end
12
12
  it 'provides the correct approval path' do
13
- approval_path.should == './spec/rspec/approvals_spec/rspec_integration/provides_the_correct_approval_path'
13
+ approval_path.should == './spec/git/approvals/rspec_spec/rspec_integration/provides_the_correct_approval_path'
14
14
  end
15
15
 
16
16
  describe '#verify' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-approvals
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,38 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-11 00:00:00.000000000 Z
12
+ date: 2013-06-14 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: tilt
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.1
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.4.1
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: awesome_print
16
32
  requirement: !ruby/object:Gem::Requirement
17
33
  none: false
18
34
  requirements:
19
- - - '='
35
+ - - ~>
20
36
  - !ruby/object:Gem::Version
21
37
  version: 1.1.0
22
- type: :runtime
38
+ type: :development
23
39
  prerelease: false
24
40
  version_requirements: !ruby/object:Gem::Requirement
25
41
  none: false
26
42
  requirements:
27
- - - '='
43
+ - - ~>
28
44
  - !ruby/object:Gem::Version
29
45
  version: 1.1.0
30
46
  - !ruby/object:Gem::Dependency
@@ -43,6 +59,22 @@ dependencies:
43
59
  - - ~>
44
60
  - !ruby/object:Gem::Version
45
61
  version: 2.1.1
62
+ - !ruby/object:Gem::Dependency
63
+ name: sass
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 3.2.9
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: 3.2.9
46
78
  - !ruby/object:Gem::Dependency
47
79
  name: bundler
48
80
  requirement: !ruby/object:Gem::Requirement
@@ -160,19 +192,25 @@ files:
160
192
  - lib/git-approvals.rb
161
193
  - lib/git/approvals.rb
162
194
  - lib/git/approvals/approval.rb
195
+ - lib/git/approvals/awesome_print_formatter.rb
196
+ - lib/git/approvals/json_formatter.rb
197
+ - lib/git/approvals/rspec.rb
198
+ - lib/git/approvals/sass_formatter.rb
199
+ - lib/git/approvals/uglifier_formatter.rb
163
200
  - lib/git/approvals/utils.rb
164
201
  - lib/git/approvals/version.rb
165
202
  - lib/rspec/approvals.rb
166
203
  - spec/fixtures/array.txt
204
+ - spec/fixtures/asset.css
167
205
  - spec/fixtures/asset.js
168
206
  - spec/fixtures/hash.json
169
207
  - spec/fixtures/hash.txt
170
208
  - spec/fixtures/string.txt
171
209
  - spec/git/approvals/approval_spec.rb
210
+ - spec/git/approvals/rspec_spec.rb
211
+ - spec/git/approvals/rspec_spec/rspec_integration/verify/fails_when_changed.txt
212
+ - spec/git/approvals/rspec_spec/rspec_integration/verify/passes_when_unchanged.txt
172
213
  - spec/git/approvals/utils_spec.rb
173
- - spec/rspec/approvals_spec.rb
174
- - spec/rspec/approvals_spec/rspec_integration/verify/fails_when_changed.txt
175
- - spec/rspec/approvals_spec/rspec_integration/verify/passes_when_unchanged.txt
176
214
  - spec/spec_helper.rb
177
215
  homepage: https://github.com/jeremyruppel/git-approvals
178
216
  licenses:
@@ -201,14 +239,15 @@ specification_version: 3
201
239
  summary: Simple git-powered approval tests.
202
240
  test_files:
203
241
  - spec/fixtures/array.txt
242
+ - spec/fixtures/asset.css
204
243
  - spec/fixtures/asset.js
205
244
  - spec/fixtures/hash.json
206
245
  - spec/fixtures/hash.txt
207
246
  - spec/fixtures/string.txt
208
247
  - spec/git/approvals/approval_spec.rb
248
+ - spec/git/approvals/rspec_spec.rb
249
+ - spec/git/approvals/rspec_spec/rspec_integration/verify/fails_when_changed.txt
250
+ - spec/git/approvals/rspec_spec/rspec_integration/verify/passes_when_unchanged.txt
209
251
  - spec/git/approvals/utils_spec.rb
210
- - spec/rspec/approvals_spec.rb
211
- - spec/rspec/approvals_spec/rspec_integration/verify/fails_when_changed.txt
212
- - spec/rspec/approvals_spec/rspec_integration/verify/passes_when_unchanged.txt
213
252
  - spec/spec_helper.rb
214
253
  has_rdoc: