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.
- checksums.yaml +4 -4
- data/README.md +105 -444
- data/lib/railsforge/analyzers/controller_analyzer.rb +29 -55
- data/lib/railsforge/analyzers/database_analyzer.rb +16 -30
- data/lib/railsforge/analyzers/metrics_analyzer.rb +8 -22
- data/lib/railsforge/analyzers/model_analyzer.rb +29 -46
- data/lib/railsforge/analyzers/performance_analyzer.rb +34 -94
- data/lib/railsforge/analyzers/refactor_analyzer.rb +77 -57
- data/lib/railsforge/analyzers/security_analyzer.rb +34 -91
- data/lib/railsforge/analyzers/spec_analyzer.rb +17 -31
- data/lib/railsforge/cli.rb +14 -650
- data/lib/railsforge/cli_minimal.rb +8 -55
- data/lib/railsforge/doctor.rb +52 -225
- data/lib/railsforge/formatter.rb +102 -0
- data/lib/railsforge/issue.rb +23 -0
- data/lib/railsforge/loader.rb +4 -64
- data/lib/railsforge/version.rb +1 -1
- metadata +14 -82
- data/lib/railsforge/api_generator.rb +0 -397
- data/lib/railsforge/audit.rb +0 -289
- data/lib/railsforge/config.rb +0 -181
- data/lib/railsforge/database_analyzer.rb +0 -300
- data/lib/railsforge/feature_generator.rb +0 -560
- data/lib/railsforge/generator.rb +0 -313
- data/lib/railsforge/generators/api_generator.rb +0 -392
- data/lib/railsforge/generators/base_generator.rb +0 -75
- data/lib/railsforge/generators/demo_generator.rb +0 -307
- data/lib/railsforge/generators/devops_generator.rb +0 -287
- data/lib/railsforge/generators/form_generator.rb +0 -180
- data/lib/railsforge/generators/job_generator.rb +0 -176
- data/lib/railsforge/generators/monitoring_generator.rb +0 -134
- data/lib/railsforge/generators/policy_generator.rb +0 -220
- data/lib/railsforge/generators/presenter_generator.rb +0 -173
- data/lib/railsforge/generators/query_generator.rb +0 -174
- data/lib/railsforge/generators/serializer_generator.rb +0 -166
- data/lib/railsforge/generators/service_generator.rb +0 -122
- data/lib/railsforge/generators/stimulus_controller_generator.rb +0 -129
- data/lib/railsforge/generators/test_generator.rb +0 -289
- data/lib/railsforge/generators/view_component_generator.rb +0 -169
- data/lib/railsforge/graph.rb +0 -270
- data/lib/railsforge/mailer_generator.rb +0 -191
- data/lib/railsforge/plugins/plugin_loader.rb +0 -60
- data/lib/railsforge/plugins.rb +0 -30
- data/lib/railsforge/profiles.rb +0 -99
- data/lib/railsforge/refactor_analyzer.rb +0 -401
- data/lib/railsforge/refactor_controller.rb +0 -277
- data/lib/railsforge/refactors/refactor_controller.rb +0 -117
- data/lib/railsforge/template_loader.rb +0 -105
- data/lib/railsforge/templates/v1/form/spec_template.rb +0 -18
- data/lib/railsforge/templates/v1/form/template.rb +0 -28
- data/lib/railsforge/templates/v1/job/spec_template.rb +0 -17
- data/lib/railsforge/templates/v1/job/template.rb +0 -13
- data/lib/railsforge/templates/v1/policy/spec_template.rb +0 -41
- data/lib/railsforge/templates/v1/policy/template.rb +0 -57
- data/lib/railsforge/templates/v1/presenter/spec_template.rb +0 -12
- data/lib/railsforge/templates/v1/presenter/template.rb +0 -13
- data/lib/railsforge/templates/v1/query/spec_template.rb +0 -12
- data/lib/railsforge/templates/v1/query/template.rb +0 -16
- data/lib/railsforge/templates/v1/serializer/spec_template.rb +0 -13
- data/lib/railsforge/templates/v1/serializer/template.rb +0 -11
- data/lib/railsforge/templates/v1/service/spec_template.rb +0 -12
- data/lib/railsforge/templates/v1/service/template.rb +0 -25
- data/lib/railsforge/templates/v1/stimulus_controller/template.rb +0 -35
- data/lib/railsforge/templates/v1/view_component/template.rb +0 -24
- data/lib/railsforge/templates/v2/job/template.rb +0 -49
- data/lib/railsforge/templates/v2/query/template.rb +0 -66
- data/lib/railsforge/templates/v2/service/spec_template.rb +0 -33
- data/lib/railsforge/templates/v2/service/template.rb +0 -71
- data/lib/railsforge/templates/v3/job/template.rb +0 -72
- data/lib/railsforge/templates/v3/query/spec_template.rb +0 -54
- data/lib/railsforge/templates/v3/query/template.rb +0 -115
- data/lib/railsforge/templates/v3/service/spec_template.rb +0 -51
- data/lib/railsforge/templates/v3/service/template.rb +0 -93
- data/lib/railsforge/wizard.rb +0 -265
- 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
|