require "erb" require "fileutils" class Frappuccino attr_writer :files, :documentations, :doctree, :title def initialize title, files if File.directory? files docfiles = [] Dir.glob("#{files}/*").each do |file| docfiles.push(file) unless File.directory? file end files = docfiles end @files = files @documentations = [] @doctree = {:namespaces => {}} @title = title iterate_files documentations_to_doctree # sort alphabetically @doctree[:namespaces] = @doctree[:namespaces].sort_by {|k,v| k} generate_html end def iterate_files for file in @files File.open(file) do |opened_file| puts "* Parsing documentation from #{file}" collect_documentation opened_file end end end # parses documentation bodies def collect_documentation opened_file doc_start = false current_documentation = [] opened_file.each_line do |line| # documentation starts here if line.include?("###") and !doc_start doc_start = true # documentation ends here elsif line.include?("###") and doc_start @documentations.push current_documentation current_documentation = [] doc_start = false # in the middle of documentation elsif doc_start current_documentation.push line end end end def documentations_to_doctree @documentations.each do |docbody| doctree_format docbody end end # transforms array of strings to doctree hash def doctree_format docbody doctree = {} value_regexp = /^.*:\s(.*)/ namespace_arr = [] namespace_tree = {} function_name = nil object_name = nil description = "" rest_is_description = false docbody.each do |line| if line.match(/^\s*function/) function_name = line.match(value_regexp)[1] elsif line.match(/^\s*object/) object_name = line.match(value_regexp)[1] elsif line.match(/^\s*description/) rest_is_description = true elsif line.match(/^\s*namespace/) namespace_arr = line.match(value_regexp)[1].split(".") elsif rest_is_description description += line end end full_namespace = namespace_arr.join(".") if !function_name.nil? docdata = {:full_namespace => full_namespace, :functions => [{:function_name => function_name, :description => description}]} elsif !object_name.nil? docdata = {:full_namespace => full_namespace, :objects => [{:object_name => object_name, :description => description}]} else if rest_is_description docdata = {:full_namespace => full_namespace, :description => description} else docdata = {:full_namespace => full_namespace} end end namespace_is_added = false @doctree[:namespaces].each do |key, value| namespace_is_added = true if key == full_namespace end if namespace_is_added @doctree[:namespaces][full_namespace] = deep_safe_merge(@doctree[:namespaces][full_namespace], docdata) else @doctree[:namespaces][full_namespace] = docdata end end def generate_html template = ERB.new File.new("#{File.dirname(__FILE__)}/../template/index.erb").read rendered_template = template.result(binding) FileUtils.mkdir "docs" unless File.directory? "docs" File.open("docs/index.html", "w") do |f| f.write rendered_template end FileUtils.cp("#{File.dirname(__FILE__)}/../template/bg.png", "docs/bg.png") puts "* Documentation file generated (docs/index.html)" end # helpers: def deep_safe_merge(source_hash, new_hash) source_hash.merge(new_hash) do |key, old, new| if new.respond_to?(:blank) && new.blank? old elsif (old.kind_of?(Hash) and new.kind_of?(Hash)) deep_merge(old, new) elsif (old.kind_of?(Array) and new.kind_of?(Array)) old.concat(new).uniq else new end end end end