diff --git a/Text/Inflections.hs b/Text/Inflections.hs
--- a/Text/Inflections.hs
+++ b/Text/Inflections.hs
@@ -12,6 +12,62 @@
 "Inflections" library found in Rails:
 
 <http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html>
+
+While many of the functions in this library are the same as in implementations
+in Rails' ActiveSupport, the philosophy of this library is fundamentally
+different.  Where Rails tries to be as permissive as possible, and return a
+String when given any input, this library tries to output strings that make
+sense according to the function that is called.
+
+When you look closely at many of the functions in Rails' inflections
+library, you will notice that many of them are partial. That is, they only
+have well-defined output for some of the possible inputs to the function allowed
+by the type system. As an example, let's take the @underscore@ function. In
+Rails, it works like this:
+
+>>> "fooBar".underscore
+"foo_bar"
+
+Looks ok so far. However, it's also easy to produce less expected results:
+
+>>> "foo bar".underscore
+"foo bar"
+
+The output isn't underscored - it contains a space! It turns out that some of
+the functions from Inflections in ActiveSupport are /partial/. Ie., the outputs
+are really only specified for a certain range of the inputs allowed by the
+String type.
+
+In the Haskell inflections library, we aim to deliver more predictable results
+by separating the parsing of strings into tokens from the application of
+transformations. Let's see an example.
+
+First, we tokenize an underscored String using 'parseSnakeCase':
+
+>>> parseSnakeCase [] "foo_bar"
+Right [Word "foo",Word "bar"]
+
+We can chain together the tokenization of the input String and the
+transformation to CamelCase by using 'Control.Monad.LiftM':
+
+>>> import Control.Monad (liftM)
+>>> liftM camelize $ parseSnakeCase "foo_bar"
+
+By separating out the tokenization from the application of inflections, we also
+end up with useful libraries for validating input which can be used
+independently:
+
+>>> parseSnakeCase [] "fooBar"
+Left "(unknown)" (line 1, column 4):
+unexpected 'B'
+expecting lowercase letter, "_" or end of input
+
+This library is still a work-in-progress, and contributions are welcome for
+missing pieces and to fix bugs. Please see the Github page to contribute with
+code or bug reports:
+
+<https://github.com/stackbuilders/inflections-hs>
+
 -}
 
 module Text.Inflections
@@ -19,11 +75,13 @@
     , camelizeCustom
 
     , dasherize
-    , dasherizeCustom
 
+    , humanize
+
     , underscore
-    , underscoreCustom
 
+    , titleize
+
     , defaultMap
 
     , parameterize
@@ -34,41 +92,34 @@
 
     , ordinal
     , ordinalize
+
+    , parseSnakeCase
+    , parseCamelCase
+    , Transliterations
     )
 where
 
-import Data.Char (isAscii)
-import qualified Data.Map as Map
 
-import Text.Inflections.Data (defaultMap)
+import Text.Inflections.Data ( defaultMap )
 
 import Text.Inflections.Parameterize ( Transliterations
                                      , parameterize
                                      , parameterizeCustom )
 
-import Text.Inflections.Underscore ( underscore, underscoreCustom )
+import Text.Inflections.Underscore ( underscore )
 
 import Text.Inflections.Camelize ( camelize, camelizeCustom )
 
-import Text.Inflections.Dasherize ( dasherize, dasherizeCustom )
+import Text.Inflections.Humanize ( humanize )
 
+import Text.Inflections.Titleize ( titleize )
+
+import Text.Inflections.Transliterate ( transliterate, transliterateCustom )
+
+import Text.Inflections.Dasherize ( dasherize )
+
 import Text.Inflections.Ordinal ( ordinal, ordinalize )
 
--- |Returns a String after default approximations for changing Unicode characters
--- to a valid ASCII range are applied. If you want to supplement the default
--- approximations with your own, you should use the transliterateCustom
--- function instead of transliterate.
-transliterate :: String -> String
-transliterate = transliterateCustom "?" defaultMap
+import Text.Inflections.Parse.SnakeCase ( parseSnakeCase )
 
--- |Returns a String after default approximations for changing Unicode characters
--- to a valid ASCII range are applied.
-transliterateCustom :: String -> Transliterations -> String -> String
-transliterateCustom replacement ts = concatMap lookupCharTransliteration
-  where lookupCharTransliteration c =
-          if isAscii c then -- Don't bother looking up Chars in ASCII range
-            [c]
-          else
-            case Map.lookup c ts of
-              Nothing  -> replacement
-              Just val -> val
+import Text.Inflections.Parse.CamelCase ( parseCamelCase )
diff --git a/Text/Inflections/Camelize.hs b/Text/Inflections/Camelize.hs
--- a/Text/Inflections/Camelize.hs
+++ b/Text/Inflections/Camelize.hs
@@ -1,38 +1,29 @@
-module Text.Inflections.Camelize
-  ( camelize
-  , camelizeCustom )
-where
+module Text.Inflections.Camelize ( camelize, camelizeCustom ) where
 
-import Text.Inflections.Parse.SnakeCase (Word(..), parser)
-import Text.Parsec (ParseError, parse)
-import Data.Char (toUpper)
+import Text.Inflections.Parse.Types (Word(..))
 
--- |Turns a String in snake_case into CamelCase. Returns the CamelCase string,
--- or a ParseError if the input String is not in valid snake_case.
+import Data.Char (toUpper, toLower)
+
+-- |Turns a an input Word List in into CamelCase. Returns the CamelCase String.
 camelize
-  :: String -- ^ The input string, in snake_case
-  -> Either ParseError String
-camelize s = camelizeCustom [] True s
+  :: [Word] -- ^ Input Words to separate with underscores
+  -> String -- ^ The camelized String
+camelize ws = camelizeCustom True ws
 
--- |Turns an input String in snake_case into CamelCase. Returns the CamelCase
--- String, or a ParseError if the input String is not in valid snake_case.
--- Accepts arguments to control parsing and output format.
+-- |Turns an input Word List into a CamelCase String.
 camelizeCustom
-  :: [String] -- ^ A list of acronyms that will be kept whole and accepted as valid input
-  -> Bool     -- ^ Whether to capitalize the first character in the output String
-  -> String   -- ^ The input string, in snake_case
-  -> Either ParseError String
-camelizeCustom acronyms isFirstCap s =
-  case parse (parser acronyms) "(unknown)" s of
-    Left errs -> Left errs
-    Right res -> Right $ concatMap (caseForWord isFirstCap) $ isFirstList res
+  :: Bool   -- ^ Whether to capitalize the first character in the output String
+  -> [Word] -- ^ The input Words
+  -> String -- ^ The camelized String
+camelizeCustom isFirstCap = concatMap (caseForWord isFirstCap) . isFirstList
 
+
 caseForWord :: Bool -> (Word, Bool) -> String
-caseForWord True (Word (c:cs), True) = toUpper c : cs
-caseForWord False (Word s, True)     = s
-caseForWord _ (Word (c:cs), _)       = toUpper c : cs
-caseForWord _ (Word [], _)           = []
-caseForWord _ (Acronym s, _)         = s
+caseForWord True (Word (c:cs), True)  = toUpper c : cs
+caseForWord False (Word (c:cs), True) = toLower c : cs
+caseForWord _ (Word (c:cs), _)        = toUpper c : cs
+caseForWord _ (Word [], _)            = []
+caseForWord _ (Acronym s, _)          = s
 
 -- |Returns list with Bool indicating if an element is first.
 isFirstList :: [a] -> [(a, Bool)]
diff --git a/Text/Inflections/Dasherize.hs b/Text/Inflections/Dasherize.hs
--- a/Text/Inflections/Dasherize.hs
+++ b/Text/Inflections/Dasherize.hs
@@ -1,30 +1,14 @@
-module Text.Inflections.Dasherize
-  ( dasherize
-  , dasherizeCustom )
-where
+module Text.Inflections.Dasherize ( dasherize ) where
 
-import Text.Inflections.Parse.SnakeCase (Word(..), parser)
-import Text.Parsec (ParseError, parse)
+import Text.Inflections.Parse.Types (Word(..))
 
 import Data.List (intercalate)
 
 -- |Replaces underscores in a snake_cased string with dashes (hyphens).
 dasherize
-  :: String -- ^ The input string, in snake_case
-  -> Either ParseError String
-dasherize s = dasherizeCustom [] s
-
--- |Turns a snake_case string into dasherized form. Returns a ParseError if
--- the input string is not in proper snake_case.
-dasherizeCustom
-  :: [String] -- ^ A list of acronyms that will be kept whole and accepted as valid input
-  -> String   -- ^ The input string, in snake_case
-  -> Either ParseError String
-dasherizeCustom acronyms s =
-  case parse (parser acronyms) "(unknown)" s of
-    Left errs -> Left errs
-    Right res -> Right $ intercalate "-" $ map toString res
-
+  :: [Word] -- ^ Input Words to separate with dashes
+  -> String -- ^ The dasherized String
+dasherize ws = intercalate "-" $ map toString ws
 
 toString :: Word -> String
 toString (Acronym s) = s
diff --git a/Text/Inflections/Data.hs b/Text/Inflections/Data.hs
--- a/Text/Inflections/Data.hs
+++ b/Text/Inflections/Data.hs
@@ -2,8 +2,8 @@
 
 import Data.Map (Map, fromList)
 
--- |These default transliterations stolen from the Ruby i18n library -
--- https://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/transliterator.rb#L41:L69
+-- |These default transliterations stolen from the Ruby i18n library - see
+-- <https://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/transliterator.rb#L41:L69>.
 defaultMap :: Map Char String
 defaultMap = fromList [
   ('À', "A"), ('Á', "A"), ('Â', "A"), ('Ã', "A"), ('Ä', "A"), ('Å', "A"),
diff --git a/Text/Inflections/Humanize.hs b/Text/Inflections/Humanize.hs
new file mode 100644
--- /dev/null
+++ b/Text/Inflections/Humanize.hs
@@ -0,0 +1,23 @@
+module Text.Inflections.Humanize (humanize) where
+
+import Text.Inflections.Parse.Types (Word(..))
+
+import Data.List (intercalate)
+import Data.Char (toUpper)
+
+-- |Capitalizes the first word and turns underscores into spaces Like titleize,
+-- this is meant for creating pretty output.
+humanize
+  :: [Word] -- ^ List of Words, first of which will be capitalized
+  -> String -- ^ The humanized output
+humanize s = intercalate " " $ map caseForWord $ isFirstList s
+
+-- |Returns list with Bool indicating if an element is first.
+isFirstList :: [a] -> [(a, Bool)]
+isFirstList xs = zip xs $ True : repeat False
+
+caseForWord :: (Word, Bool) -> String
+caseForWord (Word (c:cs), True)  = toUpper c : cs
+caseForWord (Word s, False)      = s
+caseForWord (Word [], _)         = []
+caseForWord (Acronym s, _)       = s  -- Acronyms are left intact
diff --git a/Text/Inflections/Parameterize.hs b/Text/Inflections/Parameterize.hs
--- a/Text/Inflections/Parameterize.hs
+++ b/Text/Inflections/Parameterize.hs
@@ -18,8 +18,8 @@
                                               , parser
                                               , isValidParamChar )
 
--- |A Map containing mappings from international characters to sequences
--- approximating these characters within the ASCII range.
+-- |A 'Data.Map.Map' containing mappings from international characters to
+-- sequences approximating these characters within the ASCII range.
 type Transliterations = Map.Map Char String
 
 -- |Replaces special characters in a string so that it may be used as part of a
diff --git a/Text/Inflections/Parse/CamelCase.hs b/Text/Inflections/Parse/CamelCase.hs
--- a/Text/Inflections/Parse/CamelCase.hs
+++ b/Text/Inflections/Parse/CamelCase.hs
@@ -1,23 +1,26 @@
 {-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction #-}
 
-module Text.Inflections.Parse.CamelCase ( parser )
+module Text.Inflections.Parse.CamelCase ( parseCamelCase )
 where
 
-import qualified Text.ParserCombinators.Parsec.Char as C
-import qualified Text.Parsec as P
+import Text.Parsec
 
 import Text.Inflections.Parse.Types (Word(..))
 import Text.Inflections.Parse.Acronym (acronym)
 
+parseCamelCase :: [String] -> String -> Either ParseError [Word]
+parseCamelCase acronyms = parse (parser acronyms) "(unknown)"
+
+
 -- |Recognizes an input String in CamelCase.
-parser :: P.Stream s m Char => [String] -> P.ParsecT s u m [Word]
+parser :: Stream s m Char => [String] -> ParsecT s u m [Word]
 parser acronyms = do
-  ws <- P.many $ P.choice [ acronym acronyms, word ]
-  P.eof
+  ws <- many $ choice [ acronym acronyms, word ]
+  eof
   return ws
 
-word :: P.Stream s m Char => P.ParsecT s u m Word
+word :: Stream s m Char => ParsecT s u m Word
 word = do
-  firstChar <- C.upper P.<|> C.lower
-  restChars <- P.many C.lower
+  firstChar <- upper <|> lower
+  restChars <- many lower
   return $ Word $ firstChar : restChars
diff --git a/Text/Inflections/Parse/SnakeCase.hs b/Text/Inflections/Parse/SnakeCase.hs
--- a/Text/Inflections/Parse/SnakeCase.hs
+++ b/Text/Inflections/Parse/SnakeCase.hs
@@ -1,20 +1,23 @@
 {-# LANGUAGE FlexibleContexts, NoMonomorphismRestriction #-}
 
-module Text.Inflections.Parse.SnakeCase ( Word(..), parser )
+module Text.Inflections.Parse.SnakeCase ( parseSnakeCase )
 where
 
-import qualified Text.ParserCombinators.Parsec.Char as C
-import qualified Text.Parsec as P
 import Control.Applicative ((<$>))
+import Text.Parsec
 
 import Text.Inflections.Parse.Types (Word(..))
 import Text.Inflections.Parse.Acronym (acronym)
 
-word :: P.Stream s m Char => P.ParsecT s u m Word
-word = Word <$> P.many1 C.lower
+parseSnakeCase :: [String] -> String -> Either ParseError [Word]
+parseSnakeCase acronyms = parse (parser acronyms) "(unknown)"
 
-parser :: P.Stream s m Char => [String] -> P.ParsecT s u m [Word]
+
+parser :: Stream s m Char => [String] -> ParsecT s u m [Word]
 parser acronyms = do
-  ws <- (acronym acronyms P.<|> word) `P.sepBy` (C.char '_')
-  P.eof
+  ws <- (acronym acronyms <|> word) `sepBy` (char '_')
+  eof
   return ws
+
+word :: Stream s m Char => ParsecT s u m Word
+word = Word <$> ((many1 lower) <|> (many1 digit))
diff --git a/Text/Inflections/Parse/Types.hs b/Text/Inflections/Parse/Types.hs
--- a/Text/Inflections/Parse/Types.hs
+++ b/Text/Inflections/Parse/Types.hs
@@ -1,5 +1,12 @@
 module Text.Inflections.Parse.Types ( Word(..) ) where
 
-data Word = Word String
-          | Acronym String deriving (Show, Eq)
+-- |A 'String' that should be kept whole through applied inflections
+data Word
 
+    -- | A word that may be transformed by inflection
+    = Word String
+
+    -- | A word that may not be transformed by inflections
+    | Acronym String
+
+    deriving (Show, Eq)
diff --git a/Text/Inflections/Titleize.hs b/Text/Inflections/Titleize.hs
new file mode 100644
--- /dev/null
+++ b/Text/Inflections/Titleize.hs
@@ -0,0 +1,17 @@
+module Text.Inflections.Titleize (titleize) where
+
+import Text.Inflections.Parse.Types (Word(..))
+
+import Data.List (intercalate)
+import Data.Char (toUpper)
+
+-- |Capitalizes Capitalizes all the words.
+titleize
+  :: [Word] -- ^ List of Words, first of which will be capitalized
+  -> String -- ^ The titleized String
+titleize s = intercalate " " $ map upperCaseWord s
+
+upperCaseWord :: Word -> String
+upperCaseWord (Word (c:cs))  = toUpper c : cs
+upperCaseWord (Word [])      = []
+upperCaseWord (Acronym s)    = s  -- Acronyms are left intact
diff --git a/Text/Inflections/Transliterate.hs b/Text/Inflections/Transliterate.hs
new file mode 100644
--- /dev/null
+++ b/Text/Inflections/Transliterate.hs
@@ -0,0 +1,31 @@
+module Text.Inflections.Transliterate
+    ( transliterate
+    , transliterateCustom
+    )
+where
+
+import Text.Inflections.Parameterize ( Transliterations )
+import Text.Inflections.Data (defaultMap)
+
+import Data.Char (isAscii)
+
+import qualified Data.Map as Map
+
+-- |Returns a String after default approximations for changing Unicode characters
+-- to a valid ASCII range are applied. If you want to supplement the default
+-- approximations with your own, you should use the transliterateCustom
+-- function instead of transliterate.
+transliterate :: String -> String
+transliterate = transliterateCustom "?" defaultMap
+
+-- |Returns a String after default approximations for changing Unicode characters
+-- to a valid ASCII range are applied.
+transliterateCustom :: String -> Transliterations -> String -> String
+transliterateCustom replacement ts = concatMap lookupCharTransliteration
+  where lookupCharTransliteration c =
+          if isAscii c then -- Don't bother looking up Chars in ASCII range
+            [c]
+          else
+            case Map.lookup c ts of
+              Nothing  -> replacement
+              Just val -> val
diff --git a/Text/Inflections/Underscore.hs b/Text/Inflections/Underscore.hs
--- a/Text/Inflections/Underscore.hs
+++ b/Text/Inflections/Underscore.hs
@@ -1,31 +1,17 @@
-module Text.Inflections.Underscore (underscore, underscoreCustom) where
+module Text.Inflections.Underscore ( underscore ) where
 
-import Text.Inflections.Parse.CamelCase (parser)
 import Text.Inflections.Parse.Types (Word(..))
 
-import Text.Parsec (ParseError, parse)
 import Data.Char (toLower)
 import Data.List (intercalate)
 
 -- |Turns a CamelCase string into an underscore_separated String.
 underscore
-  :: String -- ^ A String in CamelCase
-  -> Either ParseError String
-underscore s = underscoreCustom [] s
-
--- |Changes an input String in CamelCase into a String of Words separated by
--- underscores. Accepts options for customization.
-underscoreCustom
-  :: [String] -- ^ A list of acronyms that will be kept whole and accepted as valid input
-  -> String -- ^ A String in CamelCase
-  -> Either ParseError String
-underscoreCustom acronyms s =
-  case parse (parser acronyms) "(unknown)" s of
-    Left errs -> Left errs
-    Right res -> Right $ intercalate "_" $ map toDowncasedString res
+  :: [Word] -- ^ Input Words to separate with underscores
+  -> String -- ^ The underscored String
+underscore ws = intercalate "_" $ map toDowncasedString ws
 
 
 toDowncasedString :: Word -> String
 toDowncasedString (Acronym s) = map toLower s
-toDowncasedString (Word s) = map toLower s
-
+toDowncasedString (Word s)    = map toLower s
diff --git a/inflections.cabal b/inflections.cabal
--- a/inflections.cabal
+++ b/inflections.cabal
@@ -1,5 +1,5 @@
 name:                inflections
-version:             0.1.0.5
+version:             0.1.0.6
 synopsis:            Inflections library for Haskell
 description:
   Inflections provides methods for singularization, pluralization,
@@ -21,20 +21,24 @@
 
 library
   exposed-modules:       Text.Inflections
+                       , Text.Inflections.Parse.Types
 
+
   other-modules:         Text.Inflections.Data
                        , Text.Inflections.Parameterize
+                       , Text.Inflections.Humanize
                        , Text.Inflections.Underscore
                        , Text.Inflections.Camelize
                        , Text.Inflections.Dasherize
                        , Text.Inflections.Ordinal
+                       , Text.Inflections.Titleize
+                       , Text.Inflections.Transliterate
 
                        , Text.Inflections.Parse.Acronym
-                       , Text.Inflections.Parse.SnakeCase
                        , Text.Inflections.Parse.Parameterizable
-                       , Text.Inflections.Parse.CamelCase
-                       , Text.Inflections.Parse.Types
 
+                       , Text.Inflections.Parse.SnakeCase
+                       , Text.Inflections.Parse.CamelCase
 
   ghc-options:         -Wall
   build-depends:       base >=4.5 && <4.7, parsec, containers
diff --git a/test/Suite.hs b/test/Suite.hs
--- a/test/Suite.hs
+++ b/test/Suite.hs
@@ -5,8 +5,12 @@
 import qualified Text.Inflections.Tests
 import qualified Text.Inflections.UnderscoreTest
 import qualified Text.Inflections.OrdinalTest
+import qualified Text.Inflections.HumanizeTest
+import qualified Text.Inflections.TitleizeTest
 
 main :: IO ()
 main = defaultMain $ Text.Inflections.Tests.tests ++
                      Text.Inflections.UnderscoreTest.tests ++
-                     Text.Inflections.OrdinalTest.tests
+                     Text.Inflections.OrdinalTest.tests ++
+                     Text.Inflections.HumanizeTest.tests ++
+                     Text.Inflections.TitleizeTest.tests
