ruby-maat 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.commitlintrc.json +44 -0
  3. data/.mailmap +3 -0
  4. data/.overcommit.yml +77 -0
  5. data/.release-please-config.json +33 -0
  6. data/.release-please-manifest.json +3 -0
  7. data/.rspec +3 -0
  8. data/.rubocop.yml +48 -0
  9. data/CHANGELOG.md +46 -0
  10. data/CI_CD_SETUP.md +180 -0
  11. data/CLAUDE.md +130 -0
  12. data/Dockerfile +40 -0
  13. data/README.md +444 -0
  14. data/README_RUBY.md +300 -0
  15. data/RELEASE_PLEASE_SETUP.md +198 -0
  16. data/RUBY_MAAT.md +227 -0
  17. data/Rakefile +12 -0
  18. data/doc/imgs/abs_churn_sample.png +0 -0
  19. data/doc/imgs/code_age_sample.png +0 -0
  20. data/doc/imgs/coupling_sample.png +0 -0
  21. data/doc/imgs/crime_cover.jpg +0 -0
  22. data/doc/imgs/tree_map_sample.png +0 -0
  23. data/doc/intro.md +3 -0
  24. data/exe/ruby-maat +6 -0
  25. data/lib/ruby_maat/analysis/authors.rb +47 -0
  26. data/lib/ruby_maat/analysis/base_analysis.rb +70 -0
  27. data/lib/ruby_maat/analysis/churn.rb +255 -0
  28. data/lib/ruby_maat/analysis/code_age.rb +53 -0
  29. data/lib/ruby_maat/analysis/commit_messages.rb +58 -0
  30. data/lib/ruby_maat/analysis/communication.rb +56 -0
  31. data/lib/ruby_maat/analysis/effort.rb +150 -0
  32. data/lib/ruby_maat/analysis/entities.rb +40 -0
  33. data/lib/ruby_maat/analysis/identity.rb +12 -0
  34. data/lib/ruby_maat/analysis/logical_coupling.rb +134 -0
  35. data/lib/ruby_maat/analysis/sum_of_coupling.rb +43 -0
  36. data/lib/ruby_maat/analysis/summary.rb +43 -0
  37. data/lib/ruby_maat/app.rb +143 -0
  38. data/lib/ruby_maat/change_record.rb +47 -0
  39. data/lib/ruby_maat/cli.rb +187 -0
  40. data/lib/ruby_maat/dataset.rb +205 -0
  41. data/lib/ruby_maat/groupers/layer_grouper.rb +67 -0
  42. data/lib/ruby_maat/groupers/team_mapper.rb +51 -0
  43. data/lib/ruby_maat/groupers/time_grouper.rb +70 -0
  44. data/lib/ruby_maat/output/csv_output.rb +65 -0
  45. data/lib/ruby_maat/parsers/base_parser.rb +63 -0
  46. data/lib/ruby_maat/parsers/git2_parser.rb +72 -0
  47. data/lib/ruby_maat/parsers/git_parser.rb +66 -0
  48. data/lib/ruby_maat/parsers/mercurial_parser.rb +64 -0
  49. data/lib/ruby_maat/parsers/perforce_parser.rb +77 -0
  50. data/lib/ruby_maat/parsers/svn_parser.rb +76 -0
  51. data/lib/ruby_maat/parsers/tfs_parser.rb +103 -0
  52. data/lib/ruby_maat/version.rb +5 -0
  53. data/lib/ruby_maat.rb +44 -0
  54. metadata +143 -0
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ module RubyMaat
5
+ module Parsers
6
+ # Git2 parser - preferred Git parser (more tolerant and faster)
7
+ #
8
+ # Input: git log --all --numstat --date=short --pretty=format:'--%h--%ad--%aN' --no-renames --after=YYYY-MM-DD
9
+ #
10
+ # Sample format:
11
+ # --586b4eb--2015-06-15--Adam Tornhill
12
+ # 35 0 src/code_maat/mining/vcs.clj
13
+ # 2 1 test/file.rb
14
+ #
15
+ # --abc123--2015-06-16--Jane Doe
16
+ # 10 5 lib/example.rb
17
+ class Git2Parser < BaseParser
18
+ COMMIT_SEPARATOR = /^--([a-z0-9]+)--(\d{4}-\d{2}-\d{2})--(.+)$/
19
+ CHANGE_PATTERN = /^(-|\d+)\s+(-|\d+)\s+(.*)$/
20
+
21
+ protected
22
+
23
+ def parse_content(content)
24
+ records = []
25
+ current_commit = nil
26
+
27
+ content.each_line do |line|
28
+ line.strip!
29
+ next if line.empty?
30
+
31
+ if (commit_match = line.match(COMMIT_SEPARATOR))
32
+ current_commit = {
33
+ revision: commit_match[1],
34
+ date: parse_date(commit_match[2]),
35
+ author: commit_match[3].strip
36
+ }
37
+ elsif current_commit && (change_match = line.match(CHANGE_PATTERN))
38
+ added = clean_numstat(change_match[1])
39
+ deleted = clean_numstat(change_match[2])
40
+ file = change_match[3].strip
41
+
42
+ next if file.empty? || file == File::NULL
43
+ next if added.nil? && deleted.nil?
44
+
45
+ records << ChangeRecord.new(
46
+ entity: file,
47
+ author: current_commit[:author],
48
+ date: current_commit[:date],
49
+ revision: current_commit[:revision],
50
+ loc_added: added,
51
+ loc_deleted: deleted
52
+ )
53
+ end
54
+ end
55
+
56
+ records
57
+ end
58
+
59
+ private
60
+
61
+ def parse_date(date_str)
62
+ Date.parse(date_str)
63
+ rescue Date::Error
64
+ nil
65
+ end
66
+
67
+ def clean_numstat(value)
68
+ (value == "-") ? nil : value.to_i
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyMaat
4
+ module Parsers
5
+ # Legacy Git parser for backward compatibility
6
+ #
7
+ # Input: git log --pretty=format:'[%h] %aN %ad %s' --date=short --numstat --after=YYYY-MM-DD
8
+ #
9
+ # Sample format:
10
+ # [586b4eb] Adam Tornhill 2015-06-15 Add new feature
11
+ # 35 0 src/code_maat/mining/vcs.clj
12
+ # 2 1 test/file.rb
13
+ #
14
+ # [abc123] Jane Doe 2015-06-16 Fix bug in parser
15
+ # 10 5 lib/example.rb
16
+ class GitParser < BaseParser
17
+ COMMIT_PATTERN = /^\[([a-f0-9]+)\]\s+(.+?)\s+(\d{4}-\d{2}-\d{2})\s+(.*)$/
18
+ CHANGE_PATTERN = /^(\d+|-)\s+(\d+|-)\s+(.+)$/
19
+
20
+ protected
21
+
22
+ def parse_content(content)
23
+ entries = []
24
+ current_commit = nil
25
+
26
+ content.each_line do |line|
27
+ line = line.chomp
28
+
29
+ # Skip empty lines
30
+ next if line.strip.empty?
31
+
32
+ if (commit_match = line.match(COMMIT_PATTERN))
33
+ # New commit header
34
+ current_commit = {
35
+ revision: commit_match[1],
36
+ author: commit_match[2].strip,
37
+ date: parse_date(commit_match[3]),
38
+ message: commit_match[4].strip
39
+ }
40
+ elsif current_commit && (change_match = line.match(CHANGE_PATTERN))
41
+ # File change line
42
+ added = clean_numstat(change_match[1])
43
+ deleted = clean_numstat(change_match[2])
44
+ file = change_match[3].strip
45
+
46
+ # Skip empty or invalid file names
47
+ next if file.empty? || file == File::NULL
48
+
49
+ entries << ChangeRecord.new(
50
+ entity: file,
51
+ author: current_commit[:author],
52
+ date: current_commit[:date],
53
+ revision: current_commit[:revision],
54
+ message: current_commit[:message],
55
+ loc_added: added,
56
+ loc_deleted: deleted
57
+ )
58
+ end
59
+ # Ignore unrecognized lines
60
+ end
61
+
62
+ entries
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyMaat
4
+ module Parsers
5
+ # Mercurial parser
6
+ #
7
+ # Input: hg log --template "rev: {rev} author: {author} date: {date|shortdate} files:\n{files %'{file}\n'}\n" --date ">YYYY-MM-DD"
8
+ #
9
+ # Sample format:
10
+ # rev: 123 author: John Doe date: 2015-06-15 files:
11
+ # src/main.py
12
+ # test/test_main.py
13
+ #
14
+ # rev: 124 author: Jane Smith date: 2015-06-16 files:
15
+ # lib/helper.py
16
+ class MercurialParser < BaseParser
17
+ ENTRY_PATTERN = /^rev:\s+(\d+)\s+author:\s+(.+?)\s+date:\s+(\d{4}-\d{2}-\d{2})\s+files:$/
18
+
19
+ protected
20
+
21
+ def parse_content(content)
22
+ entries = []
23
+ current_commit = nil
24
+ in_files_section = false
25
+
26
+ content.each_line do |line|
27
+ line = line.chomp
28
+
29
+ if line.strip.empty?
30
+ # Empty line marks end of current commit
31
+ current_commit = nil
32
+ in_files_section = false
33
+ next
34
+ end
35
+
36
+ if (commit_match = line.match(ENTRY_PATTERN))
37
+ # New commit header
38
+ current_commit = {
39
+ revision: commit_match[1],
40
+ author: commit_match[2].strip,
41
+ date: parse_date(commit_match[3])
42
+ }
43
+ in_files_section = true
44
+ elsif current_commit && in_files_section && !line.strip.empty?
45
+ # File line
46
+ file = line.strip
47
+
48
+ # Skip invalid file names
49
+ next if file.empty? || file == File::NULL
50
+
51
+ entries << ChangeRecord.new(
52
+ entity: file,
53
+ author: current_commit[:author],
54
+ date: current_commit[:date],
55
+ revision: current_commit[:revision]
56
+ )
57
+ end
58
+ end
59
+
60
+ entries
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyMaat
4
+ module Parsers
5
+ # Perforce parser
6
+ #
7
+ # Input: p4 changes -s submitted -m 5000 //depot/project/... | cut -d ' ' -f 2 | xargs -I commitid -n1 sh -c 'p4 describe -s commitid | grep -v "^\s*$" && echo ""'
8
+ #
9
+ # Sample format:
10
+ # Change 12345 by jdoe@workspace on 2015/06/15 10:30:45
11
+ #
12
+ # Fix bug in parser
13
+ #
14
+ # Affected files ...
15
+ #
16
+ # ... //depot/project/src/main.java#2 edit
17
+ # ... //depot/project/test/test.java#1 add
18
+ class PerforceParser < BaseParser
19
+ CHANGE_PATTERN = %r{^Change\s+(\d+)\s+by\s+([^@]+)@\S+\s+on\s+(\d{4}/\d{2}/\d{2})}
20
+ FILE_PATTERN = /^\.\.\.\s+(.+?)#\d+\s+(\w+)/
21
+
22
+ protected
23
+
24
+ def parse_content(content)
25
+ entries = []
26
+ current_commit = nil
27
+ in_files_section = false
28
+
29
+ content.each_line do |line|
30
+ line = line.chomp
31
+
32
+ if (change_match = line.match(CHANGE_PATTERN))
33
+ # New changelist header
34
+ current_commit = {
35
+ revision: change_match[1],
36
+ author: change_match[2].strip,
37
+ date: parse_perforce_date(change_match[3])
38
+ }
39
+ in_files_section = false
40
+ elsif line.include?("Affected files")
41
+ # Start of files section
42
+ in_files_section = true
43
+ elsif current_commit && in_files_section && (file_match = line.match(FILE_PATTERN))
44
+ # File change line
45
+ file = file_match[1].strip
46
+ action = file_match[2]
47
+
48
+ # Skip deleted files for most analyses (they don't contribute to current state)
49
+ next if action == "delete"
50
+ next if file.empty?
51
+
52
+ entries << ChangeRecord.new(
53
+ entity: file,
54
+ author: current_commit[:author],
55
+ date: current_commit[:date],
56
+ revision: current_commit[:revision]
57
+ )
58
+ elsif line.strip.empty? && current_commit
59
+ # Empty line might end current changelist
60
+ # But we keep current_commit until we see a new one
61
+ end
62
+ end
63
+
64
+ entries
65
+ end
66
+
67
+ private
68
+
69
+ def parse_perforce_date(date_str)
70
+ # Perforce date format: 2015/06/15
71
+ Date.strptime(date_str, "%Y/%m/%d")
72
+ rescue Date::Error => e
73
+ raise ArgumentError, "Invalid Perforce date format: #{date_str} (#{e.message})"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rexml/document"
4
+
5
+ module RubyMaat
6
+ module Parsers
7
+ # SVN parser for XML log files
8
+ #
9
+ # Input: svn log -v --xml > logfile.log -r {YYYYmmDD}:HEAD
10
+ #
11
+ # Sample XML format:
12
+ # <log>
13
+ # <logentry revision="12345">
14
+ # <author>jdoe</author>
15
+ # <date>2015-06-15T10:30:45.123456Z</date>
16
+ # <paths>
17
+ # <path action="M">/trunk/src/file.java</path>
18
+ # <path action="A">/trunk/test/test.java</path>
19
+ # </paths>
20
+ # <msg>Fix bug in parser</msg>
21
+ # </logentry>
22
+ # </log>
23
+ class SvnParser < BaseParser
24
+ protected
25
+
26
+ def parse_content(content)
27
+ entries = []
28
+
29
+ begin
30
+ doc = REXML::Document.new(content)
31
+
32
+ doc.elements.each("log/logentry") do |logentry|
33
+ revision = logentry.attributes["revision"]
34
+ author = logentry.elements["author"]&.text || "unknown"
35
+ date_text = logentry.elements["date"]&.text
36
+ message = logentry.elements["msg"]&.text || ""
37
+
38
+ next unless date_text && revision
39
+
40
+ date = parse_svn_date(date_text)
41
+
42
+ # Extract all path changes
43
+ logentry.elements.each("paths/path") do |path_element|
44
+ entity = path_element.text&.strip
45
+ path_element.attributes["action"]
46
+
47
+ next if entity.nil? || entity.empty?
48
+
49
+ entries << ChangeRecord.new(
50
+ entity: entity,
51
+ author: author,
52
+ date: date,
53
+ revision: revision,
54
+ message: message
55
+ )
56
+ end
57
+ end
58
+ rescue REXML::ParseException => e
59
+ raise ArgumentError, "Invalid XML format in SVN log file: #{e.message}"
60
+ end
61
+
62
+ entries
63
+ end
64
+
65
+ private
66
+
67
+ def parse_svn_date(date_str)
68
+ # SVN date format: 2015-06-15T10:30:45.123456Z
69
+ # Convert to Date object
70
+ DateTime.parse(date_str).to_date
71
+ rescue => e
72
+ raise ArgumentError, "Invalid SVN date format: #{date_str} (#{e.message})"
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyMaat
4
+ module Parsers
5
+ # Team Foundation Server parser
6
+ #
7
+ # Input: tf hist /path/to/workspace /noprompt /format:detailed /recursive
8
+ #
9
+ # Sample format:
10
+ # Changeset: 12345
11
+ # User: DOMAIN\jdoe
12
+ # Date: Friday, January 15, 2016 1:12:35 PM
13
+ #
14
+ # Comment:
15
+ # Fix bug in parser
16
+ #
17
+ # Items:
18
+ # edit $/Project/src/main.cs
19
+ # add $/Project/test/test.cs
20
+ class TfsParser < BaseParser
21
+ CHANGESET_PATTERN = /^Changeset:\s+(\d+)/
22
+ USER_PATTERN = /^User:\s+(.+)/
23
+ DATE_PATTERN = /^Date:\s+(.+)/
24
+ ITEM_PATTERN = /^\s+(edit|add|delete)\s+(\S.+)/
25
+
26
+ protected
27
+
28
+ def parse_content(content)
29
+ entries = []
30
+ current_commit = nil
31
+ in_items_section = false
32
+
33
+ content.each_line do |line|
34
+ line = line.chomp
35
+
36
+ if (changeset_match = line.match(CHANGESET_PATTERN))
37
+ # New changeset
38
+ current_commit = {revision: changeset_match[1]}
39
+ in_items_section = false
40
+ elsif current_commit && (user_match = line.match(USER_PATTERN))
41
+ # User line
42
+ user = user_match[1].strip
43
+ # Remove domain prefix if present (DOMAIN\user -> user)
44
+ user = user.split("\\").last if user.include?("\\")
45
+ current_commit[:author] = user
46
+ elsif current_commit && (date_match = line.match(DATE_PATTERN))
47
+ # Date line
48
+ begin
49
+ current_commit[:date] = parse_tfs_date(date_match[1])
50
+ rescue ArgumentError
51
+ # Skip this changeset if we can't parse the date
52
+ current_commit = nil
53
+ next
54
+ end
55
+ elsif line.strip == "Items:"
56
+ # Start of items section
57
+ in_items_section = true
58
+ elsif current_commit && in_items_section && (item_match = line.match(ITEM_PATTERN))
59
+ # Item change line
60
+ action = item_match[1]
61
+ file = item_match[2].strip
62
+
63
+ # Skip deleted files and invalid paths
64
+ next if action == "delete"
65
+ next if file.empty? || file == "$/null"
66
+
67
+ # Ensure we have all required fields
68
+ next unless current_commit[:author] && current_commit[:date]
69
+
70
+ entries << ChangeRecord.new(
71
+ entity: file,
72
+ author: current_commit[:author],
73
+ date: current_commit[:date],
74
+ revision: current_commit[:revision]
75
+ )
76
+ elsif line.strip.empty?
77
+ # Empty line might separate sections
78
+ in_items_section = false if in_items_section
79
+ end
80
+ end
81
+
82
+ entries
83
+ end
84
+
85
+ private
86
+
87
+ def parse_tfs_date(date_str)
88
+ # TFS date format: "Friday, January 15, 2016 1:12:35 PM"
89
+ # Note: The parser expects en-US locale format
90
+ begin
91
+ DateTime.strptime(date_str.strip, "%A, %B %d, %Y %I:%M:%S %p").to_date
92
+ rescue Date::Error
93
+ # Try alternative format without day of week
94
+ DateTime.strptime(date_str.strip, "%B %d, %Y %I:%M:%S %p").to_date
95
+ end
96
+ rescue Date::Error => e
97
+ raise ArgumentError,
98
+ "Invalid TFS date format: #{date_str}. Expected en-US locale format like " \
99
+ "'Friday, January 15, 2016 1:12:35 PM' (#{e.message})"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyMaat
4
+ VERSION = "1.0.0"
5
+ end
data/lib/ruby_maat.rb ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ruby_maat/version"
4
+ require_relative "ruby_maat/change_record"
5
+ require_relative "ruby_maat/dataset"
6
+
7
+ # Core parsers
8
+ require_relative "ruby_maat/parsers/base_parser"
9
+ require_relative "ruby_maat/parsers/git_parser"
10
+ require_relative "ruby_maat/parsers/git2_parser"
11
+ require_relative "ruby_maat/parsers/svn_parser"
12
+ require_relative "ruby_maat/parsers/mercurial_parser"
13
+ require_relative "ruby_maat/parsers/perforce_parser"
14
+ require_relative "ruby_maat/parsers/tfs_parser"
15
+
16
+ # Data processors
17
+ require_relative "ruby_maat/groupers/layer_grouper"
18
+ require_relative "ruby_maat/groupers/time_grouper"
19
+ require_relative "ruby_maat/groupers/team_mapper"
20
+
21
+ # Analysis modules (load before app.rb since app references them)
22
+ require_relative "ruby_maat/analysis/base_analysis"
23
+ require_relative "ruby_maat/analysis/authors"
24
+ require_relative "ruby_maat/analysis/entities"
25
+ require_relative "ruby_maat/analysis/logical_coupling"
26
+ require_relative "ruby_maat/analysis/churn"
27
+ require_relative "ruby_maat/analysis/effort"
28
+ require_relative "ruby_maat/analysis/communication"
29
+ require_relative "ruby_maat/analysis/code_age"
30
+ require_relative "ruby_maat/analysis/summary"
31
+ require_relative "ruby_maat/analysis/commit_messages"
32
+ require_relative "ruby_maat/analysis/sum_of_coupling"
33
+ require_relative "ruby_maat/analysis/identity"
34
+
35
+ # Output
36
+ require_relative "ruby_maat/output/csv_output"
37
+
38
+ # Main app and CLI (load after dependencies)
39
+ require_relative "ruby_maat/app"
40
+ require_relative "ruby_maat/cli"
41
+
42
+ module RubyMaat
43
+ class Error < StandardError; end
44
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-maat
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Tornhill
8
+ - Claude Code
9
+ - Bart Agapinan
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2025-08-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: csv
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '3.2'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '3.2'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rexml
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '3.2'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '3.2'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rover-df
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '0.3'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.3'
56
+ description: Ruby Maat is a command line tool used to mine and analyze data from version-control
57
+ systems (VCS). This is a Ruby port of the original Clojure Code Maat.
58
+ email:
59
+ - bart@sonic.net
60
+ executables:
61
+ - ruby-maat
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".commitlintrc.json"
66
+ - ".mailmap"
67
+ - ".overcommit.yml"
68
+ - ".release-please-config.json"
69
+ - ".release-please-manifest.json"
70
+ - ".rspec"
71
+ - ".rubocop.yml"
72
+ - CHANGELOG.md
73
+ - CI_CD_SETUP.md
74
+ - CLAUDE.md
75
+ - Dockerfile
76
+ - README.md
77
+ - README_RUBY.md
78
+ - RELEASE_PLEASE_SETUP.md
79
+ - RUBY_MAAT.md
80
+ - Rakefile
81
+ - doc/imgs/abs_churn_sample.png
82
+ - doc/imgs/code_age_sample.png
83
+ - doc/imgs/coupling_sample.png
84
+ - doc/imgs/crime_cover.jpg
85
+ - doc/imgs/tree_map_sample.png
86
+ - doc/intro.md
87
+ - exe/ruby-maat
88
+ - lib/ruby_maat.rb
89
+ - lib/ruby_maat/analysis/authors.rb
90
+ - lib/ruby_maat/analysis/base_analysis.rb
91
+ - lib/ruby_maat/analysis/churn.rb
92
+ - lib/ruby_maat/analysis/code_age.rb
93
+ - lib/ruby_maat/analysis/commit_messages.rb
94
+ - lib/ruby_maat/analysis/communication.rb
95
+ - lib/ruby_maat/analysis/effort.rb
96
+ - lib/ruby_maat/analysis/entities.rb
97
+ - lib/ruby_maat/analysis/identity.rb
98
+ - lib/ruby_maat/analysis/logical_coupling.rb
99
+ - lib/ruby_maat/analysis/sum_of_coupling.rb
100
+ - lib/ruby_maat/analysis/summary.rb
101
+ - lib/ruby_maat/app.rb
102
+ - lib/ruby_maat/change_record.rb
103
+ - lib/ruby_maat/cli.rb
104
+ - lib/ruby_maat/dataset.rb
105
+ - lib/ruby_maat/groupers/layer_grouper.rb
106
+ - lib/ruby_maat/groupers/team_mapper.rb
107
+ - lib/ruby_maat/groupers/time_grouper.rb
108
+ - lib/ruby_maat/output/csv_output.rb
109
+ - lib/ruby_maat/parsers/base_parser.rb
110
+ - lib/ruby_maat/parsers/git2_parser.rb
111
+ - lib/ruby_maat/parsers/git_parser.rb
112
+ - lib/ruby_maat/parsers/mercurial_parser.rb
113
+ - lib/ruby_maat/parsers/perforce_parser.rb
114
+ - lib/ruby_maat/parsers/svn_parser.rb
115
+ - lib/ruby_maat/parsers/tfs_parser.rb
116
+ - lib/ruby_maat/version.rb
117
+ homepage: https://github.com/viamin/ruby-maat
118
+ licenses:
119
+ - GPL-3.0
120
+ metadata:
121
+ allowed_push_host: https://rubygems.org
122
+ homepage_uri: https://github.com/viamin/ruby-maat
123
+ source_code_uri: https://github.com/viamin/ruby-maat
124
+ changelog_uri: https://github.com/viamin/ruby-maat/blob/main/CHANGELOG.md
125
+ rubygems_mfa_required: 'true'
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: 3.2.0
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubygems_version: 3.6.2
141
+ specification_version: 4
142
+ summary: A command line tool used to mine and analyze data from version-control systems
143
+ test_files: []