Wrangler est un générateur de sites statiques destiné aux personnes qui ne créent pas de blogs.
Caractéristiques:
Chez Springload, nous avons souvent besoin de créer des sites statiques, mais nous avons eu du mal à trouver un outil qui, eh bien… nous permette de continuer. Entrez dans le Wrangler. Il ne s'attend pas à ce que votre contenu soit formaté comme une série d'articles de blog. Il ne copie pas les actifs statiques, ne traite pas le SaSS et ne prépare pas de café.
Il fait une chose, et il le fait plutôt bien.
Nous espérons que vous l’aimerez.
Installez le Wrangler via pip :
pip install wrangler
Générez un nouveau projet dans le répertoire courant .
wrangler create .
Cela créera un tas de répertoires. Pour vérifier que cela fonctionne, construisez le petit site généré automatiquement :
wrangler build content www
Servez votre site via un moteur de votre choix ou le serveur intégré pratique à l' http://127.0.0.1:8000/
:
wrangler serve www
Vous souhaitez surveiller les modifications apportées à votre contenu et à vos modèles et les reconstruire automatiquement ? Il existe une application pour ça. La tâche watch prend toutes les mêmes options que build
.
wrangler watch content www
Wrangler suit une convention de système de fichiers assez simple :
my-site/
| --content
| ----index.yaml
| --lib
| --templates
| ----template.j2
| --var
| --wrangler.yaml
| --www
content
- le répertoire de contenu. La structure de votre site reflétera ce répertoire. Si vous avez content/index.yaml
, vous obtiendrez www/index.html
templates
- où se trouvent vos modèles jinja2 .j2
www
- le dossier racine Web. Vraiment, vous pouvez sortir n'importe où, nous avons simplement choisi www comme valeur par défaut raisonnable.lib
- les extensions personnalisées, les classes, les hooks, etc. vont ici. Écrivez quelques modules Python et transmettez les résultats à Wranglervar
- contient le cache des modèles et le cache des objets fichier (Wrangler utilise le combo Pickle et Shelve prêt à l'emploi) Tous ces chemins peuvent être modifiés dans wrangler.yaml
Wrangler suppose que vous travaillez avec une sorte de données structurées et que vous souhaitez traduire ces fichiers de données en HTML (ou même en ASP classique, si c'est votre truc).
Trois analyseurs sont inclus dans le package : json, yaml et markdown (avec la présentation yaml). Ils fonctionnent fichier par fichier, donc ceci est parfaitement valable :
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
Voici une belle aide-mémoire de démarque
Utilisez les métadonnées pour tout ce qui concerne la page. Vous pouvez mettre ce que vous voulez ici, mais il y a quelques mots réservés :
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
Le nom de la page dans la navigation (et probablement votre balise de titre aussi)
Chemin du modèle, par rapport au templates_dir
de votre wrangler.yaml
Raccourci pour le titre, qui peut être utilisé à la place dans la navigation
Tente de remplacer la classe Python pour l'objet page. Doit être une sous-classe de wrangler.Core.Page
Masquer cette page de l'arborescence de navigation.
Ce qui est écrit sur la boîte
Une liste de mots-clés
Remplacez l' output_file_extension
par défaut de wrangler.yaml. La page sera rendue avec cette extension.
Pratique pour trier les pages, de bas en haut. Par défaut, Wrangler utilisera le tri alphabétique du système de fichiers.
Chemin d'accès à une image miniature
Une liste de pages associées. Dans votre modèle, cela vous permettra d'obtenir des informations de base sur d'autres pages (comme le titre et la description).
Le Wrangler ajoute automatiquement certains éléments à vos métadonnées. Dans vos modèles, vous pouvez accéder :
{{ meta.url }}
{{ meta.segments }}
{{ meta.filepath }}
{{ meta.mtime }}
{{ meta.children }}
{{ meta.parents }}
{{ meta.parents_siblings }}
Le chemin d'accès au fichier construit, relatif au output_dir
, par exemple /
Une liste de tous les segments d'URL : ["sub-directory", "index.html"]
Le nom du fichier d'entrée
L'heure modifiée. Vous pouvez l'utiliser pour créer un horodatage de blog, par exemple.
Tous les enfants directs du répertoire actuel
Tous les nœuds entre le fichier courant et /
Les frères et sœurs du répertoire parent.
Les données de page sont entièrement facultatives.
Regardons cette petite page, custom-page.yaml
Vous pouvez lancer à Wrangler une page sans données et tout coder en dur dans le modèle, custom-page.j2
si vous le souhaitez.
meta :
title : No content!
template : custom-page.j2
output_file_extension : txt
Cela créera www/custom-page.txt
.
Wrangler est livré avec un filtre de démarque jinja2. Si vous utilisez un fichier de démarque, la démarque est disponible sur data.content
. Dirigez le contenu vers le filtre de démarque et vous avez terminé.
< div class = " content " >
{{ data.content|markdown }}
</ div >
Markdown est un format d'écriture fantastique, mais il peut présenter certaines limites lorsque vous traitez des données plus structurées. Pour les fichiers YAML et JSON, accédez à certaines parties du dictionnaire data
et connectez-les comme bon vous semble :
< div class = " content " >
{{ data.content }}
{% for block in data . blocks %}
< p >{{ block }}</ p >
{% endfor %}
</ div >
Les options modifiables du wrangler sont enregistrées dans le fichier wrangler.yaml
à la racine de votre projet.
Ouvrez-le et vous trouverez trois nœuds : wrangler
, site
et extensions
C'est la configuration de base, le noyau dur. Cela ressemble un peu à ceci :
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....
Configurez toutes les extensions que vous avez configurées ici. Les extensions vous permettent d'exécuter n'importe quelle fonction Python de votre choix et d'injecter les résultats dans vos modèles.
# 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 }}
Certaines extensions par défaut sont incluses : sitemap
, fileinfo
et cachebuster
Les variables de site sont des variables à l'échelle du site, disponibles dans vos modèles en tant qu'enfants de l'objet site
.
Par exemple, pour obtenir le chemin des images, vous pouvez appeler {{ site.paths.images }}
et vous épargner du temps de saisie.
# 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 }}
Toute cette documentation se trouve également dans le fichier wrangler.yaml
, vous ne vous perdrez donc pas !
Prend un seul argument de position, le chemin par lequel créer votre nouveau projet :
cd my-sweet-site && wrangler create .
# or
wrangler create my-sweet-site
input_dir
Répertoire d'entrée tel que site/content
output_dir
Répertoire de sortie tel que www
wrangler build content www
Forcer le rendu quelle que soit la date de la dernière modification de votre contenu :
wrangler build content www --force
Remettre en cache tous les objets de la page
wrangler build content www --nocache
Modifiez l'extension du fichier de sortie de toutes les pages en asp
classique. (Pourquoi quelqu'un ferait-il cela ?)
wrangler build content www -o ".asp"
Changez le format de données à rechercher dans input_dir
en json
wrangler build content www -d 'json'
Changer l'emplacement du répertoire des modèles
wrangler build content www -t other-templates-dir
Changer l'emplacement du fichier de configuration
wrangler build content www -c site/config/wrangler.yaml
A toutes les mêmes options que wrangler build
Imprimez toute la plomberie à chaque fois qu'un fichier change :
wrangler watch content www --verbose
Accepte un argument de position (le répertoire à servir) et un --port
facultatif (8000 par défaut).
wrangler serve www --port 8001
Supprimez le cache de modèles et le cache d'objets du répertoire 'var'.
wrangler clean
Wrangler charge tous les modules python trouvés dans le répertoire lib
de votre projet lors de son démarrage.
Cela vous donne le pouvoir d'étendre les fonctions principales et de manipuler les données de la page. Par exemple, vous pouvez charger certaines valeurs d'une base de données et les rendre disponibles dans vos modèles.
Lorsque vous appelez build
, Wrangler crée une représentation de la structure arborescente dans votre répertoire content/
.
Il utilise une liste doublement liée d'objets Node
, qui sont mélangés dans un NodeGraph
, un conteneur pratique pour gérer les nœuds.
# 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...
Les nœuds peuvent accéder à leurs enfants, ainsi qu'à leurs parents :
# More pseudocode
Node :
path : " content/index.md "
children :
- Node :
- Node :
- Node :
parent :
Node :
Pour garder les choses en ordre, l'objet Node ne contient pas directement de représentation des données de la page – les nœuds ne sont que des conteneurs.
Suivant les idées de cette discussion, le Node possède une propriété cargo qui contient la vraie classe de page :
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
Les pages contiennent une représentation dict
des données de votre fichier source et fournissent au Renderer
un moyen cohérent d'accéder aux données. Pour créer une page personnalisée, sous-classez simplement wrangler.Core.Page
et elle sera chargée automatiquement.
Astuce pratique : si votre classe personnalisée porte le nom Page
, elle écrasera l'objet Page
par défaut pour toutes les pages.
# 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 ()
}
Dans notre exemple ci-dessus, nous modifions les trois méthodes de page principales, get_content()
, get_metadata()
et get_properties()
Appelé lors du rendu de la page, il est disponible dans votre modèle en tant qu'objet data
:
<!doctype html>
< div class = ' dump-of-data-object ' >
{{ data.content }}
</ div >
Appelé lors du rendu de la page, il s'agit du meta
objet :
<!doctype html>
< title >{{ meta.title }}
Un peu plus délicat à expliquer, mais toujours génial. Lorsqu'un Node
est rendu, il demande certaines informations sur les pages liées à la page actuelle, telles que les enfants, les frères et sœurs, les parents et les pages liées manuellement.
Plutôt que de tout partager avec tout le reste , chaque classe Page
décrit les informations de base qu'elle est heureuse de partager avec d'autres pages.
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 ()
}
Regardons un exemple très simple, une classe de page personnalisée qui inverse tout le texte de la page. Très pratique.
Tout d’abord, définissez la propriété class
dans la méta de votre page pour indiquer à Wrangler quelle classe charger :
contenu/custom.md :
---
class : RightToLeft
---
# My custom page
With its custom content.
Créez ensuite une nouvelle classe quelque part dans votre répertoire lib/
qui sous-classe Page
. Peu importe où il se trouve dans votre répertoire lib/
, la seule règle est qu'il doit sous-classer l'objet Page
:
lib/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" ]
Super! Notre page sera imprimée avec du texte de droite à gauche.
Si vous regardez dans votre fichier wrangler.yaml
, vous remarquerez qu'il accepte trois types de fichiers : ["yaml", "json", "md"]
Wrangler comprend trois analyseurs par défaut, Yaml
, Markdown
et Json
, qui consomment les fichiers d'entrée et les représentent sous forme de données significatives.
Le chargeur automatique recherche tout ce qui sous-classe wrangler.Core.Parser
.
Par exemple, vous pouvez le faire quelque part dans votre lib/Parsers.py
pour prendre en charge le format texte
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 utilise les signaux des clignotants pour traiter les crochets et les extensions.
Les hooks sont des signaux déclenchés à des points critiques du processus de rendu. Ils sont traités dans l'ordre dans lequel ils apparaissent dans vos modules et peuvent modifier directement les objets entrants. Ils ont également accès à config
, renderer
et 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 ""
Les extensions sont des scripts Python qui renvoient des données pratiques au dictionnaire extensions
de vos modèles.
Prenons ce petit script :
# 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" ]
Sera accessible à partir de votre modèle sur extensions.YOUR_EXTENSION_NAME
:
< em class = " extension " >
{{ extensions.my_extension }}
</ em >
Ce qui donne ce résultat :
< i > "This is my basic extension!" </ i >
Dans votre wrangler.yaml
il y a une section pour gérer vos extensions :
# My extension just prints a string... not very exciting!
my_extension :
string_to_print : " This is my basic extension! "
Wrangler vous permet d'étendre Jinja2 avec des filtres personnalisés.
Les filtres peuvent être placés dans n'importe quel fichier de votre répertoire lib, lib/
. Ils sont connectés via un décorateur, bien nommé 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 vous avez besoin d'accéder au contextfilter
ou envcontextfilter
de jinja, vous pouvez également les importer et les appliquer à votre fonction :
En savoir plus sur les filtres contextuels 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