diff --git a/README.md b/README.md
index 16153b1..a19316c 100644
--- a/README.md
+++ b/README.md
@@ -76,10 +76,10 @@ Write back to plain text, too:
 
 Or write to a file (or file-like object):
 
-    >>> from io import StringIO
-    >>> f = StringIO()
+    >>> from io import BytesIO
+    >>> f = BytesIO()
     >>> frontmatter.dump(post, f)
-    >>> print(f.getvalue()) # doctest: +NORMALIZE_WHITESPACE
+    >>> print(f.getvalue().decode('utf-8')) # doctest: +NORMALIZE_WHITESPACE
     ---
     excerpt: tl;dr
     layout: post
diff --git a/docs/conf.py b/docs/conf.py
index 6fffc9e..1f9fb46 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -16,9 +16,9 @@
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 #
-# import os
-# import sys
-# sys.path.insert(0, os.path.abspath('.'))
+import os
+import sys
+sys.path.insert(0, os.path.abspath('..'))
 
 # -- General configuration ------------------------------------------------
 
diff --git a/frontmatter/__init__.py b/frontmatter/__init__.py
index 889882f..dd31fe3 100644
--- a/frontmatter/__init__.py
+++ b/frontmatter/__init__.py
@@ -40,16 +40,24 @@ if TOMLHandler is not None:
     handlers['+++'] = TOMLHandler()
 
 
-def parse(text, **defaults):
+def parse(text, encoding='utf-8', **defaults):
     """
     Parse text with frontmatter, return metadata and content.
     Pass in optional metadata defaults as keyword args.
 
     If frontmatter is not found, returns an empty metadata dictionary
     (or defaults) and original text content.
+
+    ::
+
+        >>> with open('tests/hello-world.markdown') as f:
+        ...     metadata, content = frontmatter.parse(f.read())
+        >>> print(metadata['title'])
+        Hello, world!
+
     """
     # ensure unicode first
-    text = u(text).strip()
+    text = u(text, encoding).strip()
 
     # metadata starts with defaults
     metadata = defaults.copy()
@@ -76,44 +84,86 @@ def parse(text, **defaults):
     return metadata, content.strip()
 
 
-def load(fd, **defaults):
+def load(fd, encoding='utf-8', **defaults):
     """
-    Load and parse a file or filename, return a post.
+    Load and parse a file-like object or filename, 
+    return a :py:class:`post <frontmatter.Post>`.
+
+    ::
+
+        >>> post = frontmatter.load('tests/hello-world.markdown')
+        >>> with open('tests/hello-world.markdown') as f:
+        ...     post = frontmatter.load(f)
+
     """
     if hasattr(fd, 'read'):
         text = fd.read()
 
     else:
-        with codecs.open(fd, 'r', 'utf-8') as f:
+        with codecs.open(fd, 'r', encoding) as f:
             text = f.read()
 
-    return loads(text, **defaults)
+    return loads(text, encoding, **defaults)
 
 
-def loads(text, **defaults):
+def loads(text, encoding='utf-8', **defaults):
     """
-    Parse text and return a post.
+    Parse text (binary or unicode) and return a :py:class:`post <frontmatter.Post>`.
+
+    ::
+
+        >>> with open('tests/hello-world.markdown') as f:
+        ...     post = frontmatter.loads(f.read())
+
     """
-    metadata, content = parse(text, **defaults)
+    metadata, content = parse(text, encoding, **defaults)
     return Post(content, **metadata)
 
 
-def dump(post, fd, **kwargs):
+def dump(post, fd, encoding='utf-8', **kwargs):
     """
-    Serialize post to a string and dump to a file-like object.
+    Serialize :py:class:`post <frontmatter.Post>` to a string and write to a file-like object.
+    Text will be encoded on the way out (utf-8 by default).
+
+    ::
+
+        >>> from io import StringIO
+        >>> f = StringIO()
+        >>> frontmatter.dump(post, f)
+        >>> print(f.getvalue())
+        ---
+        excerpt: tl;dr
+        layout: post
+        title: Hello, world!
+        ---
+        Well, hello there, world.
+
+
     """
-    content = dumps(post, **kwargs)
+    content = dumps(post, **kwargs).encode(encoding)
     if hasattr(fd, 'write'):
         fd.write(content)
 
     else:
-        with codecs.open(fd, 'w', 'utf-8') as f:
+        with codecs.open(fd, 'w', encoding) as f:
             f.write(content)
 
 
 def dumps(post, **kwargs):
     """
-    Serialize post to a string and return text.
+    Serialize a :py:class:`post <frontmatter.Post>` to a string and return text. 
+    This always returns unicode text, which can then be encoded.
+
+    ::
+
+        >>> print(frontmatter.dumps(post))
+        ---
+        excerpt: tl;dr
+        layout: post
+        title: Hello, world!
+        ---
+        Well, hello there, world.
+
     """
     kwargs.setdefault('Dumper', SafeDumper)
     kwargs.setdefault('default_flow_style', False)

diff --git a/test.py b/test.py
index 07b2883..05fdb3c 100644
--- a/test.py
+++ b/test.py
@@ -44,7 +44,7 @@ class FrontmatterTest(unittest.TestCase):
 
     def test_unicode_post(self):
         "Ensure unicode is parsed correctly"
-        chinese = frontmatter.load('tests/chinese.txt')
+        chinese = frontmatter.load('tests/chinese.txt', 'utf-8')
 
         self.assertTrue(isinstance(chinese.content, six.text_type))
 
@@ -107,7 +107,7 @@ class FrontmatterTest(unittest.TestCase):
     def test_with_crlf_string(self):
         import codecs
         markdown_bytes = b'---\r\ntitle: "my title"\r\ncontent_type: "post"\r\npublished: no\r\n---\r\n\r\nwrite your content in markdown here'
-        loaded = frontmatter.loads(codecs.decode(markdown_bytes, 'utf-8'))
+        loaded = frontmatter.loads(markdown_bytes, 'utf-8')
         self.assertEqual(loaded['title'], 'my title')
 
     def test_dumping_with_custom_delimiters(self):

Allow user to pass in an encoding when loading and dumping
test.py::FrontmatterTest::test_unicode_post test.py::FrontmatterTest::test_with_crlf_string
test.py::FrontmatterTest::test_all_the_tests test.py::FrontmatterTest::test_custom_handler test.py::FrontmatterTest::test_dumping_with_custom_delimiters test.py::FrontmatterTest::test_empty_frontmatter test.py::FrontmatterTest::test_json test.py::FrontmatterTest::test_no_frontmatter test.py::FrontmatterTest::test_pretty_dumping test.py::FrontmatterTest::test_to_dict test.py::FrontmatterTest::test_to_string test.py::FrontmatterTest::test_toml test.py::FrontmatterTest::test_with_markdown_content