ramper 0.0.1 → 0.0.3
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.
- 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
|