git_diff 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.
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: