twitter-conduit 0.0.2.1 → 0.0.3
raw patch · 9 files changed
+180/−32 lines, 9 files
Files
- .travis.yml +29/−0
- Web/Twitter/Conduit/Api.hs +101/−14
- Web/Twitter/Conduit/Base.hs +2/−1
- Web/Twitter/Conduit/Cursor.hs +3/−0
- Web/Twitter/Conduit/Parameters.hs +4/−1
- Web/Twitter/Conduit/Request.hs +8/−1
- Web/Twitter/Conduit/Status.hs +27/−0
- tests/doctests.hs +3/−12
- twitter-conduit.cabal +3/−3
.travis.yml view
@@ -1,1 +1,30 @@ language: haskell++env:+ - GHCVER=7.4.2+ - GHCVER=7.6.3+ - GHCVER=7.8.2+ - GHCVER=head++matrix:+ allow_failures:+ - env: GHCVER=head++before_install:+ - travis_retry sudo add-apt-repository -y ppa:hvr/ghc+ - travis_retry sudo apt-get update+ - travis_retry sudo apt-get install cabal-install-1.18 ghc-$GHCVER+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/1.18/bin:$PATH++install:+ - export PATH=$HOME/.cabal/bin:$PATH+ - which cabal+ - cabal update+ - cabal install happy --constraint="transformers < 0.4"+ - cabal install --only-dependencies --enable-tests+ - ghc-pkg list++script:+ - cabal configure --enable-tests+ - cabal build+ - cabal test --show-details=always
Web/Twitter/Conduit/Api.hs view
@@ -11,7 +11,8 @@ module Web.Twitter.Conduit.Api ( -- * Search- Search+ SearchTweets+ , searchTweets , search -- * Direct Messages@@ -27,17 +28,20 @@ , directMessagesNew -- * Friends & Followers- -- , friendshipsNoRetweetsIds+ , FriendshipsNoRetweetsIds+ , friendshipsNoRetweetsIds , FriendsIds , friendsIds , FollowersIds , followersIds- -- , friendshipsLookup- -- , friendshipsIncoming- -- , friendshipsOutgoing+ , FriendshipsIncoming+ , friendshipsIncoming+ , FriendshipsOutgoing+ , friendshipsOutgoing , FriendshipsCreate , friendshipsCreate- -- , friendshipsDestroy+ , FriendshipsDestroy+ , friendshipsDestroy -- , friendshipsUpdate -- , friendshipsShow , FriendsList@@ -110,24 +114,24 @@ -- >>> :set -XOverloadedStrings -- >>> import Control.Lens -data Search+data SearchTweets -- | Returns search query. -- -- You can perform a search query using 'call': -- -- @--- res <- 'call' ('search' \"search text\")+-- res <- 'call' ('searchTweets' \"search text\") -- 'liftIO' . 'print' $ res ^. 'searchResultStatuses' -- @ ----- >>> search "search text"+-- >>> searchTweets "search text" -- APIRequestGet "https://api.twitter.com/1.1/search/tweets.json" [("q","search text")]--- >>> search "search text" & lang ?~ "ja" & count ?~ 100+-- >>> searchTweets "search text" & lang ?~ "ja" & count ?~ 100 -- APIRequestGet "https://api.twitter.com/1.1/search/tweets.json" [("count","100"),("lang","ja"),("q","search text")]-search :: T.Text -- ^ search string- -> APIRequest Search (SearchResult [SearchStatus])-search q = APIRequestGet (endpoint ++ "search/tweets.json") [("q", T.encodeUtf8 q)]-deriveHasParamInstances ''Search+searchTweets :: T.Text -- ^ search string+ -> APIRequest SearchTweets (SearchResult [SearchStatus])+searchTweets q = APIRequestGet (endpoint ++ "search/tweets.json") [("q", T.encodeUtf8 q)]+deriveHasParamInstances ''SearchTweets [ "lang" , "locale" -- , "result_type"@@ -139,6 +143,11 @@ -- , "callback" (needless) ] +-- | Alias of 'searchTweets', for backward compatibility+search :: T.Text -- ^ search string+ -> APIRequest SearchTweets (SearchResult [SearchStatus])+search = searchTweets+ data DirectMessages -- | Returns query data which asks recent direct messages sent to the authenticating user. --@@ -233,6 +242,20 @@ directMessagesNew :: UserParam -> T.Text -> APIRequest DirectMessagesNew DirectMessage directMessagesNew q msg = APIRequestPost (endpoint ++ "direct_messages/new.json") (("text", T.encodeUtf8 msg):mkUserParam q) +data FriendshipsNoRetweetsIds+-- | Returns a collection of user_ids that the currently authenticated user does not want to receive retweets from.+--+-- You can perform a request using 'call':+--+-- @+-- res <- 'call' '$' 'friendshipsNoRetweetsIds'+-- @+--+-- >>> friendshipsNoRetweetsIds+-- APIRequestGet "https://api.twitter.com/1.1/friendships/no_retweets/ids.json" []+friendshipsNoRetweetsIds :: APIRequest FriendshipsNoRetweetsIds [UserId]+friendshipsNoRetweetsIds = APIRequestGet (endpoint ++ "friendships/no_retweets/ids.json") []+ data FriendsIds -- | Returns query data which asks a collection of user IDs for every user the specified user is following. --@@ -287,6 +310,54 @@ , "count" ] +data FriendshipsIncoming+-- | Returns a collection of numeric IDs for every user who has a pending request to follow the authenticating user.+--+-- You can perform a request by using 'call':+--+-- @+-- res <- 'call' '$' 'friendshipsIncoming'+-- @+--+-- Or, you can iterate with 'sourceWithCursor':+--+-- @+-- 'sourceWithCursor' 'friendshipsIncoming' $$ CL.consume+-- @+--+-- >>> friendshipsIncoming+-- APIRequestGet "https://api.twitter.com/1.1/friendships/incoming.json" []+friendshipsIncoming :: APIRequest FriendshipsIncoming (WithCursor IdsCursorKey UserId)+friendshipsIncoming = APIRequestGet (endpoint ++ "friendships/incoming.json") def+deriveHasParamInstances ''FriendshipsIncoming+ [ "cursor"+ -- , "stringify_ids" -- (needless)+ ]++data FriendshipsOutgoing+-- | Returns a collection of numeric IDs for every protected user for whom the authenticating user has a pending follow request.+--+-- You can perform a request by using 'call':+--+-- @+-- res <- 'call' '$' 'friendshipsOutgoing'+-- @+--+-- Or, you can iterate with 'sourceWithCursor':+--+-- @+-- 'sourceWithCursor' 'friendshipsOutgoing' $$ CL.consume+-- @+--+-- >>> friendshipsOutgoing+-- APIRequestGet "https://api.twitter.com/1.1/friendships/outgoing.json" []+friendshipsOutgoing :: APIRequest FriendshipsOutgoing (WithCursor IdsCursorKey UserId)+friendshipsOutgoing = APIRequestGet (endpoint ++ "friendships/outgoing.json") def+deriveHasParamInstances ''FriendshipsOutgoing+ [ "cursor"+ -- , "stringify_ids" -- (needless)+ ]+ data FriendshipsCreate -- | Returns post data which follows the user specified in the ID parameter. --@@ -305,6 +376,22 @@ deriveHasParamInstances ''FriendshipsCreate [ "follow" ]++data FriendshipsDestroy+-- | Returns post data which follows the user specified in the ID parameter.+--+-- You can perform request by using 'call':+--+-- @+-- res <- 'call' '$' 'friendshipsDestroy' ('ScreenNameParam' \"thimura\")+-- @+--+-- >>> friendshipsDestroy (ScreenNameParam "thimura")+-- APIRequestPost "https://api.twitter.com/1.1/friendships/destroy.json" [("screen_name","thimura")]+-- >>> friendshipsDestroy (UserIdParam 69179963)+-- APIRequestPost "https://api.twitter.com/1.1/friendships/destroy.json" [("user_id","69179963")]+friendshipsDestroy :: UserParam -> APIRequest FriendshipsDestroy User+friendshipsDestroy user = APIRequestPost (endpoint ++ "friendships/destroy.json") (mkUserParam user) data FriendsList -- | Returns query data which asks a cursored collection of user objects for every user the specified users is following.
Web/Twitter/Conduit/Base.hs view
@@ -25,6 +25,7 @@ , showBS ) where +import Prelude as P import Web.Twitter.Conduit.Monad import Web.Twitter.Conduit.Error import Web.Twitter.Conduit.Parameters@@ -120,7 +121,7 @@ src C.$$+- sinkFromJSON where body = prt ++ partParam- partParam = map (uncurry partBS . over _1 T.decodeUtf8) param+ partParam = P.map (uncurry partBS . over _1 T.decodeUtf8) param sourceWithMaxId :: ( TwitterBaseM m , FromJSON responseType
Web/Twitter/Conduit/Cursor.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE CPP #-} module Web.Twitter.Conduit.Cursor ( CursorKey (..)@@ -31,6 +32,7 @@ instance CursorKey UsersCursorKey where cursorKey = const "users" +#if __GLASGOW_HASKELL__ >= 706 -- | A wrapper for API responses which have "next_cursor" field. -- -- The first type parameter of 'WithCursor' specifies the field name of contents.@@ -46,6 +48,7 @@ -- 0 -- >>> contents res -- [1000]+#endif data WithCursor cursorKey wrapped = WithCursor { previousCursor :: Integer , nextCursor :: Integer
Web/Twitter/Conduit/Parameters.hs view
@@ -23,6 +23,7 @@ , HasUntilParam (..) , HasSkipStatusParam (..) , HasFollowParam (..)+ , HasMapParam (..) , UserParam(..) , UserListParam(..)@@ -32,6 +33,7 @@ , mkListParam ) where +import Prelude as P import Web.Twitter.Conduit.Parameters.Internal import Web.Twitter.Conduit.Parameters.TH import Web.Twitter.Types@@ -70,6 +72,7 @@ defineHasParamClass "until" ''Day 'readShow defineHasParamClass "skip_status" ''Bool 'booleanQuery defineHasParamClass "follow" ''Bool 'booleanQuery+defineHasParamClass "map" ''Bool 'booleanQuery -- | converts 'UserParam' to 'HT.SimpleQuery'. --@@ -91,7 +94,7 @@ -- [("screen_name","thimura,NikaidouShinku")] mkUserListParam :: UserListParam -> HT.SimpleQuery mkUserListParam (UserIdListParam uids) = [("user_id", uids ^.. traversed . re readShow & S8.intercalate ",")]-mkUserListParam (ScreenNameListParam sns) = [("screen_name", S8.intercalate "," . map S8.pack $ sns)]+mkUserListParam (ScreenNameListParam sns) = [("screen_name", S8.intercalate "," . P.map S8.pack $ sns)] -- | converts 'ListParam' to 'HT.SimpleQuery'. --
Web/Twitter/Conduit/Request.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE CPP #-} module Web.Twitter.Conduit.Request ( APIRequest(..)@@ -12,8 +13,13 @@ import qualified Network.HTTP.Types as HT import Control.Applicative +-- In GHC 7.4.2, the following test fails with Overlapping instances error.+-- It may be caused by #5820 "defining instance in GHCi leads to duplicated instances".+-- So, we bypass below tests when GHC version older than 7.6.+-- see details: https://ghc.haskell.org/trac/ghc/ticket/5820+#if __GLASGOW_HASKELL__ >= 706 -- $setup--- >>> :set -XOverloadedStrings -XRank2Types -XEmptyDataDecls -XFlexibleInstances+-- >>> :set -XOverloadedStrings -XRank2Types -XEmptyDataDecls -XFlexibleInstances -XOverlappingInstances -XIncoherentInstances -- >>> import Control.Lens -- >>> import Data.Default -- >>> data SampleApi@@ -47,6 +53,7 @@ -- [("max_id","1234567890"),("count","100")] -- >>> (sampleApiRequest & count ?~ 100 & maxId ?~ 1234567890 & count .~ Nothing) ^. params -- [("max_id","1234567890")]+#endif data APIRequest apiName responseType = APIRequestGet { _url :: String
Web/Twitter/Conduit/Status.hs view
@@ -36,14 +36,18 @@ , updateWithMedia -- , oembed -- , retweetersIds+ , StatusesLookup+ , lookup ) where +import Prelude hiding ( lookup ) import Web.Twitter.Conduit.Base import Web.Twitter.Conduit.Request import Web.Twitter.Conduit.Parameters import Web.Twitter.Conduit.Parameters.TH import Web.Twitter.Types +import qualified Data.ByteString as S import qualified Data.Text as T import qualified Data.Text.Encoding as T import Network.HTTP.Client.MultipartFormData@@ -287,4 +291,27 @@ -- , "lat_long" -- , "place_id" , "display_coordinates"+ ]++data StatusesLookup+-- | Returns fully-hydrated tweet objects for up to 100 tweets per request, as specified by comma-separated values passed to the id parameter.+--+-- You can perform a request using 'call':+--+-- @+-- res <- 'call' '$' 'lookup' [20, 432656548536401920]+-- @+--+-- >>> lookup [10]+-- APIRequestGet "https://api.twitter.com/1.1/statuses/lookup.json" [("id","10")]+-- >>> lookup [10, 432656548536401920]+-- APIRequestGet "https://api.twitter.com/1.1/statuses/lookup.json" [("id","10,432656548536401920")]+-- >>> lookup [10, 432656548536401920] & includeEntities ?~ True+-- APIRequestGet "https://api.twitter.com/1.1/statuses/lookup.json" [("include_entities","true"),("id","10,432656548536401920")]+lookup :: [ StatusId ] -> APIRequest StatusesLookup [Status]+lookup ids = APIRequestGet (endpoint ++ "statuses/lookup.json") [("id", S.intercalate "," . Prelude.map showBS $ ids)]+deriveHasParamInstances ''StatusesLookup+ [ "include_entities"+ , "trim_user"+ , "map" ]
tests/doctests.hs view
@@ -8,21 +8,12 @@ import Control.Applicative main = do- sources <- findSources "Web"- doctest $ args ++ sources+ -- sources <- findSources "Web"+ doctest $ args -- ++ sources where args = [ "-i." , "-idist/build/autogen" , "-optP-include" , "-optPdist/build/autogen/cabal_macros.h"+ , "Web/Twitter/Conduit.hs" ]--findSources :: FilePath -> IO [FilePath]-findSources dir = filter (isSuffixOf ".hs") <$> go dir- where- go dir = do- (dirs, files) <- listFiles dir- (files ++) . concat <$> mapM go dirs- listFiles dir = do- entries <- map (dir </>) . filter (`notElem` [".", ".."]) <$> getDirectoryContents dir- (,) <$> filterM doesDirectoryExist entries <*> filterM doesFileExist entries
twitter-conduit.cabal view
@@ -1,5 +1,5 @@ name: twitter-conduit-version: 0.0.2.1+version: 0.0.3 license: BSD3 license-file: LICENSE author: HATTORI Hiroki, Hideyuki Tanaka, Takahiro HIMURA@@ -14,8 +14,8 @@ description: This package provides bindings to Twitter's APIs (see <https://dev.twitter.com/>). .- This package uses http-conduit package for access Twitter API (see <http://hackage.haskell.org/package/http-conduit>).- This package also depends to twitter-types package (see <http://hackage.haskell.org/package/twitter-types>).+ This package uses the http-conduit package for accessing the Twitter API (see <http://hackage.haskell.org/package/http-conduit>).+ This package also depends on the twitter-types package (see <http://hackage.haskell.org/package/twitter-types>). . You can find basic examples in the <https://github.com/himura/twitter-conduit/tree/master/sample> directory. .