Wrangler es un generador de sitios estáticos para personas que no crean blogs.
Características:
En Springload, a menudo necesitamos crear sitios estáticos, pero nos ha costado encontrar una herramienta que, bueno... nos permita seguir adelante. Entra el Wrangler. No esperará que su contenido tenga el formato de una serie de publicaciones de blog. No copia activos estáticos ni procesa SaSS ni prepara café.
Hace una cosa, y la hace bastante bien.
Esperamos que te guste.
Instale el Wrangler mediante pip:
pip install wrangler
Generar un nuevo proyecto en el directorio actual .
wrangler create .
Esto creará un montón de directorios. Para comprobar que funciona, cree el pequeño sitio generado automáticamente:
wrangler build content www
Sirve tu sitio a través de un motor de tu elección o del práctico servidor integrado en http://127.0.0.1:8000/
:
wrangler serve www
¿Quiere observar su contenido y sus plantillas en busca de cambios y reconstruirlos automáticamente? Hay una aplicación para eso. La tarea de vigilancia requiere las mismas opciones que la build
.
wrangler watch content www
Wrangler sigue una convención de sistema de archivos bastante simple:
my-site/
| --content
| ----index.yaml
| --lib
| --templates
| ----template.j2
| --var
| --wrangler.yaml
| --www
content
: el directorio de contenido. La estructura de su sitio reflejará este directorio. Si tienes content/index.yaml
, obtendrás www/index.html
templates
: dónde viven tus plantillas jinja2 .j2
www
: la carpeta raíz web. Realmente, puedes enviar a cualquier lugar, simplemente elegimos www como valor predeterminado sensato.lib
: aquí entran extensiones personalizadas, clases, ganchos, etc. Escriba algunos módulos de Python y pase los resultados a Wranglervar
: contiene la caché de plantilla y la caché de objetos de archivo (wrangler usa el combo Pickle y Shelve listo para usar) Todas estas rutas se pueden cambiar en wrangler.yaml
Wrangler asume que estás trabajando con algún tipo de datos estructurados y deseas traducir esos archivos de datos a HTML (o incluso ASP clásico, si eso es lo tuyo).
Se incluyen tres analizadores en el paquete: json, yaml y markdown (con yaml front-matter). Operan por archivo, por lo que esto es perfectamente válido:
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
Aquí hay una buena hoja de referencia de rebajas
Utilice los metadatos para cualquier cosa relacionada con la página. Puedes incluir lo que quieras aquí, pero hay algunas palabras reservadas:
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
El nombre de la página en la navegación (y probablemente también la etiqueta del título)
Ruta de la plantilla, relativa al templates_dir
de tu wrangler.yaml
Taquigrafía del título, que se puede utilizar en la navegación.
Intenta reemplazar la clase Python para el objeto de página. Debe ser una subclase de wrangler.Core.Page
Oculte esta página del árbol de navegación.
Lo que dice en la lata
Una lista de palabras clave
Anule la output_file_extension
predeterminada de wrangler.yaml. La página se representará con esta extensión.
Útil para ordenar páginas, de menor a mayor. De forma predeterminada, Wrangler utilizará la clasificación alfabética del sistema de archivos.
Ruta a una imagen en miniatura
Una lista de páginas relacionadas. En tu plantilla, esto te permitirá obtener información básica sobre otras páginas (como el título y la descripción).
El wrangler agrega algunas cosas a tus metadatos automáticamente, en tus plantillas puedes acceder:
{{ meta.url }}
{{ meta.segments }}
{{ meta.filepath }}
{{ meta.mtime }}
{{ meta.children }}
{{ meta.parents }}
{{ meta.parents_siblings }}
La ruta al archivo creado, relativa al output_dir
, por ejemplo /
Una lista de todos los segmentos de URL: ["sub-directory", "index.html"]
El nombre del archivo de entrada.
La hora modificada. Podrías usar esto para crear una marca de tiempo para un blog, por ejemplo.
Cualquier hijo directo del directorio actual.
Todos los nodos entre el archivo actual y /
Los hermanos del directorio principal.
Los datos de la página son completamente opcionales.
Echemos un vistazo a esta pequeña página, custom-page.yaml
Puede enviarle a Wrangler una página sin datos y codificar todo en la plantilla, custom-page.j2
si lo desea.
meta :
title : No content!
template : custom-page.j2
output_file_extension : txt
Esto creará www/custom-page.txt
.
Wrangler se envía con un filtro de rebajas jinja2. Si está utilizando un archivo de rebajas, el descuento está disponible en data.content
. Canalice el contenido al filtro de rebajas y listo.
< div class = " content " >
{{ data.content|markdown }}
</ div >
Markdown es un formato de escritura fantástico, pero puede presentar algunas limitaciones cuando se trata de datos más estructurados. Para archivos YAML y JSON, acceda a partes del diccionario data
y conéctelas como mejor le parezca:
< div class = " content " >
{{ data.content }}
{% for block in data . blocks %}
< p >{{ block }}</ p >
{% endfor %}
</ div >
Las opciones editables para el Wrangler se guardan en el archivo wrangler.yaml
en la raíz de su proyecto.
Ábralo y encontrará tres nodos: wrangler
, site
y extensions
Esta es la configuración central, lo más importante. Se parece un poco a esto:
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....
Configure aquí las extensiones que haya configurado. Las extensiones te permiten ejecutar cualquier función de Python que desees e inyectar los resultados en tus plantillas.
# 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 }}
Se incluyen algunas extensiones predeterminadas: sitemap
, fileinfo
y cachebuster
Las variables del sitio son variables de todo el sitio, disponibles dentro de sus plantillas como elementos secundarios del objeto site
.
Por ejemplo, para obtener la ruta de las imágenes, puede llamar a {{ site.paths.images }}
y ahorrarse algo de escribir.
# 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 }}
Toda esta documentación también está en el archivo wrangler.yaml
, ¡así que no te perderás!
Toma un único argumento posicional, la ruta en la que crear tu nuevo proyecto:
cd my-sweet-site && wrangler create .
# or
wrangler create my-sweet-site
input_dir
Directorio de entrada como site/content
output_dir
Directorio de salida como www
wrangler build content www
Forzar la renderización independientemente de cuándo se modificó su contenido por última vez:
wrangler build content www --force
Vuelva a almacenar en caché todos los objetos de la página.
wrangler build content www --nocache
Cambie la extensión del archivo de salida para todas las páginas a asp
clásico. (¿Por qué alguien haría eso?)
wrangler build content www -o ".asp"
Cambie el formato de datos para buscar en input_dir
a json
wrangler build content www -d 'json'
Cambiar la ubicación del directorio de plantillas.
wrangler build content www -t other-templates-dir
Cambiar la ubicación del archivo de configuración
wrangler build content www -c site/config/wrangler.yaml
Tiene las mismas opciones que wrangler build
Imprime toda la plomería cada vez que cambia un archivo:
wrangler watch content www --verbose
Acepta un argumento posicional (el directorio a servir) y un --port
opcional (predeterminado 8000).
wrangler serve www --port 8001
Elimine la caché de plantilla y la caché de objetos del directorio 'var'.
wrangler clean
Wrangler carga todos los módulos de Python que se encuentran en el directorio lib
de su proyecto cuando arranca.
Esto le brinda el poder de ampliar las funciones principales y manipular los datos de la página; por ejemplo, puede cargar algunos valores desde una base de datos y ponerlos a disposición en sus plantillas.
Cuando llamas build
, Wrangler crea una representación de la estructura de árbol en tu directorio content/
.
Está utilizando una lista doblemente enlazada de objetos Node
, que se combinan en un NodeGraph
, un contenedor útil para tratar con los nodos.
# 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...
Los nodos pueden acceder a sus hijos y también a sus padres:
# More pseudocode
Node :
path : " content/index.md "
children :
- Node :
- Node :
- Node :
parent :
Node :
Para mantener todo ordenado, el objeto Nodo no contiene una representación de los datos de la página directamente en él; los nodos son solo contenedores.
Siguiendo las ideas de esta discusión, el Nodo tiene una propiedad cargo que contiene la clase de página real :
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
Las páginas contienen una representación dict
de los datos de su archivo fuente y proporcionan una forma consistente para que el Renderer
acceda a los datos. Para crear una página personalizada, simplemente cree la subclase wrangler.Core.Page
y se cargará automáticamente.
Consejo útil: si su clase personalizada tiene el nombre de Page
, sobrescribirá el objeto Page
predeterminado para todas las páginas.
# 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 ()
}
En nuestro ejemplo anterior, estamos modificando los tres métodos de la página principal, get_content()
, get_metadata()
y get_properties()
Se llama cuando se representa la página y está disponible en su plantilla como objeto data
:
<!doctype html>
< div class = ' dump-of-data-object ' >
{{ data.content }}
</ div >
Se llama cuando se representa la página, este es el meta
:
<!doctype html>
< title >{{ meta.title }}
Un poco más complicado de explicar, pero sigue siendo asombroso. Cuando se representa un Node
, solicita cierta información sobre las páginas relacionadas con la página actual, como las páginas secundarias, hermanos, padres y relacionadas manualmente.
En lugar de compartir todo con todo lo demás , cada clase Page
describe la información básica que está feliz de compartir con otras páginas.
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 ()
}
Veamos un ejemplo realmente simple, una clase de página personalizada que invierte todo el texto de la página. Muy práctico.
En primer lugar, establezca la propiedad class
en el meta de su página para indicarle a Wrangler qué clase cargar:
contenido/personalizado.md:
---
class : RightToLeft
---
# My custom page
With its custom content.
Luego cree una nueva clase en algún lugar de su directorio lib/
que subclase Page
. No importa dónde termine dentro de su directorio lib/
, la única regla es que tiene que subclasificar el objeto Page
:
lib/páginas.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" ]
¡Excelente! Nuestra página se imprimirá con texto de derecha a izquierda.
Si observa su archivo wrangler.yaml
, notará que acepta tres tipos de archivos: ["yaml", "json", "md"]
Wrangler incluye tres analizadores de forma predeterminada, Yaml
, Markdown
y Json
, que consumen los archivos de entrada y los representan como datos significativos.
El cargador automático busca cualquier cosa que subcasifique wrangler.Core.Parser
.
Por ejemplo, podrías hacer esto en algún lugar de tu lib/Parsers.py
para admitir el formato de texto.
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 utiliza señales intermitentes para procesar ganchos y extensiones.
Los ganchos son señales que se activan en puntos críticos del proceso de renderizado. Se procesan en el orden en que aparecen en sus módulos y pueden modificar los objetos entrantes directamente. También tienen acceso a config
, renderer
y reporter
de Wrangler.
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 ""
Las extensiones son secuencias de comandos de Python que devuelven datos útiles al diccionario extensions
de sus plantillas.
Tomemos este pequeño guión:
# 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" ]
Será accesible desde su plantilla en extensions.YOUR_EXTENSION_NAME
:
< em class = " extension " >
{{ extensions.my_extension }}
</ em >
Lo que da como resultado este resultado:
< i > "This is my basic extension!" </ i >
En tu wrangler.yaml
hay una sección para administrar tus extensiones:
# My extension just prints a string... not very exciting!
my_extension :
string_to_print : " This is my basic extension! "
Wrangler te permite ampliar Jinja2 con filtros personalizados.
Los filtros pueden ir en cualquier archivo de su directorio lib, lib/
. Están conectados a través de un decorador, llamado apropiadamente template_filter
#lib/filters.py
from wrangler . Core import template_filter
from jinja2 import contextfilter
@ template_filter
def my_filter ( value ):
return value . lower ()
Si necesita acceso al contextfilter
o envcontextfilter
de jinja, puede importarlos y aplicarlos a su función también:
Lea más sobre los filtros de contexto de 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