From 6f4f3485a4939edfb3c7c658b3510f49806ac741 Mon Sep 17 00:00:00 2001 From: Mathieu PATUREL Date: Sun, 29 Jul 2018 16:56:35 -0400 Subject: [PATCH] Add pygame documentation --- lib/docs/filters/pygame/clean_html.rb | 104 ++++++++++++++++++++++++++ lib/docs/filters/pygame/entries.rb | 35 +++++++++ lib/docs/scrapers/pygame.rb | 26 +++++++ public/icons/docs/pygame/16.png | Bin 0 -> 6782 bytes public/icons/docs/pygame/16@2x.png | Bin 0 -> 10305 bytes 5 files changed, 165 insertions(+) create mode 100644 lib/docs/filters/pygame/clean_html.rb create mode 100644 lib/docs/filters/pygame/entries.rb create mode 100644 lib/docs/scrapers/pygame.rb create mode 100644 public/icons/docs/pygame/16.png create mode 100644 public/icons/docs/pygame/16@2x.png diff --git a/lib/docs/filters/pygame/clean_html.rb b/lib/docs/filters/pygame/clean_html.rb new file mode 100644 index 00000000..5e81fe2c --- /dev/null +++ b/lib/docs/filters/pygame/clean_html.rb @@ -0,0 +1,104 @@ +module Docs + class Pygame + class CleanHtmlFilter < Filter + def call + + @doc = at_css '.body' + + if root_page? + # remove unneeded stuff + at_css('.modindex-jumpbox').remove + css('[role="navigation"],.pcap, .cap, .footer').each do |node| + node.remove + end + # table -> list + list = at_css('table') + list.replace(list.children) + list.name = 'ul' + css('tr').each do |row| + row.name = 'li' + row['class'] = '' + end + return doc + end + + # remove unwanted stuff + # .headerlink => ΒΆ after links + # .toc => table of content + # .tooltip-content => tooltips after links to functions + if toremove = css('table.toc.docutils, .headerlink, .tooltip-content') + toremove.each do |node| + node.remove + end + end + + # Remove wrapper .section + section = at_css('.section') + definition = at_css('.definition') + definition['id'] = section['id'] + section.replace(section.children) + + # Format code for it be highlighted + css('.highlight-default.notranslate').each do |node| + pre = node.at_css('pre') + node.replace(pre) + # gets rid of the already existing syntax highlighting + pre.inner_html = pre.inner_text + pre['class'] = 'language-python' + pre['data-language'] = "python" + end + + # change descriptions of functions/attributes to blockquote + css('.line-block').each do |node| + node.name = 'blockquote' + end + + # change functions + css('.definition').each do |d| + + # the header is the function/attribute name. It might look something like + # this: + # pygame.image.load() + # It'll end up being something like this: + # pygame.image.load(filename) -> Surface + # pygame.image.load(fileobj, namehint="") -> Surface + + header = d.at_css('dt.title') + if d['class'].include?('class') or d['class'].include?('module') + header.name = 'h1' + @section = header.content.strip + else + header.name = 'h3' + end + # save the original header + initial_header = header.content.strip + # save the real name for the entries + header['data-name'] = initial_header + # empty the header + if header.name == 'h3' + header.inner_html = '' + end + # to replace it with the signatures + next_el = header.next_element + signatures = next_el.css('.signature') + signatures.each do |sig| + sig.name = 'code' + if header.name == 'h3' + sig.parent = header + # the signature don't contain pygame.module. I think it's better + # to display them, as it avoids confusion with methods (have a + # look at the pygame.Rect page) + if initial_header.start_with?(@section) + sig.content = @section + '.' + sig.text + end + # seperate the signatures on different lines. + header.add_child "
" + end + end + end + + doc + end + end + end +end diff --git a/lib/docs/filters/pygame/entries.rb b/lib/docs/filters/pygame/entries.rb new file mode 100644 index 00000000..5d589a63 --- /dev/null +++ b/lib/docs/filters/pygame/entries.rb @@ -0,0 +1,35 @@ +module Docs + class Pygame + class EntriesFilter < Docs::EntriesFilter + def get_name + return 'pygame' + end + + def get_type + at_css('h1').content + end + + def include_default_entry? + return false + end + + def additional_entries + return ['pygame'] if root_page? + + entries = [] + css('h1,h2,h3').each do |node| + parentclass = node.parent['class'] + name = node['id'] + if not name + name = node['data-name'] + elsif parentclass.include?('function') or parentclass.include?('method') + name += '()' + end + name = name.sub('pygame.', '') + entries << [name, node['id'], nil] + end + entries + end + end + end +end diff --git a/lib/docs/scrapers/pygame.rb b/lib/docs/scrapers/pygame.rb new file mode 100644 index 00000000..8dcc4515 --- /dev/null +++ b/lib/docs/scrapers/pygame.rb @@ -0,0 +1,26 @@ +module Docs + class Pygame < UrlScraper + + self.type = 'simple' + + self.release = 'v1.9.4.dev0' + + self.initial_paths = ['py-modindex.html'] + self.base_url = 'https://www.pygame.org/docs/' + self.root_path = 'py-modindex.html' + self.initial_paths = [] + + self.links = { + home: 'https://www.pygame.org/', + code: 'https://github.com/pygame/pygame' + } + + html_filters.push 'pygame/clean_html', 'pygame/entries' + + options[:only_patterns] = [/ref\//] + + options[:attribution] = <<-HTML + © Pygame Developpers. + HTML + end +end diff --git a/public/icons/docs/pygame/16.png b/public/icons/docs/pygame/16.png new file mode 100644 index 0000000000000000000000000000000000000000..f6edae5900951559787169e71bed46ea86cc324e GIT binary patch literal 6782 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 Nxj49!Pb^=T@IUEajA;M> literal 0 HcmV?d00001 diff --git a/public/icons/docs/pygame/16@2x.png b/public/icons/docs/pygame/16@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9ef9a9e713961590bcc26fbec51230a6b5ffa34c GIT binary patch literal 10305 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