def test_node_depth_of_with_file(isfile): ("Node#depth_of(path) should return the approriate number") isfile.return_value = True Node("/foo/bar/").depth_of("/foo/bar/another/dir/file.py").should.equal(2) Node("/foo/bar").depth_of("/foo/bar/another/dir/file.py").should.equal(2) Node("/foo/bar//").depth_of("/foo/bar/another/dir/file.py").should.equal(2)
def test_cd_enters_a_path_and_returns_a_node_representing_it_abs(exists): ("Node#cd should return a node representing the given path. " "Testing with absolute path") nd = Node("/foo/bar/") other = nd.cd("/etc/") other.path.should.equal('/etc')
def test_open(io): ("Node#open should return an open file") io.open.return_value = 'an open file' nd = Node('/foo/bar') nd.open('wee.py').should.equal('an open file') io.open.assert_once_called_with('/foo/bar/wee.py')
def test_node_could_be_updated_by_false(exists): ("Node#could_be_updated_by returns False if given " "node has an older modification time") nd = Node(__file__) nd.metadata.mtime = 1000 other = Mock() other.metadata.mtime = 0 nd.could_be_updated_by(other).should.be.false
def test_node_list(os): ("Node#list should return a list containing one node " "per file found inside of the current node") os.listdir.return_value = ['/foo/bar/items/whatever.py'] nd = Node('/foo/bar/items/') nd.list().should.have.length_of(1) os.listdir.assert_once_called_with('/foo/bar/items')
def test_contains_checks_if_path_exists(exists): ("Node#cd should return a node representing the given path.") exists.return_value = True nd = Node("/foo/bar/") nd.contains("file.py").should.be.truthy exists.assert_has_calls([ call('/foo/bar/file.py'), ]) exists.call_count.should.equal(1)
def generate_index(event, args, project, theme, generated): destination = Node(args.OUTPUT) index = project.meta['documentation']['index'] if index.lower().strip() == 'index.md': return renamed = re.sub(r'[.](md|markdown)$', '.html', index, re.I) src = destination.join(renamed) dst = destination.join('index.html') copy2(src, dst)
def test_trip_at_when_not_lazy_absolute(os): ("Node#trip_at(path, lazy=False) returns a list when lazy=False " "(testing with absolute path)") os.walk.return_value = [ ("/dummy/", [], ["file1.py", "file2.py"]), ] nd = Node("/foo/bar/") nd.trip_at('/dummy/', lazy=False).should.equal([ "/dummy/file1.py", "/dummy/file2.py", ])
def test_trip_at_when_not_lazy_relative(os): ("Node#trip_at(path, lazy=False) returns a list when lazy=False " "(testing with relative path)") os.walk.return_value = [ ("/foo/bar/somewhere", [], ["file1.py", "file2.py"]), ] nd = Node("/foo/bar/") nd.trip_at('somewhere', lazy=False).should.equal([ "/foo/bar/somewhere/file1.py", "/foo/bar/somewhere/file2.py", ])
def test_find_greps_and_get_the_first_one_none(exists): ('Node#find returns the None if nothing is found') nd = Node('/foo/bar') nd.walk = Mock() nd.walk.return_value = [ "/foo/wisdom/aaa.py", "/foo/wisdom/bbb.txt", "/foo/wisdom/ccc.php", "/foo/wisdom/ddd.py", ] ret = nd.find('^$') ret.should.be.none nd.walk.assert_once_called_with(lazy=True)
def test_trip_at_when_lazy_relative(os): ("Node#trip_at(path, lazy=True) returns a generator when lazy=True " "(testing with relative path)") os.walk.return_value = [ ("/dummy/", [], ["file1.py", "file2.py"]), ] nd = Node("/foo/bar/") nd.trip_at('/dummy/', lazy=True).should.be.a('types.GeneratorType') list(nd.trip_at('/dummy/', lazy=True)).should.equal([ "/dummy/file1.py", "/dummy/file2.py", ])
def test_find_greps_and_get_the_first_one(exists): ('Node#find returns the first result from grep when found') nd = Node('/foo/bar') nd.walk = Mock() nd.walk.return_value = [ "/foo/wisdom/aaa.py", "/foo/wisdom/bbb.txt", "/foo/wisdom/ccc.php", "/foo/wisdom/ddd.py", ] ret = nd.find('[.]\w{3}$') ret.should.be.a(Node) ret.should.equal(Node("/foo/wisdom/bbb.txt")) nd.walk.assert_once_called_with(lazy=True)
def test_node_path_to_related(): ("Node#path_to_related(path) should return the approriate path") source_path = L('sandbox_simple/img/logo.png') requesting_path = L('sandbox_simple/index.md') result = Node(source_path).path_to_related(requesting_path) result.should.equal("./img/logo.png")
def test_node_non_existing_path_to_related(): ("Node#path_to_related(path) should return the approriate path" "even when it does not exist") source_path = L('sandbox_simple/img/404.png') requesting_path = L('sandbox_simple/index.markdown') result = Node(source_path).path_to_related(requesting_path) result.should.equal("./img/404.png")
def test_node_path_to_related_in_subtree(): ("Node#path_to_related(path) should return the " "approriate number when in a subtree") source_path = L('sandbox_simple/img/logo.png') requesting_path = L('sandbox_simple/docs/strings.md') result = Node(source_path).path_to_related(requesting_path) result.should.equal("../img/logo.png")
def test_node_path_to_related_in_subtree_deep_in_it(): ("Node#path_to_related(path) should return the " "approriate number when really deep in a subtree") source_path = L('sandbox_simple/img/logo.png') requesting_path = L('sandbox_simple/docs/even/deeper/item.md') result = Node(source_path).path_to_related(requesting_path) result.should.equal("../../../img/logo.png")
def test_node_non_existing_path_to_related_in_subtree(): ("Node#path_to_related(path) should return the " "approriate number when in a subtree" "even when it does not exist") source_path = L('sandbox_simple/img/404.png') requesting_path = L('sandbox_simple/docs/strings.markdown') result = Node(source_path).path_to_related(requesting_path) result.should.equal("../img/404.png")
def save_sitemap(event, args, project, theme, generated): if not args.SITEMAP_PREFIX: return urlset = etree.Element("urlset") destination = Node(args.OUTPUT) NAME = 'sitemap.xml' for item in filter(lambda x: x.endswith('html'), generated): relative = destination.relative(item) url = etree.SubElement(urlset, "url") loc = etree.SubElement(url, "loc") loc.text = "{0}/{1}".format( args.SITEMAP_PREFIX.rstrip('/'), relative, ) with destination.open(NAME, 'w') as f: f.write(etree.tostring(urlset, pretty_print=True).decode('utf-8'))
def test_node_depth_of(): ("Node#depth_of(path) should return the approriate number") path = L() (Node(path).depth_of(L('sandbox_simple/img/logo.png')).should.equal(2)) (Node(path).depth_of(L('sandbox_simple/img/')).should.equal(2)) (Node(path).depth_of(L('sandbox_simple/img')).should.equal(2)) path = L().rstrip('/') (Node(path).depth_of(L('sandbox_simple/img/logo.png')).should.equal(2)) (Node(path).depth_of(L('sandbox_simple/img/')).should.equal(2)) (Node(path).depth_of(L('sandbox_simple/img')).should.equal(2)) path = L() + "///" (Node(path).depth_of(L('sandbox_simple/img/logo.png')).should.equal(2)) (Node(path).depth_of(L('sandbox_simple/img/')).should.equal(2)) (Node(path).depth_of(L('sandbox_simple/img')).should.equal(2))
def test_walk_trips_at_node_path(): ("Node#walk() trips at node.path") nd = Node("/foo/bar/") nd.trip_at = Mock() nd.walk() nd.walk(lazy=True) nd.trip_at.assert_has_calls([ call('/foo/bar', lazy=False), call('/foo/bar', lazy=True), ])
def test_glob_filters_results_from_walk_using_fnmatch_nonlazy(exists): ('Node#glob returns an evaluated list of nodes') nd = Node('/foo/bar') nd.walk = Mock() nd.walk.return_value = [ "/foo/wisdom/aaa.py", "/foo/wisdom/bbb.txt", "/foo/wisdom/ccc.php", "/foo/wisdom/ddd.py", ] ret = nd.glob('*.py', lazy=False) ret.should.be.a(list) ret.should.equal([ Node("/foo/wisdom/aaa.py"), Node("/foo/wisdom/ddd.py"), ]) nd.walk.assert_once_called_with(lazy=False)
def test_glob_filters_results_from_walk_using_fnmatch(exists): ('Node#glob returns a lazy list of nodes') nd = Node('/foo/bar') nd.walk = Mock() nd.walk.return_value = [ "/foo/wisdom/aaa.py", "/foo/wisdom/bbb.txt", "/foo/wisdom/ccc.php", "/foo/wisdom/ddd.py", ] ret = nd.glob('*.py', lazy='passed-to-walk') ret.should.be.a('types.GeneratorType') list(ret).should.equal([ Node("/foo/wisdom/aaa.py"), Node("/foo/wisdom/ddd.py"), ]) nd.walk.assert_once_called_with(lazy='passed-to-walk')
def test_node_dir_when_is_dir(): ("Node#dir should return itself when the current " "node is pointing to a file") nd = Node('/foo/bar/items/') nd.dir.path.should.equal('/foo/bar/items')
def server(source_path, theme): current_dir = os.path.abspath(source_path) current_node = Node(current_dir) static_url_path = '/raw' app = Flask(__name__, static_folder=current_dir, static_url_path=static_url_path) app.secret_key = uuid.uuid4().hex def url_prefix_callback(link, current_document_info): target = link.lower() if target.endswith(".md") or target.endswith(".markdown"): return link else: return "{0}/{1}".format(static_url_path, link.lstrip('/')) def link(path, current_document_info): if path.endswith('.md') or path.endswith('.markdown'): return url_for('.render_path', path=path) else: found = current_node.cd(path) relative_path = current_node.relative(found.path) return '/raw/{0}'.format(relative_path) def static_url_callback(path, current_document_info): if theme.node.find(path): return '/assets/{0}'.format(path) return '/raw/{0}'.format(path) @app.before_request def get_project(): g.project = Project.discover(current_dir) @app.context_processor def inject_basics(): return {'server_mode': True} @app.route("/") def index(): return redirect( url_for('.render_path', path=g.project.meta['documentation']['index'])) @app.route("/preview/<path:path>") def render_path(path): items = list( g.project.generate(theme, static_url_cb=static_url_callback, link_cb=link)) for generated in items: print "." * 10 print if generated['relative_path'].endswith(path): return Response(generated['html']) print len(items) return Response('not found', status=404) @app.route("/assets/<path:path>") def serve_asset(path): contenttype = mimetypes.guess_type(path)[0] with open(theme.static_file(path)) as f: data = f.read() return Response(data, mimetype=contenttype) return app
#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import unicode_literals import os import sys import time import requests from markment.fs import Node from markment.ui import Theme from markment.server import server local_node = Node(__file__).dir themes = [x.dir for x in reversed(local_node.parent.cd('markment/themes').grep('markment.yml'))] output_path = local_node.join('_output') for t in themes: print t.basename
from markment.events import before, after from markment.plugins.couleur_output import * from markment.version import version LOGO = """ _ _ _ __ ___ __ _ _ __| | ___ __ ___ ___ _ __ | |_ | '_ ` _ \ / _` | '__| |/ / '_ ` _ \ / _ \ '_ \| __| | | | | | | (_| | | | <| | | | | | __/ | | | |_ |_| |_| |_|\__,_|_| |_|\_\_| |_| |_|\___|_| |_|\__| version {0} ... Generate beautiful documentation for your project """.format(version) local_node = Node(__file__).dir parser = argparse.ArgumentParser( add_help=True, formatter_class=argparse.RawTextHelpFormatter, description=LOGO, epilog= '''Markment finds all the markdown files recursively in the given source directory and generated static html for all of them. It comes with a few builtin themes so you have absolutely no more work other than just having your documentation well written. A builtin HTTP server is also available so you can preview your documentation before generating it.
def test_cd_enters_a_path_and_returns_a_node_representing_it(exists): ("Node#cd should return a node representing the given path") nd = Node("/foo/bar/") other = nd.cd("awesome/") other.path.should.equal('/foo/bar/awesome')
def test_node_path_to_related(exists): ("Node#path_to_related takes a path and returns the relative way there") nd = Node("/foo/bar/something.py") result = nd.path_to_related("/foo/docs/assets/style.css") result.should.equal('../../bar/something.py')
def test_node_relative(exists): ("Node#relative() returns a path relative to the base") nd = Node("/foo/bar/") nd.relative('/foo/bar/yes.py').should.equal('yes.py')
def test_node_dir_when_is_file(): ("Node#dir should return a node pointing to the parent " "dir when the current node is pointing to a file") nd = Node('/foo/bar/items/some.py') nd.dir.path.should.equal('/foo/bar/items')
def test_node_basename(): ("Node#basename should return the basename for the node.path") nd = Node(__file__) nd.basename.should.equal('test_node.py')