Skip to content

Commit

Permalink
Make the composers designate their output extension.
Browse files Browse the repository at this point in the history
This will be used for file resolving later.
  • Loading branch information
mblayman committed Jun 27, 2015
1 parent 7a9dffa commit 425e2df
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 3 deletions.
12 changes: 12 additions & 0 deletions handroll/composers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ def compose(self, catalog, source_file, out_dir):
"""
raise NotImplementedError

@property
def output_extension(self):
"""Get the extension of the output file generated by this composer."""
raise NotImplementedError


class Composers(object):
"""A collection of available composers"""
Expand Down Expand Up @@ -96,3 +101,10 @@ def compose(self, catalog, source_file, out_dir):
logger.info(_('Copying {filename} to {out_dir} ...').format(
filename=filename, out_dir=out_dir))
shutil.copy(source_file, out_dir)

@property
def output_extension(self):
raise AttributeError(
'The output extension of the CopyComposer is dependent '
'on the source file extension. This property should not '
'be invoked for this composer.')
3 changes: 2 additions & 1 deletion handroll/composers/atom.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ class AtomComposer(Composer):
.. literalinclude:: ../sample/atom_sample.atom
"""
output_extension = '.xml'

def compose(self, catalog, source_file, out_dir):
root, ext = os.path.splitext(os.path.basename(source_file))
filename = root + '.xml'
filename = root + self.output_extension
output_file = os.path.join(out_dir, filename)
if self._needs_update(source_file, output_file):
logger.info(_('Generating Atom XML for {source_file} ...').format(
Expand Down
3 changes: 2 additions & 1 deletion handroll/composers/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class GenericHTMLComposer(Composer):
The title will be extracted from the first line and the remaining source
lines will be passed to a template method for further processing.
"""
output_extension = '.html'

# A pattern to get source content from a file with YAML front matter.
yaml_scanner = re.compile(r""".*? # YAML header
Expand All @@ -40,7 +41,7 @@ def compose(self, catalog, source_file, out_dir):

# Determine the output filename.
root, ext = os.path.splitext(os.path.basename(source_file))
filename = root + '.html'
filename = root + self.output_extension
output_file = os.path.join(out_dir, filename)

if self._needs_update(template, source_file, output_file):
Expand Down
3 changes: 2 additions & 1 deletion handroll/composers/sass.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class SassComposer(Composer):
installed separately before it can be used. Check out the `installation
options <http://sass-lang.com/install>`_.
"""
output_extension = '.css'

def __init__(self, path=None):
self.sass = spawn.find_executable('sass', path)
Expand All @@ -29,7 +30,7 @@ def __init__(self, path=None):

def compose(self, catalog, source_file, out_dir):
root, ext = os.path.splitext(os.path.basename(source_file))
filename = root + '.css'
filename = root + self.output_extension
output_file = os.path.join(out_dir, filename)

logger.info(_('Generating CSS for {source_file} ...').format(
Expand Down
26 changes: 26 additions & 0 deletions handroll/tests/test_composers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ def test_compose_not_implemented(self):
self.assertRaises(
NotImplementedError, composer.compose, None, None, None)

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


class TestComposers(unittest.TestCase):

Expand Down Expand Up @@ -81,6 +86,10 @@ def test_skips_up_to_date(self, json):
composer.compose(None, self.source_file, self.outdir)
self.assertFalse(json.loads.called)

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


class TestCopyComposer(unittest.TestCase):

Expand Down Expand Up @@ -109,6 +118,15 @@ def test_copies_when_content_differs(self, shutil):
composer.compose(None, source_file, outdir)
self.assertTrue(shutil.copy.called)

def test_output_extension(self):
"""The copy composer takes the extension of the source file.
This composer is the fallback composer and resolution should
never rely on this composer's output extension.
"""
composer = CopyComposer()
self.assertRaises(AttributeError, lambda: composer.output_extension)


class TestGenericHTMLComposer(unittest.TestCase):

Expand Down Expand Up @@ -189,6 +207,10 @@ def test_needs_update(self):
self.assertFalse(
composer._needs_update(template, source_file, output_file))

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


class TestMarkdownComposer(unittest.TestCase):

Expand Down Expand Up @@ -274,6 +296,10 @@ def test_failed_sass_aborts(self, subprocess):
self.assertRaises(
AbortError, composer.compose, None, source_file, output_dir)

def test_output_extension(self):
composer = SassComposer()
self.assertEqual('.css', composer.output_extension)


class TestTextileComposer(unittest.TestCase):

Expand Down

0 comments on commit 425e2df

Please sign in to comment.