Last active
November 5, 2024 22:06
-
-
Save sulmanweb/70f8886ddcdef1fddb96f0b365946991 to your computer and use it in GitHub Desktop.
Generating a Markdown Documentation for Your Codebase with Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'fileutils' | |
ALWAYS_IGNORE = ['.git', 'tmp', 'log', '.ruby-lsp', '.github', '.devcontainer'].freeze | |
IGNORED_EXTENSIONS = %w[.jpg .jpeg .png .gif .bmp .svg .webp .ico .pdf .tiff .raw].freeze | |
def read_gitignore(directory_path) | |
gitignore_path = File.join(directory_path, '.gitignore') | |
return [] unless File.exist?(gitignore_path) | |
File.readlines(gitignore_path).map(&:chomp).reject(&:empty?) | |
end | |
def ignored?(path, base_path, ignore_patterns) | |
relative_path = path.sub("#{base_path}/", '') | |
# Check if the path starts with any of the ALWAYS_IGNORE directories | |
return true if ALWAYS_IGNORE.any? { |dir| relative_path.start_with?(dir + '/') || relative_path == dir } | |
# Check if the file has an ignored extension | |
return true if IGNORED_EXTENSIONS.include?(File.extname(path).downcase) | |
ignore_patterns.any? do |pattern| | |
File.fnmatch?(pattern, relative_path, File::FNM_PATHNAME | File::FNM_DOTMATCH) || | |
File.fnmatch?(File.join('**', pattern), relative_path, File::FNM_PATHNAME | File::FNM_DOTMATCH) | |
end | |
end | |
def convert_to_markdown(file_path) | |
extension = File.extname(file_path).downcase[1..] | |
format = extension.nil? || extension.empty? ? 'text' : extension | |
begin | |
content = File.read(file_path, encoding: 'UTF-8') | |
"# #{File.basename(file_path)}\n\n```#{format}\n#{content}\n```\n\n" | |
rescue StandardError => e | |
"# #{File.basename(file_path)}\n\n[File content not displayed: #{e.message}]\n\n" | |
end | |
end | |
def sanitize_anchor(text) | |
text.gsub(/[^a-zA-Z0-9\-_]/, '-').gsub(/-+/, '-').downcase | |
end | |
def process_directory(directory_path, output_file) | |
ignore_patterns = read_gitignore(directory_path) | |
markdown_content = "# File Documentation\n\n## Table of Contents\n\n" | |
file_contents = [] | |
Dir.glob("#{directory_path}/**/*", File::FNM_DOTMATCH).each do |file_path| | |
next if File.directory?(file_path) | |
next if ['.', '..'].include?(File.basename(file_path)) | |
next if ignored?(file_path, directory_path, ignore_patterns) | |
relative_path = file_path.sub("#{directory_path}/", '') | |
anchor = sanitize_anchor(relative_path) | |
markdown_content += "- [#{relative_path}](##{anchor})\n" | |
file_contents << "## #{relative_path}\n\n#{convert_to_markdown(file_path)}" | |
end | |
markdown_content += "\n---\n\n" + file_contents.join("\n---\n\n") | |
File.write(output_file, markdown_content) | |
puts "Markdown file created: #{output_file}" | |
end | |
# Check if correct number of arguments are provided | |
if ARGV.length != 2 | |
puts "Usage: ruby ruby_to_md.rb <input_directory> <output_file>" | |
exit 1 | |
end | |
input_directory = ARGV[0] | |
output_file = ARGV[1] | |
process_directory(input_directory, output_file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment