git_fame 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ [submodule "spec/fixtures/gash"]
2
+ path = spec/fixtures/gash
3
+ url = git://github.com/water/gash.git
data/.rspec ADDED
@@ -0,0 +1,5 @@
1
+ --color
2
+ -fs
3
+ -Ilib
4
+ -Ispec
5
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git_fame.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Linus Oleander
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.
@@ -0,0 +1,115 @@
1
+ # GitFame
2
+
3
+ Who did what in your project?
4
+
5
+ ## Output
6
+
7
+ ```
8
+ Total number of files: 2,053
9
+ Total number of lines: 63,132
10
+ Total number of commits: 4,330
11
+
12
+ +------------------------+--------+---------+-------+--------------------+
13
+ | name | loc | commits | files | percent |
14
+ +------------------------+--------+---------+-------+--------------------+
15
+ | Johan Sørensen | 22,272 | 1,814 | 414 | 35.3 / 41.9 / 20.2 |
16
+ | Marius Mathiesen | 10,387 | 502 | 229 | 16.5 / 11.6 / 11.2 |
17
+ | Jesper Josefsson | 9,689 | 519 | 191 | 15.3 / 12.0 / 9.3 |
18
+ | Ole Martin Kristiansen | 6,632 | 24 | 60 | 10.5 / 0.6 / 2.9 |
19
+ | Linus Oleander | 5,769 | 705 | 277 | 9.1 / 16.3 / 13.5 |
20
+ | Fabio Akita | 2,122 | 24 | 60 | 3.4 / 0.6 / 2.9 |
21
+ | August Lilleaas | 1,572 | 123 | 63 | 2.5 / 2.8 / 3.1 |
22
+ | David A. Cuadrado | 731 | 111 | 35 | 1.2 / 2.6 / 1.7 |
23
+ | Jonas Ängeslevä | 705 | 148 | 51 | 1.1 / 3.4 / 2.5 |
24
+ | Diego Algorta | 650 | 6 | 5 | 1.0 / 0.1 / 0.2 |
25
+ | Arash Rouhani | 629 | 95 | 31 | 1.0 / 2.2 / 1.5 |
26
+ | Sofia Larsson | 595 | 70 | 77 | 0.9 / 1.6 / 3.8 |
27
+ | Tor Arne Vestbø | 527 | 51 | 97 | 0.8 / 1.2 / 4.7 |
28
+ | spontus | 339 | 18 | 42 | 0.5 / 0.4 / 2.0 |
29
+ | Pontus | 225 | 49 | 34 | 0.4 / 1.1 / 1.7 |
30
+ +------------------------+--------+---------+-------+--------------------+
31
+ ```
32
+
33
+ ## Installation
34
+
35
+ `[sudo] gem install git_fame`
36
+
37
+ ## Usage
38
+
39
+ ### Console
40
+
41
+ Start by navigating to a git repository.
42
+
43
+ Run `git fame` to generate output as above.
44
+
45
+ #### Options
46
+
47
+ - `git fame --order=loc` Order table by `loc`. Available options are: `loc`, `commits` and `files`. Default is `loc`.
48
+ - `git fame --repository=/path/to/repo` Git repository to be used. Default is the current folder.
49
+ - `git fame --progressbar=1` Should a progressbar be visible during the calculation? Default is `1`.
50
+
51
+ ### Class
52
+
53
+ Want to work with the data before printing it?
54
+
55
+ #### Constructor arguments
56
+
57
+ - **repository** (String) Path to repository.
58
+ - **sort** (String) What should #authors be sorted by? Available options are: `loc`, `commits` and `files`. Default is `loc`.
59
+ - **progressbar** (Boolean) Should a progressbar be shown during the calculation? Default is `false`.
60
+
61
+ ``` ruby
62
+ repository = GitFame::Base.new({
63
+ sort: "loc",
64
+ repository: "/tmp/repo",
65
+ progressbar: false
66
+ })
67
+ ```
68
+
69
+ #### Print table to console
70
+
71
+ `repository.pretty_puts`
72
+
73
+ ### Statistics
74
+
75
+ #### GitFame
76
+
77
+ - `repository.loc` (Fixnum) Total number of lines.
78
+ - `repository.commits` (Fixnum) Total number of commits.
79
+ - `repository.files` (Fixnum) Total number of files.
80
+ - `repository.authors` (Array< Author >) All authors.
81
+
82
+ #### Author
83
+
84
+ `author = repository.authors.first`
85
+
86
+ - Formated
87
+ - `author.loc` (String) Number of lines.
88
+ - `author.commits` (String) Number of commits.
89
+ - `author.files` (String) Number of files changed.
90
+ - Non formated
91
+ - `author.percent` (String) Percent of total (loc/commits/files)
92
+ - `author.raw_loc` (Fixnum) Number of lines.
93
+ - `author.raw_commits` (Fixnum) Number of commits.
94
+ - `author.raw_files` (Fixnum) Number of files changed.
95
+
96
+ ## Contributing
97
+
98
+ 1. Fork it
99
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
100
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
101
+ 4. Push to the branch (`git push origin my-new-feature`)
102
+ 5. Create new Pull Request
103
+
104
+ ## Testing
105
+
106
+ 1. Download fixtures (`spec/fixtures`) using `git submodule update --init`.
107
+ 2. Run rspec using `rspec spec`.
108
+
109
+ ## Requirements
110
+
111
+ *GitFame* is tested in *OS X 10.7.4* using Ruby *1.9.2*.
112
+
113
+ ## License
114
+
115
+ *GitFame* is released under the *MIT license*.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require "git_fame"
4
+ require "trollop"
5
+
6
+ sort = ["name", "commits", "loc", "files"]
7
+ opts = Trollop::options do
8
+ version "git-fame #{GitFame::VERSION} (c) 2012 Linus Oleander"
9
+ opt :repository, "What git repository should be used?", default: "."
10
+ opt :sort, "What should the printed table be sorted by? #{sort.join(", ")}", default: "loc", type: String
11
+ opt :progressbar, "Show progressbar during calculation", default: 1, type: Integer
12
+ end
13
+
14
+ Trollop::die :repository, "is not a git repository" unless GitFame::Base.git_repository?(opts[:repository])
15
+ Trollop::die :sort, "must be one of the following; #{sort.join(", ")}" unless sort.include?(opts[:sort])
16
+ GitFame::Base.new({
17
+ repository: opts[:repository],
18
+ progressbar: opts[:progressbar] == 1,
19
+ sort: opts[:sort]
20
+ }).pretty_puts
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/git_fame/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Linus Oleander"]
6
+ gem.email = ["linus@oleander.nu"]
7
+ gem.description = %q{Generates some awesome stats from git-blame}
8
+ gem.summary = %q{
9
+ Generates some awesome stats from git-blame
10
+
11
+ A Ruby wrapper for git-blame.
12
+ Generates data like:
13
+ - Number of files changed by a user
14
+ - Number of commits by user
15
+ - Lines of code by a user
16
+ }
17
+
18
+ gem.homepage = "https://github.com/oleander/git-fame-rb"
19
+
20
+ gem.files = `git ls-files`.split($\)
21
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
22
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
23
+ gem.name = "git_fame"
24
+ gem.require_paths = ["lib"]
25
+ gem.version = GitFame::VERSION
26
+
27
+ gem.add_dependency("progressbar")
28
+ gem.add_dependency("trollop")
29
+ gem.add_dependency("hirb")
30
+ gem.add_dependency("mimer_plus")
31
+
32
+ gem.add_development_dependency("rspec")
33
+ gem.required_ruby_version = "~> 1.9.0"
34
+ end
@@ -0,0 +1,9 @@
1
+ $-v = false
2
+ require "git_fame/version"
3
+ require "progressbar"
4
+ require "mimer_plus"
5
+ require "hirb"
6
+ require "git_fame/helper"
7
+ require "git_fame/author"
8
+ require "git_fame/silent_progressbar"
9
+ require "git_fame/base"
@@ -0,0 +1,30 @@
1
+ module GitFame
2
+ class Author
3
+ include GitFame::Helper
4
+ attr_accessor :name, :raw_files, :raw_commits, :raw_loc, :files_list
5
+ #
6
+ # @args Hash
7
+ #
8
+ def initialize(args = {})
9
+ @raw_loc = 0
10
+ @raw_commits = 0
11
+ @raw_files = 0
12
+ args.keys.each { |name| instance_variable_set "@" + name.to_s, args[name] }
13
+ end
14
+
15
+ #
16
+ # @return String Percent of total
17
+ # @format loc / commits / files
18
+ #
19
+ def percent
20
+ "%.1f / %.1f / %.1f" % [:loc, :commits, :files].
21
+ map{ |w| (send("raw_#{w}") / @parent.send(w).to_f) * 100 }
22
+ end
23
+
24
+ [:commits, :files, :loc].each do |method|
25
+ define_method(method) do
26
+ number_with_delimiter(send("raw_#{method}"))
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,150 @@
1
+ module GitFame
2
+ class Base
3
+ include GitFame::Helper
4
+
5
+ #
6
+ # @args[:repository] String Absolute path to git repository
7
+ # @args[:sort] String What should #authors be sorted by?
8
+ #
9
+ def initialize(args)
10
+ @sort = "loc"
11
+ @progressbar = false
12
+ args.keys.each { |name| instance_variable_set "@" + name.to_s, args[name] }
13
+ @authors = {}
14
+ @file_authors = Hash.new { |h,k| h[k] = {} }
15
+ end
16
+
17
+ #
18
+ # Generates pretty output
19
+ #
20
+ def pretty_puts
21
+ extend Hirb::Console
22
+ Hirb.enable({pager: false})
23
+ puts "\nTotal number of files: #{number_with_delimiter(files)}"
24
+ puts "Total number of lines: #{number_with_delimiter(loc)}"
25
+ puts "Total number of commits: #{number_with_delimiter(commits)}\n"
26
+ table(authors, fields: [:name, :loc, :commits, :files, :percent])
27
+ end
28
+
29
+ #
30
+ # @return Fixnum Total number of files
31
+ #
32
+ def files
33
+ populate.instance_variable_get("@files").count
34
+ end
35
+
36
+ #
37
+ # @return Fixnum Total number of commits
38
+ #
39
+ def commits
40
+ authors.inject(0){ |result, author| author.raw_commits + result }
41
+ end
42
+
43
+ #
44
+ # @return Fixnum Total number of lines
45
+ #
46
+ def loc
47
+ populate.authors.inject(0){ |result, author| author.raw_loc + result }
48
+ end
49
+
50
+ #
51
+ # @return Array<Author> A list of authors
52
+ #
53
+ def authors
54
+ authors = populate.instance_variable_get("@authors").values
55
+ @sort ? authors.sort_by do |author|
56
+ if @sort == "name"
57
+ author.send(@sort)
58
+ else
59
+ -1 * author.send("raw_#{@sort}")
60
+ end
61
+ end : authors
62
+ end
63
+
64
+ #
65
+ # @return Boolean Is the given @dir a git repository?
66
+ # @dir Path (relative or absolute) to git repository
67
+ #
68
+ def self.git_repository?(dir)
69
+ Dir.exists?(File.join(dir, ".git"))
70
+ end
71
+
72
+ private
73
+ #
74
+ # @command String Command to be executed inside the @repository path
75
+ #
76
+ def execute(command)
77
+ Dir.chdir(@repository) do
78
+ return `#{command}`
79
+ end
80
+ end
81
+
82
+ #
83
+ # @author String Author
84
+ # @args Hash Argument that should be set in @return
85
+ # @return Author
86
+ #
87
+ def update(author, args)
88
+ fetch(author).tap do |found|
89
+ args.keys.each do |key|
90
+ found.send("#{key}=", args[key])
91
+ end
92
+ end
93
+ end
94
+
95
+ #
96
+ # @return Author
97
+ # @author String
98
+ #
99
+ def fetch(author)
100
+ @authors[author] ||= Author.new({name: author, parent: self})
101
+ end
102
+
103
+ #
104
+ # @return GitFame
105
+ #
106
+ def populate
107
+ @_pop ||= lambda {
108
+ @files = execute("git ls-files").split("\n")
109
+ progressbar = SilentProgressbar.new("Blame", @files.count, @progressbar)
110
+ @files.each do |file|
111
+ progressbar.inc
112
+ if type = Mimer.identify(File.join(@repository, file)) and not type.mime_type.match(/binary/)
113
+ begin
114
+ execute("git blame '#{file}'").scan(/\((.+?)\s+\d{4}-\d{2}-\d{2}/).each do |author|
115
+ fetch(author.first).raw_loc += 1
116
+ @file_authors[author.first][file] ||= 1
117
+ end
118
+ rescue ArgumentError; end # Encoding error
119
+ end
120
+ end
121
+
122
+ execute("git shortlog -se").split("\n").map do |l|
123
+ _, commits, u = l.match(%r{^\s*(\d+)\s+(.+?)\s+<.+?>}).to_a
124
+ user = fetch(u)
125
+
126
+ # Has this user been updated before?
127
+ if user.raw_commits.zero?
128
+ update(u, {
129
+ raw_commits: commits.to_i,
130
+ raw_files: @file_authors[u].keys.count,
131
+ files_list: @file_authors[u].keys
132
+ })
133
+ else
134
+ # Calculate the number of files edited by users
135
+ files = (user.files_list + @file_authors[u].keys).uniq
136
+ update(u, {
137
+ raw_commits: commits.to_i + user.raw_commits,
138
+ raw_files: files.count,
139
+ files_list: files
140
+ })
141
+ end
142
+ end
143
+
144
+ progressbar.finish
145
+
146
+ }.call
147
+ return self
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,11 @@
1
+ module GitFame
2
+ module Helper
3
+ #
4
+ # @value Fixnum Value to be formated
5
+ # @return String Formated according ActionView::Helpers::NumberHelper.number_with_delimiter
6
+ #
7
+ def number_with_delimiter(value)
8
+ value.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class SilentProgressbar < ProgressBar
2
+ #
3
+ # @name String Name for progressbar
4
+ # @steps Fixnum Total number of steps
5
+ # @active Should progressbar be visible?
6
+ #
7
+ def initialize(name, steps, active = false)
8
+ out = active ? $stdout : File.new("/dev/null", "w")
9
+ super(name, steps, out)
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module GitFame
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,96 @@
1
+ describe GitFame::Base do
2
+ let(:subject) { GitFame::Base.new({repository: @repository}) }
3
+ describe "#authors" do
4
+ it "should have a list of authors" do
5
+ should have(3).authors
6
+ end
7
+
8
+ describe "author" do
9
+ let(:author) { subject.authors.last }
10
+ it "should have a bunch of commits" do
11
+ author.raw_commits.should eq(23)
12
+ end
13
+
14
+ it "should respond to name" do
15
+ author.name.should eq("Linus Oleander")
16
+ end
17
+
18
+ it "should have a number of locs" do
19
+ author.raw_loc.should eq(136)
20
+ end
21
+
22
+ it "should have a number of files" do
23
+ author.raw_files.should eq(7)
24
+ end
25
+
26
+ it "should have some percentage" do
27
+ author.percent.should eq("12.6 / 32.9 / 43.8")
28
+ end
29
+ end
30
+ describe "format" do
31
+ let(:author) { GitFame::Author.new({raw_commits: 12345, raw_files: 6789, raw_loc: 1234})}
32
+ it "should format #commits" do
33
+ author.commits.should eq("12,345")
34
+ end
35
+
36
+ it "should format #files" do
37
+ author.files.should eq("6,789")
38
+ end
39
+
40
+ it "should format #loc" do
41
+ author.loc.should eq("1,234")
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "total" do
47
+ it "should respond to #loc, #commits and #files" do
48
+ subject.files.should eq(16)
49
+ subject.commits.should eq(70)
50
+ subject.loc.should eq(1082)
51
+ end
52
+ end
53
+
54
+ describe "sort" do
55
+ it "should be able to sort #authors by name" do
56
+ authors = GitFame::Base.new({repository: @repository, sort: "name"}).authors
57
+ authors.map(&:name).should eq(["7rans", "Linus Oleander", "Magnus Holm"])
58
+ end
59
+
60
+ it "should be able to sort #authors by commits" do
61
+ authors = GitFame::Base.new({repository: @repository, sort: "commits"}).authors
62
+ authors.map(&:name).should eq(["Magnus Holm", "Linus Oleander", "7rans"])
63
+ end
64
+
65
+ it "should be able to sort #authors by files" do
66
+ authors = GitFame::Base.new({repository: @repository, sort: "files"}).authors
67
+ authors.map(&:name).should eq(["7rans", "Linus Oleander", "Magnus Holm"])
68
+ end
69
+ end
70
+
71
+ describe "#pretty_print" do
72
+ it "should print" do
73
+ lambda {
74
+ 2.times { subject.pretty_puts }
75
+ }.should_not raise_error
76
+ end
77
+ end
78
+
79
+ describe ".git_repository?" do
80
+ it "should know if a folder is a git repository [absolute path]" do
81
+ GitFame::Base.git_repository?(@repository).should be_true
82
+ end
83
+
84
+ it "should know if a folder exists or not [absolute path]" do
85
+ GitFame::Base.git_repository?("/f67c2bcbfcfa30fccb36f72dca22a817").should be_false
86
+ end
87
+
88
+ it "should know if a folder is a git repository [relative path]" do
89
+ GitFame::Base.git_repository?("spec/fixtures/gash").should be_true
90
+ end
91
+
92
+ it "should know if a folder exists or not [relative path]" do
93
+ GitFame::Base.git_repository?("f67c2bcbfcfa30fccb36f72dca22a817").should be_false
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,13 @@
1
+ require "rspec"
2
+ require "git_fame"
3
+
4
+ RSpec.configure do |config|
5
+ config.mock_with :rspec
6
+ config.order = "random"
7
+ config.before(:all) do
8
+ @repository = File.join(File.dirname(File.dirname(__FILE__)), "spec/fixtures/gash")
9
+ Dir.chdir(@repository) do
10
+ `git checkout 7ab01bc5a720`
11
+ end
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git_fame
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Linus Oleander
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-22 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: progressbar
16
+ requirement: &70317512929600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70317512929600
25
+ - !ruby/object:Gem::Dependency
26
+ name: trollop
27
+ requirement: &70317512928780 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70317512928780
36
+ - !ruby/object:Gem::Dependency
37
+ name: hirb
38
+ requirement: &70317512926760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70317512926760
47
+ - !ruby/object:Gem::Dependency
48
+ name: mimer_plus
49
+ requirement: &70317512919640 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70317512919640
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &70317512919040 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70317512919040
69
+ description: Generates some awesome stats from git-blame
70
+ email:
71
+ - linus@oleander.nu
72
+ executables:
73
+ - git-fame
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - .gitmodules
79
+ - .rspec
80
+ - Gemfile
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - bin/git-fame
85
+ - git_fame.gemspec
86
+ - lib/git_fame.rb
87
+ - lib/git_fame/author.rb
88
+ - lib/git_fame/base.rb
89
+ - lib/git_fame/helper.rb
90
+ - lib/git_fame/silent_progressbar.rb
91
+ - lib/git_fame/version.rb
92
+ - spec/git_fame_spec.rb
93
+ - spec/spec_helper.rb
94
+ homepage: https://github.com/oleander/git-fame-rb
95
+ licenses: []
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ~>
104
+ - !ruby/object:Gem::Version
105
+ version: 1.9.0
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 1.8.15
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: ! 'Generates some awesome stats from git-blame A Ruby wrapper for git-blame.
118
+ Generates data like: - Number of files changed by a user - Number of commits by
119
+ user - Lines of code by a user'
120
+ test_files:
121
+ - spec/git_fame_spec.rb
122
+ - spec/spec_helper.rb