packages feed

ocaml-export 0.6.0.0 → 0.7.0.0

raw patch · 13 files changed

+199/−53 lines, 13 files

Files

ocaml-export.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 1958ab6ed0c01872336472224fcf702904c8cfb26230a75529ea37b5ab11a6d4+-- hash: 8ba9cf12795b26fa199a0b74560d1d13c2ee2f1c686baed377ef3127ff1d9789  name:           ocaml-export-version:        0.6.0.0+version:        0.7.0.0 synopsis:       Convert Haskell types in OCaml types description:    Use GHC.Generics and Typeable to convert Haskell types to OCaml types. Convert aeson serialization to ocaml. category:       Web@@ -23,10 +23,15 @@   type: git   location: https://github.com/plow-technologies/ocaml-export +flag servant-spec+  description: Test ocaml-export against a servant server. Internal test use only.+  manual: True+  default: False+ library   hs-source-dirs:       src-  ghc-options: -Wall -Wredundant-constraints -fprint-potential-instances+  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints -Wredundant-constraints -fprint-potential-instances   build-depends:       QuickCheck     , aeson@@ -37,6 +42,7 @@     , file-embed     , filepath     , formatting+    , hspec     , hspec-golden-aeson >=0.4.0.0     , mtl     , quickcheck-arbitrary-adt@@ -68,7 +74,7 @@   main-is: Spec.hs   hs-source-dirs:       test-  ghc-options: -Wall+  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints   build-depends:       QuickCheck     , aeson@@ -91,6 +97,8 @@     , wai     , wai-extra     , warp+  if flag(servant-spec)+    cpp-options: -DSERVANT_SPEC   other-modules:       Dependency       File
src/OCaml/BuckleScript/Encode.hs view
@@ -10,6 +10,7 @@ OCaml type to JSON (aeson) encoder. -} +{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -405,7 +406,12 @@   let jsonConstructorName = T.pack . Aeson.constructorTagModifier ao . T.unpack $ name       constructorMatchCase = "|" <+> stext name <+> "->"       encodeTag = pair (dquotes "tag") ("Aeson.Encode.string" <+> dquotes (stext jsonConstructorName))+#if MIN_VERSION_aeson(1,1,0)+      encodeContents  = ";" <+> pair (dquotes "contents") ("Aeson.Encode.array [| |]")+  pure $ jsonEncodeObject constructorMatchCase encodeTag (Just encodeContents)+#else   pure $ jsonEncodeObject constructorMatchCase encodeTag Nothing+#endif  renderSum (OCamlValueConstructor (NamedConstructor name value)) = do   let constructorParams = constructorParameters 0 value
src/OCaml/BuckleScript/Internal/Module.hs view
@@ -122,7 +122,7 @@ class HasOCamlType api where   mkType :: Proxy api -> Options -> Bool -> Map.Map String EmbeddedOCamlFiles -> [Text]   mkInterface :: Proxy api -> Options -> Map.Map String EmbeddedOCamlFiles -> [Text]-  mkSpec :: Proxy api -> Options -> [Text] -> Text -> Text -> Map.Map String EmbeddedOCamlFiles -> [Text]+  mkSpec :: Proxy api -> Options -> [Text] -> Maybe Text -> Text -> Map.Map String EmbeddedOCamlFiles -> [Text]  instance (HasOCamlTypeFlag a ~ flag, HasOCamlType' flag (a :: *)) => HasOCamlType a where   mkType = mkType' (Proxy :: Proxy flag)@@ -140,7 +140,7 @@ class HasOCamlType' (flag :: Nat) api where   mkType' :: Proxy flag -> Proxy api -> Options -> Bool -> Map.Map String EmbeddedOCamlFiles -> [Text]   mkInterface' :: Proxy flag -> Proxy api -> Options -> Map.Map String EmbeddedOCamlFiles -> [Text]-  mkSpec' :: Proxy flag -> Proxy api -> Options -> [Text] -> Text -> Text -> Map.Map String EmbeddedOCamlFiles -> [Text]+  mkSpec' :: Proxy flag -> Proxy api -> Options -> [Text] -> Maybe Text -> Text -> Map.Map String EmbeddedOCamlFiles -> [Text]  instance (KnownSymbol subModule, HasOCamlType b) => HasOCamlType' 4 (OCamlSubModule subModule :> b) where   mkType' _ Proxy options interface fileMap = ["module " <> (T.pack $ symbolVal (Proxy :: Proxy subModule)) <> " = struct\n"] <> (mkType (Proxy :: Proxy b) options interface fileMap) <> ["\nend"]@@ -172,7 +172,7 @@       Just (Just v) -> [decodeUtf8 v]       _ -> fail $ "Unable to find the embedded file for " ++ typeName -  mkSpec' _ Proxy _options modules url goldendir _fileMap = +  mkSpec' _ Proxy _options modules url goldendir _fileMap =     [typeInFileToOCamlSpec (Proxy :: Proxy a) typeParameterRefCount modules url goldendir]     where       parameters = fmap show . snd . splitTyConApp $ typeRep (Proxy :: Proxy a)
src/OCaml/BuckleScript/Internal/Package.hs view
@@ -86,8 +86,6 @@ type NoDependency = '[]  -- -- ============================================== -- Data Types -- ==============================================@@ -111,12 +109,12 @@   = SpecOptions     { specDir :: FilePath -- ^ Directory in which to store the OCaml spec, relative to 'packageRootDir'.     , goldenDir :: FilePath -- ^ Location of golden JSON files produced by Haskell, relative to 'packageRootDir'.-    , servantURL :: String -- ^ The URL of the automated Servant spec server to run OCaml specs against.+    , servantURL :: Maybe String -- ^ If Just url then run the automated Servant spec server to run OCaml specs against it, otherwise test files only.      }  -- | Default 'SpecOptions'. defaultSpecOptions :: SpecOptions-defaultSpecOptions = SpecOptions "/__tests__" "/__tests__/golden" "localhost:8081"+defaultSpecOptions = SpecOptions "/__tests__" "/__tests__/golden" (Just "localhost:8081")   -- ==============================================@@ -181,7 +179,7 @@         case mSpecOptions packageOptions of           Nothing -> pure ()           Just specOptions -> do-            let specF = (<> "\n") . T.intercalate "\n\n" $ mkSpec (Proxy :: Proxy api) (defaultOptions {dependencies = ds}) moduls (T.pack $ servantURL specOptions) (T.pack $ goldenDir specOptions) (packageEmbeddedFiles packageOptions)+            let specF = (<> "\n") . T.intercalate "\n\n" $ mkSpec (Proxy :: Proxy api) (defaultOptions {dependencies = ds}) moduls (T.pack <$> servantURL specOptions) (T.pack $ goldenDir specOptions) (packageEmbeddedFiles packageOptions)             let specBody = if specF /= "" then ("let () =\n" <> specF) else ""             createDirectoryIfMissing True (rootDir </> (specDir specOptions))             T.writeFile (specFp <> "_spec" <.> "ml") specBody
src/OCaml/BuckleScript/Internal/Spec.hs view
@@ -31,6 +31,7 @@   , MkOCamlSpecAPI    , mkGoldenFiles+  , runGoldenSpec    -- utility functions   , OCamlSpecAPI@@ -45,16 +46,25 @@ import GHC.TypeLits  -- aeson-import Data.Aeson (ToJSON)+import Data.Aeson (FromJSON, ToJSON) +-- hspec+import Test.Hspec (Spec) -- hspec-aeson-golden import Test.Aeson.Internal.ADT.GoldenSpecs (mkGoldenFileForType)+import Test.Aeson.GenericSpecs+  ( roundtripAndGoldenADTSpecsWithSettings+  , defaultSettings+  , GoldenDirectoryOption (..)+  , Settings (..)+  )  -- ocaml-export import OCaml.Internal.Common hiding ((</>)) import OCaml.BuckleScript.Internal.Module import OCaml.BuckleScript.Internal.Package-+-- QuickCheck+import Test.QuickCheck (Arbitrary) -- quickcheck-arbitrary-adt import Test.QuickCheck.Arbitrary.ADT @@ -142,8 +152,59 @@   mkGoldenFiles' _ Proxy size fp = mkGoldenFileForType size (Proxy :: Proxy a) fp  +-- | Make hspec-aeson-golden golden files for each type in an OCamlPackage+class HasRunGoldenSpec a where+  runGoldenSpec :: Proxy a -> Int -> FilePath -> Spec +instance (HasRunGoldenSpecFlag a ~ flag, HasRunGoldenSpec' flag (a :: *)) => HasRunGoldenSpec a where+  runGoldenSpec = runGoldenSpec' (Proxy :: Proxy flag) +type family (HasRunGoldenSpecFlag a) :: Nat where+  HasRunGoldenSpecFlag (OCamlPackage a b :> c) = 7+  HasRunGoldenSpecFlag ((OCamlModule a :> b) :<|> c) = 6+  HasRunGoldenSpecFlag (OCamlModule a :> b) = 5+  HasRunGoldenSpecFlag (OCamlSubModule a :> b) = 4+  HasRunGoldenSpecFlag (HaskellTypeName a (OCamlTypeInFile b c)) = 3+  HasRunGoldenSpecFlag (OCamlTypeInFile a b) = 3+  HasRunGoldenSpecFlag (a :> b) = 2+  HasRunGoldenSpecFlag a = 1++class HasRunGoldenSpec' (flag :: Nat) a where+  runGoldenSpec' :: Proxy flag -> Proxy a -> Int -> FilePath -> Spec++instance (HasRunGoldenSpec a) => HasRunGoldenSpec' 7 (OCamlPackage packageName deps :> a) where+  runGoldenSpec' _ Proxy size fp = runGoldenSpec (Proxy :: Proxy a) size fp++instance (HasRunGoldenSpec a, HasRunGoldenSpec b) => HasRunGoldenSpec' 6 ((OCamlModule modules :> a) :<|> b) where+  runGoldenSpec' _ Proxy size fp = do+    runGoldenSpec (Proxy :: Proxy a) size fp+    runGoldenSpec (Proxy :: Proxy b) size fp+    +instance (HasRunGoldenSpec a) => HasRunGoldenSpec' 5 (OCamlModule modules :> a) where+  runGoldenSpec' _ Proxy size fp = runGoldenSpec (Proxy :: Proxy a) size fp++instance (HasRunGoldenSpec a) => HasRunGoldenSpec' 4 (OCamlSubModule subModule :> a) where+  runGoldenSpec' _ Proxy size fp = runGoldenSpec (Proxy :: Proxy a) size fp++instance (Arbitrary b, Eq b, Show b, ToADTArbitrary b, FromJSON b, ToJSON b) => HasRunGoldenSpec' 3 (HaskellTypeName a (OCamlTypeInFile b c)) where+  runGoldenSpec' _ Proxy size fp =+    roundtripAndGoldenADTSpecsWithSettings+      (defaultSettings {sampleSize = size, goldenDirectoryOption = CustomDirectoryName fp})+      (Proxy :: Proxy b)++instance (Arbitrary a, Eq a, Show a, ToADTArbitrary a, FromJSON a, ToJSON a) => HasRunGoldenSpec' 3 (OCamlTypeInFile a b) where+  runGoldenSpec' _ Proxy size fp =+    roundtripAndGoldenADTSpecsWithSettings+      (defaultSettings {sampleSize = size, goldenDirectoryOption = CustomDirectoryName fp})+      (Proxy :: Proxy a)++instance (HasRunGoldenSpec a, HasRunGoldenSpec b) => HasRunGoldenSpec' 2 (a :> b) where+  runGoldenSpec' _ Proxy size fp = do+    runGoldenSpec (Proxy :: Proxy a) size fp+    runGoldenSpec (Proxy :: Proxy b) size fp++instance (Arbitrary a, Eq a, Show a, ToADTArbitrary a, FromJSON a, ToJSON a) => HasRunGoldenSpec' 1 a where+  runGoldenSpec' _ Proxy size fp = roundtripAndGoldenADTSpecsWithSettings (defaultSettings {sampleSize = size, goldenDirectoryOption = CustomDirectoryName fp}) (Proxy :: Proxy a)  -- | Convert an OCamlPackage into a servant API. type family MkOCamlSpecAPI a :: * where
src/OCaml/BuckleScript/Spec.hs view
@@ -3,6 +3,7 @@  module OCaml.BuckleScript.Spec   ( mkSampleServerAndGoldenSpec+  , mkGoldenDirSpec   , toOCamlSpec   , typeInFileToOCamlSpec   ) where@@ -36,9 +37,29 @@     modul = T.intercalate "." (textUppercaseFirst <$> modules) :: Text     smodul = stext $ if modul /= "" then modul <> "." else ""     urlModul = T.intercalate "/" (textUppercaseFirst <$> modules) :: Text- mkSampleServerAndGoldenSpec (OCamlPrimitive _) _ _mod _url _fp = "" +-- | test OCaml type serialization (bs-aeson) against Haskell produced golden files+mkGoldenDirSpec :: OCamlDatatype -> Maybe Int -> [Text] -> Text -> Doc+mkGoldenDirSpec (OCamlDatatype _ typeName constructors) mParameterRefCount modules goldenDir =+  indent 2 $+    "AesonSpec.goldenDirSpec" <$$> (indent 2 $+          decoders+      <$$> encoders+      <$$> (dquotes down)+      <$$> (dquotes (stext $ goldenDir </> textUppercaseFirst typeName)) <> ";")+  where+    (tprDecoders, tprEncoders) = renderTypeParameterVals mParameterRefCount constructors+    decoders = if tprDecoders == "" then (smodul <> "decode" <> up) else ("(" <> smodul <> "decode" <> up <+> (stext tprDecoders) <> ")")+    encoders = if tprEncoders == "" then (smodul <> "encode" <> up) else ("(" <> smodul <> "encode" <> up <+> (stext tprEncoders) <> ")")+    up = stext . textUppercaseFirst $ typeName+    down = stext . textLowercaseFirst $ typeName+    modul = T.intercalate "." (textUppercaseFirst <$> modules) :: Text+    smodul = stext $ if modul /= "" then modul <> "." else ""++mkGoldenDirSpec (OCamlPrimitive _) _ _ _ = ""++ renderTypeParameterVals :: Maybe Int -> OCamlConstructor -> (Text,Text) renderTypeParameterVals (Just count) _ = renderTypeParameterValsAux count renderTypeParameterVals _ (OCamlValueConstructor vc) =@@ -65,29 +86,18 @@ getOCamlValues (RecordConstructor    _ value) = [value] getOCamlValues (MultipleConstructors cs)      = concat $ getOCamlValues <$> cs -toOCamlSpec :: OCamlType a => a -> [Text] -> Text -> Text -> Text-toOCamlSpec a modules url fp =-  pprinter $ mkSampleServerAndGoldenSpec (toOCamlType a) Nothing modules url fp+toOCamlSpec :: OCamlType a => a -> [Text] -> Maybe Text -> Text -> Text+toOCamlSpec a modules mUrl fp =+  case mUrl of+    Just url -> pprinter $ mkSampleServerAndGoldenSpec (toOCamlType a) Nothing modules url fp+    Nothing  -> pprinter $ mkGoldenDirSpec (toOCamlType a) Nothing modules fp  -- | OCamlTypeInFile do not require an instance of OCamlType since they are --   hand written OCaml files for Haskell types. Use typeable to get the --   type name.-{--typeInFileToOCamlSpec :: Text -> Int -> [Text] -> Text -> Text -> Text-typeInFileToOCamlSpec aTyConName typeParameterRefCount modules url fp =-  pprinter $ mkSampleServerAndGoldenSpec-    (OCamlDatatype (HaskellTypeMetaData aTyConName "" "")-       aTyConName $ OCamlValueConstructor $ NamedConstructor aTyConName $ OCamlEmpty)-    (Just typeParameterRefCount)-    modules-    url-    fp--}-typeInFileToOCamlSpec :: OCamlType a => a -> Int -> [Text] -> Text -> Text -> Text-typeInFileToOCamlSpec a typeParameterRefCount modules url fp =-  pprinter $ mkSampleServerAndGoldenSpec-    (toOCamlType a)-    (Just typeParameterRefCount)-    modules-    url-    fp+typeInFileToOCamlSpec :: OCamlType a => a -> Int -> [Text] -> Maybe Text -> Text -> Text+typeInFileToOCamlSpec a typeParameterRefCount modules mUrl fp =+  case mUrl of+    Just url ->+      pprinter $ mkSampleServerAndGoldenSpec (toOCamlType a) (Just typeParameterRefCount) modules url fp+    Nothing -> pprinter $ mkGoldenDirSpec (toOCamlType a) (Just typeParameterRefCount) modules fp
src/OCaml/Export.hs view
@@ -41,7 +41,8 @@   , mkOCamlSpecServer   , MkOCamlSpecAPI   , mkGoldenFiles-+  , runGoldenSpec+     -- re-export   , Proxy (..)   , (:>)
src/OCaml/Internal/Common.hs view
@@ -8,7 +8,6 @@  -} - {-# LANGUAGE OverloadedStrings #-}  module OCaml.Internal.Common where@@ -71,7 +70,12 @@   }  defaultOptions :: Options-defaultOptions = Options {includeOCamlInterface = False, aesonOptions = Aeson.defaultOptions, dependencies = Map.empty}+defaultOptions =+  Options+    { includeOCamlInterface = False+    , aesonOptions = Aeson.defaultOptions+    , dependencies = Map.empty+    }  data TypeMetaData = TypeMetaData   { topLevelOCamlTypeMetaData :: Maybe OCamlTypeMetaData -- Just if not primitive
test/FileApp.hs view
@@ -24,9 +24,22 @@ spec :: Spec spec = do   runIO $ mkGoldenFiles (Proxy :: Proxy FilePackage) 10 "test/interface/golden/golden/file"-+  -- runGoldenSpec (Proxy :: Proxy FilePackage) 10 "test/interface/golden/golden/file"   let dir = "test/interface/temp"-  runIO $ mkPackage (Proxy :: Proxy FilePackage) (PackageOptions dir "file" fileMap True $ Just $ SpecOptions "__tests__/file" "golden/file" "http://localhost:8083")++  -- create spec to be tested against servant+  runIO $+    mkPackage+      (Proxy :: Proxy FilePackage)+      (PackageOptions dir "file" fileMap True $+        Just $ SpecOptions "__tests__/file-servant" "golden/file" (Just "http://localhost:8083"))++  -- create spec to be tested against files only+  runIO $+    mkPackage+      (Proxy :: Proxy FilePackage)+      (PackageOptions dir "file" fileMap True $+        Just $ SpecOptions "__tests__/file" "golden/file" Nothing)    describe "OCaml Declaration with Interface: Product Types" $     compareInterfaceFiles "File"
test/Product.hs view
@@ -417,7 +417,7 @@   deriving (Eq,Show,Generic,ToJSON,FromJSON)  instance (ToADTArbitrary a, Arbitrary a) => ToADTArbitrary (NewTypeKey a)-instance Arbitrary a => Arbitrary (NewTypeKey a) where+instance Arbitrary (NewTypeKey a) where   arbitrary = NewTypeKey <$> arbitrary instance (Typeable a, OCamlType a) => OCamlType (NewTypeKey a) 
test/ProductApp.hs view
@@ -16,10 +16,32 @@  spec :: Spec spec = do-  runIO $ mkGoldenFiles (Proxy :: Proxy ProductPackage) 10 "test/interface/golden/golden/product"  +  runIO $ mkGoldenFiles (Proxy :: Proxy ProductPackage) 10 "test/interface/golden/golden/product"+  runGoldenSpec (Proxy :: Proxy ProductPackage) 10 "test/interface/golden/golden/product"    let dir = "test/interface/temp"-  runIO $ mkPackage (Proxy :: Proxy ProductPackage) (PackageOptions dir "product" fileMap True $ Just $ SpecOptions "__tests__/product" "golden/product" "http://localhost:8081")++  -- create spec to be tested against servant+  runIO $+    mkPackage+      (Proxy :: Proxy ProductPackage)+      (PackageOptions dir "product" fileMap True $+       Just $+         SpecOptions+           "__tests__/product-servant"+           "golden/product"+           (Just "http://localhost:8081"))++  -- create spec to be tested against files only+  runIO $+    mkPackage+      (Proxy :: Proxy ProductPackage)+      (PackageOptions dir "product" fileMap True $+       Just $+         SpecOptions+           "__tests__/product"+           "golden/product"+           Nothing)      describe "OCaml Declaration with Interface: Product Types" $ do     compareInterfaceFiles "Person"
test/Spec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE OverloadedStrings #-}@@ -7,7 +8,6 @@ {-# LANGUAGE TypeOperators #-}  -- base-import Control.Concurrent (forkIO) import Data.Monoid ((<>)) -- hspec import Test.Hspec@@ -17,10 +17,14 @@ import qualified Product as Product import qualified ProductApp as Product import qualified Sum as Sum-import SumApp import OCaml.Export++#ifdef SERVANT_SPEC+import Control.Concurrent (forkIO)+import SumApp -- warp import Network.Wai.Handler.Warp+#endif  main :: IO () main = do@@ -34,8 +38,9 @@       it "mkOCamlTypeMetaData on package A and B should equal mkOCamlTypeMetaData on B which has A as a dependency" $         (mkOCamlTypeMetaData (Proxy :: Proxy Product.ProductPackage)) <> (mkOCamlTypeMetaData (Proxy :: Proxy D.DependencyPackageWithoutProduct))           `shouldBe` mkOCamlTypeMetaData (Proxy :: Proxy D.DependencyPackage)-+  +#ifdef SERVANT_SPEC   _ <- forkIO $ run 8081 Product.productPackageApp   _ <- forkIO $ run 8082 sumPackageApp   run 8083 File.filePackageApp-  pure ()+#endif
test/Sum.hs view
@@ -48,9 +48,6 @@ compareInterfaceFiles :: FilePath -> SpecWith () compareInterfaceFiles = compareFiles "test/interface" "sum" True -compareNoInterfaceFiles :: FilePath -> SpecWith ()-compareNoInterfaceFiles = compareFiles "test/nointerface" "sum" False- mkGolden :: forall a. (ToADTArbitrary a, ToJSON a) => Proxy a -> IO () mkGolden Proxy = mkGoldenFileForType 10 (Proxy :: Proxy a) "test/interface/golden/golden/sum" @@ -67,8 +64,29 @@ spec :: Spec spec = do   runIO mkGoldenFiles+  runGoldenSpec (Proxy :: Proxy SumPackage) 10 "test/interface/golden/golden/sum"+   let dir = "test/interface/temp"-  runIO $ mkPackage (Proxy :: Proxy SumPackage) (PackageOptions dir "sum" Map.empty True $ Just $ SpecOptions "__tests__/sum" "golden/sum" "http://localhost:8082")++  -- create spec to be tested against servant+  runIO $+    mkPackage+     (Proxy :: Proxy SumPackage)+     (PackageOptions dir "sum" Map.empty True $+        Just $ SpecOptions+          "__tests__/sum-servant"+          "golden/sum"+          (Just "http://localhost:8082"))++  -- create spec to be tested against files only+  runIO $+    mkPackage+     (Proxy :: Proxy SumPackage)+     (PackageOptions dir "sum" Map.empty True $+        Just $ SpecOptions+          "__tests__/sum"+          "golden/sum"+          Nothing)    describe "OCaml Declaration with Interface: Sum Types" $ do     compareInterfaceFiles "OnOrOff"