net-spider 0.4.2.0 → 0.4.3.0
raw patch · 7 files changed
+239/−4 lines, 7 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ NetSpider.Log: logErrorW :: Text -> WriterLoggingM ()
+ NetSpider.Log: logInfoW :: Text -> WriterLoggingM ()
+ NetSpider.Log: logWarnW :: Text -> WriterLoggingM ()
+ NetSpider.SeqID: convertGraph :: (Eq n, Hashable n, Enum i, Eq i, Hashable i) => SeqIDMaker n i -> SnapshotGraph n na la -> (SeqIDMaker n i, SnapshotGraph i na la)
+ NetSpider.SeqID: convertLink :: (Eq n, Hashable n, Enum i, Eq i, Hashable i) => SeqIDMaker n i -> SnapshotLink n la -> (SeqIDMaker n i, SnapshotLink i la)
+ NetSpider.SeqID: convertNode :: (Eq n, Hashable n, Enum i, Eq i, Hashable i) => SeqIDMaker n i -> SnapshotNode n na -> (SeqIDMaker n i, SnapshotNode i na)
+ NetSpider.SeqID: convertNodeID :: (Eq n, Hashable n, Enum i, Eq i, Hashable i) => SeqIDMaker n i -> n -> (SeqIDMaker n i, i)
+ NetSpider.SeqID: data SeqIDMaker n i
+ NetSpider.SeqID: instance (GHC.Classes.Eq n, GHC.Classes.Eq i) => GHC.Classes.Eq (NetSpider.SeqID.SeqIDMaker n i)
+ NetSpider.SeqID: instance (GHC.Show.Show n, GHC.Show.Show i) => GHC.Show.Show (NetSpider.SeqID.SeqIDMaker n i)
+ NetSpider.SeqID: newSeqIDMaker :: i -> SeqIDMaker n i
+ NetSpider.SeqID: originalIDFor :: (Eq i, Hashable i) => SeqIDMaker n i -> i -> Maybe n
+ NetSpider.Snapshot: graphTimestamp :: SnapshotGraph n na la -> Maybe Timestamp
Files
- ChangeLog.md +12/−0
- net-spider.cabal +5/−3
- src/NetSpider.hs +2/−1
- src/NetSpider/Log.hs +15/−0
- src/NetSpider/SeqID.hs +109/−0
- src/NetSpider/Snapshot.hs +15/−0
- test/NetSpider/SeqIDSpec.hs +81/−0
ChangeLog.md view
@@ -1,5 +1,17 @@ # Revision history for net-spider +## 0.4.3.0 -- 2020-04-18++* Add SeqID module.++### Snapshot module++* Add `graphTimestamp` function.++### Log module++* Add `logInfoW`, `logWarnW` and `logErrorW` functions.+ ## 0.4.2.0 -- 2020-03-21 * Add Weaver module.
net-spider.cabal view
@@ -1,5 +1,5 @@ name: net-spider-version: 0.4.2.0+version: 0.4.3.0 author: Toshio Ito <debug.ito@gmail.com> maintainer: Toshio Ito <debug.ito@gmail.com> license: BSD3@@ -45,7 +45,8 @@ NetSpider.GraphML.Writer, NetSpider.GraphML.Attribute, NetSpider.Interval,- NetSpider.Weaver+ NetSpider.Weaver,+ NetSpider.SeqID other-modules: NetSpider.Graph.Internal, NetSpider.Spider.Internal.Graph, NetSpider.Spider.Internal.Log,@@ -93,7 +94,8 @@ NetSpider.TimestampSpec, NetSpider.FoundSpec, NetSpider.SnapshotSpec,- NetSpider.WeaverSpec+ NetSpider.WeaverSpec,+ NetSpider.SeqIDSpec, JSONUtil, SnapshotTestCase, TestCommon
src/NetSpider.hs view
@@ -41,7 +41,8 @@ -- -- == Utility ----- * "NetSpider.Pair"+-- * "NetSpider.Pair": Swap-insensitive two-element homogeneous tuple -- * "NetSpider.Log"+-- * "NetSpider.SeqID": Utility to generate sequential node IDs. module NetSpider () where
src/NetSpider/Log.hs view
@@ -12,6 +12,9 @@ WriterLoggingM, runWriterLoggingM, logDebugW,+ logInfoW,+ logWarnW,+ logErrorW, spack ) where @@ -28,6 +31,18 @@ logDebugW :: Text -> WriterLoggingM () logDebugW = Log.logDebugN++-- | @since 0.4.3.0+logInfoW :: Text -> WriterLoggingM ()+logInfoW = Log.logInfoN++-- | @since 0.4.3.0+logWarnW :: Text -> WriterLoggingM ()+logWarnW = Log.logWarnN++-- | @since 0.4.3.0+logErrorW :: Text -> WriterLoggingM ()+logErrorW = Log.logErrorN spack :: Show a => a -> Text spack = pack . show
+ src/NetSpider/SeqID.hs view
@@ -0,0 +1,109 @@+-- |+-- Module: NetSpider.SeqID+-- Description: Sequential node IDs+-- Maintainer: Toshio Ito <debug.ito@gmail.com>+--+-- @since 0.4.3.0+module NetSpider.SeqID+ ( -- * Type+ SeqIDMaker,+ -- * Construction+ newSeqIDMaker,+ -- * Conversion+ convertGraph,+ convertLink,+ convertNode,+ convertNodeID,+ originalIDFor+ ) where++import Data.Foldable (foldl')+import Data.List (reverse)+import Data.Hashable (Hashable)+import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HM++import NetSpider.Snapshot.Internal+ ( SnapshotNode(_nodeId),+ SnapshotLink(_sourceNode, _destinationNode),+ SnapshotGraph+ )+++-- | 'SeqIDMaker' converts node ID type @n@ into the new node ID type+-- @i@. The type @i@ is supposed to be an 'Enum', and it generates the+-- node ID of type @i@ sequentially for each node ID of type @n@.+--+-- 'SeqIDMaker' is useful to convert the 'SnapshotGraph' into a graph+-- representation of another graph library such as+-- [fgl](https://hackage.haskell.org/package/fgl). Note that the+-- target graph library can provide a better way for conversion. For+-- example, fgl has @NodeMap@ type to do basically the same thing.+data SeqIDMaker n i =+ SeqIDMaker+ { toSeqID :: HashMap n i,+ fromSeqID :: HashMap i n,+ nextID :: i+ }+ deriving (Show,Eq)++-- | Make a 'SeqIDMaker' with the given initial ID.+newSeqIDMaker :: i -- ^ Initial ID+ -> SeqIDMaker n i+newSeqIDMaker init_id = SeqIDMaker HM.empty HM.empty init_id++-- | Convert the given node ID of type @n@ into the sequential ID of+-- type @i@.+convertNodeID :: (Eq n, Hashable n, Enum i, Eq i, Hashable i)+ => SeqIDMaker n i+ -> n -- ^ Old ID+ -> (SeqIDMaker n i, i) -- ^ Updated 'SeqIDMaker' and the new ID.+convertNodeID maker nid =+ case HM.lookup nid $ toSeqID maker of+ Just existing_id -> (maker, existing_id)+ Nothing -> (new_maker, new_id)+ where+ new_id = nextID maker+ new_next_id = succ $ new_id+ new_maker = maker { toSeqID = new_to,+ fromSeqID = new_from,+ nextID = new_next_id+ }+ new_to = HM.insert nid new_id $ toSeqID maker+ new_from = HM.insert new_id nid $ fromSeqID maker+ +-- | Convert node IDs in the 'SnapshotGraph'.+convertGraph :: (Eq n, Hashable n, Enum i, Eq i, Hashable i)+ => SeqIDMaker n i -> SnapshotGraph n na la -> (SeqIDMaker n i, SnapshotGraph i na la)+convertGraph maker (nodes, links) = (new_maker, (new_nodes, new_links))+ where+ (inter_maker, new_nodes_rev) = foldl' nodeFolder (maker, []) nodes+ nodeFolder (m, ns) node = let (step_m, new_node) = convertNode m node+ in (step_m, new_node : ns)+ new_nodes = reverse new_nodes_rev+ (new_maker, new_links_rev) = foldl' linkFolder (inter_maker, []) links+ linkFolder (m, ls) link = let (step_m, new_link) = convertLink m link+ in (step_m, new_link : ls)+ new_links = reverse new_links_rev++-- | Convert node IDs in the 'SnapshotLink'.+convertLink :: (Eq n, Hashable n, Enum i, Eq i, Hashable i)+ => SeqIDMaker n i -> SnapshotLink n la -> (SeqIDMaker n i, SnapshotLink i la)+convertLink maker link = (new_maker, new_link)+ where+ (inter_maker, seq_source) = convertNodeID maker $ _sourceNode link+ (new_maker, seq_dest) = convertNodeID inter_maker $ _destinationNode link+ new_link = link { _sourceNode = seq_source, _destinationNode = seq_dest }++-- | Convert node ID in the 'SnapshotNode'.+convertNode :: (Eq n, Hashable n, Enum i, Eq i, Hashable i)+ => SeqIDMaker n i -> SnapshotNode n na -> (SeqIDMaker n i, SnapshotNode i na)+convertNode maker node = (new_maker, new_node)+ where+ (new_maker, seq_id) = convertNodeID maker $ _nodeId node+ new_node = node { _nodeId = seq_id }++-- | Get the original ID of type @n@ for the new ID of type @i@.+originalIDFor :: (Eq i, Hashable i)+ => SeqIDMaker n i -> i -> Maybe n+originalIDFor maker seq_id = HM.lookup seq_id $ fromSeqID maker
src/NetSpider/Snapshot.hs view
@@ -8,6 +8,7 @@ module NetSpider.Snapshot ( -- * SnapshotGraph SnapshotGraph,+ graphTimestamp, -- * SnapshotNode SnapshotNode, nodeId,@@ -25,6 +26,8 @@ linkAttributes ) where +import Data.Maybe (catMaybes)+ import NetSpider.Snapshot.Internal ( SnapshotGraph, SnapshotNode(..),@@ -33,6 +36,18 @@ linkNodePair ) import NetSpider.Timestamp (Timestamp)++-- | Get the timestamp of the graph. It's the latest timestamp of the+-- nodes and links.+--+-- @since 0.4.3.0+graphTimestamp :: SnapshotGraph n na la -> Maybe Timestamp+graphTimestamp (nodes, links) = maximum' (node_times ++ link_times)+ where+ maximum' [] = Nothing+ maximum' ts = Just $ maximum ts+ node_times = catMaybes $ map nodeTimestamp nodes+ link_times = map linkTimestamp links nodeId :: SnapshotNode n na -> n nodeId = _nodeId
+ test/NetSpider/SeqIDSpec.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE OverloadedStrings #-}+module NetSpider.SeqIDSpec (main,spec) where++import Data.Text (Text)+import Test.Hspec++import NetSpider.SeqID+ ( newSeqIDMaker, convertNodeID, convertGraph, originalIDFor+ )+import NetSpider.Snapshot.Internal (SnapshotNode(..), SnapshotLink(..))+import NetSpider.Snapshot (nodeId, linkNodeTuple)+import NetSpider.Timestamp (fromEpochMillisecond)++main :: IO ()+main = hspec spec++spec :: Spec+spec = describe "SeqIDMaker" $ do+ specify "first ID" $ do+ let m = newSeqIDMaker (0 :: Int)+ (got_m, got) = convertNodeID m ("hoge" :: Text)+ got `shouldBe` 0+ (snd $ convertNodeID got_m "hoge") `shouldBe` 0+ originalIDFor got_m 0 `shouldBe` Just "hoge"+ originalIDFor got_m 1 `shouldBe` Nothing+ originalIDFor got_m 2 `shouldBe` Nothing+ specify "second ID" $ do+ let m = newSeqIDMaker (0 :: Int)+ (m1, _) = convertNodeID m ("bar" :: Text)+ (got_m, got) = convertNodeID m1 ("foo" :: Text)+ got `shouldBe` 1+ (snd $ convertNodeID got_m "bar") `shouldBe` 0+ (snd $ convertNodeID got_m "foo") `shouldBe` 1+ originalIDFor got_m 0 `shouldBe` Just "bar"+ originalIDFor got_m 1 `shouldBe` Just "foo"+ originalIDFor got_m 2 `shouldBe` Nothing+ specify "duplicate ID" $ do+ let m = newSeqIDMaker (5 :: Int)+ (m1, id1) = convertNodeID m ("bar" :: Text)+ (got_m, id2) = convertNodeID m1 ("bar" :: Text)+ id1 `shouldBe` 5+ id2 `shouldBe` 5+ originalIDFor got_m 0 `shouldBe` Nothing+ originalIDFor got_m 5 `shouldBe` Just "bar"+ specify "convertGraph" $ do+ let input = (nodes, links)+ mkNode :: Text -> SnapshotNode Text ()+ mkNode nid = SnapshotNode+ { _nodeId = nid,+ _isOnBoundary = False,+ _nodeTimestamp = Just $ fromEpochMillisecond 100,+ _nodeAttributes = Just ()+ }+ mkLink :: Text -> Text -> SnapshotLink Text ()+ mkLink source dest = SnapshotLink+ { _sourceNode = source,+ _destinationNode = dest,+ _isDirected = True,+ _linkTimestamp = fromEpochMillisecond 100,+ _linkAttributes = ()+ }+ nodes = [ mkNode "n1",+ mkNode "n2",+ mkNode "n3",+ mkNode "n4",+ mkNode "n5"+ ]+ links = [ mkLink "n1" "n3",+ mkLink "n4" "n2",+ mkLink "n3" "n5",+ mkLink "n5" "n2"+ ]+ (got_m, (got_nodes, got_links)) = convertGraph (newSeqIDMaker (1 :: Int)) input+ map nodeId got_nodes `shouldBe` [1,2,3,4,5]+ map linkNodeTuple got_links `shouldBe`+ [ (1, 3), (4, 2), (3, 5), (5, 2)+ ]+ map (originalIDFor got_m) [1 .. 6] `shouldBe`+ [ Just "n1", Just "n2", Just "n3", Just "n4", Just "n5", Nothing+ ]+