packages feed

tweet-hs 1.0.0.1 → 1.0.1.0

raw patch · 8 files changed

+135/−100 lines, 8 filesdep −hspec-megaparsecdep ~megaparsecPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: hspec-megaparsec

Dependency ranges changed: megaparsec

API changes (from Hackage documentation)

- Web.Tweet: showTweets :: Bool -> Either (ParseError Char Dec) Timeline -> String
+ Web.Tweet: showTweets :: Bool -> Either (ParseError Char Void) Timeline -> String
- Web.Tweet.API: deleteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: deleteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: deleteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: deleteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: favoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: favoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: getProfile :: String -> Int -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: getProfile :: String -> Int -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: getProfileMax :: String -> Int -> FilePath -> Maybe Int -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: getProfileMax :: String -> Int -> FilePath -> Maybe Int -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: getProfileMaxMem :: String -> Int -> Config -> Maybe Int -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: getProfileMaxMem :: String -> Int -> Config -> Maybe Int -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: getTimeline :: Int -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: getTimeline :: Int -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: getTimelineMem :: Int -> Config -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: getTimelineMem :: Int -> Config -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: mentions :: Int -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: mentions :: Int -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: mentionsMem :: Int -> Config -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: mentionsMem :: Int -> Config -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: retweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: retweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: retweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: retweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: unfavoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: unfavoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: unfavoriteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: unfavoriteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: unretweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: unretweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline)
- Web.Tweet.API: unretweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)
+ Web.Tweet.API: unretweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline)

Files

src/Web/Tweet/API.hs view
@@ -3,14 +3,15 @@ -- | Module containing the functions directly dealing with twitter's API. Most functions in this module have two versions - one which takes a path to a TOML file containing api keys/secrets and tokens/secrets, the other takes api keys/secrets and tokens/secrets as an argument. module Web.Tweet.API where +import           Control.Lens+import           Control.Monad import qualified Data.ByteString.Lazy.Char8 as BSL-import Web.Tweet.Types-import Web.Tweet.Utils-import Control.Monad-import Control.Lens-import Text.Megaparsec.Error-import Web.Tweet.Utils.API-import Data.Composition+import           Data.Composition+import           Data.Void+import           Text.Megaparsec.Error+import           Web.Tweet.Types+import           Web.Tweet.Utils+import           Web.Tweet.Utils.API  -- | Get tweets (text only) for some user getMarkov :: String -> Maybe Int -> FilePath -> IO [String]@@ -21,7 +22,7 @@ getAll screenName maxId filepath = do     tweets <- either (error "Parse tweets failed") id <$> getProfileMax screenName 200 filepath maxId     let lastId = _tweetId . last $ tweets-    if (Just lastId) == maxId then +    if (Just lastId) == maxId then         pure []     else         do@@ -46,11 +47,11 @@     pure . (view tweetId) . head . either (error "failed to parse tweet") id . getTweets . BSL.toStrict $ bytes  -- | Gets user profile with max_id set.-getProfileMax :: String -> Int -> FilePath -> Maybe Int -> IO (Either (ParseError Char Dec) Timeline)+getProfileMax :: String -> Int -> FilePath -> Maybe Int -> IO (Either (ParseError Char Void) Timeline) getProfileMax = fmap (getTweets . BSL.toStrict) .*** getProfileRaw  -- | Gets user profile with max_id set.-getProfileMaxMem :: String -> Int -> Config -> Maybe Int -> IO (Either (ParseError Char Dec) Timeline)+getProfileMaxMem :: String -> Int -> Config -> Maybe Int -> IO (Either (ParseError Char Void) Timeline) getProfileMaxMem = fmap (getTweets . BSL.toStrict) .*** getProfileRawMem  -- | Gets user profile with max_id set.@@ -68,11 +69,11 @@         Nothing -> "?screen_name=" ++ screenName ++ "&count=" ++ (show count) }  -- | Get mentions and parse response as a list of tweets-mentions :: Int -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+mentions :: Int -> FilePath -> IO (Either (ParseError Char Void) Timeline) mentions = fmap (getTweets . BSL.toStrict) .* mentionsRaw  -- | Get mentions and parse response as a list of tweets-mentionsMem :: Int -> Config -> IO (Either (ParseError Char Dec) Timeline)+mentionsMem :: Int -> Config -> IO (Either (ParseError Char Void) Timeline) mentionsMem = fmap (getTweets . BSL.toStrict) .* mentionsRawMem  -- | Gets mentions@@ -86,7 +87,7 @@     where requestString = "?count=" ++ (show count)  -- | Get user profile given screen name and how many tweets to return-getProfile :: String -> Int -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+getProfile :: String -> Int -> FilePath -> IO (Either (ParseError Char Void) Timeline) getProfile screenName count filepath = getProfileMax screenName count filepath Nothing  -- | Mute a user given their screen name@@ -126,11 +127,11 @@     where requestString = "?count=" ++ (show count)  -- | Get a timeline-getTimeline :: Int -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+getTimeline :: Int -> FilePath -> IO (Either (ParseError Char Void) Timeline) getTimeline = (fmap (getTweets . BSL.toStrict)) .* getTimelineRaw  -- | Get a timeline-getTimelineMem :: Int -> Config -> IO (Either (ParseError Char Dec) Timeline)+getTimelineMem :: Int -> Config -> IO (Either (ParseError Char Void) Timeline) getTimelineMem = (fmap (getTweets . BSL.toStrict)) .* getTimelineRawMem  -- | Get a user's timeline and return response as a bytestring@@ -152,11 +153,11 @@ deleteTweetMem = (fmap void) . deleteTweetRawMem  -- | Get response, i.e. the tweet deleted-deleteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+deleteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) deleteTweetResponse = fmap (getTweets . BSL.toStrict) .* deleteTweetRaw  -- | Get response, i.e. the tweet deleted-deleteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)+deleteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) deleteTweetResponseMem = fmap (getTweets . BSL.toStrict) .* deleteTweetRawMem  -- | Favorite a tweet given its id@@ -168,7 +169,7 @@ favoriteTweetMem = (fmap void) . favoriteTweetRawMem  -- | Favorite a tweet and returned the (parsed) response-favoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+favoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) favoriteTweetResponse = fmap (getTweets . BSL.toStrict) .* favoriteTweetRaw  -- | Unfavorite a tweet given its id@@ -180,11 +181,11 @@ unfavoriteTweetMem = (fmap void) . unfavoriteTweetRawMem  -- | Unfavorite a tweet and returned the (parsed) response-unfavoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+unfavoriteTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) unfavoriteTweetResponse = fmap (getTweets . BSL.toStrict) .* unfavoriteTweetRaw  -- | Unfavorite a tweet and returned the (parsed) response-unfavoriteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)+unfavoriteTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) unfavoriteTweetResponseMem = fmap (getTweets . BSL.toStrict) .* unfavoriteTweetRawMem  -- | Unretweet a tweet given its id@@ -196,11 +197,11 @@ unretweetTweetMem = (fmap void) . unretweetTweetRawMem  -- | Unretweet a tweet and returned the (parsed) response-unretweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+unretweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) unretweetTweetResponse = fmap (getTweets . BSL.toStrict) .* unretweetTweetRaw  -- | Unretweet a tweet and returned the (parsed) response-unretweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)+unretweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) unretweetTweetResponseMem = fmap (getTweets . BSL.toStrict) .* unretweetTweetRawMem  -- | Unfollow a user given their screen name@@ -244,11 +245,11 @@ retweetTweetMem = (fmap void) . retweetTweetRawMem  -- | Retweet a tweet and returned the (parsed) response-retweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Dec) Timeline)+retweetTweetResponse :: Integer -> FilePath -> IO (Either (ParseError Char Void) Timeline) retweetTweetResponse = fmap (getTweets . BSL.toStrict) .* retweetTweetRaw  -- | Retweet a tweet and returned the (parsed) response-retweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Dec) Timeline)+retweetTweetResponseMem :: Integer -> Config -> IO (Either (ParseError Char Void) Timeline) retweetTweetResponseMem = fmap (getTweets . BSL.toStrict) .* retweetTweetRawMem  -- | Favorite a tweet given its id; return bytestring response
src/Web/Tweet/API/Internal.hs view
@@ -3,17 +3,18 @@ -- | Helper functions for the command line tool. module Web.Tweet.API.Internal where -import Web.Tweet.API-import Web.Tweet.Types-import Web.Tweet.Utils-import Text.Megaparsec.Error+import           Data.Void+import           Text.Megaparsec.Error+import           Web.Tweet.API+import           Web.Tweet.Types+import           Web.Tweet.Utils --- | Show a user profile given screen name, how many tweets to return, +-- | Show a user profile given screen name, how many tweets to return, -- and whether to print them in color. showProfile :: String -> Int -> Bool -> FilePath -> IO String showProfile screenName count color = fmap (showTweets color) . getProfile screenName count --- | Show the most successful tweets by a given user, given their screen name. +-- | Show the most successful tweets by a given user, given their screen name. showBest :: String -> Int -> Bool -> FilePath -> IO String showBest screenName n color = fmap (showTweets color . pure . (take n . hits)) . getAll screenName Nothing @@ -23,8 +24,8 @@  -- | Display user timeline showTimeline :: Int -> Bool -> FilePath -> IO String-showTimeline count color = (fmap (showTweets color)) . getTimeline count +showTimeline count color = (fmap (showTweets color)) . getTimeline count  -- | Display user timeline in color, as appropriate-showTweets :: Bool -> Either (ParseError Char Dec) Timeline -> String+showTweets :: Bool -> Either (ParseError Char Void) Timeline -> String showTweets color = (either show id) . (fmap (if color then displayTimelineColor else displayTimeline))
src/Web/Tweet/Exec.hs view
@@ -140,6 +140,8 @@         <> command "dump" (info dump (progDesc "Dump tweets (for debugging)"))         <> command "block" (info blockParser (progDesc "Block a user"))         <> command "unblock" (info unblockParser (progDesc "Unblock a user"))+        <> command "mute" (info muteParser (progDesc "Mute a user"))+        <> command "unmute" (info unmuteParser (progDesc "Unmute a user"))         <> command "mentions" (info mentionsParser (progDesc "Fetch mentions"))))     <*> (optional $ strOption         (long "cred"@@ -184,6 +186,14 @@ -- | Parser for the unfollow subcommand unfol :: Parser Command unfol = Unfollow <$> user++-- | Parser for the unfollow subcommand+muteParser :: Parser Command+muteParser = Mute <$> user++-- | Parser for the unfollow subcommand+unmuteParser :: Parser Command+unmuteParser = Unmute <$> user  -- | Parse a user screen name user :: Parser String
src/Web/Tweet/Parser.hs view
@@ -4,9 +4,11 @@                         , getData ) where  import qualified Data.ByteString as BS-import Text.Megaparsec.ByteString-import Text.Megaparsec.Lexer as L+import qualified Data.ByteString.Char8 as BSW import Text.Megaparsec+import Text.Megaparsec.Byte+import Text.Megaparsec.Byte.Lexer as L+import Text.Megaparsec import Web.Tweet.Types import Data.Monoid import qualified Data.Map as M@@ -14,7 +16,11 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as TE import Control.Monad+import Data.Void+import Data.Word +type Parser = Parsec Void String+ -- | Parse some number of tweets parseTweet :: Parser Timeline parseTweet = many (try getData <|> (const (TweetEntity "" "" "" 0 Nothing 0 0) <$> eof))@@ -96,10 +102,10 @@     string "\\ud"     str1 <- count 3 anyChar     str2 <- string "\\ud" >> count 3 anyChar-    let num = decodeUtf16 $ "d" <> str1 <> "d" <> str2-    pure . head $ num+    let num = TE.decodeUtf16BE . BSW.pack $ "d" <> str1 <> "d" <> str2+    pure . T.head $ num -decodeUtf16 = T.unpack . TE.decodeUtf16BE . BS.concat . go+decodeUtf16 = TE.decodeUtf16BE . BS.concat . go     where         go []             = []         go (a:b:c:d:rest) = let sym = convert16 [a,b] [c,d] in sym : go rest@@ -122,11 +128,11 @@ -- | Parse escaped characters specialChar :: Char -> Parser Char specialChar c = do-    string $ "\\" ++ pure c+    string $ (c:"\\")     pure c  -- | Convert a string of four hexadecimal digits to an integer. fromHex :: BS.ByteString -> Integer-fromHex = fromRight . (parse (L.hexadecimal :: Parser Integer) "")-    where fromRight (Right a) = a-          fromRight (Left x) = error (show x)+fromHex = fromRight . (parseMaybe (L.hexadecimal :: Parsec Void BS.ByteString Integer))+    where fromRight (Just a) = a+          fromRight _        = error "failed to parse hex"
src/Web/Tweet/Utils.hs view
@@ -15,11 +15,12 @@ import qualified Data.ByteString.Char8       as BS import           Data.List import           Data.List.Extra-import           Web.Tweet.Parser.FastParser hiding (text)+import           Data.Void+import           Text.Megaparsec import           Web.Tweet.Parser+import           Web.Tweet.Parser.FastParser hiding (text) import           Web.Tweet.Types import           Web.Tweet.Utils.Colors-import Text.Megaparsec  -- | filter out retweets, and sort by most successful. hits :: Timeline -> Timeline@@ -41,9 +42,9 @@ filterQuotes :: Timeline -> Timeline filterQuotes = filter ((==Nothing) . (view quoted)) --- | Get a list of tweets from a response, returning author, favorites, retweets, and content. -getTweets :: BS2.ByteString -> Either (ParseError Char Dec) Timeline-getTweets = parse parseTweet "" +-- | Get a list of tweets from a response, returning author, favorites, retweets, and content.+getTweets :: BS2.ByteString -> Either (ParseError Char Void) Timeline+getTweets = parse parseTweet "" . BS.unpack  -- | Get a list of tweets from a response, returning author, favorites, retweets, and content. -- This version uses aeson, which it's far faster, but also has worse error messages.
stack.yaml view
@@ -1,39 +1,66 @@-resolver: lts-8.19+# This file was automatically generated by 'stack init'+#+# Some commonly used options have been documented as comments in this file.+# For advanced use and comprehensive documentation of the format, please see:+# https://docs.haskellstack.org/en/stable/yaml_configuration/++# Resolver to choose a 'specific' stackage snapshot or a compiler version.+# A snapshot resolver dictates the compiler version and the set of packages+# to be used for project dependencies. For example:+#+# resolver: lts-3.5+# resolver: nightly-2015-09-21+# resolver: ghc-7.10.2+# resolver: ghcjs-0.1.0_ghc-7.10.2+# resolver:+#  name: custom-snapshot+#  location: "./custom-snapshot.yaml"+resolver: lts-9.0++# User packages to be built.+# Various formats can be used as shown in the example below.+#+# packages:+# - some-directory+# - https://example.com/foo/bar/baz-0.0.2.tar.gz+# - location:+#    git: https://github.com/commercialhaskell/stack.git+#    commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a+# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a+#   extra-dep: true+#  subdirs:+#  - auto-update+#  - wai+#+# A package marked 'extra-dep: true' will only be built if demanded by a+# non-dependency (i.e. a user package), and its test suites and benchmarks+# will not be run. This is useful for tweaking upstream packages. packages:- - .- - extra-dep: true-   location:-       git: https://github.com/haskell/deepseq-       commit: 0b22c9825ef79c1ee41d2f19e7c997f5cdc93494- - extra-dep: true-   location:-       git: https://github.com/ekmett/semigroupoids.git-       commit: c3297f970658ae874db098190327ec742044a2e6- - extra-dep: true-   location:-       git: http://github.com/ekmett/lens.git-       commit: 7031e00f62a704a86c3149c75c1e2afc059af022- - extra-dep: true-   location:-       git: https://github.com/dreixel/syb.git-       commit: f584ecd525179778063df2eb02dc6bbe406d7e75-flags:-    tweet-hs:-        llvm-fast: true-        parallel-gc: false-ghc-options:-    tweet-hs: -fdiagnostics-color=always-allow-newer: true-compiler: ghc-8.2.0.20170507-compiler-check: match-exact-setup-info:- ghc:-  linux64:-   8.2.0.20170507:-    url: https://downloads.haskell.org/~ghc/8.2.1-rc2/ghc-8.2.0.20170507-x86_64-deb8-linux.tar.xz-  macosx:-   8.2.0.20170507:-    url: https://downloads.haskell.org/~ghc/8.2.1-rc2/ghc-8.2.0.20170507-x86_64-apple-darwin.tar.xz-  windows64:-   8.2.0.20170507:-    url: https://downloads.haskell.org/~ghc/8.2.1-rc2/ghc-8.2.0.20170507-x86_64-unknown-mingw32.tar.xz+- .+# Dependency packages to be pulled from upstream that are not in the resolver+# (e.g., acme-missiles-0.3)+extra-deps: []++# Override default flag values for local packages and extra-deps+flags: {}++# Extra package databases containing global packages+extra-package-dbs: []++# Control whether we use the GHC we find on the path+# system-ghc: true+#+# Require a specific version of stack, using version ranges+# require-stack-version: -any # Default+# require-stack-version: ">=1.5"+#+# Override the architecture used by stack, especially useful on Windows+# arch: i386+# arch: x86_64+#+# Extra directories used by stack for building+# extra-include-dirs: [/path/to/dir]+# extra-lib-dirs: [/path/to/dir]+#+# Allow a newer minor version of GHC than the snapshot specifies+# compiler-check: newer-minor
test/Spec.hs view
@@ -2,28 +2,19 @@  import qualified Data.ByteString             as BS import           Test.Hspec-import Test.Hspec.Megaparsec import           Web.Tweet.Parser.FastParser-import Web.Tweet.Parser import Web.Tweet.Sign import Data.Monoid-import Text.Megaparsec import System.Environment import Test.QuickCheck  main :: IO () main = hspec $ do-    describe "aeson parser" $ do-        file <- runIO $ BS.readFile "test/data"-        parallel $ it "parses sample tweets wrong" $ do-            fastParse "" `shouldBe` Left "Error in $: not enough input"-    describe "handrolled parser" $ do+    describe "fastParse" $ do         file <- runIO $ BS.readFile "test/data"-        parallel $ it "parses sample tweets right" $ do-            parse parseTweet "test suite" `shouldSucceedOn` file-    describe "config parser" $ do         config <- runIO $ (<> "/.cred") <$> getEnv "HOME"         configToml <- runIO $ (<> "/.cred.toml") <$> getEnv "HOME"+        parallel $ it "parses sample tweets wrong" $ do+            fastParse "" `shouldBe` Left "Error in $: not enough input"         parallel $ it "parses a config file the same way with the toml parser" $             ((==) <$> mkConfigToml configToml <*> mkConfig config) >>= (`shouldBe` True)-
tweet-hs.cabal view
@@ -1,5 +1,5 @@ name:                tweet-hs-version:             1.0.0.1+version:             1.0.1.0 synopsis:            Command-line tool for twitter description:         a Command Line Interface Tweeter homepage:            https://github.com/vmchale/command-line-tweeter#readme@@ -53,7 +53,7 @@                      , http-client                      , http-types                      , authenticate-oauth-                     , megaparsec+                     , megaparsec >= 6.0                      , bytestring                      , split                      , optparse-applicative @@ -120,8 +120,6 @@                      , hspec                      , QuickCheck                      , bytestring-                     , hspec-megaparsec-                     , megaparsec   if flag(gold)      ghc-options:       -optl-fuse-ld=gold     ld-options:        -fuse-ld=gold