railsforge 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 (73) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +528 -0
  4. data/bin/railsforge +8 -0
  5. data/lib/railsforge/analyzers/base_analyzer.rb +41 -0
  6. data/lib/railsforge/analyzers/controller_analyzer.rb +83 -0
  7. data/lib/railsforge/analyzers/database_analyzer.rb +55 -0
  8. data/lib/railsforge/analyzers/metrics_analyzer.rb +55 -0
  9. data/lib/railsforge/analyzers/model_analyzer.rb +74 -0
  10. data/lib/railsforge/analyzers/performance_analyzer.rb +161 -0
  11. data/lib/railsforge/analyzers/refactor_analyzer.rb +118 -0
  12. data/lib/railsforge/analyzers/security_analyzer.rb +169 -0
  13. data/lib/railsforge/analyzers/spec_analyzer.rb +58 -0
  14. data/lib/railsforge/api_generator.rb +397 -0
  15. data/lib/railsforge/audit.rb +289 -0
  16. data/lib/railsforge/cli.rb +671 -0
  17. data/lib/railsforge/config.rb +181 -0
  18. data/lib/railsforge/database_analyzer.rb +300 -0
  19. data/lib/railsforge/doctor.rb +250 -0
  20. data/lib/railsforge/feature_generator.rb +560 -0
  21. data/lib/railsforge/generator.rb +313 -0
  22. data/lib/railsforge/generators/base_generator.rb +70 -0
  23. data/lib/railsforge/generators/demo_generator.rb +307 -0
  24. data/lib/railsforge/generators/devops_generator.rb +287 -0
  25. data/lib/railsforge/generators/monitoring_generator.rb +134 -0
  26. data/lib/railsforge/generators/service_generator.rb +122 -0
  27. data/lib/railsforge/generators/stimulus_controller_generator.rb +129 -0
  28. data/lib/railsforge/generators/test_generator.rb +289 -0
  29. data/lib/railsforge/generators/view_component_generator.rb +169 -0
  30. data/lib/railsforge/graph.rb +270 -0
  31. data/lib/railsforge/loader.rb +56 -0
  32. data/lib/railsforge/mailer_generator.rb +191 -0
  33. data/lib/railsforge/plugins/plugin_loader.rb +60 -0
  34. data/lib/railsforge/plugins.rb +30 -0
  35. data/lib/railsforge/profiles/admin_app.yml +49 -0
  36. data/lib/railsforge/profiles/api_only.yml +47 -0
  37. data/lib/railsforge/profiles/blog.yml +47 -0
  38. data/lib/railsforge/profiles/standard.yml +44 -0
  39. data/lib/railsforge/profiles.rb +99 -0
  40. data/lib/railsforge/refactor_analyzer.rb +401 -0
  41. data/lib/railsforge/refactor_controller.rb +277 -0
  42. data/lib/railsforge/refactors/refactor_controller.rb +117 -0
  43. data/lib/railsforge/template_loader.rb +105 -0
  44. data/lib/railsforge/templates/v1/form/spec_template.rb +18 -0
  45. data/lib/railsforge/templates/v1/form/template.rb +28 -0
  46. data/lib/railsforge/templates/v1/job/spec_template.rb +17 -0
  47. data/lib/railsforge/templates/v1/job/template.rb +13 -0
  48. data/lib/railsforge/templates/v1/policy/spec_template.rb +41 -0
  49. data/lib/railsforge/templates/v1/policy/template.rb +57 -0
  50. data/lib/railsforge/templates/v1/presenter/spec_template.rb +12 -0
  51. data/lib/railsforge/templates/v1/presenter/template.rb +13 -0
  52. data/lib/railsforge/templates/v1/query/spec_template.rb +12 -0
  53. data/lib/railsforge/templates/v1/query/template.rb +16 -0
  54. data/lib/railsforge/templates/v1/serializer/spec_template.rb +13 -0
  55. data/lib/railsforge/templates/v1/serializer/template.rb +11 -0
  56. data/lib/railsforge/templates/v1/service/spec_template.rb +12 -0
  57. data/lib/railsforge/templates/v1/service/template.rb +25 -0
  58. data/lib/railsforge/templates/v1/stimulus_controller/template.rb +35 -0
  59. data/lib/railsforge/templates/v1/view_component/template.rb +24 -0
  60. data/lib/railsforge/templates/v2/job/template.rb +49 -0
  61. data/lib/railsforge/templates/v2/query/template.rb +66 -0
  62. data/lib/railsforge/templates/v2/service/spec_template.rb +33 -0
  63. data/lib/railsforge/templates/v2/service/template.rb +71 -0
  64. data/lib/railsforge/templates/v3/job/template.rb +72 -0
  65. data/lib/railsforge/templates/v3/query/spec_template.rb +54 -0
  66. data/lib/railsforge/templates/v3/query/template.rb +115 -0
  67. data/lib/railsforge/templates/v3/service/spec_template.rb +51 -0
  68. data/lib/railsforge/templates/v3/service/template.rb +84 -0
  69. data/lib/railsforge/version.rb +5 -0
  70. data/lib/railsforge/wizard.rb +265 -0
  71. data/lib/railsforge/wizard_tui.rb +286 -0
  72. data/lib/railsforge.rb +13 -0
  73. metadata +216 -0
@@ -0,0 +1,84 @@
1
+ # Service class template v3
2
+ # Advanced service with result monad and chaining
3
+ class <%= class_name %>
4
+ include Dry::Monads[:result, :do]
5
+
6
+ # Initialize with dependencies
7
+ # @param [Hash] params - Parameters for the service
8
+ def initialize(params = {})
9
+ @params = params
10
+ @dependencies = {}
11
+ end
12
+
13
+ # Register a dependency
14
+ # @param [Symbol] key - Dependency key
15
+ # @param [Object] value - Dependency value
16
+ def register(key, value)
17
+ @dependencies[key] = value
18
+ self
19
+ end
20
+
21
+ # Execute the service - returns a Dry::Monads Result
22
+ def call
23
+ yield validate!
24
+ yield process!
25
+ Success(result_data)
26
+ rescue StandardError => e
27
+ Failure(error: e.message, code: :unexpected_error)
28
+ end
29
+
30
+ # Chain another service
31
+ # @param [Class] service_class - Next service to call
32
+ # @param [Hash] params - Parameters for next service
33
+ def then(service_class, params = {})
34
+ result = call
35
+ return result unless result.success?
36
+
37
+ service = service_class.new(@params.merge(params)).call
38
+ service
39
+ end
40
+
41
+ # Class-level call
42
+ def self.call(params = {})
43
+ new(params).call
44
+ end
45
+
46
+ private
47
+
48
+ # Validate inputs - returns Result
49
+ def validate!
50
+ # TODO: Add validation logic
51
+ # Example:
52
+ # return Failure(errors: ['Name required']) if @params[:name].blank?
53
+ Success(true)
54
+ end
55
+
56
+ # Process the main logic - returns Result
57
+ def process!
58
+ # TODO: Implement service logic
59
+ @result = {}
60
+ Success(true)
61
+ end
62
+
63
+ # Build result data
64
+ def result_data
65
+ {
66
+ data: @result,
67
+ metadata: {
68
+ service: self.class.name,
69
+ timestamp: Time.now.utc.iso8601
70
+ }
71
+ }
72
+ end
73
+ end
74
+
75
+ # Result wrapper for success/failure
76
+ module Result
77
+ def self.success(data)
78
+ { success: true, data: data }
79
+ end
80
+
81
+ def self.failure(errors)
82
+ { success: false, errors: errors }
83
+ end
84
+ end
@@ -0,0 +1,5 @@
1
+ # Version module for RailsForge gem
2
+ # Defines the current version of the gem
3
+ module RailsForge
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,265 @@
1
+ # Wizard module for RailsForge
2
+ # Interactive project scaffolding
3
+
4
+ require 'fileutils'
5
+
6
+ module RailsForge
7
+ # Wizard class provides interactive project setup
8
+ class Wizard
9
+ # Project types available
10
+ PROJECT_TYPES = {
11
+ "saas" => {
12
+ name: "SaaS Application",
13
+ description: "Full-featured SaaS with auth, admin, payments",
14
+ features: %w[authentication admin background_jobs]
15
+ },
16
+ "blog" => {
17
+ name: "Blog",
18
+ description: "Content blog with articles and comments",
19
+ features: %w[authentication comments]
20
+ },
21
+ "api" => {
22
+ name: "API Only",
23
+ description: "RESTful API with JWT authentication",
24
+ features: %w[jwt_auth background_jobs]
25
+ },
26
+ "admin_app" => {
27
+ name: "Admin Dashboard",
28
+ description: "Admin panel with CRUD operations",
29
+ features: %w[authentication admin]
30
+ },
31
+ "standard" => {
32
+ name: "Standard Rails",
33
+ description: "Basic Rails application",
34
+ features: []
35
+ }
36
+ }.freeze
37
+
38
+ # Initialize wizard
39
+ def initialize
40
+ @options = {
41
+ project_name: nil,
42
+ project_type: nil,
43
+ features: [],
44
+ generators: [],
45
+ analyze_after: false
46
+ }
47
+ end
48
+
49
+ # Run the interactive wizard
50
+ # @return [Hash] Selected options
51
+ def run
52
+ puts ""
53
+ puts "=" * 60
54
+ puts "RailsForge Project Wizard"
55
+ puts "=" * 60
56
+ puts ""
57
+
58
+ # Step 1: Project name
59
+ ask_project_name
60
+
61
+ # Step 2: Project type
62
+ ask_project_type
63
+
64
+ # Step 3: Features
65
+ ask_features
66
+
67
+ # Step 4: Generators
68
+ ask_generators
69
+
70
+ # Step 5: Analysis
71
+ ask_analysis
72
+
73
+ # Summary
74
+ show_summary
75
+
76
+ @options
77
+ end
78
+
79
+ # Execute the wizard choices
80
+ def execute
81
+ return unless @options[:project_name]
82
+
83
+ puts ""
84
+ puts "Creating Rails app: #{@options[:project_name]}"
85
+ puts ""
86
+
87
+ # Build options for RailsForge::Generator
88
+ generator_options = {
89
+ profile: @options[:project_type]
90
+ }
91
+
92
+ # Add features
93
+ generator_options[:auth] = "devise" if @options[:features].include?("authentication")
94
+ generator_options[:admin] = "activeadmin" if @options[:features].include?("admin")
95
+ generator_options[:jobs] = "sidekiq" if @options[:features].include?("background_jobs")
96
+
97
+ begin
98
+ # Create the Rails app
99
+ result = RailsForge::Generator.create_app(@options[:project_name], generator_options)
100
+ puts result
101
+ puts ""
102
+
103
+ # Run selected generators
104
+ run_generators if @options[:generators].any?
105
+
106
+ # Run analysis if requested
107
+ run_analysis if @options[:analyze_after]
108
+
109
+ puts ""
110
+ puts "✓ Project created successfully!"
111
+ rescue => e
112
+ puts "Error: #{e.message}"
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ # Ask for project name
119
+ def ask_project_name
120
+ print "Enter project name: "
121
+ name = STDIN.gets.strip
122
+
123
+ if name.empty?
124
+ puts "Please enter a valid project name"
125
+ ask_project_name
126
+ elsif name =~ /\A\d/ || name =~ /\s/
127
+ puts "Project name cannot start with a number or contain spaces"
128
+ ask_project_name
129
+ else
130
+ @options[:project_name] = name
131
+ end
132
+ end
133
+
134
+ # Ask for project type
135
+ def ask_project_type
136
+ puts ""
137
+ puts "Select project type:"
138
+ puts ""
139
+
140
+ PROJECT_TYPES.each do |key, type|
141
+ puts " #{key.ljust(12)} - #{type[:name]}"
142
+ puts " #{type[:description]}"
143
+ puts ""
144
+ end
145
+
146
+ print "Enter type (default: standard): "
147
+ type = STDIN.gets.strip.downcase
148
+
149
+ if type.empty?
150
+ @options[:project_type] = "standard"
151
+ elsif PROJECT_TYPES.key?(type)
152
+ @options[:project_type] = type
153
+ @options[:features] = PROJECT_TYPES[type][:features].dup
154
+ else
155
+ puts "Invalid project type"
156
+ ask_project_type
157
+ end
158
+ end
159
+
160
+ # Ask for additional features
161
+ def ask_features
162
+ puts ""
163
+ puts "Select additional features (comma-separated, or 'done'):"
164
+ puts ""
165
+
166
+ available_features = [
167
+ ["authentication", "User authentication (Devise)"],
168
+ ["admin", "Admin panel (ActiveAdmin)"],
169
+ ["background_jobs", "Background jobs (Sidekiq)"],
170
+ ["api", "REST API endpoints"],
171
+ ["comments", "Comment system"],
172
+ ["notifications", "Email/push notifications"],
173
+ ["payments", "Payment integration (Stripe)"],
174
+ ["uploads", "File uploads (Carrierwave/ActiveStorage)"]
175
+ ]
176
+
177
+ available_features.each do |key, desc|
178
+ included = @options[:features].include?(key) ? " ✓" : ""
179
+ puts " #{key.ljust(20)} - #{desc}#{included}"
180
+ end
181
+ puts ""
182
+
183
+ print "Features (or 'done' to continue): "
184
+ features_input = STDIN.gets.strip.downcase
185
+
186
+ if features_input != "done"
187
+ selected = features_input.split(",").map(&:strip).reject(&:empty?)
188
+ @options[:features] = (@options[:features] + selected).uniq
189
+ end
190
+ end
191
+
192
+ # Ask which generators to run
193
+ def ask_generators
194
+ puts ""
195
+ puts "Select generators to run after creation (comma-separated, or 'none'):"
196
+ puts ""
197
+
198
+ available_generators = [
199
+ ["scaffold", "Full scaffold (model, controller, views)"],
200
+ ["resource", "API resource only"],
201
+ ["service", "Example service object"],
202
+ ["job", "Example background job"]
203
+ ]
204
+
205
+ available_generators.each do |key, desc|
206
+ puts " #{key.ljust(12)} - #{desc}"
207
+ end
208
+ puts ""
209
+
210
+ print "Generators (or 'none'): "
211
+ generators_input = STDIN.gets.strip.downcase
212
+
213
+ if generators_input != "none" && !generators_input.empty?
214
+ @options[:generators] = generators_input.split(",").map(&:strip).reject(&:empty?)
215
+ end
216
+ end
217
+
218
+ # Ask whether to run analysis
219
+ def ask_analysis
220
+ puts ""
221
+ print "Run architecture analysis after creation? (y/N): "
222
+ answer = STDIN.gets.strip.downcase
223
+
224
+ @options[:analyze_after] = answer == "y" || answer == "yes"
225
+ end
226
+
227
+ # Show summary of choices
228
+ def show_summary
229
+ puts ""
230
+ puts "-" * 40
231
+ puts "Summary:"
232
+ puts " Project: #{@options[:project_name]}"
233
+ puts " Type: #{@options[:project_type]} (#{PROJECT_TYPES[@options[:project_type]][:name]})"
234
+ puts " Features: #{@options[:features].join(', ')}"
235
+ puts " Generators: #{@options[:generators].join(', ')}"
236
+ puts " Analyze: #{@options[:analyze_after] ? 'Yes' : 'No'}"
237
+ puts "-" * 40
238
+ end
239
+
240
+ # Run selected generators
241
+ def run_generators
242
+ puts ""
243
+ puts "Running generators..."
244
+
245
+ Dir.chdir(@options[:project_name]) do
246
+ @options[:generators].each do |generator|
247
+ puts " Running #{generator} generator..."
248
+ # In a full implementation, this would run the actual generators
249
+ end
250
+ end
251
+ end
252
+
253
+ # Run analysis
254
+ def run_analysis
255
+ puts ""
256
+ puts "Running architecture analysis..."
257
+
258
+ Dir.chdir(@options[:project_name]) do
259
+ # Run the doctor
260
+ doctor = RailsForge::Doctor.new
261
+ doctor.run
262
+ end
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,286 @@
1
+ # WizardTUI - Menu-driven interactive terminal interface for RailsForge
2
+ # Uses TTY::Prompt for interactive menus
3
+
4
+ module RailsForge
5
+ # WizardTUI - Interactive TUI wizard
6
+ class WizardTUI
7
+ # Available project types mapped to profiles
8
+ PROJECT_TYPES = {
9
+ "standard" => { name: "Standard", description: "Basic Rails application", profile: "standard" },
10
+ "blog" => { name: "Blog", description: "Content blog with articles and comments", profile: "blog" },
11
+ "admin_app" => { name: "Admin App", description: "Admin dashboard with CRUD operations", profile: "admin_app" },
12
+ "api_only" => { name: "API-Only", description: "RESTful API with JWT authentication", profile: "api_only" },
13
+ "saas" => { name: "SaaS", description: "Full-featured SaaS with auth, admin, payments", profile: "standard" }
14
+ }.freeze
15
+
16
+ # Available features/generators
17
+ AVAILABLE_FEATURES = %w[
18
+ services queries jobs forms presenters policies serializers
19
+ mailers features apis components stimulus
20
+ ].freeze
21
+
22
+ # Available analyzers
23
+ AVAILABLE_ANALYZERS = %w[
24
+ controllers models specs database metrics
25
+ security performance
26
+ ].freeze
27
+
28
+ # Initialize wizard
29
+ def initialize
30
+ # Lazy-load TTY dependencies
31
+ require 'tty-prompt'
32
+ require 'tty-table'
33
+
34
+ @prompt = TTY::Prompt.new
35
+ @options = {
36
+ project_name: nil,
37
+ project_type: nil,
38
+ template_version: nil,
39
+ features: [],
40
+ analyzers: [],
41
+ dry_run: false
42
+ }
43
+ end
44
+
45
+ # Main execution method
46
+ def run
47
+ puts ""
48
+ puts "🚀 Welcome to RailsForge Wizard!".color(:green)
49
+ puts "=" * 50
50
+ puts ""
51
+
52
+ # Step 1: Project name
53
+ ask_project_name
54
+
55
+ # Step 2: Project type
56
+ select_project_type
57
+
58
+ # Step 3: Template version
59
+ select_template_version
60
+
61
+ # Step 4: Features
62
+ select_features
63
+
64
+ # Step 5: Analyzers
65
+ select_analyzers
66
+
67
+ # Step 6: Dry-run option
68
+ ask_dry_run
69
+
70
+ # Step 7: Summary and confirmation
71
+ confirm_and_run
72
+ end
73
+
74
+ private
75
+
76
+ # Ask for project name
77
+ def ask_project_name
78
+ @options[:project_name] = @prompt.ask("Project name:") do |q|
79
+ q.required true
80
+ q.validate(/^[a-z][a-z0-9_]*$/i, "Must be valid Ruby identifier (letters, numbers, underscores)")
81
+ q.modify :strip
82
+ end
83
+ end
84
+
85
+ # Select project type
86
+ def select_project_type
87
+ choices = PROJECT_TYPES.map do |key, value|
88
+ { name: "#{value[:name]} - #{value[:description]}", value: key }
89
+ end
90
+
91
+ @options[:project_type] = @prompt.select("Select project type:", choices, default: "standard")
92
+ end
93
+
94
+ # Select template version
95
+ def select_template_version
96
+ versions = detect_template_versions
97
+
98
+ # Check for default in config
99
+ default_version = RailsForge::Config.get("generators.default_template_version") rescue "v1"
100
+
101
+ choices = versions.map { |v| { name: "Version #{v}", value: v } }
102
+ @options[:template_version] = @prompt.select("Select template version:", choices, default: default_version)
103
+ end
104
+
105
+ # Detect available template versions
106
+ def detect_template_versions
107
+ templates_dir = File.expand_path("../templates", __FILE__)
108
+ return ["v1"] unless Dir.exist?(templates_dir)
109
+
110
+ Dir.glob(File.join(templates_dir, "v*")).map do |dir|
111
+ File.basename(dir)
112
+ end.sort
113
+ end
114
+
115
+ # Select features
116
+ def select_features
117
+ feature_descriptions = {
118
+ "services" => "Service objects for business logic",
119
+ "queries" => "Query objects for database queries",
120
+ "jobs" => "Background jobs",
121
+ "forms" => "Form objects",
122
+ "presenters" => "Presenter objects",
123
+ "policies" => "Policy objects",
124
+ "serializers" => "Serializer objects",
125
+ "mailers" => "Mailer classes",
126
+ "features" => "Feature specs",
127
+ "apis" => "API resources",
128
+ "components" => "ViewComponent components",
129
+ "stimulus" => "Stimulus controllers"
130
+ }
131
+
132
+ choices = AVAILABLE_FEATURES.map do |f|
133
+ { name: "#{f.capitalize.ljust(15)} - #{feature_descriptions[f]}", value: f }
134
+ end
135
+
136
+ @options[:features] = @prompt.multi_select("Select features to include:", choices, min: 0)
137
+ end
138
+
139
+ # Select analyzers
140
+ def select_analyzers
141
+ analyzer_descriptions = {
142
+ "controllers" => "Analyze controllers for issues",
143
+ "models" => "Analyze models for issues",
144
+ "specs" => "Check spec coverage",
145
+ "database" => "Check database schema",
146
+ "metrics" => "Code metrics analysis",
147
+ "security" => "Security vulnerability scan",
148
+ "performance" => "Performance issue detection"
149
+ }
150
+
151
+ choices = AVAILABLE_ANALYZERS.map do |a|
152
+ { name: "#{a.capitalize.ljust(15)} - #{analyzer_descriptions[a]}", value: a }
153
+ end
154
+
155
+ # Add "Run All" option
156
+ all_choice = { name: "Run All Analyzers", value: "all" }
157
+ choices.unshift(all_choice)
158
+
159
+ selected = @prompt.multi_select("Select analyzers to run after generation:", choices, min: 0)
160
+
161
+ # Handle "all" selection
162
+ @options[:analyzers] = selected.include?("all") ? AVAILABLE_ANALYZERS.dup : selected
163
+ end
164
+
165
+ # Ask for dry-run
166
+ def ask_dry_run
167
+ @options[:dry_run] = @prompt.yes?("Preview files without creating?")
168
+ end
169
+
170
+ # Display summary and confirm
171
+ def confirm_and_run
172
+ puts ""
173
+ puts "📋 Summary".color(:cyan)
174
+ puts "-" * 40
175
+ puts "Project: #{@options[:project_name]}"
176
+ puts "Type: #{PROJECT_TYPES[@options[:project_type]][:name]}"
177
+ puts "Template: #{@options[:template_version]}"
178
+ puts "Features: #{@options[:features].join(', ')}"
179
+ puts "Analyzers: #{@options[:analyzers].join(', ')}"
180
+ puts "Dry-run: #{@options[:dry_run] ? 'Yes' : 'No'}"
181
+ puts "-" * 40
182
+
183
+ confirmed = @prompt.yes?("Proceed with generation?")
184
+
185
+ if confirmed
186
+ execute
187
+ else
188
+ puts "Cancelled.".color(:yellow)
189
+ end
190
+ end
191
+
192
+ # Execute the wizard choices
193
+ def execute
194
+ puts ""
195
+ puts "� Generating Rails app...".color(:green)
196
+
197
+ if @options[:dry_run]
198
+ dry_run_output
199
+ else
200
+ run_generation
201
+ run_analyzers
202
+ print_results
203
+ end
204
+ end
205
+
206
+ # Dry-run output
207
+ def dry_run_output
208
+ puts ""
209
+ puts "🔍 Dry-run mode - Preview of files to generate".color(:yellow)
210
+ puts ""
211
+
212
+ # Show what would be created
213
+ puts "Profile: #{@options[:project_type]}"
214
+ puts "Template version: #{@options[:template_version]}"
215
+ puts ""
216
+ puts "Features to generate:"
217
+ @options[:features].each { |f| puts " - #{f}" }
218
+ puts ""
219
+ puts "Analyzers to run:"
220
+ @options[:analyzers].each { |a| puts " - #{a}" }
221
+ end
222
+
223
+ # Run the actual generation
224
+ def run_generation
225
+ # Apply profile
226
+ profile = RailsForge::Profile.load(@options[:project_type])
227
+ RailsForge::Profile.create_folders(@options[:project_name], profile)
228
+
229
+ # Run selected generators
230
+ @options[:features].each do |feature|
231
+ puts " Running #{feature} generator..."
232
+ # Note: In a full implementation, this would run the actual generators
233
+ end
234
+ end
235
+
236
+ # Run selected analyzers
237
+ def run_analyzers
238
+ return if @options[:analyzers].empty?
239
+
240
+ puts ""
241
+ puts "🔍 Running analyzers...".color(:cyan)
242
+
243
+ @options[:analyzers].each do |analyzer|
244
+ puts " Running #{analyzer} analyzer..."
245
+ case analyzer
246
+ when "controllers"
247
+ results = RailsForge::Analyzers::ControllerAnalyzer.analyze
248
+ RailsForge::Analyzers::ControllerAnalyzer.print_results(results)
249
+ when "models"
250
+ results = RailsForge::Analyzers::ModelAnalyzer.analyze
251
+ RailsForge::Analyzers::ModelAnalyzer.print_results(results)
252
+ when "specs"
253
+ results = RailsForge::Analyzers::SpecAnalyzer.analyze
254
+ RailsForge::Analyzers::SpecAnalyzer.print_results(results)
255
+ when "database"
256
+ results = RailsForge::Analyzers::DatabaseAnalyzer.analyze
257
+ RailsForge::Analyzers::DatabaseAnalyzer.print_report(results)
258
+ when "metrics"
259
+ results = RailsForge::Analyzers::MetricsAnalyzer.analyze
260
+ RailsForge::Analyzers::MetricsAnalyzer.print_results(results)
261
+ when "security"
262
+ results = RailsForge::Analyzers::SecurityAnalyzer.analyze
263
+ RailsForge::Analyzers::SecurityAnalyzer.print_report(results)
264
+ when "performance"
265
+ results = RailsForge::Analyzers::PerformanceAnalyzer.analyze
266
+ RailsForge::Analyzers::PerformanceAnalyzer.print_report(results)
267
+ end
268
+ end
269
+ end
270
+
271
+ # Print final results
272
+ def print_results
273
+ puts ""
274
+ puts "✅ Generation complete!".color(:green)
275
+ puts ""
276
+ puts "Project '#{@options[:project_name]}' created successfully!"
277
+ end
278
+ end
279
+ end
280
+
281
+ # Add color support for String class
282
+ class String
283
+ def color(color_code)
284
+ "\e[#{color_code}m#{self}\e[0m"
285
+ end
286
+ end
data/lib/railsforge.rb ADDED
@@ -0,0 +1,13 @@
1
+ # RailsForge gem entry point
2
+ # This file is the main entry point for the gem
3
+
4
+ require_relative "railsforge/loader"
5
+
6
+ # The main RailsForge module is defined in loader.rb
7
+ # This file exists for backward compatibility
8
+ module RailsForge
9
+ # Greeting method - kept for compatibility
10
+ def self.greet
11
+ "Welcome to RailsForge #{VERSION}!"
12
+ end
13
+ end