diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e99e36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..bfb6446 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: python +python: + - "2.7" + - "3.2" +before_install: + - sudo apt-get update -qq + - sudo apt-get install -qq --no-install-recommends ruby-sass +install: + - pip install nose + - pip install -e git://github.com/getpelican/pelican.git#egg=pelican + - pip install --use-mirrors Markdown + - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors webassets cssmin; fi +script: nosetests tests diff --git a/Contributing.rst b/Contributing.rst new file mode 100644 index 0000000..913d71c --- /dev/null +++ b/Contributing.rst @@ -0,0 +1,29 @@ +Contributing a plugin +===================== + +Details of how to write a plugin is explained in the official Pelican `docs`_. + +If you want to contribute, please fork this repository and issue your pull +request. Make sure that your plugin follows the structure below:: + + my_plugin + ├── __init__.py + ├── my_plugin.py + └── Readme.rst / Readme.md + +``my_plugin.py`` is the actual plugin implementation. Include a brief +explanation of what the plugin does as a module docstring. Leave any further +explanations and usage details to ``Readme`` file. + +``__init__.py`` should contain a single line with ``from .my_plugin import *``. + +If you have tests for your plugin, place them in the ``tests`` folder with name +``test_my_plugin.py``. You can use ``test_data`` folder inside, if you need content +or templates in your tests. + +**Note:** Plugins in the repository are licensed with *GNU AFFERO GENERAL PUBLIC LICENSE +Version 3*. By submitting a pull request, you accept to release your +contribution under same license. Please refer to the ``LICENSE`` file for +full text of the license. + +.. _docs: http://docs.getpelican.com/en/latest/plugins.html#how-to-create-plugins diff --git a/README.rst b/README.rst deleted file mode 100644 index 41de2bd..0000000 --- a/README.rst +++ /dev/null @@ -1,11 +0,0 @@ -Pelican Plugins -############### - -This repository contains plugins for Pelican. At the moment, this is only a -subset of the available plugins, with others currently residing in the primary -Pelican repository. Those latter plugins will eventually be moved here, so all -plugins will be in one place. - -That being the case, if you have a plugin to contribute, please fork this -Pelican Plugins repository and issue your pull request from there (as opposed -to the primary Pelican repository). diff --git a/Readme.rst b/Readme.rst new file mode 100644 index 0000000..5d957aa --- /dev/null +++ b/Readme.rst @@ -0,0 +1,41 @@ +Pelican Plugins +############### + +Beginning with version 3.0, Pelican supports plugins. Plugins are a way to add +features to Pelican without having to directly modify the Pelican core. Starting +with 3.2, all plugins (including the ones previously in the core) are +moved here, so this is the central place for all plugins. + +How to use plugins +================== + +Easiest way to install and use these plugins is cloning this repo:: + + git clone https://github.com/getpelican/pelican-plugins + +and activating the ones you want in your settings file:: + + PLUGIN_PATH = 'path/to/pelican-plugins' + PLUGINS = ['assets', 'sitemap', 'gravatar'] + +``PLUGIN_PATH`` can be a path relative to your settings file or an absolute path. + +Alternatively, if plugins are in an importable path, you can omit ``PLUGIN_PATH`` +and list them:: + + PLUGINS = ['assets', 'sitemap', 'gravatar'] + +or you can ``import`` the plugin directly and give that:: + + import my_plugin + PLUGINS = [my_plugin, 'assets'] + +Please refer to the ``Readme`` file in a plugin's folder for detailed information about +that plugin. + +Contributing a plugin +===================== + +Please refer to the `Contributing`_ file. + +.. _Contributing: Contributing.rst diff --git a/assets/Readme.rst b/assets/Readme.rst new file mode 100644 index 0000000..a61959f --- /dev/null +++ b/assets/Readme.rst @@ -0,0 +1,80 @@ +Asset management +---------------- + +This plugin allows you to use the `Webassets`_ module to manage assets such as +CSS and JS files. The module must first be installed:: + + pip install webassets + +The Webassets module allows you to perform a number of useful asset management +functions, including: + +* CSS minifier (``cssmin``, ``yui_css``, ...) +* CSS compiler (``less``, ``sass``, ...) +* JS minifier (``uglifyjs``, ``yui_js``, ``closure``, ...) + +Others filters include gzip compression, integration of images in CSS via data +URIs, and more. Webassets can also append a version identifier to your asset +URL to convince browsers to download new versions of your assets when you use +far-future expires headers. Please refer to the `Webassets documentation`_ for +more information. + +When used with Pelican, Webassets is configured to process assets in the +``OUTPUT_PATH/theme`` directory. You can use Webassets in your templates by +including one or more template tags. The Jinja variable ``{{ ASSET_URL }}`` can +be used in templates and is relative to the ``theme/`` url. The +``{{ ASSET_URL }}`` variable should be used in conjunction with the +``{{ SITEURL }}`` variable in order to generate URLs properly. For example: + +.. code-block:: jinja + + {% assets filters="cssmin", output="css/style.min.css", "css/inuit.css", "css/pygment-monokai.css", "css/main.css" %} + + {% endassets %} + +... will produce a minified css file with a version identifier that looks like: + +.. code-block:: html + + + +These filters can be combined. Here is an example that uses the SASS compiler +and minifies the output: + +.. code-block:: jinja + + {% assets filters="sass,cssmin", output="css/style.min.css", "css/style.scss" %} + + {% endassets %} + +Another example for Javascript: + +.. code-block:: jinja + + {% assets filters="uglifyjs,gzip", output="js/packed.js", "js/jquery.js", "js/base.js", "js/widgets.js" %} + + {% endassets %} + +The above will produce a minified and gzipped JS file: + +.. code-block:: html + + + +Pelican's debug mode is propagated to Webassets to disable asset packaging +and instead work with the uncompressed assets. + +Many of Webasset's available compilers have additional configuration options +(i.e. 'Less', 'Sass', 'Stylus', 'Closure_js'). You can pass these options to +Webassets using the ``ASSET_CONFIG`` in your settings file. + +The following will handle Google Closure's compilation level and locate +LessCSS's binary: + +.. code-block:: python + + ASSET_CONFIG = (('closure_compressor_optimization', 'WHITESPACE_ONLY'), + ('less_bin', 'lessc.cmd'), ) + +.. _Webassets: https://github.com/miracle2k/webassets +.. _Webassets documentation: http://webassets.readthedocs.org/en/latest/builtin_filters.html diff --git a/assets/__init__.py b/assets/__init__.py new file mode 100644 index 0000000..67b75dd --- /dev/null +++ b/assets/__init__.py @@ -0,0 +1 @@ +from .assets import * diff --git a/assets/assets.py b/assets/assets.py new file mode 100644 index 0000000..4e2d104 --- /dev/null +++ b/assets/assets.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +""" +Asset management plugin for Pelican +=================================== + +This plugin allows you to use the `webassets`_ module to manage assets such as +CSS and JS files. + +The ASSET_URL is set to a relative url to honor Pelican's RELATIVE_URLS +setting. This requires the use of SITEURL in the templates:: + + + +.. _webassets: https://webassets.readthedocs.org/ + +""" +from __future__ import unicode_literals + +import os +import logging + +from pelican import signals +from webassets import Environment +from webassets.ext.jinja2 import AssetsExtension + + +def add_jinja2_ext(pelican): + """Add Webassets to Jinja2 extensions in Pelican settings.""" + + pelican.settings['JINJA_EXTENSIONS'].append(AssetsExtension) + + +def create_assets_env(generator): + """Define the assets environment and pass it to the generator.""" + + assets_url = 'theme/' + assets_src = os.path.join(generator.output_path, 'theme') + generator.env.assets_environment = Environment(assets_src, assets_url) + + if 'ASSET_CONFIG' in generator.settings: + for item in generator.settings['ASSET_CONFIG']: + generator.env.assets_environment.config[item[0]] = item[1] + + logger = logging.getLogger(__name__) + if logging.getLevelName(logger.getEffectiveLevel()) == "DEBUG": + generator.env.assets_environment.debug = True + + +def register(): + """Plugin registration.""" + + signals.initialized.connect(add_jinja2_ext) + signals.generator_init.connect(create_assets_env) diff --git a/github_activity/Readme.rst b/github_activity/Readme.rst new file mode 100644 index 0000000..fa3b95d --- /dev/null +++ b/github_activity/Readme.rst @@ -0,0 +1,30 @@ +GitHub activity +--------------- + +This plugin makes use of the `feedparser`_ library that you'll need to +install. + +Set the ``GITHUB_ACTIVITY_FEED`` parameter to your GitHub activity feed. +For example, to track Pelican project activity, the setting would be:: + + GITHUB_ACTIVITY_FEED = 'https://github.com/getpelican.atom' + +On the template side, you just have to iterate over the ``github_activity`` +variable, as in this example:: + + {% if GITHUB_ACTIVITY_FEED %} +
+

Github Activity

+ +
+ {% endif %} + +``github_activity`` is a list of lists. The first element is the title, +and the second element is the raw HTML from GitHub. + +.. _feedparser: https://crate.io/packages/feedparser/ diff --git a/github_activity/__init__.py b/github_activity/__init__.py new file mode 100644 index 0000000..19b6db8 --- /dev/null +++ b/github_activity/__init__.py @@ -0,0 +1 @@ +from .github_activity import * diff --git a/github_activity/github_activity.py b/github_activity/github_activity.py new file mode 100644 index 0000000..f0b1e0b --- /dev/null +++ b/github_activity/github_activity.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# NEEDS WORK +""" +Copyright (c) Marco Milanesi + +Github Activity +--------------- +A plugin to list your Github Activity +""" + +from __future__ import unicode_literals, print_function + +from pelican import signals + + +class GitHubActivity(): + """ + A class created to fetch github activity with feedparser + """ + def __init__(self, generator): + try: + import feedparser + self.activities = feedparser.parse( + generator.settings['GITHUB_ACTIVITY_FEED']) + except ImportError: + raise Exception("Unable to find feedparser") + + def fetch(self): + """ + returns a list of html snippets fetched from github actitivy feed + """ + + entries = [] + for activity in self.activities['entries']: + entries.append( + [element for element in [activity['title'], + activity['content'][0]['value']]]) + + return entries + + +def fetch_github_activity(gen, metadata): + """ + registered handler for the github activity plugin + it puts in generator.context the html needed to be displayed on a + template + """ + + if 'GITHUB_ACTIVITY_FEED' in gen.settings.keys(): + gen.context['github_activity'] = gen.plugin_instance.fetch() + + +def feed_parser_initialization(generator): + """ + Initialization of feed parser + """ + + generator.plugin_instance = GitHubActivity(generator) + + +def register(): + """ + Plugin registration + """ + signals.article_generator_init.connect(feed_parser_initialization) + signals.article_generate_context.connect(fetch_github_activity) diff --git a/global_license/Readme.rst b/global_license/Readme.rst new file mode 100644 index 0000000..0b314f0 --- /dev/null +++ b/global_license/Readme.rst @@ -0,0 +1,6 @@ +Global license +-------------- + +This plugin allows you to define a ``LICENSE`` setting and adds the contents of that +license variable to the article's context, making that variable available to use +from within your theme's templates. diff --git a/global_license/__init__.py b/global_license/__init__.py new file mode 100644 index 0000000..ffe2862 --- /dev/null +++ b/global_license/__init__.py @@ -0,0 +1 @@ +from .global_license import * diff --git a/global_license/global_license.py b/global_license/global_license.py new file mode 100644 index 0000000..60c4fe9 --- /dev/null +++ b/global_license/global_license.py @@ -0,0 +1,18 @@ +""" +License plugin for Pelican +========================== + +This plugin allows you to define a LICENSE setting and adds the contents of that +license variable to the article's context, making that variable available to use +from within your theme's templates. +""" + +from pelican import signals + +def add_license(generator, metadata): + if 'license' not in metadata.keys()\ + and 'LICENSE' in generator.settings.keys(): + metadata['license'] = generator.settings['LICENSE'] + +def register(): + signals.article_generate_context.connect(add_license) diff --git a/pelicanext/goodreads_activity/README.md b/goodreads_activity/Readme.md similarity index 100% rename from pelicanext/goodreads_activity/README.md rename to goodreads_activity/Readme.md diff --git a/goodreads_activity/__init__.py b/goodreads_activity/__init__.py new file mode 100644 index 0000000..176113d --- /dev/null +++ b/goodreads_activity/__init__.py @@ -0,0 +1 @@ +from .goodreads_activity import * \ No newline at end of file diff --git a/pelicanext/goodreads_activity/goodreads_activity.py b/goodreads_activity/goodreads_activity.py similarity index 91% rename from pelicanext/goodreads_activity/goodreads_activity.py rename to goodreads_activity/goodreads_activity.py index 8e1ebc0..e92c3d3 100644 --- a/pelicanext/goodreads_activity/goodreads_activity.py +++ b/goodreads_activity/goodreads_activity.py @@ -1,4 +1,13 @@ # -*- coding: utf-8 -*- +""" +Goodreads Activity +================== + +A Pelican plugin to lists books from your Goodreads shelves. + +Copyright (c) Talha Mansoor +""" + from __future__ import unicode_literals from pelican import signals import feedparser diff --git a/gravatar/Readme.rst b/gravatar/Readme.rst new file mode 100644 index 0000000..a37335d --- /dev/null +++ b/gravatar/Readme.rst @@ -0,0 +1,15 @@ +Gravatar +-------- + +This plugin assigns the ``author_gravatar`` variable to the Gravatar URL and +makes the variable available within the article's context. You can add +``AUTHOR_EMAIL`` to your settings file to define the default author's email +address. Obviously, that email address must be associated with a Gravatar +account. + +Alternatively, you can provide an email address from within article metadata:: + + :email: john.doe@example.com + +If the email address is defined via at least one of the two methods above, +the ``author_gravatar`` variable is added to the article's context. diff --git a/gravatar/__init__.py b/gravatar/__init__.py new file mode 100644 index 0000000..cc60487 --- /dev/null +++ b/gravatar/__init__.py @@ -0,0 +1 @@ +from .gravatar import * diff --git a/gravatar/gravatar.py b/gravatar/gravatar.py new file mode 100644 index 0000000..303d3c0 --- /dev/null +++ b/gravatar/gravatar.py @@ -0,0 +1,31 @@ +""" +Gravatar plugin for Pelican +=========================== + +This plugin assigns the ``author_gravatar`` variable to the Gravatar URL and +makes the variable available within the article's context. +""" + +import hashlib +import six + +from pelican import signals + + +def add_gravatar(generator, metadata): + + #first check email + if 'email' not in metadata.keys()\ + and 'AUTHOR_EMAIL' in generator.settings.keys(): + metadata['email'] = generator.settings['AUTHOR_EMAIL'] + + #then add gravatar url + if 'email' in metadata.keys(): + email_bytes = six.b(metadata['email']).lower() + gravatar_url = "http://www.gravatar.com/avatar/" + \ + hashlib.md5(email_bytes).hexdigest() + metadata["author_gravatar"] = gravatar_url + + +def register(): + signals.article_generate_context.connect(add_gravatar) diff --git a/gzip_cache/Readme.rst b/gzip_cache/Readme.rst new file mode 100644 index 0000000..c5ff76f --- /dev/null +++ b/gzip_cache/Readme.rst @@ -0,0 +1,10 @@ +Gzip cache +---------- + +Certain web servers (e.g., Nginx) can use a static cache of gzip-compressed +files to prevent the server from compressing files during an HTTP call. Since +compression occurs at another time, these compressed files can be compressed +at a higher compression level for increased optimization. + +The ``gzip_cache`` plugin compresses all common text type files into a ``.gz`` +file within the same directory as the original file. diff --git a/gzip_cache/__init__.py b/gzip_cache/__init__.py new file mode 100644 index 0000000..fb76712 --- /dev/null +++ b/gzip_cache/__init__.py @@ -0,0 +1 @@ +from .gzip_cache import * diff --git a/gzip_cache/gzip_cache.py b/gzip_cache/gzip_cache.py new file mode 100644 index 0000000..1a8dd83 --- /dev/null +++ b/gzip_cache/gzip_cache.py @@ -0,0 +1,84 @@ +''' +Copyright (c) 2012 Matt Layman + +Gzip cache +---------- + +A plugin to create .gz cache files for optimization. +''' + +import gzip +import logging +import os + +from pelican import signals + +logger = logging.getLogger(__name__) + +# A list of file types to exclude from possible compression +EXCLUDE_TYPES = [ + # Compressed types + '.bz2', + '.gz', + + # Audio types + '.aac', + '.flac', + '.mp3', + '.wma', + + # Image types + '.gif', + '.jpg', + '.jpeg', + '.png', + + # Video types + '.avi', + '.mov', + '.mp4', +] + +def create_gzip_cache(pelican): + '''Create a gzip cache file for every file that a webserver would + reasonably want to cache (e.g., text type files). + + :param pelican: The Pelican instance + ''' + for dirpath, _, filenames in os.walk(pelican.settings['OUTPUT_PATH']): + for name in filenames: + if should_compress(name): + filepath = os.path.join(dirpath, name) + create_gzip_file(filepath) + +def should_compress(filename): + '''Check if the filename is a type of file that should be compressed. + + :param filename: A file name to check against + ''' + for extension in EXCLUDE_TYPES: + if filename.endswith(extension): + return False + + return True + +def create_gzip_file(filepath): + '''Create a gzipped file in the same directory with a filepath.gz name. + + :param filepath: A file to compress + ''' + compressed_path = filepath + '.gz' + + with open(filepath, 'rb') as uncompressed: + try: + logger.debug('Compressing: %s' % filepath) + compressed = gzip.open(compressed_path, 'wb') + compressed.writelines(uncompressed) + except Exception as ex: + logger.critical('Gzip compression failed: %s' % ex) + finally: + compressed.close() + +def register(): + signals.finalized.connect(create_gzip_cache) + diff --git a/html_rst_directive/Readme.rst b/html_rst_directive/Readme.rst new file mode 100644 index 0000000..93a7a1d --- /dev/null +++ b/html_rst_directive/Readme.rst @@ -0,0 +1,45 @@ +HTML tags for reStructuredText +------------------------------ + +This plugin allows you to use HTML tags from within reST documents. + + +Directives +---------- + + +:: + + .. html:: + + (HTML code) + + +Example +------- + +A search engine:: + + .. html:: + +
+ + + +
+ + +A contact form:: + + .. html:: + +
+

+ +
+ +
+ +

+
diff --git a/html_rst_directive/__init__.py b/html_rst_directive/__init__.py new file mode 100644 index 0000000..57ec228 --- /dev/null +++ b/html_rst_directive/__init__.py @@ -0,0 +1 @@ +from .html_rst_directive import * diff --git a/html_rst_directive/html_rst_directive.py b/html_rst_directive/html_rst_directive.py new file mode 100644 index 0000000..ed877da --- /dev/null +++ b/html_rst_directive/html_rst_directive.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +""" +HTML tags for reStructuredText +============================== + +This plugin allows you to use HTML tags from within reST documents. + +""" + +from __future__ import unicode_literals +from docutils import nodes +from docutils.parsers.rst import directives, Directive + + +class RawHtml(Directive): + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = True + has_content = True + + def run(self): + html = ' '.join(self.content) + node = nodes.raw('', html, format='html') + return [node] + + + +def register(): + directives.register_directive('html', RawHtml) + diff --git a/pelicanext/latex/Readme.md b/latex/Readme.md similarity index 100% rename from pelicanext/latex/Readme.md rename to latex/Readme.md diff --git a/latex/__init__.py b/latex/__init__.py new file mode 100644 index 0000000..1b2ce76 --- /dev/null +++ b/latex/__init__.py @@ -0,0 +1 @@ +from .latex import * \ No newline at end of file diff --git a/latex/latex.py b/latex/latex.py new file mode 100644 index 0000000..2ebd1c7 --- /dev/null +++ b/latex/latex.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +""" +Latex Plugin For Pelican +======================== + +This plugin allows you to write mathematical equations in your articles using Latex. +It uses the MathJax Latex JavaScript library to render latex that is embedded in +between `$..$` for inline math and `$$..$$` for displayed math. It also allows for +writing equations in by using `\begin{equation}`...`\end{equation}`. +""" + +from pelican import signals + +latexScript = """ + +""" + +def addLatex(gen, metadata): + """ + The registered handler for the latex plugin. It will add + the latex script to the article metadata + """ + if 'LATEX' in gen.settings.keys() and gen.settings['LATEX'] == 'article': + if 'latex' in metadata.keys(): + metadata['latex'] = latexScript + else: + metadata['latex'] = latexScript + +def register(): + """ + Plugin registration + """ + signals.article_generate_context.connect(addLatex) diff --git a/pelicanext/multi_part/README.md b/multi_part/Readme.md similarity index 87% rename from pelicanext/multi_part/README.md rename to multi_part/Readme.md index ec553eb..f6caf93 100644 --- a/pelicanext/multi_part/README.md +++ b/multi_part/Readme.md @@ -7,7 +7,9 @@ In order to mark posts as part of a multi-part post, use the `:parts:` metadata: :parts: MY_AWESOME_MULTI_PART_POST -You can then use the `article.related_posts` variable in your templates to display other parts of current post. +You can then use the `article.metadata.parts_articles` variable in your templates +to display other parts of current post. + For example: {% if article.metadata.parts_articles %} diff --git a/multi_part/__init__.py b/multi_part/__init__.py new file mode 100644 index 0000000..6e00046 --- /dev/null +++ b/multi_part/__init__.py @@ -0,0 +1 @@ +from .multi_part import * diff --git a/pelicanext/multi_part/multi_part.py b/multi_part/multi_part.py similarity index 53% rename from pelicanext/multi_part/multi_part.py rename to multi_part/multi_part.py index 0581b50..8aa3bca 100644 --- a/pelicanext/multi_part/multi_part.py +++ b/multi_part/multi_part.py @@ -6,33 +6,8 @@ Multiple part support ===================== Create a navigation menu for multi-part related_posts - -Article metadata: ------------------- - -:parts: a unique identifier for multi-part posts, must be the same in each -post part. - -Usage ------ - {% if article.metadata.parts_articles %} -
    - {% for part_article in article.metadata.parts_articles %} - {% if part_article == article %} -
  1. - {{ part_article.title }} - -
  2. - {% else %} -
  3. - {{ part_article.title }} - -
  4. - {% endif %} - {% endfor %} -
- {% endif %} """ + from collections import defaultdict from pelican import signals diff --git a/pelicanext/neighbors/README.rst b/neighbors/Readme.rst similarity index 55% rename from pelicanext/neighbors/README.rst rename to neighbors/Readme.rst index e772fde..e6f7eb5 100644 --- a/pelicanext/neighbors/README.rst +++ b/neighbors/Readme.rst @@ -4,23 +4,6 @@ Neighbor Articles Plugin for Pelican This plugin adds ``next_article`` (newer) and ``prev_article`` (older) variables to the article's context -Installation ------------- -To enable, ensure that ``neighbors.py`` is in somewhere you can ``import``. -Then use the following in your `settings`:: - - PLUGINS = ["neighbors"] - -Or you can put the plugin in ``plugins`` folder in pelican installation. You -can find the location by typing:: - - python -c 'import pelican.plugins as p, os; print os.path.dirname(p.__file__)' - -Once you get the folder, copy the ``neighbors.py`` there and use the following -in your settings:: - - PLUGINS = ["pelican.plugins.neighbors"] - Usage ----- @@ -41,4 +24,4 @@ Usage {% endif %} - \ No newline at end of file + diff --git a/neighbors/__init__.py b/neighbors/__init__.py new file mode 100644 index 0000000..9038d7e --- /dev/null +++ b/neighbors/__init__.py @@ -0,0 +1 @@ +from .neighbors import * diff --git a/pelicanext/neighbors/neighbors.py b/neighbors/neighbors.py similarity index 100% rename from pelicanext/neighbors/neighbors.py rename to neighbors/neighbors.py diff --git a/pelicanext/latex/latex.py b/pelicanext/latex/latex.py deleted file mode 100644 index 8785fdf..0000000 --- a/pelicanext/latex/latex.py +++ /dev/null @@ -1,112 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Latex Plugin For Pelican -======================== - -This plugin allows you to write mathematical equations in your articles using Latex. -It uses the MathJax Latex JavaScript library to render latex that is embedded in -between `$..$` for inline math and `$$..$$` for displayed math. It also allows for -writing equations in by using `\begin{equation}`...`\end{equation}`. - -Installation ------------- - -To enable, ensure that `latex.py` is put somewhere that is accessible. -Then use as follows by adding the following to your settings.py: - - PLUGINS = ["latex"] - -Be careful: Not loading the plugin is easy to do, and difficult to detect. To -make life easier, find where pelican is installed, and then copy the plugin -there. An easy way to find where pelican is installed is to verbose list the -available themes by typing `pelican-themes -l -v`. - -Once the pelican folder is found, copy `latex.py` to the `plugins` folder. Then -add to settings.py like this: - - PLUGINS = ["pelican.plugins.latex"] - -Now all that is left to do is to embed the following to your template file -between the `` parameters (for the NotMyIdea template, this file is base.html) - - {% if article and article.latex %} - {{ article.latex }} - {% endif %} - -Usage ------ -Latex will be embedded in every article. If however you want latex only for -selected articles, then in settings.py, add - - LATEX = 'article' - -And in each article, add the metadata key `latex:`. For example, with the above -settings, creating an article that I want to render latex math, I would just -include 'Latex' as part of the metadata without any value: - - Date: 1 sep 2012 - Status: draft - Latex: - -Latex Examples --------------- -###Inline -Latex between `$`..`$`, for example, `$`x^2`$`, will be rendered inline -with respect to the current html block. - -###Displayed Math -Latex between `$$`..`$$`, for example, `$$`x^2`$$`, will be rendered centered in a -new paragraph. - -###Equations -Latex between `\begin` and `\end`, for example, `begin{equation}` x^2 `\end{equation}`, -will be rendered centered in a new paragraph with a right justified equation number -at the top of the paragraph. This equation number can be referenced in the document. -To do this, use a `label` inside of the equation format and then refer to that label -using `ref`. For example: `begin{equation}` `\label{eq}` X^2 `\end{equation}`. Now -refer to that equation number by `$`\ref{eq}`$`. - -Template And Article Examples ------------------------------ -To see an example of this plugin in action, look at -[this article](http://doctrina.org/How-RSA-Works-With-Examples.html). To see how -this plugin works with a template, look at -[this template](https://github.com/barrysteyn/pelican_theme-personal_blog). -""" - -from pelican import signals - -latexScript = """ - -""" - -def addLatex(gen, metadata): - """ - The registered handler for the latex plugin. It will add - the latex script to the article metadata - """ - if 'LATEX' in gen.settings.keys() and gen.settings['LATEX'] == 'article': - if 'latex' in metadata.keys(): - metadata['latex'] = latexScript - else: - metadata['latex'] = latexScript - -def register(): - """ - Plugin registration - """ - signals.article_generate_context.connect(addLatex) diff --git a/pelicanext/random_article/Readme.md b/pelicanext/random_article/Readme.md deleted file mode 100644 index f12a899..0000000 --- a/pelicanext/random_article/Readme.md +++ /dev/null @@ -1,36 +0,0 @@ -Random Article Plugin For Pelican -======================== - -This plugin generates a html file which redirect to a random article -using javascript's window.location. The generated html file is -saved at SITEURL. - -Only published articles are listed to redirect. - - -Installation ------------- - -To enable, ensure that `random_article.py` is put somewhere that is accessible. -Then use as follows by adding the following to your settings.py: - - PLUGINS = ["random_article"] - -An easy way to find where pelican is installed is to verbose list the -available themes by typing `pelican-themes -l -v`. - -Once the pelican folder is found, copy `random_article.py` to the `plugins` folder. Then -add to settings.py like this: - - PLUGINS = ["pelican.plugins.random_article"] - -Usage ------ - -To use it you have to add in your config file the name of the file to use: - - RANDOM = 'random.html' - -Then in some template you add: - - random article diff --git a/pelicanext/sitemap/__init__.py b/pelicanext/sitemap/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/random_article/Readme.md b/random_article/Readme.md new file mode 100644 index 0000000..fcf00a1 --- /dev/null +++ b/random_article/Readme.md @@ -0,0 +1,19 @@ +Random Article Plugin For Pelican +======================== + +This plugin generates a html file which redirect to a random article +using javascript's `window.location`. The generated html file is +saved at `SITEURL`. + +Only published articles are listed to redirect. + +Usage +----- + +To use it you have to add in your config file the name of the file to use: + + RANDOM = 'random.html' + +Then in some template you add: + + random article diff --git a/random_article/__init__.py b/random_article/__init__.py new file mode 100644 index 0000000..b59a6a0 --- /dev/null +++ b/random_article/__init__.py @@ -0,0 +1 @@ +from .random_article import * diff --git a/pelicanext/random_article/random_article.py b/random_article/random_article.py similarity index 89% rename from pelicanext/random_article/random_article.py rename to random_article/random_article.py index 056c542..8f49448 100644 --- a/pelicanext/random_article/random_article.py +++ b/random_article/random_article.py @@ -1,4 +1,13 @@ # -*- coding: utf-8 -*- +""" +Random Article Plugin For Pelican +======================== + +This plugin generates a html file which redirect to a random article +using javascript's window.location. The generated html file is +saved at SITEURL. +""" + from __future__ import unicode_literals import os.path diff --git a/related_posts/Readme.rst b/related_posts/Readme.rst new file mode 100644 index 0000000..db97149 --- /dev/null +++ b/related_posts/Readme.rst @@ -0,0 +1,19 @@ +Related posts +------------- + +This plugin adds the ``related_posts`` variable to the article's context. +By default, up to 5 articles are listed. You can customize this value by +defining ``RELATED_POSTS_MAX`` in your settings file:: + + RELATED_POSTS_MAX = 10 + +You can then use the ``article.related_posts`` variable in your templates. +For example:: + + {% if article.related_posts %} + + {% endif %} diff --git a/related_posts/__init__.py b/related_posts/__init__.py new file mode 100644 index 0000000..057540e --- /dev/null +++ b/related_posts/__init__.py @@ -0,0 +1 @@ +from .related_posts import * diff --git a/related_posts/related_posts.py b/related_posts/related_posts.py new file mode 100644 index 0000000..8199900 --- /dev/null +++ b/related_posts/related_posts.py @@ -0,0 +1,35 @@ +""" +Related posts plugin for Pelican +================================ + +Adds related_posts variable to article's context +""" + +from pelican import signals +from collections import Counter + + +def add_related_posts(generator): + # get the max number of entries from settings + # or fall back to default (5) + numentries = generator.settings.get('RELATED_POSTS_MAX', 5) + + for article in generator.articles: + # no tag, no relation + if not hasattr(article, 'tags'): + continue + + # score = number of common tags + scores = Counter() + for tag in article.tags: + scores += Counter(generator.tags[tag]) + + # remove itself + scores.pop(article) + + article.related_posts = [other for other, count + in scores.most_common(numentries)] + + +def register(): + signals.article_generator_finalized.connect(add_related_posts) \ No newline at end of file diff --git a/sitemap/Readme.rst b/sitemap/Readme.rst new file mode 100644 index 0000000..b58a8d5 --- /dev/null +++ b/sitemap/Readme.rst @@ -0,0 +1,65 @@ +Sitemap +------- + +The sitemap plugin generates plain-text or XML sitemaps. You can use the +``SITEMAP`` variable in your settings file to configure the behavior of the +plugin. + +The ``SITEMAP`` variable must be a Python dictionary and can contain three keys: + +- ``format``, which sets the output format of the plugin (``xml`` or ``txt``) + +- ``priorities``, which is a dictionary with three keys: + + - ``articles``, the priority for the URLs of the articles and their + translations + + - ``pages``, the priority for the URLs of the static pages + + - ``indexes``, the priority for the URLs of the index pages, such as tags, + author pages, categories indexes, archives, etc... + + All the values of this dictionary must be decimal numbers between ``0`` and ``1``. + +- ``changefreqs``, which is a dictionary with three items: + + - ``articles``, the update frequency of the articles + + - ``pages``, the update frequency of the pages + + - ``indexes``, the update frequency of the index pages + + Valid frequency values are ``always``, ``hourly``, ``daily``, ``weekly``, ``monthly``, + ``yearly`` and ``never``. + +If a key is missing or a value is incorrect, it will be replaced with the +default value. + +The sitemap is saved in ``/sitemap.``. + +.. note:: + ``priorities`` and ``changefreqs`` are information for search engines. + They are only used in the XML sitemaps. + For more information: + +**Example** + +Here is an example configuration (it's also the default settings): + +.. code-block:: python + + PLUGINS=['pelican.plugins.sitemap',] + + SITEMAP = { + 'format': 'xml', + 'priorities': { + 'articles': 0.5, + 'indexes': 0.5, + 'pages': 0.5 + }, + 'changefreqs': { + 'articles': 'monthly', + 'indexes': 'daily', + 'pages': 'monthly' + } + } diff --git a/sitemap/__init__.py b/sitemap/__init__.py new file mode 100644 index 0000000..6523d3a --- /dev/null +++ b/sitemap/__init__.py @@ -0,0 +1 @@ +from .sitemap import * \ No newline at end of file diff --git a/pelicanext/sitemap/sitemap.py b/sitemap/sitemap.py similarity index 98% rename from pelicanext/sitemap/sitemap.py rename to sitemap/sitemap.py index 8043baa..33529b7 100644 --- a/pelicanext/sitemap/sitemap.py +++ b/sitemap/sitemap.py @@ -1,4 +1,11 @@ # -*- coding: utf-8 -*- +''' +Sitemap +------- + +The sitemap plugin generates plain-text or XML sitemaps. +''' + from __future__ import unicode_literals import collections diff --git a/summary/Readme.rst b/summary/Readme.rst new file mode 100644 index 0000000..08691da --- /dev/null +++ b/summary/Readme.rst @@ -0,0 +1,27 @@ +Summary +------- + +This plugin allows easy, variable length summaries directly embedded into the +body of your articles. It introduces two new settings: ``SUMMARY_BEGIN_MARKER`` +and ``SUMMARY_END_MARKER``: strings which can be placed directly into an article +to mark the beginning and end of a summary. When found, the standard +``SUMMARY_MAX_LENGTH`` setting will be ignored. The markers themselves will also +be removed from your articles before they are published. The default values +are ```` and ````. +For example:: + + Title: My super title + Date: 2010-12-03 10:20 + Tags: thats, awesome + Category: yeah + Slug: my-super-post + Author: Alexis Metaireau + + This is the content of my super blog post. + + and this content occurs after the summary. + +Here, the summary is taken to be the first line of the post. Because no +beginning marker was found, it starts at the top of the body. It is possible +to leave out the end marker instead, in which case the summary will start at the +beginning marker and continue to the end of the body. diff --git a/summary/__init__.py b/summary/__init__.py new file mode 100644 index 0000000..afe9311 --- /dev/null +++ b/summary/__init__.py @@ -0,0 +1 @@ +from .summary import * diff --git a/summary/summary.py b/summary/summary.py new file mode 100644 index 0000000..500e6ec --- /dev/null +++ b/summary/summary.py @@ -0,0 +1,61 @@ +""" +Summary +------- + +This plugin allows easy, variable length summaries directly embedded into the +body of your articles. +""" + +import types + +from pelican import signals + +def initialized(pelican): + from pelican.settings import _DEFAULT_CONFIG + _DEFAULT_CONFIG.setdefault('SUMMARY_BEGIN_MARKER', + '') + _DEFAULT_CONFIG.setdefault('SUMMARY_END_MARKER', + '') + if pelican: + pelican.settings.setdefault('SUMMARY_BEGIN_MARKER', + '') + pelican.settings.setdefault('SUMMARY_END_MARKER', + '') + +def content_object_init(instance): + # if summary is already specified, use it + if 'summary' in instance.metadata: + return + + def _get_content(self): + content = self._content + if self.settings['SUMMARY_BEGIN_MARKER']: + content = content.replace( + self.settings['SUMMARY_BEGIN_MARKER'], '', 1) + if self.settings['SUMMARY_END_MARKER']: + content = content.replace( + self.settings['SUMMARY_END_MARKER'], '', 1) + return content + instance._get_content = types.MethodType(_get_content, instance) + + # extract out our summary + if not hasattr(instance, '_summary') and instance._content is not None: + content = instance._content + begin_summary = -1 + end_summary = -1 + if instance.settings['SUMMARY_BEGIN_MARKER']: + begin_summary = content.find(instance.settings['SUMMARY_BEGIN_MARKER']) + if instance.settings['SUMMARY_END_MARKER']: + end_summary = content.find(instance.settings['SUMMARY_END_MARKER']) + if begin_summary != -1 or end_summary != -1: + # the beginning position has to take into account the length + # of the marker + begin_summary = (begin_summary + + len(instance.settings['SUMMARY_BEGIN_MARKER']) + if begin_summary != -1 else 0) + end_summary = end_summary if end_summary != -1 else None + instance._summary = content[begin_summary:end_summary] + +def register(): + signals.initialized.connect(initialized) + signals.content_object_init.connect(content_object_init) diff --git a/tests/Readme.rst b/tests/Readme.rst new file mode 100644 index 0000000..9ed244d --- /dev/null +++ b/tests/Readme.rst @@ -0,0 +1,13 @@ +Test Data +--------- + +Place tests for your plugin here. ``test_data`` folder contains following +common data for your tests, if you need them. + +=============== =========================== +File/Folder Description +=============== =========================== +content A sample content folder +themes Default themes from Pelican +pelican.conf.py A sample settings file +=============== =========================== diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..32353ea --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,2 @@ +import logging +logging.getLogger().addHandler(logging.NullHandler()) diff --git a/tests/test_assets.py b/tests/test_assets.py new file mode 100644 index 0000000..1c14b2b --- /dev/null +++ b/tests/test_assets.py @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- +# from __future__ import unicode_literals + +import hashlib +import locale +import os +from codecs import open +from tempfile import mkdtemp +from shutil import rmtree +import unittest +import subprocess + +from pelican import Pelican +from pelican.settings import read_settings + +CUR_DIR = os.path.dirname(__file__) +THEME_DIR = os.path.join(CUR_DIR, 'test_data', 'themes', 'assets_theme') +CSS_REF = open(os.path.join(THEME_DIR, 'static', 'css', + 'style.min.css')).read() +CSS_HASH = hashlib.md5(CSS_REF).hexdigest()[0:8] + + +def skipIfNoExecutable(executable): + """Skip test if `executable` is not found + + Tries to run `executable` with subprocess to make sure it's in the path, + and skips the tests if not found (if subprocess raises a `OSError`). + """ + + with open(os.devnull, 'w') as fnull: + try: + res = subprocess.call(executable, stdout=fnull, stderr=fnull) + except OSError: + res = None + + if res is None: + return unittest.skip('{0} executable not found'.format(executable)) + + return lambda func: func + + +def module_exists(module_name): + """Test if a module is importable.""" + + try: + __import__(module_name) + except ImportError: + return False + else: + return True + + + +@unittest.skipUnless(module_exists('webassets'), "webassets isn't installed") +@skipIfNoExecutable(['scss', '-v']) +@skipIfNoExecutable(['cssmin', '--version']) +class TestWebAssets(unittest.TestCase): + """Base class for testing webassets.""" + + def setUp(self, override=None): + import assets + + self.temp_path = mkdtemp(prefix='pelicantests.') + settings = { + 'PATH': os.path.join(CUR_DIR, 'test_data', 'content'), + 'OUTPUT_PATH': self.temp_path, + 'PLUGINS': [assets], + 'THEME': THEME_DIR, + 'LOCALE': locale.normalize('en_US'), + } + if override: + settings.update(override) + + self.settings = read_settings(override=settings) + pelican = Pelican(settings=self.settings) + pelican.run() + + def tearDown(self): + rmtree(self.temp_path) + + def check_link_tag(self, css_file, html_file): + """Check the presence of `css_file` in `html_file`.""" + + link_tag = ('' + .format(css_file=css_file)) + html = open(html_file).read() + self.assertRegexpMatches(html, link_tag) + + +class TestWebAssetsRelativeURLS(TestWebAssets): + """Test pelican with relative urls.""" + + + def setUp(self): + TestWebAssets.setUp(self, override={'RELATIVE_URLS': True}) + + def test_jinja2_ext(self): + # Test that the Jinja2 extension was correctly added. + + from webassets.ext.jinja2 import AssetsExtension + self.assertIn(AssetsExtension, self.settings['JINJA_EXTENSIONS']) + + def test_compilation(self): + # Compare the compiled css with the reference. + + gen_file = os.path.join(self.temp_path, 'theme', 'gen', + 'style.{0}.min.css'.format(CSS_HASH)) + self.assertTrue(os.path.isfile(gen_file)) + + css_new = open(gen_file).read() + self.assertEqual(css_new, CSS_REF) + + def test_template(self): + # Look in the output files for the link tag. + + css_file = './theme/gen/style.{0}.min.css'.format(CSS_HASH) + html_files = ['index.html', 'archives.html', + 'this-is-a-super-article.html'] + for f in html_files: + self.check_link_tag(css_file, os.path.join(self.temp_path, f)) + + self.check_link_tag( + '../theme/gen/style.{0}.min.css'.format(CSS_HASH), + os.path.join(self.temp_path, 'category/yeah.html')) + + +class TestWebAssetsAbsoluteURLS(TestWebAssets): + """Test pelican with absolute urls.""" + + def setUp(self): + TestWebAssets.setUp(self, override={'RELATIVE_URLS': False, + 'SITEURL': 'http://localhost'}) + + def test_absolute_url(self): + # Look in the output files for the link tag with absolute url. + + css_file = ('http://localhost/theme/gen/style.{0}.min.css' + .format(CSS_HASH)) + html_files = ['index.html', 'archives.html', + 'this-is-a-super-article.html'] + for f in html_files: + self.check_link_tag(css_file, os.path.join(self.temp_path, f)) diff --git a/tests/test_data/content/2012-11-30_filename-metadata.rst b/tests/test_data/content/2012-11-30_filename-metadata.rst new file mode 100644 index 0000000..b048103 --- /dev/null +++ b/tests/test_data/content/2012-11-30_filename-metadata.rst @@ -0,0 +1,4 @@ +FILENAME_METADATA example +######################### + +Some cool stuff! diff --git a/tests/test_data/content/another_super_article-fr.rst b/tests/test_data/content/another_super_article-fr.rst new file mode 100644 index 0000000..71ac963 --- /dev/null +++ b/tests/test_data/content/another_super_article-fr.rst @@ -0,0 +1,7 @@ +Trop bien ! +########### + +:lang: fr +:slug: oh-yeah + +Et voila du contenu en français diff --git a/tests/test_data/content/another_super_article.rst b/tests/test_data/content/another_super_article.rst new file mode 100644 index 0000000..e6e0a92 --- /dev/null +++ b/tests/test_data/content/another_super_article.rst @@ -0,0 +1,20 @@ +Oh yeah ! +######### + +:tags: oh, bar, yeah +:date: 2010-10-20 10:14 +:category: bar +:author: Alexis Métaireau +:slug: oh-yeah +:license: WTFPL + +Why not ? +========= + +After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst ! +YEAH ! + +.. image:: |filename|/pictures/Sushi.jpg + :height: 450 px + :width: 600 px + :alt: alternate text diff --git a/tests/test_data/content/article2-fr.rst b/tests/test_data/content/article2-fr.rst new file mode 100644 index 0000000..31970f7 --- /dev/null +++ b/tests/test_data/content/article2-fr.rst @@ -0,0 +1,9 @@ +Deuxième article +################ + +:tags: foo, bar, baz +:date: 2012-02-29 +:lang: fr +:slug: second-article + +Ceci est un article, en français. diff --git a/tests/test_data/content/article2.rst b/tests/test_data/content/article2.rst new file mode 100644 index 0000000..66f768e --- /dev/null +++ b/tests/test_data/content/article2.rst @@ -0,0 +1,9 @@ +Second article +############## + +:tags: foo, bar, baz +:date: 2012-02-29 +:lang: en +:slug: second-article + +This is some article, in english diff --git a/tests/test_data/content/cat1/article1.rst b/tests/test_data/content/cat1/article1.rst new file mode 100644 index 0000000..1148a8f --- /dev/null +++ b/tests/test_data/content/cat1/article1.rst @@ -0,0 +1,7 @@ +Article 1 +######### + +:date: 2011-02-17 +:yeah: oh yeah ! + +Article 1 diff --git a/tests/test_data/content/cat1/article2.rst b/tests/test_data/content/cat1/article2.rst new file mode 100644 index 0000000..a4f8786 --- /dev/null +++ b/tests/test_data/content/cat1/article2.rst @@ -0,0 +1,6 @@ +Article 2 +######### + +:date: 2011-02-17 + +Article 2 diff --git a/tests/test_data/content/cat1/article3.rst b/tests/test_data/content/cat1/article3.rst new file mode 100644 index 0000000..5347117 --- /dev/null +++ b/tests/test_data/content/cat1/article3.rst @@ -0,0 +1,6 @@ +Article 3 +######### + +:date: 2011-02-17 + +Article 3 diff --git a/tests/test_data/content/cat1/markdown-article.md b/tests/test_data/content/cat1/markdown-article.md new file mode 100644 index 0000000..5307b47 --- /dev/null +++ b/tests/test_data/content/cat1/markdown-article.md @@ -0,0 +1,7 @@ +Title: A markdown powered article +Date: 2011-04-20 + +You're mutually oblivious. + +[a root-relative link to unbelievable](|filename|/unbelievable.rst) +[a file-relative link to unbelievable](|filename|../unbelievable.rst) diff --git a/tests/test_data/content/draft_article.rst b/tests/test_data/content/draft_article.rst new file mode 100644 index 0000000..76ce9a1 --- /dev/null +++ b/tests/test_data/content/draft_article.rst @@ -0,0 +1,7 @@ +A draft article +############### + +:status: draft + +This is a draft article, it should live under the /drafts/ folder and not be +listed anywhere else. diff --git a/tests/test_data/content/extra/robots.txt b/tests/test_data/content/extra/robots.txt new file mode 100644 index 0000000..ae5b0d0 --- /dev/null +++ b/tests/test_data/content/extra/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: /static/pictures diff --git a/tests/test_data/content/pages/hidden_page.rst b/tests/test_data/content/pages/hidden_page.rst new file mode 100644 index 0000000..ab8704e --- /dev/null +++ b/tests/test_data/content/pages/hidden_page.rst @@ -0,0 +1,9 @@ +This is a test hidden page +########################## + +:category: test +:status: hidden + +This is great for things like error(404) pages +Anyone can see this page but it's not linked to anywhere! + diff --git a/tests/test_data/content/pages/jinja2_template.html b/tests/test_data/content/pages/jinja2_template.html new file mode 100644 index 0000000..1b0dc4e --- /dev/null +++ b/tests/test_data/content/pages/jinja2_template.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% block content %} + +Some text + +{% endblock %} diff --git a/tests/test_data/content/pages/override_url_saveas.rst b/tests/test_data/content/pages/override_url_saveas.rst new file mode 100644 index 0000000..8a515f6 --- /dev/null +++ b/tests/test_data/content/pages/override_url_saveas.rst @@ -0,0 +1,9 @@ +Override url/save_as +#################### + +:date: 2012-12-07 +:url: override/ +:save_as: override/index.html + +Test page which overrides save_as and url so that this page will be generated +at a custom location. diff --git a/tests/test_data/content/pages/test_page.rst b/tests/test_data/content/pages/test_page.rst new file mode 100644 index 0000000..2285f17 --- /dev/null +++ b/tests/test_data/content/pages/test_page.rst @@ -0,0 +1,12 @@ +This is a test page +################### + +:category: test + +Just an image. + +.. image:: |filename|/pictures/Fat_Cat.jpg + :height: 450 px + :width: 600 px + :alt: alternate text + diff --git a/tests/test_data/content/pictures/Fat_Cat.jpg b/tests/test_data/content/pictures/Fat_Cat.jpg new file mode 100644 index 0000000..d8a96d3 Binary files /dev/null and b/tests/test_data/content/pictures/Fat_Cat.jpg differ diff --git a/tests/test_data/content/pictures/Sushi.jpg b/tests/test_data/content/pictures/Sushi.jpg new file mode 100644 index 0000000..e49e5f0 Binary files /dev/null and b/tests/test_data/content/pictures/Sushi.jpg differ diff --git a/tests/test_data/content/pictures/Sushi_Macro.jpg b/tests/test_data/content/pictures/Sushi_Macro.jpg new file mode 100644 index 0000000..21f935a Binary files /dev/null and b/tests/test_data/content/pictures/Sushi_Macro.jpg differ diff --git a/tests/test_data/content/super_article.rst b/tests/test_data/content/super_article.rst new file mode 100644 index 0000000..76e5768 --- /dev/null +++ b/tests/test_data/content/super_article.rst @@ -0,0 +1,36 @@ +This is a super article ! +######################### + +:tags: foo, bar, foobar +:date: 2010-12-02 10:14 +:category: yeah +:author: Alexis Métaireau +:summary: + Multi-line metadata should be supported + as well as **inline markup**. + +Some content here ! + +This is a simple title +====================== + +And here comes the cool stuff_. + +.. image:: |filename|/pictures/Sushi.jpg + :height: 450 px + :width: 600 px + :alt: alternate text + +.. image:: |filename|/pictures/Sushi_Macro.jpg + :height: 450 px + :width: 600 px + :alt: alternate text + +:: + + >>> from ipdb import set_trace + >>> set_trace() + +→ And now try with some utf8 hell: ééé + +.. _stuff: http://books.couchdb.org/relax/design-documents/views diff --git a/tests/test_data/content/unbelievable.rst b/tests/test_data/content/unbelievable.rst new file mode 100644 index 0000000..20cb9dc --- /dev/null +++ b/tests/test_data/content/unbelievable.rst @@ -0,0 +1,9 @@ +Unbelievable ! +############## + +:date: 2010-10-15 20:30 + +Or completely awesome. Depends the needs. + +`a root-relative link to markdown-article <|filename|/cat1/markdown-article.md>`_ +`a file-relative link to markdown-article <|filename|cat1/markdown-article.md>`_ diff --git a/tests/test_data/content/unwanted_file b/tests/test_data/content/unwanted_file new file mode 100644 index 0000000..591255a --- /dev/null +++ b/tests/test_data/content/unwanted_file @@ -0,0 +1 @@ +not to be parsed diff --git a/tests/test_data/pelican.conf.py b/tests/test_data/pelican.conf.py new file mode 100755 index 0000000..714a418 --- /dev/null +++ b/tests/test_data/pelican.conf.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +AUTHOR = 'Alexis Métaireau' +SITENAME = "Alexis' log" +SITEURL = 'http://blog.notmyidea.org' +TIMEZONE = "Europe/Paris" + +GITHUB_URL = 'http://github.com/ametaireau/' +DISQUS_SITENAME = "blog-notmyidea" +PDF_GENERATOR = False +REVERSE_CATEGORY_ORDER = True +LOCALE = "C" +DEFAULT_PAGINATION = 4 +DEFAULT_DATE = (2012, 3, 2, 14, 1, 1) + +FEED_ALL_RSS = 'feeds/all.rss.xml' +CATEGORY_FEED_RSS = 'feeds/%s.rss.xml' + +LINKS = (('Biologeek', 'http://biologeek.org'), + ('Filyb', "http://filyb.info/"), + ('Libert-fr', "http://www.libert-fr.com"), + ('N1k0', "http://prendreuncafe.com/blog/"), + ('Tarek Ziadé', "http://ziade.org/blog"), + ('Zubin Mithra', "http://zubin71.wordpress.com/"),) + +SOCIAL = (('twitter', 'http://twitter.com/ametaireau'), + ('lastfm', 'http://lastfm.com/user/akounet'), + ('github', 'http://github.com/ametaireau'),) + +# global metadata to all the contents +DEFAULT_METADATA = (('yeah', 'it is'),) + +# static paths will be copied under the same name +STATIC_PATHS = ["pictures", ] + +# A list of files to copy from the source to the destination +FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),) + +# custom page generated with a jinja2 template +TEMPLATE_PAGES = {'pages/jinja2_template.html': 'jinja2_template.html'} + +# foobar will not be used, because it's not in caps. All configuration keys +# have to be in caps +foobar = "barbaz" diff --git a/tests/test_data/themes/assets_theme/static/css/style.min.css b/tests/test_data/themes/assets_theme/static/css/style.min.css new file mode 100644 index 0000000..daf9c3c --- /dev/null +++ b/tests/test_data/themes/assets_theme/static/css/style.min.css @@ -0,0 +1 @@ +body{font:14px/1.5 "Droid Sans",sans-serif;background-color:#e4e4e4;color:#242424}a{color:red}a:hover{color:orange} \ No newline at end of file diff --git a/tests/test_data/themes/assets_theme/static/css/style.scss b/tests/test_data/themes/assets_theme/static/css/style.scss new file mode 100644 index 0000000..10cd05b --- /dev/null +++ b/tests/test_data/themes/assets_theme/static/css/style.scss @@ -0,0 +1,19 @@ +/* -*- scss-compile-at-save: nil -*- */ + +$baseFontFamily : "Droid Sans", sans-serif; +$textColor : #242424; +$bodyBackground : #e4e4e4; + +body { + font: 14px/1.5 $baseFontFamily; + background-color: $bodyBackground; + color: $textColor; +} + +a { + color: red; + + &:hover { + color: orange; + } +} diff --git a/tests/test_data/themes/assets_theme/templates/base.html b/tests/test_data/themes/assets_theme/templates/base.html new file mode 100644 index 0000000..05a32d0 --- /dev/null +++ b/tests/test_data/themes/assets_theme/templates/base.html @@ -0,0 +1,7 @@ +{% extends "!simple/base.html" %} + +{% block head %} + {% assets filters="scss,cssmin", output="gen/style.%(version)s.min.css", "css/style.scss" %} + + {% endassets %} +{% endblock %} diff --git a/tests/test_data/themes/notmyidea/static/css/main.css b/tests/test_data/themes/notmyidea/static/css/main.css new file mode 100644 index 0000000..5722444 --- /dev/null +++ b/tests/test_data/themes/notmyidea/static/css/main.css @@ -0,0 +1,446 @@ +/* + Name: Smashing HTML5 + Date: July 2009 + Description: Sample layout for HTML5 and CSS3 goodness. + Version: 1.0 + Author: Enrique Ramírez + Autor URI: http://enrique-ramirez.com +*/ + +/* Imports */ +@import url("reset.css"); +@import url("pygment.css"); +@import url("typogrify.css"); +@import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz&subset=latin); + +/***** Global *****/ +/* Body */ +body { + background: #F5F4EF; + color: #000305; + font-size: 87.5%; /* Base font size: 14px */ + font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; + line-height: 1.429; + margin: 0; + padding: 0; + text-align: left; +} + +/* Headings */ +h1 {font-size: 2em } +h2 {font-size: 1.571em} /* 22px */ +h3 {font-size: 1.429em} /* 20px */ +h4 {font-size: 1.286em} /* 18px */ +h5 {font-size: 1.143em} /* 16px */ +h6 {font-size: 1em} /* 14px */ + +h1, h2, h3, h4, h5, h6 { + font-weight: 400; + line-height: 1.1; + margin-bottom: .8em; + font-family: 'Yanone Kaffeesatz', arial, serif; +} + +h3, h4, h5, h6 { margin-top: .8em; } + +hr { border: 2px solid #EEEEEE; } + +/* Anchors */ +a {outline: 0;} +a img {border: 0px; text-decoration: none;} +a:link, a:visited { + color: #C74350; + padding: 0 1px; + text-decoration: underline; +} +a:hover, a:active { + background-color: #C74350; + color: #fff; + text-decoration: none; + text-shadow: 1px 1px 1px #333; +} + +h1 a:hover { + background-color: inherit +} + +/* Paragraphs */ +div.line-block, +p { margin-top: 1em; + margin-bottom: 1em;} + +strong, b {font-weight: bold;} +em, i {font-style: italic;} + +/* Lists */ +ul { + list-style: outside disc; + margin: 0em 0 0 1.5em; +} + +ol { + list-style: outside decimal; + margin: 0em 0 0 1.5em; +} + +li { margin-top: 0.5em;} + +.post-info { + float:right; + margin:10px; + padding:5px; +} + +.post-info p{ + margin-top: 1px; + margin-bottom: 1px; +} + +.readmore { float: right } + +dl {margin: 0 0 1.5em 0;} +dt {font-weight: bold;} +dd {margin-left: 1.5em;} + +pre{background-color: rgb(238, 238, 238); padding: 10px; margin: 10px; overflow: auto;} + +/* Quotes */ +blockquote { + margin: 20px; + font-style: italic; +} +cite {} + +q {} + +div.note { + float: right; + margin: 5px; + font-size: 85%; + max-width: 300px; +} + +/* Tables */ +table {margin: .5em auto 1.5em auto; width: 98%;} + + /* Thead */ + thead th {padding: .5em .4em; text-align: left;} + thead td {} + + /* Tbody */ + tbody td {padding: .5em .4em;} + tbody th {} + + tbody .alt td {} + tbody .alt th {} + + /* Tfoot */ + tfoot th {} + tfoot td {} + +/* HTML5 tags */ +header, section, footer, +aside, nav, article, figure { + display: block; +} + +/***** Layout *****/ +.body {clear: both; margin: 0 auto; width: 800px;} +img.right, figure.right {float: right; margin: 0 0 2em 2em;} +img.left, figure.left {float: left; margin: 0 2em 2em 0;} + +/* + Header +*****************/ +#banner { + margin: 0 auto; + padding: 2.5em 0 0 0; +} + + /* Banner */ + #banner h1 {font-size: 3.571em; line-height: 0;} + #banner h1 a:link, #banner h1 a:visited { + color: #000305; + display: block; + font-weight: bold; + margin: 0 0 .6em .2em; + text-decoration: none; + } + #banner h1 a:hover, #banner h1 a:active { + background: none; + color: #C74350; + text-shadow: none; + } + + #banner h1 strong {font-size: 0.36em; font-weight: normal;} + + /* Main Nav */ + #banner nav { + background: #000305; + font-size: 1.143em; + height: 40px; + line-height: 30px; + margin: 0 auto 2em auto; + padding: 0; + text-align: center; + width: 800px; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + } + + #banner nav ul {list-style: none; margin: 0 auto; width: 800px;} + #banner nav li {float: left; display: inline; margin: 0;} + + #banner nav a:link, #banner nav a:visited { + color: #fff; + display: inline-block; + height: 30px; + padding: 5px 1.5em; + text-decoration: none; + } + #banner nav a:hover, #banner nav a:active, + #banner nav .active a:link, #banner nav .active a:visited { + background: #C74451; + color: #fff; + text-shadow: none !important; + } + + #banner nav li:first-child a { + border-top-left-radius: 5px; + -moz-border-radius-topleft: 5px; + -webkit-border-top-left-radius: 5px; + + border-bottom-left-radius: 5px; + -moz-border-radius-bottomleft: 5px; + -webkit-border-bottom-left-radius: 5px; + } + +/* + Featured +*****************/ +#featured { + background: #fff; + margin-bottom: 2em; + overflow: hidden; + padding: 20px; + width: 760px; + + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +#featured figure { + border: 2px solid #eee; + float: right; + margin: 0.786em 2em 0 5em; + width: 248px; +} +#featured figure img {display: block; float: right;} + +#featured h2 {color: #C74451; font-size: 1.714em; margin-bottom: 0.333em;} +#featured h3 {font-size: 1.429em; margin-bottom: .5em;} + +#featured h3 a:link, #featured h3 a:visited {color: #000305; text-decoration: none;} +#featured h3 a:hover, #featured h3 a:active {color: #fff;} + +/* + Body +*****************/ +#content { + background: #fff; + margin-bottom: 2em; + overflow: hidden; + padding: 20px 20px; + width: 760px; + + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +/* + Extras +*****************/ +#extras {margin: 0 auto 3em auto; overflow: hidden;} + +#extras ul {list-style: none; margin: 0;} +#extras li {border-bottom: 1px solid #fff;} +#extras h2 { + color: #C74350; + font-size: 1.429em; + margin-bottom: .25em; + padding: 0 3px; +} + +#extras a:link, #extras a:visited { + color: #444; + display: block; + border-bottom: 1px solid #F4E3E3; + text-decoration: none; + padding: .3em .25em; +} + +#extras a:hover, #extras a:active {color: #fff;} + + /* Blogroll */ + #extras .blogroll { + float: left; + width: 615px; + } + + #extras .blogroll li {float: left; margin: 0 20px 0 0; width: 185px;} + + /* Social */ + #extras .social { + float: right; + width: 175px; + } + + #extras div[class='social'] a { + background-repeat: no-repeat; + background-position: 3px 6px; + padding-left: 25px; + } + + /* Icons */ + .social a[href*='about.me'] {background-image: url('../images/icons/aboutme.png');} + .social a[href*='bitbucket.org'] {background-image: url('../images/icons/bitbucket.png');} + .social a[href*='delicious.com'] {background-image: url('../images/icons/delicious.png');} + .social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');} + .social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');} + .social a[href*='gitorious.org'] {background-image: url('../images/icons/gitorious.png');} + .social a[href*='github.com'], + .social a[href*='git.io'] {background-image: url('../images/icons/github.png');} + .social a[href*='gittip.com'] {background-image: url('../images/icons/gittip.png');} + .social a[href*='plus.google.com'] {background-image: url('../images/icons/google-plus.png');} + .social a[href*='groups.google.com'] {background-image: url('../images/icons/google-groups.png');} + .social a[href*='news.ycombinator.com'], + .social a[href*='hackernewsers.com'] {background-image: url('../images/icons/hackernews.png');} + .social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');} + .social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');} + .social a[href*='reddit.com'] {background-image: url('../images/icons/reddit.png');} + .social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');} + .social a[href*='slideshare.net'] {background-image: url('../images/icons/slideshare.png');} + .social a[href*='speakerdeck.com'] {background-image: url('../images/icons/speakerdeck.png');} + .social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');} + .social a[href*='vimeo.com'] {background-image: url('../images/icons/vimeo.png');} + .social a[href*='youtube.com'] {background-image: url('../images/icons/youtube.png');} + +/* + About +*****************/ +#about { + background: #fff; + font-style: normal; + margin-bottom: 2em; + overflow: hidden; + padding: 20px; + text-align: left; + width: 760px; + + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +#about .primary {float: left; width: 165px;} +#about .primary strong {color: #C64350; display: block; font-size: 1.286em;} +#about .photo {float: left; margin: 5px 20px;} + +#about .url:link, #about .url:visited {text-decoration: none;} + +#about .bio {float: right; width: 500px;} + +/* + Footer +*****************/ +#contentinfo {padding-bottom: 2em; text-align: right;} + +/***** Sections *****/ +/* Blog */ +.hentry { + display: block; + clear: both; + border-bottom: 1px solid #eee; + padding: 1.5em 0; +} +li:last-child .hentry, #content > .hentry {border: 0; margin: 0;} +#content > .hentry {padding: 1em 0;} +.hentry img{display : none ;} +.entry-title {font-size: 3em; margin-bottom: 10px; margin-top: 0;} +.entry-title a:link, .entry-title a:visited {text-decoration: none; color: #333;} +.entry-title a:visited {background-color: #fff;} + +.hentry .post-info * {font-style: normal;} + + /* Content */ + .hentry footer {margin-bottom: 2em;} + .hentry footer address {display: inline;} + #posts-list footer address {display: block;} + + /* Blog Index */ + #posts-list {list-style: none; margin: 0;} + #posts-list .hentry {padding-left: 10px; position: relative;} + + #posts-list footer { + left: 10px; + position: relative; + float: left; + top: 0.5em; + width: 190px; + } + + /* About the Author */ + #about-author { + background: #f9f9f9; + clear: both; + font-style: normal; + margin: 2em 0; + padding: 10px 20px 15px 20px; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + } + + #about-author strong { + color: #C64350; + clear: both; + display: block; + font-size: 1.429em; + } + + #about-author .photo {border: 1px solid #ddd; float: left; margin: 5px 1em 0 0;} + + /* Comments */ + #comments-list {list-style: none; margin: 0 1em;} + #comments-list blockquote { + background: #f8f8f8; + clear: both; + font-style: normal; + margin: 0; + padding: 15px 20px; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + } + #comments-list footer {color: #888; padding: .5em 1em 0 0; text-align: right;} + + #comments-list li:nth-child(2n) blockquote {background: #F5f5f5;} + + /* Add a Comment */ + #add-comment label {clear: left; float: left; text-align: left; width: 150px;} + #add-comment input[type='text'], + #add-comment input[type='email'], + #add-comment input[type='url'] {float: left; width: 200px;} + + #add-comment textarea {float: left; height: 150px; width: 495px;} + + #add-comment p.req {clear: both; margin: 0 .5em 1em 0; text-align: right;} + + #add-comment input[type='submit'] {float: right; margin: 0 .5em;} + #add-comment * {margin-bottom: .5em;} diff --git a/tests/test_data/themes/notmyidea/static/css/pygment.css b/tests/test_data/themes/notmyidea/static/css/pygment.css new file mode 100644 index 0000000..fdd056f --- /dev/null +++ b/tests/test_data/themes/notmyidea/static/css/pygment.css @@ -0,0 +1,205 @@ +.hll { +background-color:#eee; +} +.c { +color:#408090; +font-style:italic; +} +.err { +border:1px solid #FF0000; +} +.k { +color:#007020; +font-weight:bold; +} +.o { +color:#666666; +} +.cm { +color:#408090; +font-style:italic; +} +.cp { +color:#007020; +} +.c1 { +color:#408090; +font-style:italic; +} +.cs { +background-color:#FFF0F0; +color:#408090; +} +.gd { +color:#A00000; +} +.ge { +font-style:italic; +} +.gr { +color:#FF0000; +} +.gh { +color:#000080; +font-weight:bold; +} +.gi { +color:#00A000; +} +.go { +color:#303030; +} +.gp { +color:#C65D09; +font-weight:bold; +} +.gs { +font-weight:bold; +} +.gu { +color:#800080; +font-weight:bold; +} +.gt { +color:#0040D0; +} +.kc { +color:#007020; +font-weight:bold; +} +.kd { +color:#007020; +font-weight:bold; +} +.kn { +color:#007020; +font-weight:bold; +} +.kp { +color:#007020; +} +.kr { +color:#007020; +font-weight:bold; +} +.kt { +color:#902000; +} +.m { +color:#208050; +} +.s { +color:#4070A0; +} +.na { +color:#4070A0; +} +.nb { +color:#007020; +} +.nc { +color:#0E84B5; +font-weight:bold; +} +.no { +color:#60ADD5; +} +.nd { +color:#555555; +font-weight:bold; +} +.ni { +color:#D55537; +font-weight:bold; +} +.ne { +color:#007020; +} +.nf { +color:#06287E; +} +.nl { +color:#002070; +font-weight:bold; +} +.nn { +color:#0E84B5; +font-weight:bold; +} +.nt { +color:#062873; +font-weight:bold; +} +.nv { +color:#BB60D5; +} +.ow { +color:#007020; +font-weight:bold; +} +.w { +color:#BBBBBB; +} +.mf { +color:#208050; +} +.mh { +color:#208050; +} +.mi { +color:#208050; +} +.mo { +color:#208050; +} +.sb { +color:#4070A0; +} +.sc { +color:#4070A0; +} +.sd { +color:#4070A0; +font-style:italic; +} +.s2 { +color:#4070A0; +} +.se { +color:#4070A0; +font-weight:bold; +} +.sh { +color:#4070A0; +} +.si { +color:#70A0D0; +font-style:italic; +} +.sx { +color:#C65D09; +} +.sr { +color:#235388; +} +.s1 { +color:#4070A0; +} +.ss { +color:#517918; +} +.bp { +color:#007020; +} +.vc { +color:#BB60D5; +} +.vg { +color:#BB60D5; +} +.vi { +color:#BB60D5; +} +.il { +color:#208050; +} diff --git a/tests/test_data/themes/notmyidea/static/css/reset.css b/tests/test_data/themes/notmyidea/static/css/reset.css new file mode 100644 index 0000000..1e21756 --- /dev/null +++ b/tests/test_data/themes/notmyidea/static/css/reset.css @@ -0,0 +1,52 @@ +/* + Name: Reset Stylesheet + Description: Resets browser's default CSS + Author: Eric Meyer + Author URI: http://meyerweb.com/eric/tools/css/reset/ +*/ + +/* v1.0 | 20080212 */ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + background: transparent; + border: 0; + font-size: 100%; + margin: 0; + outline: 0; + padding: 0; + vertical-align: baseline; +} + +body {line-height: 1;} + +ol, ul {list-style: none;} + +blockquote, q {quotes: none;} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +/* remember to define focus styles! */ +:focus { + outline: 0; +} + +/* remember to highlight inserts somehow! */ +ins {text-decoration: none;} +del {text-decoration: line-through;} + +/* tables still need 'cellspacing="0"' in the markup */ +table { + border-collapse: collapse; + border-spacing: 0; +} \ No newline at end of file diff --git a/tests/test_data/themes/notmyidea/static/css/typogrify.css b/tests/test_data/themes/notmyidea/static/css/typogrify.css new file mode 100644 index 0000000..c9b34dc --- /dev/null +++ b/tests/test_data/themes/notmyidea/static/css/typogrify.css @@ -0,0 +1,3 @@ +.caps {font-size:.92em;} +.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;} +.dquo {margin-left:-.38em;} diff --git a/tests/test_data/themes/notmyidea/static/css/wide.css b/tests/test_data/themes/notmyidea/static/css/wide.css new file mode 100644 index 0000000..88fd59c --- /dev/null +++ b/tests/test_data/themes/notmyidea/static/css/wide.css @@ -0,0 +1,48 @@ +@import url("main.css"); + +body { + font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif; +} + +.post-info{ + display: none; +} + +#banner nav { + display: none; + -moz-border-radius: 0px; + margin-bottom: 20px; + overflow: hidden; + font-size: 1em; + background: #F5F4EF; +} + +#banner nav ul{ + padding-right: 50px; +} + +#banner nav li{ + float: right; + color: #000; +} + +#banner nav li a { + color: #000; +} + +#banner h1 { + margin-bottom: -18px; +} + +#featured, #extras { + padding: 50px; +} + +#featured { + padding-top: 20px; +} + +#extras { + padding-top: 0px; + padding-bottom: 0px; +} diff --git a/tests/test_data/themes/notmyidea/static/images/icons/aboutme.png b/tests/test_data/themes/notmyidea/static/images/icons/aboutme.png new file mode 100644 index 0000000..9609df3 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/aboutme.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/bitbucket.png b/tests/test_data/themes/notmyidea/static/images/icons/bitbucket.png new file mode 100644 index 0000000..d05ba16 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/bitbucket.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/delicious.png b/tests/test_data/themes/notmyidea/static/images/icons/delicious.png new file mode 100644 index 0000000..3dccdd8 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/delicious.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/facebook.png b/tests/test_data/themes/notmyidea/static/images/icons/facebook.png new file mode 100644 index 0000000..74e7ad5 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/facebook.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/github.png b/tests/test_data/themes/notmyidea/static/images/icons/github.png new file mode 100644 index 0000000..6c52b48 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/github.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/gitorious.png b/tests/test_data/themes/notmyidea/static/images/icons/gitorious.png new file mode 100644 index 0000000..3eeb3ec Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/gitorious.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/gittip.png b/tests/test_data/themes/notmyidea/static/images/icons/gittip.png new file mode 100644 index 0000000..af94962 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/gittip.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/google-groups.png b/tests/test_data/themes/notmyidea/static/images/icons/google-groups.png new file mode 100644 index 0000000..5de15e6 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/google-groups.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/google-plus.png b/tests/test_data/themes/notmyidea/static/images/icons/google-plus.png new file mode 100644 index 0000000..3c6b743 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/google-plus.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/hackernews.png b/tests/test_data/themes/notmyidea/static/images/icons/hackernews.png new file mode 100644 index 0000000..fc7a82d Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/hackernews.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/lastfm.png b/tests/test_data/themes/notmyidea/static/images/icons/lastfm.png new file mode 100644 index 0000000..3a6c626 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/lastfm.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/linkedin.png b/tests/test_data/themes/notmyidea/static/images/icons/linkedin.png new file mode 100644 index 0000000..d29c120 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/linkedin.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/reddit.png b/tests/test_data/themes/notmyidea/static/images/icons/reddit.png new file mode 100644 index 0000000..71ae121 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/reddit.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/rss.png b/tests/test_data/themes/notmyidea/static/images/icons/rss.png new file mode 100644 index 0000000..7862c65 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/rss.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/slideshare.png b/tests/test_data/themes/notmyidea/static/images/icons/slideshare.png new file mode 100644 index 0000000..ecc9741 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/slideshare.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/speakerdeck.png b/tests/test_data/themes/notmyidea/static/images/icons/speakerdeck.png new file mode 100644 index 0000000..087d093 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/speakerdeck.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/twitter.png b/tests/test_data/themes/notmyidea/static/images/icons/twitter.png new file mode 100644 index 0000000..d0ef3cc Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/twitter.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/vimeo.png b/tests/test_data/themes/notmyidea/static/images/icons/vimeo.png new file mode 100644 index 0000000..dba4720 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/vimeo.png differ diff --git a/tests/test_data/themes/notmyidea/static/images/icons/youtube.png b/tests/test_data/themes/notmyidea/static/images/icons/youtube.png new file mode 100644 index 0000000..ce6cbe4 Binary files /dev/null and b/tests/test_data/themes/notmyidea/static/images/icons/youtube.png differ diff --git a/tests/test_data/themes/notmyidea/templates/analytics.html b/tests/test_data/themes/notmyidea/templates/analytics.html new file mode 100644 index 0000000..4de2c86 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/analytics.html @@ -0,0 +1,12 @@ +{% if GOOGLE_ANALYTICS %} + +{% endif %} \ No newline at end of file diff --git a/tests/test_data/themes/notmyidea/templates/archives.html b/tests/test_data/themes/notmyidea/templates/archives.html new file mode 100644 index 0000000..f678494 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/archives.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} +{% block content %} +
+

Archives for {{ SITENAME }}

+ +
+{% for article in dates %} +
{{ article.locale_date }}
+
{{ article.title }}
+{% endfor %} +
+
+{% endblock %} diff --git a/tests/test_data/themes/notmyidea/templates/article.html b/tests/test_data/themes/notmyidea/templates/article.html new file mode 100644 index 0000000..516fd3b --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/article.html @@ -0,0 +1,35 @@ +{% extends "base.html" %} +{% block title %}{{ article.title|striptags }}{% endblock %} +{% block content %} +
+
+
+

+ {{ article.title}}

+ {% include 'twitter.html' %} +
+ +
+ {% include 'article_infos.html' %} + {{ article.content }} +
+ {% if DISQUS_SITENAME and SITEURL and article.status != "draft" %} +
+

Comments !

+
+ +
+ {% endif %} + +
+
+{% endblock %} diff --git a/tests/test_data/themes/notmyidea/templates/article_infos.html b/tests/test_data/themes/notmyidea/templates/article_infos.html new file mode 100644 index 0000000..4b86716 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/article_infos.html @@ -0,0 +1,15 @@ +
+ + {{ article.locale_date }} + + + {% if article.author %} +
+ By {{ article.author }} +
+ {% endif %} +

In {{ article.category }}. {% if PDF_PROCESSOR %}get the pdf{% endif %}

+{% include 'taglist.html' %} +{% import 'translations.html' as translations with context %} +{{ translations.translations_for(article) }} +
diff --git a/tests/test_data/themes/notmyidea/templates/author.html b/tests/test_data/themes/notmyidea/templates/author.html new file mode 100644 index 0000000..0b37290 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/author.html @@ -0,0 +1,2 @@ +{% extends "index.html" %} +{% block title %}{{ SITENAME }} - {{ author }}{% endblock %} diff --git a/pelicanext/__init__.py b/tests/test_data/themes/notmyidea/templates/authors.html similarity index 100% rename from pelicanext/__init__.py rename to tests/test_data/themes/notmyidea/templates/authors.html diff --git a/tests/test_data/themes/notmyidea/templates/base.html b/tests/test_data/themes/notmyidea/templates/base.html new file mode 100644 index 0000000..42a2cec --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/base.html @@ -0,0 +1,88 @@ + + + + {% block title %}{{ SITENAME }}{%endblock%} + + + {% if FEED_ALL_ATOM %} + + {% endif %} + {% if FEED_ALL_RSS %} + + {% endif %} + + + + + + + + + + +{% include 'github.html' %} + + {% block content %} + {% endblock %} +
+ {% if LINKS %} +
+

blogroll

+
    + {% for name, link in LINKS %} +
  • {{ name }}
  • + {% endfor %} +
+
+ {% endif %} + {% if SOCIAL or FEED_ALL_ATOM or FEED_ALL_RSS %} + + {% endif %} +
+ + + +{% include 'analytics.html' %} +{% include 'piwik.html' %} +{% include 'disqus_script.html' %} + + diff --git a/tests/test_data/themes/notmyidea/templates/category.html b/tests/test_data/themes/notmyidea/templates/category.html new file mode 100644 index 0000000..56f8e93 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/category.html @@ -0,0 +1,2 @@ +{% extends "index.html" %} +{% block title %}{{ SITENAME }} - {{ category }}{% endblock %} diff --git a/tests/test_data/themes/notmyidea/templates/comments.html b/tests/test_data/themes/notmyidea/templates/comments.html new file mode 100644 index 0000000..bb033c0 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/comments.html @@ -0,0 +1 @@ +{% if DISQUS_SITENAME %}

There are comments.

{% endif %} diff --git a/tests/test_data/themes/notmyidea/templates/disqus_script.html b/tests/test_data/themes/notmyidea/templates/disqus_script.html new file mode 100644 index 0000000..c4f442c --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/disqus_script.html @@ -0,0 +1,11 @@ +{% if DISQUS_SITENAME %} + +{% endif %} diff --git a/tests/test_data/themes/notmyidea/templates/github.html b/tests/test_data/themes/notmyidea/templates/github.html new file mode 100644 index 0000000..75592ac --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/github.html @@ -0,0 +1,9 @@ +{% if GITHUB_URL %} + +{% if GITHUB_POSITION != "left" %} +Fork me on GitHub +{% else %} +Fork me on GitHub +{% endif %} + +{% endif %} diff --git a/tests/test_data/themes/notmyidea/templates/index.html b/tests/test_data/themes/notmyidea/templates/index.html new file mode 100644 index 0000000..8752a6b --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/index.html @@ -0,0 +1,61 @@ +{% extends "base.html" %} +{% block content_title %}{% endblock %} +{% block content %} +{% if articles %} + {% for article in articles_page.object_list %} + + {# First item #} + {% if loop.first and not articles_page.has_previous() %} + + {% if loop.length > 1 %} +
+

Other articles

+
+
    + {% endif %} + {# other items #} + {% else %} + {% if loop.first and articles_page.has_previous %} +
    +
      + {% endif %} +
    1. +
      +

      {{ article.title }}

      +
      + +
      + {% include 'article_infos.html' %} + {{ article.summary }} + read more + {% include 'comments.html' %} +
      +
    2. + {% endif %} + {% if loop.last %} +
    + {% if loop.last and (articles_page.has_previous() + or not articles_page.has_previous() and loop.length > 1) %} + {% include 'pagination.html' %} + {% endif %} +
    + {% endif %} + {% endfor %} +{% else %} +
    +

    Pages

    + {% for page in PAGES %} +
  1. {{ page.title }}
  2. + {% endfor %} +
    +{% endif %} +{% endblock content %} diff --git a/tests/test_data/themes/notmyidea/templates/page.html b/tests/test_data/themes/notmyidea/templates/page.html new file mode 100644 index 0000000..60409d5 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/page.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% block title %}{{ page.title }}{% endblock %} +{% block content %} +
    +

    {{ page.title }}

    + {% import 'translations.html' as translations with context %} + {{ translations.translations_for(page) }} + {% if PDF_PROCESSOR %}get + the pdf{% endif %} + {{ page.content }} +
    +{% endblock %} diff --git a/tests/test_data/themes/notmyidea/templates/piwik.html b/tests/test_data/themes/notmyidea/templates/piwik.html new file mode 100644 index 0000000..ff459af --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/piwik.html @@ -0,0 +1,16 @@ +{% if PIWIK_URL and PIWIK_SITE_ID %} + +{% endif %} \ No newline at end of file diff --git a/tests/test_data/themes/notmyidea/templates/tag.html b/tests/test_data/themes/notmyidea/templates/tag.html new file mode 100644 index 0000000..68cdcba --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/tag.html @@ -0,0 +1,2 @@ +{% extends "index.html" %} +{% block title %}{{ SITENAME }} - {{ tag }}{% endblock %} diff --git a/tests/test_data/themes/notmyidea/templates/taglist.html b/tests/test_data/themes/notmyidea/templates/taglist.html new file mode 100644 index 0000000..c792fd7 --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/taglist.html @@ -0,0 +1,2 @@ +{% if article.tags %}

    tags: {% for tag in article.tags %}{{ tag }}{% endfor %}

    {% endif %} +{% if PDF_PROCESSOR %}

    get the pdf

    {% endif %} diff --git a/tests/test_data/themes/notmyidea/templates/translations.html b/tests/test_data/themes/notmyidea/templates/translations.html new file mode 100644 index 0000000..ca03a2c --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/translations.html @@ -0,0 +1,8 @@ +{% macro translations_for(article) %} +{% if article.translations %} +Translations: + {% for translation in article.translations %} + {{ translation.lang }} + {% endfor %} +{% endif %} +{% endmacro %} diff --git a/tests/test_data/themes/notmyidea/templates/twitter.html b/tests/test_data/themes/notmyidea/templates/twitter.html new file mode 100644 index 0000000..c6b159f --- /dev/null +++ b/tests/test_data/themes/notmyidea/templates/twitter.html @@ -0,0 +1,3 @@ +{% if TWITTER_USERNAME %} + +{% endif %} \ No newline at end of file diff --git a/tests/test_data/themes/simple/templates/archives.html b/tests/test_data/themes/simple/templates/archives.html new file mode 100644 index 0000000..050f268 --- /dev/null +++ b/tests/test_data/themes/simple/templates/archives.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% block content %} +

    Archives for {{ SITENAME }}

    + +
    +{% for article in dates %} +
    {{ article.locale_date }}
    +
    {{ article.title }}
    +{% endfor %} +
    +{% endblock %} diff --git a/tests/test_data/themes/simple/templates/article.html b/tests/test_data/themes/simple/templates/article.html new file mode 100644 index 0000000..98cc852 --- /dev/null +++ b/tests/test_data/themes/simple/templates/article.html @@ -0,0 +1,25 @@ +{% extends "base.html" %} +{% block content %} +
    +
    +

    + {{ article.title }}

    + {% import 'translations.html' as translations with context %} + {{ translations.translations_for(article) }} +
    +
    + + {{ article.locale_date }} + + {% if article.author %} +
    + By {{ article.author }} +
    + {% endif %} +
    +
    + {{ article.content }} +
    +
    +{% endblock %} diff --git a/tests/test_data/themes/simple/templates/author.html b/tests/test_data/themes/simple/templates/author.html new file mode 100644 index 0000000..e9f7870 --- /dev/null +++ b/tests/test_data/themes/simple/templates/author.html @@ -0,0 +1,7 @@ +{% extends "index.html" %} + +{% block title %}{{ SITENAME }} - Articles by {{ author }}{% endblock %} +{% block content_title %} +

    Articles by {{ author }}

    +{% endblock %} + diff --git a/tests/test_data/themes/simple/templates/base.html b/tests/test_data/themes/simple/templates/base.html new file mode 100644 index 0000000..7973d77 --- /dev/null +++ b/tests/test_data/themes/simple/templates/base.html @@ -0,0 +1,63 @@ + + + + {% block head %} + {% block title %}{{ SITENAME }}{% endblock title %} + + {% if FEED_ALL_ATOM %} + + {% endif %} + {% if FEED_ALL_RSS %} + + {% endif %} + {% if FEED_ATOM %} + + {% endif %} + {% if FEED_RSS %} + + {% endif %} + {% if CATEGORY_FEED_ATOM and category %} + + {% endif %} + {% if CATEGORY_FEED_RSS and category %} + + {% endif %} + {% if TAG_FEED_ATOM and tag %} + + {% endif %} + {% if TAG_FEED_RSS and tag %} + + {% endif %} + {% endblock head %} + + + + + + {% block content %} + {% endblock %} +
    +
    + Proudly powered by Pelican, + which takes great advantage of Python. +
    +
    + + diff --git a/tests/test_data/themes/simple/templates/categories.html b/tests/test_data/themes/simple/templates/categories.html new file mode 100644 index 0000000..e29be0c --- /dev/null +++ b/tests/test_data/themes/simple/templates/categories.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% block content %} +
      +{% for category, articles in categories %} +
    • {{ category }}
    • +{% endfor %} +
    +{% endblock %} diff --git a/tests/test_data/themes/simple/templates/category.html b/tests/test_data/themes/simple/templates/category.html new file mode 100644 index 0000000..4e6fd24 --- /dev/null +++ b/tests/test_data/themes/simple/templates/category.html @@ -0,0 +1,5 @@ +{% extends "index.html" %} +{% block content_title %} +

    Articles in the {{ category }} category

    +{% endblock %} + diff --git a/tests/test_data/themes/simple/templates/gosquared.html b/tests/test_data/themes/simple/templates/gosquared.html new file mode 100644 index 0000000..f47efcf --- /dev/null +++ b/tests/test_data/themes/simple/templates/gosquared.html @@ -0,0 +1,14 @@ +{% if GOSQUARED_SITENAME %} + +{% endif %} diff --git a/tests/test_data/themes/simple/templates/index.html b/tests/test_data/themes/simple/templates/index.html new file mode 100644 index 0000000..5bb94df --- /dev/null +++ b/tests/test_data/themes/simple/templates/index.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{% block content %} +
    +{% block content_title %} +

    All articles

    +{% endblock %} + +
      +{% for article in articles_page.object_list %} +
    1. +{% endfor %} +
    +{% include 'pagination.html' %} +
    +{% endblock content %} diff --git a/tests/test_data/themes/simple/templates/page.html b/tests/test_data/themes/simple/templates/page.html new file mode 100644 index 0000000..3a0dc4a --- /dev/null +++ b/tests/test_data/themes/simple/templates/page.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% block title %}{{ page.title }}{%endblock%} +{% block content %} +

    {{ page.title }}

    + {% import 'translations.html' as translations with context %} + {{ translations.translations_for(page) }} + + {{ page.content }} +{% endblock %} diff --git a/tests/test_data/themes/simple/templates/pagination.html b/tests/test_data/themes/simple/templates/pagination.html new file mode 100644 index 0000000..83c587a --- /dev/null +++ b/tests/test_data/themes/simple/templates/pagination.html @@ -0,0 +1,15 @@ +{% if DEFAULT_PAGINATION %} +

    + {% if articles_page.has_previous() %} + {% if articles_page.previous_page_number() == 1 %} + « + {% else %} + « + {% endif %} + {% endif %} + Page {{ articles_page.number }} / {{ articles_paginator.num_pages }} + {% if articles_page.has_next() %} + » + {% endif %} +

    +{% endif %} diff --git a/pelicanext/goodreads_activity/__init__.py b/tests/test_data/themes/simple/templates/tag.html similarity index 100% rename from pelicanext/goodreads_activity/__init__.py rename to tests/test_data/themes/simple/templates/tag.html diff --git a/pelicanext/latex/__init__.py b/tests/test_data/themes/simple/templates/tags.html similarity index 100% rename from pelicanext/latex/__init__.py rename to tests/test_data/themes/simple/templates/tags.html diff --git a/tests/test_data/themes/simple/templates/translations.html b/tests/test_data/themes/simple/templates/translations.html new file mode 100644 index 0000000..db8c372 --- /dev/null +++ b/tests/test_data/themes/simple/templates/translations.html @@ -0,0 +1,9 @@ +{% macro translations_for(article) %} +{% if article.translations %} +Translations: +{% for translation in article.translations %} +{{ translation.lang }} +{% endfor %} +{% endif %} +{% endmacro %} + diff --git a/tests/test_data/themes/test_summary.py b/tests/test_data/themes/test_summary.py new file mode 100644 index 0000000..c995106 --- /dev/null +++ b/tests/test_data/themes/test_summary.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +import unittest + +from jinja2.utils import generate_lorem_ipsum + +# generate one paragraph, enclosed with

    +TEST_CONTENT = str(generate_lorem_ipsum(n=1)) +TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) + + +from pelican.contents import Page + +import summary + +class TestSummary(unittest.TestCase): + def setUp(self): + super(TestSummary, self).setUp() + + summary.register() + summary.initialized(None) + self.page_kwargs = { + 'content': TEST_CONTENT, + 'context': { + 'localsiteurl': '', + }, + 'metadata': { + 'summary': TEST_SUMMARY, + 'title': 'foo bar', + 'author': 'Blogger', + }, + } + + def _copy_page_kwargs(self): + # make a deep copy of page_kwargs + page_kwargs = dict([(key, self.page_kwargs[key]) for key in + self.page_kwargs]) + for key in page_kwargs: + if not isinstance(page_kwargs[key], dict): + break + page_kwargs[key] = dict([(subkey, page_kwargs[key][subkey]) + for subkey in page_kwargs[key]]) + + return page_kwargs + + def test_end_summary(self): + page_kwargs = self._copy_page_kwargs() + del page_kwargs['metadata']['summary'] + page_kwargs['content'] = ( + TEST_SUMMARY + '' + TEST_CONTENT) + page = Page(**page_kwargs) + # test both the summary and the marker removal + self.assertEqual(page.summary, TEST_SUMMARY) + self.assertEqual(page.content, TEST_SUMMARY + TEST_CONTENT) + + def test_begin_summary(self): + page_kwargs = self._copy_page_kwargs() + del page_kwargs['metadata']['summary'] + page_kwargs['content'] = ( + 'FOOBAR' + TEST_CONTENT) + page = Page(**page_kwargs) + # test both the summary and the marker removal + self.assertEqual(page.summary, TEST_CONTENT) + self.assertEqual(page.content, 'FOOBAR' + TEST_CONTENT) + + def test_begin_end_summary(self): + page_kwargs = self._copy_page_kwargs() + del page_kwargs['metadata']['summary'] + page_kwargs['content'] = ( + 'FOOBAR' + TEST_SUMMARY + + '' + TEST_CONTENT) + page = Page(**page_kwargs) + # test both the summary and the marker removal + self.assertEqual(page.summary, TEST_SUMMARY) + self.assertEqual(page.content, 'FOOBAR' + TEST_SUMMARY + TEST_CONTENT) diff --git a/tests/test_gzip_cache.py b/tests/test_gzip_cache.py new file mode 100644 index 0000000..a41e212 --- /dev/null +++ b/tests/test_gzip_cache.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +'''Core plugins unit tests''' + +import os +import tempfile +import unittest + +from contextlib import contextmanager +from tempfile import mkdtemp +from shutil import rmtree + +import gzip_cache + +@contextmanager +def temporary_folder(): + """creates a temporary folder, return it and delete it afterwards. + + This allows to do something like this in tests: + + >>> with temporary_folder() as d: + # do whatever you want + """ + tempdir = mkdtemp() + try: + yield tempdir + finally: + rmtree(tempdir) + + +class TestGzipCache(unittest.TestCase): + + def test_should_compress(self): + # Some filetypes should compress and others shouldn't. + self.assertTrue(gzip_cache.should_compress('foo.html')) + self.assertTrue(gzip_cache.should_compress('bar.css')) + self.assertTrue(gzip_cache.should_compress('baz.js')) + self.assertTrue(gzip_cache.should_compress('foo.txt')) + + self.assertFalse(gzip_cache.should_compress('foo.gz')) + self.assertFalse(gzip_cache.should_compress('bar.png')) + self.assertFalse(gzip_cache.should_compress('baz.mp3')) + self.assertFalse(gzip_cache.should_compress('foo.mov')) + + def test_creates_gzip_file(self): + # A file matching the input filename with a .gz extension is created. + + # The plugin walks over the output content after the finalized signal + # so it is safe to assume that the file exists (otherwise walk would + # not report it). Therefore, create a dummy file to use. + with temporary_folder() as tempdir: + _, a_html_filename = tempfile.mkstemp(suffix='.html', dir=tempdir) + gzip_cache.create_gzip_file(a_html_filename) + self.assertTrue(os.path.exists(a_html_filename + '.gz')) +