Esempio n. 1
0
    def testRecursivelyEvaluateJinjaExpressions(self):
        file_map = {
            'docA.md':
            self.join_lines(
                '~ title: test',  # Creates a variable called 'title'
                '{{ title|capitalize }}'),
        }
        template_loader = jinja2.DictLoader({
            'some/path':
            '{{ blocks["all"] }}',  # Use the block defined in the content.
        })
        jinja_env = jinja2.Environment(loader=template_loader)

        # By default, should not recursively evaluate Jinja expressions.
        with self.mock_open(file_map):
            result = publish(ConfigBuilder().build(),
                             source='docA.md',
                             template='some/path',
                             jinja_env=jinja_env,
                             no_write=True)
        self.assertEquals('{{ title|capitalize }}', result)

        # Set recursively_evaluate_jinja_expressions to True.
        config = ConfigBuilder().set_recursively_evaluate_jinja_expressions(
            True).build()
        with self.mock_open(file_map):
            result = publish(config,
                             source='docA.md',
                             template='some/path',
                             jinja_env=jinja_env,
                             no_write=True)
        self.assertEquals('Test', result)
Esempio n. 2
0
    def testOnlySource_withRulesAndBlocks(self):
        file_map = {
            'docA.md': self.join_lines(
                'outer content',
                '<block blockA>',
                'inner content',
                '</block blockA>',
                'outer content'),
        }
        class AppliedRule(Rule):
            counter = 0
            def apply(self, content):
                self.counter += 1
                return 'segment {}: '.format(self.counter) + content
        config_builder = ConfigBuilder()
        config_builder.append_postprocess_rules(AppliedRule())

        with self.mock_open(file_map):
            result = publish(config_builder.build(), source='docA.md', no_write=True)
        self.assertEquals(
            self.join_lines(
                'segment 1: outer content',
                'segment 2: inner content',
                'segment 3: outer content'),
            result)
Esempio n. 3
0
    def testOnlySource_withRulesAndBlocks(self):
        file_map = {
            'docA.md':
            self.join_lines('outer content', '<block blockA>', 'inner content',
                            '</block blockA>', 'outer content'),
        }

        class AppliedRule(Rule):
            counter = 0

            def apply(self, content):
                self.counter += 1
                return 'segment {}: '.format(self.counter) + content

        config_builder = ConfigBuilder()
        config_builder.append_postprocess_rules(AppliedRule())

        with self.mock_open(file_map):
            result = publish(config_builder.build(),
                             source='docA.md',
                             no_write=True)
        self.assertEquals(
            self.join_lines('segment 1: outer content',
                            'segment 2: inner content',
                            'segment 3: outer content'), result)
Esempio n. 4
0
    def testCompilerRules(self):
        rule1, rule2 = Rule(), Rule()
        builder = ConfigBuilder().append_compiler_rules(rule1, rule2)
        self.assertSequenceEqual([rule1, rule2], builder.build().compiler_rules)

        rule3, rule4 = Rule(), Rule()
        builder.prepend_compiler_rules(rule3, rule4)
        self.assertSequenceEqual([rule3, rule4, rule1, rule2], builder.build().compiler_rules)

        builder.clear_compiler_rules()
        self.assertSequenceEqual([], builder.build().compiler_rules)
Esempio n. 5
0
    def testPostprocessRules(self):
        rule1, rule2 = Rule(), Rule()
        builder = ConfigBuilder().append_postprocess_rules(rule1, rule2)
        self.assertSequenceEqual([rule1, rule2], builder.build().postprocess_rules)

        rule3, rule4 = Rule(), Rule()
        builder.prepend_postprocess_rules(rule3, rule4)
        self.assertSequenceEqual([rule3, rule4, rule1, rule2], builder.build().postprocess_rules)

        builder.clear_postprocess_rules()
        self.assertSequenceEqual([], builder.build().postprocess_rules)
Esempio n. 6
0
    def testOnlySource_preserveNewlinesOutsideOfBlocks(self):
        file_map = {
            'docA.md':
            """<block zero>
zero
</block zero>
<block one>
one
</block one>

<block two>
two
</block two>


<block three>
three
</block three>"""
        }
        with self.mock_open(file_map):
            result = publish(ConfigBuilder().build(),
                             source='docA.md',
                             no_write=True)
        self.assertEquals("""zero
one

two


three""", result)
Esempio n. 7
0
 def testTemplateDirs_preventNonExistentPath(self):
     with mock.patch('os.path.isdir', lambda s: False):
         with self.assertRaises(ConfigBuilderError) as cm:
             ConfigBuilder().add_template_dirs('no/such/path')
     self.assertEqual(
             'template_dir path is not a directory: no/such/path',
             str(cm.exception))
Esempio n. 8
0
 def testVariables_preventNonStrings_addVariables(self):
     with self.assertRaises(ConfigBuilderError) as cm:
         ConfigBuilder().add_variables({
             4: 'val1',
             'var2': 'val2',
         })
     self.assertEqual('variable must be a string, but instead was: 4', str(cm.exception))
Esempio n. 9
0
 def testTemplateDirs_preventNonBooleans(self):
     with self.assertRaises(ConfigBuilderError) as cm:
         ConfigBuilder().set_recursively_evaluate_jinja_expressions(4)
     self.assertEqual(
             'recursively_evaluate_jinja_expressions must be a boolean, '
             'but instead was: 4',
             str(cm.exception))
Esempio n. 10
0
    def testRecursivelyEvaluateJinjaExpressions_preventInfiniteLoop(self):
        file_map = {
            'docA.md': '{{ blocks["all"] }}',  # Refers to itself.
        }
        template_loader = jinja2.DictLoader({
            'some/path':
            '{{ blocks["all"] }}',  # Use the block defined in the content.
        })
        jinja_env = jinja2.Environment(loader=template_loader)

        # Set recursively_evaluate_jinja_expressions to True.
        config = ConfigBuilder().set_recursively_evaluate_jinja_expressions(
            True).build()
        with self.assertRaises(PublishError) as cm:
            with self.mock_open(file_map):
                result = publish(config,
                                 source='docA.md',
                                 template='some/path',
                                 jinja_env=jinja_env,
                                 no_write=True)
        self.assertEquals(
            self.join_lines(
                'Recursive Jinja expression evaluation exceeded the allowed number of '
                'iterations. Last state of template:', '{{ blocks["all"] }}'),
            str(cm.exception))
Esempio n. 11
0
    def testConfigIsImmutable(self):
        with mock.patch('os.path.isdir', lambda s: True):
            builder = ConfigBuilder().add_template_dirs('template/path1', 'template/path2')
        builder.add_variable('var1', 'val1')
        config = builder.build()

        # Verify config was constructed correctly.
        self.assertSequenceEqual(['template/path1', 'template/path2'], config.template_dirs)
        self.assertDictEqual({'var1': 'val1'}, config.variables)

        new_builder = config.to_builder()
        new_builder.clear_template_dirs()
        new_builder.add_variable('var2', 'val2')

        # Verify previously built config was not affected by changes to new_builder.
        self.assertSequenceEqual(['template/path1', 'template/path2'], config.template_dirs)
        self.assertDictEqual({'var1': 'val1'}, config.variables)
Esempio n. 12
0
    def testOnlyTemplate_success(self):
        template_loader = jinja2.DictLoader({
            'some/path':
            self.join_lines(
                '<title>{{ title }}</title>', '<ul>',
                '{% for user in users -%}',
                '<li><a href="{{ user.url }}">{{ user.username }}</a></li>',
                '{% endfor -%}', '</ul>')
        })
        jinja_env = jinja2.Environment(loader=template_loader)

        class User(object):
            def __init__(self, url, username):
                self.url = url
                self.username = username

        # Build Templar config.
        config_builder = ConfigBuilder()
        config_builder.add_variable('title', 'Test')
        config_builder.add_variable(
            'users', [User('url1', 'user1'),
                      User('url2', 'user2')])
        config = config_builder.build()

        result = publish(config,
                         template='some/path',
                         jinja_env=jinja_env,
                         no_write=True)
        self.assertEqual(
            self.join_lines('<title>Test</title>', '<ul>',
                            '<li><a href="url1">user1</a></li>',
                            '<li><a href="url2">user2</a></li>', '</ul>'),
            result)
Esempio n. 13
0
    def testSourceAndTemplate(self):
        file_map = {
            'docA.md': self.join_lines(
                '~ title: Test',    # Creates a variable called 'title'
                'outside block',
                '<block first>',
                'inside block',
                '</block first>'),
        }
        template_loader = jinja2.DictLoader({
            'some/path': self.join_lines(
                '<title>{{ title }}</title>',  # Use the variable defined in the content.
                '<p>',
                '{{ blocks.first }}',   # Use the block defined in the content.
                '{{ var }}',            # Use the variable defined by VarRule, below.
                '</p>')
        })
        jinja_env = jinja2.Environment(loader=template_loader)

        # Test rule application.
        class UpperCaseRule(Rule):
            def apply(self, content):
                return content.upper()
        class VarRule(VariableRule):
            def extract(self, content):
                return {'var': 'val'}
        config_builder = ConfigBuilder()
        config_builder.append_preprocess_rules(UpperCaseRule(), VarRule())

        with self.mock_open(file_map):
            result = publish(
                    config_builder.build(),
                    source='docA.md',
                    template='some/path',
                    jinja_env=jinja_env,
                    no_write=True)
        self.assertEquals(
                self.join_lines(
                    '<title>Test</title>',
                    '<p>',
                    'INSIDE BLOCK',
                    'val',
                    '</p>'),
                result)
Esempio n. 14
0
    def testSourceAndTemplate(self):
        file_map = {
            'docA.md':
            self.join_lines(
                '~ title: Test',  # Creates a variable called 'title'
                'outside block',
                '<block first>',
                'inside block',
                '</block first>'),
        }
        template_loader = jinja2.DictLoader({
            'some/path':
            self.join_lines(
                '<title>{{ title }}</title>',  # Use the variable defined in the content.
                '<p>',
                '{{ blocks.first }}',  # Use the block defined in the content.
                '{{ var }}',  # Use the variable defined by VarRule, below.
                '</p>')
        })
        jinja_env = jinja2.Environment(loader=template_loader)

        # Test rule application.
        class UpperCaseRule(Rule):
            def apply(self, content):
                return content.upper()

        class VarRule(VariableRule):
            def extract(self, content):
                return {'var': 'val'}

        config_builder = ConfigBuilder()
        config_builder.append_preprocess_rules(UpperCaseRule(), VarRule())

        with self.mock_open(file_map):
            result = publish(config_builder.build(),
                             source='docA.md',
                             template='some/path',
                             jinja_env=jinja_env,
                             no_write=True)
        self.assertEquals(
            self.join_lines('<title>Test</title>', '<p>', 'INSIDE BLOCK',
                            'val', '</p>'), result)
Esempio n. 15
0
    def testOnlyTemplate_success(self):
        template_loader = jinja2.DictLoader({
            'some/path': self.join_lines(
                '<title>{{ title }}</title>',
                '<ul>',
                '{% for user in users -%}',
                '<li><a href="{{ user.url }}">{{ user.username }}</a></li>',
                '{% endfor -%}',
                '</ul>')
        })
        jinja_env = jinja2.Environment(loader=template_loader)
        class User(object):
            def __init__(self, url, username):
                self.url = url
                self.username = username
        # Build Templar config.
        config_builder = ConfigBuilder()
        config_builder.add_variable('title', 'Test')
        config_builder.add_variable('users', [User('url1', 'user1'), User('url2', 'user2')])
        config = config_builder.build()

        result = publish(config, template='some/path', jinja_env=jinja_env, no_write=True)
        self.assertEqual(
                self.join_lines(
                    '<title>Test</title>',
                    '<ul>',
                    '<li><a href="url1">user1</a></li>',
                    '<li><a href="url2">user2</a></li>',
                    '</ul>'),
                result)
Esempio n. 16
0
    def testRecursiveEvaluateJinjaExpressions(self):
        builder = ConfigBuilder()
        # Default should be False.
        self.assertFalse(builder.build().recursively_evaluate_jinja_expressions)

        builder.set_recursively_evaluate_jinja_expressions(True)
        self.assertTrue(builder.build().recursively_evaluate_jinja_expressions)
Esempio n. 17
0
    def testTemplateDirs(self):
        with mock.patch('os.path.isdir', lambda s: True):
            builder = ConfigBuilder().add_template_dirs('template/path1', 'template/path2')
        self.assertSequenceEqual(
                ['template/path1', 'template/path2'],
                builder.build().template_dirs)

        builder.clear_template_dirs()
        self.assertSequenceEqual([], builder.build().template_dirs)
Esempio n. 18
0
 def testOnlySource_withLinks(self):
     file_map = {
         'docA.md':
         self.join_lines('To be or not to be', '<include docB.md:hamlet>'),
         'docB.md':
         self.join_lines('Catchphrases', '<block hamlet>',
                         'That is the question', '</block hamlet>'),
     }
     with self.mock_open(file_map):
         result = publish(ConfigBuilder().build(),
                          source='docA.md',
                          no_write=True)
     self.assertEquals(
         self.join_lines('To be or not to be', 'That is the question'),
         result)
Esempio n. 19
0
    def testWrite(self):
        template_loader = jinja2.DictLoader({
            'some/path': 'content',
        })
        jinja_env = jinja2.Environment(loader=template_loader)

        # Use a simple mock_open instead of this test's mock_open method, since we don't need to
        # open multiple files.
        mock_open = mock.mock_open()
        with mock.patch('builtins.open', mock_open):
            result = publish(ConfigBuilder().build(),
                             template='some/path',
                             destination='dest.html',
                             jinja_env=jinja_env)

        # Verify a file handle to the destination file was opened.
        mock_open.assert_called_once_with('dest.html', 'w')
        # Verify the result was actually written to the destination fie handle.
        handle = mock_open()
        handle.write.assert_called_once_with('content')
Esempio n. 20
0
    def testOnlySource_withRules(self):
        file_map = {
            'docA.md': 'original content',
        }
        class AppliedRule(Rule):
            def apply(self, content):
                return content + ' rule1'
        class NotAppliedRule(Rule):
            def apply(self, content):
                return content + 'rule2'
        config_builder = ConfigBuilder()
        config_builder.append_preprocess_rules(
                AppliedRule(src=r'\.md'),
                NotAppliedRule(dst=r'\.html'))
        config_builder.append_postprocess_rules(AppliedRule(), NotAppliedRule(src=r'\.py'))

        with self.mock_open(file_map):
            result = publish(config_builder.build(), source='docA.md', no_write=True)
        self.assertEquals('original content rule1 rule1', result)
Esempio n. 21
0
    def testOnlySource_withRules(self):
        file_map = {
            'docA.md': 'original content',
        }

        class AppliedRule(Rule):
            def apply(self, content):
                return content + ' rule1'

        class NotAppliedRule(Rule):
            def apply(self, content):
                return content + 'rule2'

        config_builder = ConfigBuilder()
        config_builder.append_preprocess_rules(AppliedRule(src=r'\.md'),
                                               NotAppliedRule(dst=r'\.html'))
        config_builder.append_postprocess_rules(AppliedRule(),
                                                NotAppliedRule(src=r'\.py'))

        with self.mock_open(file_map):
            result = publish(config_builder.build(),
                             source='docA.md',
                             no_write=True)
        self.assertEquals('original content rule1 rule1', result)
Esempio n. 22
0
 def testPostprocessRules_preventNonRules(self):
     with self.assertRaises(ConfigBuilderError) as cm:
         ConfigBuilder().append_postprocess_rules(4)
     self.assertEqual(
             'postprocess_rule must be a Rule object, but instead was: 4',
             str(cm.exception))
Esempio n. 23
0
 def testMissingSourceAndTemplate(self):
     with self.assertRaises(PublishError) as cm:
         publish(ConfigBuilder().build(), no_write=True)
     self.assertEquals(
         "When publishing, source and template cannot both be omitted.",
         str(cm.exception))
Esempio n. 24
0
 def testCompilerRules_preventNonRules(self):
     with self.assertRaises(ConfigBuilderError) as cm:
         ConfigBuilder().append_compiler_rules(4)
     self.assertEqual(
             'compiler_rule must be a Rule, but instead was: 4',
             str(cm.exception))
Esempio n. 25
0
if os.path.isfile("PH_PATH"):
    f = open("PH_PATH", 'r')
    for line in f:
        PH_PATH = line.rstrip()

PH_ASSETS_PATH = os.path.join(PH_PATH, "assets")

##################
# Configurations #
##################


class HomePageLinkRule(SubstitutionRule):
    pattern = r'<home-page-link>'

    def substitute(self, match):
        return PH_PATH


config = ConfigBuilder().add_template_dirs(os.path.join(
    FILEPATH, "templates"), ).add_variables({
        'datetime':
        '{dt:%A}, {dt:%B} {dt.day}, {dt:%Y} at {dt:%l}:{dt:%M} {dt:%p}'.format(
            dt=datetime.now()),
        'class':
        'CS 195',
    }).append_compiler_rules(MarkdownToHtmlRule(), ).append_postprocess_rules(
        HomePageLinkRule(src='md$', dst='html$'),
        HtmlTableOfContents(),
    ).build()
Esempio n. 26
0
 def testVariables_addVariables(self):
     builder = ConfigBuilder().add_variables({
         'var1': 'val1',
         'var2': 'val2',
     })
     self.assertDictEqual({'var1': 'val1', 'var2': 'val2'}, builder.build().variables)
Esempio n. 27
0
    def testVariables_addVariable(self):
        builder = ConfigBuilder().add_variable('var1', 'val1').add_variable('var2', 'val2')
        self.assertDictEqual({'var1': 'val1', 'var2': 'val2'}, builder.build().variables)

        builder.clear_variables()
        self.assertDictEqual({}, builder.build().variables)
Esempio n. 28
0
from templar.api.config import ConfigBuilder

import os.path

config = ConfigBuilder().add_template_dirs(os.path.dirname(__file__)).build()
Esempio n. 29
0
 def testTemplateDirs_preventNonStrings(self):
     with self.assertRaises(ConfigBuilderError) as cm:
         ConfigBuilder().add_template_dirs(4)
     self.assertEqual(
             'template_dir must be a string, but instead was: 4',
             str(cm.exception))
Esempio n. 30
0
# A valid config file must contain a variable called 'config' that is a Config
# object.

from templar.api.config import ConfigBuilder

config = ConfigBuilder()  # Didn't call build.
Esempio n. 31
0
 def testEmptyBuilder(self):
     config = ConfigBuilder().build()
     self.assertSequenceEqual([], config.template_dirs)
     self.assertDictEqual({}, config.variables)
     self.assertSequenceEqual([], config.preprocess_rules)
     self.assertSequenceEqual([], config.postprocess_rules)
Esempio n. 32
0
from templar.api.config import ConfigBuilder
from templar.api.rules.core import SubstitutionRule
from templar.api.rules.compiler_rules import MarkdownToHtmlRule
from templar.api.rules.table_of_contents import HtmlTableOfContents


class ImageRule(SubstitutionRule):
    pattern = re.compile(r'(<img.*?)>')

    def substitute(self, match):
        return match.group(1) + ' class="img-responsive">'


_config_builder = ConfigBuilder().add_template_dirs(
    'templates',
    'projects/templates',
    'cs61a/review/templates',
).add_variables({
    'MASTER_DIR': '',
    'CS61A_DIR': '/cs61a',
    'REVIEW_DIR': '/cs61a/review',
    'NOTES_DIR': '/cs61a/notes',
    'BLOG_DIR': '/blog',
    'PROJECTS_DIR': '/projects',
}).append_compiler_rules(MarkdownToHtmlRule()).append_postprocess_rules(
    HtmlTableOfContents(),
    ImageRule(dst=r'\.html'),
)

config = _config_builder.build()
Esempio n. 33
0
 def testRules(self):
     rule1, rule2, rule3, = Rule(), Rule(), Rule()
     builder = ConfigBuilder().append_preprocess_rules(rule1)
     builder.append_compiler_rules(rule2)
     builder.append_postprocess_rules(rule3)
     self.assertSequenceEqual([rule1, rule2, rule3], builder.build().rules)