diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+## 0.8.10
+
+Add the Data.Yaml.Include module
diff --git a/Data/Yaml.hs b/Data/Yaml.hs
--- a/Data/Yaml.hs
+++ b/Data/Yaml.hs
@@ -183,6 +183,7 @@
                     | AesonException String
                     | OtherParseException SomeException
                     | NonStringKeyAlias Y.AnchorName Value
+                    | CyclicIncludes
     deriving (Show, Typeable)
 instance Exception ParseException
 
diff --git a/Data/Yaml/Include.hs b/Data/Yaml/Include.hs
new file mode 100644
--- /dev/null
+++ b/Data/Yaml/Include.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE RankNTypes #-}
+module Data.Yaml.Include (decodeFile, decodeFileEither) where
+
+import Control.Applicative
+import Control.Monad (when)
+import Control.Exception (throwIO)
+import Control.Monad.IO.Class (liftIO)
+import Control.Monad.Trans.Resource (MonadResource)
+import System.Directory
+import System.FilePath
+import Data.Text (unpack)
+import Data.Text.Encoding (decodeUtf8)
+import Data.Aeson (FromJSON)
+import Data.Conduit
+import qualified Data.Conduit.List as CL
+import Data.Yaml (ParseException(..), decodeHelper)
+import Text.Libyaml hiding (decodeFile)
+import qualified Text.Libyaml as Y
+
+eventsFromFile
+    :: MonadResource m
+    => FilePath
+    -> Producer m Event
+eventsFromFile = go []
+  where
+    go :: MonadResource m => [FilePath] -> FilePath -> Producer m Event
+    go seen fp = do
+        cfp <- liftIO $ canonicalizePath fp
+        when (cfp `elem` seen) $ do
+            liftIO $ throwIO CyclicIncludes
+        Y.decodeFile cfp $= do
+            awaitForever $ \event -> case event of
+                EventScalar f (UriTag "!include") _ _ -> do
+                    let includeFile = takeDirectory cfp </> unpack (decodeUtf8 f)
+                    go (cfp : seen) includeFile $= CL.filter (`notElem` irrelevantEvents)
+                _ -> yield event
+
+    irrelevantEvents = [EventStreamStart, EventDocumentStart, EventDocumentEnd, EventStreamEnd]
+
+-- | Like `Data.Yaml.decodeFile` but with support for relative and absolute
+-- includes.
+--
+-- The syntax for includes follows the form:
+--
+-- > somekey: !include ./somefile.yaml
+decodeFile
+    :: FromJSON a
+    => FilePath
+    -> IO (Maybe a)
+decodeFile fp = decodeHelper (eventsFromFile fp) >>= either throwIO (return . either (const Nothing) id)
+
+-- | Like `Data.Yaml.decodeFileEither` but with support for relative and
+-- absolute includes.
+--
+-- The syntax for includes follows the form:
+--
+-- > somekey: !include ./somefile.yaml
+decodeFileEither
+    :: FromJSON a
+    => FilePath
+    -> IO (Either ParseException a)
+decodeFileEither fp = either Left (either (Left . AesonException) Right) <$> decodeHelper (eventsFromFile fp)
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
+## yaml
+
+Provides support for parsing and emitting Yaml documents.
+
+This package includes the [full libyaml C library version 0.1.5 by Kirill
+Simonov](http://pyyaml.org/wiki/LibYAML) in the package so you
+don't need to worry about any non-Haskell dependencies.
+
+The package is broken down into two primary modules.
+"Data.Yaml" provides a high-level interface based
+around the JSON datatypes provided by the @aeson@
+package. "Text.Libyaml" provides a lower-level,
+streaming interface. For most users, "Data.Yaml" is recommended.
+
+Additional modules:
+
+* Data.Yaml.Include supports adding `!include` directives to your YAML files.
+* DAta.Yaml.Builder and Data.Yaml.Parser allow more fine-grained control of parsing an rendering, as opposed to just using the aeson typeclass and datatype system for parsing and rendering.
+* Data.Yaml.Aeson is currently a re-export of Data.Yaml to explicitly choose to use the aeson-compatible API.
diff --git a/test/Data/Yaml/IncludeSpec.hs b/test/Data/Yaml/IncludeSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/Yaml/IncludeSpec.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE QuasiQuotes #-}
+module Data.Yaml.IncludeSpec (main, spec) where
+
+import           Test.Hspec
+import           Data.Aeson
+import           Data.Aeson.QQ
+
+import           Data.Yaml.Include
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+  describe "decodeFile" $ do
+    it "supports includes" $ do
+      decodeFile "test/resources/foo.yaml" `shouldReturn` Just [aesonQQ|
+        {
+          foo: 23,
+          bar: {one: 1, two: 2},
+          baz: 42
+        }
+      |]
+
+    it "supports recursive includes" $ do
+      decodeFile "test/resources/baz.yaml" `shouldReturn` Just [aesonQQ|
+      {
+        foo: {
+          foo: 23,
+          bar: {one: 1, two: 2},
+          baz: 42
+        }
+      }
+      |]
+
+    it "aborts on cyclic includes" $ do
+      (decodeFile "test/resources/loop/foo.yaml" :: IO (Maybe Value)) `shouldThrow` anyException
diff --git a/test/Data/YamlSpec.hs b/test/Data/YamlSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/YamlSpec.hs
@@ -0,0 +1,443 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE PackageImports #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Data.YamlSpec (main, spec) where
+
+import qualified Text.Libyaml as Y
+import qualified Data.ByteString.Char8 as B8
+
+import Test.HUnit hiding (Test, path)
+
+import qualified Data.Conduit as C
+import qualified Control.Monad.Trans.Resource as C
+import qualified Data.Conduit.List as CL
+
+import System.Directory
+import Control.Monad
+import Control.Exception (try, SomeException)
+import Test.Hspec
+
+import qualified Data.Yaml as D
+import Data.Yaml (object, array, (.=))
+import Data.Maybe
+import qualified Data.HashMap.Strict as M
+import qualified Data.Text as T
+import Data.Aeson.TH
+import Data.Text (Text)
+import Data.Vector (Vector)
+import qualified Data.Vector as V
+import Data.HashMap.Strict (HashMap)
+import qualified Data.HashMap.Strict as HM
+
+data TestJSON = TestJSON
+              { string :: Text
+              , number :: Int
+              , anArray  :: Vector Text
+              , hash   :: HashMap Text Text
+              , extrastring :: Text
+              } deriving (Show, Eq)
+
+deriveJSON defaultOptions ''TestJSON
+
+main :: IO ()
+main = hspec spec
+
+spec :: Spec
+spec = do
+    describe "streaming" $ do
+        it "count scalars with anchor" caseCountScalarsWithAnchor
+        it "count sequences with anchor" caseCountSequencesWithAnchor
+        it "count mappings with anchor" caseCountMappingsWithAnchor
+        it "count aliases" caseCountAliases
+        it "count scalars" caseCountScalars
+        it "largest string" caseLargestString
+        it "encode/decode" caseEncodeDecode
+        it "encode/decode file" caseEncodeDecodeFile
+        it "interleaved encode/decode" caseInterleave
+        it "decode invalid document (without segfault)" caseDecodeInvalidDocument
+    describe "Data.Yaml" $ do
+        it "encode/decode" caseEncodeDecodeData
+        it "encode/decode file" caseEncodeDecodeFileData
+        it "encode/decode strings" caseEncodeDecodeStrings
+        it "decode invalid file" caseDecodeInvalid
+        it "processes datatypes" caseDataTypes
+    describe "Data.Yaml aliases" $ do
+        it "simple scalar alias" caseSimpleScalarAlias
+        it "simple sequence alias" caseSimpleSequenceAlias
+        it "simple mapping alias" caseSimpleMappingAlias
+        it "mapping alias before anchor" caseMappingAliasBeforeAnchor
+        it "mapping alias inside anchor" caseMappingAliasInsideAnchor
+        it "scalar alias overriding" caseScalarAliasOverriding
+    describe "Data.Yaml merge keys" $ do
+        it "test uniqueness of keys" caseAllKeysShouldBeUnique
+        it "test mapping merge" caseSimpleMappingMerge
+        it "test sequence of mappings merging" caseMergeSequence
+    describe "numbers" $ do
+        it "parses as string when quoted" caseQuotedNumber
+        it "parses as number when unquoted" caseUnquotedNumber
+        it "parses as number !!str is present" caseAttribNumber
+        it "integers have no decimals" caseIntegerDecimals
+    describe "booleans" $ do
+        it "parses when all lowercase" caseLowercaseBool
+        it "parses when all uppercase" caseUppercaseBool
+        it "parses when titlecase" caseTitlecaseBool
+    describe "empty input" $ do
+        it "doesn't crash" caseEmptyInput
+    describe "alias stripping" $ do
+        it "works" caseStripAlias
+    describe "nulls" $ do
+        checkNull "null"
+        checkNull "Null"
+        checkNull "NULL"
+        checkNull "~"
+        checkNull ""
+
+    describe "pretty output" $ do
+        it "simple nulls" $ D.encode (object ["foo" .= D.Null]) `shouldBe` "foo: null\n"
+        it "simple numbers" $ D.encode (object ["foo" .= (4 :: Int)]) `shouldBe` "foo: 4\n"
+        it "True" $ D.encode (object ["foo" .= True]) `shouldBe` "foo: true\n"
+        it "False" $ D.encode (object ["foo" .= False]) `shouldBe` "foo: false\n"
+        it "simple string" $ D.encode (object ["foo" .= ("bar" :: T.Text)]) `shouldBe` "foo: bar\n"
+
+    describe "special keys" $ do
+        let tester key = it (T.unpack key) $
+                let value = object [key .= True]
+                 in D.decode (D.encode value) `shouldBe` Just value
+        mapM_ tester specialStrings
+
+    describe "special values" $ do
+        let tester value = it (T.unpack value) $
+                let value' = object ["foo" .= value]
+                 in D.decode (D.encode value') `shouldBe` Just value'
+        mapM_ tester specialStrings
+
+    describe "yamlFileJSONparse" $
+        it "loads YAML through JSON into Haskell data" $ do
+          tj <- either (error . show) id `fmap` D.decodeFileEither "test/json.yaml"
+          tj `shouldBe` TestJSON
+                          { string = "str"
+                          , number = 2
+                          , anArray = V.fromList ["a", "b"]
+                          , hash = HM.fromList [("key1", "value1"), ("key2", "value2")]
+                          , extrastring = "1234-foo"
+                          }
+
+    describe "round-tripping of special scalars" $ do
+        let special = words "y Y On ON false 12345 12345.0 12345a 12e3"
+        forM_ special $ \w -> it w $
+            let v = object ["word" .= w]
+             in D.decode (D.encode v) `shouldBe` Just v
+        it "no tags" $ D.encode (object ["word" .= ("true" :: String)]) `shouldBe` "word: 'true'\n"
+
+    it "aliases in keys #49" caseIssue49
+
+
+specialStrings :: [T.Text]
+specialStrings =
+    [ "fo\"o"
+    , "fo\'o"
+    , "fo\\'o"
+    , "fo: o"
+    , "foo\nbar\nbaz\n"
+    ]
+
+counter :: Monad m => (Y.Event -> Bool) -> C.Sink Y.Event m Int
+counter pred' =
+    CL.fold (\cnt e -> (if pred' e then 1 else 0) + cnt) 0
+
+caseHelper :: String
+           -> (Y.Event -> Bool)
+           -> Int
+           -> Assertion
+caseHelper yamlString pred' expRes = do
+    res <- C.runResourceT $ Y.decode (B8.pack yamlString) C.$$ counter pred'
+    res @?= expRes
+
+caseCountScalarsWithAnchor :: Assertion
+caseCountScalarsWithAnchor =
+    caseHelper yamlString isScalarA 1
+  where
+    yamlString = "foo:\n  - &anchor bin1\n  - bin2\n  - bin3"
+    isScalarA (Y.EventScalar _ _ _ (Just _)) = True
+    isScalarA _ = False
+
+caseCountSequencesWithAnchor :: Assertion
+caseCountSequencesWithAnchor =
+    caseHelper yamlString isSequenceStartA 1
+  where
+    yamlString = "foo: &anchor\n  - bin1\n  - bin2\n  - bin3"
+    isSequenceStartA (Y.EventSequenceStart (Just _)) = True
+    isSequenceStartA _ = False
+
+caseCountMappingsWithAnchor :: Assertion
+caseCountMappingsWithAnchor =
+    caseHelper yamlString isMappingA 1
+  where
+    yamlString = "foo: &anchor\n  key1: bin1\n  key2: bin2\n  key3: bin3"
+    isMappingA (Y.EventMappingStart (Just _)) = True
+    isMappingA _ = False
+
+caseCountAliases :: Assertion
+caseCountAliases =
+    caseHelper yamlString isAlias 1
+  where
+    yamlString = "foo: &anchor\n  key1: bin1\n  key2: bin2\n  key3: bin3\nboo: *anchor"
+    isAlias Y.EventAlias{} = True
+    isAlias _ = False
+
+caseCountScalars :: Assertion
+caseCountScalars = do
+    res <- C.runResourceT $ Y.decode yamlBS C.$$ CL.fold adder accum
+    res @?= (7, 1, 2)
+  where
+    yamlString = "foo:\n  baz: [bin1, bin2, bin3]\nbaz: bazval"
+    yamlBS = B8.pack yamlString
+    adder (s, l, m) (Y.EventScalar{})        = (s + 1, l, m)
+    adder (s, l, m) (Y.EventSequenceStart{}) = (s, l + 1, m)
+    adder (s, l, m) (Y.EventMappingStart{})  = (s, l, m + 1)
+    adder a         _                      = a
+    accum = (0, 0, 0) :: (Int, Int, Int)
+
+caseLargestString :: Assertion
+caseLargestString = do
+    res <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.fold adder accum
+    res @?= (length expected, expected)
+    where
+        expected = "this one is just a little bit bigger than the others"
+        filePath = "test/largest-string.yaml"
+        adder (i, s) (Y.EventScalar bs _ _ _) =
+            let s' = B8.unpack bs
+                i' = length s'
+             in if i' > i then (i', s') else (i, s)
+        adder acc _ = acc
+        accum = (0, "no strings found")
+
+newtype MyEvent = MyEvent Y.Event deriving Show
+instance Eq MyEvent where
+    (MyEvent (Y.EventScalar s t _ _)) == (MyEvent (Y.EventScalar s' t' _ _)) =
+        s == s' && t == t'
+    MyEvent e1 == MyEvent e2 = e1 == e2
+
+caseEncodeDecode :: Assertion
+caseEncodeDecode = do
+    eList <- C.runResourceT $ Y.decode yamlBS C.$$ CL.consume
+    bs <- C.runResourceT $ CL.sourceList eList C.$$ Y.encode
+    eList2 <- C.runResourceT $ Y.decode bs C.$$ CL.consume
+    map MyEvent eList @=? map MyEvent eList2
+  where
+    yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
+    yamlBS = B8.pack yamlString
+
+removeFile' :: FilePath -> IO ()
+removeFile' fp = do
+    x <- doesFileExist fp
+    when x $ removeFile fp
+
+caseEncodeDecodeFile :: Assertion
+caseEncodeDecodeFile = do
+    removeFile' tmpPath
+    eList <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
+    C.runResourceT $ CL.sourceList eList C.$$ Y.encodeFile tmpPath
+    eList2 <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
+    map MyEvent eList @=? map MyEvent eList2
+  where
+    filePath = "test/largest-string.yaml"
+    tmpPath = "tmp.yaml"
+
+caseInterleave :: Assertion
+caseInterleave = do
+    removeFile' tmpPath
+    removeFile' tmpPath2
+    () <- C.runResourceT $ Y.decodeFile filePath C.$$ Y.encodeFile tmpPath
+    () <- C.runResourceT $ Y.decodeFile tmpPath C.$$ Y.encodeFile tmpPath2
+    f1 <- readFile tmpPath
+    f2 <- readFile tmpPath2
+    f1 @=? f2
+  where
+    filePath = "test/largest-string.yaml"
+    tmpPath = "tmp.yaml"
+    tmpPath2 = "tmp2.yaml"
+
+caseDecodeInvalidDocument :: Assertion
+caseDecodeInvalidDocument = do
+    x <- try $ C.runResourceT $ Y.decode yamlBS C.$$ CL.sinkNull
+    case x of
+        Left (_ :: SomeException) -> return ()
+        Right y -> do
+            putStrLn $ "bad return value: " ++ show y
+            assertFailure "expected parsing exception, but got no errors"
+  where
+    yamlString = "  - foo\n  - baz\nbuz"
+    yamlBS = B8.pack yamlString
+
+mkScalar :: String -> D.Value
+mkScalar = mkStrScalar
+
+mkStrScalar :: String -> D.Value
+mkStrScalar = D.String . T.pack
+
+mappingKey :: D.Value-> String -> D.Value
+mappingKey (D.Object m) k = (fromJust . M.lookup (T.pack k) $ m)
+mappingKey _ _ = error "expected Object"
+
+decodeYaml :: String -> Maybe D.Value
+decodeYaml s = D.decode $ B8.pack s
+
+sample :: D.Value
+sample = array
+    [ D.String "foo"
+    , object
+        [ ("bar1", D.String "bar2")
+        , ("bar3", D.String "")
+        ]
+    , D.String ""
+    ]
+
+caseEncodeDecodeData :: Assertion
+caseEncodeDecodeData = do
+    let out = D.decode $ D.encode sample
+    out @?= Just sample
+
+caseEncodeDecodeFileData :: Assertion
+caseEncodeDecodeFileData = do
+    let fp = "tmp.yaml"
+    D.encodeFile fp sample
+    out <- D.decodeFile fp
+    out @?= Just sample
+
+caseEncodeDecodeStrings :: Assertion
+caseEncodeDecodeStrings = do
+    let out = D.decode $ D.encode sample
+    out @?= Just sample
+
+caseDecodeInvalid :: Assertion
+caseDecodeInvalid = do
+    let invalid = B8.pack "\tthis is 'not' valid :-)"
+    Nothing @=? (D.decode invalid :: Maybe D.Value)
+
+caseSimpleScalarAlias :: Assertion
+caseSimpleScalarAlias = do
+    let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch"
+    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
+    let res = fromJust maybeRes
+    res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo")]
+
+caseSimpleSequenceAlias :: Assertion
+caseSimpleSequenceAlias = do
+    let maybeRes = decodeYaml "seq: &anch\n  - foo\n  - baz\nseq2: *anch"
+    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
+    let res = fromJust maybeRes
+    res @?= object [("seq", array [(mkScalar "foo"), (mkScalar "baz")]), ("seq2", array [(mkScalar "foo"), (mkScalar "baz")])]
+
+caseSimpleMappingAlias :: Assertion
+caseSimpleMappingAlias = do
+    let maybeRes = decodeYaml "map: &anch\n  key1: foo\n  key2: baz\nmap2: *anch"
+    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
+    let res = fromJust maybeRes
+    res @?= object [(T.pack "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (T.pack "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]
+
+caseMappingAliasBeforeAnchor :: Assertion
+caseMappingAliasBeforeAnchor = do
+    let res = decodeYaml "map: *anch\nmap2: &anch\n  key1: foo\n  key2: baz"
+    isNothing res @? "decode should return Nothing due to unknown alias"
+
+caseMappingAliasInsideAnchor :: Assertion
+caseMappingAliasInsideAnchor = do
+    let res = decodeYaml "map: &anch\n  key1: foo\n  key2: *anch"
+    isNothing res @? "decode should return Nothing due to unknown alias"
+
+caseScalarAliasOverriding :: Assertion
+caseScalarAliasOverriding = do
+    let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch"
+    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
+    let res = fromJust maybeRes
+    res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo"), (mkScalar "boo"), (mkScalar "buz"), (mkScalar "boo")]
+
+caseAllKeysShouldBeUnique :: Assertion
+caseAllKeysShouldBeUnique = do
+    let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\nfoo1: buz"
+    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
+    let res = fromJust maybeRes
+    mappingKey res "foo1" @?= (mkScalar "buz")
+
+caseSimpleMappingMerge :: Assertion
+caseSimpleMappingMerge = do
+    let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\n<<:\n  foo1: buz\n  foo3: fuz"
+    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
+    let res = fromJust maybeRes
+    mappingKey res "foo1" @?= (mkScalar "foo")
+    mappingKey res "foo3" @?= (mkScalar "fuz")
+
+caseMergeSequence :: Assertion
+caseMergeSequence = do
+    let maybeRes = decodeYaml "m1: &m1\n  k1: !!str 1\n  k2: !!str 2\nm2: &m2\n  k1: !!str 3\n  k3: !!str 4\nfoo1: foo\n<<: [ *m1, *m2 ]"
+    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
+    let res = fromJust maybeRes
+    mappingKey res "foo1" @?= (mkScalar "foo")
+    mappingKey res "k1" @?= (D.String "1")
+    mappingKey res "k2" @?= (D.String "2")
+    mappingKey res "k3" @?= (D.String "4")
+
+caseDataTypes :: Assertion
+caseDataTypes =
+    D.decode (D.encode val) @?= Just val
+  where
+    val = object
+        [ ("string", D.String "foo")
+        , ("int", D.Number 5)
+        , ("float", D.Number 4.3)
+        , ("true", D.Bool True)
+        , ("false", D.Bool False)
+        , ("null", D.Null)
+        ]
+
+caseQuotedNumber, caseUnquotedNumber, caseAttribNumber, caseIntegerDecimals :: Assertion
+caseQuotedNumber = D.decode "foo: \"1234\"" @?= Just (object [("foo", D.String "1234")])
+caseUnquotedNumber = D.decode "foo: 1234" @?= Just (object [("foo", D.Number 1234)])
+caseAttribNumber = D.decode "foo: !!str 1234" @?= Just (object [("foo", D.String "1234")])
+caseIntegerDecimals = D.encode (1 :: Int) @?= "1\n...\n"
+
+obj :: Maybe D.Value
+obj = Just (object [("foo", D.Bool False), ("bar", D.Bool True), ("baz", D.Bool True)])
+
+caseLowercaseBool, caseUppercaseBool, caseTitlecaseBool :: Assertion
+caseLowercaseBool = D.decode "foo: off\nbar: y\nbaz: true" @?= obj
+caseUppercaseBool = D.decode "foo: FALSE\nbar: Y\nbaz: ON" @?= obj
+caseTitlecaseBool = D.decode "foo: No\nbar: Yes\nbaz: True" @?= obj
+
+caseEmptyInput :: Assertion
+caseEmptyInput = D.decode B8.empty @?= (Nothing :: Maybe D.Value)
+
+checkNull :: T.Text -> Spec
+checkNull x =
+    it ("null recognized: " ++ show x) assertion
+  where
+    assertion = Just (object [("foo", D.Null)]) @=? D.decode (B8.pack $ "foo: " ++ T.unpack x)
+
+caseStripAlias :: Assertion
+caseStripAlias =
+    D.decode src @?= Just (object
+        [ "Default" .= object
+            [ "foo" .= (1 :: Int)
+            , "bar" .= (2 :: Int)
+            ]
+        , "Obj" .= object
+            [ "foo" .= (1 :: Int)
+            , "bar" .= (2 :: Int)
+            , "key" .= (3 :: Int)
+            ]
+        ])
+  where
+    src = "Default: &def\n  foo: 1\n  bar: 2\nObj:\n  <<: *def\n  key: 3\n"
+
+caseIssue49 :: Assertion
+caseIssue49 =
+    D.decodeEither src @?= Right (object
+        [ "a" .= object [ "value" .= (1.0 :: Double) ]
+        , "b" .= object [ "value" .= (1.2 :: Double) ]
+        ])
+  where
+    src = "---\na:\n  &id5 value: 1.0\nb:\n  *id5: 1.2"
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/test/main.hs b/test/main.hs
deleted file mode 100644
--- a/test/main.hs
+++ /dev/null
@@ -1,438 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE PackageImports #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE TemplateHaskell #-}
-
-import qualified Text.Libyaml as Y
-import qualified Data.ByteString.Char8 as B8
-
-import Test.HUnit hiding (Test, path)
-
-import qualified Data.Conduit as C
-import qualified Control.Monad.Trans.Resource as C
-import qualified Data.Conduit.List as CL
-
-import System.Directory
-import Control.Monad
-import Control.Exception (try, SomeException)
-import Test.Hspec
-
-import qualified Data.Yaml as D
-import Data.Yaml (object, array, (.=))
-import Data.Maybe
-import qualified Data.HashMap.Strict as M
-import qualified Data.Text as T
-import Data.Aeson.TH
-import Data.Text (Text)
-import Data.Vector (Vector)
-import qualified Data.Vector as V
-import Data.HashMap.Strict (HashMap)
-import qualified Data.HashMap.Strict as HM
-
-data TestJSON = TestJSON
-              { string :: Text
-              , number :: Int
-              , anArray  :: Vector Text
-              , hash   :: HashMap Text Text
-              , extrastring :: Text
-              } deriving (Show, Eq)
-
-deriveJSON defaultOptions ''TestJSON
-
-main :: IO ()
-main = hspec $ do
-    describe "streaming" $ do
-        it "count scalars with anchor" caseCountScalarsWithAnchor
-        it "count sequences with anchor" caseCountSequencesWithAnchor
-        it "count mappings with anchor" caseCountMappingsWithAnchor
-        it "count aliases" caseCountAliases
-        it "count scalars" caseCountScalars
-        it "largest string" caseLargestString
-        it "encode/decode" caseEncodeDecode
-        it "encode/decode file" caseEncodeDecodeFile
-        it "interleaved encode/decode" caseInterleave
-        it "decode invalid document (without segfault)" caseDecodeInvalidDocument
-    describe "Data.Yaml" $ do
-        it "encode/decode" caseEncodeDecodeData
-        it "encode/decode file" caseEncodeDecodeFileData
-        it "encode/decode strings" caseEncodeDecodeStrings
-        it "decode invalid file" caseDecodeInvalid
-        it "processes datatypes" caseDataTypes
-    describe "Data.Yaml aliases" $ do
-        it "simple scalar alias" caseSimpleScalarAlias
-        it "simple sequence alias" caseSimpleSequenceAlias
-        it "simple mapping alias" caseSimpleMappingAlias
-        it "mapping alias before anchor" caseMappingAliasBeforeAnchor
-        it "mapping alias inside anchor" caseMappingAliasInsideAnchor
-        it "scalar alias overriding" caseScalarAliasOverriding
-    describe "Data.Yaml merge keys" $ do
-        it "test uniqueness of keys" caseAllKeysShouldBeUnique
-        it "test mapping merge" caseSimpleMappingMerge
-        it "test sequence of mappings merging" caseMergeSequence
-    describe "numbers" $ do
-        it "parses as string when quoted" caseQuotedNumber
-        it "parses as number when unquoted" caseUnquotedNumber
-        it "parses as number !!str is present" caseAttribNumber
-        it "integers have no decimals" caseIntegerDecimals
-    describe "booleans" $ do
-        it "parses when all lowercase" caseLowercaseBool
-        it "parses when all uppercase" caseUppercaseBool
-        it "parses when titlecase" caseTitlecaseBool
-    describe "empty input" $ do
-        it "doesn't crash" caseEmptyInput
-    describe "alias stripping" $ do
-        it "works" caseStripAlias
-    describe "nulls" $ do
-        checkNull "null"
-        checkNull "Null"
-        checkNull "NULL"
-        checkNull "~"
-        checkNull ""
-
-    describe "pretty output" $ do
-        it "simple nulls" $ D.encode (object ["foo" .= D.Null]) `shouldBe` "foo: null\n"
-        it "simple numbers" $ D.encode (object ["foo" .= (4 :: Int)]) `shouldBe` "foo: 4\n"
-        it "True" $ D.encode (object ["foo" .= True]) `shouldBe` "foo: true\n"
-        it "False" $ D.encode (object ["foo" .= False]) `shouldBe` "foo: false\n"
-        it "simple string" $ D.encode (object ["foo" .= ("bar" :: T.Text)]) `shouldBe` "foo: bar\n"
-
-    describe "special keys" $ do
-        let tester key = it (T.unpack key) $
-                let value = object [key .= True]
-                 in D.decode (D.encode value) `shouldBe` Just value
-        mapM_ tester specialStrings
-
-    describe "special values" $ do
-        let tester value = it (T.unpack value) $
-                let value' = object ["foo" .= value]
-                 in D.decode (D.encode value') `shouldBe` Just value'
-        mapM_ tester specialStrings
-
-    describe "yamlFileJSONparse" $
-        it "loads YAML through JSON into Haskell data" $ do
-          tj <- either (error . show) id `fmap` D.decodeFileEither "test/json.yaml"
-          tj `shouldBe` TestJSON
-                          { string = "str"
-                          , number = 2
-                          , anArray = V.fromList ["a", "b"]
-                          , hash = HM.fromList [("key1", "value1"), ("key2", "value2")]
-                          , extrastring = "1234-foo"
-                          }
-
-    describe "round-tripping of special scalars" $ do
-        let special = words "y Y On ON false 12345 12345.0 12345a 12e3"
-        forM_ special $ \w -> it w $
-            let v = object ["word" .= w]
-             in D.decode (D.encode v) `shouldBe` Just v
-        it "no tags" $ D.encode (object ["word" .= ("true" :: String)]) `shouldBe` "word: 'true'\n"
-
-    it "aliases in keys #49" caseIssue49
-
-
-specialStrings :: [T.Text]
-specialStrings =
-    [ "fo\"o"
-    , "fo\'o"
-    , "fo\\'o"
-    , "fo: o"
-    , "foo\nbar\nbaz\n"
-    ]
-
-counter :: Monad m => (Y.Event -> Bool) -> C.Sink Y.Event m Int
-counter pred' =
-    CL.fold (\cnt e -> (if pred' e then 1 else 0) + cnt) 0
-
-caseHelper :: String
-           -> (Y.Event -> Bool)
-           -> Int
-           -> Assertion
-caseHelper yamlString pred' expRes = do
-    res <- C.runResourceT $ Y.decode (B8.pack yamlString) C.$$ counter pred'
-    res @?= expRes
-
-caseCountScalarsWithAnchor :: Assertion
-caseCountScalarsWithAnchor =
-    caseHelper yamlString isScalarA 1
-  where
-    yamlString = "foo:\n  - &anchor bin1\n  - bin2\n  - bin3"
-    isScalarA (Y.EventScalar _ _ _ (Just _)) = True
-    isScalarA _ = False
-
-caseCountSequencesWithAnchor :: Assertion
-caseCountSequencesWithAnchor =
-    caseHelper yamlString isSequenceStartA 1
-  where
-    yamlString = "foo: &anchor\n  - bin1\n  - bin2\n  - bin3"
-    isSequenceStartA (Y.EventSequenceStart (Just _)) = True
-    isSequenceStartA _ = False
-
-caseCountMappingsWithAnchor :: Assertion
-caseCountMappingsWithAnchor =
-    caseHelper yamlString isMappingA 1
-  where
-    yamlString = "foo: &anchor\n  key1: bin1\n  key2: bin2\n  key3: bin3"
-    isMappingA (Y.EventMappingStart (Just _)) = True
-    isMappingA _ = False
-
-caseCountAliases :: Assertion
-caseCountAliases =
-    caseHelper yamlString isAlias 1
-  where
-    yamlString = "foo: &anchor\n  key1: bin1\n  key2: bin2\n  key3: bin3\nboo: *anchor"
-    isAlias Y.EventAlias{} = True
-    isAlias _ = False
-
-caseCountScalars :: Assertion
-caseCountScalars = do
-    res <- C.runResourceT $ Y.decode yamlBS C.$$ CL.fold adder accum
-    res @?= (7, 1, 2)
-  where
-    yamlString = "foo:\n  baz: [bin1, bin2, bin3]\nbaz: bazval"
-    yamlBS = B8.pack yamlString
-    adder (s, l, m) (Y.EventScalar{})        = (s + 1, l, m)
-    adder (s, l, m) (Y.EventSequenceStart{}) = (s, l + 1, m)
-    adder (s, l, m) (Y.EventMappingStart{})  = (s, l, m + 1)
-    adder a         _                      = a
-    accum = (0, 0, 0) :: (Int, Int, Int)
-
-caseLargestString :: Assertion
-caseLargestString = do
-    res <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.fold adder accum
-    res @?= (length expected, expected)
-    where
-        expected = "this one is just a little bit bigger than the others"
-        filePath = "test/largest-string.yaml"
-        adder (i, s) (Y.EventScalar bs _ _ _) =
-            let s' = B8.unpack bs
-                i' = length s'
-             in if i' > i then (i', s') else (i, s)
-        adder acc _ = acc
-        accum = (0, "no strings found")
-
-newtype MyEvent = MyEvent Y.Event deriving Show
-instance Eq MyEvent where
-    (MyEvent (Y.EventScalar s t _ _)) == (MyEvent (Y.EventScalar s' t' _ _)) =
-        s == s' && t == t'
-    MyEvent e1 == MyEvent e2 = e1 == e2
-
-caseEncodeDecode :: Assertion
-caseEncodeDecode = do
-    eList <- C.runResourceT $ Y.decode yamlBS C.$$ CL.consume
-    bs <- C.runResourceT $ CL.sourceList eList C.$$ Y.encode
-    eList2 <- C.runResourceT $ Y.decode bs C.$$ CL.consume
-    map MyEvent eList @=? map MyEvent eList2
-  where
-    yamlString = "foo: bar\nbaz:\n - bin1\n - bin2\n"
-    yamlBS = B8.pack yamlString
-
-removeFile' :: FilePath -> IO ()
-removeFile' fp = do
-    x <- doesFileExist fp
-    when x $ removeFile fp
-
-caseEncodeDecodeFile :: Assertion
-caseEncodeDecodeFile = do
-    removeFile' tmpPath
-    eList <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
-    C.runResourceT $ CL.sourceList eList C.$$ Y.encodeFile tmpPath
-    eList2 <- C.runResourceT $ Y.decodeFile filePath C.$$ CL.consume
-    map MyEvent eList @=? map MyEvent eList2
-  where
-    filePath = "test/largest-string.yaml"
-    tmpPath = "tmp.yaml"
-
-caseInterleave :: Assertion
-caseInterleave = do
-    removeFile' tmpPath
-    removeFile' tmpPath2
-    () <- C.runResourceT $ Y.decodeFile filePath C.$$ Y.encodeFile tmpPath
-    () <- C.runResourceT $ Y.decodeFile tmpPath C.$$ Y.encodeFile tmpPath2
-    f1 <- readFile tmpPath
-    f2 <- readFile tmpPath2
-    f1 @=? f2
-  where
-    filePath = "test/largest-string.yaml"
-    tmpPath = "tmp.yaml"
-    tmpPath2 = "tmp2.yaml"
-
-caseDecodeInvalidDocument :: Assertion
-caseDecodeInvalidDocument = do
-    x <- try $ C.runResourceT $ Y.decode yamlBS C.$$ CL.sinkNull
-    case x of
-        Left (_ :: SomeException) -> return ()
-        Right y -> do
-            putStrLn $ "bad return value: " ++ show y
-            assertFailure "expected parsing exception, but got no errors"
-  where
-    yamlString = "  - foo\n  - baz\nbuz"
-    yamlBS = B8.pack yamlString
-
-mkScalar :: String -> D.Value
-mkScalar = mkStrScalar
-
-mkStrScalar :: String -> D.Value
-mkStrScalar = D.String . T.pack
-
-mappingKey :: D.Value-> String -> D.Value
-mappingKey (D.Object m) k = (fromJust . M.lookup (T.pack k) $ m)
-mappingKey _ _ = error "expected Object"
-
-decodeYaml :: String -> Maybe D.Value
-decodeYaml s = D.decode $ B8.pack s
-
-sample :: D.Value
-sample = array
-    [ D.String "foo"
-    , object
-        [ ("bar1", D.String "bar2")
-        , ("bar3", D.String "")
-        ]
-    , D.String ""
-    ]
-
-caseEncodeDecodeData :: Assertion
-caseEncodeDecodeData = do
-    let out = D.decode $ D.encode sample
-    out @?= Just sample
-
-caseEncodeDecodeFileData :: Assertion
-caseEncodeDecodeFileData = do
-    let fp = "tmp.yaml"
-    D.encodeFile fp sample
-    out <- D.decodeFile fp
-    out @?= Just sample
-
-caseEncodeDecodeStrings :: Assertion
-caseEncodeDecodeStrings = do
-    let out = D.decode $ D.encode sample
-    out @?= Just sample
-
-caseDecodeInvalid :: Assertion
-caseDecodeInvalid = do
-    let invalid = B8.pack "\tthis is 'not' valid :-)"
-    Nothing @=? (D.decode invalid :: Maybe D.Value)
-
-caseSimpleScalarAlias :: Assertion
-caseSimpleScalarAlias = do
-    let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch"
-    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
-    let res = fromJust maybeRes
-    res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo")]
-
-caseSimpleSequenceAlias :: Assertion
-caseSimpleSequenceAlias = do
-    let maybeRes = decodeYaml "seq: &anch\n  - foo\n  - baz\nseq2: *anch"
-    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
-    let res = fromJust maybeRes
-    res @?= object [("seq", array [(mkScalar "foo"), (mkScalar "baz")]), ("seq2", array [(mkScalar "foo"), (mkScalar "baz")])]
-
-caseSimpleMappingAlias :: Assertion
-caseSimpleMappingAlias = do
-    let maybeRes = decodeYaml "map: &anch\n  key1: foo\n  key2: baz\nmap2: *anch"
-    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
-    let res = fromJust maybeRes
-    res @?= object [(T.pack "map", object [("key1", mkScalar "foo"), ("key2", (mkScalar "baz"))]), (T.pack "map2", object [("key1", (mkScalar "foo")), ("key2", mkScalar "baz")])]
-
-caseMappingAliasBeforeAnchor :: Assertion
-caseMappingAliasBeforeAnchor = do
-    let res = decodeYaml "map: *anch\nmap2: &anch\n  key1: foo\n  key2: baz"
-    isNothing res @? "decode should return Nothing due to unknown alias"
-
-caseMappingAliasInsideAnchor :: Assertion
-caseMappingAliasInsideAnchor = do
-    let res = decodeYaml "map: &anch\n  key1: foo\n  key2: *anch"
-    isNothing res @? "decode should return Nothing due to unknown alias"
-
-caseScalarAliasOverriding :: Assertion
-caseScalarAliasOverriding = do
-    let maybeRes = decodeYaml "- &anch foo\n- baz\n- *anch\n- &anch boo\n- buz\n- *anch"
-    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
-    let res = fromJust maybeRes
-    res @?= array [(mkScalar "foo"), (mkScalar "baz"), (mkScalar "foo"), (mkScalar "boo"), (mkScalar "buz"), (mkScalar "boo")]
-
-caseAllKeysShouldBeUnique :: Assertion
-caseAllKeysShouldBeUnique = do
-    let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\nfoo1: buz"
-    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
-    let res = fromJust maybeRes
-    mappingKey res "foo1" @?= (mkScalar "buz")
-
-caseSimpleMappingMerge :: Assertion
-caseSimpleMappingMerge = do
-    let maybeRes = decodeYaml "foo1: foo\nfoo2: baz\n<<:\n  foo1: buz\n  foo3: fuz"
-    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
-    let res = fromJust maybeRes
-    mappingKey res "foo1" @?= (mkScalar "foo")
-    mappingKey res "foo3" @?= (mkScalar "fuz")
-
-caseMergeSequence :: Assertion
-caseMergeSequence = do
-    let maybeRes = decodeYaml "m1: &m1\n  k1: !!str 1\n  k2: !!str 2\nm2: &m2\n  k1: !!str 3\n  k3: !!str 4\nfoo1: foo\n<<: [ *m1, *m2 ]"
-    isJust maybeRes @? "decoder should return Just YamlObject but returned Nothing"
-    let res = fromJust maybeRes
-    mappingKey res "foo1" @?= (mkScalar "foo")
-    mappingKey res "k1" @?= (D.String "1")
-    mappingKey res "k2" @?= (D.String "2")
-    mappingKey res "k3" @?= (D.String "4")
-
-caseDataTypes :: Assertion
-caseDataTypes =
-    D.decode (D.encode val) @?= Just val
-  where
-    val = object
-        [ ("string", D.String "foo")
-        , ("int", D.Number 5)
-        , ("float", D.Number 4.3)
-        , ("true", D.Bool True)
-        , ("false", D.Bool False)
-        , ("null", D.Null)
-        ]
-
-caseQuotedNumber, caseUnquotedNumber, caseAttribNumber, caseIntegerDecimals :: Assertion
-caseQuotedNumber = D.decode "foo: \"1234\"" @?= Just (object [("foo", D.String "1234")])
-caseUnquotedNumber = D.decode "foo: 1234" @?= Just (object [("foo", D.Number 1234)])
-caseAttribNumber = D.decode "foo: !!str 1234" @?= Just (object [("foo", D.String "1234")])
-caseIntegerDecimals = D.encode (1 :: Int) @?= "1\n...\n"
-
-obj :: Maybe D.Value
-obj = Just (object [("foo", D.Bool False), ("bar", D.Bool True), ("baz", D.Bool True)])
-
-caseLowercaseBool, caseUppercaseBool, caseTitlecaseBool :: Assertion
-caseLowercaseBool = D.decode "foo: off\nbar: y\nbaz: true" @?= obj
-caseUppercaseBool = D.decode "foo: FALSE\nbar: Y\nbaz: ON" @?= obj
-caseTitlecaseBool = D.decode "foo: No\nbar: Yes\nbaz: True" @?= obj
-
-caseEmptyInput :: Assertion
-caseEmptyInput = D.decode B8.empty @?= (Nothing :: Maybe D.Value)
-
-checkNull :: T.Text -> Spec
-checkNull x =
-    it ("null recognized: " ++ show x) assertion
-  where
-    assertion = Just (object [("foo", D.Null)]) @=? D.decode (B8.pack $ "foo: " ++ T.unpack x)
-
-caseStripAlias :: Assertion
-caseStripAlias =
-    D.decode src @?= Just (object
-        [ "Default" .= object
-            [ "foo" .= (1 :: Int)
-            , "bar" .= (2 :: Int)
-            ]
-        , "Obj" .= object
-            [ "foo" .= (1 :: Int)
-            , "bar" .= (2 :: Int)
-            , "key" .= (3 :: Int)
-            ]
-        ])
-  where
-    src = "Default: &def\n  foo: 1\n  bar: 2\nObj:\n  <<: *def\n  key: 3\n"
-
-caseIssue49 :: Assertion
-caseIssue49 =
-    D.decodeEither src @?= Right (object
-        [ "a" .= object [ "value" .= (1.0 :: Double) ]
-        , "b" .= object [ "value" .= (1.2 :: Double) ]
-        ])
-  where
-    src = "---\na:\n  &id5 value: 1.0\nb:\n  *id5: 1.2"
diff --git a/test/resources/bar.yaml b/test/resources/bar.yaml
new file mode 100644
--- /dev/null
+++ b/test/resources/bar.yaml
@@ -0,0 +1,2 @@
+one: 1
+two: 2
diff --git a/test/resources/baz.yaml b/test/resources/baz.yaml
new file mode 100644
--- /dev/null
+++ b/test/resources/baz.yaml
@@ -0,0 +1,1 @@
+foo: !include foo.yaml
diff --git a/test/resources/foo.yaml b/test/resources/foo.yaml
new file mode 100644
--- /dev/null
+++ b/test/resources/foo.yaml
@@ -0,0 +1,3 @@
+foo: 23
+bar: !include bar.yaml
+baz: 42
diff --git a/test/resources/loop/bar.yaml b/test/resources/loop/bar.yaml
new file mode 100644
--- /dev/null
+++ b/test/resources/loop/bar.yaml
@@ -0,0 +1,2 @@
+one: 1
+two: !include foo.yaml
diff --git a/test/resources/loop/foo.yaml b/test/resources/loop/foo.yaml
new file mode 100644
--- /dev/null
+++ b/test/resources/loop/foo.yaml
@@ -0,0 +1,3 @@
+foo: 23
+bar: !include bar.yaml
+baz: 42
diff --git a/yaml.cabal b/yaml.cabal
--- a/yaml.cabal
+++ b/yaml.cabal
@@ -1,33 +1,29 @@
 name:            yaml
-version:         0.8.9.4
+version:         0.8.10
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>, Anton Ageev <antage@gmail.com>,Kirill Simonov 
 maintainer:      Michael Snoyman <michael@snoyman.com>
 synopsis:        Support for parsing and rendering YAML documents.
-description:     Provides support for parsing and emitting Yaml documents.
-                 .
-                 This package includes the full libyaml C library version 0.1.2 by Kirill
-                 Simonov (<http://pyyaml.org/wiki/LibYAML>) in the package so you
-                 don't need to worry about any non-Haskell dependencies.
-                 .
-                 The package is broken down into two modules.
-                 "Data.Yaml" provides a high-level interface based
-                 around the JSON datatypes provided by the @aeson@
-                 package. "Text.Libyaml" provides a lower-level,
-                 streaming interface. For most users, "Data.Yaml" is recommended.
+description:     Please see the README.md file.
 category:        Web
 stability:       stable
 cabal-version:   >= 1.8
 build-type:      Simple
 homepage:        http://github.com/snoyberg/yaml/
-extra-source-files: c/helper.h,
-                    libyaml/yaml_private.h,
-                    libyaml/yaml.h,
-		            libyaml/LICENSE
-                    test/main.hs
+extra-source-files: c/helper.h
+                    libyaml/yaml_private.h
+                    libyaml/yaml.h
+                    libyaml/LICENSE
                     test/largest-string.yaml
                     test/json.yaml
+                    test/resources/foo.yaml
+                    test/resources/bar.yaml
+                    test/resources/baz.yaml
+                    test/resources/loop/foo.yaml
+                    test/resources/loop/bar.yaml
+                    README.md
+                    ChangeLog.md
 
 flag no-exe
   description: don't install the yaml2json or json2yaml executables
@@ -54,11 +50,14 @@
                    , text
                    , attoparsec
                    , scientific
+                   , filepath
+                   , directory
     exposed-modules: Text.Libyaml
                      Data.Yaml
                      Data.Yaml.Aeson
                      Data.Yaml.Builder
                      Data.Yaml.Parser
+                     Data.Yaml.Include
     ghc-options:     -Wall
     c-sources:       c/helper.c
     include-dirs:    c
@@ -104,10 +103,12 @@
                  , aeson >= 0.5
 
 
-test-suite test
+test-suite spec
     type: exitcode-stdio-1.0
     hs-source-dirs:  test
-    main-is:         main.hs
+    main-is:         Spec.hs
+    other-modules:   Data.YamlSpec
+                     Data.Yaml.IncludeSpec
     cpp-options:     -DTEST
     build-depends:   hspec >= 1.3
                    , HUnit
@@ -122,6 +123,7 @@
                    , unordered-containers
                    , vector
                    , resourcet
+                   , aeson-qq
     ghc-options:     -Wall
 
 source-repository head
