packages feed

jonathanscard (empty) → 0.1

raw patch · 5 files changed

+181/−0 lines, 5 filesdep +HTTPdep +basedep +bytestringsetup-changed

Dependencies added: HTTP, base, bytestring, containers, json, mtl, network

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2011, Spearhead Development, L.L.C.++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Spearhead Development, L.L.C. nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.mkd view
@@ -0,0 +1,17 @@+# Overview++This is an implementation of the [Jonathan's Card API](http://jonathanstark.com/card/#api).+The API is created by [Jonathan Stark](http://jonathanstark.com/),+while this implementation is created by [Michael Schade](http://mschade.me/)+([@michaelschade](https://twitter.com/intent/user?screen_name=michaelschade))++# Usage++Usage is fairly self-explanatory. Simply make a call to:++* `balances`+* `changes`+* `latest`++and then unwrap it from the IO and Either monads to play with `Balance`+or `Change`.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ jonathanscard.cabal view
@@ -0,0 +1,31 @@+Name:                jonathanscard+Version:             0.1+Synopsis:            An implementation of the Jonathan's Card API.+Description:         This implements the Jonathan's Card API, as detailed at+                     <http://jonathanstark.com/card/#api>+License:             BSD3+License-file:        LICENSE+Author:              Spearhead Development, L.L.C.+Maintainer:          Michael Schade <michael@spearheaddev.com>+Copyright:           (c) 2011 Spearhead Development, L.L.C.+Category:            Web+Build-type:          Simple+Extra-source-files:  README.mkd+Cabal-version:       >= 1.6++source-repository head+    type:       git+    location:   git://github.com/michaelschade/hs-jonathanscard.git++Library+  -- Modules exported by the library.+    ghc-options:        -Wall -fwarn-tabs+    Hs-Source-Dirs:     src+    Exposed-modules:      Web.JonathansCard+    Build-depends:        base          >= 3 && < 5+                        , bytestring    >= 0.9+                        , containers    == 0.4.*+                        , HTTP          == 4000.1.*+                        , json          == 0.4.4+                        , mtl           == 2.0.1.*+                        , network       == 2.3.*
+ src/Web/JonathansCard.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE OverloadedStrings #-}++module Web.JonathansCard+    (+      Balance(..)+    , Change(..)+    , balances+    , latest+    , changes+    ) where++import Control.Monad        ( ap, liftM )+import Text.JSON            ( JSON(..), JSObject(..), JSValue(..), Result+                            , decode, resultToEither, valFromObj+                            )+import Network.HTTP         ( Header(Header), HeaderName(..), Request(Request)+                            , RequestMethod(GET), getResponseBody, simpleHTTP+                            , catchIO+                            )+import Network.URI          ( URI(URI), URIAuth(URIAuth) )+import Data.ByteString.Char8 ( ByteString, unpack )++-- | Represents a Balance on Jonathan's Card+data Balance = Balance+    { balAmount     :: Double+    , balBalanceId  :: Int+    , balCreated    :: String+    , balMessage    :: String+    } deriving Show++-- | Represents the changes over time on Jonathan's Card+data Change = Change+    { chgBalance    :: Double+    , chgCreated    :: String+    , chgDelta      :: Double+    } deriving Show++-- | Retrieve a list of balances on Jonathan's Card+balances :: IO (Either String [Balance])+balances  = apiCall "balances" "balances" "balances"++-- | Retrieve the latest balance on Jonathan's Card+latest :: IO (Either String Balance)+latest  = apiCall "latest" "balance" "latest balance"++-- | Retrieve the changes in amounts on Jonathan's Card+changes :: IO (Either String [Change])+changes  = apiCall "changes" "changes" "changes"++-- | Abstracts the details of the API call and body parsing.+apiCall :: JSON a => String -> String -> String -> IO (Either String a)+apiCall endpoint parent errObject = flip catchIO (\_ -> err) $ do+    rsp <- (decode . unpack) `liftM` request endpoint+    return . resultToEither $ valFromObj parent =<< rsp+    where err = return . Left $ "Unable to retrieve " ++ errObject ++ "."++-----------------------+-- Request Utilities --+-----------------------++-- | Sends response to server+request  :: String -> IO ByteString+request p = (simpleHTTP $ prepRq p) >>= getResponseBody++-- | Prepare request to API+prepRq  :: String -> Request ByteString+prepRq p = Request (url p) GET headers ""+    where+        headers = [ Header HdrAccept    "application/json"+                  , Header HdrUserAgent "JonathansCard/0.1 haskell"+                  ]++-- | Define request URL based on endpoint+url  :: String -> URI+url p = URI "http:" uriAuth ("/card/api/" ++ p) "" ""+    where uriAuth = Just $ URIAuth "" "jonathanstark.com" ":80"++----------------------------+-- JSON Parsing Utilities --+----------------------------++-- | Convenient name to get a field from a given 'JSON' object.+get :: JSON a => JSObject JSValue -> String -> Result a+get  = flip valFromObj++instance JSON Balance where+    readJSON (JSObject rsp) = do+        Balance  `liftM` (read `liftM` get rsp "amount")+                    `ap` (read `liftM` get rsp "balance_id")+                    `ap` get rsp "created_at"+                    `ap` get rsp "message"+    readJSON _ = undefined+    showJSON   = undefined++instance JSON Change where+    readJSON (JSObject rsp) = do+        Change   `liftM` (read `liftM` get rsp "balance")+                    `ap` get rsp "created_at"+                    `ap` (read `liftM` get rsp "delta")+    readJSON _ = undefined+    showJSON   = undefined