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,66 +0,0 @@
1
- # Query object template v2
2
- # Enhanced query with chainable interface
3
- class <%= class_name %>
4
- attr_reader :relation
5
-
6
- def initialize(relation = nil)
7
- @relation = relation || default_relation
8
- end
9
-
10
- # Chainable scope methods
11
- def filter_by(**conditions)
12
- conditions.each do |attribute, value|
13
- @relation = @relation.where(attribute => value)
14
- end
15
- self
16
- end
17
-
18
- def order_by(attribute, direction = :asc)
19
- @relation = @relation.order(attribute => direction)
20
- self
21
- end
22
-
23
- def limit(count)
24
- @relation = @relation.limit(count)
25
- self
26
- end
27
-
28
- def offset(count)
29
- @relation = @relation.offset(count)
30
- self
31
- end
32
-
33
- # Execute the query
34
- def call
35
- @relation
36
- end
37
-
38
- # Convenience methods
39
- def first
40
- @relation.first
41
- end
42
-
43
- def last
44
- @relation.last
45
- end
46
-
47
- def all
48
- @relation.to_a
49
- end
50
-
51
- def count
52
- @relation.count
53
- end
54
-
55
- def exists?
56
- @relation.exists?
57
- end
58
-
59
- private
60
-
61
- def default_relation
62
- # TODO: Replace with actual model
63
- # Example: Model.where(active: true)
64
- raise NotImplementedError, "Override #default_relation in subclass"
65
- end
66
- end
@@ -1,33 +0,0 @@
1
- # RSpec tests for <%= class_name %>
2
- # Enhanced v2 testing with better patterns
3
- RSpec.describe <%= class_name %> do
4
- let(:params) { {} }
5
- let(:service) { described_class.new(params) }
6
-
7
- describe "#call" do
8
- context "with valid params" do
9
- it "returns a successful result" do
10
- result = service.call
11
- expect(result.success?).to be true
12
- expect(result.data).to be_a(Hash)
13
- end
14
- end
15
-
16
- context "with invalid params" do
17
- let(:params) { { invalid: true } }
18
-
19
- it "returns a failure result" do
20
- result = service.call
21
- expect(result.failure?).to be true
22
- expect(result.errors).to be_an(Array)
23
- end
24
- end
25
- end
26
-
27
- describe ".call" do
28
- it "creates and calls the service" do
29
- result = described_class.call({})
30
- expect(result).to be_a(Result)
31
- end
32
- end
33
- end
@@ -1,71 +0,0 @@
1
- # Service class template v2
2
- # Enhanced service with better practices
3
- class <%= class_name %>
4
- # Initialize with dependencies
5
- # @param [Hash] params - Parameters for the service
6
- def initialize(params = {})
7
- @params = params
8
- @errors = []
9
- end
10
-
11
- # Execute the service logic
12
- # @return [Result] Result object with success/failure
13
- def call
14
- return failure(["Validation failed"]) unless validate?
15
-
16
- success(execute_operation)
17
- rescue StandardError => e
18
- failure([e.message])
19
- end
20
-
21
- # Class-level call for convenience
22
- # @param [Hash] params - Parameters for the service
23
- # @return [Result] Result object
24
- def self.call(params = {})
25
- new(params).call
26
- end
27
-
28
- private
29
-
30
- # Validate inputs
31
- # @return [Boolean] True if valid
32
- def validate?
33
- true
34
- end
35
-
36
- # Execute the main operation
37
- # @return [Object] Operation result
38
- def execute_operation
39
- # TODO: Implement service logic
40
- {}
41
- end
42
-
43
- # Helper method for success result
44
- # @param [Object] data - Result data
45
- # @return [Result]
46
- def success(data)
47
- Result.new(success: true, data: data, errors: [])
48
- end
49
-
50
- # Helper method for failure result
51
- # @param [Array<String>] errors - Error messages
52
- # @return [Result]
53
- def failure(errors)
54
- Result.new(success: false, data: nil, errors: errors)
55
- end
56
- end
57
-
58
- # Result class for service responses
59
- class Result
60
- attr_reader :success, :data, :errors
61
-
62
- def initialize(success:, data:, errors:)
63
- @success = success
64
- @data = data
65
- @errors = errors
66
- end
67
-
68
- def failure?
69
- !success
70
- end
71
- end
@@ -1,72 +0,0 @@
1
- # Job template v3
2
- # Advanced job with retries, priority, and callbacks
3
- class <%= class_name %>Job < ApplicationJob
4
- # Queue configuration
5
- queue_with_priority PRIORITIES[:default]
6
-
7
- # Retry configuration
8
- retry_on StandardError, wait: :exponential_backoff, attempts: 5
9
-
10
- # Discard configuration for permanent failures
11
- discard_on PermanentJobError do |job, error|
12
- Rails.logger.error("Job #{job.job_id} permanently failed: #{error.message}")
13
- end
14
-
15
- # Callback hooks
16
- around_perform :instrument_job
17
- before_perform :log_start
18
- after_perform :log_complete
19
-
20
- # Perform the job
21
- # @param [Hash] args - Job arguments
22
- def perform(*args)
23
- # TODO: Implement job logic
24
- # Example:
25
- # user = User.find(args[:user_id])
26
- # UserMailer.welcome(user).deliver_now
27
- Rails.logger.info("Executing #{self.class.name}")
28
- end
29
-
30
- # Schedule for later
31
- # @param [Integer] delay - Delay in seconds
32
- def self.perform_in(delay, *args)
33
- set(wait: delay seconds).perform_later(*args)
34
- end
35
-
36
- # Schedule at specific time
37
- # @param [DateTime] time - Scheduled time
38
- def self.perform_at(time, *args)
39
- set(wait_until: time).perform_later(*args)
40
- end
41
-
42
- # Unique job - prevent duplicates
43
- def self.unique_by(*attributes)
44
- sidekiq_options unique: true,
45
- unique_args: ->(args) { args }
46
- end
47
-
48
- private
49
-
50
- # Instrument the job for monitoring
51
- def instrument_job
52
- start_time = Time.now
53
- Rails.logger.info("Starting #{self.class.name} at #{start_time}")
54
-
55
- begin
56
- yield
57
- ensure
58
- duration = Time.now - start_time
59
- Rails.logger.info("Completed #{self.class.name} in #{duration.round(2)}s")
60
- end
61
- end
62
-
63
- # Log job start
64
- def log_start
65
- Rails.logger.debug("Job #{job_id} starting")
66
- end
67
-
68
- # Log job completion
69
- def log_complete
70
- Rails.logger.debug("Job #{job_id} completed")
71
- end
72
- end
@@ -1,54 +0,0 @@
1
- # Query spec template v3
2
- require 'rails_helper'
3
-
4
- RSpec.describe <%= class_name %> do
5
- let(:query) { described_class.new(relation) }
6
- let(:relation) { double('Relation') }
7
-
8
- describe '#where' do
9
- it 'adds conditions' do
10
- expect(query.where(status: 'active')).to be_a(described_class)
11
- end
12
- end
13
-
14
- describe '#includes' do
15
- it 'adds includes' do
16
- expect(query.includes(:user)).to be_a(described_class)
17
- end
18
- end
19
-
20
- describe '#order' do
21
- it 'adds order' do
22
- expect(query.order(created_at: :desc)).to be_a(described_class)
23
- end
24
- end
25
-
26
- describe '#paginate' do
27
- it 'sets limit and offset' do
28
- paginated = query.paginate(page: 2, per_page: 10)
29
- expect(paginated).to be_a(described_class)
30
- end
31
- end
32
-
33
- describe '#call' do
34
- it 'executes the query' do
35
- allow(relation).to receive_message_chain(:where, :includes, :order, :to_a).and_return([])
36
- expect(query.call).to eq([])
37
- end
38
- end
39
-
40
- describe '#count' do
41
- it 'returns total count' do
42
- allow(relation).to receive_message_chain(:where, :includes, :order, :count).and_return(10)
43
- expect(query.count).to eq(10)
44
- end
45
- end
46
-
47
- describe '#pagination_info' do
48
- it 'returns pagination metadata' do
49
- allow(relation).to receive_message_chain(:where, :includes, :order, :count).and_return(25)
50
- info = query.pagination_info(page: 1, per_page: 10)
51
- expect(info[:total_pages]).to eq(3)
52
- end
53
- end
54
- end
@@ -1,115 +0,0 @@
1
- # Query object template v3
2
- # Advanced query with pagination and caching
3
- class <%= class_name %>
4
- # @return [ActiveRecord::Relation] relation
5
- attr_reader :relation
6
-
7
- def initialize(relation = default_relation)
8
- @relation = relation
9
- @conditions = []
10
- @includes = []
11
- @order = []
12
- @limit_value = nil
13
- @offset_value = nil
14
- end
15
-
16
- # Add conditions
17
- # @param [Hash] conditions - Query conditions
18
- def where(conditions)
19
- @conditions << conditions
20
- self
21
- end
22
-
23
- # Eager load associations
24
- # @param [Array<Symbol>] associations - Associations to include
25
- def includes(*associations)
26
- @includes << associations
27
- self
28
- end
29
-
30
- # Order results
31
- # @param [Hash] order_spec - Order specification
32
- def order(order_spec)
33
- @order << order_spec
34
- self
35
- end
36
-
37
- # Paginate results
38
- # @param [Integer] page - Page number (1-indexed)
39
- # @param [Integer] per_page - Items per page
40
- def paginate(page: 1, per_page: 25)
41
- @limit_value = per_page
42
- @offset_value = (page - 1) * per_page
43
- self
44
- end
45
-
46
- # Cache results
47
- # @param [Integer] duration - Cache duration in seconds
48
- def cached(duration: 5.minutes)
49
- cache_key = generate_cache_key
50
- Rails.cache.fetch(cache_key, expires_in: duration) do
51
- to_a
52
- end
53
- end
54
-
55
- # Execute query and return results
56
- def call
57
- build_relation.to_a
58
- end
59
-
60
- # Get total count
61
- def count
62
- build_relation.count
63
- end
64
-
65
- # Pagination metadata
66
- def pagination_info(page: 1, per_page: 25)
67
- total = count
68
- {
69
- current_page: page,
70
- per_page: per_page,
71
- total_count: total,
72
- total_pages: (total.to_f / per_page).ceil,
73
- has_next_page: (page * per_page) < total,
74
- has_previous_page: page > 1
75
- }
76
- end
77
-
78
- # Reset to default
79
- def reset
80
- @conditions = []
81
- @includes = []
82
- @order = []
83
- @limit_value = nil
84
- @offset_value = nil
85
- self
86
- end
87
-
88
- private
89
-
90
- def default_relation
91
- raise NotImplementedError, "Override default_relation in subclass"
92
- end
93
-
94
- def build_relation
95
- result = @relation
96
-
97
- @conditions.each { |cond| result = result.where(cond) }
98
- @includes.flatten.each { |inc| result = result.includes(inc) }
99
- @order.each { |ord| result = result.order(ord) }
100
- result = result.limit(@limit_value) if @limit_value
101
- result = result.offset(@offset_value) if @offset_value
102
-
103
- result
104
- end
105
-
106
- def generate_cache_key
107
- {
108
- conditions: @conditions,
109
- includes: @includes,
110
- order: @order,
111
- limit: @limit_value,
112
- offset: @offset_value
113
- }
114
- end
115
- end
@@ -1,51 +0,0 @@
1
- # Service spec template v3
2
- require 'rails_helper'
3
-
4
- RSpec.describe <%= class_name %> do
5
- let(:service) { described_class.new(params) }
6
- let(:params) { { name: 'Test' } }
7
-
8
- describe '#call' do
9
- context 'with valid params' do
10
- it 'returns success' do
11
- result = service.call
12
- expect(result).to be_success
13
- end
14
-
15
- it 'contains data in result' do
16
- result = service.call
17
- expect(result.value!).to have_key(:data)
18
- end
19
-
20
- it 'includes metadata' do
21
- result = service.call
22
- expect(result.value!).to have_key(:metadata)
23
- end
24
- end
25
-
26
- context 'with invalid params' do
27
- let(:params) { {} }
28
-
29
- it 'returns failure' do
30
- result = service.call
31
- expect(result).to be_failure
32
- end
33
- end
34
- end
35
-
36
- describe '.call' do
37
- it 'works as class method' do
38
- result = described_class.call(name: 'Test')
39
- expect(result).to be_success
40
- end
41
- end
42
-
43
- describe '#then' do
44
- let(:next_service) { double('NextService', new: double(call: Success({}))) }
45
-
46
- it 'chains to another service' do
47
- result = service.then(next_service, extra: 'param')
48
- expect(result).to be_a(Dry::Monads::Result)
49
- end
50
- end
51
- end
@@ -1,93 +0,0 @@
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
- # Override this method to add custom validation
50
- # @example
51
- # def validate!
52
- # return Failure(errors: ['Name required']) if @params[:name].blank?
53
- # Success(true)
54
- # end
55
- def validate!
56
- Success(true)
57
- end
58
-
59
- # Process the main logic - returns Result
60
- # Override this method to implement your service logic
61
- # @example
62
- # def process!
63
- # user = User.create!(@params)
64
- # @result = { user: user }
65
- # Success(true)
66
- # end
67
- def process!
68
- @result = {}
69
- Success(true)
70
- end
71
-
72
- # Build result data
73
- def result_data
74
- {
75
- data: @result,
76
- metadata: {
77
- service: self.class.name,
78
- timestamp: Time.now.utc.iso8601
79
- }
80
- }
81
- end
82
- end
83
-
84
- # Result wrapper for success/failure
85
- module Result
86
- def self.success(data)
87
- { success: true, data: data }
88
- end
89
-
90
- def self.failure(errors)
91
- { success: false, errors: errors }
92
- end
93
- end