git_statistics 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,7 +1,14 @@
1
1
  language: ruby
2
+
2
3
  rvm:
3
4
  - 1.9.2
4
5
  - 1.9.3
5
6
 
7
+ bundler_args: --without development darwin
8
+
9
+ before_install:
10
+ - sudo apt-get update
11
+ - sudo apt-get install libicu-dev
12
+
6
13
  notifications:
7
14
  email: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # CHANGELOG
2
+
3
+ * [0.3.0 - September 12, 2012](https://github.com/kevinjalbert/git_statistics/compare/v0.2.0...v0.3.0)
4
+ * [0.2.0 - September 6, 2012](https://github.com/kevinjalbert/git_statistics/compare/v0.1.2...v0.2.0)
5
+ * [0.1.2 - April 12, 2012](https://github.com/kevinjalbert/git_statistics/compare/v0.1.1...v0.1.2)
6
+ * [0.1.1 - April 12, 2012](https://github.com/kevinjalbert/git_statistics/compare/0e82e507e5b64a1140623c702015b97b1b3f7f81...v0.1.1)
data/Gemfile CHANGED
@@ -4,9 +4,20 @@ gem "json"
4
4
  gem "trollop"
5
5
  gem "grit"
6
6
  gem "github-linguist"
7
+ gem "os"
7
8
 
8
9
  group :test do
9
10
  gem "simplecov"
10
11
  gem "rspec"
11
12
  gem "rake"
12
13
  end
14
+
15
+ group :development do
16
+ gem "guard"
17
+ gem "guard-rspec"
18
+ end
19
+
20
+ group :darwin do
21
+ gem "rb-fsevent"
22
+ gem "terminal-notifier-guard"
23
+ end
data/Gemfile.lock CHANGED
@@ -15,13 +15,21 @@ GEM
15
15
  diff-lcs (~> 1.1)
16
16
  mime-types (~> 1.15)
17
17
  posix-spawn (~> 0.3.6)
18
+ guard (1.3.2)
19
+ listen (>= 0.4.2)
20
+ thor (>= 0.14.6)
21
+ guard-rspec (1.2.1)
22
+ guard (>= 1.1)
18
23
  json (1.7.5)
24
+ listen (0.5.0)
19
25
  mime-types (1.19)
20
26
  multi_json (1.3.6)
27
+ os (0.9.6)
21
28
  posix-spawn (0.3.6)
22
29
  pygments.rb (0.2.13)
23
30
  rubypython (~> 0.5.3)
24
31
  rake (0.9.2.2)
32
+ rb-fsevent (0.9.1)
25
33
  rspec (2.11.0)
26
34
  rspec-core (~> 2.11.0)
27
35
  rspec-expectations (~> 2.11.0)
@@ -37,6 +45,8 @@ GEM
37
45
  multi_json (~> 1.0)
38
46
  simplecov-html (~> 0.5.3)
39
47
  simplecov-html (0.5.3)
48
+ terminal-notifier-guard (1.5.3)
49
+ thor (0.16.0)
40
50
  trollop (2.0)
41
51
 
42
52
  PLATFORMS
@@ -45,8 +55,13 @@ PLATFORMS
45
55
  DEPENDENCIES
46
56
  github-linguist
47
57
  grit
58
+ guard
59
+ guard-rspec
48
60
  json
61
+ os
49
62
  rake
63
+ rb-fsevent
50
64
  rspec
51
65
  simplecov
66
+ terminal-notifier-guard
52
67
  trollop
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+ guard :rspec, :version => 2, :all_on_start => false do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
data/README.md CHANGED
@@ -26,11 +26,16 @@ This gem will analyze every commit within a git repository using `git log` and [
26
26
  * Total file renames
27
27
  * Total file copies
28
28
 
29
- This gem also uses [github/linguist](https://github.com/github/linguist) to determine the langugae of each individual file within commits. This augments the reported statistics by breaking down the author's statistics by languages.
29
+ This gem also uses [github/linguist](https://github.com/github/linguist) to determine the language of each individual file within commits. This augments the reported statistics by breaking down the author's statistics by languages.
30
30
 
31
31
  This gem also has the ability to save the acquired data into a JSON file (in either a compressed or pretty format). If a saved file is present for the repository you can use the gem to load the data from the file, thus saving time for re-displaying the statistics using a different set of display flags (what statistic to sort on, number of authors to show, consider merges, etc...). In the event that a repository updates with new commits the gem allows you to update the saved file with the new commits.
32
32
 
33
- ## Contributing
33
+ # Example Output
34
+ The following is the output produced by *git_statistics* when used on the [pengwynn/octokit](https://github.com/pengwynn/octokit) (at commit [95a9de3](https://github.com/pengwynn/octokit/commit/95a9de325bee4ca03c9c1d61de2d643666c90037)) git repository. In this output we show the top three authors in rankings based on number of commits (merge commits are excluded from these results).
35
+
36
+ ![screenshot](http://cloud.github.com/downloads/kevinjalbert/git_statistics/pengwynn_octokit_output.png)
37
+
38
+ # Contributing
34
39
 
35
40
  1. Fork it
36
41
  2. Create your feature branch (`git checkout -b my-new-feature`)
@@ -19,4 +19,5 @@ Gem::Specification.new do |gem|
19
19
  gem.add_dependency('trollop')
20
20
  gem.add_dependency('grit')
21
21
  gem.add_dependency('github-linguist')
22
+ gem.add_dependency('os')
22
23
  end
@@ -6,16 +6,7 @@ module GitStatistics
6
6
  def initialize(verbose)
7
7
  @commits = Commits.new
8
8
  @verbose = verbose
9
-
10
- # Connect to git repository if it exists
11
- directory = Pathname.new(Dir.pwd)
12
- while @repo == nil && !directory.root? do
13
- begin
14
- @repo = Grit::Repo.new(directory)
15
- rescue
16
- directory = directory.parent
17
- end
18
- end
9
+ @repo = Utilities.get_repository
19
10
 
20
11
  # Abort if no git repository is found
21
12
  if @repo == nil
@@ -23,86 +14,134 @@ module GitStatistics
23
14
  end
24
15
  end
25
16
 
26
- def collect(branch, since="")
17
+ def collect(branch, time_since="", time_until="")
18
+ # Create pipe for git log to acquire branches
19
+ pipe = open("|git --no-pager branch --no-color")
20
+
27
21
  # Collect branches to use for git log
28
- branches = collect_branches
22
+ branches = collect_branches(pipe)
29
23
  branches = ["", ""] if branch
30
24
 
31
25
  # Create pipe for the git log to acquire commits
32
26
  pipe = open("|git --no-pager log #{branches.join(' ')} --date=iso --reverse"\
33
27
  " --no-color --find-copies-harder --numstat --encoding=utf-8 "\
34
- "--summary #{since} --format=\"%H,%an,%ae,%ad,%p\"")
28
+ "--summary #{time_since} #{time_until} "\
29
+ "--format=\"%H,%an,%ae,%ad,%p\"")
35
30
 
36
31
  # Use a buffer approach to queue up lines from the log for each commit
37
32
  buffer = []
38
33
  pipe.each do |line|
39
34
 
40
- line = clean_string(line)
35
+ line = Utilities.clean_string(line)
41
36
 
42
37
  # Extract the buffer (commit) when we match ','x5 in the log format (delimeter)
43
38
  if line.split(',').size == 5
39
+
40
+ # Sometimes 'git log' doesn't populate the buffer, try fallback option if so
41
+ buffer = fall_back_collect_commit(line.split(',').first) if buffer.size == 1
42
+
44
43
  extract_commit(buffer) if not buffer.empty?
45
44
  buffer = []
46
45
  end
47
46
 
48
- buffer << line.strip
47
+ buffer << line
49
48
  end
50
49
 
51
50
  # Extract the last commit
52
51
  extract_commit(buffer) if not buffer.empty?
53
52
  end
54
53
 
55
- def collect_branches
56
- # Create pipe for git log to acquire branches
57
- pipe = open("|git --no-pager branch --no-color")
54
+ def fall_back_collect_commit(sha)
55
+
56
+ # Create pipe for the git log to acquire commits
57
+ pipe = open("|git --no-pager show #{sha} --date=iso --reverse"\
58
+ " --no-color --find-copies-harder --numstat --encoding=utf-8 "\
59
+ "--summary --format=\"%H,%an,%ae,%ad,%p\"")
60
+
61
+ buffer = []
62
+ pipe.each do |line|
63
+ buffer << Utilities.clean_string(line)
64
+ end
58
65
 
59
- # Acquire all availble branches from repository
66
+ # Check that the buffer has valid information (i.e., sha was valid)
67
+ if buffer.empty?
68
+ return nil
69
+ elsif buffer.first.split(',').first == sha
70
+ return buffer
71
+ else
72
+ return nil
73
+ end
74
+ end
75
+
76
+ def collect_branches(pipe)
77
+ # Acquire all available branches from repository
60
78
  branches = []
61
79
  pipe.each do |line|
62
80
 
63
81
  # Remove the '*' leading the current branch
64
82
  line = line[1..-1] if line[0] == '*'
65
- branches << clean_string(line)
83
+ branches << Utilities.clean_string(line)
66
84
  end
67
85
 
68
86
  return branches
69
87
  end
70
88
 
71
- def extract_commit(buffer)
72
- # Acquire general commit information
73
- commit_info = buffer[0].split(',')
74
- sha = commit_info[0]
89
+ def acquire_commit_data(line)
90
+ # Split up formated line
91
+ commit_info = line.split(',')
75
92
 
76
93
  # Initialize commit data
77
- data = (@commits[sha] ||= Hash.new(0))
94
+ data = (@commits[commit_info[0]] ||= Hash.new(0))
78
95
  data[:author] = commit_info[1]
79
96
  data[:author_email] = commit_info[2]
80
97
  data[:time] = commit_info[3]
81
98
  data[:files] = []
82
99
 
83
- # Flag commit as merge if nessecary (determined if two parents)
100
+ # Flag commit as merge if necessary (determined if two parents)
84
101
  if commit_info[4] == nil or commit_info[4].split(' ').size == 1
85
102
  data[:merge] = false
86
103
  else
87
104
  data[:merge] = true
88
105
  end
89
106
 
90
- puts "Extracting #{sha}" if @verbose
107
+ return {:sha => commit_info[0], :data => data}
108
+ end
109
+
110
+ def extract_commit(buffer)
111
+ # Acquire general commit information
112
+ commit_data = acquire_commit_data(buffer[0])
113
+
114
+ puts "Extracting #{commit_data[:sha]}" if @verbose
115
+
116
+ # Abort if the commit sha extracted form the buffer is invalid
117
+ if commit_data[:sha].scan(/[\d|a-f]{40}/)[0] == nil
118
+ puts "Invalid buffer containing commit information"
119
+ return
120
+ end
91
121
 
92
122
  # Identify all changed files for this commit
93
- files = identify_changed_files(buffer)
123
+ files = identify_changed_files(buffer[2..-1])
124
+
125
+ # No files were changed in this commit, abort commit
126
+ if files == nil
127
+ puts "No files were changed"
128
+ return
129
+ end
94
130
 
95
131
  # Acquire blob for each changed file and process it
96
132
  files.each do |file|
97
- blob = get_blob(sha, file)
133
+ blob = get_blob(commit_data[:sha], file)
98
134
 
99
- # Only process blobs, otherwise log problematic file/blob
135
+ # Only process blobs, or log the submodules and problematic files
100
136
  if blob.instance_of?(Grit::Blob)
101
- process_blob(data, blob, file)
137
+ process_blob(commit_data[:data], blob, file)
138
+ elsif blob.instance_of?(Grit::Submodule)
139
+ puts "Ignoring submodule #{blob.name}"
102
140
  else
103
141
  puts "Problem processing file #{file[:file]}"
104
142
  end
105
143
  end
144
+ return commit_data[:data]
106
145
  end
107
146
 
108
147
  def get_blob(sha, file)
@@ -110,7 +149,7 @@ module GitStatistics
110
149
  file = file[:file].split(File::Separator)
111
150
 
112
151
  # Acquire blob of the file for this specific commit
113
- blob = find_blob_in_tree(sha, @repo.tree(sha), file)
152
+ blob = Utilities.find_blob_in_tree(@repo.tree(sha), file)
114
153
 
115
154
  # If we cannot find blob in current commit (deleted file), check previous commit
116
155
  if blob == nil || blob.instance_of?(Grit::Tree)
@@ -118,94 +157,60 @@ module GitStatistics
118
157
  return nil if prev_commit == nil
119
158
 
120
159
  prev_tree = @repo.tree(prev_commit.id)
121
- blob = find_blob_in_tree(prev_commit.id, prev_tree, file)
160
+ blob = Utilities.find_blob_in_tree(prev_tree, file)
122
161
  end
123
162
  return blob
124
163
  end
125
164
 
126
165
  def identify_changed_files(buffer)
127
- # If the buffer is larger than 2 lines then we have per-file details to process
128
- changed_files = []
129
- if buffer.size > 2
130
-
131
- # For each modification extract the details
132
- buffer[2..-1].each do |line|
166
+ return buffer if buffer == nil
133
167
 
134
- # Extract changed file information if it exists
135
- data = extract_change_file(line)
136
- if data != nil
137
- changed_files << data
138
- next # This line is processed, skip to next
139
- end
168
+ # For each modification extract the details
169
+ changed_files = []
170
+ buffer.each do |line|
140
171
 
141
- # Extract details of create/delete files if it exists
142
- data = extract_create_delete_file(line)
143
- if data != nil
144
- augmented = false
145
- # Augment changed file with create/delete information if possible
146
- changed_files.each do |file|
147
- if file[:file] == data[:file]
148
- file[:status] = data[:status]
149
- augmented = true
150
- break
151
- end
152
- end
153
- changed_files << data if !augmented
154
- next # This line is processed, skip to next
155
- end
172
+ # Extract changed file information if it exists
173
+ data = extract_change_file(line)
174
+ if data != nil
175
+ changed_files << data
176
+ next # This line is processed, skip to next
177
+ end
156
178
 
157
- # Extract details of rename/copy files if it exists
158
- data = extract_rename_copy_file(line)
159
- if data != nil
160
- augmented = false
161
- # Augment changed file with rename/copy information if possible
162
- changed_files.each do |file|
163
- if file[:file] == data[:new_file]
164
- file[:status] = data[:status]
165
- file[:old_file] = data[:old_file]
166
- file[:similar] = data[:similar]
167
- augmented = true
168
- break
169
- end
179
+ # Extract details of create/delete files if it exists
180
+ data = extract_create_delete_file(line)
181
+ if data != nil
182
+ augmented = false
183
+ # Augment changed file with create/delete information if possible
184
+ changed_files.each do |file|
185
+ if file[:file] == data[:file]
186
+ file[:status] = data[:status]
187
+ augmented = true
188
+ break
170
189
  end
171
- changed_files << data if !augmented
172
- next # This line is processed, skip to next
173
190
  end
191
+ changed_files << data if !augmented
192
+ next # This line is processed, skip to next
174
193
  end
175
- end
176
- return changed_files
177
- end
178
-
179
- def find_blob_in_tree(sha, tree, file)
180
- # Check If cannot find tree in commit or if we found a submodule as the changed file
181
- if tree == nil
182
- return nil
183
- elsif tree.instance_of?(Grit::Submodule)
184
- return tree
185
- end
186
-
187
- # If the blob is within the current directory (tree)
188
- if file.size == 1
189
- blob = tree / file.first
190
-
191
- # Check if blob is nil (could not find changed file in tree)
192
- if blob == nil
193
194
 
194
- # Try looking for submodules as they cannot be found using tree / file notation
195
- tree.contents.each do |content|
196
- if file.first == content.name
197
- return nil
195
+ # Extract details of rename/copy files if it exists
196
+ data = extract_rename_copy_file(line)
197
+ if data != nil
198
+ augmented = false
199
+ # Augment changed file with rename/copy information if possible
200
+ changed_files.each do |file|
201
+ if file[:file] == data[:new_file]
202
+ file[:status] = data[:status]
203
+ file[:old_file] = data[:old_file]
204
+ file[:similar] = data[:similar]
205
+ augmented = true
206
+ break
198
207
  end
199
208
  end
200
-
201
- # Exit through recusion with the base case of a nil tree/blob
202
- return find_blob_in_tree(sha, blob, file)
209
+ changed_files << data if !augmented
210
+ next # This line is processed, skip to next
203
211
  end
204
- return blob
205
- else
206
- # Explore deeper in the tree to find the blob of the changed file
207
- return find_blob_in_tree(sha, tree / file.first, file[1..-1])
208
212
  end
213
+ return changed_files
209
214
  end
210
215
 
211
216
  def process_blob(data, blob, file)
@@ -221,36 +226,21 @@ module GitStatistics
221
226
  data[:additions] += file[:additions]
222
227
  data[:deletions] += file[:deletions]
223
228
 
224
- # Handle submodule if present, otherwise acquire specifics on blob
225
- if blob.instance_of?(Grit::Submodule)
226
- file_hash[:language] = "Submodule"
229
+ # Acquire specifics on blob
230
+ file_hash[:binary] = blob.binary?
231
+ file_hash[:image] = blob.image?
232
+ file_hash[:vendored] = blob.vendored?
233
+ file_hash[:generated] = blob.generated?
234
+
235
+ # Identify the language of the blob if possible
236
+ if blob.language == nil
237
+ file_hash[:language] = "Unknown"
227
238
  else
228
- file_hash[:binary] = blob.binary?
229
- file_hash[:image] = blob.image?
230
- file_hash[:vendored] = blob.vendored?
231
- file_hash[:generated] = blob.generated?
232
-
233
- # Identify the language of the blob if possible
234
- if blob.language == nil
235
- file_hash[:language] = "Unknown"
236
- else
237
- file_hash[:language] = blob.language.name
238
- end
239
+ file_hash[:language] = blob.language.name
239
240
  end
240
241
  data[:files] << file_hash
241
- end
242
242
 
243
- def clean_string(file_name)
244
- #if file_name.include?("foo")
245
- #blob = @repo.tree("1ec5c2674fd792e8f9ddbff5afcacc3e1f7c506d") / "actionpack" / "test" / "fixtures" / "public" / "foo"
246
- #ap "=-=-=-=-=-=-="
247
- #ap file_name
248
- #ap "--------------------"
249
- #ap blob.contents[2].name
250
- #ap "=-=-=-=-=-=-="
251
- #end
252
- # Clean up a string and force utf-8 encoding
253
- return file_name.strip.gsub('"', '').gsub("\\\\", "\\").force_encoding("utf-8")
243
+ return data
254
244
  end
255
245
 
256
246
  def extract_change_file(line)
@@ -258,11 +248,11 @@ module GitStatistics
258
248
  changes = line.scan(/^([-|\d]+)\s+([-|\d]+)\s+(.+)\s+=>\s+(.+)/)[0]
259
249
  if changes != nil and changes.size == 4
260
250
  # Split up the file into the old and new file
261
- split_file = split_old_new_file(changes[2], changes[3])
251
+ split_file = Utilities.split_old_new_file(changes[2], changes[3])
262
252
  return {:additions => changes[0].to_i,
263
253
  :deletions => changes[1].to_i,
264
- :file => clean_string(split_file[:new_file]),
265
- :old_file => clean_string(split_file[:old_file])}
254
+ :file => Utilities.clean_string(split_file[:new_file]),
255
+ :old_file => Utilities.clean_string(split_file[:old_file])}
266
256
  end
267
257
 
268
258
  # Use regex to detect a changed file | 1 2 /path/test/file.txt
@@ -270,7 +260,7 @@ module GitStatistics
270
260
  if changes != nil and changes.size == 3
271
261
  return {:additions => changes[0].to_i,
272
262
  :deletions => changes[1].to_i,
273
- :file => clean_string(changes[2])}
263
+ :file => Utilities.clean_string(changes[2])}
274
264
  end
275
265
  return nil
276
266
  end
@@ -279,8 +269,8 @@ module GitStatistics
279
269
  # Use regex to detect a create/delete file | create mode 100644 /path/test/file.txt
280
270
  changes = line.scan(/^(create|delete) mode \d+ ([^\\\n]*)/)[0]
281
271
  if changes != nil and changes.size == 2
282
- return {:status => clean_string(changes[0]),
283
- :file => clean_string(changes[1])}
272
+ return {:status => Utilities.clean_string(changes[0]),
273
+ :file => Utilities.clean_string(changes[1])}
284
274
  end
285
275
  return nil
286
276
  end
@@ -290,118 +280,13 @@ module GitStatistics
290
280
  changes = line.scan(/^(rename|copy)\s+(.+)\s+=>\s+(.+)\s+\((\d+)/)[0]
291
281
  if changes != nil and changes.size == 4
292
282
  # Split up the file into the old and new file
293
- split_file = split_old_new_file(changes[1], changes[2])
294
- return {:status => clean_string(changes[0]),
295
- :old_file => clean_string(split_file[:old_file]),
296
- :new_file => clean_string(split_file[:new_file]),
283
+ split_file = Utilities.split_old_new_file(changes[1], changes[2])
284
+ return {:status => Utilities.clean_string(changes[0]),
285
+ :old_file => Utilities.clean_string(split_file[:old_file]),
286
+ :new_file => Utilities.clean_string(split_file[:new_file]),
297
287
  :similar => changes[3].to_i}
298
288
  end
299
289
  return nil
300
290
  end
301
-
302
- def split_old_new_file(old, new)
303
- # Split the old and new chunks up (separted by the =>)
304
- split_old = old.split('{')
305
- split_new = new.split('}')
306
-
307
- # Handle recombine the file splits into their whole paths)
308
- if split_old.size == 1 && split_new.size == 1
309
- old_file = split_old[0]
310
- new_file = split_new[0]
311
- elsif split_new.size == 1
312
- old_file = split_old[0] + split_old[1] + split_new[0]
313
- new_file = split_old[0] + split_new[0]
314
- elsif split_old.size == 1
315
- old_file = split_old[0] + split_new[1]
316
- new_file = split_old[0] + split_new[0] + split_new[1]
317
- else
318
- old_file = split_old[0] + split_old[1] + split_new[1]
319
- new_file = split_old[0] + split_new[0] + split_new[1]
320
- end
321
-
322
- # Return files, yet remove the '//' if present from combining splits
323
- return {:old_file => old_file.gsub('//', '/'),
324
- :new_file => new_file.gsub('//', '/')}
325
- end
326
-
327
- def print_summary(sort_type, email, n=0)
328
- # Default to a 0 if given a negative number to display
329
- n = 0 if n < 0
330
-
331
- # Acquire data based on sorty type and top # to show
332
- data = @commits.author_top_n_type(sort_type, n)
333
- if data == nil
334
- raise "Parameter for --sort is not valid"
335
- end
336
-
337
- # Acquire formatting pattern for output
338
- author_length = find_longest_author(data)
339
- language_length = find_longest_language(data)
340
- pattern = "%-#{author_length}s | %-#{language_length}s | %7s | %9s | %9s | %7s | %7s | %7s | %6s | %6s |"
341
-
342
- # Print query/header information
343
- print_header(pattern, sort_type, n, author_length, language_length)
344
-
345
- # Print per author information
346
- data.each do |key,value|
347
- puts pattern % [key, "", value[:commits], value[:additions],
348
- value[:deletions], value[:create], value[:delete],
349
- value[:rename], value[:copy], value[:merges]]
350
- print_language_data(pattern, value)
351
- end
352
-
353
- # Reprint query/header for repository information
354
- print_header(pattern, sort_type, n, author_length, language_length)
355
- data = @commits.totals
356
- puts pattern % ["Repository Totals", "", data[:commits],
357
- data[:additions], data[:deletions], data[:create],
358
- data[:delete], data[:rename], data[:copy], data[:merges]]
359
- print_language_data(pattern, data)
360
- end
361
-
362
- def print_language_data(pattern, data)
363
- # Print information of each language for the data
364
- data[:languages].each do |key,value|
365
- puts pattern % ["", key, "", value[:additions], value[:deletions],
366
- value[:create], value[:delete], value[:rename],
367
- value[:copy], value[:merges]]
368
- end
369
- end
370
-
371
- def print_header(pattern, sort_type, n, author_length, language_length)
372
- total_authors = @commits.author_list.length
373
-
374
- # Print summary information of displayed results
375
- if n > 0 and n < total_authors
376
- puts "\nTop #{n} authors(#{total_authors}) sorted by #{sort_type.to_s}\n"
377
- else
378
- puts "\nAll authors(#{total_authors}) sorted by #{sort_type.to_s}\n"
379
- end
380
-
381
- # Print column headers
382
- puts "-"*87 + "-"*author_length + "-"*language_length
383
- puts pattern % ['Name/Email', 'Language', 'Commits', 'Additions', 'Deletions', 'Creates', 'Deletes', 'Renames', 'Copies', 'Merges']
384
- puts "-"*87 + "-"*author_length + "-"*language_length
385
- end
386
-
387
- def find_longest_author(data)
388
- # Find the longest author name/email (for string formatting)
389
- total_authors = @commits.author_list.length
390
- author_length = 17
391
- data.each do |key,value|
392
- author_length = key.length if key.length > author_length
393
- end
394
- return author_length
395
- end
396
-
397
- def find_longest_language(data)
398
- # Find the longest language name (for string formatting)
399
- total_language = @commits.language_list.length
400
- language_length = 9
401
- @commits.language_list.each do |key,value|
402
- language_length = key.length if key.length > language_length
403
- end
404
- return language_length
405
- end
406
291
  end
407
292
  end