git_diff 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +17 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +86 -0
  8. data/Rakefile +10 -0
  9. data/git_diff.gemspec +21 -0
  10. data/lib/git_diff/diff.rb +38 -0
  11. data/lib/git_diff/file.rb +66 -0
  12. data/lib/git_diff/hunk.rb +42 -0
  13. data/lib/git_diff/line/addition.rb +13 -0
  14. data/lib/git_diff/line/context.rb +28 -0
  15. data/lib/git_diff/line/deletion.rb +13 -0
  16. data/lib/git_diff/line.rb +22 -0
  17. data/lib/git_diff/line_number.rb +42 -0
  18. data/lib/git_diff/line_number_calculation.rb +22 -0
  19. data/lib/git_diff/line_number_range.rb +18 -0
  20. data/lib/git_diff/parser.rb +22 -0
  21. data/lib/git_diff/range_info.rb +28 -0
  22. data/lib/git_diff/stats.rb +18 -0
  23. data/lib/git_diff/stats_calculator.rb +31 -0
  24. data/lib/git_diff/stats_collector/hunk.rb +41 -0
  25. data/lib/git_diff/stats_collector/rollup.rb +15 -0
  26. data/lib/git_diff/stats_collector.rb +2 -0
  27. data/lib/git_diff/stats_rollup.rb +0 -0
  28. data/lib/git_diff/version.rb +3 -0
  29. data/lib/git_diff.rb +23 -0
  30. data/test/diff_file_test.rb +60 -0
  31. data/test/git_diff_test.rb +131 -0
  32. data/test/hunk_test.rb +27 -0
  33. data/test/line/addition_test.rb +15 -0
  34. data/test/line/context_test.rb +21 -0
  35. data/test/line/deletion_test.rb +15 -0
  36. data/test/line_number_calculation_test.rb +34 -0
  37. data/test/line_number_range_test.rb +24 -0
  38. data/test/line_number_test.rb +30 -0
  39. data/test/line_test.rb +30 -0
  40. data/test/range_info_test.rb +32 -0
  41. data/test/stats_calculator_test.rb +47 -0
  42. data/test/test_helper.rb +3 -0
  43. metadata +127 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e3b41b08c6a9dccc59f7a462cdcdb68e5b1cfaec
4
+ data.tar.gz: 366a324e52d933f22147093c90d8844d4af34710
5
+ SHA512:
6
+ metadata.gz: bb7a0f39886899976aeb0a98aedd8ffbb7588a61177072dd77c082ee14b72a11ebb30908af0d7d99ac5e50eb9db1e3a9d46cd9dfbfdae657020ba7a885f33309
7
+ data.tar.gz: 7d0e155533df7ef127f9c1769b7f81e281cba163c22dc72af5b8a1f0fe845aa3d21e2368712c4c383d96ff8cd68762303b2d99ed7b91af680a07c12e7e5e4670
data/.gitignore ADDED
@@ -0,0 +1,13 @@
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
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git_diff.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ git_diff (0.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ rake (10.1.0)
10
+
11
+ PLATFORMS
12
+ ruby
13
+
14
+ DEPENDENCIES
15
+ bundler (~> 1.3)
16
+ git_diff!
17
+ rake
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andrew Olson
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,86 @@
1
+ # GitDiff
2
+
3
+ A Ruby library for parsing the unified diff format generated with `git diff`
4
+
5
+ [![Code Climate](https://codeclimate.com/github/anolson/git_diff.png)](https://codeclimate.com/github/anolson/git_diff)
6
+ [![Build Status](https://travis-ci.org/anolson/git_diff.png?branch=master)](https://travis-ci.org/anolson/git_diff)
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'git_diff', git: 'https://github.com/anolson/git_diff.git'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install git_diff
21
+
22
+ ## Usage
23
+
24
+ #### Generate a diff
25
+
26
+ ```sh
27
+ $ git diff
28
+ diff --git a/README.md b/README.md
29
+ index bbbf9c9..9dff09f 100644
30
+ --- a/README.md
31
+ +++ b/README.md
32
+ @@ -25,7 +25,7 @@ Or install it yourself as:
33
+
34
+ $ git diff
35
+
36
+ -#### Parse the output with
37
+ +#### Parse the output
38
+
39
+ GitDiff.from_string(diff)
40
+
41
+ ```
42
+
43
+ #### Parse the output
44
+
45
+ ```ruby
46
+ require "git_diff"
47
+
48
+ diff = <<-DIFF
49
+ diff --git a/README.md b/README.md
50
+ index bbbf9c9..9dff09f 100644
51
+ --- a/README.md
52
+ +++ b/README.md
53
+ @@ -25,7 +25,7 @@ Or install it yourself as:
54
+
55
+ $ git diff
56
+
57
+ -#### Parse the output with
58
+ +#### Parse the output
59
+
60
+ GitDiff.from_string(diff)
61
+
62
+ DIFF
63
+
64
+ diff = GitDiff.from_string(diff)
65
+
66
+ puts " #{diff_file.number_of_additions} addition(s)."
67
+ puts " #{diff_file.number_of_deletions} deletion(s)."
68
+ ```
69
+
70
+ _Outputs_
71
+ ```
72
+ 1 addition(s).
73
+ 1 deletion(s).
74
+ ```
75
+
76
+ ## Run the tests
77
+
78
+ $ bundle exec rake test
79
+
80
+ ## Contributing
81
+
82
+ 1. Fork it
83
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
84
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
85
+ 4. Push to the branch (`git push origin my-new-feature`)
86
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << "lib"
6
+ t.libs << "test"
7
+ t.pattern = "test/**/*_test.rb"
8
+ end
9
+
10
+ task :default => :test
data/git_diff.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git_diff/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git_diff"
8
+ spec.version = GitDiff::VERSION
9
+ spec.authors = ["Andrew Olson"]
10
+ spec.email = ["aolson@geezeo.com"]
11
+ spec.summary = %q{A Ruby library for parsing git diffs.}
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake"
21
+ end
@@ -0,0 +1,38 @@
1
+ module GitDiff
2
+ class Diff
3
+ attr_reader :files, :stats
4
+
5
+ def initialize
6
+ @files = []
7
+ end
8
+
9
+ def <<(string)
10
+ if file = File.from_string(string)
11
+ add_file file
12
+ else
13
+ append_to_current_file string
14
+ end
15
+ end
16
+
17
+ def stats
18
+ @stats ||= Stats.total(collector)
19
+ end
20
+
21
+ private
22
+
23
+ def collector
24
+ GitDiff::StatsCollector::Rollup.new(files)
25
+ end
26
+
27
+ attr_accessor :current_file
28
+
29
+ def add_file(file)
30
+ self.current_file = file
31
+ files << current_file
32
+ end
33
+
34
+ def append_to_current_file(line)
35
+ current_file << line
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,66 @@
1
+ module GitDiff
2
+ class File
3
+
4
+ attr_reader :a_path, :a_blob, :b_path, :b_blob, :b_mode, :hunks
5
+
6
+ def self.from_string(string)
7
+ if /^diff --git/.match(string)
8
+ File.new
9
+ end
10
+ end
11
+
12
+ def initialize
13
+ @hunks = []
14
+ end
15
+
16
+ def <<(string)
17
+ return if extract_diff_meta_data(string)
18
+
19
+ if(range_info = RangeInfo.from_string(string))
20
+ add_hunk Hunk.new(range_info)
21
+ else
22
+ append_to_current_hunk string
23
+ end
24
+ end
25
+
26
+ def stats
27
+ @stats ||= Stats.total(collector)
28
+ end
29
+
30
+ private
31
+
32
+ attr_accessor :current_hunk
33
+
34
+ def collector
35
+ GitDiff::StatsCollector::Rollup.new(hunks)
36
+ end
37
+
38
+ def add_hunk(hunk)
39
+ self.current_hunk = hunk
40
+ hunks << current_hunk
41
+ end
42
+
43
+ def append_to_current_hunk(string)
44
+ current_hunk << string
45
+ end
46
+
47
+ def extract_diff_meta_data(string)
48
+ case
49
+ when a_path_info = /^[-]{3} \/dev\/null(.*)$/.match(string)
50
+ @a_path = "/dev/null"
51
+ when a_path_info = /^[-]{3} a\/(.*)$/.match(string)
52
+ @a_path = a_path_info[1]
53
+ when b_path_info = /^[+]{3} \/dev\/null(.*)$/.match(string)
54
+ @b_path = "/dev/null"
55
+ when b_path_info = /^[+]{3} b\/(.*)$/.match(string)
56
+ @b_path = b_path_info[1]
57
+ when blob_info = /^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$/.match(string)
58
+ @a_blob, @b_blob, @b_mode = *blob_info.captures
59
+ when /^new file mode [0-9]{6}$/.match(string)
60
+ @a_path = "/dev/null"
61
+ when /^deleted file mode [0-9]{6}$/.match(string)
62
+ @b_path = "/dev/null"
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,42 @@
1
+ require "forwardable"
2
+
3
+ module GitDiff
4
+ class Hunk
5
+ include Enumerable
6
+ extend Forwardable
7
+
8
+ def_delegators :lines, :each
9
+
10
+ attr_reader :lines, :range_info
11
+
12
+ def initialize(range_info)
13
+ @range_info = range_info
14
+ @lines = []
15
+ end
16
+
17
+ def <<(string)
18
+ Line.from_string(string).tap do |line|
19
+ line_number_calculation.increment(line)
20
+ lines << line
21
+ end
22
+ end
23
+
24
+ def stats
25
+ @stats ||= Stats.total(collector)
26
+ end
27
+
28
+ private
29
+
30
+ def collector
31
+ GitDiff::StatsCollector::Hunk.new(self)
32
+ end
33
+
34
+ def initial_line_number
35
+ @initial_line_number ||= LineNumber.new(range_info.original_range.start, range_info.new_range.start)
36
+ end
37
+
38
+ def line_number_calculation
39
+ @line_number_calculation ||= LineNumberCalculation.new(initial_line_number)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ module GitDiff
2
+ module Line
3
+ class Addition < Context
4
+ def line_number=(line_number)
5
+ @line_number = LineNumber.for_addition(line_number)
6
+ end
7
+
8
+ def addition?
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module GitDiff
2
+ module Line
3
+ class Context
4
+ attr_reader :content, :line_number
5
+
6
+ def initialize(content, line_number=nil)
7
+ @content = content
8
+ @line_number = line_number
9
+ end
10
+
11
+ def line_number=(line_number)
12
+ @line_number = LineNumber.for_context(line_number)
13
+ end
14
+
15
+ def deletion?
16
+ false
17
+ end
18
+
19
+ def addition?
20
+ false
21
+ end
22
+
23
+ def to_s
24
+ content
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ module GitDiff
2
+ module Line
3
+ class Deletion < Context
4
+ def line_number=(line_number)
5
+ @line_number = LineNumber.for_deletion(line_number)
6
+ end
7
+
8
+ def deletion?
9
+ true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ require "git_diff/line/context"
2
+ require "git_diff/line/addition"
3
+ require "git_diff/line/deletion"
4
+
5
+ module GitDiff
6
+ module Line
7
+ module ClassMethods
8
+ def from_string(string)
9
+ line_class(string[0]).new(string)
10
+ end
11
+
12
+ def line_class(symbol)
13
+ line_classes[symbol] || Context
14
+ end
15
+
16
+ def line_classes
17
+ { "+" => Addition, "-" => Deletion }
18
+ end
19
+ end
20
+ extend ClassMethods
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ module GitDiff
2
+ class LineNumber
3
+ attr_reader :left, :right
4
+
5
+ module ClassMethods
6
+ def for_addition(line_number)
7
+ new(nil, line_number.right)
8
+ end
9
+
10
+ def for_deletion(line_number)
11
+ new(line_number.left, nil)
12
+ end
13
+
14
+ def for_context(line_number)
15
+ new(line_number.left, line_number.right)
16
+ end
17
+ end
18
+ extend ClassMethods
19
+
20
+ def initialize(left, right)
21
+ @left = left
22
+ @right = right
23
+ end
24
+
25
+ def increment_left
26
+ @left += 1
27
+ end
28
+
29
+ def increment_right
30
+ @right += 1
31
+ end
32
+
33
+ def increment
34
+ increment_left
35
+ increment_right
36
+ end
37
+
38
+ def pair
39
+ [left, right]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ module GitDiff
2
+ class LineNumberCalculation
3
+
4
+ attr_reader :current
5
+
6
+ def initialize(line_number)
7
+ @current = line_number
8
+ end
9
+
10
+ def increment(line)
11
+ line.line_number = current
12
+
13
+ if line.addition?
14
+ current.increment_right
15
+ elsif line.deletion?
16
+ current.increment_left
17
+ else
18
+ current.increment
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module GitDiff
2
+ class LineNumberRange
3
+ attr_reader :start, :number_of_lines
4
+
5
+ def self.from_string(string)
6
+ new(*string.split(","))
7
+ end
8
+
9
+ def initialize(start = 0, number_of_lines = 0)
10
+ @start = start.to_i
11
+ @number_of_lines = number_of_lines.to_i
12
+ end
13
+
14
+ def to_s(type)
15
+ "#{type}#{start},#{number_of_lines}"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module GitDiff
2
+ class Parser
3
+ attr_reader :string, :diff
4
+
5
+ def initialize(string)
6
+ @string = string
7
+ @diff = Diff.new
8
+ end
9
+
10
+ def parse
11
+ lines.each do |line|
12
+ diff << line
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def lines
19
+ string.split("\n")
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ module GitDiff
2
+ class RangeInfo
3
+ attr_reader :original_range, :new_range, :header
4
+
5
+ module ClassMethods
6
+ def from_string(string)
7
+ if(range_data = extract_hunk_range_data(string))
8
+ new(*range_data.captures)
9
+ end
10
+ end
11
+
12
+ def extract_hunk_range_data(string)
13
+ /@@ \-(.+) \+(.+) @@(.*)/.match(string)
14
+ end
15
+ end
16
+ extend ClassMethods
17
+
18
+ def initialize(original_range, new_range, header)
19
+ @original_range = LineNumberRange.from_string(original_range)
20
+ @new_range = LineNumberRange.from_string(new_range)
21
+ @header = header.strip
22
+ end
23
+
24
+ def to_s
25
+ "@@ #{original_range.to_s(:-)} #{new_range.to_s(:+)} @@ #{header}".strip
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module GitDiff
2
+ class Stats
3
+ attr_reader :number_of_additions, :number_of_lines, :number_of_deletions
4
+
5
+ module ClassMethods
6
+ def total(collector)
7
+ StatsCalculator.new(collector).total
8
+ end
9
+ end
10
+ extend ClassMethods
11
+
12
+ def initialize(attributes)
13
+ attributes.each do |name, value|
14
+ instance_variable_set("@#{name}", value)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ module GitDiff
2
+ class StatsCalculator
3
+ attr_reader :collector
4
+
5
+ def initialize(collector)
6
+ @collector = collector
7
+ end
8
+
9
+ def total
10
+ GitDiff::Stats.new(
11
+ number_of_lines: calculate_total(:number_of_lines),
12
+ number_of_additions: calculate_total(:number_of_additions),
13
+ number_of_deletions: calculate_total(:number_of_deletions)
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def calculate_total(type)
20
+ collect_stat(type).inject(:+)
21
+ end
22
+
23
+ def collect_stat(type)
24
+ stats_collection.map { |stats| stats.public_send(type) }.flatten
25
+ end
26
+
27
+ def stats_collection
28
+ Array(collector.collect)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ module GitDiff
2
+ module StatsCollector
3
+ class Hunk
4
+ attr_reader :hunk
5
+
6
+ def initialize(hunk)
7
+ @hunk = hunk
8
+ end
9
+
10
+ def collect
11
+ GitDiff::Stats.new(
12
+ number_of_lines: number_of_lines,
13
+ number_of_additions: number_of_additions,
14
+ number_of_deletions: number_of_deletions
15
+ )
16
+ end
17
+
18
+ private
19
+
20
+ def number_of_lines
21
+ lines.count
22
+ end
23
+
24
+ def number_of_additions
25
+ lines.select(&:addition?).count
26
+ end
27
+
28
+ def number_of_deletions
29
+ lines.select(&:deletion?).count
30
+ end
31
+
32
+ def lines
33
+ hunk.lines
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+
40
+
41
+
@@ -0,0 +1,15 @@
1
+ module GitDiff
2
+ module StatsCollector
3
+ class StatsCollector::Rollup
4
+ attr_reader :collection
5
+
6
+ def initialize(collection)
7
+ @collection = collection
8
+ end
9
+
10
+ def collect
11
+ collection.map { |item| item.stats }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,2 @@
1
+ require "git_diff/stats_collector/hunk"
2
+ require "git_diff/stats_collector/rollup"
File without changes
@@ -0,0 +1,3 @@
1
+ module GitDiff
2
+ VERSION = "0.3.0"
3
+ end
data/lib/git_diff.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "forwardable"
2
+
3
+ require "git_diff/stats_collector"
4
+ require "git_diff/diff"
5
+ require "git_diff/file"
6
+ require "git_diff/hunk"
7
+ require "git_diff/line"
8
+ require "git_diff/line_number"
9
+ require "git_diff/line_number_calculation"
10
+ require "git_diff/line_number_range"
11
+ require "git_diff/parser"
12
+ require "git_diff/range_info"
13
+ require "git_diff/stats"
14
+ require "git_diff/stats_calculator"
15
+ require "git_diff/version"
16
+
17
+ module GitDiff
18
+ def self.from_string(string)
19
+ parser = Parser.new(string)
20
+ parser.parse
21
+ parser.diff
22
+ end
23
+ end
@@ -0,0 +1,60 @@
1
+ require "test_helper"
2
+
3
+ class DiffFileTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @file = GitDiff::File.new
7
+ end
8
+
9
+ def test_from_string_with_a_diff
10
+ file = GitDiff::File.from_string "diff --git"
11
+
12
+ refute_nil file
13
+ assert_instance_of GitDiff::File, file
14
+ end
15
+
16
+ def test_from_string_without_a_diff
17
+ file = GitDiff::File.from_string ""
18
+
19
+ assert_nil file
20
+ end
21
+
22
+ def test_blob_data_is_correctly_extracted
23
+ @file << "index 033b446..0e2d140 100644"
24
+
25
+ assert_equal "033b446", @file.a_blob
26
+ assert_equal "0e2d140", @file.b_blob
27
+ end
28
+
29
+ def test_mode_data_is_correctly_extracted
30
+ @file << "index 033b446..0e2d140 100644"
31
+
32
+ assert_equal "100644", @file.b_mode
33
+ end
34
+
35
+ def test_paths_are_correctly_extracted
36
+ @file << "--- a/lib/grit/repo.rb"
37
+ @file << "+++ b/lib/grit/repo.rb"
38
+
39
+ assert_equal "lib/grit/repo.rb", @file.a_path
40
+ assert_equal "lib/grit/repo.rb", @file.b_path
41
+ end
42
+
43
+ def test_appending_a_hunk
44
+ @file << "@@ -180,7 +180,7 @@ module Grit"
45
+ @file << " io = StringIO.new(text)"
46
+ @file << " objects = []"
47
+ @file << " while line = io.gets"
48
+ @file << "- sha, type, size = line.split(" ", 3)"
49
+ @file << "+ sha, type, size = line.split(" ", 3) #wut"
50
+ @file << " parser = BATCH_PARSERS[type]"
51
+ @file << " if type == 'missing' || !parser"
52
+ @file << " io.seek(size.to_i + 1, IO::SEEK_CUR)"
53
+
54
+ assert_equal 1, @file.hunks.count
55
+ assert_equal 8, @file.stats.number_of_lines
56
+ assert_equal 1, @file.stats.number_of_additions
57
+ assert_equal 1, @file.stats.number_of_deletions
58
+ end
59
+
60
+ end
@@ -0,0 +1,131 @@
1
+ require "test_helper"
2
+
3
+ class GitDiffTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ string = <<-'DIFF'
7
+ diff --git a/lib/grit/commit.rb b/lib/grit/commit.rb
8
+ index 403ea33..dd4b590 100644
9
+ --- a/lib/grit/commit.rb
10
+ +++ b/lib/grit/commit.rb
11
+ @@ -27,6 +27,7 @@
12
+
13
+ lines = info.split("\n")
14
+ tree = lines.shift.split(' ', 2).last
15
+ +
16
+ parents = []
17
+ parents << lines.shift[7..-1] while lines.first[0, 6] == 'parent'
18
+ author, authored_date = Grit::Commit.actor(lines.shift)
19
+ diff --git a/lib/grit/new_file.rb b/lib/grit/new_file.rb
20
+ new file mode 100644
21
+ index 0000000..24f83d1
22
+ --- /dev/null
23
+ +++ b/lib/grit/new_file.rb
24
+ @@ -0,0 +1 @@
25
+ +#
26
+ diff --git a/grit/old_file.rb b/grit/old_file.rb
27
+ deleted file mode 100644
28
+ index ba6b733..0000000
29
+ --- a/lib/grit/old_file.rb
30
+ +++ /dev/null
31
+ @@ -1 +0,0 @@
32
+ -#
33
+ diff --git a/lib/grit/repo.rb b/lib/grit/repo.rb
34
+ index 033b446..0e2d140 100644
35
+ --- a/lib/grit/repo.rb
36
+ +++ b/lib/grit/repo.rb
37
+ @@ -180,7 +180,7 @@ module Grit
38
+ io = StringIO.new(text)
39
+ objects = []
40
+ while line = io.gets
41
+ - sha, type, size = line.split(" ", 3)
42
+ + sha, type, size = line.split(" ", 3) #wut
43
+ parser = BATCH_PARSERS[type]
44
+ if type == 'missing' || !parser
45
+ io.seek(size.to_i + 1, IO::SEEK_CUR)
46
+ DIFF
47
+
48
+ @diff = GitDiff::from_string(string)
49
+ end
50
+
51
+ def first_diff_file
52
+ @diff.files.first
53
+ end
54
+
55
+ def last_diff_file
56
+ @diff.files.last
57
+ end
58
+
59
+ def test_returns_the_number_of_files
60
+ assert_equal 4, @diff.files.count
61
+ end
62
+
63
+ def test_returns_the_number_of_lines_per_file
64
+ assert_equal 7, first_diff_file.stats.number_of_lines
65
+ assert_equal 8, last_diff_file.stats.number_of_lines
66
+ end
67
+
68
+ def test_returns_the_path_info
69
+ assert_equal "lib/grit/commit.rb", first_diff_file.a_path
70
+ assert_equal "lib/grit/commit.rb", first_diff_file.b_path
71
+
72
+ assert_equal "lib/grit/repo.rb", last_diff_file.a_path
73
+ assert_equal "lib/grit/repo.rb", last_diff_file.b_path
74
+ end
75
+
76
+ def test_returns_the_blob_info
77
+ assert_equal "403ea33", first_diff_file.a_blob
78
+ assert_equal "dd4b590", first_diff_file.b_blob
79
+ assert_equal "100644", first_diff_file.b_mode
80
+
81
+ assert_equal "033b446", last_diff_file.a_blob
82
+ assert_equal "0e2d140", last_diff_file.b_blob
83
+ assert_equal "100644", last_diff_file.b_mode
84
+ end
85
+
86
+ def test_returns_the_total_number_of_additions
87
+ assert_equal 1, first_diff_file.stats.number_of_additions
88
+ assert_equal 1, last_diff_file.stats.number_of_additions
89
+ assert_equal 3, @diff.stats.number_of_additions
90
+ end
91
+
92
+ def test_returns_the_total_number_of_subtractions
93
+ assert_equal 0, first_diff_file.stats.number_of_deletions
94
+ assert_equal 1, last_diff_file.stats.number_of_deletions
95
+ assert_equal 2, @diff.stats.number_of_deletions
96
+ end
97
+
98
+ def test_returns_the_hunk_range_info
99
+ first_hunk = first_diff_file.hunks.first
100
+ assert_equal "@@ -27,6 +27,7 @@", first_hunk.range_info.to_s
101
+
102
+ second_hunk = last_diff_file.hunks.first
103
+ assert_equal "@@ -180,7 +180,7 @@ module Grit", second_hunk.range_info.to_s
104
+ end
105
+
106
+ def test_returns_the_correct_line_numbers
107
+ first_hunk = first_diff_file.hunks.first
108
+ second_hunk = last_diff_file.hunks.first
109
+
110
+ assert_equal [
111
+ [27,27],
112
+ [28,28],
113
+ [29,29],
114
+ [nil,30],
115
+ [30,31],
116
+ [31,32],
117
+ [32,33]
118
+ ], first_hunk.lines.map { |line| line.line_number.pair }
119
+
120
+ assert_equal [
121
+ [180,180],
122
+ [181,181],
123
+ [182,182],
124
+ [183,nil],
125
+ [nil,183],
126
+ [184,184],
127
+ [185,185],
128
+ [186,186]
129
+ ], second_hunk.lines.map { |line| line.line_number.pair }
130
+ end
131
+ end
data/test/hunk_test.rb ADDED
@@ -0,0 +1,27 @@
1
+ require "test_helper"
2
+
3
+ class HunkTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @range_info = GitDiff::RangeInfo.new("180,7", "180,7", "module Grit")
7
+ @hunk = GitDiff::Hunk.new(@range_info)
8
+ end
9
+
10
+ def test_append_context_line
11
+ @hunk << "some content"
12
+
13
+ assert_equal 1, @hunk.stats.number_of_lines
14
+ end
15
+
16
+ def test_append_addition_line
17
+ @hunk << "+ addition"
18
+
19
+ assert_equal 1, @hunk.stats.number_of_additions
20
+ end
21
+
22
+ def test_append_deletion_line
23
+ @hunk << "- deletion"
24
+
25
+ assert_equal 1, @hunk.stats.number_of_deletions
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ require "test_helper"
2
+
3
+ class AdditionTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @addition = GitDiff::Line::Addition.new("+ addition")
6
+ end
7
+
8
+ def test_addition_is_true
9
+ assert @addition.addition?
10
+ end
11
+
12
+ def test_deletion_is_false
13
+ refute @addition.deletion?
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require "test_helper"
2
+
3
+ class ContextTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @line_number = GitDiff::LineNumber.new(0,0)
6
+ @content = "some content"
7
+ @context = GitDiff::Line::Context.new(@content, @line_number)
8
+ end
9
+
10
+ def test_addition_is_false
11
+ refute @context.addition?
12
+ end
13
+
14
+ def test_deletion_is_false
15
+ refute @context.deletion?
16
+ end
17
+
18
+ def test_to_s_returns_the_content
19
+ assert_equal @content, @context.to_s
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require "test_helper"
2
+
3
+ class DeletionTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @deletion = GitDiff::Line::Deletion.new("- deletion")
6
+ end
7
+
8
+ def test_addition_is_false
9
+ refute @deletion.addition?
10
+ end
11
+
12
+ def test_deletion_is_true
13
+ assert @deletion.deletion?
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ require "test_helper"
2
+
3
+ class LineNumberCalculationTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @line_number = GitDiff::LineNumber.new(0, 0)
7
+ @line_number_calculation = GitDiff::LineNumberCalculation.new(@line_number)
8
+
9
+ @addition = GitDiff::Line::Addition.new("+ addition", @line_number)
10
+ @deletion = GitDiff::Line::Deletion.new("- deletion", @line_number)
11
+ @context = GitDiff::Line::Context.new(" context", @line_number)
12
+ end
13
+
14
+ def test_increment_with_addition_line
15
+ @line_number_calculation.increment(@addition)
16
+
17
+ assert_equal 0, @line_number_calculation.current.left
18
+ assert_equal 1, @line_number_calculation.current.right
19
+ end
20
+
21
+ def test_increment_with_deletion_line
22
+ @line_number_calculation.increment(@deletion)
23
+
24
+ assert_equal 1, @line_number_calculation.current.left
25
+ assert_equal 0, @line_number_calculation.current.right
26
+ end
27
+
28
+ def test_increment_with_context_line
29
+ @line_number_calculation.increment(@context)
30
+
31
+ assert_equal 1, @line_number_calculation.current.left
32
+ assert_equal 1, @line_number_calculation.current.right
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ require "test_helper"
2
+
3
+ class LineNumberRangeTest < MiniTest::Unit::TestCase
4
+
5
+ def test_from_string_with_empty_string
6
+ range = GitDiff::LineNumberRange.from_string("")
7
+
8
+ assert_equal 0, range.start
9
+ assert_equal 0, range.number_of_lines
10
+ end
11
+
12
+ def test_from_string_with_empty_string
13
+ range = GitDiff::LineNumberRange.from_string("180,7")
14
+
15
+ assert_equal 180, range.start
16
+ assert_equal 7, range.number_of_lines
17
+ end
18
+
19
+ def test_to_s
20
+ range = GitDiff::LineNumberRange.from_string("180,7")
21
+
22
+ assert_equal "+180,7", range.to_s(:+)
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ require "test_helper"
2
+
3
+ class LineNumberTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @line_number = GitDiff::LineNumber.new(0,0)
7
+ end
8
+
9
+ def test_increment_left
10
+ @line_number.increment_left
11
+ assert_equal 1, @line_number.left
12
+ assert_equal 0, @line_number.right
13
+ end
14
+
15
+ def test_increment_right
16
+ @line_number.increment_right
17
+ assert_equal 0, @line_number.left
18
+ assert_equal 1, @line_number.right
19
+ end
20
+
21
+ def test_increment
22
+ @line_number.increment
23
+ assert_equal 1, @line_number.left
24
+ assert_equal 1, @line_number.right
25
+ end
26
+
27
+ def test_pair
28
+ assert_equal [0,0], @line_number.pair
29
+ end
30
+ end
data/test/line_test.rb ADDED
@@ -0,0 +1,30 @@
1
+ require "test_helper"
2
+
3
+ class LineTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @line_number = GitDiff::LineNumber.new(0, 0)
7
+ end
8
+
9
+
10
+ def test_from_string_with_addition
11
+ addition = GitDiff::Line.from_string("+ addition")
12
+
13
+ refute_nil addition
14
+ assert_instance_of GitDiff::Line::Addition, addition
15
+ end
16
+
17
+ def test_from_string_with_deletion
18
+ deletion = GitDiff::Line.from_string("- deletion")
19
+
20
+ refute_nil deletion
21
+ assert_instance_of GitDiff::Line::Deletion, deletion
22
+ end
23
+
24
+ def test_from_string_with_context
25
+ context = GitDiff::Line.from_string(" context")
26
+
27
+ refute_nil context
28
+ assert_instance_of GitDiff::Line::Context, context
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ require "test_helper"
2
+
3
+ class RangeInfoTest < MiniTest::Unit::TestCase
4
+ def setup
5
+ @range_info = GitDiff::RangeInfo.new("180,7", "180,7", "module Grit")
6
+ end
7
+
8
+ def test_from_string
9
+ range_info = GitDiff::RangeInfo.from_string("@@ -180,7 +180,7 @@")
10
+
11
+ refute_nil range_info
12
+ assert_instance_of GitDiff::RangeInfo, range_info
13
+ end
14
+
15
+ def test_from_string_with_header
16
+ range_info = GitDiff::RangeInfo.from_string("@@ -180,7 +180,7 @@ module Grit")
17
+
18
+ refute_nil range_info
19
+ assert_instance_of GitDiff::RangeInfo, range_info
20
+ end
21
+
22
+ def test_with_incomplete_range_info
23
+ range_info = GitDiff::RangeInfo.from_string("@@ -1 +1,2 @@")
24
+
25
+ refute_nil range_info
26
+ assert_instance_of GitDiff::RangeInfo, range_info
27
+ end
28
+
29
+ def test_to_s
30
+ assert_equal "@@ -180,7 +180,7 @@ module Grit", @range_info.to_s
31
+ end
32
+ end
@@ -0,0 +1,47 @@
1
+ require "test_helper"
2
+
3
+ class Collector
4
+
5
+ def collect
6
+ GitDiff::Stats.new(
7
+ number_of_lines: number_of_lines,
8
+ number_of_additions: number_of_additions,
9
+ number_of_deletions: number_of_deletions
10
+ )
11
+ end
12
+
13
+ private
14
+
15
+ def number_of_additions
16
+ [1, 2, 3]
17
+ end
18
+
19
+ def number_of_deletions
20
+ [4, 5, 6]
21
+ end
22
+
23
+ def number_of_lines
24
+ [7, 8, 9]
25
+ end
26
+ end
27
+
28
+ class StatsCalculatorTest < MiniTest::Unit::TestCase
29
+ def setup
30
+ collector = Collector.new
31
+
32
+ calculator = GitDiff::StatsCalculator.new(collector)
33
+ @stats = calculator.total
34
+ end
35
+
36
+ def test_total_number_additions_is_the_sum_of_all_the_additions
37
+ assert_equal 6, @stats.number_of_additions
38
+ end
39
+
40
+ def test_total_number_additions_is_the_sum_of_all_the_deletions
41
+ assert_equal 15, @stats.number_of_deletions
42
+ end
43
+
44
+ def test_total_number_additions_is_the_sum_of_all_the_lines
45
+ assert_equal 24, @stats.number_of_lines
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ require "minitest/autorun"
2
+ require "minitest/pride"
3
+ require "git_diff"
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git_diff
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Olson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email:
43
+ - aolson@geezeo.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".travis.yml"
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - git_diff.gemspec
56
+ - lib/git_diff.rb
57
+ - lib/git_diff/diff.rb
58
+ - lib/git_diff/file.rb
59
+ - lib/git_diff/hunk.rb
60
+ - lib/git_diff/line.rb
61
+ - lib/git_diff/line/addition.rb
62
+ - lib/git_diff/line/context.rb
63
+ - lib/git_diff/line/deletion.rb
64
+ - lib/git_diff/line_number.rb
65
+ - lib/git_diff/line_number_calculation.rb
66
+ - lib/git_diff/line_number_range.rb
67
+ - lib/git_diff/parser.rb
68
+ - lib/git_diff/range_info.rb
69
+ - lib/git_diff/stats.rb
70
+ - lib/git_diff/stats_calculator.rb
71
+ - lib/git_diff/stats_collector.rb
72
+ - lib/git_diff/stats_collector/hunk.rb
73
+ - lib/git_diff/stats_collector/rollup.rb
74
+ - lib/git_diff/stats_rollup.rb
75
+ - lib/git_diff/version.rb
76
+ - test/diff_file_test.rb
77
+ - test/git_diff_test.rb
78
+ - test/hunk_test.rb
79
+ - test/line/addition_test.rb
80
+ - test/line/context_test.rb
81
+ - test/line/deletion_test.rb
82
+ - test/line_number_calculation_test.rb
83
+ - test/line_number_range_test.rb
84
+ - test/line_number_test.rb
85
+ - test/line_test.rb
86
+ - test/range_info_test.rb
87
+ - test/stats_calculator_test.rb
88
+ - test/test_helper.rb
89
+ homepage:
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.2.2
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: A Ruby library for parsing git diffs.
113
+ test_files:
114
+ - test/diff_file_test.rb
115
+ - test/git_diff_test.rb
116
+ - test/hunk_test.rb
117
+ - test/line/addition_test.rb
118
+ - test/line/context_test.rb
119
+ - test/line/deletion_test.rb
120
+ - test/line_number_calculation_test.rb
121
+ - test/line_number_range_test.rb
122
+ - test/line_number_test.rb
123
+ - test/line_test.rb
124
+ - test/range_info_test.rb
125
+ - test/stats_calculator_test.rb
126
+ - test/test_helper.rb
127
+ has_rdoc: