# coding: utf-8 # Copyright 2019 DragonRuby LLC # MIT License # docs.rb has been released under MIT (*only this file*). module DocsOrganizer def self.sort_docs_classes! $docs_classes.sort! do |l, r| l_index = (class_sort_order.find_index l) || 50000 r_index = (class_sort_order.find_index r) || 50000 l_index = 51000 if l == :docs_classes r_index = 51000 if r == :docs_classes l_index <=> r_index end end def self.reserved_methods [ :docs_export_docs!, :docs_all, :docs_method_sort_order, :docs_classes, :docs_search ] end def self.class_sort_order [ GTK::ReadMe, GTK::Runtime, Array, GTK::Args, GTK::Outputs, GTK::Mouse, GTK::OpenEntity, Numeric, Kernel, ] end def self.check_class_sort_order unsorted = $docs_classes.find_all do |klass| !class_sort_order.include? klass end unsorted.each do |k| puts <<-S * WARNING: #{klass.name} is not included in DocsOrganizer::class_sort_order. Please place this module in its correct topological order. S end if unsorted.length == 0 puts <<-S * INFO: Success. All documented classes have a sort order associated with them. S end end def self.sort_method_delegate l, r, method_sort_order l_index = (method_sort_order.find_index l) || 50000 r_index = (method_sort_order.find_index r) || 50000 l_index = 51000 if l == :docs_classes r_index = 51000 if r == :docs_classes l_index = -51000 if l == :docs_class r_index = -51000 if r == :docs_class l_index <=> r_index end def self.find_methods_with_docs klass klass_method_sort_order = klass.docs_method_sort_order klass.methods.find_all { |m| m.start_with? 'docs_' } .reject { |m| reserved_methods.include? m } .sort do |l, r| sort_method_delegate l, r, klass_method_sort_order end end end module Docs def self.extended klass $docs_classes ||= [] $docs_classes << klass $docs_classes.uniq! end def docs_method_sort_order [] end def docs_classes DocsOrganizer.sort_docs_classes! list = $docs_classes.map { |mod| "** #{mod.name}.docs" }.join "\n" <<-S * DOCS: Here are the classes that have documentation. You can call the .docs method on any of these classes: #{list} S end def docs_all docs_methods = DocsOrganizer.find_methods_with_docs(self).map { |d| send d }.join "\n" <<-S #{docs_methods} S end def docs docs_methods = [DocsOrganizer.find_methods_with_docs(self), :docs_classes].flatten.map { |d| "** #{self.name}.#{d}" }.join "\n" if self == Kernel <<-S * DOCS: #{self.name} Some Classes in Game Toolkit have a method called docs. You can invoke this method interactively to see information about functions within the engine. For example, invoking ~Kernel.docs_tick_count~ will give you documentation for the Kernel.tick_count method. To export all documentation you can use ~Kernel.export_docs!~ (or just ~export_docs!~). To search docs you can use Kernel.docs_search (or just `docs_search`) by providing it a search term. For example: #+begin_src docs_search "array find remove nil" #+end_src You can do more advanced searches by providing a block: #+begin_src docs_search do |entry| (entry.include? "Array") && (!entry.include? "Enumerable") end #+end_src #{docs_methods} ** NOTE: Invoke any of the methods above on #{self.name} to see detailed documentation. ** NOTE: Calling the docs_classes method will give you all classes in Game Toolkit that contain docs. S else <<-S * DOCS: #{self.name} #{docs_methods} S end end def self.__docs_search__ words = nil, &block end def __docs_search_help_text__ <<-S * DOCS: How To Search The Docs To search docs you can use Kernel.docs_search (or just ~docs_search~) by providing it a search term. For example: #+begin_src docs_search "array find remove nil" #+end_src You can do more advanced searches by providing a block: #+begin_src docs_search do |entry| (entry.include? "Array") && (!entry.include? "Enumerable") end #+end_src S end def __docs_search_results__ words = nil, &block words ||= "" if words.strip.length != 0 each_word = words.split(' ').find_all { |w| w.strip.length > 3 } block = lambda do |entry| each_word.any? { |w| entry.downcase.include? w.downcase } end end return [__docs_search_help_text__] if !block DocsOrganizer.sort_docs_classes! this_block = block search_results = [] if self == Kernel $docs_classes.each do |k| DocsOrganizer.find_methods_with_docs(k).each do |m| s = k.send m search_results << s if block.call s end end else DocsOrganizer.find_methods_with_docs(self).each do |m| s = send m search_results << s if block.call s end end search_results end def docs_search words = nil, &block results = __docs_search_results__ words, &block final_string = results.join "\n" final_string = "* DOCS: No results found." if final_string.strip.length == 0 $gtk.write_file_root "docs/search_results.txt", final_string if !final_string.include? "* DOCS: No results found." log "* INFO: Search results have been written to docs/search_results.txt." end "\n" + final_string end def __export_docs__! opts = {} DocsOrganizer.sort_docs_classes! opts = defaults_export_docs!.merge opts opts[:methods] = methods_with_docs.reject { |m| m == :docs_classes } if opts[:methods].include? :all content = opts[:methods].map do |m| puts "* INFO: Getting docs for #{m}." (send m).ltrim + "\n" end.join "\n" file_path = "docs/#{self.name}.txt" $gtk.write_file_root "#{file_path}", content puts "* INFO: Documentation for #{self.name} has been exported to #{file_path}." $gtk.console.set_system_command file_path nil end def export_docs! opts = {} __export_docs__! opts end def __docs_append_true_line__ true_lines, true_line, parse_log true_line.rstrip! parse_log << "*** True Line Result\n#{true_line}" true_lines << true_line end # may god have mercy on your soul if you try to expand this def __docs_to_html__ string parse_log = [] html_start_to_toc_start = <<-S
'
elsif l.start_with? "#+end_src"
parse_log << "- PRE end detected."
inside_ol = false
inside_ul = false
inside_pre = false
content_html << "\n"
elsif l.start_with? "#+begin_quote"
parse_log << "- BLOCKQUOTE start detected."
content_html += close_list_if_needed.call inside_ul, inside_ol
inside_ol = false
inside_ul = false
content_html << "\n" elsif l.start_with? "#+end_quote" parse_log << "- BLOCKQUOTE end detected." content_html << "\n" elsif (l.start_with? "1. ") && !inside_ol parse_log << "- OL start detected." parse_log << "- LI detected." inside_ol = true content_html << "
\n#{__docs_line_to_html__ l, parse_log}\n
\n" end end end toc_html += "" final_html = html_start_to_toc_start + toc_html + html_toc_end_to_content_start + content_html + html_content_end_to_html_end { original: string, html: final_html, parse_log: parse_log } rescue Exception => e $gtk.write_file_root 'docs/parse_log.txt', (parse_log.join "\n") raise "* ERROR in Docs::__docs_to_html__. #{e}" end def __docs_line_to_html__ line, parse_log parse_log << "- Determining if line is a header." if line.start_with? "**** " line = line.gsub "**** ", "" parse_log << "- Line contains ~**** ~... gsub-ing empty string" elsif line.start_with? "*** " line = line.gsub "*** ", "" parse_log << "- Line contains ~*** ~... gsub-ing empty string" elsif line.start_with? "** " line = line.gsub "** ", "" parse_log << "- Line contains ~** ~... gsub-ing empty string" elsif line.start_with? "* " line = line.gsub "* ", "" parse_log << "- Line contains ~* ~... gsub-ing empty string" elsif line.start_with? "* DOCS: " line = line.gsub "* DOCS: ", "" parse_log << "- Line contains ~* DOCS:~... gsub-ing empty string" else parse_log << "- Line does not appear to be a header." end tilde_count = line.count "~" line_has_link_marker = (line.include? "[[") && (line.include? "]]") parse_log << "- Formatting line: ~#{line}~" parse_log << "- Line's tilde count is: #{tilde_count}" parse_log << "- Line contains link marker: #{line_has_link_marker}" line_to_format = line.rstrip # logic
if tilde_count.even? && tilde_count != 0
parse_log << "- CODE detected."
temp = line_to_format
line_to_format = ""
in_literal = false
in_code = false
temp.each_char do |c|
if c == "~" && !in_code
in_code = true
line_to_format << ""
elsif c == "~" && in_code
line_to_format << ""
in_code = false
else
line_to_format << c
end
end
end
# and
logic
if line_has_link_marker
line_to_format = line_to_format.gsub "[[", "["
line_to_format = line_to_format.gsub "]]", "]"
parse_log << "- LINK detected."
temp = line_to_format
line_to_format = ""
in_literal = false
in_link = false
link_url = ""
temp.each_char.with_index do |c, i|
next_c = temp[i + 1]
if !in_link && c == "["
in_link = true
link_url = ""
elsif in_link && c == "]"
in_link = false
if link_url.end_with? ".gif"
line_to_format << "
"
else
line_to_format << "#{link_url}"
end
elsif in_link
link_url << c
else
line_to_format << c
end
end
end
return line_to_format
rescue Exception => e
parse_log << "* ERROR: Failed to parse line: ~#{line}~, #{e}"
return line.rstrip
end
end