packages feed

openweathermap 0.0.0 → 0.1.0

raw patch · 14 files changed

+154/−144 lines, 14 filesdep ~servant-clientsetup-changedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: servant-client

API changes (from Hackage documentation)

- Web.OpenWeatherMap.Types.Sys: [message] :: Sys -> Double
- Web.OpenWeatherMap.Client: getWeather :: String -> Location -> IO (Either ServantError CurrentWeather)
+ Web.OpenWeatherMap.Client: getWeather :: String -> Location -> IO (Either ClientError CurrentWeather)
- Web.OpenWeatherMap.Types.Sys: Sys :: Double -> Maybe String -> Int -> Int -> Sys
+ Web.OpenWeatherMap.Types.Sys: Sys :: Maybe String -> Int -> Int -> Sys

Files

ChangeLog.md view
@@ -1,3 +1,12 @@+0.1.0+=====++  * Removed the `message` field from the `Sys` type.+    It was some internal parameter and might be absent.++  * Require servant-client >= 0.16 (for `ClientError` instead of `ServantError`).++ 0.0.0 ===== 
README.md view
@@ -7,7 +7,7 @@ ============  OpenWeatherMap is written in Haskell with [GHC](http://www.haskell.org/ghc/).-All required Haskell libraries are listed in [openweathermap.cabal](ldapply.cabal).+All required Haskell libraries are listed in [openweathermap.cabal](openweathermap.cabal). Use [cabal-install](http://www.haskell.org/haskellwiki/Cabal-Install) to fetch and build all pre-requisites automatically. @@ -36,7 +36,7 @@   -h,--help                Show this help text  ```-By default, `openweathermap` read the API key+By default, `openweathermap` reads the API key from the `$XDG_CONFIG_HOME/openweathermap/key` file, where [`$XDG_CONFIG_HOME`](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) is typically `~/.config` on Linux systems.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
cmd/Main.hs view
@@ -1,8 +1,8 @@ {-# LANGUAGE LambdaCase #-} -module Main (-  main-) where+module Main+  ( main+  ) where  import Control.Monad (when) import Data.List (intercalate)@@ -11,9 +11,24 @@ import System.Exit (die) import System.IO (IOMode(ReadMode), hGetLine, hPrint, stderr, withFile) -import Options.Applicative (-    (<**>), (<|>), Parser, auto, execParser, fullDesc, header, help, helper,-    info, long, metavar, option, optional, short, strOption, switch+import Options.Applicative+  ( Parser+  , (<**>)+  , (<|>)+  , auto+  , execParser+  , fullDesc+  , header+  , help+  , helper+  , info+  , long+  , metavar+  , option+  , optional+  , short+  , strOption+  , switch   ) import System.Directory (createDirectoryIfMissing) import System.Environment.XDG.BaseDir (getUserConfigDir, getUserConfigFile)@@ -33,22 +48,17 @@ parseLocation :: Parser Client.Location parseLocation = byName <|> byCoord   where-    byName = Client.Name <$> strOption-      (  long "city"-      <> short 'c'-      <> metavar "CITY"-      <> help "City name" )--    byCoord = Client.Coord-      <$> option auto-        (  long "lat"-        <> metavar "NUM"-        <> help "Latitude in decimal degrees" )-      <*> option auto-        (  long "lon"-        <> metavar "NUM"-        <> help "Longitude in decimal degrees" )-+    byName =+      Client.Name <$>+      strOption (long "city" <> short 'c' <> metavar "CITY" <> help "City name")+    byCoord =+      Client.Coord <$>+      option+        auto+        (long "lat" <> metavar "NUM" <> help "Latitude in decimal degrees") <*>+      option+        auto+        (long "lon" <> metavar "NUM" <> help "Longitude in decimal degrees")  data ApiKey   = ApiKeyFile FilePath@@ -57,18 +67,15 @@ parseApiKey :: Parser ApiKey parseApiKey = fromFile <|> inCmdLine   where-    fromFile = ApiKeyFile <$> strOption-      (  long "api-key-file"-      <> short 'K'-      <> metavar "APIKEYFILE"-      <> help "Read API key from this file" )--    inCmdLine = ApiKey <$> strOption-      (  long "api-key"-      <> short 'k'-      <> metavar "APIKEY"-      <> help "API key" )-+    fromFile =+      ApiKeyFile <$>+      strOption+        (long "api-key-file" <> short 'K' <> metavar "APIKEYFILE" <>+         help "Read API key from this file")+    inCmdLine =+      ApiKey <$>+      strOption+        (long "api-key" <> short 'k' <> metavar "APIKEY" <> help "API key")  data Config = Config   { apikey :: Maybe ApiKey@@ -77,10 +84,9 @@   }  parseConfig :: Parser Config-parseConfig = Config-          <$> optional parseApiKey-          <*> parseLocation-          <*> switch (long "debug" <> short 'd' <> help "Enable debug")+parseConfig =+  Config <$> optional parseApiKey <*> parseLocation <*>+  switch (long "debug" <> short 'd' <> help "Enable debug")  getApiKey :: Maybe ApiKey -> IO String getApiKey (Just (ApiKey key)) = return key@@ -89,16 +95,18 @@   createDirectoryIfMissing True =<< getUserConfigDir appName   getUserConfigFile appName "key" >>= getApiKey . Just . ApiKeyFile - showLocation :: CurrentWeather.CurrentWeather -> String showLocation w = city ++ maybe "" ("," ++) country ++ " " ++ coords   where     name = CurrentWeather.name w     coord = CurrentWeather.coord w     country = Sys.country . CurrentWeather.sys $ w-    city = if name /= "" then name else "<unknown>"-    coords = "("++ show (Coord.lat coord) ++ "°, "-                ++ show (Coord.lon coord) ++ "°)"+    city =+      if name /= ""+        then name+        else "<unknown>"+    coords =+      "(" ++ show (Coord.lat coord) ++ "°, " ++ show (Coord.lon coord) ++ "°)"  showWeather :: [Weather.Weather] -> String showWeather w = intercalate "," $ Weather.main <$> w@@ -125,7 +133,7 @@     speed = round . Wind.speed $ w     deg = Wind.deg w     --     [ "N", "NE", "E", "SE", "S", "SW", "W", "NW" ]-    dirs = [ "↓", "↙",  "←", "↖",  "↑", "↗",  "→", "↘"  ]+    dirs = ["↓", "↙", "←", "↖", "↑", "↗", "→", "↘"]     l = length dirs     sector = round $ (deg * fromIntegral l) / 360.0     dir = dirs !! (sector `rem` l)@@ -138,10 +146,14 @@     tmin :: Int     tmax = round . k2c . Main.temp_max $ m     tmin = round . k2c . Main.temp_min $ m-    show' t = if t > 0 then "+" ++ show t else show t-    temp = if tmax /= tmin-           then show' tmin ++ ".." ++ show' tmax-           else show' tmin+    show' t =+      if t > 0+        then "+" ++ show t+        else show t+    temp =+      if tmax /= tmin+        then show' tmin ++ ".." ++ show' tmax+        else show' tmin  printWeather :: CurrentWeather.CurrentWeather -> IO () printWeather w = putStrLn out@@ -150,15 +162,23 @@     place = showLocation w     mainw = CurrentWeather.main w     wind = CurrentWeather.wind w-    out = place ++ ": " ++ intercalate ",  "-      [ weather, showHumidity mainw, showPressure mainw, showTemp mainw,-        showWind wind ]+    out =+      place +++      ": " +++      intercalate+        ",  "+        [ weather+        , showHumidity mainw+        , showPressure mainw+        , showTemp mainw+        , showWind wind+        ]  run :: Config -> IO () run cfg = do   appid <- getApiKey . apikey $ cfg   Client.getWeather appid (location cfg) >>= \case-    Left err      -> die $ show err+    Left err -> die $ show err     Right weather -> do       when (debug cfg) $ hPrint stderr weather       printWeather weather@@ -167,7 +187,7 @@ main = run =<< execParser opts   where     opts = info (parseConfig <**> helper) (fullDesc <> header desc)-    desc = "openweathermap "-        ++ showVersion version-        ++ " - command-line client for https://openweathermap.org/api"-+    desc =+      "openweathermap " +++      showVersion version +++      " - command-line client for https://openweathermap.org/api"
lib/Web/OpenWeatherMap/API.hs view
@@ -2,44 +2,37 @@ Direct API functions. For API key (a.k.a appid) refer to <http://openweathermap.org/appid>. -}- {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeOperators #-} -module Web.OpenWeatherMap.API (-  weatherByName,-  weatherByCoord-) where+module Web.OpenWeatherMap.API+  ( weatherByName+  , weatherByCoord+  ) where  import Data.Proxy (Proxy(..)) -import Servant.API ((:>), (:<|>)(..), JSON, Get, QueryParam)-import Servant.Client (client)-import Servant.Common.Req (ClientM)+import Servant.API ((:<|>)(..), (:>), Get, JSON, QueryParam)+import Servant.Client (ClientM, client)  import Web.OpenWeatherMap.Types.CurrentWeather (CurrentWeather) +type GetCurrentWeather = AppId :> Get '[ JSON] CurrentWeather -type GetCurrentWeather = AppId :> Get '[JSON] CurrentWeather type AppId = QueryParam "appid" String  type API-     = "weather" :> QueryParam "q" String :> GetCurrentWeather-  :<|> "weather" :> QueryParam "lat" Double :> QueryParam "lon" Double-                 :> GetCurrentWeather+   = "weather" :> QueryParam "q" String :> GetCurrentWeather :<|> "weather" :> QueryParam "lat" Double :> QueryParam "lon" Double :> GetCurrentWeather  -- | Request current weather in the city.-weatherByName-  :: Maybe String  -- ^ City name, e. g. \"Moscow\" or \"Moscow,ru\".-  -> Maybe String  -- ^ API key.+weatherByName ::+     Maybe String -- ^ City name, e. g. \"Moscow\" or \"Moscow,ru\".+  -> Maybe String -- ^ API key.   -> ClientM CurrentWeather- -- | Request current weather at the geographic coordinates (in decimal degrees).-weatherByCoord-  :: Maybe Double  -- ^ Latitude, e. g. 55.7522200 for Moscow.-  -> Maybe Double  -- ^ Longitude, e. g. 37.6155600 for Moscow.-  -> Maybe String  -- ^ API key.+weatherByCoord ::+     Maybe Double -- ^ Latitude, e. g. 55.7522200 for Moscow.+  -> Maybe Double -- ^ Longitude, e. g. 37.6155600 for Moscow.+  -> Maybe String -- ^ API key.   -> ClientM CurrentWeather- weatherByName :<|> weatherByCoord = client (Proxy :: Proxy API)-
lib/Web/OpenWeatherMap/Client.hs view
@@ -1,38 +1,42 @@ {-| High-level client functions perfoming requests to OpenWeatherMap API. -}-module Web.OpenWeatherMap.Client (-  Location(..),-  getWeather-) where+module Web.OpenWeatherMap.Client+  ( Location(..)+  , getWeather+  ) where -import Network.HTTP.Client (newManager, defaultManagerSettings)-import Servant.Client (ClientEnv(..), runClientM, ServantError)-import Servant.Common.BaseUrl (BaseUrl(..), Scheme(..))-import Servant.Common.Req (ClientM)+import Network.HTTP.Client (defaultManagerSettings, newManager)+import Servant.Client+  ( BaseUrl(BaseUrl)+  , ClientEnv+  , ClientError+  , ClientM+  , Scheme(Http)+  , mkClientEnv+  , runClientM+  ) -import Web.OpenWeatherMap.Types.CurrentWeather (CurrentWeather) import qualified Web.OpenWeatherMap.API as API-+import Web.OpenWeatherMap.Types.CurrentWeather (CurrentWeather)  -- | Various way to specify location. data Location-  = Name String          -- ^ City name.-  | Coord Double Double  -- ^ Geographic coordinates: latitude and longitude.-+  = Name String -- ^ City name.+  | Coord Double+          Double -- ^ Geographic coordinates: latitude and longitude.  -- | Make a request to OpenWeatherMap API --   and return current weather in given location.-getWeather-  :: String -- ^ API key.+getWeather ::+     String -- ^ API key.   -> Location-  -> IO (Either ServantError CurrentWeather)-getWeather appid loc =-  defaultEnv >>= runClientM (api loc appid)+  -> IO (Either ClientError CurrentWeather)+getWeather appid loc = defaultEnv >>= runClientM (api loc appid) -api-  :: Location-  -> String                  -- ^ API key.+api ::+     Location+  -> String -- ^ API key.   -> ClientM CurrentWeather api (Name city) = API.weatherByName (Just city) . Just api (Coord lat lon) = API.weatherByCoord (Just lat) (Just lon) . Just@@ -40,10 +44,9 @@ defaultEnv :: IO ClientEnv defaultEnv = do   manager <- newManager defaultManagerSettings-  return $ ClientEnv manager baseUrl+  return $ mkClientEnv manager baseUrl  -- XXX openweathermap.org does not support HTTPS, -- XXX appid is passed in clear text. Oops. baseUrl :: BaseUrl baseUrl = BaseUrl Http "api.openweathermap.org" 80 "/data/2.5"-
lib/Web/OpenWeatherMap/Types/Clouds.hs view
@@ -1,16 +1,14 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module Web.OpenWeatherMap.Types.Clouds (-  Clouds(..)-) where+module Web.OpenWeatherMap.Types.Clouds+  ( Clouds(..)+  ) where  import GHC.Generics (Generic)  import Data.Aeson (FromJSON)-   data Clouds = Clouds   { all :: Double   } deriving (Show, Generic, FromJSON)-
lib/Web/OpenWeatherMap/Types/Coord.hs view
@@ -1,17 +1,15 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module Web.OpenWeatherMap.Types.Coord (-  Coord(..)-) where+module Web.OpenWeatherMap.Types.Coord+  ( Coord(..)+  ) where  import GHC.Generics (Generic)  import Data.Aeson (FromJSON) - data Coord = Coord   { lon :: Double   , lat :: Double   } deriving (Show, Generic, FromJSON)-
lib/Web/OpenWeatherMap/Types/CurrentWeather.hs view
@@ -1,12 +1,12 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module Web.OpenWeatherMap.Types.CurrentWeather (-  CurrentWeather(..)-) where+module Web.OpenWeatherMap.Types.CurrentWeather+  ( CurrentWeather(..)+  ) where -import Prelude hiding (id) import GHC.Generics (Generic)+import Prelude hiding (id)  import Data.Aeson (FromJSON) @@ -32,4 +32,3 @@   , name :: String   , cod :: Int   } deriving (Show, Generic, FromJSON)-
lib/Web/OpenWeatherMap/Types/Main.hs view
@@ -1,16 +1,16 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module Web.OpenWeatherMap.Types.Main (-  Main(..)-) where+module Web.OpenWeatherMap.Types.Main+  ( Main(..)+  ) where  import GHC.Generics (Generic)  import Data.Aeson (FromJSON)-   {-# ANN module "HLint: ignore Use camelCase" #-}+ data Main = Main   { temp :: Double   , pressure :: Double@@ -20,4 +20,3 @@   , sea_level :: Maybe Double   , grnd_level :: Maybe Double   } deriving (Show, Generic, FromJSON)-
lib/Web/OpenWeatherMap/Types/Sys.hs view
@@ -1,19 +1,16 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module Web.OpenWeatherMap.Types.Sys (-  Sys(..)-) where+module Web.OpenWeatherMap.Types.Sys+  ( Sys(..)+  ) where  import GHC.Generics (Generic)  import Data.Aeson (FromJSON)-   data Sys = Sys-  { message :: Double-  , country :: Maybe String+  { country :: Maybe String   , sunrise :: Int   , sunset :: Int   } deriving (Show, Generic, FromJSON)-
lib/Web/OpenWeatherMap/Types/Weather.hs view
@@ -1,19 +1,17 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module Web.OpenWeatherMap.Types.Weather (-  Weather(..)-) where+module Web.OpenWeatherMap.Types.Weather+  ( Weather(..)+  ) where  import GHC.Generics (Generic)  import Data.Aeson (FromJSON) - data Weather = Weather   { id :: Int   , main :: String   , description :: String   , icon :: String   } deriving (Show, Generic, FromJSON)-
lib/Web/OpenWeatherMap/Types/Wind.hs view
@@ -1,17 +1,15 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} -module Web.OpenWeatherMap.Types.Wind (-  Wind(..)-) where+module Web.OpenWeatherMap.Types.Wind+  ( Wind(..)+  ) where  import GHC.Generics (Generic)  import Data.Aeson (FromJSON)-   data Wind = Wind   { speed :: Double   , deg :: Double   } deriving (Show, Generic, FromJSON)-
openweathermap.cabal view
@@ -1,5 +1,5 @@ name: openweathermap-version: 0.0.0+version: 0.1.0 synopsis: Access data at OpenWeatherMap description: Client library and command-line utility to access   OpenWeatherMap https://openweathermap.org@@ -11,7 +11,7 @@ category: Web build-type: Simple extra-source-files: README.md ChangeLog.md-cabal-version: >= 1.20+cabal-version: 1.20  source-repository head   type: git@@ -30,7 +30,7 @@     , aeson     , http-client     , servant-    , servant-client >= 0.9+    , servant-client >= 0.16   exposed-modules:      Web.OpenWeatherMap.API      Web.OpenWeatherMap.Client