Wrangler ist ein statischer Site-Generator für Leute, die keine Blogs erstellen.
Merkmale:
Bei Springload müssen wir oft statische Websites erstellen, aber wir hatten Mühe, ein Tool zu finden, mit dem wir damit weitermachen können. Betreten Sie den Wrangler. Es wird nicht erwartet, dass Ihre Inhalte als eine Reihe von Blogbeiträgen formatiert sind. Es kopiert keine statischen Assets, verarbeitet kein SaSS und kocht auch keinen Kaffee.
Es macht eine Sache, und diese eine Sache macht es ziemlich gut.
Wir hoffen, dass es Ihnen gefällt.
Installieren Sie den Wrangler über Pip:
pip install wrangler
Erzeugen Sie ein neues Projekt im aktuellen Verzeichnis .
wrangler create .
Dadurch wird eine Reihe von Verzeichnissen erstellt. Um zu überprüfen, ob es funktioniert, erstellen Sie die kleine automatisch generierte Site:
wrangler build content www
Bedienen Sie Ihre Website über eine Engine Ihrer Wahl oder den praktischen integrierten Server unter http://127.0.0.1:8000/
:
wrangler serve www
Möchten Sie Ihre Inhalte und Vorlagen auf Änderungen überwachen und diese automatisch neu erstellen? Dafür gibt es eine App. Der Watch-Task verwendet dieselben Optionen wie build
.
wrangler watch content www
Wrangler folgt einer ziemlich einfachen Dateisystemkonvention:
my-site/
| --content
| ----index.yaml
| --lib
| --templates
| ----template.j2
| --var
| --wrangler.yaml
| --www
content
– das Inhaltsverzeichnis. Ihre Site-Struktur spiegelt dieses Verzeichnis wider. Wenn Sie content/index.yaml
haben, erhalten Sie www/index.html
templates
– wo Ihre Jinja2 .j2
-Vorlagen lebenwww
– der Web-Stammordner. Eigentlich können Sie überall ausgeben, wir haben einfach www als sinnvollen Standard ausgewählt.lib
– hier kommen benutzerdefinierte Erweiterungen, Klassen, Hooks usw. rein. Schreiben Sie einige Python-Module und geben Sie die Ergebnisse an Wrangler zurückvar
– enthält den Vorlagen-Cache und den Dateiobjekt-Cache (Wrangler verwendet die sofort einsatzbereite Pickle- und Shelve-Kombination). Alle diese Pfade können in wrangler.yaml
geändert werden
Wrangler geht davon aus, dass Sie mit strukturierten Daten arbeiten und diese Datendateien in HTML übersetzen möchten (oder sogar in klassisches ASP, wenn das Ihr Ding ist).
Im Paket sind drei Parser enthalten: JSON, Yaml und Markdown (mit Yaml-Frontmatter). Sie arbeiten auf einer Pro-Datei-Basis, daher ist dies vollkommen gültig:
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
Hier ist ein schöner Markdown-Spickzettel
Verwenden Sie die Metadaten für alles, was mit der Seite zu tun hat. Sie können hier hineinwerfen, was Sie wollen, aber es gibt ein paar reservierte Worte:
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
Der Seitenname in der Navigation (und wahrscheinlich auch Ihr Title-Tag)
Vorlagenpfad, relativ zum templates_dir
Ihrer wrangler.yaml
Abkürzung für den Titel, die stattdessen in der Navigation verwendet werden kann
Versucht, die Python-Klasse für das Seitenobjekt zu ersetzen. Muss eine Unterklasse von wrangler.Core.Page
sein
Diese Seite aus der Navigationsstruktur ausblenden.
Was auf der Verpackung steht
Eine Liste von Schlüsselwörtern
Überschreiben Sie die standardmäßige output_file_extension
aus wrangler.yaml. Die Seite wird mit dieser Erweiterung gerendert.
Praktisch zum Ordnen der Seiten von niedrig nach hoch. Standardmäßig verwendet Wrangler die alphabetische Sortierung des Dateisystems.
Pfad zu einem Miniaturbild
Eine Liste verwandter Seiten. Dadurch erhalten Sie in Ihrer Vorlage einige grundlegende Informationen zu anderen Seiten (z. B. Titel und Beschreibung).
Der Wrangler fügt Ihren Metadaten automatisch einige Dinge hinzu. In Ihren Vorlagen können Sie darauf zugreifen:
{{ meta.url }}
{{ meta.segments }}
{{ meta.filepath }}
{{ meta.mtime }}
{{ meta.children }}
{{ meta.parents }}
{{ meta.parents_siblings }}
Der Pfad zur erstellten Datei, relativ zum output_dir
, zum Beispiel /
Eine Liste aller URL-Segmente: ["sub-directory", "index.html"]
Der Name der Eingabedatei
Die geänderte Zeit. Sie könnten damit beispielsweise einen Blog-Zeitstempel erstellen.
Alle direkten untergeordneten Elemente des aktuellen Verzeichnisses
Alle Knoten zwischen der aktuellen Datei und /
Die Geschwister des übergeordneten Verzeichnisses.
Seitendaten sind völlig optional.
Schauen wir uns diese kleine Seite an, custom-page.yaml
Sie können Wrangler eine Seite ohne Daten erstellen und alles in der Vorlage, custom-page.j2
fest codieren, wenn Sie möchten.
meta :
title : No content!
template : custom-page.j2
output_file_extension : txt
Dadurch wird www/custom-page.txt
erstellt.
Wrangler wird mit einem Jinja2-Markdown-Filter ausgeliefert. Wenn Sie eine Markdown-Datei verwenden, ist der Markdown unter data.content
verfügbar. Leiten Sie den Inhalt an den Markdown-Filter weiter, und schon sind Sie fertig.
< div class = " content " >
{{ data.content|markdown }}
</ div >
Markdown ist ein fantastisches Schreibformat, kann jedoch einige Einschränkungen mit sich bringen, wenn Sie mit strukturierteren Daten arbeiten. Greifen Sie bei YAML- und JSON-Dateien auf Teile des data
zu und verknüpfen Sie diese nach Bedarf:
< div class = " content " >
{{ data.content }}
{% for block in data . blocks %}
< p >{{ block }}</ p >
{% endfor %}
</ div >
Die bearbeitbaren Optionen für den Wrangler werden in der Datei wrangler.yaml
in Ihrem Projektstammverzeichnis gespeichert.
Öffnen Sie es und Sie finden drei Knoten: wrangler
, site
und extensions
Das ist die Kernkonfiguration, das Hardcore-Zeug. Es sieht ungefähr so aus:
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....
Konfigurieren Sie hier alle von Ihnen eingerichteten Erweiterungen. Mit Erweiterungen können Sie jede gewünschte Python-Funktion ausführen und die Ergebnisse in Ihre Vorlagen einfügen.
# 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 }}
Einige Standarderweiterungen sind enthalten: sitemap
, fileinfo
und cachebuster
Site-Variablen sind Site-weite Variablen, die in Ihren Vorlagen als untergeordnete Elemente des site
Objekts verfügbar sind.
Um beispielsweise den Bildpfad abzurufen, können Sie {{ site.paths.images }}
aufrufen und sich so etwas Tipparbeit sparen.
# 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 }}
Die gesamte Dokumentation befindet sich auch in der Datei wrangler.yaml
, damit Sie sich nicht verlaufen!
Akzeptiert ein einzelnes Positionsargument, den Pfad, in dem Ihr neues Projekt erstellt werden soll:
cd my-sweet-site && wrangler create .
# or
wrangler create my-sweet-site
input_dir
Eingabeverzeichnis wie site/content
output_dir
Ausgabeverzeichnis wie www
wrangler build content www
Rendern erzwingen, unabhängig davon, wann Ihr Inhalt zuletzt geändert wurde:
wrangler build content www --force
Alle Seitenobjekte erneut zwischenspeichern
wrangler build content www --nocache
Ändern Sie die Ausgabedateierweiterung für alle Seiten in „classic asp
. (Warum sollte das jemand tun?)
wrangler build content www -o ".asp"
Ändern Sie das Datenformat, nach dem im input_dir
gesucht werden soll, in json
wrangler build content www -d 'json'
Ändern Sie den Speicherort des Vorlagenverzeichnisses
wrangler build content www -t other-templates-dir
Ändern Sie den Speicherort der Konfigurationsdatei
wrangler build content www -c site/config/wrangler.yaml
Hat alle gleichen Optionen wie wrangler build
Drucken Sie jedes Mal, wenn sich eine Datei ändert, alle Informationen aus:
wrangler watch content www --verbose
Akzeptiert ein Positionsargument (das bereitzustellende Verzeichnis) und einen optionalen --port
(Standard 8000).
wrangler serve www --port 8001
Entfernen Sie den Vorlagencache und den Objektcache aus dem Verzeichnis „var“.
wrangler clean
Wrangler lädt beim Booten alle Python-Module, die sich im lib
Verzeichnis Ihres Projekts befinden.
Dies gibt Ihnen die Möglichkeit, die Kernfunktionen zu erweitern und Seitendaten zu manipulieren – Sie könnten beispielsweise einige Werte aus einer Datenbank laden und sie in Ihren Vorlagen verfügbar machen.
Wenn Sie build
aufrufen, erstellt wrangler eine Darstellung der Baumstruktur in Ihrem content/
-Verzeichnis.
Es verwendet eine doppelt verknüpfte Liste von Node
-Objekten, die in einem NodeGraph
zusammengefasst werden, einem praktischen Container für den Umgang mit den Knoten.
# 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...
Knoten können auf ihre Kinder und auch auf ihre Eltern zugreifen:
# More pseudocode
Node :
path : " content/index.md "
children :
- Node :
- Node :
- Node :
parent :
Node :
Um Ordnung zu schaffen, enthält das Node-Objekt keine Darstellung der Seitendaten direkt – Knoten sind nur Container.
Gemäß den Ideen in dieser Diskussion verfügt der Knoten über eine Frachteigenschaft , die die echte Seitenklasse enthält:
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
Seiten enthalten eine dict
der Daten Ihrer Quelldatei und bieten dem Renderer
eine konsistente Möglichkeit, auf die Daten zuzugreifen. Um eine benutzerdefinierte Seite zu erstellen, erstellen Sie einfach eine Unterklasse wrangler.Core.Page
und sie wird automatisch geladen.
Praktischer Tipp: Wenn Ihre benutzerdefinierte Klasse den Namen Page
hat, überschreibt sie das Standard Page
Objekt für alle Seiten.
# 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 ()
}
In unserem obigen Beispiel ändern wir die drei Hauptseitenmethoden get_content()
, get_metadata()
und get_properties()
Wird beim Rendern der Seite aufgerufen und ist in Ihrer Vorlage als data
verfügbar:
<!doctype html>
< div class = ' dump-of-data-object ' >
{{ data.content }}
</ div >
Wird aufgerufen, wenn die Seite gerendert wird. Dies ist das meta
:
<!doctype html>
< title >{{ meta.title }}
Etwas schwieriger zu erklären, aber trotzdem großartig. Wenn ein Node
gerendert wird, fordert er bestimmte Informationen zu Seiten an, die sich auf die aktuelle Seite beziehen, z. B. die untergeordneten, Geschwister-, Eltern- und manuell verknüpften Seiten.
Anstatt alles mit allen anderen zu teilen, beschreibt jede Page
Klasse die grundlegenden Informationen, die sie gerne mit anderen Seiten teilt.
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 ()
}
Schauen wir uns ein wirklich einfaches Beispiel an, eine benutzerdefinierte Seitenklasse, die den gesamten Text auf der Seite umkehrt. Sehr praktisch.
Legen Sie zunächst die class
in Ihrem Seiten-Meta fest, um Wrangler mitzuteilen, welche Klasse geladen werden soll:
content/custom.md:
---
class : RightToLeft
---
# My custom page
With its custom content.
Erstellen Sie dann irgendwo in Ihrem lib/
-Verzeichnis eine neue Klasse, die Page
unterordnet. Es spielt keine Rolle, wo in Ihrem lib/
-Verzeichnis es landet, die einzige Regel ist, dass es eine Unterklasse des Page
-Objekts bilden muss:
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" ]
Großartig! Unsere Seite wird mit Text von rechts nach links gedruckt.
Wenn Sie sich Ihre wrangler.yaml
Datei ansehen, werden Sie feststellen, dass sie drei Dateitypen akzeptiert: ["yaml", "json", "md"]
Wrangler enthält standardmäßig drei Parser, Yaml
, Markdown
und Json
, die die Eingabedateien verarbeiten und als aussagekräftige Daten darstellen.
Der Autoloader sucht nach allem, was wrangler.Core.Parser
untergeordnet ist.
Sie könnten dies beispielsweise irgendwo in Ihrer lib/Parsers.py
tun, um das Textformat zu unterstützen
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 nutzt Blinkersignale zur Verarbeitung von Hooks und Extensions.
Hooks sind Signale, die an kritischen Punkten im Renderprozess ausgelöst werden. Sie werden in der Reihenfolge verarbeitet, in der sie in Ihren Modulen erscheinen, und können die eingehenden Objekte direkt ändern. Sie haben auch Zugriff auf wrangler's config
, renderer
und 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 ""
Erweiterungen sind Python-Skripte, die praktische Daten an das extensions
Ihrer Vorlagen zurückgeben.
Nehmen wir dieses kleine Skript:
# 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" ]
Wird über Ihre Vorlage unter extensions.YOUR_EXTENSION_NAME
zugänglich sein:
< em class = " extension " >
{{ extensions.my_extension }}
</ em >
Was zu dieser Ausgabe führt:
< i > "This is my basic extension!" </ i >
In Ihrer wrangler.yaml
gibt es einen Abschnitt zum Verwalten Ihrer Erweiterungen:
# My extension just prints a string... not very exciting!
my_extension :
string_to_print : " This is my basic extension! "
Mit Wrangler können Sie Jinja2 mit benutzerdefinierten Filtern erweitern.
Filter können in jede Datei in Ihrem lib-Verzeichnis eingefügt werden, lib/
. Sie sind über einen Dekorator mit dem treffenden Namen template_filter
verbunden
#lib/filters.py
from wrangler . Core import template_filter
from jinja2 import contextfilter
@ template_filter
def my_filter ( value ):
return value . lower ()
Wenn Sie Zugriff auf Jinjas contextfilter
oder envcontextfilter
benötigen, können Sie diese importieren und auch auf Ihre Funktion anwenden:
Lesen Sie mehr über die Kontextfilter von 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