Skip to content

Commit

Permalink
Give each composer a handle to the configuration.
Browse files Browse the repository at this point in the history
  • Loading branch information
mblayman committed Sep 11, 2015
1 parent e71a252 commit 8807fb8
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 23 deletions.
9 changes: 7 additions & 2 deletions handroll/composers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
class Composer(object):
"""Interface for all composers"""

def __init__(self, config):
"""Each composer is given access to the configuration."""
self._config = config

def compose(self, catalog, source_file, out_dir):
"""Compose whatever appropriate output is generated by the composer.
Expand All @@ -36,7 +40,7 @@ def __init__(self, config):
self._config = config
self._available_composers = {}
self._composers = {}
self.default_composer = CopyComposer()
self.default_composer = CopyComposer(config)

# pkg_resources emits an annoying message related to security that is
# completely irritating for an average user to address. Filter it out.
Expand Down Expand Up @@ -66,7 +70,8 @@ def _get_composer(self, ext):
"""
if ext not in self._composers:
if ext in self._available_composers:
self._composers[ext] = self._available_composers[ext]()
composer_cls = self._available_composers[ext]
self._composers[ext] = composer_cls(self._config)
else:
self._composers[ext] = self.default_composer

Expand Down
72 changes: 51 additions & 21 deletions handroll/tests/test_composers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,25 @@

class TestComposer(TestCase):

def _make_one(self):
config = self.factory.make_configuration()
return Composer(config)

def test_compose_not_implemented(self):
composer = Composer()
composer = self._make_one()
self.assertRaises(
NotImplementedError, composer.compose, None, None, None)

def test_output_extension_not_implemented(self):
composer = Composer()
composer = self._make_one()
self.assertRaises(
NotImplementedError, lambda: composer.output_extension)

def test_has_config(self):
config = self.factory.make_configuration()
composer = Composer(config)
self.assertEqual(config, composer._config)


class TestComposers(TestCase):

Expand All @@ -52,6 +61,10 @@ def test_has_config(self):

class TestAtomComposer(TestCase):

def _make_one(self):
config = self.factory.make_configuration()
return AtomComposer(config)

def setUp(self):
site = tempfile.mkdtemp()
self.source_file = os.path.join(site, 'feed.atom')
Expand All @@ -73,7 +86,7 @@ def test_composes_feed(self):
}"""
with open(self.source_file, 'w') as f:
f.write(source)
composer = AtomComposer()
composer = self._make_one()
composer.compose(None, self.source_file, self.outdir)
self.assertTrue(os.path.exists(self.output_file))

Expand All @@ -84,24 +97,28 @@ def test_must_have_entries(self):
}"""
with open(self.source_file, 'w') as f:
f.write(source)
composer = AtomComposer()
composer = self._make_one()
self.assertRaises(
AbortError, composer.compose, None, self.source_file, self.outdir)

@mock.patch('handroll.composers.atom.json')
def test_skips_up_to_date(self, json):
open(self.output_file, 'w').close()
composer = AtomComposer()
composer = self._make_one()
composer.compose(None, self.source_file, self.outdir)
self.assertFalse(json.loads.called)

def test_output_extension(self):
composer = AtomComposer()
composer = self._make_one()
self.assertEqual('.xml', composer.output_extension)


class TestCopyComposer(TestCase):

def _make_one(self):
config = self.factory.make_configuration()
return CopyComposer(config)

@mock.patch('handroll.composers.shutil')
def test_skips_same_files(self, shutil):
marker = 'marker.txt'
Expand All @@ -110,7 +127,7 @@ def test_skips_same_files(self, shutil):
outdir = tempfile.mkdtemp()
open(source_file, 'w').close()
open(os.path.join(outdir, marker), 'w').close()
composer = CopyComposer()
composer = self._make_one()
composer.compose(None, source_file, outdir)
self.assertFalse(shutil.copy.called)

Expand All @@ -123,7 +140,7 @@ def test_copies_when_content_differs(self, shutil):
open(source_file, 'w').close()
with open(os.path.join(outdir, marker), 'w') as f:
f.write('something different')
composer = CopyComposer()
composer = self._make_one()
composer.compose(None, source_file, outdir)
self.assertTrue(shutil.copy.called)

Expand All @@ -133,19 +150,23 @@ def test_output_extension(self):
This composer is the fallback composer and resolution should
never rely on this composer's output extension.
"""
composer = CopyComposer()
composer = self._make_one()
self.assertRaises(AttributeError, lambda: composer.output_extension)


class TestGenericHTMLComposer(TestCase):

def _make_one(self):
config = self.factory.make_configuration()
return GenericHTMLComposer(config)

def test_composes_file(self):
catalog = mock.MagicMock()
site = tempfile.mkdtemp()
source_file = os.path.join(site, 'sample.generic')
open(source_file, 'w').close()
outdir = ''
composer = GenericHTMLComposer()
composer = self._make_one()
self.assertRaises(
NotImplementedError,
composer.compose, catalog, source_file, outdir)
Expand All @@ -154,13 +175,13 @@ def test_selects_default_template(self):
catalog = mock.MagicMock()
default = mock.PropertyMock()
type(catalog).default = default
composer = GenericHTMLComposer()
composer = self._make_one()
composer.select_template(catalog, {})
self.assertTrue(default.called)

def test_selects_specified_template(self):
catalog = mock.MagicMock()
composer = GenericHTMLComposer()
composer = self._make_one()
composer.select_template(catalog, {'template': 'base.j2'})
catalog.get_template.assert_called_once_with('base.j2')

Expand All @@ -173,7 +194,7 @@ def test_gets_frontmatter(self):
""")
with tempfile.NamedTemporaryFile(delete=False) as f:
f.write(source.encode('utf-8'))
composer = GenericHTMLComposer()
composer = self._make_one()
data, source = composer._get_data(f.name)
self.assertEqual('A Fake Title', data['title'])
self.assertEqual('The Content', source)
Expand All @@ -188,7 +209,7 @@ def test_fires_frontmatter_loaded(self, signals):
""")
with tempfile.NamedTemporaryFile(delete=False) as f:
f.write(source.encode('utf-8'))
composer = GenericHTMLComposer()
composer = self._make_one()
data, source = composer._get_data(f.name)
signals.frontmatter_loaded.send.assert_called_once_with(
f.name, frontmatter={'title': 'A Fake Title'})
Expand All @@ -204,7 +225,7 @@ def test_needs_update(self):
template = mock.MagicMock()
template.last_modified = future

composer = GenericHTMLComposer()
composer = self._make_one()
self.assertTrue(composer._needs_update(None, source_file, output_file))

past = future - 10
Expand All @@ -217,15 +238,19 @@ def test_needs_update(self):
composer._needs_update(template, source_file, output_file))

def test_output_extension(self):
composer = GenericHTMLComposer()
composer = self._make_one()
self.assertEqual('.html', composer.output_extension)


class TestMarkdownComposer(TestCase):

def _make_one(self):
config = self.factory.make_configuration()
return MarkdownComposer(config)

def test_generates_html(self):
source = '**bold**'
composer = MarkdownComposer()
composer = self._make_one()
html = composer._generate_content(source)
self.assertEqual('<p><strong>bold</strong></p>', html)

Expand All @@ -244,22 +269,26 @@ def test_composes_no_update(self):
catalog = mock.MagicMock()
catalog.default = template

composer = MarkdownComposer()
composer = self._make_one()
composer.compose(catalog, source_file, outdir)
self.assertFalse(template.render.called)

def test_uses_smartypants(self):
source = '"quoted"'
composer = MarkdownComposer()
composer = self._make_one()
html = composer._generate_content(source)
self.assertEqual('<p>&ldquo;quoted&rdquo;</p>', html)


class TestReStructuredTextComposer(TestCase):

def _make_one(self):
config = self.factory.make_configuration()
return ReStructuredTextComposer(config)

def test_generates_html(self):
source = '**bold**'
composer = ReStructuredTextComposer()
composer = self._make_one()
html = composer._generate_content(source)
expected = '<div class="document">\n' \
'<p><strong>bold</strong></p>\n' \
Expand Down Expand Up @@ -321,6 +350,7 @@ class TestTextileComposer(TestCase):

def test_generates_html(self):
source = '*bold*'
composer = TextileComposer()
config = self.factory.make_configuration()
composer = TextileComposer(config)
html = composer._generate_content(source)
self.assertEqual('\t<p><strong>bold</strong></p>', html)

0 comments on commit 8807fb8

Please sign in to comment.