packages feed

hslua-module-text 0.2.1 → 0.3.0

raw patch · 7 files changed

+230/−69 lines, 7 filesdep +tasty-luadep ~basedep ~hsluaPVP ok

version bump matches the API change (PVP)

Dependencies added: tasty-lua

Dependency ranges changed: base, hslua

API changes (from Hackage documentation)

+ Foreign.Lua.Module.Text: description :: Text
+ Foreign.Lua.Module.Text: documentedModule :: Module
+ Foreign.Lua.Module.Text: functions :: [(Text, HaskellFunction)]
+ Foreign.Lua.Module.Text: preloadModule :: String -> Lua ()

Files

ChangeLog.md view
@@ -1,5 +1,13 @@ # Revision history for hslua-module-text +## 0.3.0 -- 2020-08-15++- Use self-documenting module. This allows to include+  documentation with the module definition, and to auto-generate+  documentation from that. Requires hslua-1.2.0 or newer.++- Run CI tests with all GHC 8 versions, test stack builds.+ ## 0.2.1 -- 2019-05-04  - Require at least HsLua v1.0.3: that version has better support
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2017 Albert Krewinkel+Copyright (c) 2017-2020 Albert Krewinkel  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
hslua-module-text.cabal view
@@ -1,5 +1,5 @@ name:                hslua-module-text-version:             0.2.1+version:             0.3.0 synopsis:            Lua module for text description:         UTF-8 aware subset of Lua's `string` module. homepage:            https://github.com/hslua/hslua-module-text@@ -7,17 +7,18 @@ license-file:        LICENSE author:              Albert Krewinkel maintainer:          albert+hslua@zeitkraut.de-copyright:           © 2017–2019 Albert Krewinkel+copyright:           © 2017–2020 Albert Krewinkel category:            Foreign build-type:          Simple extra-source-files:  ChangeLog.md-                     test/hstext-test.lua+                     test/test-text.lua cabal-version:       >=1.10-tested-with:         GHC == 7.10.3-                   , GHC == 8.0.2+tested-with:         GHC == 8.0.2                    , GHC == 8.2.2                    , GHC == 8.4.4                    , GHC == 8.6.5+                   , GHC == 8.8.3+                   , GHC == 8.10.1  source-repository head   type:              git@@ -25,9 +26,9 @@  library   exposed-modules:     Foreign.Lua.Module.Text-  build-depends:       base       >= 4.7    && < 5+  build-depends:       base       >= 4.8    && < 5                      , bytestring >= 0.10.2 && < 0.11-                     , hslua      >= 1.0.3  && < 1.2+                     , hslua      >= 1.2    && < 1.3                      , text       >= 1      && < 1.3   hs-source-dirs:      src   default-language:    Haskell2010@@ -44,4 +45,5 @@                      , hslua-module-text                      , tasty                      , tasty-hunit+                     , tasty-lua   >= 0.2    && < 0.3                      , text
src/Foreign/Lua/Module/Text.hs view
@@ -1,7 +1,8 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-} {-| Module      : Foreign.Lua.Module.Text-Copyright   : © 2017–2019 Albert Krewinkel+Copyright   : © 2017–2020 Albert Krewinkel License     : MIT Maintainer  : Albert Krewinkel <tarleb+hslua@zeitkraut.de> Stability   : alpha@@ -10,44 +11,147 @@ Provide a lua module containing a selection of useful Text functions. -} module Foreign.Lua.Module.Text-  ( pushModule++  ( -- * Module+    pushModule+  , preloadModule+  , documentedModule+  , description+  , functions++    -- * Legacy   , pushModuleText   , preloadTextModule-  )where+  ) where +import Prelude hiding (reverse) import Control.Applicative ((<$>)) import Data.ByteString (ByteString) import Data.Text (Text) import Data.Maybe (fromMaybe) import Foreign.Lua (NumResults, Lua, Peekable, Pushable, ToHaskellFunction)+import Foreign.Lua.Call+import Foreign.Lua.Module hiding (preloadModule, pushModule)+import Foreign.Lua.Peek (Peeker, peekIntegral, peekText)+import Foreign.Lua.Push (pushIntegral, pushText) import qualified Foreign.Lua as Lua import qualified Data.Text as T +import qualified Foreign.Lua.Module as Module+--+-- Module+--++-- | Textual description of the "text" module.+description :: Text+description =+  "UTF-8 aware text manipulation functions, implemented in Haskell."++documentedModule :: Module+documentedModule = Module+  { moduleName = "paths"+  , moduleFields = []+  , moduleDescription = description+  , moduleFunctions = functions+  }+ -- | Pushes the @text@ module to the Lua stack. pushModule :: Lua NumResults-pushModule = do-  Lua.newtable-  Lua.addfunction "lower" (return . T.toLower :: Text -> Lua Text)-  Lua.addfunction "upper" (return . T.toUpper :: Text -> Lua Text)-  Lua.addfunction "reverse" (return . T.reverse :: Text -> Lua Text)-  Lua.addfunction "len" (return . fromIntegral . T.length :: Text -> Lua Lua.Integer)-  Lua.addfunction "sub" sub-  return 1+pushModule = 1 <$ Module.pushModule documentedModule --- | Legacy alias for '@pushModule@'. pushModuleText :: Lua NumResults-pushModuleText = pushModule+pushModuleText = 1 <$ Module.pushModule documentedModule +-- | Add the @text@ module under the given name to the table of+-- preloaded packages.+preloadModule :: String -> Lua ()+preloadModule name = Module.preloadModule $+  documentedModule { moduleName = T.pack name }+ -- | Add the text module under the given name to the table of preloaded -- packages. preloadTextModule :: String -> Lua ()-preloadTextModule = flip Lua.preloadhs pushModule+preloadTextModule = flip Lua.preloadhs pushModuleText +--+-- Functions+--++functions :: [(Text, HaskellFunction)]+functions =+  [ ("len", len)+  , ("lower", lower)+  , ("reverse", reverse)+  , ("sub", sub)+  , ("upper", upper)+  ]++-- | Wrapper for @'T.length'@.+len :: HaskellFunction+len = toHsFnPrecursor T.length+  <#> textParam "s"+  =#> intResult "length"+  #? "Determines the number of characters in a string."++-- | Wrapper for @'T.toLower'@.+lower :: HaskellFunction+lower = toHsFnPrecursor T.toLower+  <#> textParam "s"+  =#> textResult "Lowercase copy of `s`"+  #? "Convert a string to lower case"++-- | Wrapper for @'T.reverse'@.+reverse :: HaskellFunction+reverse = toHsFnPrecursor T.reverse+  <#> textParam "s"+  =#> textResult "Reversed `s`"+  #? "Reverses a string."+ -- | Returns a substring, using Lua's string indexing rules.-sub :: Text -> Lua.Integer -> Lua.Optional Lua.Integer -> Lua Text-sub s i j =-  let i' = fromIntegral i-      j' = fromIntegral . fromMaybe (-1) $ Lua.fromOptional j-      fromStart = if i' >= 0 then  i' - 1 else T.length s + i'-      fromEnd   = if j' <  0 then -j' - 1 else T.length s - j'-  in return . T.dropEnd fromEnd . T.drop fromStart $ s+sub :: HaskellFunction+sub = toHsFnPrecursor substring+  <#> textParam "s"+  <#> textIndex "i" "substring start position"+  <#> textOptionalIndex "j" "substring end position"+  =#> textResult "text substring"+  #? "Returns a substring, using Lua's string indexing rules."+  where+    substring :: Text -> Int -> Maybe Int -> Text+    substring s i jopt =+      let j = fromMaybe (-1) jopt+          fromStart = if i >= 0 then  i - 1 else T.length s + i+          fromEnd   = if j <  0 then -j - 1 else T.length s - j+      in T.dropEnd fromEnd . T.drop fromStart $ s++-- | Wrapper for @'T.toUpper'@.+upper :: HaskellFunction+upper = toHsFnPrecursor T.toUpper+  <#> textParam "s"+  =#> textResult "Lowercase copy of `s`"+  #? "Convert a string to lower case"++--+-- Parameters+--++textParam :: Text -> Parameter Text+textParam name =+  parameter peekText "string" name "UTF-8 encoded string"++textIndex :: Text -> Text -> Parameter Int+textIndex = parameter (peekIntegral @Int) "integer"++textOptionalIndex :: Text -> Text -> Parameter (Maybe Int)+textOptionalIndex = optionalParameter (peekIntegral @Int) "integer"++--+-- Results+--++textResult :: Text -- ^ Description+           -> FunctionResults Text+textResult = functionResult pushText "string"++intResult :: Text -- ^ Description+          -> FunctionResults Int+intResult = functionResult (pushIntegral @Int) "integer"
− test/hstext-test.lua
@@ -1,29 +0,0 @@------ Tests for the hstext module----local hstext = require 'hstext'--assert(hstext.lower 'YELLING' == 'yelling')-assert(hstext.upper 'silence' == 'SILENCE')-assert(hstext.len 'five' == 4)---- Test UTF-8-assert(hstext.upper 'Lübeck' == 'LÜBECK')-assert(hstext.upper 'Spaß' == 'SPASS')--assert(hstext.len 'Straße' == 6)-assert(hstext.len 'Charité' == 7)-assert(hstext.len '☃' == 1)--assert(hstext.reverse 'être' == 'ertê')-assert(hstext.reverse 'être' == 'ertê')--local hw = 'Hello, World'-assert(string.sub(hw, 6)      == hstext.sub(hw, 6))-assert(string.sub(hw, -1, -1) == hstext.sub(hw, -1, -1))-assert(string.sub(hw, -7, -2) == hstext.sub(hw, -7, -2))-assert(string.sub(hw,  7, -2) == hstext.sub(hw, 7, -2))-assert(string.sub(hw,  1,  5) == hstext.sub(hw, 1, 5))-assert(string.sub(hw,  5,  0) == hstext.sub(hw, 5, 0))-assert(string.sub(hw,  0,  2) == hstext.sub(hw, 0, 2))-assert(string.sub(hw, -19, 5) == hstext.sub(hw, -19, 5))
test/test-hslua-module-text.hs view
@@ -1,5 +1,5 @@ {--Copyright © 2017–2019 Albert Krewinkel+Copyright © 2017–2020 Albert Krewinkel  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal@@ -21,16 +21,22 @@ -} {-# LANGUAGE OverloadedStrings #-} -import Control.Monad (void, when)+import Control.Monad (void) import Foreign.Lua (Lua) import Foreign.Lua.Module.Text (preloadTextModule, pushModuleText) import Test.Tasty (TestTree, defaultMain, testGroup) import Test.Tasty.HUnit (assertEqual, testCase)+import Test.Tasty.Lua (translateResultsFromFile)  import qualified Foreign.Lua as Lua  main :: IO ()-main = defaultMain $ testGroup "hslua-module-text" [tests]+main = do+  luaTest <- Lua.run $ do+    Lua.openlibs+    Lua.requirehs "text" (void pushModuleText)+    translateResultsFromFile "test/test-text.lua"+  defaultMain $ testGroup "hslua-module-text" [tests, luaTest]  -- | HSpec tests tests :: TestTree@@ -50,14 +56,6 @@       preloadTextModule "hstext"       assertEqual' "loading the module fails " Lua.OK =<<         Lua.dostring "require 'hstext'"--  , testCase "Lua tests pass" . Lua.run $ do-      Lua.openlibs-      preloadTextModule "hstext"-      assertEqual' "error while running lua tests" Lua.OK =<< do-        st <- Lua.loadfile "test/hstext-test.lua"-        when (st == Lua.OK) $ Lua.call 0 0-        return st   ]  assertEqual' :: (Show a, Eq a) => String -> a -> a -> Lua ()
+ test/test-text.lua view
@@ -0,0 +1,78 @@+--+-- Tests for the text module+--+local text = require 'text'+local tasty = require 'tasty'++local group = tasty.test_group+local test = tasty.test_case+local assert = tasty.assert++return {+  group 'len' {+    test('ASCII', function ()+      tasty.assert.are_equal(text.len 'five!', 5)+    end),+    test('German sz', function ()+      tasty.assert.are_equal(text.len 'Straße', 6)+    end),+    test('string with small letter e accute', function ()+      tasty.assert.are_equal(text.len 'Charité', 7)+    end),+    test('Unicode snowman', function ()+      tasty.assert.are_equal(text.len '☃', 1)+    end)+  },++  group 'lower' {+    test('uppercase ASCII', function ()+      assert.are_equal(text.lower 'YELLING', 'yelling')+    end),+    test('lowercase ASCII', function ()+      assert.are_equal(text.lower 'talking', 'talking')+    end),+    test('capitalized word with umlaut', function ()+      assert.are_equal(text.lower 'Lübeck', 'lübeck')+    end),+  },++  group 'upper' {+    test('uppercase ASCII', function ()+      assert.are_equal(text.upper 'YELLING', 'YELLING')+    end),+    test('lowercase ASCII', function ()+      assert.are_equal(text.upper 'silence', 'SILENCE')+    end),+    test('capitalized word with umlaut', function ()+      assert.are_equal(text.upper 'Lübeck', 'LÜBECK')+    end),+    test('German ß becomes double S', function ()+      assert.are_equal(text.upper 'Spaß', 'SPASS')+    end),+  },++  group 'reverse' {+    test('être becomes ertê', function ()+      assert.are_equal(text.reverse 'être', 'ertê')+    end)+  },++  group 'sub' {+    test('behaves like string.sub for ASCII text', function ()+      local hw = 'Hello, World'+      assert.are_equal(text.sub(hw, 6),      string.sub(hw, 6))+      assert.are_equal(text.sub(hw, -1, -1), string.sub(hw, -1, -1))+      assert.are_equal(text.sub(hw, -7, -2), string.sub(hw, -7, -2))+      assert.are_equal(text.sub(hw,  7, -2), string.sub(hw, 7, -2))+      assert.are_equal(text.sub(hw,  1,  5), string.sub(hw, 1, 5))+      assert.are_equal(text.sub(hw,  5,  0), string.sub(hw, 5, 0))+      assert.are_equal(text.sub(hw,  0,  2), string.sub(hw, 0, 2))+      assert.are_equal(text.sub(hw, -19, 5), string.sub(hw, -19, 5))+    end),+    test('respects UTF-8', function ()+      assert.are_equal(text.sub('Für dich', 5), 'dich')+      assert.are_equal(text.sub('☢ radioactive', 0, 1), '☢')+      assert.are_equal(text.sub('☢ radioactive', -11, -1), 'radioactive')+    end)+  }+}