packages feed

mmtf 0.1.1.0 → 0.1.2.0

raw patch · 5 files changed

+120/−74 lines, 5 filesdep ~binarydep ~containersdep ~data-msgpackPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: binary, containers, data-msgpack, http-conduit, text

API changes (from Hackage documentation)

- Bio.MMTF: AtomData :: !Maybe [Int32] -> !Maybe [Char] -> !Maybe [Float] -> ![Float] -> ![Float] -> ![Float] -> !Maybe [Float] -> AtomData
+ Bio.MMTF: AtomData :: ![Int32] -> ![Char] -> ![Float] -> ![Float] -> ![Float] -> ![Float] -> ![Float] -> AtomData
- Bio.MMTF: ChainData :: ![Int32] -> ![Text] -> !Maybe [Text] -> ChainData
+ Bio.MMTF: ChainData :: ![Int32] -> ![Text] -> ![Text] -> ChainData
- Bio.MMTF: GroupData :: ![GroupType] -> ![Int32] -> ![Int32] -> !Maybe [SecondaryStructure] -> !Maybe [Char] -> !Maybe [Int32] -> GroupData
+ Bio.MMTF: GroupData :: ![GroupType] -> ![Int32] -> ![Int32] -> ![SecondaryStructure] -> ![Char] -> ![Int32] -> GroupData
- Bio.MMTF: StructureData :: !Maybe Text -> !Maybe Text -> !Maybe Text -> !Maybe Text -> !Int32 -> !Int32 -> !Int32 -> !Int32 -> !Int32 -> !Maybe Text -> !Maybe UnitCell -> !Maybe [[Float]] -> !Maybe [Assembly] -> !Maybe [Entity] -> !Maybe Float -> !Maybe Float -> !Maybe Float -> !Maybe [Text] -> !Maybe [Int32] -> !Maybe [Int8] -> StructureData
+ Bio.MMTF: StructureData :: !Text -> !Text -> !Text -> !Text -> !Int32 -> !Int32 -> !Int32 -> !Int32 -> !Int32 -> !Text -> !Maybe UnitCell -> ![[Float]] -> ![Assembly] -> ![Entity] -> !Maybe Float -> !Maybe Float -> !Maybe Float -> ![Text] -> ![Int32] -> ![Int8] -> StructureData
- Bio.MMTF: [altLocList] :: AtomData -> !Maybe [Char]
+ Bio.MMTF: [altLocList] :: AtomData -> ![Char]
- Bio.MMTF: [atomIdList] :: AtomData -> !Maybe [Int32]
+ Bio.MMTF: [atomIdList] :: AtomData -> ![Int32]
- Bio.MMTF: [bFactorList] :: AtomData -> !Maybe [Float]
+ Bio.MMTF: [bFactorList] :: AtomData -> ![Float]
- Bio.MMTF: [bioAssemblyList] :: StructureData -> !Maybe [Assembly]
+ Bio.MMTF: [bioAssemblyList] :: StructureData -> ![Assembly]
- Bio.MMTF: [bondAtomList] :: StructureData -> !Maybe [Int32]
+ Bio.MMTF: [bondAtomList] :: StructureData -> ![Int32]
- Bio.MMTF: [bondOrderList] :: StructureData -> !Maybe [Int8]
+ Bio.MMTF: [bondOrderList] :: StructureData -> ![Int8]
- Bio.MMTF: [chainNameList] :: ChainData -> !Maybe [Text]
+ Bio.MMTF: [chainNameList] :: ChainData -> ![Text]
- Bio.MMTF: [depositionDate] :: StructureData -> !Maybe Text
+ Bio.MMTF: [depositionDate] :: StructureData -> !Text
- Bio.MMTF: [entityList] :: StructureData -> !Maybe [Entity]
+ Bio.MMTF: [entityList] :: StructureData -> ![Entity]
- Bio.MMTF: [experimentalMethods] :: StructureData -> !Maybe [Text]
+ Bio.MMTF: [experimentalMethods] :: StructureData -> ![Text]
- Bio.MMTF: [insCodeList] :: GroupData -> !Maybe [Char]
+ Bio.MMTF: [insCodeList] :: GroupData -> ![Char]
- Bio.MMTF: [ncsOperatorList] :: StructureData -> !Maybe [[Float]]
+ Bio.MMTF: [ncsOperatorList] :: StructureData -> ![[Float]]
- Bio.MMTF: [occupancyList] :: AtomData -> !Maybe [Float]
+ Bio.MMTF: [occupancyList] :: AtomData -> ![Float]
- Bio.MMTF: [releaseDate] :: StructureData -> !Maybe Text
+ Bio.MMTF: [releaseDate] :: StructureData -> !Text
- Bio.MMTF: [secStructList] :: GroupData -> !Maybe [SecondaryStructure]
+ Bio.MMTF: [secStructList] :: GroupData -> ![SecondaryStructure]
- Bio.MMTF: [sequenceIndexList] :: GroupData -> !Maybe [Int32]
+ Bio.MMTF: [sequenceIndexList] :: GroupData -> ![Int32]
- Bio.MMTF: [spaceGroup] :: StructureData -> !Maybe Text
+ Bio.MMTF: [spaceGroup] :: StructureData -> !Text
- Bio.MMTF: [structureId] :: StructureData -> !Maybe Text
+ Bio.MMTF: [structureId] :: StructureData -> !Text
- Bio.MMTF: [title] :: StructureData -> !Maybe Text
+ Bio.MMTF: [title] :: StructureData -> !Text

Files

mmtf.cabal view
@@ -1,5 +1,5 @@ name:                mmtf-version:             0.1.1.0+version:             0.1.2.0 synopsis:            Macromolecular Transmission Format implementation description:         Haskell implementation of MMTF biological structure format. homepage:            https://github.com/zmactep/mmtf#readme@@ -34,12 +34,24 @@ test-suite mmtf-test   type:                exitcode-stdio-1.0   hs-source-dirs:      test+                     , src   main-is:             Spec.hs+  other-modules:       Bio.MMTF+                     , Bio.MMTF.Type+                     , Bio.MMTF.MessagePack+                     , Bio.MMTF.Decode+                     , Bio.MMTF.Decode.Codec+                     , Bio.MMTF.Decode.MessagePack   build-depends:       base                      , mmtf-                     , QuickCheck >= 2.9.2 && < 2.10-                     , hspec >= 2.4.1 && < 2.5+                     , QuickCheck >= 2.9.2 && < 2.13+                     , hspec >= 2.4.1 && < 2.7+                     , data-msgpack+                     , text                      , bytestring+                     , binary+                     , containers+                     , http-conduit   ghc-options:         -threaded -rtsopts -with-rtsopts=-N   default-language:    Haskell2010 
src/Bio/MMTF/Decode.hs view
@@ -7,6 +7,7 @@ import           Bio.MMTF.Type  import           Control.Monad               ((>=>))+import           Data.ByteString.Lazy        (empty) import           Data.Map.Strict             (Map) import           Data.MessagePack            (Object) import           Data.Text                   (Text)@@ -27,76 +28,76 @@ -- chainData :: Monad m => Map Text Object -> m ChainData chainData mp = do gpc <- atP mp "groupsPerChain" asIntList-                  cil <- codec5 . parseBinary <$> atP mp "chainIdList" asBinary-                  cnl <- (codec5 . parseBinary <$>) <$> atPM mp "chainNameList" asBinary+                  cil <- codec5 . parseBinary <$> atP   mp "chainIdList"   asBinary+                  cnl <- codec5 . parseBinary <$> atPMD mp "chainNameList" asBinary empty                   pure $ ChainData gpc cil cnl  -- | Parses atom data from ObjectMap -- atomData :: Monad m => Map Text Object -> m AtomData-atomData mp = do ail' <- (codec8 . parseBinary <$>) <$> atPM mp "atomIdList" asBinary-                 all' <- (codec6 . parseBinary <$>) <$> atPM mp "altLocList" asBinary-                 bfl' <- (codec10 . parseBinary <$>) <$> atPM mp "bFactorList" asBinary-                 xcl' <- codec10 . parseBinary <$> atP mp "xCoordList" asBinary-                 ycl' <- codec10 . parseBinary <$> atP mp "yCoordList" asBinary-                 zcl' <- codec10 . parseBinary <$> atP mp "zCoordList" asBinary-                 ol' <-  (codec9 . parseBinary <$>) <$> atPM mp "occupancyList" asBinary+atomData mp = do ail' <-  codec8 . parseBinary <$> atPMD mp "atomIdList"    asBinary empty+                 all' <-  codec6 . parseBinary <$> atPMD mp "altLocList"    asBinary empty+                 bfl' <- codec10 . parseBinary <$> atPMD mp "bFactorList"   asBinary empty+                 xcl' <- codec10 . parseBinary <$> atP   mp "xCoordList"    asBinary+                 ycl' <- codec10 . parseBinary <$> atP   mp "yCoordList"    asBinary+                 zcl' <- codec10 . parseBinary <$> atP   mp "zCoordList"    asBinary+                 ol' <-   codec9 . parseBinary <$> atPMD mp "occupancyList" asBinary empty                  pure $ AtomData ail' all' bfl' xcl' ycl' zcl' ol'  -- | Parses group data from ObjectMap -- groupData :: Monad m => Map Text Object -> m GroupData groupData mp = do gl' <- atP mp "groupList" asObjectList >>= traverse (transformObjectMap >=> groupType)-                  gtl' <- codec4 . parseBinary <$> atP mp "groupTypeList" asBinary-                  gil' <- codec8 . parseBinary <$> atP mp "groupIdList" asBinary-                  ssl' <- (map ssDec . codec2 . parseBinary <$>) <$> atPM mp "secStructList" asBinary-                  icl' <- (codec6 . parseBinary <$>) <$> atPM mp "insCodeList" asBinary-                  sil' <- (codec8 . parseBinary <$>) <$> atPM mp "sequenceIndexList" asBinary+                  gtl' <-              codec4 . parseBinary <$> atP   mp "groupTypeList"     asBinary+                  gil' <-              codec8 . parseBinary <$> atP   mp "groupIdList"       asBinary+                  ssl' <- fmap ssDec . codec2 . parseBinary <$> atPMD mp "secStructList"     asBinary empty+                  icl' <-              codec6 . parseBinary <$> atPMD mp "insCodeList"       asBinary empty+                  sil' <-              codec8 . parseBinary <$> atPMD mp "sequenceIndexList" asBinary empty                   pure $ GroupData gl' gtl' gil' ssl' icl' sil'  -- | Parses group type from ObjectMap -- groupType :: Monad m => Map Text Object -> m GroupType groupType mp = do fcl' <- atP mp "formalChargeList" asIntList-                  anl' <- atP mp "atomNameList" asStrList-                  el'  <- atP mp "elementList" asStrList-                  bal' <- atP mp "bondAtomList" asIntList-                  bol' <- atP mp "bondOrderList" asIntList-                  gn'  <- atP mp "groupName" asStr+                  anl' <- atP mp "atomNameList"     asStrList+                  el'  <- atP mp "elementList"      asStrList+                  bal' <- atP mp "bondAtomList"     asIntList+                  bol' <- atP mp "bondOrderList"    asIntList+                  gn'  <- atP mp "groupName"        asStr                   slc' <- atP mp "singleLetterCode" asChar-                  cct' <- atP mp "chemCompType" asStr+                  cct' <- atP mp "chemCompType"     asStr                   pure $ GroupType fcl' anl' el' bal' bol' gn' slc' cct'  -- | Parses structure data from ObjectMap -- structureData :: Monad m => Map Text Object -> m StructureData-structureData mp = do ttl' <- atPM mp "title" asStr-                      sid' <- atPM mp "structureId" asStr-                      dd'  <- atPM mp "depositionDate" asStr-                      rd'  <- atPM mp "releaseDate" asStr-                      nb'  <- atP mp "numBonds" asInt-                      na'  <- atP mp "numAtoms" asInt-                      ng'  <- atP mp "numGroups" asInt-                      nc'  <- atP mp "numChains" asInt-                      nm'  <- atP mp "numModels" asInt-                      sg'  <- atPM mp "spaceGroup" asStr-                      uc'  <- (>>= ucDec) <$> atPM mp "unitCell" asFloatList-                      nol' <- ((>>= asFloatList) <$>) <$> atPM mp "ncsOperatorList" asObjectList-                      bal' <- (>>= traverse (transformObjectMap >=> bioAssembly)) <$> atPM mp "bioAssemblyList" asObjectList-                      el'  <- (>>= traverse (transformObjectMap >=> entity)) <$> atPM mp "entityList" asObjectList-                      res' <- atPM mp "resolution" asFloat-                      rf'  <- atPM mp "rFree" asFloat-                      rw'  <- atPM mp "rWork" asFloat-                      em'  <- atPM mp "experimentalMethods" asStrList-                      btl' <- (codec4 . parseBinary <$>) <$> atPM mp "bondAtomList" asBinary-                      bol' <- (codec2 . parseBinary <$>) <$> atPM mp "bondOrderList" asBinary+structureData mp = do ttl' <-                          atPMD mp "title"               asStr        ""+                      sid' <-                          atPMD mp "structureId"         asStr        ""+                      dd'  <-                          atPMD mp "depositionDate"      asStr        ""+                      rd'  <-                          atPMD mp "releaseDate"         asStr        ""+                      nb'  <-                          atP   mp "numBonds"            asInt+                      na'  <-                          atP   mp "numAtoms"            asInt+                      ng'  <-                          atP   mp "numGroups"           asInt+                      nc'  <-                          atP   mp "numChains"           asInt+                      nm'  <-                          atP   mp "numModels"           asInt+                      sg'  <-                          atPMD mp "spaceGroup"          asStr        ""+                      uc'  <-          (>>= ucDec) <$> atPM  mp "unitCell"            asFloatList+                      nol' <-    (>>= asFloatList) <$> atPMD mp "ncsOperatorList"     asObjectList []+                      bal' <-                          atPMD mp "bioAssemblyList"     asObjectList [] >>= traverse (transformObjectMap >=> bioAssembly)+                      el'  <-                          atPMD mp "entityList"          asObjectList [] >>= traverse (transformObjectMap >=> entity)+                      res' <-                          atPM  mp "resolution"          asFloat+                      rf'  <-                          atPM  mp "rFree"               asFloat+                      rw'  <-                          atPM  mp "rWork"               asFloat+                      em'  <-                          atPMD mp "experimentalMethods" asStrList []+                      btl' <- codec4 . parseBinary <$> atPMD mp "bondAtomList"        asBinary empty+                      bol' <- codec2 . parseBinary <$> atPMD mp "bondOrderList"       asBinary empty                       pure $ StructureData ttl' sid' dd' rd' nb' na' ng' nc' nm' sg' uc' nol'                                            bal' el' res' rf' rw' em' btl' bol'  -- | Parses bio assembly data from ObjectMap -- bioAssembly :: Monad m => Map Text Object -> m Assembly-bioAssembly mp = do nme' <- atP mp "name" asStr+bioAssembly mp = do nme' <- atP mp "name"          asStr                     tlt' <- atP mp "transformList" asObjectList >>= traverse (transformObjectMap >=> transform)                     pure $ Assembly tlt' nme' @@ -104,14 +105,14 @@ -- transform :: Monad m => Map Text Object -> m Transform transform mp = do cil' <- atP mp "chainIndexList" asIntList-                  mtx' <- atP mp "matrix" asFloatList+                  mtx' <- atP mp "matrix"         asFloatList                   pure $ Transform cil' mtx'  -- | Parses entity data from ObjectMap -- entity :: Monad m => Map Text Object -> m Entity entity mp = do cil' <- atP mp "chainIndexList" asIntList-               dsc' <- atP mp "description" asStr-               tpe' <- atP mp "type" asStr-               sqc' <- atP mp "sequence" asStr+               dsc' <- atP mp "description"    asStr+               tpe' <- atP mp "type"           asStr+               sqc' <- atP mp "sequence"       asStr                pure $ Entity cil' dsc' tpe' sqc'
src/Bio/MMTF/Decode/MessagePack.hs view
@@ -24,6 +24,12 @@ atPM :: Monad m => Map Text Object -> Text -> (Object -> m a) -> m (Maybe a) atPM m k conv = traverse conv $ M.lookup k m +atPMD :: Monad m => Map Text Object -> Text -> (Object -> m a) -> a -> m a+atPMD m k conv def = do x <- atPM m k conv+                        case x of+                          Just r  -> pure r+                          Nothing -> pure def+                        asStr :: Monad m => Object -> m Text asStr (ObjectStr s) = pure s asStr _             = fail "Not a string data"
src/Bio/MMTF/Type.hs view
@@ -72,26 +72,26 @@  -- | Structure data ---data StructureData = StructureData { title               :: !(Maybe Text)       -- ^ A short description of the structural data included in the file-                                   , structureId         :: !(Maybe Text)       -- ^ An ID for the structure, for example the PDB ID if applicable-                                   , depositionDate      :: !(Maybe Text)       -- ^ A date that relates to the deposition of the structure in a database-                                   , releaseDate         :: !(Maybe Text)       -- ^ A date that relates to the release of the structure in a database+data StructureData = StructureData { title               :: !Text               -- ^ A short description of the structural data included in the file+                                   , structureId         :: !Text               -- ^ An ID for the structure, for example the PDB ID if applicable+                                   , depositionDate      :: !Text               -- ^ A date that relates to the deposition of the structure in a database+                                   , releaseDate         :: !Text               -- ^ A date that relates to the release of the structure in a database                                    , numBonds            :: !Int32              -- ^ The overall number of bonds                                    , numAtoms            :: !Int32              -- ^ The overall number of atoms in the structure                                    , numGroups           :: !Int32              -- ^ The overall number of groups in the structure                                    , numChains           :: !Int32              -- ^ The overall number of chains in the structure                                    , numModels           :: !Int32              -- ^ The overall number of models in the structure-                                   , spaceGroup          :: !(Maybe Text)       -- ^ The Hermann-Mauguin space-group symbol+                                   , spaceGroup          :: !Text               -- ^ The Hermann-Mauguin space-group symbol                                    , unitCell            :: !(Maybe UnitCell)   -- ^ Array of six values defining the unit cell-                                   , ncsOperatorList     :: !(Maybe [[Float]])  -- ^ List of lists representing 4x4 transformation matrices that are stored linearly in row major order (transformation matrices describe noncrystallographic symmetry operations needed to create all molecules in the unit cell)-                                   , bioAssemblyList     :: !(Maybe [Assembly]) -- ^ List of instructions on how to transform coordinates for an array of chains to create (biological) assemblies-                                   , entityList          :: !(Maybe [Entity])   -- ^ List of unique molecular entities within the structure+                                   , ncsOperatorList     :: ![[Float]]          -- ^ List of lists representing 4x4 transformation matrices that are stored linearly in row major order (transformation matrices describe noncrystallographic symmetry operations needed to create all molecules in the unit cell)+                                   , bioAssemblyList     :: ![Assembly]         -- ^ List of instructions on how to transform coordinates for an array of chains to create (biological) assemblies+                                   , entityList          :: ![Entity]           -- ^ List of unique molecular entities within the structure                                    , resolution          :: !(Maybe Float)      -- ^ The experimental resolution in Angstrom                                    , rFree               :: !(Maybe Float)      -- ^ The R-free value                                    , rWork               :: !(Maybe Float)      -- ^ The R-work value-                                   , experimentalMethods :: !(Maybe [Text])     -- ^ List of experimental methods employed for structure determination-                                   , bondAtomList        :: !(Maybe [Int32])    -- ^ Pairs of values represent indices of covalently bonded atoms [binary (type 4)]-                                   , bondOrderList       :: !(Maybe [Int8])     -- ^ List of bond orders for bonds in 'bondAtomList' [binary (type 2)]+                                   , experimentalMethods :: ![Text]             -- ^ List of experimental methods employed for structure determination+                                   , bondAtomList        :: ![Int32]            -- ^ Pairs of values represent indices of covalently bonded atoms [binary (type 4)]+                                   , bondOrderList       :: ![Int8]             -- ^ List of bond orders for bonds in 'bondAtomList' [binary (type 2)]                                    }   deriving (Show, Eq) @@ -105,7 +105,7 @@ -- data ChainData = ChainData { groupsPerChain :: ![Int32]        -- ^ List of the number of groups (aka residues) in each chain                            , chainIdList    :: ![Text]         -- ^ List of chain IDs [binary (type 5)]-                           , chainNameList  :: !(Maybe [Text]) -- ^ List of chain names [binary (type 5)]+                           , chainNameList  :: ![Text]         -- ^ List of chain names [binary (type 5)]                            }   deriving (Show, Eq) @@ -114,21 +114,21 @@ data GroupData = GroupData { groupList         :: ![GroupType]                  -- ^ List of groupType objects                            , groupTypeList     :: ![Int32]                      -- ^ List of pointers to 'groupType' entries in 'groupList' by their keys [binary (type 4)]                            , groupIdList       :: ![Int32]                      -- ^ List of group (residue) numbers [binary (type 8)]-                           , secStructList     :: !(Maybe [SecondaryStructure]) -- ^ List of secondary structure assignments [binary (type 2)]-                           , insCodeList       :: !(Maybe [Char])               -- ^ List of insertion codes, one for each group (residue) [binary (type 6)]-                           , sequenceIndexList :: !(Maybe [Int32])              -- ^ List of indices that point into the sequence property of an entity object in the 'entityList' field that is associated with the chain the group belongs to [binary (type 8)]+                           , secStructList     :: ![SecondaryStructure]         -- ^ List of secondary structure assignments [binary (type 2)]+                           , insCodeList       :: ![Char]                       -- ^ List of insertion codes, one for each group (residue) [binary (type 6)]+                           , sequenceIndexList :: ![Int32]                      -- ^ List of indices that point into the sequence property of an entity object in the 'entityList' field that is associated with the chain the group belongs to [binary (type 8)]                            }   deriving (Show, Eq)  -- | Atoms data ---data AtomData = AtomData { atomIdList    :: !(Maybe [Int32]) -- ^ List of atom serial numbers [binary (type 8)]-                         , altLocList    :: !(Maybe [Char])  -- ^ List of alternate location labels, one for each atom [binary (type 6)]-                         , bFactorList   :: !(Maybe [Float]) -- ^ List of atom B-factors in in A^2, one for each atom [binary (type 10)]+data AtomData = AtomData { atomIdList    :: ![Int32]         -- ^ List of atom serial numbers [binary (type 8)]+                         , altLocList    :: ![Char]          -- ^ List of alternate location labels, one for each atom [binary (type 6)]+                         , bFactorList   :: ![Float]         -- ^ List of atom B-factors in in A^2, one for each atom [binary (type 10)]                          , xCoordList    :: ![Float]         -- ^ List of x atom coordinates in A, one for each atom [binary (type 10)]                          , yCoordList    :: ![Float]         -- ^ List of y atom coordinates in A, one for each atom [binary (type 10)]                          , zCoordList    :: ![Float]         -- ^ List of z atom coordinates in A, one for each atom [binary (type 10)]-                         , occupancyList :: !(Maybe [Float]) -- ^ List of atom occupancies, one for each atom [binary (type 9)]+                         , occupancyList :: ![Float]         -- ^ List of atom occupancies, one for each atom [binary (type 9)]                          }   deriving (Show, Eq) 
test/Spec.hs view
@@ -2,13 +2,40 @@  import           Bio.MMTF import qualified Data.ByteString.Lazy as B+import           Data.Int             (Int8) import           Test.Hspec +import Bio.MMTF.Decode.Codec++codecSpec :: Spec+codecSpec =+  describe "MMTF decoding" $ do+    it "unpacks by Run-length encoding" $ do+      let sample = [ 1, 10, 2, 1, 1, 4 ] :: [Int8]+      runLengthDec sample `shouldBe` ([ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1 ] :: [Int8])+    it "unpacks by Delta encoding" $ do+      let sample = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1 ] :: [Int8]+      deltaDec sample `shouldBe` ([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16 ] :: [Int8])+    it "unpacks by Recursive indexing encoding" $ do+      let sample = [ 127, 41, 34, 1, 0, -50, -128, 0, 7, 127, 0, 127, 127, 14 ] :: [Int8]+      recIndexDec sample `shouldBe` [ 168, 34, 1, 0, -50, -128, 7, 127, 268 ]+    it "upacks by Integer encoding" $ do+      let sample = [ 100, 100, 100, 100, 50, 50 ] :: [Int8]+      integerDec 100 sample `shouldBe` [ 1.00, 1.00, 1.00, 1.00, 0.50, 0.50 ]++parserSpec :: Spec+parserSpec =+  describe "MMTF parser" $+  it "should parse 1FSD" $ do+    m <- fetch "1FSD"+    (structureId . structure) m `shouldBe` "1FSD"+    (numModels . structure) m `shouldBe` 41+    (length . bFactorList . atom) m `shouldBe` 20664+    (experimentalMethods . structure) m `shouldBe` ["SOLUTION NMR"]+    (head . xCoordList . atom) m `shouldBe` (-12.847)+    (last . xCoordList . atom) m `shouldBe` 5.672+ main :: IO ()-main = hspec $-  describe "MMTF" $-    it "should parse 1FSD" $ do-      contents <- B.readFile "resource/1FSD.mmtf"-      m <- decode contents-      (structureId . structure) m `shouldBe` Just "1FSD"-      (numModels . structure) m `shouldBe` 41+main = hspec $ do+         codecSpec+         parserSpec