Skip to content

Commit 4f8cf44

Browse files
authored
Matlab mark (#7)
1 parent faf66c3 commit 4f8cf44

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+347
-50
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/dist-newstyle
22
/test/dst
3+
/test/matlab-dst
34
/cabal.project.freeze

answers-script.cabal

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ library
5858
import: warnings
5959

6060
-- Modules exported by the library.
61-
exposed-modules: MyLib, MyGit, MyMark
61+
exposed-modules: MyLib, MyGit, MyMark, MatlabMark
6262

6363
-- Modules included in this library but not exported.
6464
-- other-modules: MyGit
@@ -85,7 +85,9 @@ library
8585
tagged,
8686
transformers,
8787
monad-loops,
88-
aeson
88+
aeson,
89+
attoparsec,
90+
cmark-lens
8991

9092
-- Directories containing source files.
9193
hs-source-dirs: src
@@ -145,4 +147,14 @@ test-suite answers-script-test
145147
base ^>=4.21.0.0,
146148
answers-script,
147149
filepath,
148-
containers
150+
containers,
151+
directory-tree,
152+
hspec,
153+
QuickCheck,
154+
text,
155+
bytestring,
156+
lens,
157+
attoparsec,
158+
cmark,
159+
cmark-lens,
160+
directory

app/Main.hs

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
module Main where
22

33
import MyLib (someFunc)
4+
import MatlabMark qualified
45
import Options.Applicative
56

6-
data Sample = Sample
7+
data GenerateArgs = GenerateArgs
78
{ prefix :: String,
89
src :: String,
910
dst :: String
1011
}
1112

12-
sample :: Parser Sample
13-
sample =
14-
Sample
13+
generateParser :: Parser GenerateArgs
14+
generateParser =
15+
GenerateArgs
1516
<$> strOption
1617
( long "prefix"
1718
<> value ""
@@ -26,18 +27,64 @@ sample =
2627
<> help "path to static directory"
2728
)
2829

29-
greet :: Sample -> IO ()
30-
greet (Sample prefix src dst) = do
30+
generateCommand :: ParserInfo GenerateArgs
31+
generateCommand =
32+
info
33+
(generateParser <**> helper)
34+
( fullDesc
35+
<> progDesc "Import answers-db into answers static asset"
36+
<> header "Import answers-db into answers static asset"
37+
)
38+
39+
data MatlabMarkdownArgs = MatlabMarkdownArgs FilePath FilePath
40+
41+
matlabMarkdownParser :: Parser MatlabMarkdownArgs
42+
matlabMarkdownParser =
43+
MatlabMarkdownArgs
44+
<$> strOption
45+
( long "src"
46+
<> help "path to the markdown file that is exported from MATLAB"
47+
)
48+
<*> strOption
49+
( long "dst"
50+
<> help "path to a directory in answers-db"
51+
)
52+
53+
matlabMarkdownCommand :: ParserInfo MatlabMarkdownArgs
54+
matlabMarkdownCommand =
55+
info
56+
(matlabMarkdownParser <**> helper)
57+
( fullDesc
58+
<> progDesc "Build assets from a markdown file exported from MATLAB"
59+
<> header "Build assets from a markdown file exported from MATLAB"
60+
)
61+
62+
data Args = Generate GenerateArgs | MatlabMarkdown MatlabMarkdownArgs
63+
64+
-- data Args = Args { commandArgs :: CommandArgs }
65+
66+
argsParser :: Parser Args
67+
argsParser =
68+
hsubparser
69+
( command "generate" (Generate <$> generateCommand)
70+
<> command "matlab-markdown" (MatlabMarkdown <$> matlabMarkdownCommand)
71+
)
72+
73+
greet :: Args -> IO ()
74+
greet (Generate (GenerateArgs prefix src dst)) = do
3175
_ <- someFunc prefix src dst
3276
return ()
77+
greet (MatlabMarkdown (MatlabMarkdownArgs src dst)) = do
78+
MatlabMark.generateMatlabAnswersDB dst =<< MatlabMark.readMatlabMD src
3379

3480
main :: IO ()
35-
main = greet =<< execParser opts
36-
where
37-
opts =
38-
info
39-
(sample <**> helper)
40-
( fullDesc
41-
<> progDesc "import answers-db into answers static asset"
42-
<> header "what is header?"
43-
)
81+
main =
82+
greet
83+
=<< execParser
84+
( info
85+
(argsParser <**> helper)
86+
( fullDesc
87+
<> progDesc "Collection of utility functions for the Answers web app"
88+
<> header "Collection of utility functions for the Answers web app"
89+
)
90+
)

cabal.project

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,10 @@ source-repository-package
1919
location: https://github.com/jwiegley/gitlib.git
2020
subdir: hlibgit2
2121
tag: bf256617179d853bdbc12e9283b3f570ebb9d9d7
22-
--sha256: 13k3aymqwzpcijnjjka820nv6rkgakzbvh13glw98p1c4yhqwcbf
22+
--sha256: 13k3aymqwzpcijnjjka820nv6rkgakzbvh13glw98p1c4yhqwcbf
23+
24+
source-repository-package
25+
type: git
26+
location: https://github.com/ingun37/cmark-lens.git
27+
tag: 4456f10deccb61419ce28811db448c266931190f
28+
--sha256: 0s1zzpd1bgap403awkjar365qxsysw4lwq6i23whjydqj3whqdhb

src/MatlabMark.hs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
{-# LANGUAGE TemplateHaskell #-}
3+
4+
module MatlabMark (generateMatlabAnswersDB, readMatlabMD) where
5+
6+
import CMark
7+
import CMark.Lens
8+
import Control.Lens
9+
import Data.Attoparsec.Text qualified as A
10+
import Data.Text qualified as T
11+
import Data.Text.IO qualified as TIO
12+
import System.FilePath qualified as File
13+
14+
changeMatlabMarkdownDelimeters :: T.Text -> T.Text
15+
changeMatlabMarkdownDelimeters = T.replace "\n $$ " "\n```math\n" . T.replace " $$ \n" "\n``` \n" . T.replace "\n $" "\n $`" . T.replace "$\n" "`$\n"
16+
17+
theRecurse :: [Node] -> ([Node], [(String, [Node])])
18+
theRecurse [] = ([], [])
19+
theRecurse (x : xs) =
20+
let (nodes, pairs) = theRecurse xs
21+
problemNumber = A.parseOnly parseVersion (x ^. _nodesLens . ix 0 . _nodeType . _TEXT)
22+
in case problemNumber of
23+
Left _ -> (x : nodes, pairs)
24+
Right v -> ([], (v, nodes) : pairs)
25+
26+
groupByProblems :: Node -> ([Node], [(String, [Node])])
27+
groupByProblems (Node _ DOCUMENT nodes) = theRecurse nodes
28+
groupByProblems _ = undefined
29+
30+
parseVersion :: A.Parser String
31+
parseVersion = do
32+
major <- A.many1 A.digit
33+
_ <- A.char '.'
34+
minor <- A.many1 A.digit
35+
return $ major <> "." <> minor
36+
37+
generateMatlabAnswersDB :: FilePath -> Node -> IO ()
38+
generateMatlabAnswersDB outputDirPath node =
39+
let (intro, groups) = groupByProblems node
40+
toDoc = Node Nothing DOCUMENT
41+
writeMD name nodes = TIO.writeFile (outputDirPath File.</> (name <> ".md")) (CMark.nodeToCommonmark [] Nothing (toDoc nodes))
42+
in do
43+
writeMD "cover" intro
44+
mapM_ (uncurry writeMD) groups
45+
46+
readMatlabMD :: FilePath -> IO Node
47+
readMatlabMD mdFilePath = CMark.commonmarkToNode [] . changeMatlabMarkdownDelimeters <$> TIO.readFile mdFilePath

test/Main.hs

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,61 @@
1+
{-# LANGUAGE OverloadedStrings #-}
12
module Main (main) where
2-
import MyLib qualified
3-
import MyGit qualified
4-
import System.FilePath
5-
import Control.Monad
6-
import Data.Map
73

8-
src :: FilePath
9-
src = "test" </> "answers-db"
4+
import Control.Monad
5+
import Data.ByteString qualified as B
6+
import Data.Either qualified as E
7+
import Data.Text qualified as T
8+
import Data.Text.IO qualified as TIO
9+
import Data.Text.Encoding qualified as Encoding
10+
import MyLib qualified
11+
import MatlabMark qualified
12+
import System.Directory.Tree qualified as DT
13+
import System.Directory qualified as D
14+
import System.FilePath qualified as F
15+
import Test.Hspec
16+
import Control.Lens
17+
import CMark qualified
18+
import CMark.Lens
19+
import Data.Attoparsec.Text qualified as A
1020

11-
dst :: FilePath
12-
dst = "test" </> "dst"
21+
main :: IO ()
22+
main = hspec $ do
23+
describe "changeMatlabMarkdownDelimeters" $ do
24+
it "matlab answers markdown test" $ do
25+
matlab
26+
describe "MyLib.someFunc" $ do
27+
it "asset build test" $ do
28+
testCase
1329

14-
prefix :: String
15-
prefix = "prefix"
30+
testCase :: IO ()
31+
testCase =
32+
do
33+
let expect = "test" F.</> "expect"
34+
let dst = "test" F.</> "dst"
35+
let src = "test" F.</> "answers-db"
36+
_ <- MyLib.someFunc "prefix" src dst
37+
let reader x = do
38+
b <- B.readFile x
39+
return $ E.fromRight (T.pack $ F.takeBaseName x ++ ": " ++ show (B.length b)) $ Encoding.decodeUtf8' b
40+
a <- DT.readDirectoryWith reader dst
41+
let a' = a ^.DT._dirTree
42+
let a'' = DT.flattenDir (set DT._name "" a')
43+
b <- DT.readDirectoryWith reader expect
44+
let b' = b ^.DT._dirTree
45+
let b'' = DT.flattenDir (set DT._name "" b')
46+
zipWithM_ shouldBe a'' b''
1647

17-
main :: IO ()
18-
main = do
19-
pageDatas <- MyLib.someFunc prefix src dst
20-
forM_ pageDatas print
48+
matlab :: IO ()
49+
matlab =
50+
do
51+
node <- MatlabMark.readMatlabMD $ "test" F.</> "matlab-short.md"
52+
let dst = "test" F.</> "matlab-dst"
53+
D.createDirectoryIfMissing True dst
54+
MatlabMark.generateMatlabAnswersDB dst node
55+
a <- DT.readDirectoryWith TIO.readFile dst
56+
let a' = a ^.DT._dirTree
57+
let a'' = DT.flattenDir (set DT._name "" a')
58+
b <- DT.readDirectoryWith TIO.readFile ("test" F.</> "matlab-expect")
59+
let b' = b ^.DT._dirTree
60+
let b'' = DT.flattenDir (set DT._name "" b')
61+
zipWithM_ shouldBe a'' b''
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_pageContent":{"_pageTitle":"5.1 Continuous Mappings","_hash":"2125c437aaac928d5852224ff00a83f9d9776dda","_attributes":{},"_answers":1},"_parentHash":"6c11e3a31b4b8bd07bdef3f87887ab202a568679","_childPageContents":[{"_pageTitle":"8","_hash":"3e8d61043ed9bdb6b3cd4f197f0203bbdcb13db1","_attributes":{"a.md":{"_time":"2020-10-18T14:48:51+09:00","_attributeFile":{"_content":"I'll refer $`\\mathcal{T}`$ as $`\\mathcal{T}_X`$, $`\\mathcal{T}_1`$ as $`\\mathcal{T}_Y`$, $`\\mathcal{T}_2`$ as $`\\mathcal{T}_A`$, $`\\mathcal{T}_3`$ as $`\\mathcal{T}_B`$.\n\nLet's define $`x \\in X`$ and $`U \\in \\mathcal{T}_Y`$ such that $`f(x) \\in U`$. By definition of continuous mapping, there must exists a $`V`$ such that $`x \\in V \\in \\mathcal{T}_X`$ and $`f(x) \\in fV \\subseteq U`$.\n\nIf for any $`x \\in A`$ and any B-induced open set $`U_B \\in \\mathcal{T}_B`$, which must imply existance of $`U \\in \\mathcal{T}_Y`$, such that $`g(x) \\in U_B`$,\n\n![](IMG_44AF9D4BED6C-1.jpeg)\n\n...there exists an A-induced open set $`V_A`$, which must imply existance of $`V \\in \\mathcal{T}_A`$, such that the image $`gV_A`$ satisfies $`g(x) \\in gV_A \\subseteq U_B`$, then $`g`$ must be continuous. What we have to know is that if the image $`gV_A`$is subset of $`U_B`$, in other words, every $`x \\in V_A`$ will satisfiy $`g(x) \\in U_B`$. Let's proove it.\n\n![](IMG_E7FB922B8E70-1.jpeg)\n\n```math\n\\begin{aligned}\n & x \\in V_A \\\\\n & \\rightarrow x \\in V \\\\\n & \\rightarrow g(x) \\in gV \\\\\n & \\rightarrow g(x) \\in \\text{ some } U & \\text{ since } f \\text{ is continuous} \\\\\n & \\rightarrow g(x) \\in U \\cap B & \\text{ since codomain of } g \\text{ is } B \\\\\n & \\rightarrow g(x) \\in U_B\n\\end{aligned}\n```"}},"q.md":{"_time":"2020-04-12T01:08:01+09:00","_attributeFile":{"_content":"Let $`(X,\\mathcal{T})`$ and $`(Y,\\mathcal{T}_1)`$ be topological spaces and $`f:(X,\\mathcal{T}) \\rightarrow (Y,\\mathcal{T}_1)`$ a continuous mapping. Let $`A`$ be a subset of $`X`$, $`\\mathcal{T}_2`$ the induced topology on $`A`$, $`B = f(A)`$, $`\\mathcal{T}_3`$ the induced topology on $`B`$ and $`g:(A,\\mathcal{T}_2) \\rightarrow (B,\\mathcal{T}_3)`$ the restriction of $`f`$ to $`A`$. Prove that $`g`$ is continuous."}}},"_answers":1}]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_pageContent":{"_pageTitle":"books","_hash":"2aed5404c83f7a46aa249e0a6328af756b19d513","_attributes":{"q.md":{"_time":"2022-09-25T22:34:28+09:00","_attributeFile":{"_content":"# DON'T PANIC\n\nAlthough it has many omissions and contains much that is apocryphal, or at least wildly inaccurate, but it scores over the other answers over the internet in few important respects. First, the way it is written is very subjective, and second, it has the words DON'T PANIC inscribed in large friendly letters on its home."}}},"_answers":3},"_parentHash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","_childPageContents":[{"_pageTitle":"Topology Without Tears","_hash":"4c1513c92422dc16b3c5f13bd03d34ba0feeb6df","_attributes":{"author.txt":{"_time":"2022-09-25T22:34:28+09:00","_attributeFile":{"_content":"Sidney A. Morris"}}},"_answers":1},{"_pageTitle":"Category Theory For Programmers","_hash":"b614f31d04b3bc2b3d23ee4337475251429e5a9f","_attributes":{"author.txt":{"_time":"2022-09-25T22:34:28+09:00","_attributeFile":{"_content":"Bartosz Milewski"}}},"_answers":2}]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_pageContent":{"_pageTitle":"8","_hash":"3e8d61043ed9bdb6b3cd4f197f0203bbdcb13db1","_attributes":{"a.md":{"_time":"2020-10-18T14:48:51+09:00","_attributeFile":{"_content":"I'll refer $`\\mathcal{T}`$ as $`\\mathcal{T}_X`$, $`\\mathcal{T}_1`$ as $`\\mathcal{T}_Y`$, $`\\mathcal{T}_2`$ as $`\\mathcal{T}_A`$, $`\\mathcal{T}_3`$ as $`\\mathcal{T}_B`$.\n\nLet's define $`x \\in X`$ and $`U \\in \\mathcal{T}_Y`$ such that $`f(x) \\in U`$. By definition of continuous mapping, there must exists a $`V`$ such that $`x \\in V \\in \\mathcal{T}_X`$ and $`f(x) \\in fV \\subseteq U`$.\n\nIf for any $`x \\in A`$ and any B-induced open set $`U_B \\in \\mathcal{T}_B`$, which must imply existance of $`U \\in \\mathcal{T}_Y`$, such that $`g(x) \\in U_B`$,\n\n![](IMG_44AF9D4BED6C-1.jpeg)\n\n...there exists an A-induced open set $`V_A`$, which must imply existance of $`V \\in \\mathcal{T}_A`$, such that the image $`gV_A`$ satisfies $`g(x) \\in gV_A \\subseteq U_B`$, then $`g`$ must be continuous. What we have to know is that if the image $`gV_A`$is subset of $`U_B`$, in other words, every $`x \\in V_A`$ will satisfiy $`g(x) \\in U_B`$. Let's proove it.\n\n![](IMG_E7FB922B8E70-1.jpeg)\n\n```math\n\\begin{aligned}\n & x \\in V_A \\\\\n & \\rightarrow x \\in V \\\\\n & \\rightarrow g(x) \\in gV \\\\\n & \\rightarrow g(x) \\in \\text{ some } U & \\text{ since } f \\text{ is continuous} \\\\\n & \\rightarrow g(x) \\in U \\cap B & \\text{ since codomain of } g \\text{ is } B \\\\\n & \\rightarrow g(x) \\in U_B\n\\end{aligned}\n```"}},"q.md":{"_time":"2020-04-12T01:08:01+09:00","_attributeFile":{"_content":"Let $`(X,\\mathcal{T})`$ and $`(Y,\\mathcal{T}_1)`$ be topological spaces and $`f:(X,\\mathcal{T}) \\rightarrow (Y,\\mathcal{T}_1)`$ a continuous mapping. Let $`A`$ be a subset of $`X`$, $`\\mathcal{T}_2`$ the induced topology on $`A`$, $`B = f(A)`$, $`\\mathcal{T}_3`$ the induced topology on $`B`$ and $`g:(A,\\mathcal{T}_2) \\rightarrow (B,\\mathcal{T}_3)`$ the restriction of $`f`$ to $`A`$. Prove that $`g`$ is continuous."}}},"_answers":1},"_parentHash":"2125c437aaac928d5852224ff00a83f9d9776dda","_childPageContents":[]}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"_pageContent":{"_pageTitle":"Topology Without Tears","_hash":"4c1513c92422dc16b3c5f13bd03d34ba0feeb6df","_attributes":{"author.txt":{"_time":"2022-09-25T22:34:28+09:00","_attributeFile":{"_content":"Sidney A. Morris"}}},"_answers":1},"_parentHash":"2aed5404c83f7a46aa249e0a6328af756b19d513","_childPageContents":[{"_pageTitle":"5. Continuous Mappings","_hash":"6c11e3a31b4b8bd07bdef3f87887ab202a568679","_attributes":{},"_answers":1}]}

0 commit comments

Comments
 (0)