ramper 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +57 -0
- data/README.md +29 -0
- data/bin/ramper +71 -26
- data/lib/dependency_analyzer.rb +29 -0
- data/lib/ramper.rb +128 -12
- data/lib/ramper_file_metrics.rb +103 -0
- data/ramper.gemspec +24 -0
- data/spec/ramper_file_metrics_spec.rb +56 -0
- metadata +92 -4
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ramper (0.0.2)
|
5
|
+
code_statistics (= 0.2.13)
|
6
|
+
courgette (= 0.3.0)
|
7
|
+
flay (= 2.6.1)
|
8
|
+
flog (= 4.3.2)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
ast (2.0.0)
|
14
|
+
code_statistics (0.2.13)
|
15
|
+
commander (4.3.4)
|
16
|
+
highline (~> 1.7.2)
|
17
|
+
courgette (0.3.0)
|
18
|
+
commander
|
19
|
+
graph
|
20
|
+
parser
|
21
|
+
diff-lcs (1.2.5)
|
22
|
+
flay (2.6.1)
|
23
|
+
ruby_parser (~> 3.0)
|
24
|
+
sexp_processor (~> 4.0)
|
25
|
+
flog (4.3.2)
|
26
|
+
ruby_parser (~> 3.1, > 3.1.0)
|
27
|
+
sexp_processor (~> 4.4)
|
28
|
+
graph (2.8.0)
|
29
|
+
highline (1.7.2)
|
30
|
+
parser (2.2.2.6)
|
31
|
+
ast (>= 1.1, < 3.0)
|
32
|
+
rspec (3.3.0)
|
33
|
+
rspec-core (~> 3.3.0)
|
34
|
+
rspec-expectations (~> 3.3.0)
|
35
|
+
rspec-mocks (~> 3.3.0)
|
36
|
+
rspec-core (3.3.1)
|
37
|
+
rspec-support (~> 3.3.0)
|
38
|
+
rspec-expectations (3.3.0)
|
39
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
40
|
+
rspec-support (~> 3.3.0)
|
41
|
+
rspec-mocks (3.3.1)
|
42
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
43
|
+
rspec-support (~> 3.3.0)
|
44
|
+
rspec-support (3.3.0)
|
45
|
+
ruby_parser (3.7.0)
|
46
|
+
sexp_processor (~> 4.1)
|
47
|
+
sexp_processor (4.6.0)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
ramper!
|
54
|
+
rspec (= 3.3.0)
|
55
|
+
|
56
|
+
BUNDLED WITH
|
57
|
+
1.10.5
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
ramper
|
2
|
+
======
|
3
|
+
|
4
|
+
A ruby gem To help Developers to Ramp Up Faster.
|
5
|
+
|
6
|
+
```
|
7
|
+
gem install ramper
|
8
|
+
```
|
9
|
+
|
10
|
+
https://rubygems.org/gems/ramper
|
11
|
+
|
12
|
+
```
|
13
|
+
######### USAGE ########
|
14
|
+
# ramper [a] Gives authorship summary. To figure out who to talk to.
|
15
|
+
# ramper [fmc1] [n] Files with most changes
|
16
|
+
# ramper [fmc2] [n] Returns top n files with most commit
|
17
|
+
# ramper [child] [n] Displays classes that depend on the most other classes.
|
18
|
+
# ramper [parent] [n] Displays classes that are depended on by the most other classes.
|
19
|
+
# ramper [fmr] [n] Returns the top n recently changed files
|
20
|
+
# ramper [flog] [f] Runs the flog metric on a file/dir. Higher numbers = more complex or painful code.
|
21
|
+
# ramper [flay] [f] Runs the flay tool on a file/dir. Reports similar blocks of code.
|
22
|
+
# ramper [s] Executes rake stats
|
23
|
+
# ramper [m] [f] [flags] Computes metrics for a given file based on the flags given. Defaults to computing everything
|
24
|
+
# find . -name *.rb -type f | ramper [b] [flags] Batch file metrics for input stream.
|
25
|
+
# [flags] -f: flog stats, -a: top author and number of authors, -c: number of commits and first/last commit, -l: lines of code
|
26
|
+
# ramper [help] this message
|
27
|
+
# ramper [tips] Gives some tips on how to ramp up faster
|
28
|
+
########################
|
29
|
+
```
|
data/bin/ramper
CHANGED
@@ -1,45 +1,90 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'ramper'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
USAGE = <<END
|
5
|
+
######### USAGE ########
|
6
|
+
# ramper [a] #{Ramper.author_summary_help}
|
6
7
|
# ramper [fmc1] [n] #{Ramper.files_with_most_changes_help}
|
7
8
|
# ramper [fmc2] [n] #{Ramper.files_with_most_commit_help}
|
9
|
+
# ramper [child] [n] #{Ramper.dependency_in_help}
|
10
|
+
# ramper [parent] [n] #{Ramper.dependency_out_help}
|
11
|
+
# ramper [fmr] [n] #{Ramper.files_most_recent_help}
|
12
|
+
# ramper [flog] [f] #{Ramper.flog_help}
|
13
|
+
# ramper [flay] [f] #{Ramper.flay_help}
|
8
14
|
# ramper [s] #{Ramper.stats_help}
|
15
|
+
# ramper [m] [f] [flags] #{Ramper.file_metrics_help}
|
16
|
+
# find . -name *.rb -type f | ramper [b] [flags] #{Ramper.batch_metrics_help}
|
17
|
+
# [flags] -f: flog stats, -a: top author and number of authors, -c: number of commits and first/last commit, -l: lines of code
|
9
18
|
# ramper [help] this message
|
10
|
-
|
19
|
+
# ramper [tips] #{Ramper.tips_help}
|
20
|
+
########################
|
21
|
+
END
|
11
22
|
|
12
|
-
if ARGV.length == 0
|
13
|
-
puts usage
|
14
|
-
exit
|
15
|
-
end
|
16
23
|
|
17
24
|
def get_n
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
25
|
+
arg_to_number(1, 10)
|
26
|
+
end
|
27
|
+
|
28
|
+
def maybe_n
|
29
|
+
arg_to_number(1, false)
|
30
|
+
end
|
31
|
+
|
32
|
+
def arg_to_number(index, default)
|
33
|
+
n = default
|
34
|
+
if ARGV.length == index + 1
|
35
|
+
if ARGV[index].to_i > 0
|
36
|
+
n = ARGV[index].to_i
|
22
37
|
else
|
23
|
-
puts
|
38
|
+
puts USAGE
|
24
39
|
exit
|
25
|
-
end
|
40
|
+
end
|
26
41
|
end
|
27
|
-
|
28
42
|
n
|
29
43
|
end
|
30
44
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
when 'fmc2'
|
36
|
-
Ramper.files_with_most_commit get_n
|
37
|
-
|
38
|
-
when 's'
|
39
|
-
Ramper.stats
|
45
|
+
def get_filename
|
46
|
+
ARGV.length >= 2 ? ARGV[1] : './'
|
47
|
+
end
|
40
48
|
|
41
|
-
|
42
|
-
|
43
|
-
|
49
|
+
def get_flags
|
50
|
+
ARGV.drop(2)
|
51
|
+
end
|
44
52
|
|
53
|
+
def compute_metrics
|
54
|
+
if ARGV.length == 0
|
55
|
+
return USAGE
|
56
|
+
end
|
57
|
+
case ARGV[0]
|
58
|
+
when 'fmc1'
|
59
|
+
puts Ramper.files_with_most_changes(get_n)
|
60
|
+
when 'fmc2'
|
61
|
+
Ramper.files_with_most_commit(get_n)
|
62
|
+
when 'fmr'
|
63
|
+
Ramper.files_most_recent(get_n)
|
64
|
+
when 'child'
|
65
|
+
Ramper.dependency_in(maybe_n)
|
66
|
+
when 'parent'
|
67
|
+
Ramper.dependency_out(maybe_n)
|
68
|
+
when 's'
|
69
|
+
Ramper.stats
|
70
|
+
when 'a'
|
71
|
+
Ramper.author_summary
|
72
|
+
when 'flog'
|
73
|
+
Ramper.flog(get_filename)
|
74
|
+
when 'flay'
|
75
|
+
Ramper.flay(get_filename)
|
76
|
+
when 'm'
|
77
|
+
Ramper.file_metrics(get_filename, get_flags)
|
78
|
+
when 'b'
|
79
|
+
Ramper.batch_metrics(get_flags)
|
80
|
+
# TODO: remove this and use parameters
|
81
|
+
when 'test'
|
82
|
+
Ramper.batch_from_most_list([], Ramper.method(:files_most_recent), 10)
|
83
|
+
when 'tips'
|
84
|
+
Ramper.tips
|
85
|
+
else
|
86
|
+
USAGE
|
87
|
+
end
|
45
88
|
end
|
89
|
+
|
90
|
+
puts compute_metrics
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'courgette/directory_analyser'
|
2
|
+
|
3
|
+
class DependencyAnalyzer
|
4
|
+
def initialize
|
5
|
+
@graph = Courgette::DirectoryAnalyser.new.tap { |da| da.analyse('**/*.rb') }.graph
|
6
|
+
@stats = @graph.nodes.map { |node| { :in => @graph.dependency_count(node), :out => @graph.depender_count(node), :name => node.join("::") } }
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_in_stats(n)
|
10
|
+
get_stats(maybe_take(@stats.sort { |a, b| b[:in] <=> a[:in] }, n), :in)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_out_stats(n)
|
14
|
+
get_stats(maybe_take(@stats.sort { |a, b| b[:out] <=> a[:out] }, n), :out)
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_stats(stat_array, stat_index)
|
18
|
+
stat_array.map { |x| "#{x[stat_index]} #{x[:name]}" }.join("\n")
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def maybe_take(array, n)
|
23
|
+
if n
|
24
|
+
array.take(n)
|
25
|
+
else
|
26
|
+
array
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/ramper.rb
CHANGED
@@ -1,38 +1,154 @@
|
|
1
|
+
require 'dependency_analyzer'
|
2
|
+
require 'ramper_file_metrics'
|
3
|
+
|
1
4
|
class Ramper
|
5
|
+
VERSION = "0.0.3"
|
6
|
+
|
2
7
|
def self.version
|
3
|
-
puts
|
4
|
-
end
|
5
|
-
|
6
|
-
def self.execute(command)
|
7
|
-
puts "#{command}"
|
8
|
-
puts `#{command}`
|
8
|
+
puts VERSION
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.files_with_most_changes_help
|
12
12
|
"Files with most changes"
|
13
13
|
end
|
14
|
+
|
14
15
|
def self.files_with_most_changes(n)
|
15
|
-
n = n+1 # TODO Hack, Below returns n+1 lines
|
16
16
|
# http://stackoverflow.com/questions/7686582/finding-most-changed-files-in-git
|
17
|
-
|
17
|
+
`git log --pretty=format: --name-only | sed '/^$/d' | sort | uniq -c | sort -rg | head -#{n}`
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.files_with_most_commit_help
|
21
21
|
"Returns top n files with most commit"
|
22
22
|
end
|
23
|
+
|
23
24
|
def self.files_with_most_commit(n)
|
24
25
|
# http://stackoverflow.com/questions/5669621/git-find-out-which-files-have-had-the-most-commits
|
25
|
-
|
26
|
+
`git rev-list --objects --all | awk '$2' | sort -k2 | uniq -cf1 | sort -rn |
|
26
27
|
while read frequency sample path
|
27
|
-
do
|
28
|
+
do
|
28
29
|
[ "blob" == "$(git cat-file -t $sample)" ] && echo -e "$frequency\t$path";
|
29
|
-
done | head
|
30
|
+
done | head -#{n}`.gsub(/^-e /, '') #there's a bug with bash adds -e to each line
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.files_most_recent_help
|
34
|
+
"Returns the top n recently changed files"
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.files_most_recent(n)
|
38
|
+
require 'time'
|
39
|
+
# http://serverfault.com/questions/401437/how-to-retrieve-the-last-modification-date-of-all-files-in-a-git-repository
|
40
|
+
`git ls-tree -r --name-only HEAD | while read filename; do
|
41
|
+
echo "$(git log -1 --format="%at" -- $filename) $filename"
|
42
|
+
done | sort -rg | head -#{n}`.gsub(/^(\d+) /) { |_| "#{Time.at($1.to_i).iso8601} " }
|
30
43
|
end
|
31
44
|
|
32
45
|
def self.stats_help
|
33
46
|
"Executes rake stats"
|
34
47
|
end
|
48
|
+
|
35
49
|
def self.stats
|
36
|
-
|
50
|
+
require 'rake'
|
51
|
+
require 'code_statistics'
|
52
|
+
|
53
|
+
Rake::Task[:stats].execute
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.author_summary_help
|
57
|
+
"Gives authorship summary. To figure out who to talk to."
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.author_summary
|
61
|
+
# http://stackoverflow.com/questions/1265040/how-to-count-total-lines-changed-by-a-specific-author-in-a-git-repository
|
62
|
+
`git shortlog -sne --no-merges`
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.flog_help
|
66
|
+
"Runs the flog metric on a file/dir. Higher numbers = more complex or painful code."
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.flog(file)
|
70
|
+
`flog #{file}`
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.flay_help
|
74
|
+
"Runs the flay tool on a file/dir. Reports similar blocks of code."
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.flay(file)
|
78
|
+
`flay #{file}`
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.dependency_in_help
|
82
|
+
"Displays classes that depend on the most other classes."
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.dependency_in(n)
|
86
|
+
DependencyAnalyzer.new.get_in_stats n
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.dependency_out_help
|
90
|
+
"Displays classes that are depended on by the most other classes."
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.dependency_out(n)
|
94
|
+
DependencyAnalyzer.new.get_out_stats n
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.file_metrics_help
|
98
|
+
"Computes metrics for a given file based on the flags given. Defaults to computing everything"
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.file_metrics(file, options)
|
102
|
+
file_metric_calc = RamperFileMetrics.new(options)
|
103
|
+
puts file_metric_calc.process_file_format
|
104
|
+
puts file_metric_calc.process_file(file)
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.batch_metrics_help
|
108
|
+
"Batch file metrics for input stream."
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.batch_metrics(options)
|
112
|
+
file_metric_calc = RamperFileMetrics.new(options)
|
113
|
+
puts file_metric_calc.process_file_format
|
114
|
+
while (line=STDIN.gets)
|
115
|
+
puts file_metric_calc.process_file(line.chomp)
|
116
|
+
end
|
117
|
+
exit
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.batch_from_most_list(options, most_function, most_param)
|
121
|
+
file_metric_calc = RamperFileMetrics.new(options)
|
122
|
+
puts file_metric_calc.process_file_format
|
123
|
+
pull_files_from_stats_list(most_function.call(most_param)).each do |line|
|
124
|
+
puts file_metric_calc.process_file(line)
|
125
|
+
end
|
126
|
+
exit
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def self.pull_files_from_stats_list(list)
|
132
|
+
list.split("\n").map { |l| /\s(\S*?)$/.match(l) { |_| $1 } }
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.tips_help
|
136
|
+
"Gives some tips on how to ramp up faster"
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.tips
|
140
|
+
'######### Tips ########
|
141
|
+
# Talk to developer to understand overall architecture, block diagram, dependencies.
|
142
|
+
# Use pen and paper (or IDE) and draw UML diagrams like Class Diagram, Sequence Diagrams to understand structure.
|
143
|
+
# Follow Top Down Approach. Start from Top View. Then drill down to Mid View and then Low level view features.
|
144
|
+
# Build code, Run tests, Run Interface, Change something and see tests fail.
|
145
|
+
# Run code in a debugger to see the stack trace/code flow.
|
146
|
+
# Use "git grep" to search about git code base. More "git help grep".
|
147
|
+
# Jumping around definition and references in an IDE helps a lot.
|
148
|
+
# Write a glossary. It can cover class names, function names, datatype names, common prefixes
|
149
|
+
# and file names conventions. This can be contributed back to the project as documentation.
|
150
|
+
# Read the test suite. This will give you a better idea of what the library does.
|
151
|
+
# Use "git blame" to see when things have been changed.
|
152
|
+
########################'
|
37
153
|
end
|
38
154
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'flog_cli'
|
2
|
+
|
3
|
+
class RamperFileMetrics
|
4
|
+
|
5
|
+
def initialize(flags)
|
6
|
+
if flags.empty?
|
7
|
+
selected = Array.new(CSV_COLS.count, true)
|
8
|
+
else
|
9
|
+
selected = Array.new(CSV_COLS.count, false)
|
10
|
+
selected[0] = true
|
11
|
+
#TODO: use command line parser
|
12
|
+
#TODO: change array to hash
|
13
|
+
flags.each do |f|
|
14
|
+
case f
|
15
|
+
when '-a'
|
16
|
+
selected[3] = true
|
17
|
+
when '-c'
|
18
|
+
selected[2] = true
|
19
|
+
when '-f'
|
20
|
+
selected[4] = true
|
21
|
+
when '-l'
|
22
|
+
selected[1] = true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@csv_header = CSV_COLS.select.with_index { |_, ind| selected[ind] }
|
28
|
+
@selected_metrics = METRICS.select.with_index { |_, ind| selected[ind] }
|
29
|
+
end
|
30
|
+
|
31
|
+
def process_file_format
|
32
|
+
@csv_header.flatten.join(', ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_file(file)
|
36
|
+
@selected_metrics.map.with_index do |m, ind|
|
37
|
+
begin
|
38
|
+
m.call(file)
|
39
|
+
rescue => e
|
40
|
+
Array.new(@csv_header[ind].count, "Error #{e.message}".gsub(",", ";"))
|
41
|
+
end
|
42
|
+
end.flatten.join(', ')
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def self.start_end_dates_commits(file)
|
48
|
+
dates = `git log -- #{file} | grep 'Date: '`.split("\n")
|
49
|
+
start_date = DateTime.parse(dates.last.strip.gsub(/Date: /, ''))
|
50
|
+
end_date = DateTime.parse(dates.first.strip.gsub(/Date: /, ''))
|
51
|
+
num_commits = dates.count
|
52
|
+
|
53
|
+
[start_date, end_date, num_commits]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.lines_of_code(file)
|
57
|
+
`wc -l #{file}`.split(" ").first.strip
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.get_git_author_stats(file)
|
61
|
+
`git log --pretty=short --no-merges -- #{file} | git shortlog -sne`.split("\n")
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.author_stats(file)
|
65
|
+
authors = get_git_author_stats(file)
|
66
|
+
author_table = authors.map { |line| /\s+(\d+)\t(.*) <(.*)>/.match(line) { |_| { :count => $1.to_i, :name => $2, :email => $3 } } }
|
67
|
+
unique_email_table = combine_authors(author_table, :email)
|
68
|
+
unique_table = combine_authors(unique_email_table, :name)
|
69
|
+
num_authors = unique_table.count
|
70
|
+
top_author = unique_table.max { |a, b| a[:count] <=> b[:count] }
|
71
|
+
top_author = "#{top_author[:name]} <#{top_author[:email]}>"
|
72
|
+
|
73
|
+
[top_author, num_authors]
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.combine_authors(original_table, combine_key)
|
77
|
+
other_key = combine_key == :name ? :email : :name
|
78
|
+
result_map = Hash.new { |h, k| h[k]=[] }
|
79
|
+
original_table.each { |row| result_map[row[combine_key]].push(row.reject { |k, _| k==combine_key }) }
|
80
|
+
result_map.map { |key, val| { :count => val.inject(0) { |tot_count, x| tot_count + x[:count] },
|
81
|
+
combine_key => key,
|
82
|
+
other_key => val.max { |a, b| a[:count] <=> b[:count] }[other_key] } }
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.flog_file(file)
|
86
|
+
if /.*\.rb/.match(file)
|
87
|
+
flogger = FlogCLI.new
|
88
|
+
flogger.flog(file)
|
89
|
+
flog_tot = flogger.total_score.round(2)
|
90
|
+
flog_avg = flogger.average.round(2)
|
91
|
+
|
92
|
+
[flog_tot, flog_avg]
|
93
|
+
else
|
94
|
+
Array.new(2, "N/A")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# self.method blows up unless it is after the functions are defined
|
99
|
+
CSV_COLS = ['File', 'LOC', ['First edit', 'Most recent edit', '# of commits'],
|
100
|
+
['Top author', '# of authors'], ['Flog score', 'Flog/method average']]
|
101
|
+
METRICS = [Proc.new { |x| x }, self.method(:lines_of_code), self.method(:start_end_dates_commits),
|
102
|
+
self.method(:author_stats), self.method(:flog_file)]
|
103
|
+
end
|
data/ramper.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'ramper'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'ramper'
|
6
|
+
s.version = Ramper::VERSION
|
7
|
+
s.date = '2015-07-20'
|
8
|
+
s.summary = "ramper!"
|
9
|
+
s.description = "Ramp Up!"
|
10
|
+
s.authors = ["Ankush Raina"]
|
11
|
+
s.email = 'araina@groupon.com'
|
12
|
+
s.files = `git ls-files -z`.split("\x0")
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
s.homepage = 'http://rubygems.org/gems/ramper'
|
15
|
+
s.license = 'Groupon Inc'
|
16
|
+
s.executables << 'ramper'
|
17
|
+
|
18
|
+
s.add_runtime_dependency "flog", ["4.3.2"]
|
19
|
+
s.add_runtime_dependency "flay", ["2.6.1"]
|
20
|
+
s.add_runtime_dependency "courgette", ["0.3.0"]
|
21
|
+
s.add_runtime_dependency "code_statistics", ["0.2.13"]
|
22
|
+
|
23
|
+
s.add_development_dependency "rspec", ["3.3.0"]
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'ramper_file_metrics'
|
3
|
+
|
4
|
+
describe 'RamperFileMetrics' do
|
5
|
+
|
6
|
+
context '.combine_authors' do
|
7
|
+
it 'should return the same table if it has no dupes in the given field: email' do
|
8
|
+
orig = [{ :count => 2, :name => 'name', :email => 'email1' },
|
9
|
+
{ :count => 2, :name => 'name', :email => 'email2' },
|
10
|
+
{ :count => 2, :name => 'name', :email => 'email3' }]
|
11
|
+
RamperFileMetrics.combine_authors(orig, :email).should == orig
|
12
|
+
end
|
13
|
+
it 'should return the same table if it has no dupes in the given field: name' do
|
14
|
+
orig = [{ :count => 2, :name => 'name1', :email => 'email' },
|
15
|
+
{ :count => 2, :name => 'name2', :email => 'email' },
|
16
|
+
{ :count => 2, :name => 'name3', :email => 'email' }]
|
17
|
+
RamperFileMetrics.combine_authors(orig, :name).should == orig
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should combine elements if it has dupes in the given field: email' do
|
21
|
+
orig = [{ :count => 1, :name => 'name1', :email => 'email' },
|
22
|
+
{ :count => 2, :name => 'name2', :email => 'email' },
|
23
|
+
{ :count => 3, :name => 'name3', :email => 'email' }]
|
24
|
+
new = [{ :count => 6, :name => 'name3', :email => 'email' }]
|
25
|
+
RamperFileMetrics.combine_authors(orig, :email).should == new
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should combine elements if it has dupes in the given field: name' do
|
29
|
+
orig = [{ :count => 1, :name => 'name', :email => 'email1' },
|
30
|
+
{ :count => 2, :name => 'name', :email => 'email2' },
|
31
|
+
{ :count => 3, :name => 'name', :email => 'email3' }]
|
32
|
+
new = [{ :count => 6, :name => 'name', :email => 'email3' }]
|
33
|
+
RamperFileMetrics.combine_authors(orig, :name).should == new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context '.author_stats' do
|
38
|
+
|
39
|
+
it 'should have resolved duplicates in either field' do
|
40
|
+
RamperFileMetrics.stub(:get_git_author_stats).and_return([" 8 j1 <j>",
|
41
|
+
" 5 a <a1>",
|
42
|
+
" 3 a <a2>",
|
43
|
+
" 1 j2 <j>"])
|
44
|
+
RamperFileMetrics.author_stats('').should == ["j1 <j>", 2]
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should have combined by email first' do
|
48
|
+
RamperFileMetrics.stub(:get_git_author_stats).and_return([" 8 j1 <j>",
|
49
|
+
" 5 a1 <a1>",
|
50
|
+
" 3 a2 <a2>",
|
51
|
+
" 4 a1 <a2>",
|
52
|
+
" 1 j2 <j>"])
|
53
|
+
RamperFileMetrics.author_stats('').should == ["a1 <a2>", 2]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ramper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,88 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07-
|
13
|
-
dependencies:
|
12
|
+
date: 2015-07-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: flog
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 4.3.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 4.3.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: flay
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.6.1
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.6.1
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: courgette
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.3.0
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.3.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: code_statistics
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.2.13
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.2.13
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - '='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 3.3.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - '='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 3.3.0
|
14
94
|
description: Ramp Up!
|
15
95
|
email: araina@groupon.com
|
16
96
|
executables:
|
@@ -18,8 +98,16 @@ executables:
|
|
18
98
|
extensions: []
|
19
99
|
extra_rdoc_files: []
|
20
100
|
files:
|
21
|
-
-
|
101
|
+
- .gitignore
|
102
|
+
- Gemfile
|
103
|
+
- Gemfile.lock
|
104
|
+
- README.md
|
22
105
|
- bin/ramper
|
106
|
+
- lib/dependency_analyzer.rb
|
107
|
+
- lib/ramper.rb
|
108
|
+
- lib/ramper_file_metrics.rb
|
109
|
+
- ramper.gemspec
|
110
|
+
- spec/ramper_file_metrics_spec.rb
|
23
111
|
homepage: http://rubygems.org/gems/ramper
|
24
112
|
licenses:
|
25
113
|
- Groupon Inc
|