packages feed

fb 0.3.1 → 0.4

raw patch · 8 files changed

+153/−22 lines, 8 filesdep +QuickCheckdep +old-localePVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, old-locale

API changes (from Hackage documentation)

+ Facebook: (#=) :: SimpleType a => Ascii -> a -> Argument
+ Facebook: Id :: Ascii -> Id
+ Facebook: class SimpleType a
+ Facebook: encodeFbParam :: SimpleType a => a -> Text
+ Facebook: idCode :: Id -> Ascii
+ Facebook: newtype Id
- Facebook: createAction :: ResourceIO m => Action -> SimpleQuery -> AccessToken User -> FacebookT Auth m Id
+ Facebook: createAction :: ResourceIO m => Action -> [Argument] -> AccessToken User -> FacebookT Auth m Id
- Facebook: getObject :: (ResourceIO m, FromJSON a) => Ascii -> SimpleQuery -> Maybe (AccessToken kind) -> FacebookT anyAuth m a
+ Facebook: getObject :: (ResourceIO m, FromJSON a) => Ascii -> [Argument] -> Maybe (AccessToken kind) -> FacebookT anyAuth m a
- Facebook: getUserAccessTokenStep2 :: ResourceIO m => RedirectUrl -> SimpleQuery -> FacebookT Auth m (AccessToken User)
+ Facebook: getUserAccessTokenStep2 :: ResourceIO m => RedirectUrl -> [Argument] -> FacebookT Auth m (AccessToken User)
- Facebook: postObject :: (ResourceIO m, FromJSON a) => Ascii -> SimpleQuery -> AccessToken kind -> FacebookT Auth m a
+ Facebook: postObject :: (ResourceIO m, FromJSON a) => Ascii -> [Argument] -> AccessToken kind -> FacebookT Auth m a

Files

fb.cabal view
@@ -1,5 +1,5 @@ name:              fb-version:           0.3.1+version:           0.4 license:           BSD3 license-file:      LICENSE author:            Felipe Lessa@@ -61,6 +61,7 @@     , attoparsec-conduit >= 0.0     && < 0.1     , aeson              >= 0.5     && < 0.6     , time               >= 1.2     && < 1.5+    , old-locale   extensions:     DeriveDataTypeable     EmptyDataDecls@@ -87,6 +88,7 @@        -- Test-only dependencies     , HUnit+    , QuickCheck     , hspec == 0.9.*     , fb   extensions:
src/Facebook.hs view
@@ -28,10 +28,13 @@       -- * Facebook's Open Graph API     , createAction     , Action+    , (#=)+    , SimpleType(..)        -- * Raw access to the Graph API     , getObject     , postObject+    , Id(..)        -- * Exceptions     , FacebookException(..)
src/Facebook/Auth.hs view
@@ -25,7 +25,7 @@ import qualified Data.Text.Encoding as TE import qualified Data.Text.Encoding.Error as TE import qualified Network.HTTP.Conduit as H-import qualified Network.HTTP.Types as HT+-- import qualified Network.HTTP.Types as HT   import Facebook.Types@@ -78,7 +78,7 @@ getUserAccessTokenStep2 :: C.ResourceIO m =>                            RedirectUrl -- ^ Should be exactly the same                                        -- as in 'getUserAccessTokenStep1'.-                        -> HT.SimpleQuery+                        -> [Argument]                         -> FacebookT Auth m (AccessToken User) getUserAccessTokenStep2 redirectUrl query =   case query of
src/Facebook/Base.hs view
@@ -42,8 +42,8 @@           }  --- | Class for types that may be passed on queries to Facebook's--- API.+-- | Internal class for types that may be passed on queries to+-- Facebook's API. class ToSimpleQuery a where     -- | Prepend to the given query the parameters necessary to     -- pass this data type to Facebook.
src/Facebook/Graph.hs view
@@ -29,7 +29,7 @@ -- raw JSON 'A.Value'. getObject :: (C.ResourceIO m, A.FromJSON a) =>              Ascii          -- ^ Path (should begin with a slash @\/@)-          -> HT.SimpleQuery -- ^ Arguments to be passed to Facebook+          -> [Argument]     -- ^ Arguments to be passed to Facebook           -> Maybe (AccessToken kind) -- ^ Optional access token           -> FacebookT anyAuth m a getObject path query mtoken =@@ -41,7 +41,7 @@ -- a raw JSON 'A.Value'. postObject :: (C.ResourceIO m, A.FromJSON a) =>               Ascii            -- ^ Path (should begin with a slash @\/@)-           -> HT.SimpleQuery   -- ^ Arguments to be passed to Facebook+           -> [Argument]       -- ^ Arguments to be passed to Facebook            -> AccessToken kind -- ^ Access token            -> FacebookT Auth m a postObject path query token =
src/Facebook/OpenGraph.hs view
@@ -1,21 +1,29 @@ module Facebook.OpenGraph     ( createAction     , Action(..)+    , (#=)+    , SimpleType(..)     ) where  -- import Control.Applicative -- import Control.Monad (mzero) -- import Data.ByteString.Char8 (ByteString)--- import Data.Text (Text)+import Data.Text (Text) -- import Data.Typeable (Typeable, Typeable1)+import Data.Int (Int8, Int16, Int32)+import Data.Word (Word8, Word16, Word32, Word) import Data.String (IsString(..)) import Network.HTTP.Types (Ascii)+import System.Locale (defaultTimeLocale)  -- import qualified Control.Exception.Lifted as E -- import qualified Data.Aeson as A+-- import qualified Data.ByteString.Char8 as B import qualified Data.Conduit as C--- import qualified Data.Text as T-import qualified Network.HTTP.Types as HT+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Time as TI+-- import qualified Network.HTTP.Types as HT   import Facebook.Types@@ -25,10 +33,16 @@   -- | Creates an Open Graph action on the user's timeline. Returns--- the 'Id' of the newly created action.+-- the 'Id' of the newly created action.  For example:+--+-- > now <- liftIO getCurrentTime+-- > createAction "cook"+-- >              [ "recipe" #= "http://example.com/cookie.html"+-- >              , "when"   #= now ]+-- >              token createAction :: C.ResourceIO m =>-                Action               -- ^ Action kind to be created.-             -> HT.SimpleQuery       -- ^ Arguments of the action.+                Action     -- ^ Action kind to be created.+             -> [Argument] -- ^ Arguments of the action.              -> AccessToken User              -> FacebookT Auth m Id createAction (Action action) query token = do@@ -59,3 +73,70 @@     fromString = Action . fromString  +-- | Create an 'Argument' with a 'SimpleType'.  See the docs on+-- 'createAction' for an example.+(#=) :: SimpleType a => Ascii -> a -> Argument+p #= v = (p, TE.encodeUtf8 (encodeFbParam v))++++-- | Class for data types that may be represented as a Facebook+-- simple type. (see+-- <https://developers.facebook.com/docs/opengraph/simpletypes/>).+class SimpleType a where+    encodeFbParam :: a -> Text++-- | Facebook's simple type @Boolean@.+instance SimpleType Bool where+    encodeFbParam b = if b then "1" else "0"++-- | Facebook's simple type @DateTime@ with only the date.+instance SimpleType TI.Day where+    encodeFbParam = T.pack . TI.formatTime defaultTimeLocale "%Y-%m-%d"+-- | Facebook's simple type @DateTime@.+instance SimpleType TI.UTCTime where+    encodeFbParam = T.pack . TI.formatTime defaultTimeLocale "%Y%m%dT%H%MZ"+-- | Facebook's simple type @DateTime@.+instance SimpleType TI.ZonedTime where+    encodeFbParam = encodeFbParam . TI.zonedTimeToUTC++-- @Enum@ doesn't make sense to support as a Haskell data type.++-- | Facebook's simple type @Float@ with less precision than supported.+instance SimpleType Float where+    encodeFbParam = showT+-- | Facebook's simple type @Float@.+instance SimpleType Double where+    encodeFbParam = showT++-- | Facebook's simple type @Integer@.+instance SimpleType Int where+    encodeFbParam = showT+-- | Facebook's simple type @Integer@.+instance SimpleType Word where+    encodeFbParam = showT+-- | Facebook's simple type @Integer@.+instance SimpleType Int8 where+    encodeFbParam = showT+-- | Facebook's simple type @Integer@.+instance SimpleType Word8 where+    encodeFbParam = showT+-- | Facebook's simple type @Integer@.+instance SimpleType Int16 where+    encodeFbParam = showT+-- | Facebook's simple type @Integer@.+instance SimpleType Word16 where+    encodeFbParam = showT+-- | Facebook's simple type @Integer@.+instance SimpleType Int32 where+    encodeFbParam = showT+-- | Facebook's simple type @Integer@.+instance SimpleType Word32 where+    encodeFbParam = showT++-- | Facebook's simple type @String@.+instance SimpleType Text where+    encodeFbParam = id++showT :: Show a => a -> Text+showT = T.pack . show
src/Facebook/Types.hs view
@@ -6,9 +6,11 @@     , accessTokenExpires     , User     , App+    , Argument     , (<>)     ) where +import Data.ByteString (ByteString) import Data.Monoid (Monoid, mappend) import Data.Time (UTCTime) import Data.Typeable (Typeable, Typeable1)@@ -72,6 +74,10 @@ -- | Phantom type used mark an 'AccessToken' as an app access -- token. data App deriving (Typeable)+++-- | An argument given to an API call.+type Argument = (ByteString, ByteString)   -- | Synonym for 'mappend'.
tests/runtests.hs view
@@ -3,8 +3,10 @@ import Control.Applicative import Control.Monad.IO.Class (MonadIO(liftIO)) import Control.Monad.Trans.Class (lift)+import Data.Int (Int8, Int16, Int32) import Data.Text (Text) import Data.Time (parseTime)+import Data.Word (Word8, Word16, Word32, Word) import System.Environment (getEnv) import System.Exit (exitFailure) import System.IO.Error (isDoesNotExistError)@@ -12,14 +14,17 @@ import qualified Data.Aeson as A import qualified Data.Aeson.Types as A import qualified Data.ByteString.Char8 as B+import qualified Data.Text as T+import qualified Data.Time as TI import qualified Control.Exception.Lifted as E import qualified Facebook as FB import qualified Network.HTTP.Conduit as H -import qualified Test.HUnit as HU+import Test.HUnit ((@?=)) import Test.Hspec.Monadic--- import Test.Hspec.QuickCheck+import Test.Hspec.QuickCheck import Test.Hspec.HUnit ()+import qualified Test.QuickCheck as QC   -- | Grab the Facebook credentials from the environment.@@ -77,7 +82,7 @@       runNoAuth :: FB.FacebookT FB.NoAuth IO a -> IO a       runNoAuth = FB.runNoAuthFacebookT manager   hspecX $ do-    describe "Facebook.getAppAccessToken" $ do+    describe "getAppAccessToken" $ do       it "works and returns a valid app access token" $         runAuth $ do           token <- FB.getAppAccessToken@@ -89,13 +94,13 @@             Right token                      -> fail $ show token             Left (_ :: FB.FacebookException) -> lift (return () :: IO ()) -    describe "Facebook.isValid" $ do+    describe "isValid" $ do       it "returns False on a clearly invalid user access token" $         runNoAuth $ FB.isValid invalidUserAccessToken #?= False       it "returns False on a clearly invalid app access token" $         runNoAuth $ FB.isValid invalidAppAccessToken  #?= False -    describe "Facebook.OpenGraph.getObject" $ do+    describe "getObject" $ do       it "is able to fetch Facebook's own page" $         runNoAuth $ do           A.Object obj <- FB.getObject "/19292868552" [] Nothing@@ -104,15 +109,49 @@                             <*> obj A..:? "website"                             <*> obj A..:? "name"               just x = Just (x :: Text)-          r @?= ( just "19292868552"+          r &?= ( just "19292868552"                 , just "http://developers.facebook.com"                 , just "Facebook Platform" ) +    describe "SimpleType" $ do+      it "works for Bool" $ (map FB.encodeFbParam [True, False]) @?= ["1", "0"] +      let day       = TI.fromGregorian 2012 12 21+          time      = TI.TimeOfDay 11 37 22+          diffTime  = TI.secondsToDiffTime (11*3600 + 37*60)+          utcTime   = TI.UTCTime day diffTime+          localTime = TI.LocalTime day time+          zonedTime = TI.ZonedTime localTime (TI.minutesToTimeZone 30)+      it "works for Day"       $ FB.encodeFbParam day       @?= "2012-12-21"+      it "works for UTCTime"   $ FB.encodeFbParam utcTime   @?= "20121221T1137Z"+      it "works for ZonedTime" $ FB.encodeFbParam zonedTime @?= "20121221T1107Z"++      let propShowRead :: (Show a, Read a, Eq a, FB.SimpleType a) => a -> Bool+          propShowRead x = read (T.unpack $ FB.encodeFbParam x) == x+      prop "works for Float"  (propShowRead :: Float  -> Bool)+      prop "works for Double" (propShowRead :: Double -> Bool)+      prop "works for Int"    (propShowRead :: Int    -> Bool)+      prop "works for Int8"   (propShowRead :: Int8   -> Bool)+      prop "works for Int16"  (propShowRead :: Int16  -> Bool)+      prop "works for Int32"  (propShowRead :: Int32  -> Bool)+      prop "works for Word"   (propShowRead :: Word   -> Bool)+      prop "works for Word8"  (propShowRead :: Word8  -> Bool)+      prop "works for Word16" (propShowRead :: Word16 -> Bool)+      prop "works for Word32" (propShowRead :: Word32 -> Bool)++      prop "works for Text" (\t -> FB.encodeFbParam t == t)++ -- Wrappers for HUnit operators using MonadIO -(@?=) :: (Eq a, Show a, MonadIO m) => a -> a -> m ()-v @?= e = liftIO (v HU.@?= e)+(&?=) :: (Eq a, Show a, MonadIO m) => a -> a -> m ()+v &?= e = liftIO (v @?= e)  (#?=) :: (Eq a, Show a, MonadIO m) => m a -> a -> m ()-m #?= e = m >>= (@?= e)+m #?= e = m >>= (&?= e)+++-- | Sad, orphan instance.+instance QC.Arbitrary Text where+    arbitrary = T.pack <$> QC.arbitrary+    shrink    = map T.pack . QC.shrink . T.unpack