import os import shutil from types import FileType from jinja2 import Environment, FileSystemLoader from typedecorator import params, returns from parser import ClassParser, MethodDoc import glob @returns([(str, FileType)]) @params(search_path=str) def find_class_files(search_path): """Find and open all files containing Eluna class methods in `search_path`. :param search_path: the path to search for Eluna methods in :return: a list of all files containing Eluna methods, and the name of their respective classes """ # Get the current working dir and switch to the search path. old_dir = os.getcwd() os.chdir(search_path) # Search for all files ending in "Methods.h". method_file_names = glob.glob('*Methods.h') # Open each file. method_files = [open(file_name, 'r') for file_name in method_file_names] # Go back to where we were before. os.chdir(old_dir) return method_files def make_renderer(template_path, link_parser_factory): """Return a function that can be used to render Jinja2 templates from the `template_path` directory.""" # Set up jinja2 environment to load templates from the templates folder. env = Environment(loader=FileSystemLoader(template_path), extensions=['jinja2.ext.with_']) def inner(template_name, output_path, level, **kwargs): env.filters['parse_links'], env.filters['parse_data_type'] = link_parser_factory(level) template = env.get_template(template_name) static = make_static(level) root = make_root(level) with open('build/' + output_path, 'w') as out: out.write(template.render(static=static, root=root, **kwargs)) return inner def make_static(level): return lambda file_name: ('../' * level) + 'static/' + file_name def make_root(level): return lambda file_name: ('../' * level) + file_name if __name__ == '__main__': # Recreate the build folder and copy static files over. if os.path.exists('build'): shutil.rmtree('build') os.mkdir('build') shutil.copytree('ElunaDoc/static', 'build/static') # Load up all files with methods we need to parse. print 'Finding Eluna method files...' class_files = find_class_files('../') # Parse all the method files. classes = [] for f in class_files: print 'Parsing file {}...'.format(f.name) classes.append(ClassParser.parse_file(f)) f.close() # Sort the classes so they are in the correct order in lists. classes.sort(key=lambda c: c.name) def make_parsers(level): """Returns a function that parses content for refs to other classes, methods, or enums, and automatically inserts the correct link. """ # Make lists of all class names and method names. class_names = [] method_names = [] for class_ in classes: class_names.append('&' + class_.name) for method in class_.methods: method_names.append('&' + class_.name + ':' + method.name) def link_parser(content): # Split the content into small tokens. tokens = content.split() # The content will be reassembled from the parsed tokens. content = '' for token in tokens: # Ignore tokens that don't start with "&". if not token.startswith('&'): content += token + ' ' continue # Try to find a matching class. for class_name in class_names: if token.startswith(class_name): # Take the "&" off the front of the token and class's name. token = token[len('&'):] class_name = class_name[len('&'):] url = '{}{}/index.html'.format(('../' * level), class_name) token = '{}'.format(url, token) break # No matching class, try to find a method. else: for method_name in method_names: if token.startswith(method_name): # Take the "amp;" off the front of the token. full_name = token[len('&'):] # Split "Class:Method" into "Class" and "Method". class_name, method_name = method_name.split(':') url = '{}{}/{}.html'.format(('../' * level), class_name, method_name) token = '{}'.format(url, full_name) break content += token + ' ' return content[:-1] # Strip off the last space. # Links to the "Programming in Lua" documentation for each Lua type. lua_type_documentation = { 'nil': 'http://www.lua.org/pil/2.1.html', 'boolean': 'http://www.lua.org/pil/2.2.html', 'number': 'http://www.lua.org/pil/2.3.html', 'string': 'http://www.lua.org/pil/2.4.html', 'table': 'http://www.lua.org/pil/2.5.html', 'function': 'http://www.lua.org/pil/2.6.html', } def data_type_parser(content): # If the type is a Lua type, return a link to Lua documentation. if content in lua_type_documentation: url = lua_type_documentation[content] return '{}'.format(url, content) # Otherwise try to build a link to the proper page. if content in class_names: class_name = content[len('&'):] url = '{}{}/index.html'.format(('../' * level), class_name) return '{}'.format(url, class_name) return link_parser, data_type_parser # Create the render function with the template path and parser maker. render = make_renderer('ElunaDoc/templates', make_parsers) # Render the index. render('index.html', 'index.html', level=0, classes=classes) # Render the search index. render('search-index.js', 'search-index.js', level=0, classes=classes) for class_ in classes: print 'Rending pages for class {}...'.format(class_.name) # Make a folder for the class. os.mkdir('build/' + class_.name) index_path = '{}/index.html'.format(class_.name) # Render the class's index page. render('class.html', index_path, level=1, classes=classes, current_class=class_) # Render each method's page. for method in class_.methods: method_path = '{}/{}.html'.format(class_.name, method.name) render('method.html', method_path, level=1, current_class=class_, current_method=method)