From 4399097564c041838140225f30dcda7f92caa88a Mon Sep 17 00:00:00 2001 From: Joris Date: Wed, 10 May 2017 10:29:30 +0200 Subject: Add tests for purescript number and parser utilities --- .gitlab-ci.yml | 2 +- Makefile | 3 ++ README.md | 2 +- bower.json | 3 +- js/Dom.js | 12 -------- js/Dom.purs | 74 -------------------------------------------- js/EditableNumber.purs | 72 ------------------------------------------- js/Main.purs | 56 ---------------------------------- js/Parser.purs | 76 ---------------------------------------------- js/src/Dom.js | 12 ++++++++ js/src/Dom.purs | 74 ++++++++++++++++++++++++++++++++++++++++++++ js/src/EditableNumber.purs | 56 ++++++++++++++++++++++++++++++++++ js/src/Main.purs | 57 ++++++++++++++++++++++++++++++++++ js/src/Number.purs | 22 ++++++++++++++ js/src/Parser.purs | 76 ++++++++++++++++++++++++++++++++++++++++++++++ js/test/Main.purs | 61 +++++++++++++++++++++++++++++++++++++ src/Main.hs | 4 +-- 17 files changed, 367 insertions(+), 295 deletions(-) delete mode 100644 js/Dom.js delete mode 100644 js/Dom.purs delete mode 100644 js/EditableNumber.purs delete mode 100644 js/Main.purs delete mode 100644 js/Parser.purs create mode 100644 js/src/Dom.js create mode 100644 js/src/Dom.purs create mode 100644 js/src/EditableNumber.purs create mode 100644 js/src/Main.purs create mode 100644 js/src/Number.purs create mode 100644 js/src/Parser.purs create mode 100644 js/test/Main.purs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 75c77f3..a7bc90d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,9 +19,9 @@ build: - npm install pulp - export PATH="$(pwd)/node_modules/.bin":$PATH - bower install --allow-root + - make test - export STACK_ROOT="$(pwd)/.stack" - stack setup - - stack install --only-dependencies - stack build - stack exec cooking build artifacts: diff --git a/Makefile b/Makefile index aaedc92..837803c 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,9 @@ start: stop: @tmux kill-session -t cooking +test: + @pulp test --src-path js + clean: @rm -rf bower_components @rm -rf node_modules diff --git a/README.md b/README.md index 44d7c1f..1a770b7 100644 --- a/README.md +++ b/README.md @@ -27,4 +27,4 @@ make stop TODO ---- -- add tests for purescript parser +- ameliore mobile view diff --git a/bower.json b/bower.json index b1fdd70..8983d5a 100644 --- a/bower.json +++ b/bower.json @@ -9,6 +9,7 @@ "purescript-maybe": "*", "purescript-parsing": "*", "purescript-integers": "*", - "purescript-math": "*" + "purescript-math": "*", + "purescript-spec": "*" } } diff --git a/js/Dom.js b/js/Dom.js deleted file mode 100644 index 6835c1f..0000000 --- a/js/Dom.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; - -exports.onInput = function (elt) { - return function (f) { - return function () { - elt.oninput = function(e) { - f(e.target.value)() - } - return {}; - }; - }; -}; diff --git a/js/Dom.purs b/js/Dom.purs deleted file mode 100644 index a71cda7..0000000 --- a/js/Dom.purs +++ /dev/null @@ -1,74 +0,0 @@ -module Dom - ( onInput - , selectElement - , selectElementFrom - , selectElementsFrom - , replaceElement - , appendNodes - , setValue - ) where - -import Control.Monad.Eff (Eff) -import Control.Monad.Except (runExcept) as Except -import Data.Array (range, catMaybes) as Array -import Data.Either (Either(Right)) -import Data.Foreign (toForeign) as Foreign -import Data.Maybe (Maybe(Nothing, Just)) -import Data.Traversable (sequence) as Traversable -import Prelude - -import DOM (DOM) -import DOM.HTML (window) as DOM -import DOM.HTML.HTMLInputElement (setValue) as HTMLInputElement -import DOM.HTML.Types (htmlDocumentToParentNode, readHTMLInputElement) as DOM -import DOM.HTML.Window (document) as DOM -import DOM.Node.Node (replaceChild, parentNode, appendChild) as DOM -import DOM.Node.NodeList (length, item) as DOM -import DOM.Node.ParentNode (QuerySelector) -import DOM.Node.ParentNode (querySelector, querySelectorAll) as DOM -import DOM.Node.Types (Element, Node) -import DOM.Node.Types (elementToParentNode) as DOM - -foreign import onInput :: forall e. Element -> (String -> Eff (dom :: DOM | e) Unit) -> Eff (dom :: DOM | e) Unit - -selectElement :: forall e. QuerySelector -> Eff (dom :: DOM | e) (Maybe Element) -selectElement query = do - document <- DOM.window >>= DOM.document - DOM.querySelector query (DOM.htmlDocumentToParentNode document) - -selectElementFrom :: forall e. Element -> QuerySelector -> Eff (dom :: DOM | e) (Maybe Element) -selectElementFrom elem query = DOM.querySelector query (DOM.elementToParentNode elem) - -selectElementsFrom :: forall e. Element -> QuerySelector -> Eff (dom :: DOM | e) (Array Node) -selectElementsFrom elem query = do - nodeList <- DOM.querySelectorAll query (DOM.elementToParentNode elem) - length <- DOM.length nodeList - Array.range 0 length - # map (\i -> DOM.item i nodeList) - # Traversable.sequence - # map Array.catMaybes - -replaceElement :: forall e. Node -> Node -> Eff (dom :: DOM | e) Unit -replaceElement before after = do - parent <- DOM.parentNode before - case parent of - Just n -> do - _ <- DOM.replaceChild after before n - pure unit - Nothing -> - pure unit - -appendNodes :: forall e. Node -> Array Node -> Eff (dom :: DOM | e) Unit -appendNodes parent nodes = - nodes - # map (\n -> DOM.appendChild n parent) - # Traversable.sequence - # map (const unit) - -setValue :: forall e. String -> Element -> Eff (dom :: DOM | e) Unit -setValue value elem = - case Except.runExcept $ DOM.readHTMLInputElement (Foreign.toForeign elem) of - Right inputElem -> do - HTMLInputElement.setValue value inputElem - _ -> - pure unit diff --git a/js/EditableNumber.purs b/js/EditableNumber.purs deleted file mode 100644 index eb5ddb0..0000000 --- a/js/EditableNumber.purs +++ /dev/null @@ -1,72 +0,0 @@ -module EditableNumber - ( NumberElem - , set - , formatNumber - ) where - -import Control.Monad.Eff (Eff) -import Data.Int (round, toNumber, pow) as Int -import Data.Maybe (Maybe(..)) -import Data.String (Pattern(..), Replacement(..)) -import Data.String (replace) as String -import DOM (DOM) -import DOM.HTML (window) as DOM -import DOM.HTML.Types (htmlDocumentToDocument) as DOM -import DOM.HTML.Window (document) as DOM -import DOM.Node.Document (createElement, createTextNode) as DOM -import DOM.Node.Element (setClassName, setAttribute) as DOM -import DOM.Node.Node (textContent) as DOM -import DOM.Node.Types (Element, Node) -import DOM.Node.Types (elementToNode, textToNode) as DOM -import Math (round) as Math -import Prelude - -import Dom (replaceElement, appendNodes) as Dom -import Parser (TextWithNumber) -import Parser (textWithNumber) as Parser - -type NumberElem = - { elem :: Element - , number :: Number - } - -set :: forall e. { tag :: String, node :: Node } -> Eff (dom :: DOM | e) (Maybe NumberElem) -set { tag, node } = do - content <- DOM.textContent node - case Parser.textWithNumber content of - Just twn -> do - textWithNumber <- textWithNumberElem tag twn - Dom.replaceElement node (DOM.elementToNode textWithNumber) - pure (Just { elem: textWithNumber, number: twn.number }) - Nothing -> - pure Nothing - -textWithNumberElem :: forall e. String -> TextWithNumber -> Eff (dom :: DOM | e) Element -textWithNumberElem tag { begin, number, end } = do - document <- DOM.htmlDocumentToDocument <$> (DOM.window >>= DOM.document) - elem <- DOM.createElement tag document - beginNode <- DOM.textToNode <$> DOM.createTextNode begin document - numberNode <- numberElem number - endNode <- DOM.textToNode <$> DOM.createTextNode end document - Dom.appendNodes (DOM.elementToNode elem) [ beginNode, DOM.elementToNode numberNode, endNode ] - pure elem - -numberElem :: forall e. Number -> Eff (dom :: DOM | e) Element -numberElem number = do - document <- DOM.htmlDocumentToDocument <$> (DOM.window >>= DOM.document) - container <- DOM.createElement "input" document - DOM.setClassName "number" container - DOM.setAttribute "value" (formatNumber number) container - pure container - -formatNumber :: Number -> String -formatNumber number = - if Math.round number == number then - show (Int.round number) - else - String.replace (Pattern ".") (Replacement ",") (show (roundAt 1 number)) - -roundAt :: Int -> Number -> Number -roundAt at n = - let exp = Int.toNumber (Int.pow 10 at) - in Math.round (n * exp) / exp diff --git a/js/Main.purs b/js/Main.purs deleted file mode 100644 index 062eb1d..0000000 --- a/js/Main.purs +++ /dev/null @@ -1,56 +0,0 @@ -module Main (main) where - -import Control.Monad.Eff (Eff) -import Data.Array (catMaybes) as Array -import Data.Maybe (Maybe(..)) -import Data.Traversable (sequence, sequence_) as Traversable -import DOM (DOM) -import DOM.Node.ParentNode (QuerySelector(..)) -import DOM.Node.Types (Node) -import DOM.Node.Types (elementToNode) as DOM -import Prelude - -import Dom (selectElement, selectElementsFrom, onInput, setValue, selectElementFrom) as Dom -import EditableNumber (NumberElem) -import EditableNumber (set, formatNumber) as EditableNumber -import Parser (number) as Parser - -main :: forall e. Eff (dom :: DOM | e) Unit -main = do - tagElems <- getNumberElements - numberElems <- Array.catMaybes <$> (Traversable.sequence $ map EditableNumber.set tagElems) - Traversable.sequence_ $ map (onInput numberElems) numberElems - -getNumberElements :: forall e. Eff (dom :: DOM | e) (Array { tag :: String, node :: Node }) -getNumberElements = do - h2 <- (map (\elem -> { tag: "h2", node: DOM.elementToNode elem})) <$> Dom.selectElement (QuerySelector "h2") - ul <- Dom.selectElement (QuerySelector "ul") - lis <- case ul of - Just elem -> do - myLis <- Dom.selectElementsFrom elem (QuerySelector "li") - pure $ map (\node -> { tag: "li", node: node }) myLis - _ -> do - pure [] - pure $ (maybeToArray h2 <> lis) - -onInput :: forall e. Array NumberElem -> NumberElem -> Eff (dom :: DOM | e) Unit -onInput numberElems { elem, number } = do - Dom.onInput elem (\value -> do - case Parser.number value of - Just newNumber -> - let mul = newNumber / number - in numberElems - # map (\ne -> do - inputNode <- Dom.selectElementFrom ne.elem (QuerySelector "input") - case inputNode of - Just node -> Dom.setValue (EditableNumber.formatNumber (ne.number * mul)) node - _ -> pure unit - ) - # Traversable.sequence_ - _ -> - pure unit - ) - -maybeToArray :: forall a. Maybe a -> Array a -maybeToArray (Just x) = [ x ] -maybeToArray _ = [] diff --git a/js/Parser.purs b/js/Parser.purs deleted file mode 100644 index cad9f1b..0000000 --- a/js/Parser.purs +++ /dev/null @@ -1,76 +0,0 @@ -module Parser - ( TextWithNumber - , textWithNumber - , number - ) where - -import Control.Alt ((<|>)) -import Data.Array as Array -import Data.Char as Char -import Data.Either (Either(Right)) -import Data.Int as Int -import Data.Maybe (fromMaybe) as Maybe -import Data.Maybe (Maybe(Just, Nothing)) -import Data.String as String -import Prelude -import Text.Parsing.Parser (Parser) -import Text.Parsing.Parser (runParser) as Parser -import Text.Parsing.Parser.Combinators (optionMaybe) as Parser -import Text.Parsing.Parser.String (satisfy, anyChar, string, eof) as Parser - -type TextWithNumber = - { begin :: String - , number :: Number - , end :: String - } - -textWithNumber :: String -> Maybe TextWithNumber -textWithNumber input = - case Parser.runParser input textWithNumberParser of - Right x -> Just x - _ -> Nothing - -number :: String -> Maybe Number -number input = - case Parser.runParser input (numberParser <* Parser.eof) of - Right x -> Just x - _ -> Nothing - -textWithNumberParser :: Parser String TextWithNumber -textWithNumberParser = do - begin <- String.fromCharArray <$> Array.many notDigit - num <- numberParser - end <- String.fromCharArray <$> Array.many Parser.anyChar - pure { begin: begin, number: num, end: end } - -numberFromIntArray :: Array Int -> Int -numberFromIntArray xs = - Array.range 0 (Array.length xs - 1) - # map (Int.pow 10) - # Array.reverse - # Array.zipWith (*) xs - # Array.foldl (+) 0 - -notDigit :: Parser String Char -notDigit = Parser.satisfy (not <<< isDigit) - -numberParser :: Parser String Number -numberParser = do - whole <- numberFromIntArray <$> Array.some digit - decimal <- Parser.optionMaybe $ do - _ <- Parser.string "," <|> Parser.string "." - digits <- Array.some digit - let decimals = numberFromIntArray digits - pure $ Int.toNumber decimals / Int.toNumber (Int.pow 10 (Array.length digits)) - pure (Int.toNumber whole + Maybe.fromMaybe 0.0 decimal) - -digit :: Parser String Int -digit = map (\c -> Char.toCharCode c - zeroCode) $ Parser.satisfy isDigit - -isDigit :: Char -> Boolean -isDigit char = - let code = Char.toCharCode char - in code >= zeroCode && code <= zeroCode + 9 - -zeroCode :: Int -zeroCode = 48 diff --git a/js/src/Dom.js b/js/src/Dom.js new file mode 100644 index 0000000..6835c1f --- /dev/null +++ b/js/src/Dom.js @@ -0,0 +1,12 @@ +"use strict"; + +exports.onInput = function (elt) { + return function (f) { + return function () { + elt.oninput = function(e) { + f(e.target.value)() + } + return {}; + }; + }; +}; diff --git a/js/src/Dom.purs b/js/src/Dom.purs new file mode 100644 index 0000000..a71cda7 --- /dev/null +++ b/js/src/Dom.purs @@ -0,0 +1,74 @@ +module Dom + ( onInput + , selectElement + , selectElementFrom + , selectElementsFrom + , replaceElement + , appendNodes + , setValue + ) where + +import Control.Monad.Eff (Eff) +import Control.Monad.Except (runExcept) as Except +import Data.Array (range, catMaybes) as Array +import Data.Either (Either(Right)) +import Data.Foreign (toForeign) as Foreign +import Data.Maybe (Maybe(Nothing, Just)) +import Data.Traversable (sequence) as Traversable +import Prelude + +import DOM (DOM) +import DOM.HTML (window) as DOM +import DOM.HTML.HTMLInputElement (setValue) as HTMLInputElement +import DOM.HTML.Types (htmlDocumentToParentNode, readHTMLInputElement) as DOM +import DOM.HTML.Window (document) as DOM +import DOM.Node.Node (replaceChild, parentNode, appendChild) as DOM +import DOM.Node.NodeList (length, item) as DOM +import DOM.Node.ParentNode (QuerySelector) +import DOM.Node.ParentNode (querySelector, querySelectorAll) as DOM +import DOM.Node.Types (Element, Node) +import DOM.Node.Types (elementToParentNode) as DOM + +foreign import onInput :: forall e. Element -> (String -> Eff (dom :: DOM | e) Unit) -> Eff (dom :: DOM | e) Unit + +selectElement :: forall e. QuerySelector -> Eff (dom :: DOM | e) (Maybe Element) +selectElement query = do + document <- DOM.window >>= DOM.document + DOM.querySelector query (DOM.htmlDocumentToParentNode document) + +selectElementFrom :: forall e. Element -> QuerySelector -> Eff (dom :: DOM | e) (Maybe Element) +selectElementFrom elem query = DOM.querySelector query (DOM.elementToParentNode elem) + +selectElementsFrom :: forall e. Element -> QuerySelector -> Eff (dom :: DOM | e) (Array Node) +selectElementsFrom elem query = do + nodeList <- DOM.querySelectorAll query (DOM.elementToParentNode elem) + length <- DOM.length nodeList + Array.range 0 length + # map (\i -> DOM.item i nodeList) + # Traversable.sequence + # map Array.catMaybes + +replaceElement :: forall e. Node -> Node -> Eff (dom :: DOM | e) Unit +replaceElement before after = do + parent <- DOM.parentNode before + case parent of + Just n -> do + _ <- DOM.replaceChild after before n + pure unit + Nothing -> + pure unit + +appendNodes :: forall e. Node -> Array Node -> Eff (dom :: DOM | e) Unit +appendNodes parent nodes = + nodes + # map (\n -> DOM.appendChild n parent) + # Traversable.sequence + # map (const unit) + +setValue :: forall e. String -> Element -> Eff (dom :: DOM | e) Unit +setValue value elem = + case Except.runExcept $ DOM.readHTMLInputElement (Foreign.toForeign elem) of + Right inputElem -> do + HTMLInputElement.setValue value inputElem + _ -> + pure unit diff --git a/js/src/EditableNumber.purs b/js/src/EditableNumber.purs new file mode 100644 index 0000000..6a6e3a8 --- /dev/null +++ b/js/src/EditableNumber.purs @@ -0,0 +1,56 @@ +module EditableNumber + ( NumberElem + , set + ) where + +import Control.Monad.Eff (Eff) +import Data.Maybe (Maybe(..)) +import DOM (DOM) +import DOM.HTML (window) as DOM +import DOM.HTML.Types (htmlDocumentToDocument) as DOM +import DOM.HTML.Window (document) as DOM +import DOM.Node.Document (createElement, createTextNode) as DOM +import DOM.Node.Element (setClassName, setAttribute) as DOM +import DOM.Node.Node (textContent) as DOM +import DOM.Node.Types (Element, Node) +import DOM.Node.Types (elementToNode, textToNode) as DOM +import Prelude + +import Dom (replaceElement, appendNodes) as Dom +import Number (format) as Number +import Parser (TextWithNumber) +import Parser (textWithNumber) as Parser + +type NumberElem = + { elem :: Element + , number :: Number + } + +set :: forall e. { tag :: String, node :: Node } -> Eff (dom :: DOM | e) (Maybe NumberElem) +set { tag, node } = do + content <- DOM.textContent node + case Parser.textWithNumber content of + Just twn -> do + textWithNumber <- textWithNumberElem tag twn + Dom.replaceElement node (DOM.elementToNode textWithNumber) + pure (Just { elem: textWithNumber, number: twn.number }) + Nothing -> + pure Nothing + +textWithNumberElem :: forall e. String -> TextWithNumber -> Eff (dom :: DOM | e) Element +textWithNumberElem tag { begin, number, end } = do + document <- DOM.htmlDocumentToDocument <$> (DOM.window >>= DOM.document) + elem <- DOM.createElement tag document + beginNode <- DOM.textToNode <$> DOM.createTextNode begin document + numberNode <- numberElem number + endNode <- DOM.textToNode <$> DOM.createTextNode end document + Dom.appendNodes (DOM.elementToNode elem) [ beginNode, DOM.elementToNode numberNode, endNode ] + pure elem + +numberElem :: forall e. Number -> Eff (dom :: DOM | e) Element +numberElem number = do + document <- DOM.htmlDocumentToDocument <$> (DOM.window >>= DOM.document) + container <- DOM.createElement "input" document + DOM.setClassName "number" container + DOM.setAttribute "value" (Number.format number) container + pure container diff --git a/js/src/Main.purs b/js/src/Main.purs new file mode 100644 index 0000000..42db131 --- /dev/null +++ b/js/src/Main.purs @@ -0,0 +1,57 @@ +module Main (main) where + +import Control.Monad.Eff (Eff) +import Data.Array (catMaybes) as Array +import Data.Maybe (Maybe(..)) +import Data.Traversable (sequence, sequence_) as Traversable +import DOM (DOM) +import DOM.Node.ParentNode (QuerySelector(..)) +import DOM.Node.Types (elementToNode) as DOM +import DOM.Node.Types (Node) +import Prelude + +import Dom (selectElement, selectElementsFrom, onInput, setValue, selectElementFrom) as Dom +import EditableNumber (NumberElem) +import EditableNumber (set) as EditableNumber +import Number (format) as Number +import Parser (number) as Parser + +main :: forall e. Eff (dom :: DOM | e) Unit +main = do + tagElems <- getNumberElements + numberElems <- Array.catMaybes <$> (Traversable.sequence $ map EditableNumber.set tagElems) + Traversable.sequence_ $ map (onInput numberElems) numberElems + +getNumberElements :: forall e. Eff (dom :: DOM | e) (Array { tag :: String, node :: Node }) +getNumberElements = do + h2 <- (map (\elem -> { tag: "h2", node: DOM.elementToNode elem})) <$> Dom.selectElement (QuerySelector "h2") + ul <- Dom.selectElement (QuerySelector "ul") + lis <- case ul of + Just elem -> do + myLis <- Dom.selectElementsFrom elem (QuerySelector "li") + pure $ map (\node -> { tag: "li", node: node }) myLis + _ -> do + pure [] + pure $ (maybeToArray h2 <> lis) + +onInput :: forall e. Array NumberElem -> NumberElem -> Eff (dom :: DOM | e) Unit +onInput numberElems { elem, number } = do + Dom.onInput elem (\value -> do + case Parser.number value of + Just newNumber -> + let mul = newNumber / number + in numberElems + # map (\ne -> do + inputNode <- Dom.selectElementFrom ne.elem (QuerySelector "input") + case inputNode of + Just node -> Dom.setValue (Number.format (ne.number * mul)) node + _ -> pure unit + ) + # Traversable.sequence_ + _ -> + pure unit + ) + +maybeToArray :: forall a. Maybe a -> Array a +maybeToArray (Just x) = [ x ] +maybeToArray _ = [] diff --git a/js/src/Number.purs b/js/src/Number.purs new file mode 100644 index 0000000..0403f19 --- /dev/null +++ b/js/src/Number.purs @@ -0,0 +1,22 @@ +module Number + ( format + , roundAt + ) where + +import Data.Int (round, toNumber, pow) as Int +import Data.String (Pattern(..), Replacement(..)) +import Data.String (replace) as String +import Math (round) as Math +import Prelude + +format :: Number -> String +format number = + if Math.round number == number then + show (Int.round number) + else + String.replace (Pattern ".") (Replacement ",") (show (roundAt 1 number)) + +roundAt :: Int -> Number -> Number +roundAt at n = + let exp = Int.toNumber (Int.pow 10 at) + in Math.round (n * exp) / exp diff --git a/js/src/Parser.purs b/js/src/Parser.purs new file mode 100644 index 0000000..cad9f1b --- /dev/null +++ b/js/src/Parser.purs @@ -0,0 +1,76 @@ +module Parser + ( TextWithNumber + , textWithNumber + , number + ) where + +import Control.Alt ((<|>)) +import Data.Array as Array +import Data.Char as Char +import Data.Either (Either(Right)) +import Data.Int as Int +import Data.Maybe (fromMaybe) as Maybe +import Data.Maybe (Maybe(Just, Nothing)) +import Data.String as String +import Prelude +import Text.Parsing.Parser (Parser) +import Text.Parsing.Parser (runParser) as Parser +import Text.Parsing.Parser.Combinators (optionMaybe) as Parser +import Text.Parsing.Parser.String (satisfy, anyChar, string, eof) as Parser + +type TextWithNumber = + { begin :: String + , number :: Number + , end :: String + } + +textWithNumber :: String -> Maybe TextWithNumber +textWithNumber input = + case Parser.runParser input textWithNumberParser of + Right x -> Just x + _ -> Nothing + +number :: String -> Maybe Number +number input = + case Parser.runParser input (numberParser <* Parser.eof) of + Right x -> Just x + _ -> Nothing + +textWithNumberParser :: Parser String TextWithNumber +textWithNumberParser = do + begin <- String.fromCharArray <$> Array.many notDigit + num <- numberParser + end <- String.fromCharArray <$> Array.many Parser.anyChar + pure { begin: begin, number: num, end: end } + +numberFromIntArray :: Array Int -> Int +numberFromIntArray xs = + Array.range 0 (Array.length xs - 1) + # map (Int.pow 10) + # Array.reverse + # Array.zipWith (*) xs + # Array.foldl (+) 0 + +notDigit :: Parser String Char +notDigit = Parser.satisfy (not <<< isDigit) + +numberParser :: Parser String Number +numberParser = do + whole <- numberFromIntArray <$> Array.some digit + decimal <- Parser.optionMaybe $ do + _ <- Parser.string "," <|> Parser.string "." + digits <- Array.some digit + let decimals = numberFromIntArray digits + pure $ Int.toNumber decimals / Int.toNumber (Int.pow 10 (Array.length digits)) + pure (Int.toNumber whole + Maybe.fromMaybe 0.0 decimal) + +digit :: Parser String Int +digit = map (\c -> Char.toCharCode c - zeroCode) $ Parser.satisfy isDigit + +isDigit :: Char -> Boolean +isDigit char = + let code = Char.toCharCode char + in code >= zeroCode && code <= zeroCode + 9 + +zeroCode :: Int +zeroCode = 48 diff --git a/js/test/Main.purs b/js/test/Main.purs new file mode 100644 index 0000000..e23f9e2 --- /dev/null +++ b/js/test/Main.purs @@ -0,0 +1,61 @@ +module Test.Main + ( main + ) where + +import Control.Monad.Eff (Eff) +import Data.Maybe (Maybe(Just, Nothing)) +import Prelude +import Test.Spec (describe, it) +import Test.Spec.Assertions (shouldEqual) +import Test.Spec.Reporter.Console (consoleReporter) +import Test.Spec.Runner (RunnerEffects, run) + +import Number (roundAt, format) as Number +import Parser (TextWithNumber) +import Parser (textWithNumber, number) as Parser + +main :: Eff (RunnerEffects ()) Unit +main = run [consoleReporter] do + + describe "Number" do + it "rounds numbers" $ do + (Number.roundAt 0 0.0) `shouldEqual` (0.0) + (Number.roundAt 5 0.0) `shouldEqual` (0.0) + (Number.roundAt 0 12.3456) `shouldEqual` (12.0) + (Number.roundAt 1 12.3456) `shouldEqual` (12.3) + (Number.roundAt 2 12.3456) `shouldEqual` (12.35) + (Number.roundAt 3 12.3456) `shouldEqual` (12.346) + (Number.roundAt 4 12.3456) `shouldEqual` (12.3456) + (Number.roundAt 5 12.3456) `shouldEqual` (12.3456) + + it "formats numbers" $ do + (Number.format 0.0) `shouldEqual` "0" + (Number.format 0.1) `shouldEqual` "0,1" + (Number.format 12.3456) `shouldEqual` "12,3" + (Number.format 12.9) `shouldEqual` "12,9" + (Number.format 12.99) `shouldEqual` "13,0" + (Number.format 123456.0) `shouldEqual` "123456" + (Number.format 1234.5678) `shouldEqual` "1234,6" + + describe "Parser" do + it "parses number" $ do + (Parser.number "") `shouldEqual` Nothing + (Parser.number "auie") `shouldEqual` Nothing + (Parser.number "13.8auie") `shouldEqual` Nothing + (Parser.number "13.") `shouldEqual` Nothing + (Parser.number ".8") `shouldEqual` Nothing + (Parser.number "13") `shouldEqual` (Just 13.0) + (Parser.number "13,8") `shouldEqual` (Just 13.8) + (Parser.number "13.8") `shouldEqual` (Just 13.8) + (Parser.number "123 456") `shouldEqual` Nothing + + it "parses textWithNumber" $ do + map showTwn (Parser.textWithNumber "") `shouldEqual` Nothing + map showTwn (Parser.textWithNumber "0") `shouldEqual` Just (showTwn { begin: "", number: 0.0, end: "" }) + map showTwn (Parser.textWithNumber "13,8") `shouldEqual` Just (showTwn { begin: "", number: 13.8, end: "" }) + map showTwn (Parser.textWithNumber "begin 0 end") `shouldEqual` Just (showTwn { begin: "begin ", number: 0.0, end: " end" }) + map showTwn (Parser.textWithNumber "14end") `shouldEqual` Just (showTwn { begin: "", number: 14.0, end: "end" }) + map showTwn (Parser.textWithNumber "begin14") `shouldEqual` Just (showTwn { begin: "begin", number: 14.0, end: "" }) + +showTwn :: TextWithNumber -> String +showTwn { begin, number, end } = begin <> show number <> end diff --git a/src/Main.hs b/src/Main.hs index dd37fe4..40ed81e 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -14,14 +14,14 @@ main = hakyllWith configuration $ do route idRoute compile copyFileCompiler - match "design/*" $ do + match "design/**" $ do route $ customRoute $ const "main.css" compile $ do filePath <- getResourceFilePath unsafeCompiler (readProcess "runghc" [ filePath ] "") >>= makeItem - match "js/*" $ do + match "js/src/**" $ do route $ customRoute $ const "main.js" compile $ unsafeCompiler (readProcess "pulp" [ "build", "--optimise", "--src-path", "js" ] "") -- cgit v1.2.3