Wrangler 是一个静态站点生成器,适合那些不构建博客的人。
特征:
在 Springload,我们经常需要创建静态站点,但我们一直在努力寻找一个工具,嗯……让我们继续使用它。输入牧马人。它不会期望您的内容被格式化为一系列博客文章。它不会复制静态资产或处理 SaSS 或制作咖啡。
它只做一件事,而且把那件事做得很好。
我们希望您喜欢它。
通过 pip 安装牧马人:
pip install wrangler
在当前目录下生成一个新项目.
wrangler create .
这将创建一堆目录。要检查它是否有效,请构建自动生成的小站点:
wrangler build content www
通过您选择的引擎或方便的内置服务器http://127.0.0.1:8000/为您的网站提供服务:
wrangler serve www
想要查看您的内容和模板的更改并自动重新构建它们?有一个应用程序可以做到这一点。 watch 任务采用与build相同的所有选项。
wrangler watch content www
Wrangler 遵循一个非常简单的文件系统约定:
my-site/
| --content
| ----index.yaml
| --lib
| --templates
| ----template.j2
| --var
| --wrangler.yaml
| --wwwcontent - 内容目录。您的站点结构将镜像此目录。如果你有content/index.yaml ,你会得到www/index.htmltemplates - 你的 jinja2 .j2模板所在的位置www - 网络根文件夹。实际上,您可以输出到任何地方,我们只是选择 www 作为合理的默认值。lib - 自定义扩展、类、挂钩等都放在这里。编写一些python模块并将结果传递回wranglervar - 保存模板缓存和文件对象缓存(wrangler 使用开箱即用的 Pickle 和 Shelve 组合)所有这些路径都可以在wrangler.yaml中更改
Wrangler 假设您正在处理某种结构化数据,并且您希望将这些数据文件转换为 HTML(甚至是经典的 ASP,如果您喜欢的话)。
包中包含三个解析器:json、yaml 和 markdown(带有 yaml front-matter)。它们以每个文件为基础进行操作,因此这是完全有效的:
my-site/
| --content
| ----index.yaml
| ----page-2.json
| ----page-3.md meta :
title : My title
template : template.j2
description : " My cool page! "
data :
content : " Here's some page content! "
blocks :
- " Lots of content "
- " even more content "
- " wow, so much content! " {
"meta" : {
"title" : " My title " ,
"template" : " template.j2 " ,
"description" : " My cool page! "
},
"data" : {
"content" : " Here's some page content! " ,
"blocks" : [
" Lots of content " ,
" even more content " ,
" wow, so much content! "
]
}
} ---
title : My title
template : template.j2
description : " Markdown uses yaml front-matter "
---
# A heading!
Some paragraph text
## Another heading!
Even more text
---
Nice HR you got there.
* A list
* with some
* list items
这是一个很好的 Markdown 备忘单
将元数据用于与页面相关的任何内容。你可以在这里添加任何你喜欢的内容,但有一些保留字:
meta :
title : " Musings on the pronounciation of doge "
alias : " Doge "
template : " template.j2 "
class : DogePage
hide_from_nav : true
description : " Is it dog-e, doog, douge, douche? How do I properly refer to this meme? "
keywords : ["much", "analytics", "such", "SEO"]
output_file_extension : asp
weight : 1
thumbnail : /assets/images/thumb/doge-100x100.jpg
related :
- content/other-page.yaml
- content/pages/this-page-here.yaml 导航中的页面名称(也可能是您的标题标签)
模板路径,相对于 wrangler.yaml 的templates_dir
标题的简写,可以在导航中使用
尝试替换页面对象的 Python 类。必须是wrangler.Core.Page的子类
从导航树中隐藏此页面。
罐头上写着什么
关键词列表
覆盖 wrangler.yaml 中的默认output_file_extension 。该页面将使用此扩展名呈现。
方便对页面进行排序,从低到高。默认情况下,wrangler 将使用文件系统的字母顺序排序。
缩略图的路径
相关页面的列表。在您的模板中,这将使您获得有关其他页面的一些基本信息(例如标题和描述)。
牧马人会自动将一些内容添加到您的元数据中,您可以在模板中访问:
{{ meta.url }}
{{ meta.segments }}
{{ meta.filepath }}
{{ meta.mtime }}
{{ meta.children }}
{{ meta.parents }}
{{ meta.parents_siblings }}
构建文件的路径,相对于output_dir ,例如/
所有 url 段的列表: ["sub-directory", "index.html"]
输入文件的名称
修改的时间。例如,您可以使用它来构建博客时间戳。
当前目录的任何直接子目录
当前文件和/之间的所有节点
父目录的同级目录。
页面数据完全是可选的。
让我们看一下这个小页面, custom-page.yaml您可以向 wrangler 抛出一个没有数据的页面,并根据需要对模板中的所有内容进行硬编码, custom-page.j2 。
meta :
title : No content!
template : custom-page.j2
output_file_extension : txt这将构建www/custom-page.txt 。
Wrangler 附带了 jinja2 markdown 过滤器。如果您使用的是 Markdown 文件,则可在data.content处找到 Markdown。将内容通过管道传输到 Markdown 过滤器,就完成了。
< div class = " content " >
{{ data.content|markdown }}
</ div > Markdown 是一种很棒的写作格式,但当您处理更结构化的数据时,它可能会存在一些限制。对于 YAML 和 JSON 文件,访问data字典的部分并根据您认为合适的方式将它们连接起来:
< div class = " content " >
{{ data.content }}
{% for block in data . blocks %}
< p >{{ block }}</ p >
{% endfor %}
</ div >wrangler 的可编辑选项保存在项目根目录下的wrangler.yaml文件中。
打开它,你会发现三个节点: wrangler 、 site和extensions
这是核心配置,硬核的东西。它看起来有点像这样:
wrangler :
# Template directory relative to your project root
templates_dir : templates
# Default template to load if no template is specified for a page
default_template : template.j2
# Default output file extension. Note this can be overwritten in the content
# by specifying 'output_file_extension' in the 'meta' area
output_file_extension : html
# Supported data formats. Ensure a parser is registered for each type.
# More information about parsers can be found in the link at the top of the file.
data_formats : ['yaml', 'yml', 'json', 'js', 'md', 'markdown']
# Ignore hidden files, and files starting with underscores
ignore : ['.','_']
# Prints all the internal plumbing output to stdout
verbose : false
# Always force all pages to be rendered
force : false
# Run without the cache (useful for developing custom page classes, to prevent them
# from being cached each run).
nocache : false
# The location of the template cache zip file.
# Ensure the var path exists and is writeable by the user
build_cache_file : var/build.cache
compiled_templates_file : var/jinja
compiled_templates_log : var/jinja.log
# Custom methods/classes go in the lib directory, for instance
# lib/Page.py or lib/Extensions.py or lib/Filters.py
lib_path : lib
# file continues.... 配置您在此处设置的任何扩展。扩展允许您运行任何您想要的 python 函数,并将结果注入到您的模板中。
# wrangler.yaml continued...
extensions :
# Sitemap generates a tree structure of your entire site, relative to the
# webroot specified here
#
# {{ extensions.sitemap }}
#
# We leave it up to you to iterate over the sitemap and print everything in
# a pretty manner, but this gist might get you started:
# https://gist.github.com/joshbarr/111
sitemap :
webroot : / {{ extensions.cachebuster }}包括一些默认扩展: sitemap 、 fileinfo和cachebuster
站点变量是站点范围的变量,可在模板中作为site对象的子对象使用。
例如,要获取图像路径,您可以调用{{ site.paths.images }}并节省一些输入。
# wrangler.yaml continued...
site :
paths :
css : assets/css
js : assets/js
assets : assets {# Hey, it's those handy vars I set in my site_vars #}
{{ site.paths.css }}所有这些文档也都在wrangler.yaml文件中,所以您不会迷路!
采用单个位置参数,即创建新项目的路径:
cd my-sweet-site && wrangler create .
# or
wrangler create my-sweet-site
input_dir输入目录,例如site/content output_dir输出目录,例如www
wrangler build content www无论您的内容上次修改时间如何,都强制渲染:
wrangler build content www --force重新缓存所有页面对象
wrangler build content www --nocache将所有页面的输出文件扩展名更改为经典asp 。(为什么有人会这样做?)
wrangler build content www -o ".asp"
将input_dir中要搜索的数据格式更改为json
wrangler build content www -d 'json'
更改模板目录的位置
wrangler build content www -t other-templates-dir
更改配置文件的位置
wrangler build content www -c site/config/wrangler.yaml
具有与wrangler build相同的所有选项
每次文件更改时打印所有管道:
wrangler watch content www --verbose接受一个位置参数(要服务的目录)和一个可选的--port (默认 8000)。
wrangler serve www --port 8001从“var”目录中删除模板缓存和对象缓存。
wrangler cleanWrangler 在启动时会加载项目lib目录中找到的所有 python 模块。
这使您能够扩展核心功能并操作页面数据 - 例如,您可以从数据库加载一些值并使它们在模板中可用。
当您调用build时,wrangler 会在您的content/目录中构建树结构的表示。
它使用Node对象的双向链表,这些对象被混合到NodeGraph中,这是一个用于处理节点的方便容器。
# Pseudocode
NodeGraph :
# The nodes in their hierarchical structure, eg:
tree :
Node :
children :
- Node :
children :
- Node
- Node :
children :
- Node
- Node
- Node
# The 'all' dictionary is the same nodes represented in a flat structure.
# This can be much quicker to iterate over than the tree, and you can
# access both from within your hooks and extensions.
# The filepath is used as the unique key.
all :
content/index.md :
Node :
# node's data...
content/other-page.md :
Node :
# node's data...节点可以访问它们的子节点,也可以访问它们的父节点:
# More pseudocode
Node :
path : " content/index.md "
children :
- Node :
- Node :
- Node :
parent :
Node :为了保持整洁,Node 对象并不直接在其上保存页面数据的表示 - 节点只是容器。
按照本次讨论中的想法,节点有一个Cargo属性来保存真实的页面类:
from wrangler . Core import Node
class GoldBullion ( object ):
price = 1200
the_node = Node ( "index" , "content/index.md" , parent = None , cargo = None )
the_node . add_cargo ( GoldBullion ())
cargo = the_node . get_cargo ()
print cargo . price 页面保存源文件数据的dict表示,并为Renderer提供访问数据的一致方式。要创建自定义页面,只需子类化wrangler.Core.Page即可自动加载。
实用提示:如果您的自定义类的名称为Page ,它将覆盖所有页面的默认Page对象。
# lib/Page.py
import wrangler . Core as wrangler
class Page ( wrangler . Page ):
def get_content ( self ):
return self . data [ "data" ]
def get_metadata ( self ):
return self . data [ "meta" ]
def get_properties ( self ):
print "Hey, I'm a custom page instance!"
return {
"title" : self . get_title (),
"alias" : self . get_short_title (),
"description" : self . get_meta_description (),
"url" : self . get_tidy_url (),
"show_in_navigation" : self . show_in_navigation (),
"weight" : self . get_weight (),
"thumbnail" : self . get_thumbnail ()
}在上面的示例中,我们修改了三个主要页面方法: get_content() 、 get_metadata()和get_properties()
在渲染页面时调用,这在模板中可以作为data对象使用:
<!doctype html>
< div class = ' dump-of-data-object ' >
{{ data.content }}
</ div >当页面渲染时调用,这是meta对象:
<!doctype html>
< title >{{ meta.title }}解释起来有点棘手,但仍然很棒。当渲染Node时,它会请求与当前页面相关的页面的某些信息,例如子页面、兄弟页面、父页面和手动相关页面。
每个Page类都描述了它乐意与其他页面共享的基本信息,而不是与其他所有内容共享所有内容。
def get_properties ( self ):
return {
"title" : self . get_title (),
"alias" : self . get_short_title (),
"url" : self . get_tidy_url (),
"show_in_navigation" : self . show_in_navigation (),
"weight" : self . get_weight (),
# Let's add the modified time, so our theoretical parent
# page could know when we last saved the file.
"mtime" : self . getmtime ()
}让我们看一个非常简单的示例,一个自定义页面类,它反转页面上的所有文本。非常实用。
首先,在页面元数据中设置class属性来告诉 wrangler 要加载哪个类:
内容/自定义.md:
---
class : RightToLeft
---
# My custom page
With its custom content.然后在lib/目录中的某个位置创建一个新类,该类是Page子类。它在lib/目录中的哪个位置结束并不重要,唯一的规则是它必须子类化Page对象:
库/pages.py
import wrangler . Core as wrangler
class RightToLeft ( wrangler . Page )
def get_content ( self ):
for key , val in self . data [ "data" ]:
self . data [ "data" ][ key ] = val [:: - 1 ]
return self . data [ "data" ]伟大的!我们的页面将以从右到左的文本打印。
如果您查看wrangler.yaml文件,您会发现它接受三种文件类型: ["yaml", "json", "md"]
Wrangler 默认包含三个解析器: Yaml 、 Markdown和Json ,它们使用输入文件并将其表示为有意义的数据。
自动加载器会查找任何子类wrangler.Core.Parser内容。
例如,您可以在lib/Parsers.py中的某个位置执行此操作以支持文本格式
from wrangler . Core import Parser
from lxml import objectify
from collections import defaultdict
class XmlParser ( Parser ):
accepts = [ "xml" , "robotlanguage" ]
def interpret ( self , file_contents ):
return root = objectify . fromstring ( file_contents )
Wrangler 使用blinker 的信号来处理hook 和扩展。
钩子是在渲染过程中的关键点触发的信号。它们按照它们在模块中出现的顺序进行处理,并且可以直接修改传入的对象。他们还可以访问 wrangler 的config 、 renderer和reporter 。
from wrangler . Core import before_render , after_render , load_item , save_item , render_item
@ before_render
def before ( ** kw ):
nodes = kw [ 'nodes' ]
config = kw [ 'config' ]
renderer = kw [ 'renderer' ]
reporter = kw [ 'reporter' ]
print "Hey, I'm a hook!"
return "foo!"
@ after_render
def after ( ** kw ):
nodes = kw [ 'nodes' ]
config = kw [ 'config' ]
renderer = kw [ 'renderer' ]
reporter = kw [ 'reporter' ]
print "Hey, I'm a hook!"
return ""扩展是 python 脚本,可将方便的数据返回到模板的extensions字典中。
让我们看一下这个小脚本:
# lib/my_extensions.py
from wrangler . Core import extension
@ extension
def my_extension ( sender , ** kwargs ):
# Add some config to your YAML file and access it here:
config = kwargs [ 'config' ][ 'extensions' ][ 'my_extension' ]
return config [ "string_to_print" ]可以从您的模板访问extensions.YOUR_EXTENSION_NAME :
< em class = " extension " >
{{ extensions.my_extension }}
</ em >其结果是这样的输出:
< i > "This is my basic extension!" </ i > 在您的wrangler.yaml中有一个用于管理扩展的部分:
# My extension just prints a string... not very exciting!
my_extension :
string_to_print : " This is my basic extension! " Wrangler 允许您使用自定义过滤器扩展 Jinja2。
过滤器可以放在 lib 目录lib/中的任何文件中。它们通过装饰器连接起来,恰当地命名为template_filter
#lib/filters.py
from wrangler . Core import template_filter
from jinja2 import contextfilter
@ template_filter
def my_filter ( value ):
return value . lower ()如果您需要访问 jinja 的contextfilter或envcontextfilter您可以导入它们并将它们应用到您的函数中:
阅读有关 jinja2 上下文过滤器的更多信息
#lib/filters.py
from wrangler . Core import template_filter
from jinja2 import contextfilter
@ template_filter
@ contextfilter
def my_filter ( context , value ):
print context
return value