diff --git a/geode.cabal b/geode.cabal index 03309af6c853032fca4a8b70ede85bb069c80933..ba9c94fa6bfb192adae95bb7b239de9d80ca7e65 100644 --- a/geode.cabal +++ b/geode.cabal @@ -24,7 +24,6 @@ library exposed-modules: GEODE.Metadata , GEODE.Metadata.Entry , GEODE.Metadata.SplitContext - , GEODE.Metadata.TSV.Header , GEODE.Options -- Modules included in this library but not exported. @@ -32,6 +31,7 @@ library , GEODE.Metadata.ArticleRecord , GEODE.Metadata.Record , GEODE.Metadata.TSV + , GEODE.Metadata.TSV.Header , GEODE.Metadata.Types , GEODE.Metadata.Work diff --git a/lib/GEODE/Metadata.hs b/lib/GEODE/Metadata.hs index 4376658769573f94b626c63381fce62e6b70cdef..2d0dc5dc4300f3c47785543c9f5088b2cef8ae68 100644 --- a/lib/GEODE/Metadata.hs +++ b/lib/GEODE/Metadata.hs @@ -24,7 +24,6 @@ import GEODE.Metadata.Record as Record import GEODE.Metadata.SplitContext as SplitContext hiding (get, page, rank) import GEODE.Metadata.TSV as TSV import GEODE.Metadata.TSV.Header as TSV_Header - ( DefaultFields(..), HasDefaultHeader(..), WithDefaultHeader(..), glue ) import GEODE.Metadata.Types as Types import GEODE.Metadata.Work as Work diff --git a/lib/GEODE/Metadata/ArticleRecord.hs b/lib/GEODE/Metadata/ArticleRecord.hs index b78b70a3a610f60680aeaf39aff5dbe3e97795af..1337b74ece632b2a5565afa1e7deb7ac0aebfd22 100644 --- a/lib/GEODE/Metadata/ArticleRecord.hs +++ b/lib/GEODE/Metadata/ArticleRecord.hs @@ -7,10 +7,9 @@ module GEODE.Metadata.ArticleRecord import Data.Aeson ((.=), FromJSON(..), ToJSON(..)) import Data.Aeson.KeyMap as KeyMap (fromList) -import Data.Csv (FromNamedRecord(..), ToNamedRecord(..)) +import Data.Csv (DefaultOrdered(..), FromNamedRecord(..), ToNamedRecord(..)) import GEODE.Metadata.Record (Record(..)) import GEODE.Metadata.Types (ToJSONObject(..)) -import GEODE.Metadata.TSV.Header (DefaultFields(..), HasDefaultHeader(..)) import GEODE.Metadata.Work (Work(..)) import GHC.Generics (Generic) import System.FilePath ((</>), (<.>)) @@ -23,6 +22,7 @@ data ArticleRecord = ArticleRecord instance FromNamedRecord ArticleRecord instance ToNamedRecord ArticleRecord +instance DefaultOrdered ArticleRecord instance ToJSONObject ArticleRecord where toJSONObject (ArticleRecord {work, volume, article}) = KeyMap.fromList @@ -42,6 +42,3 @@ instance Record ArticleRecord where relativePath (ArticleRecord {work, volume, article}) extension = (show work) </> ("T" <> show volume) </> (show article) <.> extension - -instance HasDefaultHeader ArticleRecord where - defaultFields = DefaultFields [ "work", "volume", "article" ] diff --git a/lib/GEODE/Metadata/Contrastive.hs b/lib/GEODE/Metadata/Contrastive.hs index 69d9c48fe23701bb84d55dd60662d1141d3f3c74..b044e0c84ae7141d943f6f47351fe85ef40de193 100644 --- a/lib/GEODE/Metadata/Contrastive.hs +++ b/lib/GEODE/Metadata/Contrastive.hs @@ -5,9 +5,9 @@ module GEODE.Metadata.Contrastive , formatList ) where import Data.Csv - ( FromField(..), FromNamedRecord(..), ToNamedRecord(..), ToField(..) ) + ( DefaultOrdered(..), FromField(..), FromNamedRecord(..), ToNamedRecord(..) + , ToField(..) ) import Data.Text (Text, intercalate, splitOn, uncons, unsnoc) -import GEODE.Metadata.TSV.Header (DefaultFields(..), HasDefaultHeader(..)) import GHC.Generics (Generic) newtype MultiText = MultiText @@ -39,8 +39,6 @@ data Contrastive = Contrastive , domains :: MultiText , subCorpus :: MultiText } deriving (Generic, Show) +instance DefaultOrdered Contrastive instance FromNamedRecord Contrastive instance ToNamedRecord Contrastive - -instance HasDefaultHeader Contrastive where - defaultFields = DefaultFields [ "authors", "domains", "subCorpus" ] diff --git a/lib/GEODE/Metadata/Entry.hs b/lib/GEODE/Metadata/Entry.hs index 3a3ae4494325615187235b2661013bbc620b2a25..f9e568bfa01eef998c1912ac1ec00b5b20bd4e5d 100644 --- a/lib/GEODE/Metadata/Entry.hs +++ b/lib/GEODE/Metadata/Entry.hs @@ -5,11 +5,9 @@ module GEODE.Metadata.Entry , normalize ) where import Data.Char (isAlphaNum, isSpace, isUpper, toLower) -import Data.Csv (FromNamedRecord(..), ToNamedRecord(..)) +import Data.Csv (DefaultOrdered(..), FromNamedRecord(..), ToNamedRecord(..)) import Data.Text as Text (Text, concat, foldl', pack, snoc) import GEODE.Metadata.SplitContext (Field(..), SplitContext(..), next) -import GEODE.Metadata.TSV.Header - (DefaultFields(..), HasDefaultHeader(..), HasDefaultHeader(..)) import GHC.Generics (Generic) data Entry = Entry @@ -17,12 +15,10 @@ data Entry = Entry , name :: Text , page :: Int } deriving (Generic, Show) +instance DefaultOrdered Entry instance FromNamedRecord Entry instance ToNamedRecord Entry -instance HasDefaultHeader Entry where - defaultFields = DefaultFields [ "headword", "name", "page" ] - normalize :: Text -> Text normalize = Text.foldl' appendIf mempty where diff --git a/lib/GEODE/Metadata/TSV/Header.hs b/lib/GEODE/Metadata/TSV/Header.hs index 6e084e628230f23e007fe6d9d711ab2f0a7d2b04..7d9157df66abc5e57f0f07382d369a62bf829c95 100644 --- a/lib/GEODE/Metadata/TSV/Header.hs +++ b/lib/GEODE/Metadata/TSV/Header.hs @@ -1,38 +1,27 @@ {-# LANGUAGE ExplicitNamespaces, ScopedTypeVariables, TypeOperators #-} module GEODE.Metadata.TSV.Header - ( DefaultFields(..) - , HasDefaultHeader(..) - , WithDefaultHeader(..) + ( WithDefaultHeader(..) , for , getHeader , glue ) where -import Data.ByteString.Char8 as StrictByteString (pack) -import Data.Csv (Header, ToNamedRecord(..), ToRecord(..)) +import Data.Csv (DefaultOrdered(..), Header, ToNamedRecord(..), ToRecord(..)) import Data.HashMap.Strict ((!)) -import Data.Vector (fromList) import GEODE.Metadata.Types (type (@)(..)) newtype WithDefaultHeader a = WithDefaultHeader a -newtype DefaultFields a = DefaultFields [String] -class HasDefaultHeader a where - defaultFields :: DefaultFields a -instance (HasDefaultHeader a, HasDefaultHeader b) => HasDefaultHeader (a @ b) where - defaultFields = DefaultFields (a ++ b) - where - DefaultFields a = (defaultFields :: DefaultFields a) - DefaultFields b = (defaultFields :: DefaultFields b) +-- | An alias to shorten and make more intuitive the magic of +-- the DefaultOrdered class type +getHeader :: DefaultOrdered a => a -> Header +getHeader = headerOrder -getHeader :: forall a. HasDefaultHeader a => a -> Header -getHeader _ = StrictByteString.pack <$> fromList fields - where - DefaultFields fields = (defaultFields :: DefaultFields a) - -for :: HasDefaultHeader a => a +-- | This is just `undefined`, but nicer to read and making more sense with the +-- type notation `(for :: SomeTypeOfYours)` +for :: DefaultOrdered a => a for = undefined -instance (HasDefaultHeader a, ToNamedRecord a) => ToRecord (WithDefaultHeader a) where +instance (DefaultOrdered a, ToNamedRecord a) => ToRecord (WithDefaultHeader a) where toRecord (WithDefaultHeader a) = (toNamedRecord a !) <$> getHeader a glue :: a -> b -> WithDefaultHeader (a @ b) diff --git a/lib/GEODE/Metadata/Types.hs b/lib/GEODE/Metadata/Types.hs index 881168ab4151b7cb4799af160d1b204e8b72a3cb..e8ff47afd39f9762f20b337b6bbc4b65cc3e36b6 100644 --- a/lib/GEODE/Metadata/Types.hs +++ b/lib/GEODE/Metadata/Types.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE ExplicitNamespaces, FlexibleInstances, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE ExplicitNamespaces, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeOperators, UndecidableInstances #-} module GEODE.Metadata.Types ( Has(..) , ToJSONObject(..) @@ -6,7 +6,7 @@ module GEODE.Metadata.Types import Data.Aeson (FromJSON(..), Object, Series, ToJSON(..), Value(..), pairs) import Data.Aeson.KeyMap as Object (union) -import Data.Csv (FromNamedRecord(..), ToNamedRecord(..)) +import Data.Csv (DefaultOrdered(..), FromNamedRecord(..), ToNamedRecord(..)) import Data.HashMap.Strict as Hash (union) infixl 9 @ @@ -25,6 +25,9 @@ instance Has a b => Has a (b @ c) where instance {-# OVERLAPS #-} Has b (a @ b) where get (_ :@: b) = b +instance (DefaultOrdered a, DefaultOrdered b) => DefaultOrdered (a @ b) where + headerOrder _ = headerOrder (undefined :: a) <> headerOrder (undefined :: b) + instance (ToNamedRecord a, ToNamedRecord b) => ToNamedRecord (a @ b) where toNamedRecord (a :@: b) = Hash.union (toNamedRecord a) (toNamedRecord b) diff --git a/test/GEODE/Metadata/TestArticleRecord.hs b/test/GEODE/Metadata/TestArticleRecord.hs index 87ade5597b9b7b2fe59582fd3fedb4fb5a5c061a..139e4d5a53bedb74e5922cd10cea05db3ad97446 100644 --- a/test/GEODE/Metadata/TestArticleRecord.hs +++ b/test/GEODE/Metadata/TestArticleRecord.hs @@ -5,7 +5,7 @@ import Data.Csv (ToNamedRecord(..)) import Data.Foldable (toList) import Data.HashMap.Strict ((!?)) import GEODE.Metadata (Work(..), ArticleRecord(..)) -import GEODE.Metadata.TSV.Header (getHeader, for) +import GEODE.Metadata (getHeader, for) import Test.HUnit (Test(..), (~?=)) import Test.HUnit.Extra (isJust) diff --git a/test/GEODE/Metadata/TestEntry.hs b/test/GEODE/Metadata/TestEntry.hs index bf31fc76cca625834bd486d6190a80c28539accc..3b4f92bd11191bda3278dcba5bad6add80557e2d 100644 --- a/test/GEODE/Metadata/TestEntry.hs +++ b/test/GEODE/Metadata/TestEntry.hs @@ -5,9 +5,8 @@ import Data.Csv (ToNamedRecord(..)) import Data.Foldable (toList) import Data.HashMap.Strict ((!?)) import Data.Text (dropEnd) -import GEODE.Metadata (evalSplit, newEntry, normalize) +import GEODE.Metadata (evalSplit, for, getHeader, newEntry, normalize) import GEODE.Metadata.Entry (Entry(..)) -import GEODE.Metadata.TSV.Header (getHeader, for) import Test.HUnit (Test(..), (~?=)) import Test.HUnit.Extra (isJust)