rails-openapi-gen 0.0.1

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 (27) hide show
  1. checksums.yaml +7 -0
  2. data/CLAUDE.md +160 -0
  3. data/README.md +164 -0
  4. data/lib/rails_openapi_gen/configuration.rb +157 -0
  5. data/lib/rails_openapi_gen/engine.rb +11 -0
  6. data/lib/rails_openapi_gen/generators/yaml_generator.rb +302 -0
  7. data/lib/rails_openapi_gen/importer.rb +647 -0
  8. data/lib/rails_openapi_gen/parsers/comment_parser.rb +40 -0
  9. data/lib/rails_openapi_gen/parsers/comment_parsers/attribute_parser.rb +57 -0
  10. data/lib/rails_openapi_gen/parsers/comment_parsers/base_attribute_parser.rb +42 -0
  11. data/lib/rails_openapi_gen/parsers/comment_parsers/body_parser.rb +62 -0
  12. data/lib/rails_openapi_gen/parsers/comment_parsers/conditional_parser.rb +13 -0
  13. data/lib/rails_openapi_gen/parsers/comment_parsers/operation_parser.rb +50 -0
  14. data/lib/rails_openapi_gen/parsers/comment_parsers/param_parser.rb +62 -0
  15. data/lib/rails_openapi_gen/parsers/comment_parsers/query_parser.rb +62 -0
  16. data/lib/rails_openapi_gen/parsers/controller_parser.rb +153 -0
  17. data/lib/rails_openapi_gen/parsers/jbuilder_parser.rb +529 -0
  18. data/lib/rails_openapi_gen/parsers/routes_parser.rb +33 -0
  19. data/lib/rails_openapi_gen/parsers/template_processors/jbuilder_template_processor.rb +147 -0
  20. data/lib/rails_openapi_gen/parsers/template_processors/response_template_processor.rb +17 -0
  21. data/lib/rails_openapi_gen/railtie.rb +11 -0
  22. data/lib/rails_openapi_gen/tasks/openapi.rake +30 -0
  23. data/lib/rails_openapi_gen/version.rb +5 -0
  24. data/lib/rails_openapi_gen.rb +267 -0
  25. data/lib/tasks/openapi_import.rake +126 -0
  26. data/rails-openapi-gen.gemspec +30 -0
  27. metadata +155 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOpenapiGen
4
+ module Parsers
5
+ module TemplateProcessors
6
+ module ResponseTemplateProcessor
7
+ def extract_template_path(action_node, route)
8
+ raise NotImplementedError, "#{self.class} must implement #extract_template_path"
9
+ end
10
+
11
+ def find_default_template(route)
12
+ raise NotImplementedError, "#{self.class} must implement #find_default_template"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ module RailsOpenapiGen
6
+ class Railtie < Rails::Railtie
7
+ rake_tasks do
8
+ load File.expand_path("tasks/openapi.rake", __dir__)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :openapi do
4
+ desc "Generate OpenAPI specification from Rails application"
5
+ task generate: :environment do
6
+ require "rails_openapi_gen"
7
+ RailsOpenapiGen.generate
8
+ end
9
+
10
+ desc "Check for missing @openapi comments and uncommitted changes"
11
+ task check: :environment do
12
+ require "rails_openapi_gen"
13
+ RailsOpenapiGen.check
14
+ end
15
+
16
+ desc "Import OpenAPI specification and add comments to Jbuilder templates"
17
+ task :import, [:openapi_file] => :environment do |_task, args|
18
+ require "rails_openapi_gen"
19
+
20
+ openapi_file = args[:openapi_file]
21
+
22
+ if openapi_file.nil? || openapi_file.empty?
23
+ puts "Usage: bin/rails openapi:import[PATH_TO_OPENAPI_FILE]"
24
+ puts "Example: bin/rails openapi:import[docs/api/openapi.yaml]"
25
+ exit 1
26
+ end
27
+
28
+ RailsOpenapiGen.import(openapi_file)
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsOpenapiGen
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,267 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_openapi_gen/version"
4
+ require "rails_openapi_gen/configuration"
5
+ require "rails_openapi_gen/parsers/comment_parser"
6
+ require "rails_openapi_gen/generators/yaml_generator"
7
+ require "rails_openapi_gen/importer"
8
+
9
+ # Rails integration is handled by Engine
10
+
11
+ # Load Rails Engine if Rails is available
12
+ if defined?(Rails::Engine)
13
+ require "rails_openapi_gen/engine"
14
+
15
+ # Only load parser-dependent components if parser gem is available
16
+ begin
17
+ require "parser/current"
18
+ require "rails_openapi_gen/parsers/routes_parser"
19
+ require "rails_openapi_gen/parsers/controller_parser"
20
+ require "rails_openapi_gen/parsers/jbuilder_parser"
21
+ rescue LoadError
22
+ # parser gem not available, skip these components
23
+ end
24
+ end
25
+
26
+ module RailsOpenapiGen
27
+ class Error < StandardError; end
28
+
29
+ class << self
30
+ # Generates OpenAPI specification from Rails application
31
+ # @return [void]
32
+ def generate
33
+ Generator.new.run
34
+ end
35
+
36
+ # Checks for missing OpenAPI comments and uncommitted changes
37
+ # @return [void]
38
+ def check
39
+ Checker.new.run
40
+ end
41
+
42
+ # Imports OpenAPI specification and generates @openapi comments in Jbuilder files
43
+ # @param openapi_file [String, nil] Path to OpenAPI specification file (defaults to openapi/openapi.yaml)
44
+ # @return [void]
45
+ def import(openapi_file = nil)
46
+ Importer.new(openapi_file).run
47
+ end
48
+ end
49
+
50
+ class Generator
51
+ # Runs the OpenAPI generation process
52
+ # @return [void]
53
+ def run
54
+ # Load configuration
55
+ RailsOpenapiGen.configuration.load_from_file
56
+
57
+ routes = Parsers::RoutesParser.new.parse
58
+ filtered_routes = routes.select { |route| RailsOpenapiGen.configuration.route_included?(route[:path]) }
59
+
60
+ schemas = {}
61
+
62
+ filtered_routes.each do |route|
63
+ controller_info = Parsers::ControllerParser.new(route).parse
64
+
65
+ if controller_info[:jbuilder_path]
66
+ jbuilder_result = Parsers::JbuilderParser.new(controller_info[:jbuilder_path]).parse
67
+ schema = build_schema(jbuilder_result[:properties])
68
+ schemas[route] = {
69
+ schema: schema,
70
+ parameters: controller_info[:parameters] || {},
71
+ operation: jbuilder_result[:operation]
72
+ }
73
+ end
74
+ end
75
+
76
+ Generators::YamlGenerator.new(schemas).generate
77
+ puts "✅ OpenAPI specification generated successfully!"
78
+ end
79
+
80
+ private
81
+
82
+ # Builds schema from parsed AST nodes
83
+ # @param ast [Array<Hash>] Array of parsed AST nodes
84
+ # @return [Hash] OpenAPI schema definition
85
+ def build_schema(ast)
86
+ # Check if this is an array response (json.array!)
87
+ if ast.any? { |node| node[:is_array_root] }
88
+ return build_array_schema(ast)
89
+ end
90
+
91
+ schema = { "type" => "object", "properties" => {}, "required" => [] }
92
+
93
+ ast.each do |node|
94
+ property = node[:property]
95
+ comment_data = node[:comment_data] || {}
96
+
97
+ # Skip array root items as they're handled separately
98
+ next if node[:is_array_root]
99
+
100
+ property_schema = build_property_schema(node)
101
+
102
+ schema["properties"][property] = property_schema
103
+ # Don't mark conditional properties as required, even if they have required:true
104
+ if comment_data[:required] == "true" && !node[:is_conditional]
105
+ schema["required"] << property
106
+ end
107
+ end
108
+
109
+ schema
110
+ end
111
+
112
+ # Builds array schema from AST nodes containing json.array!
113
+ # @param ast [Array<Hash>] Array of parsed AST nodes
114
+ # @return [Hash] OpenAPI array schema definition
115
+ def build_array_schema(ast)
116
+ # For json.array! responses, return array schema
117
+ item_properties = {}
118
+ required_fields = []
119
+
120
+ # Find the array root node to check for array_item_properties
121
+ array_root_node = ast.find { |node| node[:is_array_root] }
122
+
123
+ if array_root_node && array_root_node[:array_item_properties]
124
+ # Use properties from the parsed partial
125
+ array_root_node[:array_item_properties].each do |node|
126
+ property = node[:property]
127
+ comment_data = node[:comment_data] || {}
128
+
129
+ property_schema = build_property_schema(node)
130
+ item_properties[property] = property_schema
131
+ if comment_data[:required] == "true" && !node[:is_conditional]
132
+ required_fields << property
133
+ end
134
+ end
135
+ else
136
+ # Fall back to looking for non-root properties
137
+ ast.each do |node|
138
+ next if node[:is_array_root]
139
+
140
+ property = node[:property]
141
+ comment_data = node[:comment_data] || {}
142
+
143
+ property_schema = build_property_schema(node)
144
+ item_properties[property] = property_schema
145
+ if comment_data[:required] == "true" && !node[:is_conditional]
146
+ required_fields << property
147
+ end
148
+ end
149
+ end
150
+
151
+ {
152
+ "type" => "array",
153
+ "items" => {
154
+ "type" => "object",
155
+ "properties" => item_properties,
156
+ "required" => required_fields
157
+ }
158
+ }
159
+ end
160
+
161
+ # Builds property schema from a single AST node
162
+ # @param node [Hash] Parsed AST node containing property information
163
+ # @return [Hash] OpenAPI property schema
164
+ def build_property_schema(node)
165
+ comment_data = node[:comment_data] || {}
166
+ property_schema = {}
167
+
168
+ # Handle different property types
169
+ if node[:is_object] || node[:is_nested]
170
+ property_schema["type"] = "object"
171
+
172
+ # Build nested properties if they exist
173
+ if node[:nested_properties] && !node[:nested_properties].empty?
174
+ nested_schema = build_nested_object_schema(node[:nested_properties])
175
+ property_schema["properties"] = nested_schema["properties"]
176
+ property_schema["required"] = nested_schema["required"] if nested_schema["required"] && !nested_schema["required"].empty?
177
+ end
178
+ elsif node[:is_array]
179
+ property_schema["type"] = "array"
180
+
181
+ if node[:array_item_properties] && !node[:array_item_properties].empty?
182
+ # Build items schema from array iteration block
183
+ items_schema = build_nested_object_schema(node[:array_item_properties])
184
+ items_def = {
185
+ "type" => "object",
186
+ "properties" => items_schema["properties"]
187
+ }
188
+ items_def["required"] = items_schema["required"] if items_schema["required"] && !items_schema["required"].empty?
189
+ property_schema["items"] = items_def
190
+ elsif comment_data[:items]
191
+ # Use specified items type from comment
192
+ property_schema["items"] = { "type" => comment_data[:items] }
193
+ else
194
+ # Default to object items
195
+ property_schema["items"] = { "type" => "object" }
196
+ end
197
+ elsif comment_data[:type] && comment_data[:type] != "TODO: MISSING COMMENT"
198
+ property_schema["type"] = comment_data[:type]
199
+
200
+ # Handle array types
201
+ if comment_data[:type] == "array"
202
+ if comment_data[:items]
203
+ # Use specified items type
204
+ property_schema["items"] = { "type" => comment_data[:items] }
205
+ else
206
+ # Default to string items if no items type is specified
207
+ property_schema["items"] = { "type" => "string" }
208
+ end
209
+ end
210
+ else
211
+ # Only show TODO message if no @openapi comment exists at all
212
+ property_schema["type"] = "string"
213
+ if comment_data.nil? || comment_data.empty?
214
+ property_schema["description"] = "TODO: MISSING COMMENT - Add @openapi comment"
215
+ end
216
+ end
217
+
218
+ # Add common properties
219
+ property_schema["description"] = comment_data[:description] if comment_data[:description]
220
+ property_schema["enum"] = comment_data[:enum] if comment_data[:enum]
221
+
222
+ property_schema
223
+ end
224
+
225
+ # Builds schema for nested object properties
226
+ # @param nested_properties [Array<Hash>] Array of nested property nodes
227
+ # @return [Hash] Schema with properties and required fields
228
+ def build_nested_object_schema(nested_properties)
229
+ schema = { "properties" => {}, "required" => [] }
230
+
231
+ nested_properties.each do |node|
232
+ property = node[:property]
233
+ comment_data = node[:comment_data] || {}
234
+
235
+ property_schema = build_property_schema(node)
236
+ schema["properties"][property] = property_schema
237
+ if comment_data[:required] == "true" && !node[:is_conditional]
238
+ schema["required"] << property
239
+ end
240
+ end
241
+
242
+ schema
243
+ end
244
+ end
245
+
246
+ class Checker
247
+ # Runs checks for missing comments and uncommitted changes
248
+ # @return [void]
249
+ def run
250
+ system("bin/rails openapi:generate")
251
+
252
+ missing_comments = `grep -r "TODO: MISSING COMMENT" openapi/`.strip
253
+ unless missing_comments.empty?
254
+ puts "❌ Missing @openapi comments found!"
255
+ exit 1
256
+ end
257
+
258
+ diff = `git diff --name-only openapi/`.strip
259
+ unless diff.empty?
260
+ puts "❌ OpenAPI spec has uncommitted changes!"
261
+ exit 1
262
+ end
263
+
264
+ puts "✅ OpenAPI spec is up to date!"
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :openapi do
4
+ desc "Import OpenAPI specification and add @openapi comments to Jbuilder files"
5
+ task :import, [:openapi_file] => :environment do |_task, args|
6
+ openapi_file = args[:openapi_file]
7
+
8
+ # Set debug mode if verbose flag is passed
9
+ ENV['DEBUG_OPENAPI_IMPORT'] = '1' if ENV['VERBOSE'] == 'true'
10
+
11
+ RailsOpenapiGen.import(openapi_file)
12
+ end
13
+
14
+ desc "Diagnose import issues by comparing OpenAPI paths with Rails routes"
15
+ task :diagnose_import, [:openapi_file] => :environment do |_task, args|
16
+ openapi_file = args[:openapi_file] || File.join(RailsOpenapiGen.configuration.output_directory,
17
+ RailsOpenapiGen.configuration.output_filename)
18
+
19
+ unless File.exist?(openapi_file)
20
+ puts "❌ OpenAPI file not found: #{openapi_file}"
21
+ exit 1
22
+ end
23
+
24
+ puts "🔍 Diagnosing OpenAPI import for: #{openapi_file}"
25
+ puts ""
26
+
27
+ # Load OpenAPI spec
28
+ openapi_spec = YAML.load_file(openapi_file)
29
+ openapi_paths = openapi_spec['paths'] || {}
30
+
31
+ # Get Rails routes
32
+ routes_parser = RailsOpenapiGen::Parsers::RoutesParser.new
33
+ rails_routes = routes_parser.parse
34
+
35
+ # Group routes by path for easier lookup
36
+ routes_by_path = rails_routes.group_by { |r| r[:path] }
37
+
38
+ puts "📊 Summary:"
39
+ puts " OpenAPI paths: #{openapi_paths.size}"
40
+ puts " Rails routes: #{rails_routes.size}"
41
+ puts ""
42
+
43
+ # Check each OpenAPI path
44
+ unmatched_paths = []
45
+ matched_paths = []
46
+
47
+ openapi_paths.each do |path, methods|
48
+ methods.each do |method, operation|
49
+ next if method == 'parameters'
50
+
51
+ # Convert OpenAPI path to Rails format
52
+ rails_path = path.gsub(/\{(\w+)\}/, ':\1')
53
+
54
+ # Try to find matching route
55
+ matching_routes = rails_routes.select do |route|
56
+ route[:method] == method.upcase &&
57
+ route[:path].gsub(/\/$/, '') == rails_path.gsub(/\/$/, '')
58
+ end
59
+
60
+ if matching_routes.empty?
61
+ unmatched_paths << { path: path, method: method.upcase, rails_path: rails_path }
62
+ else
63
+ matched_paths << { path: path, method: method.upcase, route: matching_routes.first }
64
+ end
65
+ end
66
+ end
67
+
68
+ # Report results
69
+ if matched_paths.any?
70
+ puts "✅ Matched paths (#{matched_paths.size}):"
71
+ matched_paths.each do |match|
72
+ route = match[:route]
73
+ controller_path = route[:controller].gsub('/', '::').camelize + "Controller"
74
+ action = route[:action]
75
+ puts " #{match[:method]} #{match[:path]} → #{controller_path}##{action}"
76
+ end
77
+ puts ""
78
+ end
79
+
80
+ if unmatched_paths.any?
81
+ puts "❌ Unmatched OpenAPI paths (#{unmatched_paths.size}):"
82
+ unmatched_paths.each do |unmatched|
83
+ puts " #{unmatched[:method]} #{unmatched[:path]}"
84
+
85
+ # Suggest similar routes
86
+ similar_routes = rails_routes.select do |route|
87
+ route[:method] == unmatched[:method] &&
88
+ route[:path].include?(unmatched[:rails_path].split('/').reject(&:empty?).first.to_s)
89
+ end
90
+
91
+ if similar_routes.any?
92
+ puts " Did you mean one of these?"
93
+ similar_routes.take(3).each do |route|
94
+ puts " - #{route[:path]}"
95
+ end
96
+ end
97
+ end
98
+ puts ""
99
+ end
100
+
101
+ # Check for Jbuilder templates
102
+ puts "📄 Checking Jbuilder templates:"
103
+ matched_paths.each do |match|
104
+ route = match[:route]
105
+ controller_parser = RailsOpenapiGen::Parsers::ControllerParser.new(route)
106
+ controller_info = controller_parser.parse
107
+
108
+ if controller_info[:jbuilder_path]
109
+ if File.exist?(controller_info[:jbuilder_path])
110
+ puts " ✅ #{match[:method]} #{match[:path]} → #{controller_info[:jbuilder_path]}"
111
+ else
112
+ puts " ❌ #{match[:method]} #{match[:path]} → #{controller_info[:jbuilder_path]} (file not found)"
113
+ end
114
+ else
115
+ puts " ⚠️ #{match[:method]} #{match[:path]} → No Jbuilder template found"
116
+ end
117
+ end
118
+
119
+ puts ""
120
+ puts "💡 Tips:"
121
+ puts " - Ensure your OpenAPI paths match your Rails routes exactly"
122
+ puts " - Use {id} in OpenAPI for :id in Rails routes"
123
+ puts " - Create Jbuilder templates for API endpoints that need them"
124
+ puts " - Run 'DEBUG_OPENAPI_IMPORT=1 rake openapi:import[#{openapi_file}]' for detailed import logs"
125
+ end
126
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "rails-openapi-gen"
5
+ spec.version = "0.0.1"
6
+ spec.authors = ["myzkey"]
7
+ spec.email = ["myzkey.dev@example.com"]
8
+
9
+ spec.summary = "Rails comment-driven OpenAPI generator"
10
+ spec.description = "Generates OpenAPI specs from Rails apps by parsing routes, controllers, and view templates with @openapi comment annotations"
11
+ spec.homepage = "https://github.com/myzkey/rails-openapi-gen"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = ">= 2.7.0"
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = spec.homepage
17
+
18
+ spec.files = Dir.glob("lib/**/*") + Dir.glob("*.md") + Dir.glob("*.gemspec")
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "rails", ">= 6.0"
24
+ spec.add_dependency "parser", "~> 3.2"
25
+ spec.add_dependency "yaml", "~> 0.2"
26
+
27
+ spec.add_development_dependency "rspec", "~> 3.12"
28
+ spec.add_development_dependency "rubocop", "~> 1.50"
29
+ spec.add_development_dependency "rake", "~> 13.0"
30
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-openapi-gen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - myzkey
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-07-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: parser
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yaml
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.50'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.50'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '13.0'
97
+ description: Generates OpenAPI specs from Rails apps by parsing routes, controllers,
98
+ and view templates with @openapi comment annotations
99
+ email:
100
+ - myzkey.dev@example.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - CLAUDE.md
106
+ - README.md
107
+ - lib/rails_openapi_gen.rb
108
+ - lib/rails_openapi_gen/configuration.rb
109
+ - lib/rails_openapi_gen/engine.rb
110
+ - lib/rails_openapi_gen/generators/yaml_generator.rb
111
+ - lib/rails_openapi_gen/importer.rb
112
+ - lib/rails_openapi_gen/parsers/comment_parser.rb
113
+ - lib/rails_openapi_gen/parsers/comment_parsers/attribute_parser.rb
114
+ - lib/rails_openapi_gen/parsers/comment_parsers/base_attribute_parser.rb
115
+ - lib/rails_openapi_gen/parsers/comment_parsers/body_parser.rb
116
+ - lib/rails_openapi_gen/parsers/comment_parsers/conditional_parser.rb
117
+ - lib/rails_openapi_gen/parsers/comment_parsers/operation_parser.rb
118
+ - lib/rails_openapi_gen/parsers/comment_parsers/param_parser.rb
119
+ - lib/rails_openapi_gen/parsers/comment_parsers/query_parser.rb
120
+ - lib/rails_openapi_gen/parsers/controller_parser.rb
121
+ - lib/rails_openapi_gen/parsers/jbuilder_parser.rb
122
+ - lib/rails_openapi_gen/parsers/routes_parser.rb
123
+ - lib/rails_openapi_gen/parsers/template_processors/jbuilder_template_processor.rb
124
+ - lib/rails_openapi_gen/parsers/template_processors/response_template_processor.rb
125
+ - lib/rails_openapi_gen/railtie.rb
126
+ - lib/rails_openapi_gen/tasks/openapi.rake
127
+ - lib/rails_openapi_gen/version.rb
128
+ - lib/tasks/openapi_import.rake
129
+ - rails-openapi-gen.gemspec
130
+ homepage: https://github.com/myzkey/rails-openapi-gen
131
+ licenses:
132
+ - MIT
133
+ metadata:
134
+ homepage_uri: https://github.com/myzkey/rails-openapi-gen
135
+ source_code_uri: https://github.com/myzkey/rails-openapi-gen
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 2.7.0
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 3.3.26
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: Rails comment-driven OpenAPI generator
155
+ test_files: []