mirror of
https://github.com/zhigang1992/RubyMotion.git
synced 2026-04-13 22:45:27 +08:00
add doc generator
This commit is contained in:
174
doc/Rakefile
174
doc/Rakefile
@@ -1,11 +1,177 @@
|
||||
platforms_dir = ENV['platforms_dir']
|
||||
sdk_version = ENV['sdk_version']
|
||||
DOCSET_PATHS = %w{
|
||||
/Library/Developer/Documentation/DocSets/com.apple.adc.documentation.AppleiOS4_3.iOSLibrary.docset/Contents/Resources/Documents/documentation/UIKit/Reference
|
||||
/Library/Developer/Documentation/DocSets/com.apple.adc.documentation.AppleiOS4_3.iOSLibrary.docset/Contents/Resources/Documents/documentation/Cocoa/Reference
|
||||
}
|
||||
|
||||
class DocGenerator
|
||||
require 'rubygems'
|
||||
require 'nokogiri'
|
||||
require 'fileutils'
|
||||
|
||||
def parse_html_docref(node)
|
||||
code = ''
|
||||
code << node.xpath(".//p[@class='abstract']").text
|
||||
code << "\n"
|
||||
code << node.xpath(".//div[@class='api discussion']").text.sub(/^Discussion/, '')
|
||||
|
||||
code.strip!
|
||||
code.gsub!(/^/m, ' # ')
|
||||
code << "\n"
|
||||
return code
|
||||
end
|
||||
|
||||
def parse_type(type)
|
||||
type = type.to_s
|
||||
type.strip!
|
||||
star = type.sub!(/\s*\*$/, '') # Remove pointer star.
|
||||
case type
|
||||
when /\*$/
|
||||
# A double pointer, in MacRuby this becomes a Pointer.
|
||||
'Pointer'
|
||||
when 'id'
|
||||
'Object'
|
||||
when 'void'
|
||||
'nil'
|
||||
when 'SEL'
|
||||
'Symbol'
|
||||
when 'bool', 'BOOL'
|
||||
'Boolean'
|
||||
when 'float', 'double', 'CGFloat'
|
||||
'Float'
|
||||
when 'int', 'short', 'long', 'long long', 'NSInteger', 'NSUInteger'
|
||||
'Integer'
|
||||
when 'NSString', 'NSMutableString'
|
||||
'String'
|
||||
when 'NSArray', 'NSMutableArray'
|
||||
'Array'
|
||||
when 'NSDictionary', 'NSMutableDictionary'
|
||||
'Hash'
|
||||
else
|
||||
type
|
||||
end
|
||||
end
|
||||
|
||||
def parse_html_class(name, doc)
|
||||
# Find superclass (mandatory).
|
||||
sclass = nil
|
||||
doc.xpath("//table[@class='specbox']/tr").each do |node|
|
||||
if md = node.text.match(/Inherits from([^ ]+)/)
|
||||
sclass = md[1]
|
||||
break
|
||||
end
|
||||
end
|
||||
return nil unless sclass
|
||||
|
||||
code = doc.xpath(".//p[@class='abstract']")[0].text
|
||||
code.gsub!(/^/m, '# ')
|
||||
code << "\nclass #{name} < #{sclass}\n\n"
|
||||
|
||||
# Properties.
|
||||
doc.xpath("//div[@class='api propertyObjC']").each do |node|
|
||||
decl = node.xpath(".//div[@class='declaration']/div[@class='declaration']").text
|
||||
readonly = decl.include?('readonly')
|
||||
decl.sub!(/@property\s*(\([^\)]+\))?/, '')
|
||||
md = decl.match(/(\w+)$/)
|
||||
next unless md
|
||||
title = md[1]
|
||||
type = md.pre_match
|
||||
|
||||
code << parse_html_docref(node)
|
||||
code << " # @return [#{parse_type(type)}]\n"
|
||||
code << ' ' << (readonly ? "attr_reader" : "attr_accessor") << " :#{title}\n\n"
|
||||
end
|
||||
|
||||
# Methods.
|
||||
methods = []
|
||||
methods.concat(doc.xpath("//div[@class='api classMethod']"))
|
||||
methods.concat(doc.xpath("//div[@class='api instanceMethod']"))
|
||||
methods.each do |node|
|
||||
decl = node.xpath(".//div[@class='declaration']").text
|
||||
types = decl.scan(/\(([^)]+)\)/)
|
||||
ret_type = types.shift
|
||||
|
||||
# Docref.
|
||||
code << parse_html_docref(node)
|
||||
|
||||
# Parameters and return value.
|
||||
arg_names = node.xpath(".//div[@class='api parameters']//dt")
|
||||
arg_docs = node.xpath(".//div[@class='api parameters']//dd")
|
||||
if arg_names.size == arg_docs.size
|
||||
has_types = types.size == arg_names.size
|
||||
arg_names.each_with_index do |arg_name, i|
|
||||
arg_doc = arg_docs[i]
|
||||
code << " # @param "
|
||||
code << "[#{parse_type(types[i])}] " if has_types
|
||||
code << "#{arg_name.text} #{arg_doc.text}\n"
|
||||
end
|
||||
end
|
||||
retdoc = node.xpath(".//div[@class='return_value']/p").text.strip
|
||||
code << " # @return "
|
||||
code << "[#{parse_type(ret_type)}] " if ret_type
|
||||
code << "#{retdoc}" unless retdoc.empty?
|
||||
code << "\n"
|
||||
|
||||
is_class_method = decl.match(/^\s*\+/) != nil
|
||||
decl.sub!(/^\s*[\+\-]/, '') # Remove method qualifier.
|
||||
sel_parts = decl.gsub(/\([^)]+\)/, '').split.map { |x| x.split(':') }
|
||||
head = sel_parts.shift
|
||||
code << " def #{is_class_method ? 'self.' : ''}#{head[0]}("
|
||||
code << "#{head[1]}" if head.size > 1
|
||||
unless sel_parts.empty?
|
||||
code << ', '
|
||||
code << sel_parts.map { |part| "#{part[0]}:#{part[1]}" }.join(', ')
|
||||
end
|
||||
code << "); end\n\n"
|
||||
end
|
||||
|
||||
code << "end"
|
||||
return code
|
||||
end
|
||||
|
||||
def parse_html_data(data)
|
||||
doc = Nokogiri::HTML(data)
|
||||
title = doc.xpath('/html/head/title')
|
||||
if title and md = title.text.match(/^(.+)Class Reference$/)
|
||||
parse_html_class(md[1].strip, doc)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(paths)
|
||||
@input_paths = []
|
||||
paths.each do |path|
|
||||
if File.directory?(path)
|
||||
@input_paths.concat(Dir.glob(path + '/**/*.html'))
|
||||
else
|
||||
@input_paths << path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
rb_files_dir = '/tmp/rb_docset'
|
||||
FileUtils.rm_rf(rb_files_dir)
|
||||
FileUtils.mkdir_p(rb_files_dir)
|
||||
|
||||
@input_paths.map { |path| parse_html_data(File.read(path)) }.compact.each_with_index do |code, n|
|
||||
File.open(File.join(rb_files_dir, "t#{n}.rb"), 'w') do |io|
|
||||
io.write(code)
|
||||
end
|
||||
end
|
||||
|
||||
sh "yard doc #{rb_files_dir}"
|
||||
sh "mv doc html"
|
||||
end
|
||||
end
|
||||
|
||||
task :default => :all
|
||||
task :all do
|
||||
# TODO
|
||||
if !File.exist?('html')
|
||||
DocGenerator.new(DOCSET_PATHS).run
|
||||
end
|
||||
end
|
||||
|
||||
task :clean do
|
||||
# TODO
|
||||
rm_rf 'html'
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user