rails_architect_analyzer 0.1.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.
@@ -0,0 +1,212 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "colorize"
5
+
6
+ module RailsArchitect
7
+ module Reporters
8
+ # Generates and formats analysis reports with colorized output
9
+ class ReportGenerator
10
+ attr_reader :results
11
+
12
+ def initialize(results)
13
+ @results = results
14
+ end
15
+
16
+ def generate
17
+ print_header
18
+ print_architecture_report
19
+ print_tdd_report
20
+ print_bdd_report
21
+ print_solid_report
22
+ print_summary
23
+ print_recommendations
24
+ end
25
+
26
+ def to_json(*_args)
27
+ @results.to_json
28
+ end
29
+
30
+ private
31
+
32
+ def print_header
33
+ puts "\n#{'=' * 80}"
34
+ puts "šŸ—ļø RAILS ARCHITECT - PROJECT ANALYSIS REPORT".colorize(:blue).bold
35
+ puts "#{'=' * 80}\n"
36
+ end
37
+
38
+ def print_architecture_report
39
+ arch = @results[:architecture]
40
+ puts "šŸ“ ARCHITECTURE ANALYSIS".colorize(:cyan).bold
41
+ puts "-" * 80
42
+ puts "Overall Score: #{arch[:score]}%".colorize(:yellow)
43
+
44
+ puts "\nāœ“ Existing Directories (#{arch[:structure].count { |d| d[:exists] }}/#{arch[:structure].count}):"
45
+ arch[:structure].each do |dir|
46
+ status = dir[:exists] ? "āœ…" : "āŒ"
47
+ count = dir[:exists] ? " (#{dir[:files_count]} files)" : ""
48
+ puts " #{status} #{dir[:name]}#{count}"
49
+ end
50
+
51
+ unless arch[:missing_dirs].empty?
52
+ puts "\nāš ļø Missing Important Directories:"
53
+ arch[:missing_dirs].each { |dir| puts " • #{dir}" }
54
+ end
55
+
56
+ puts "\nšŸ“¦ Optional Patterns Available:"
57
+ arch[:optional_dirs].each do |dir|
58
+ status = dir[:exists] ? "āœ… Implemented" : "āŒ Not used"
59
+ puts " #{status} - #{dir[:description]} (#{dir[:name]})"
60
+ end
61
+
62
+ if arch[:suggestions].any?
63
+ puts "\nšŸ’” Suggestions:"
64
+ arch[:suggestions].each { |suggestion| puts " • #{suggestion}" }
65
+ end
66
+
67
+ puts "\n"
68
+ end
69
+
70
+ def print_tdd_report
71
+ tdd = @results[:tdd]
72
+ puts "🧪 TEST-DRIVEN DEVELOPMENT (TDD) ANALYSIS".colorize(:cyan).bold
73
+ puts "-" * 80
74
+
75
+ score_data = tdd[:score]
76
+ puts "Coverage Score: #{score_data[:score].round(2)}% #{score_data[:rating]}".colorize(score_data[:color])
77
+
78
+ puts "\nTest Files:"
79
+ puts " • Spec files: #{tdd[:spec_files]}"
80
+ puts " • Test files: #{tdd[:test_files]}"
81
+ puts " • Total: #{tdd[:spec_files] + tdd[:test_files]}"
82
+
83
+ puts "\nTest Structure Breakdown:"
84
+ tdd[:test_structure].each do |type, counts|
85
+ puts " • #{type.capitalize}: #{counts[:total]} files (#{counts[:spec]} specs, #{counts[:test]} tests)"
86
+ end
87
+
88
+ if tdd[:suggestions].any?
89
+ puts "\nšŸ’” Suggestions:"
90
+ tdd[:suggestions].each { |suggestion| puts " • #{suggestion}" }
91
+ end
92
+
93
+ puts "\n"
94
+ end
95
+
96
+ def print_bdd_report
97
+ bdd = @results[:bdd]
98
+ puts "šŸŽÆ BEHAVIOR-DRIVEN DEVELOPMENT (BDD) ANALYSIS".colorize(:cyan).bold
99
+ puts "-" * 80
100
+
101
+ score_data = bdd[:score]
102
+ puts "BDD Score: #{score_data[:rating]}".colorize(score_data[:color])
103
+
104
+ puts "\nFrameworks:"
105
+ puts " • Cucumber: #{bdd[:has_cucumber] ? 'āœ… Installed' : 'āŒ Not installed'}"
106
+ puts " • RSpec: #{bdd[:has_rspec] ? 'āœ… Installed' : 'āŒ Not installed'}"
107
+
108
+ puts "\nFeatures & Scenarios:"
109
+ puts " • Feature files: #{bdd[:feature_files_count]}"
110
+ puts " • Step definitions: #{bdd[:step_definitions_count]}"
111
+
112
+ puts "\nBDD Practices:"
113
+ practices = bdd[:practices]
114
+ puts " • User Stories: #{practices[:user_stories] ? 'āœ… Found' : 'āŒ Not found'}"
115
+ scenarios = practices[:readable_scenarios]
116
+ readable = scenarios[:present] ? "āœ… #{scenarios[:count]} found" : "āŒ Not found"
117
+ puts " • Readable Scenarios: #{readable}"
118
+ request_specs = practices[:integration_tests][:request_specs]
119
+ integration_files = practices[:integration_tests][:integration_test_files]
120
+ puts " • Integration Tests: #{request_specs + integration_files} files"
121
+
122
+ if bdd[:suggestions].any?
123
+ puts "\nšŸ’” Suggestions:"
124
+ bdd[:suggestions].each { |suggestion| puts " • #{suggestion}" }
125
+ end
126
+
127
+ puts "\n"
128
+ end
129
+
130
+ def print_solid_report
131
+ solid = @results[:solid]
132
+ puts "⚔ SOLID PRINCIPLES ANALYSIS".colorize(:cyan).bold
133
+ puts "-" * 80
134
+
135
+ score_data = solid[:score]
136
+ puts "SOLID Score: #{score_data[:score]}/100 #{score_data[:rating]}".colorize(score_data[:color])
137
+
138
+ puts "\nPrinciple Analysis:"
139
+
140
+ srp = solid[:single_responsibility]
141
+ puts "\n1. Single Responsibility Principle (SRP)"
142
+ puts " Status: #{srp[:status]}".colorize(srp[:status].include?("āœ…") ? :light_green : :yellow)
143
+ puts " Issues found in: #{srp[:issues].join(', ')}" unless srp[:issues].empty?
144
+
145
+ ocp = solid[:open_closed]
146
+ puts "\n2. Open/Closed Principle (OCP)"
147
+ puts " Status: #{ocp[:status]}".colorize(ocp[:status].include?("āœ…") ? :light_green : :yellow)
148
+ puts " - Concerns: #{ocp[:has_concerns] ? 'āœ… Yes' : 'āŒ No'}"
149
+ puts " - Inheritance: #{ocp[:has_inheritance] ? 'āœ… Used' : 'āŒ Not used'}"
150
+
151
+ lsp = solid[:liskov_substitution]
152
+ puts "\n3. Liskov Substitution Principle (LSP)"
153
+ puts " Status: #{lsp[:status]}".colorize(lsp[:status].include?("āœ…") ? :light_green : :yellow)
154
+ puts " - Inheritance depth: #{lsp[:inheritance_chains]}"
155
+
156
+ isp = solid[:interface_segregation]
157
+ puts "\n4. Interface Segregation Principle (ISP)"
158
+ puts " Status: #{isp[:status]}".colorize(isp[:status].include?("āœ…") ? :light_green : :yellow)
159
+
160
+ dip = solid[:dependency_inversion]
161
+ puts "\n5. Dependency Inversion Principle (DIP)"
162
+ puts " Status: #{dip[:status]}".colorize(dip[:status].include?("āœ…") ? :light_green : :yellow)
163
+
164
+ if solid[:suggestions].any?
165
+ puts "\nšŸ’” Suggestions:"
166
+ solid[:suggestions].each { |suggestion| puts " • #{suggestion}" }
167
+ end
168
+
169
+ puts "\n"
170
+ end
171
+
172
+ def print_summary
173
+ puts "=" * 80
174
+ puts "šŸ“Š OVERALL SUMMARY".colorize(:blue).bold
175
+ puts "=" * 80
176
+ puts "\nArchitecture: #{@results[:architecture][:score]}%".colorize(:light_yellow)
177
+ tdd_score = @results[:tdd][:score]
178
+ tdd_str = "TDD Coverage: #{tdd_score[:score].round(2)}% #{tdd_score[:rating]}"
179
+ puts tdd_str.colorize(tdd_score[:color])
180
+ bdd_score = @results[:bdd][:score]
181
+ puts "BDD Practices: #{bdd_score[:rating]}".colorize(bdd_score[:color])
182
+ solid_score = @results[:solid][:score]
183
+ solid_str = "SOLID Score: #{solid_score[:score]}/100 #{solid_score[:rating]}"
184
+ puts solid_str.colorize(solid_score[:color])
185
+ puts "\n"
186
+ end
187
+
188
+ def print_recommendations
189
+ puts "=" * 80
190
+ puts "šŸš€ RECOMMENDATIONS FOR IMPROVEMENT".colorize(:green).bold
191
+ puts "#{'=' * 80}\n"
192
+
193
+ all_suggestions = (
194
+ @results[:architecture][:suggestions] +
195
+ @results[:tdd][:suggestions] +
196
+ @results[:bdd][:suggestions] +
197
+ @results[:solid][:suggestions]
198
+ ).uniq
199
+
200
+ if all_suggestions.any?
201
+ all_suggestions.each_with_index do |suggestion, index|
202
+ puts "#{index + 1}. #{suggestion}"
203
+ end
204
+ else
205
+ puts "āœ… Excellent! Your project follows best practices.".colorize(:light_green)
206
+ end
207
+
208
+ puts "\n#{'=' * 80}\n"
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsArchitect
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_architect/version"
4
+ require "rails_architect/analyzers/architecture_analyzer"
5
+ require "rails_architect/analyzers/tdd_analyzer"
6
+ require "rails_architect/analyzers/bdd_analyzer"
7
+ require "rails_architect/analyzers/solid_analyzer"
8
+ require "rails_architect/reporters/report_generator"
9
+ require "rails_architect/cli"
10
+
11
+ # RailsArchitect gem provides comprehensive analysis of Rails projects
12
+ # across architecture, TDD, BDD, and SOLID principles
13
+ module RailsArchitect
14
+ class Error < StandardError; end
15
+
16
+ def self.analyze(project_path = Rails.root)
17
+ RailsArchitect::Core.new(project_path).analyze
18
+ end
19
+ end
20
+
21
+ module RailsArchitect
22
+ # Core analyzer orchestrating all individual analyzers
23
+ class Core
24
+ attr_reader :project_path, :results
25
+
26
+ def initialize(project_path = Rails.root)
27
+ @project_path = project_path
28
+ @results = {}
29
+ end
30
+
31
+ def analyze
32
+ puts "šŸ” Analyzing Rails Project Architecture...\n".colorize(:blue)
33
+
34
+ run_analyzers
35
+ generate_report
36
+
37
+ @results
38
+ end
39
+
40
+ private
41
+
42
+ def run_analyzers
43
+ @results[:architecture] = RailsArchitect::Analyzers::ArchitectureAnalyzer.new(project_path).analyze
44
+ @results[:tdd] = RailsArchitect::Analyzers::TddAnalyzer.new(project_path).analyze
45
+ @results[:bdd] = RailsArchitect::Analyzers::BddAnalyzer.new(project_path).analyze
46
+ @results[:solid] = RailsArchitect::Analyzers::SolidAnalyzer.new(project_path).analyze
47
+ end
48
+
49
+ def generate_report
50
+ RailsArchitect::Reporters::ReportGenerator.new(@results).generate
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "rails_architect/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "rails_architect_analyzer"
9
+ spec.version = RailsArchitect::VERSION
10
+ spec.authors = ["Daniel Matos"]
11
+ spec.email = ["eu@danieldjam.dev.br", "danielmatos404@gmail.com"]
12
+
13
+ spec.summary = "Analyze Rails projects for architecture, TDD, BDD, and SOLID principles"
14
+ spec.description = "A gem that analyzes your Rails project structure and suggests improvements " \
15
+ "based on architecture best practices, TDD, BDD, and SOLID principles."
16
+ spec.homepage = "https://github.com/8486/rails_architect"
17
+ spec.license = "MIT"
18
+ spec.required_ruby_version = ">= 3.3.0"
19
+
20
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_dependency "ast", "~> 2.4"
28
+ spec.add_dependency "colorize", "~> 0.8"
29
+ spec.add_dependency "parser", "~> 3.1"
30
+ spec.add_dependency "rails", ">= 6.0"
31
+ spec.add_dependency "thor", "~> 1.2"
32
+
33
+ spec.metadata["rubygems_mfa_required"] = "true"
34
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_architect_analyzer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Matos
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ast
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.4'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.4'
26
+ - !ruby/object:Gem::Dependency
27
+ name: colorize
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '0.8'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.8'
40
+ - !ruby/object:Gem::Dependency
41
+ name: parser
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.1'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.1'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rails
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '6.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '6.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: thor
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.2'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.2'
82
+ description: A gem that analyzes your Rails project structure and suggests improvements
83
+ based on architecture best practices, TDD, BDD, and SOLID principles.
84
+ email:
85
+ - eu@danieldjam.dev.br
86
+ - danielmatos404@gmail.com
87
+ executables:
88
+ - rails_architect
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".github/workflows/tests.yml"
93
+ - ".gitignore"
94
+ - ".rubocop.yml"
95
+ - CHANGELOG.md
96
+ - CODE_OF_CONDUCT.md
97
+ - CONTRIBUTING.md
98
+ - EXAMPLE_GEMFILE
99
+ - Gemfile
100
+ - INDEX.md
101
+ - LICENSE.md
102
+ - README.md
103
+ - Rakefile
104
+ - exe/rails_architect
105
+ - lib/rails_architect.rb
106
+ - lib/rails_architect/analyzers/architecture_analyzer.rb
107
+ - lib/rails_architect/analyzers/bdd_analyzer.rb
108
+ - lib/rails_architect/analyzers/solid_analyzer.rb
109
+ - lib/rails_architect/analyzers/tdd_analyzer.rb
110
+ - lib/rails_architect/cli.rb
111
+ - lib/rails_architect/reporters/report_generator.rb
112
+ - lib/rails_architect/version.rb
113
+ - rails_architect.gemspec
114
+ homepage: https://github.com/8486/rails_architect
115
+ licenses:
116
+ - MIT
117
+ metadata:
118
+ rubygems_mfa_required: 'true'
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: 3.3.0
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubygems_version: 3.6.8
134
+ specification_version: 4
135
+ summary: Analyze Rails projects for architecture, TDD, BDD, and SOLID principles
136
+ test_files: []