# Path: templar/linker.py
# def link(source_path):
#     """Links the content found at source_path and represents a Block that represents the content."""
#     if not os.path.isfile(source_path):
#         raise SourceNotFound(source_path)
#     with open(source_path, 'r') as f:
#         content = f.read()
#     block_map = BlockMap()  # The map will be populated with the following function call.
#     all_block = convert_lines_to_block(
#             content.splitlines(), block_map, LinkStack(source_path), source_path)
#     return all_block, block_map.get_variables()
# 
# Path: templar/linker.py
# def get_block_dict(top_level_block):
#     """Returns a dictionary of block names (str) to block contents (str) for all child blocks, as
#     well as the original block itself.
# 
#     The block_dict argument is only used for recursive calls and should not 
#     """
#     block_stack = [top_level_block]
#     block_dict = {}
#     while block_stack:
#         block = block_stack.pop()
#         block_dict[block.name] = str(block)
#         for segment in block.segments:
#             if isinstance(segment, Block):
#                 block_stack.append(segment)
#     return block_dict
# 
# Path: templar/linker.py
# class Block(object):
#     def __init__(self, source_path, name, segments):
#         self.source_path = source_path
#         self.name = name
#         self.segments = segments
#         self._str = None  # Cache the str representation of this block.
# 
#     def apply_rule(self, rule):
#         self._str = None  # Clear str cache.
#         for i, segment in enumerate(self.segments):
#             assert isinstance(segment, str) or isinstance(segment, Block)
#             if isinstance(segment, str):
#                 self.segments[i] = rule.apply(segment)
#             else:
#                 segment.apply_rule(rule)  # Recursively apply rule onto nested blocks.
# 
#     def __str__(self):
#         if self._str is None:
#             self._str = '\n'.join(str(segment) for segment in self.segments)
#         return self._str
# 
# Path: templar/linker.py
# class SourceNotFound(TemplarError):
#     def __init__(self, source_path):
#         super().__init__('Could not find source file: ' + source_path)
# 
# Path: templar/linker.py
# class InvalidBlockName(TemplarError):
#     pass
# 
# Path: templar/linker.py
# class IncludeNonExistentBlock(TemplarError):
#     pass
# 
# Path: templar/linker.py
# class CyclicalIncludeError(TemplarError):
#     def __init__(self, link_stack, last_file):
#         super().__init__(' -> '.join(link_stack + [last_file]))


from templar.linker import link
from templar.linker import get_block_dict
from templar.linker import Block
from templar.linker import SourceNotFound
from templar.linker import InvalidBlockName
from templar.linker import IncludeNonExistentBlock
from templar.linker import CyclicalIncludeError
import unittest
import mock
        for expected_segment, actual_segment in zip(expected.segments, actual.segments):
            if isinstance(expected_segment, str):
                self.assertEqual(expected_segment, actual_segment)
            elif isinstance(expected_segment, Block):
                self.assertBlockEqual(expected_segment, actual_segment)
            else:
                self.fail('Encountered segment of type "{}"'.format(expected_segment))

    def join_lines(self, *lines):
        """Concatenates multiple strings together with newlines in between.

        Using this method is cleaner than using multiline strings (since we need to handle
        indentation and leading/trailing newlines).
        """
        return '\n'.join(lines)

class GetBlockDictTest(unittest.TestCase):
    def testNoNestedBlocks(self):
        block_all = Block('some/path', 'all', ['all content'])
        block_dict = get_block_dict(block_all)
        self.assertEqual({
            'all': 'all content',
        }, block_dict)

    def testNestedBlocks(self):
        block_inner = Block('some/path', 'inner', ['inner content'])
        block_outer = Block('some/path', 'outer', [
            'outer content',
            block_inner,
            'outer content'])

# Path: templar/linker.py
# def link(source_path):
#     """Links the content found at source_path and represents a Block that represents the content."""
#     if not os.path.isfile(source_path):
#         raise SourceNotFound(source_path)
#     with open(source_path, 'r') as f:
#         content = f.read()
#     block_map = BlockMap()  # The map will be populated with the following function call.
#     all_block = convert_lines_to_block(
#             content.splitlines(), block_map, LinkStack(source_path), source_path)
#     return all_block, block_map.get_variables()
# 
# Path: templar/linker.py
# def get_block_dict(top_level_block):
#     """Returns a dictionary of block names (str) to block contents (str) for all child blocks, as
#     well as the original block itself.
# 
#     The block_dict argument is only used for recursive calls and should not 
#     """
#     block_stack = [top_level_block]
#     block_dict = {}
#     while block_stack:
#         block = block_stack.pop()
#         block_dict[block.name] = str(block)
#         for segment in block.segments:
#             if isinstance(segment, Block):
#                 block_stack.append(segment)
#     return block_dict
# 
# Path: templar/linker.py
# class Block(object):
#     def __init__(self, source_path, name, segments):
#         self.source_path = source_path
#         self.name = name
#         self.segments = segments
#         self._str = None  # Cache the str representation of this block.
# 
#     def apply_rule(self, rule):
#         self._str = None  # Clear str cache.
#         for i, segment in enumerate(self.segments):
#             assert isinstance(segment, str) or isinstance(segment, Block)
#             if isinstance(segment, str):
#                 self.segments[i] = rule.apply(segment)
#             else:
#                 segment.apply_rule(rule)  # Recursively apply rule onto nested blocks.
# 
#     def __str__(self):
#         if self._str is None:
#             self._str = '\n'.join(str(segment) for segment in self.segments)
#         return self._str
# 
# Path: templar/linker.py
# class SourceNotFound(TemplarError):
#     def __init__(self, source_path):
#         super().__init__('Could not find source file: ' + source_path)
# 
# Path: templar/linker.py
# class InvalidBlockName(TemplarError):
#     pass
# 
# Path: templar/linker.py
# class IncludeNonExistentBlock(TemplarError):
#     pass
# 
# Path: templar/linker.py
# class CyclicalIncludeError(TemplarError):
#     def __init__(self, link_stack, last_file):
#         super().__init__(' -> '.join(link_stack + [last_file]))


# Path: tests/linker_test.py
from templar.linker import link
from templar.linker import get_block_dict
from templar.linker import Block
from templar.linker import SourceNotFound
from templar.linker import InvalidBlockName
from templar.linker import IncludeNonExistentBlock
from templar.linker import CyclicalIncludeError
import unittest
import mock

        for expected_segment, actual_segment in zip(expected.segments, actual.segments):
            if isinstance(expected_segment, str):
                self.assertEqual(expected_segment, actual_segment)
            elif isinstance(expected_segment, Block):
                self.assertBlockEqual(expected_segment, actual_segment)
            else:
                self.fail('Encountered segment of type "{}"'.format(expected_segment))

    def join_lines(self, *lines):
        """Concatenates multiple strings together with newlines in between.

        Using this method is cleaner than using multiline strings (since we need to handle
        indentation and leading/trailing newlines).
        """
        return '\n'.join(lines)

class GetBlockDictTest(unittest.TestCase):
    def testNoNestedBlocks(self):
        block_all = Block('some/path', 'all', ['all content'])
        block_dict = get_block_dict(block_all)
        self.assertEqual({
            'all': 'all content',
        }, block_dict)

    def testNestedBlocks(self):
        block_inner = Block('some/path', 'inner', ['inner content'])
        block_outer = Block('some/path', 'outer', [
            'outer content',
            block_inner,
            'outer content'])

        block_all = Block('some/path', 'all', [