railsforge 1.0.2 → 2.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +105 -444
  3. data/lib/railsforge/analyzers/controller_analyzer.rb +29 -55
  4. data/lib/railsforge/analyzers/database_analyzer.rb +16 -30
  5. data/lib/railsforge/analyzers/metrics_analyzer.rb +8 -22
  6. data/lib/railsforge/analyzers/model_analyzer.rb +29 -46
  7. data/lib/railsforge/analyzers/performance_analyzer.rb +34 -94
  8. data/lib/railsforge/analyzers/refactor_analyzer.rb +77 -57
  9. data/lib/railsforge/analyzers/security_analyzer.rb +34 -91
  10. data/lib/railsforge/analyzers/spec_analyzer.rb +17 -31
  11. data/lib/railsforge/cli.rb +14 -650
  12. data/lib/railsforge/cli_minimal.rb +8 -55
  13. data/lib/railsforge/doctor.rb +52 -225
  14. data/lib/railsforge/formatter.rb +102 -0
  15. data/lib/railsforge/issue.rb +23 -0
  16. data/lib/railsforge/loader.rb +4 -64
  17. data/lib/railsforge/version.rb +1 -1
  18. metadata +14 -82
  19. data/lib/railsforge/api_generator.rb +0 -397
  20. data/lib/railsforge/audit.rb +0 -289
  21. data/lib/railsforge/config.rb +0 -181
  22. data/lib/railsforge/database_analyzer.rb +0 -300
  23. data/lib/railsforge/feature_generator.rb +0 -560
  24. data/lib/railsforge/generator.rb +0 -313
  25. data/lib/railsforge/generators/api_generator.rb +0 -392
  26. data/lib/railsforge/generators/base_generator.rb +0 -75
  27. data/lib/railsforge/generators/demo_generator.rb +0 -307
  28. data/lib/railsforge/generators/devops_generator.rb +0 -287
  29. data/lib/railsforge/generators/form_generator.rb +0 -180
  30. data/lib/railsforge/generators/job_generator.rb +0 -176
  31. data/lib/railsforge/generators/monitoring_generator.rb +0 -134
  32. data/lib/railsforge/generators/policy_generator.rb +0 -220
  33. data/lib/railsforge/generators/presenter_generator.rb +0 -173
  34. data/lib/railsforge/generators/query_generator.rb +0 -174
  35. data/lib/railsforge/generators/serializer_generator.rb +0 -166
  36. data/lib/railsforge/generators/service_generator.rb +0 -122
  37. data/lib/railsforge/generators/stimulus_controller_generator.rb +0 -129
  38. data/lib/railsforge/generators/test_generator.rb +0 -289
  39. data/lib/railsforge/generators/view_component_generator.rb +0 -169
  40. data/lib/railsforge/graph.rb +0 -270
  41. data/lib/railsforge/mailer_generator.rb +0 -191
  42. data/lib/railsforge/plugins/plugin_loader.rb +0 -60
  43. data/lib/railsforge/plugins.rb +0 -30
  44. data/lib/railsforge/profiles.rb +0 -99
  45. data/lib/railsforge/refactor_analyzer.rb +0 -401
  46. data/lib/railsforge/refactor_controller.rb +0 -277
  47. data/lib/railsforge/refactors/refactor_controller.rb +0 -117
  48. data/lib/railsforge/template_loader.rb +0 -105
  49. data/lib/railsforge/templates/v1/form/spec_template.rb +0 -18
  50. data/lib/railsforge/templates/v1/form/template.rb +0 -28
  51. data/lib/railsforge/templates/v1/job/spec_template.rb +0 -17
  52. data/lib/railsforge/templates/v1/job/template.rb +0 -13
  53. data/lib/railsforge/templates/v1/policy/spec_template.rb +0 -41
  54. data/lib/railsforge/templates/v1/policy/template.rb +0 -57
  55. data/lib/railsforge/templates/v1/presenter/spec_template.rb +0 -12
  56. data/lib/railsforge/templates/v1/presenter/template.rb +0 -13
  57. data/lib/railsforge/templates/v1/query/spec_template.rb +0 -12
  58. data/lib/railsforge/templates/v1/query/template.rb +0 -16
  59. data/lib/railsforge/templates/v1/serializer/spec_template.rb +0 -13
  60. data/lib/railsforge/templates/v1/serializer/template.rb +0 -11
  61. data/lib/railsforge/templates/v1/service/spec_template.rb +0 -12
  62. data/lib/railsforge/templates/v1/service/template.rb +0 -25
  63. data/lib/railsforge/templates/v1/stimulus_controller/template.rb +0 -35
  64. data/lib/railsforge/templates/v1/view_component/template.rb +0 -24
  65. data/lib/railsforge/templates/v2/job/template.rb +0 -49
  66. data/lib/railsforge/templates/v2/query/template.rb +0 -66
  67. data/lib/railsforge/templates/v2/service/spec_template.rb +0 -33
  68. data/lib/railsforge/templates/v2/service/template.rb +0 -71
  69. data/lib/railsforge/templates/v3/job/template.rb +0 -72
  70. data/lib/railsforge/templates/v3/query/spec_template.rb +0 -54
  71. data/lib/railsforge/templates/v3/query/template.rb +0 -115
  72. data/lib/railsforge/templates/v3/service/spec_template.rb +0 -51
  73. data/lib/railsforge/templates/v3/service/template.rb +0 -93
  74. data/lib/railsforge/wizard.rb +0 -265
  75. data/lib/railsforge/wizard_tui.rb +0 -286
@@ -1,173 +0,0 @@
1
- # Presenter generator for RailsForge
2
- # Generates presenter object files
3
-
4
- require_relative 'base_generator'
5
-
6
- module RailsForge
7
- module Generators
8
- # PresenterGenerator creates presenter files
9
- class PresenterGenerator < BaseGenerator
10
- # Error class for invalid presenter names
11
- class InvalidPresenterNameError < StandardError; end
12
-
13
- # Template version
14
- TEMPLATE_VERSION = "v1"
15
-
16
- # Initialize the generator
17
- # @param name [String] Presenter name
18
- # @param options [Hash] Generator options
19
- def initialize(name, options = {})
20
- super(name, options)
21
- @template_version = options[:template_version] || TEMPLATE_VERSION
22
- @with_spec = options.fetch(:with_spec, true)
23
- end
24
-
25
- # Generate presenter files
26
- # @return [String] Success message
27
- def generate
28
- return "Not in a Rails application directory" unless @base_path
29
-
30
- validate_name!(@name)
31
-
32
- results = []
33
- results << generate_presenter
34
-
35
- if @with_spec
36
- results << generate_spec
37
- end
38
-
39
- "Presenter '#{@name}' generated successfully!\n" + results.join("\n")
40
- end
41
-
42
- # Class method for CLI
43
- def self.generate(presenter_name, with_spec: true, template_version: "v1")
44
- new(presenter_name, with_spec: with_spec, template_version: template_version).generate
45
- end
46
-
47
- private
48
-
49
- # Validate presenter name
50
- def validate_name!(name)
51
- raise InvalidPresenterNameError, "Presenter name cannot be empty" if name.nil? || name.strip.empty?
52
- raise InvalidPresenterNameError, "Name must match pattern: /\\A[A-Z][a-zA-Z0-9]*\\z/" unless name =~ /\A[A-Z][a-zA-Z0-9]*\z/
53
- end
54
-
55
- # Generate presenter file
56
- def generate_presenter
57
- presenter_dir = File.join(@base_path, "app", "presenters")
58
- FileUtils.mkdir_p(presenter_dir)
59
-
60
- file_name = "#{underscore}_presenter.rb"
61
- file_path = File.join(presenter_dir, file_name)
62
-
63
- return " Skipping presenter (already exists)" if File.exist?(file_path)
64
-
65
- content = load_template
66
- content = apply_template(content)
67
-
68
- File.write(file_path, content)
69
- " Created app/presenters/#{file_name}"
70
- end
71
-
72
- # Generate spec file
73
- def generate_spec
74
- spec_dir = File.join(@base_path, "spec", "presenters")
75
- FileUtils.mkdir_p(spec_dir)
76
-
77
- file_name = "#{underscore}_presenter_spec.rb"
78
- file_path = File.join(spec_dir, file_name)
79
-
80
- return " Skipping spec (already exists)" if File.exist?(file_path)
81
-
82
- content = load_spec_template
83
- content = apply_template(content)
84
-
85
- File.write(file_path, content)
86
- " Created spec/presenters/#{file_name}"
87
- end
88
-
89
- # Load template content
90
- def load_template
91
- template_path = File.join(
92
- File.dirname(__FILE__),
93
- "..",
94
- "templates",
95
- @template_version,
96
- "presenter",
97
- "template.rb"
98
- )
99
-
100
- if File.exist?(template_path)
101
- File.read(template_path)
102
- else
103
- default_template
104
- end
105
- end
106
-
107
- # Load spec template
108
- def load_spec_template
109
- spec_path = File.join(
110
- File.dirname(__FILE__),
111
- "..",
112
- "templates",
113
- @template_version,
114
- "presenter",
115
- "spec_template.rb"
116
- )
117
-
118
- if File.exist?(spec_path)
119
- File.read(spec_path)
120
- else
121
- default_spec_template
122
- end
123
- end
124
-
125
- # Default template
126
- def default_template
127
- <<~RUBY
128
- # Presenter class for #{underscore}
129
- # Encapsulates view logic
130
- class #{camelize}Presenter
131
- def initialize(object)
132
- @object = object
133
- end
134
-
135
- def title
136
- @object.name.titleize
137
- end
138
-
139
- def details
140
- # TODO: Add presenter logic
141
- end
142
- end
143
- RUBY
144
- end
145
-
146
- # Default spec template
147
- def default_spec_template
148
- <<~RUBY
149
- require 'rails_helper'
150
-
151
- RSpec.describe #{camelize}Presenter do
152
- let(:object) { double(name: 'Test Object') }
153
- subject { described_class.new(object) }
154
-
155
- describe '#title' do
156
- it 'returns titleized name' do
157
- expect(subject.title).to eq('Test Object')
158
- end
159
- end
160
- end
161
- RUBY
162
- end
163
-
164
- # Apply template variables
165
- def apply_template(content)
166
- content
167
- .gsub("<%= name %>", @name)
168
- .gsub("<%= name.camelize %>", camelize)
169
- .gsub("<%= name.underscore %>", underscore)
170
- end
171
- end
172
- end
173
- end
@@ -1,174 +0,0 @@
1
- # Query generator for RailsForge
2
- # Generates query object files
3
-
4
- require_relative 'base_generator'
5
-
6
- module RailsForge
7
- module Generators
8
- # QueryGenerator creates query files
9
- class QueryGenerator < BaseGenerator
10
- # Error class for invalid query names
11
- class InvalidQueryNameError < StandardError; end
12
-
13
- # Template version
14
- TEMPLATE_VERSION = "v1"
15
-
16
- # Initialize the generator
17
- # @param name [String] Query name
18
- # @param options [Hash] Generator options
19
- def initialize(name, options = {})
20
- super(name, options)
21
- @template_version = options[:template_version] || TEMPLATE_VERSION
22
- @with_spec = options.fetch(:with_spec, true)
23
- end
24
-
25
- # Generate query files
26
- # @return [String] Success message
27
- def generate
28
- return "Not in a Rails application directory" unless @base_path
29
-
30
- validate_name!(@name)
31
-
32
- results = []
33
- results << generate_query
34
-
35
- if @with_spec
36
- results << generate_spec
37
- end
38
-
39
- "Query '#{@name}' generated successfully!\n" + results.join("\n")
40
- end
41
-
42
- # Class method for CLI
43
- def self.generate(query_name, with_spec: true, template_version: "v1")
44
- new(query_name, with_spec: with_spec, template_version: template_version).generate
45
- end
46
-
47
- private
48
-
49
- # Validate query name
50
- def validate_name!(name)
51
- raise InvalidQueryNameError, "Query name cannot be empty" if name.nil? || name.strip.empty?
52
- raise InvalidQueryNameError, "Name must match pattern: /\\A[A-Z][a-zA-Z0-9]*\\z/" unless name =~ /\A[A-Z][a-zA-Z0-9]*\z/
53
- end
54
-
55
- # Generate query file
56
- def generate_query
57
- query_dir = File.join(@base_path, "app", "queries")
58
- FileUtils.mkdir_p(query_dir)
59
-
60
- file_name = "#{underscore}.rb"
61
- file_path = File.join(query_dir, file_name)
62
-
63
- return " Skipping query (already exists)" if File.exist?(file_path)
64
-
65
- content = load_template
66
- content = apply_template(content)
67
-
68
- File.write(file_path, content)
69
- " Created app/queries/#{file_name}"
70
- end
71
-
72
- # Generate spec file
73
- def generate_spec
74
- spec_dir = File.join(@base_path, "spec", "queries")
75
- FileUtils.mkdir_p(spec_dir)
76
-
77
- file_name = "#{underscore}_spec.rb"
78
- file_path = File.join(spec_dir, file_name)
79
-
80
- return " Skipping spec (already exists)" if File.exist?(file_path)
81
-
82
- content = load_spec_template
83
- content = apply_template(content)
84
-
85
- File.write(file_path, content)
86
- " Created spec/queries/#{file_name}"
87
- end
88
-
89
- # Load template content
90
- def load_template
91
- template_path = File.join(
92
- File.dirname(__FILE__),
93
- "..",
94
- "templates",
95
- @template_version,
96
- "query",
97
- "template.rb"
98
- )
99
-
100
- if File.exist?(template_path)
101
- File.read(template_path)
102
- else
103
- default_template
104
- end
105
- end
106
-
107
- # Load spec template
108
- def load_spec_template
109
- spec_path = File.join(
110
- File.dirname(__FILE__),
111
- "..",
112
- "templates",
113
- @template_version,
114
- "query",
115
- "spec_template.rb"
116
- )
117
-
118
- if File.exist?(spec_path)
119
- File.read(spec_path)
120
- else
121
- default_spec_template
122
- end
123
- end
124
-
125
- # Default template
126
- def default_template
127
- <<~RUBY
128
- # Query class for #{underscore}
129
- # Encapsulates database queries
130
- class #{camelize}
131
- def initialize(scope: nil)
132
- @scope = scope || default_scope
133
- end
134
-
135
- def call
136
- @scope
137
- end
138
-
139
- private
140
-
141
- def default_scope
142
- # TODO: Replace with actual model scope
143
- Model.all
144
- end
145
- end
146
- RUBY
147
- end
148
-
149
- # Default spec template
150
- def default_spec_template
151
- <<~RUBY
152
- require 'rails_helper'
153
-
154
- RSpec.describe #{camelize} do
155
- describe '#call' do
156
- it 'returns scope' do
157
- result = described_class.call
158
- expect(result).to be_a(ActiveRecord::Relation)
159
- end
160
- end
161
- end
162
- RUBY
163
- end
164
-
165
- # Apply template variables
166
- def apply_template(content)
167
- content
168
- .gsub("<%= name %>", @name)
169
- .gsub("<%= name.camelize %>", camelize)
170
- .gsub("<%= name.underscore %>", underscore)
171
- end
172
- end
173
- end
174
- end
@@ -1,166 +0,0 @@
1
- # Serializer generator for RailsForge
2
- # Generates serializer object files
3
-
4
- require_relative 'base_generator'
5
-
6
- module RailsForge
7
- module Generators
8
- # SerializerGenerator creates serializer files
9
- class SerializerGenerator < BaseGenerator
10
- # Error class for invalid serializer names
11
- class InvalidSerializerNameError < StandardError; end
12
-
13
- # Template version
14
- TEMPLATE_VERSION = "v1"
15
-
16
- # Initialize the generator
17
- # @param name [String] Serializer name
18
- # @param options [Hash] Generator options
19
- def initialize(name, options = {})
20
- super(name, options)
21
- @template_version = options[:template_version] || TEMPLATE_VERSION
22
- @with_spec = options.fetch(:with_spec, true)
23
- end
24
-
25
- # Generate serializer files
26
- # @return [String] Success message
27
- def generate
28
- return "Not in a Rails application directory" unless @base_path
29
-
30
- validate_name!(@name)
31
-
32
- results = []
33
- results << generate_serializer
34
-
35
- if @with_spec
36
- results << generate_spec
37
- end
38
-
39
- "Serializer '#{@name}' generated successfully!\n" + results.join("\n")
40
- end
41
-
42
- # Class method for CLI
43
- def self.generate(serializer_name, with_spec: true, template_version: "v1")
44
- new(serializer_name, with_spec: with_spec, template_version: template_version).generate
45
- end
46
-
47
- private
48
-
49
- # Validate serializer name
50
- def validate_name!(name)
51
- raise InvalidSerializerNameError, "Serializer name cannot be empty" if name.nil? || name.strip.empty?
52
- raise InvalidSerializerNameError, "Name must match pattern: /\\A[A-Z][a-zA-Z0-9]*\\z/" unless name =~ /\A[A-Z][a-zA-Z0-9]*\z/
53
- end
54
-
55
- # Generate serializer file
56
- def generate_serializer
57
- serializer_dir = File.join(@base_path, "app", "serializers")
58
- FileUtils.mkdir_p(serializer_dir)
59
-
60
- file_name = "#{underscore}_serializer.rb"
61
- file_path = File.join(serializer_dir, file_name)
62
-
63
- return " Skipping serializer (already exists)" if File.exist?(file_path)
64
-
65
- content = load_template
66
- content = apply_template(content)
67
-
68
- File.write(file_path, content)
69
- " Created app/serializers/#{file_name}"
70
- end
71
-
72
- # Generate spec file
73
- def generate_spec
74
- spec_dir = File.join(@base_path, "spec", "serializers")
75
- FileUtils.mkdir_p(spec_dir)
76
-
77
- file_name = "#{underscore}_serializer_spec.rb"
78
- file_path = File.join(spec_dir, file_name)
79
-
80
- return " Skipping spec (already exists)" if File.exist?(file_path)
81
-
82
- content = load_spec_template
83
- content = apply_template(content)
84
-
85
- File.write(file_path, content)
86
- " Created spec/serializers/#{file_name}"
87
- end
88
-
89
- # Load template content
90
- def load_template
91
- template_path = File.join(
92
- File.dirname(__FILE__),
93
- "..",
94
- "templates",
95
- @template_version,
96
- "serializer",
97
- "template.rb"
98
- )
99
-
100
- if File.exist?(template_path)
101
- File.read(template_path)
102
- else
103
- default_template
104
- end
105
- end
106
-
107
- # Load spec template
108
- def load_spec_template
109
- spec_path = File.join(
110
- File.dirname(__FILE__),
111
- "..",
112
- "templates",
113
- @template_version,
114
- "serializer",
115
- "spec_template.rb"
116
- )
117
-
118
- if File.exist?(spec_path)
119
- File.read(spec_path)
120
- else
121
- default_spec_template
122
- end
123
- end
124
-
125
- # Default template
126
- def default_template
127
- <<~RUBY
128
- # Serializer class for #{underscore}
129
- # Defines JSON serialization
130
- class #{camelize}Serializer < ApplicationSerializer
131
- attributes :id, :name, :created_at, :updated_at
132
-
133
- # TODO and: Add associations methods
134
- # belongs_to :user
135
- # has_many :items
136
- end
137
- RUBY
138
- end
139
-
140
- # Default spec template
141
- def default_spec_template
142
- <<~RUBY
143
- require 'rails_helper'
144
-
145
- RSpec.describe #{camelize}Serializer do
146
- let(:resource) { #{camelize}.create!(name: 'Test') }
147
- let(:serializer) { described_class.new(resource) }
148
- let(:serialization) { ActiveModel::SerializableResource.new(resource).as_json }
149
-
150
- it 'includes expected attributes' do
151
- expect(serialization[:#{camelize.underscore}] [:name]).to eq('Test')
152
- end
153
- end
154
- RUBY
155
- end
156
-
157
- # Apply template variables
158
- def apply_template(content)
159
- content
160
- .gsub("<%= name %>", @name)
161
- .gsub("<%= name.camelize %>", camelize)
162
- .gsub("<%= name.underscore %>", underscore)
163
- end
164
- end
165
- end
166
- end
@@ -1,122 +0,0 @@
1
- # Service generator for RailsForge
2
- # Generates service objects
3
-
4
- require_relative 'base_generator'
5
-
6
- module RailsForge
7
- module Generators
8
- # ServiceGenerator creates service objects
9
- class ServiceGenerator < BaseGenerator
10
- # Error class for invalid service names
11
- class InvalidServiceNameError < StandardError; end
12
-
13
- # Validates the service name
14
- # @param name [String] Service name to validate
15
- def validate_name!(name)
16
- super(name, /\A[A-Z][a-zA-Z0-9]*\z/, InvalidServiceNameError)
17
- end
18
-
19
- # Generate service file and optionally spec
20
- # @return [String] Success message
21
- def generate
22
- validate_name!(@name)
23
-
24
- unless @base_path
25
- raise "Not in a Rails application directory"
26
- end
27
-
28
- service_file_path = generate_service_file
29
-
30
- if @options[:with_spec] != false
31
- generate_spec_file
32
- end
33
-
34
- "Service '#{@name}' generated successfully!"
35
- end
36
-
37
- # Generate the service file
38
- # @return [String] Path to generated file
39
- def generate_service_file
40
- service_dir = File.join(@base_path, "app", "services")
41
- FileUtils.mkdir_p(service_dir)
42
-
43
- file_name = "#{underscore}.rb"
44
- file_path = File.join(service_dir, file_name)
45
-
46
- if File.exist?(file_path)
47
- puts " Skipping service (already exists)"
48
- return file_path
49
- end
50
-
51
- File.write(file_path, service_template)
52
- puts " Created app/services/#{file_name}"
53
- file_path
54
- end
55
-
56
- # Generate the spec file
57
- # @return [String] Path to generated spec
58
- def generate_spec_file
59
- spec_dir = File.join(@base_path, "spec", "services")
60
- FileUtils.mkdir_p(spec_dir)
61
-
62
- file_name = "#{underscore}_spec.rb"
63
- file_path = File.join(spec_dir, file_name)
64
-
65
- if File.exist?(file_path)
66
- puts " Skipping spec (already exists)"
67
- return file_path
68
- end
69
-
70
- File.write(file_path, spec_template)
71
- puts " Created spec/services/#{file_name}"
72
- file_path
73
- end
74
-
75
- # Service template
76
- # @return [String] Template content
77
- def service_template
78
- <<~RUBY
79
- # Service class for #{underscore}
80
- # Encapsulates business logic related to #{underscore}
81
- class #{@name}
82
- def initialize(**args)
83
- @args = args
84
- end
85
-
86
- def call
87
- # TODO: Implement service logic here
88
- end
89
-
90
- def self.call(**args)
91
- new(**args).call
92
- end
93
-
94
- private
95
- end
96
- RUBY
97
- end
98
-
99
- # Spec template
100
- # @return [String] Spec template content
101
- def spec_template
102
- <<~RUBY
103
- # frozen_string_literal: true
104
-
105
- RSpec.describe #{@name} do
106
- describe '#call' do
107
- it 'returns expected result' do
108
- result = described_class.call
109
- expect(result).to be_nil
110
- end
111
- end
112
- end
113
- RUBY
114
- end
115
-
116
- # Class method for CLI
117
- def self.generate(service_name, with_spec: true, template_version: "v1")
118
- new(service_name, with_spec: with_spec, template_version: template_version).generate
119
- end
120
- end
121
- end
122
- end