Skip to content

Commit cc30411

Browse files
committed
Merge pull request #185 from phadej/languages-refactor
Refactor Language -stuff
2 parents dc8b0eb + d99c170 commit cc30411

File tree

4 files changed

+54
-22
lines changed

4 files changed

+54
-22
lines changed

github.cabal

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,7 @@ Library
126126
transformers-compat >=0.4.0.3 && <0.6,
127127
unordered-containers >=0.2 && <0.3,
128128
vector >=0.10.12.3 && <0.12,
129-
vector-instances >=3.3.0.1 && <3.4,
130-
void >=0.7 && <0.8
129+
vector-instances >=3.3.0.1 && <3.4
131130

132131
if flag(aeson-compat)
133132
build-depends: aeson-compat >=0.3.0.0 && <0.4
@@ -151,6 +150,7 @@ test-suite github-test
151150
base-compat,
152151
github,
153152
vector,
153+
unordered-containers,
154154
file-embed,
155155
hspec
156156
if flag(aeson-compat)

spec/GitHub/ReposSpec.hs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
module GitHub.ReposSpec where
44

55
import GitHub.Auth (Auth (..))
6-
import GitHub.Endpoints.Repos (RepoPublicity (..), currentUserRepos, userRepos')
6+
import GitHub.Endpoints.Repos (RepoPublicity (..), currentUserRepos,
7+
languagesFor', userRepos')
78

89
import Data.Either.Compat (isRight)
910
import Data.String (fromString)
1011
import System.Environment (lookupEnv)
1112
import Test.Hspec (Spec, describe, it, pendingWith, shouldSatisfy)
1213

14+
import qualified Data.HashMap.Strict as HM
15+
1316
fromRightS :: Show a => Either a b -> b
1417
fromRightS (Right b) = b
1518
fromRightS (Left a) = error $ "Expected a Right and got a Left" ++ show a
@@ -32,3 +35,9 @@ spec = do
3235
it "works" $ withAuth $ \auth -> do
3336
cs <- userRepos' (Just auth) "phadej" RepoPublicityAll
3437
cs `shouldSatisfy` isRight
38+
39+
describe "languagesFor'" $ do
40+
it "works" $ withAuth $ \auth -> do
41+
ls <- languagesFor' (Just auth) "phadej" "github"
42+
ls `shouldSatisfy` isRight
43+
fromRightS ls `shouldSatisfy` HM.member "Haskell"

src/GitHub/Data/Gists.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Prelude.Compat
1414
import GitHub.Data.Definitions
1515
import GitHub.Data.Id (Id)
1616
import GitHub.Data.Name (Name)
17+
import GitHub.Data.Repos (Language)
1718

1819
import Control.DeepSeq (NFData (..))
1920
import Control.DeepSeq.Generics (genericRnf)
@@ -62,7 +63,7 @@ data GistFile = GistFile {
6263
gistFileType :: !Text
6364
,gistFileRawUrl :: !Text
6465
,gistFileSize :: !Int
65-
,gistFileLanguage :: !(Maybe Text)
66+
,gistFileLanguage :: !(Maybe Language)
6667
,gistFileFilename :: !Text
6768
,gistFileContent :: !(Maybe Text)
6869
} deriving (Show, Data, Typeable, Eq, Generic)

src/GitHub/Data/Repos.hs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
{-# LANGUAGE CPP #-}
12
{-# LANGUAGE DeriveDataTypeable #-}
23
{-# LANGUAGE DeriveGeneric #-}
4+
{-# LANGUAGE FlexibleInstances #-}
35
{-# LANGUAGE OverloadedStrings #-}
6+
#define UNSAFE 1
47
-----------------------------------------------------------------------------
58
-- |
69
-- License : BSD-3-Clause
710
-- Maintainer : Oleg Grenrus <oleg.grenrus@iki.fi>
811
--
12+
-- This module also exports
13+
-- @'FromJSON' a => 'FromJSON' ('HM.HashMap' 'Language' a)@
14+
-- orphan-ish instance.
915
module GitHub.Data.Repos where
1016

1117
import Prelude ()
@@ -15,19 +21,24 @@ import GitHub.Data.Definitions
1521
import GitHub.Data.Id (Id)
1622
import GitHub.Data.Name (Name)
1723

24+
--import Control.Arrow (first) -- Data.Bifunctor would be better
1825
import Control.DeepSeq (NFData (..))
1926
import Control.DeepSeq.Generics (genericRnf)
2027
import Data.Aeson.Compat (FromJSON (..), ToJSON (..), object, withObject,
21-
(.:), (.:?), (.=))
28+
withText, (.:), (.:?), (.=))
2229
import Data.Binary (Binary)
2330
import Data.Data (Data, Typeable)
31+
import Data.Hashable (Hashable (..))
32+
import Data.String (IsString (..))
2433
import Data.Text (Text)
2534
import Data.Time (UTCTime)
26-
import Data.Vector (Vector)
2735
import GHC.Generics (Generic)
2836

2937
import qualified Data.HashMap.Strict as HM
30-
import qualified Data.Vector as V
38+
39+
#if UNSAFE
40+
import Unsafe.Coerce (unsafeCoerce)
41+
#endif
3142

3243
data Repo = Repo {
3344
repoSshUrl :: !(Maybe Text)
@@ -46,7 +57,7 @@ data Repo = Repo {
4657
,repoWatchers :: !(Maybe Int)
4758
,repoOwner :: !SimpleOwner
4859
,repoName :: !(Name Repo)
49-
,repoLanguage :: !(Maybe Text)
60+
,repoLanguage :: !(Maybe Language)
5061
,repoMasterBranch :: !(Maybe Text)
5162
,repoPushedAt :: !(Maybe UTCTime) -- ^ this is Nothing for new repositories
5263
,repoId :: !(Id Repo)
@@ -111,20 +122,22 @@ data RepoPublicity
111122
| RepoPublicityMember -- ^ Only repos to which the user is a member but not an owner.
112123
deriving (Show, Eq, Ord, Typeable, Data, Generic)
113124

114-
-- | This is only used for the FromJSON instance.
115-
data Languages = Languages { getLanguages :: Vector Language }
116-
deriving (Show, Data, Typeable, Eq, Ord, Generic)
125+
-- | The value is the number of bytes of code written in that language.
126+
type Languages = HM.HashMap Language Int
117127

118-
instance NFData Languages where rnf = genericRnf
119-
instance Binary Languages
128+
-- | A programming language.
129+
newtype Language = Language Text
130+
deriving (Show, Data, Typeable, Eq, Ord, Generic)
120131

121-
-- | A programming language with the name and number of characters written in
122-
-- it.
123-
data Language = Language !Text !Int
124-
deriving (Show, Data, Typeable, Eq, Ord, Generic)
132+
getLanguage :: Language -> Text
133+
getLanguage (Language l) = l
125134

126135
instance NFData Language where rnf = genericRnf
127136
instance Binary Language
137+
instance Hashable Language where
138+
hashWithSalt salt (Language l) = hashWithSalt salt l
139+
instance IsString Language where
140+
fromString = Language . fromString
128141

129142
data Contributor
130143
-- | An existing Github user, with their number of contributions, avatar
@@ -234,8 +247,17 @@ instance FromJSON Contributor where
234247
<*> o .: "id"
235248
<*> o .: "gravatar_id"
236249

237-
instance FromJSON Languages where
238-
parseJSON = withObject "Languages" $ \o ->
239-
Languages . V.fromList <$>
240-
traverse (\name -> Language name <$> o .: name)
241-
(HM.keys o)
250+
instance FromJSON Language where
251+
parseJSON = withText "Language" (pure . Language)
252+
253+
instance FromJSON a => FromJSON (HM.HashMap Language a) where
254+
parseJSON = fmap mapKeyLanguage . parseJSON
255+
where
256+
mapKeyLanguage :: HM.HashMap Text a -> HM.HashMap Language a
257+
#ifdef UNSAFE
258+
mapKeyLanguage = unsafeCoerce
259+
#else
260+
mapKeyLanguage = mapKey Language
261+
mapKey :: (Eq k2, Hashable k2) => (k1 -> k2) -> HM.HashMap k1 a -> HM.HashMap k2 a
262+
mapKey f = HM.fromList . map (first f) . HM.toList
263+
#endif

0 commit comments

Comments
 (0)