diff --git a/IPython/core/blockbreaker.py b/IPython/core/blockbreaker.py
index 8ba4a7a..f755063 100644
--- a/IPython/core/blockbreaker.py
+++ b/IPython/core/blockbreaker.py
@@ -27,6 +27,8 @@ import sys
 # Utilities
 #-----------------------------------------------------------------------------
 
+# FIXME: move these utilities to the general ward...
+
 # compiled regexps for autoindent management
 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
@@ -76,10 +78,7 @@ def get_input_encoding():
 # Classes and functions
 #-----------------------------------------------------------------------------
 
-
 class BlockBreaker(object):
-    # List
-    buffer = None
     # Command compiler
     compile = None
     # Number of spaces of indentation
@@ -92,17 +91,23 @@ class BlockBreaker(object):
     code = None
     # Boolean indicating whether the current block is complete
     is_complete = None
+
+    # Private attributes
+    
+    # List
+    _buffer = None
     
     def __init__(self):
-        self.buffer = []
+        self._buffer = []
         self.compile = codeop.CommandCompiler()
         self.encoding = get_input_encoding()
 
     def reset(self):
         """Reset the input buffer and associated state."""
         self.indent_spaces = 0
-        self.buffer[:] = []
+        self._buffer[:] = []
         self.source = ''
+        self.code = None
 
     def get_source(self, reset=False):
         """Return the input source.
@@ -117,34 +122,6 @@ class BlockBreaker(object):
             self.reset()
         return out
 
-    def update_indent(self, lines):
-        """Keep track of the indent level."""
-
-        for line in remove_comments(lines).splitlines():
-            
-            if line and not line.isspace():
-                if self.code is not None:
-                    inisp = num_ini_spaces(line)
-                    if inisp < self.indent_spaces:
-                        self.indent_spaces = inisp
-
-                if line[-1] == ':':
-                    self.indent_spaces += 4
-                elif dedent_re.match(line):
-                    self.indent_spaces -= 4
-
-    def store(self, lines):
-        """Store one or more lines of input.
-
-        If input lines are not newline-terminated, a newline is automatically
-        appended."""
-
-        if lines.endswith('\n'):
-            self.buffer.append(lines)
-        else:
-            self.buffer.append(lines+'\n')
-        self.source = ''.join(self.buffer).encode(self.encoding)
-
     def push(self, lines):
         """Push one ore more lines of input.
 
@@ -170,10 +147,10 @@ class BlockBreaker(object):
         # this allows execution of indented pasted code. It is tempting
         # to add '\n' at the end of source to run commands like ' a=1'
         # directly, but this fails for more complicated scenarios
-        if not self.buffer and lines[:1] in [' ', '\t']:
+        if not self._buffer and lines[:1] in [' ', '\t']:
             lines = 'if 1:\n%s' % lines
         
-        self.store(lines)
+        self._store(lines)
         source = self.source
 
         # Before calling compile(), reset the code object to None so that if an
@@ -187,7 +164,7 @@ class BlockBreaker(object):
             self.is_complete = False
         else:
             self.is_complete = True
-        self.update_indent(lines)
+        self._update_indent(lines)
         return self.is_complete
 
     def interactive_block_ready(self):
@@ -223,163 +200,38 @@ class BlockBreaker(object):
         else:
             return False
 
-
     def split_blocks(self, lines):
         """Split a multiline string into multiple input blocks"""
+        raise NotImplementedError
 
-#-----------------------------------------------------------------------------
-# Tests
-#-----------------------------------------------------------------------------
+    #------------------------------------------------------------------------
+    # Private interface
+    #------------------------------------------------------------------------
+    
+    def _update_indent(self, lines):
+        """Keep track of the indent level."""
 
-import unittest
+        for line in remove_comments(lines).splitlines():
+            
+            if line and not line.isspace():
+                if self.code is not None:
+                    inisp = num_ini_spaces(line)
+                    if inisp < self.indent_spaces:
+                        self.indent_spaces = inisp
 
-import nose.tools as nt
+                if line[-1] == ':':
+                    self.indent_spaces += 4
+                elif dedent_re.match(line):
+                    self.indent_spaces -= 4
 
-    
-def test_spaces():
-    tests = [('', 0),
-             (' ', 1),
-             ('\n', 0),
-             (' \n', 1),
-             ('x', 0),
-             (' x', 1),
-             ('  x',2),
-             ('    x',4),
-             # Note: tabs are counted as a single whitespace!
-             ('\tx', 1),
-             ('\t x', 2),
-             ]
-    
-    for s, nsp in tests:
-        nt.assert_equal(num_ini_spaces(s), nsp)
-
-
-def test_remove_comments():
-    tests = [('text', 'text'),
-             ('text # comment', 'text '),
-             ('text # comment\n', 'text \n'),
-             ('text # comment \n', 'text \n'),
-             ('line # c \nline\n','line \nline\n'),
-             ('line # c \nline#c2  \nline\nline #c\n\n',
-              'line \nline\nline\nline \n\n'),
-             ]
-
-    for inp, out in tests:
-        nt.assert_equal(remove_comments(inp), out)
-
-
-def test_get_input_encoding():
-    encoding = get_input_encoding()
-    nt.assert_true(isinstance(encoding, basestring))
-    # simple-minded check that at least encoding a simple string works with the
-    # encoding we got.
-    nt.assert_equal('test'.encode(encoding), 'test')
-
-
-class BlockBreakerTestCase(unittest.TestCase):
-    def setUp(self):
-        self.bb = BlockBreaker()
-
-    def test_reset(self):
-        self.bb.store('hello')
-        self.bb.reset()
-        self.assertEqual(self.bb.buffer, [])
-        self.assertEqual(self.bb.indent_spaces, 0)
-        self.assertEqual(self.bb.get_source(), '')
-
-    def test_source(self):
-        self.bb.store('1')
-        self.bb.store('2')
-        out = self.bb.get_source()
-        self.assertEqual(out, '1\n2\n')
-        out = self.bb.get_source(reset=True)
-        self.assertEqual(out, '1\n2\n')
-        self.assertEqual(self.bb.buffer, [])
-        out = self.bb.get_source()
-        self.assertEqual(out, '')
-        
-    def test_indent(self):
-        bb = self.bb # shorthand
-        bb.push('x=1')
-        self.assertEqual(bb.indent_spaces, 0)
-        bb.push('if 1:\n    x=1')
-        self.assertEqual(bb.indent_spaces, 4)
-        bb.push('y=2\n')
-        self.assertEqual(bb.indent_spaces, 0)
-        bb.push('if 1:')
-        self.assertEqual(bb.indent_spaces, 4)
-        bb.push('    x=1')
-        self.assertEqual(bb.indent_spaces, 4)
-        # Blank lines shouldn't change the indent level
-        bb.push(' '*2)
-        self.assertEqual(bb.indent_spaces, 4)
-
-    def test_indent2(self):
-        bb = self.bb
-        # When a multiline statement contains parens or multiline strings, we
-        # shouldn't get confused.
-        bb.push("if 1:")
-        bb.push("    x = (1+\n    2)")
-        self.assertEqual(bb.indent_spaces, 4)
-
-    def test_dedent(self):
-        bb = self.bb # shorthand
-        bb.push('if 1:')
-        self.assertEqual(bb.indent_spaces, 4)
-        bb.push('    pass')
-        self.assertEqual(bb.indent_spaces, 0)
-        
-    def test_push(self):
-        bb = self.bb
-        bb.push('x=1')
-        self.assertTrue(bb.is_complete)
-
-    def test_push2(self):
-        bb = self.bb
-        bb.push('if 1:')
-        self.assertFalse(bb.is_complete)
-        for line in ['  x=1', '# a comment', '  y=2']:
-            bb.push(line)
-            self.assertTrue(bb.is_complete)
-            
-    def test_push3(self):
-        """Test input with leading whitespace"""
-        bb = self.bb
-        bb.push('  x=1')
-        bb.push('  y=2')
-        self.assertEqual(bb.source, 'if 1:\n  x=1\n  y=2\n')
-
-    def test_interactive_block_ready(self):
-        bb = self.bb
-        bb.push('x=1')
-        self.assertTrue(bb.interactive_block_ready())
-
-    def test_interactive_block_ready2(self):
-        bb = self.bb
-        bb.push('if 1:\n  x=1')
-        self.assertFalse(bb.interactive_block_ready())
-        bb.push('')
-        self.assertTrue(bb.interactive_block_ready())
-        
-    def test_interactive_block_ready3(self):
-        bb = self.bb
-        bb.push("x = (2+\n3)")
-        self.assertTrue(bb.interactive_block_ready())
-
-    def test_interactive_block_ready4(self):
-        bb = self.bb
-        # When a multiline statement contains parens or multiline strings, we
-        # shouldn't get confused.
-        # FIXME: we should be able to better handle de-dents in statements like
-        # multiline strings and multiline expressions (continued with \ or
-        # parens).  Right now we aren't handling the indentation tracking quite
-        # correctly with this, though in practice it may not be too much of a
-        # problem.  We'll need to see.
-        bb.push("if 1:")
-        bb.push("    x = (2+")
-        bb.push("    3)")
-        self.assertFalse(bb.interactive_block_ready())
-        bb.push("    y = 3")
-        self.assertFalse(bb.interactive_block_ready())
-        bb.push('')
-        self.assertTrue(bb.interactive_block_ready())
+    def _store(self, lines):
+        """Store one or more lines of input.
+
+        If input lines are not newline-terminated, a newline is automatically
+        appended."""
+
+        if lines.endswith('\n'):
+            self._buffer.append(lines)
+        else:
+            self._buffer.append(lines+'\n')
+        self.source = ''.join(self._buffer).encode(self.encoding)
diff --git a/IPython/core/tests/test_blockbreaker.py b/IPython/core/tests/test_blockbreaker.py
new file mode 100644
index 0000000..6bf642d
--- /dev/null
+++ b/IPython/core/tests/test_blockbreaker.py
@@ -0,0 +1,173 @@
+"""Tests for the blockbreaker module.
+"""
+#-----------------------------------------------------------------------------
+#  Copyright (C) 2010  The IPython Development Team
+#
+#  Distributed under the terms of the BSD License.  The full license is in
+#  the file COPYING, distributed as part of this software.
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# Imports
+#-----------------------------------------------------------------------------
+# stdlib
+import unittest
+
+# Third party
+import nose.tools as nt
+
+# Our own
+from IPython.core import blockbreaker as BB
+
+#-----------------------------------------------------------------------------
+# Tests
+#-----------------------------------------------------------------------------
+def test_spaces():
+    tests = [('', 0),
+             (' ', 1),
+             ('\n', 0),
+             (' \n', 1),
+             ('x', 0),
+             (' x', 1),
+             ('  x',2),
+             ('    x',4),
+             # Note: tabs are counted as a single whitespace!
+             ('\tx', 1),
+             ('\t x', 2),
+             ]
+    
+    for s, nsp in tests:
+        nt.assert_equal(BB.num_ini_spaces(s), nsp)
+
+
+def test_remove_comments():
+    tests = [('text', 'text'),
+             ('text # comment', 'text '),
+             ('text # comment\n', 'text \n'),
+             ('text # comment \n', 'text \n'),
+             ('line # c \nline\n','line \nline\n'),
+             ('line # c \nline#c2  \nline\nline #c\n\n',
+              'line \nline\nline\nline \n\n'),
+             ]
+
+    for inp, out in tests:
+        nt.assert_equal(BB.remove_comments(inp), out)
+
+
+def test_get_input_encoding():
+    encoding = BB.get_input_encoding()
+    nt.assert_true(isinstance(encoding, basestring))
+    # simple-minded check that at least encoding a simple string works with the
+    # encoding we got.
+    nt.assert_equal('test'.encode(encoding), 'test')
+
+
+class BlockBreakerTestCase(unittest.TestCase):
+    def setUp(self):
+        self.bb = BB.BlockBreaker()
+
+    def test_reset(self):
+        bb = self.bb
+        bb.push('x=1')
+        bb.reset()
+        self.assertEqual(bb._buffer, [])
+        self.assertEqual(bb.indent_spaces, 0)
+        self.assertEqual(bb.get_source(), '')
+        self.assertEqual(bb.code, None)
+
+    def test_source(self):
+        self.bb._store('1')
+        self.bb._store('2')
+        out = self.bb.get_source()
+        self.assertEqual(out, '1\n2\n')
+        out = self.bb.get_source(reset=True)
+        self.assertEqual(out, '1\n2\n')
+        self.assertEqual(self.bb._buffer, [])
+        out = self.bb.get_source()
+        self.assertEqual(out, '')
+        
+    def test_indent(self):
+        bb = self.bb # shorthand
+        bb.push('x=1')
+        self.assertEqual(bb.indent_spaces, 0)
+        bb.push('if 1:\n    x=1')
+        self.assertEqual(bb.indent_spaces, 4)
+        bb.push('y=2\n')
+        self.assertEqual(bb.indent_spaces, 0)
+        bb.push('if 1:')
+        self.assertEqual(bb.indent_spaces, 4)
+        bb.push('    x=1')
+        self.assertEqual(bb.indent_spaces, 4)
+        # Blank lines shouldn't change the indent level
+        bb.push(' '*2)
+        self.assertEqual(bb.indent_spaces, 4)
+
+    def test_indent2(self):
+        bb = self.bb
+        # When a multiline statement contains parens or multiline strings, we
+        # shouldn't get confused.
+        bb.push("if 1:")
+        bb.push("    x = (1+\n    2)")
+        self.assertEqual(bb.indent_spaces, 4)
+
+    def test_dedent(self):
+        bb = self.bb # shorthand
+        bb.push('if 1:')
+        self.assertEqual(bb.indent_spaces, 4)
+        bb.push('    pass')
+        self.assertEqual(bb.indent_spaces, 0)
+        
+    def test_push(self):
+        bb = self.bb
+        bb.push('x=1')
+        self.assertTrue(bb.is_complete)
+
+    def test_push2(self):
+        bb = self.bb
+        bb.push('if 1:')
+        self.assertFalse(bb.is_complete)
+        for line in ['  x=1', '# a comment', '  y=2']:
+            bb.push(line)
+            self.assertTrue(bb.is_complete)
+            
+    def test_push3(self):
+        """Test input with leading whitespace"""
+        bb = self.bb
+        bb.push('  x=1')
+        bb.push('  y=2')
+        self.assertEqual(bb.source, 'if 1:\n  x=1\n  y=2\n')
+
+    def test_interactive_block_ready(self):
+        bb = self.bb
+        bb.push('x=1')
+        self.assertTrue(bb.interactive_block_ready())
+
+    def test_interactive_block_ready2(self):
+        bb = self.bb
+        bb.push('if 1:\n  x=1')
+        self.assertFalse(bb.interactive_block_ready())
+        bb.push('')
+        self.assertTrue(bb.interactive_block_ready())
+        
+    def test_interactive_block_ready3(self):
+        bb = self.bb
+        bb.push("x = (2+\n3)")
+        self.assertTrue(bb.interactive_block_ready())
+
+    def test_interactive_block_ready4(self):
+        bb = self.bb
+        # When a multiline statement contains parens or multiline strings, we
+        # shouldn't get confused.
+        # FIXME: we should be able to better handle de-dents in statements like
+        # multiline strings and multiline expressions (continued with \ or
+        # parens).  Right now we aren't handling the indentation tracking quite
+        # correctly with this, though in practice it may not be too much of a
+        # problem.  We'll need to see.
+        bb.push("if 1:")
+        bb.push("    x = (2+")
+        bb.push("    3)")
+        self.assertFalse(bb.interactive_block_ready())
+        bb.push("    y = 3")
+        self.assertFalse(bb.interactive_block_ready())
+        bb.push('')
+        self.assertTrue(bb.interactive_block_ready())