提交 41bfb9e4 编写于 作者: M Mars Liu

document; data basic structure init

上级 1bb7d17f
...@@ -62,7 +62,7 @@ pip install -r requirements.txt ...@@ -62,7 +62,7 @@ pip install -r requirements.txt
{ {
// ... // ...
"export": [ "export": [
// TODO ... "hello.sh"
] ]
} }
``` ```
...@@ -74,137 +74,17 @@ pip install -r requirements.txt ...@@ -74,137 +74,17 @@ pip install -r requirements.txt
## `知识节点` 的导出习题选项配置编辑 ## `知识节点` 的导出习题选项配置编辑
首先,在知识节点下增加一个习题代码,例如在 `data/1.toolchains初阶/1.git/4.push修改到远程创库` 下增加一个`HelloWord.sh`代码: 如前内容,我们在知识节点下增加一个习题定义,例如在 `data/1.toolchains初阶/1.git/4.push修改到远程创库` 下增加一个`hello.json`代码:
```console
$ git add README.txt
$ git commit -m "first modify README.txt"
$ git push origin master
```
其次,增加一个同名的选项配置文件`HelloWord.json`,目前有三种配置规则
**单行替换规则**
* 配置由`one_line`字段指定的单行替换字典
* 格式是:`"<源字符串>"`: [`"<替换字符串A>"`, `<替换字符串B>`,...],
* 其中每个 `"<源字符串>"` `/` `"<替换字符串A>"` 被生成为是一个替换选项
* 指定的配置应该能至少生成 `3+` 个替换选项
```json
{
"one_line": {
"git add": ["git put", "git in", "git checkout"]
}
}
```
上面的替换规则会将代码替换成 3 个变种的代码:
```console
// 变种代码1
$ git put README.txt
$ git commit -m "first modify README.txt"
$ git push origin master
```
```console
// 变种代码2
$ git in README.txt
$ git commit -m "first modify README.txt"
$ git push origin master
```
```html
// 变种代码3
$ git checkout README.txt
$ git commit -m "first modify README.txt"
$ git push origin master
```
这些变种代码将会作为技能树该知识点该代码选择题的选项。
**多行替换规则**
* 配置由`multiline`字段指定的多行替换数组
* 数组的每个元素是一组替换规则,会整组被替换
例如:
```json
{
"mulitiline": [{
"git add": "git put",
"git commit -m": "git commit -a"
},
{
"git commit": "git base",
"git push": "git pull"
}]
}
```
同样,该配置将支持将源代码生成2个变种代码
```console
// 变种代码1
$ git put README.txt
$ git commit -a "first modify README.txt"
$ git push origin master
```
```console
// 变种代码2, 注意第2组替换规则,包含了两行替换
$ git add README.txt
$ git base -m "first modify README.txt"
$ git pull origin master
```
## 预制的替换规则
* 配置由 `prepared` 字段制定的预制文件数组
* 数组每一个元素是一个预制的代码文件的路径文件名
例如:
```json
{
"prepared": [
"HelloWord.1.sh",
"HelloWord.2.sh",
"HelloWord.3.sh"]
}
```
同样,该配置将支持将源代码生成3个变种代码
```console
// HelloWord.1.sh
$ git put README.txt
$ git commit -a "first modify README.txt"
$ git push origin master
```
```console
$ git add README.txt
$ git base -m "first modify README.txt"
$ git pull origin master
```
## 使用 markdown 编写习题
如前内容,我们在知识节点下增加一个习题配置,例如在 `data/1.toolchains初阶/1.git/4.push修改到远程创库` 下增加一个`HelloWorld.json`代码:
```json ```json
{ {
"type": "code_options", "type": "code_options",
"author": "刘鑫", "author": "刘鑫",
"source": "HelloWorld.md", "source": "hello.md",
"exercise_id":"1190bb7834904da0b1f20915960714d5", "notebook_enable": false
"notebook_enable": true
} }
``` ```
其中 type 字段目前都固定是 `code_options`exercise_id 可以不写,处理程序会自动填补这个数据。根据具体情况写好其它字段,注意这里 source 的文件名,我们指定了一个 markdwon 文件。现在我们新建一个 HelloWorld.md 并编辑为: 其中 type 字段目前都固定是 `code_options`。根据具体情况写好其它字段,注意这里 source 的文件名,我们指定了一个 markdwon 文件。现在我们新建一个 HelloWorld.md 并编辑为:
````markdown ````markdown
# Hello World # Hello World
...@@ -222,7 +102,7 @@ $ git push origin master ...@@ -222,7 +102,7 @@ $ git push origin master
## 选项 ## 选项
### A ### add 子命令错误
```console ```console
// HelloWord.1.sh // HelloWord.1.sh
...@@ -231,7 +111,7 @@ $ git commit -a "first modify README.txt" ...@@ -231,7 +111,7 @@ $ git commit -a "first modify README.txt"
$ git push origin master $ git push origin master
``` ```
### B ### commit 子命令错误
```console ```console
$ git add README.txt $ git add README.txt
...@@ -239,6 +119,13 @@ $ git base -m "first modify README.txt" ...@@ -239,6 +119,13 @@ $ git base -m "first modify README.txt"
$ git pull origin master $ git pull origin master
``` ```
### push 子命令错误
```console
$ git add README.txt
$ git commit -m "first modify README.txt"
$ git pull origin master
```
```` ````
...@@ -256,13 +143,13 @@ $ git pull origin master ...@@ -256,13 +143,13 @@ $ git pull origin master
### before ### before
```console ```shell
echo "do something before" echo "do something before"
``` ```
### after ### after
```console ```shell
echo "do something after" echo "do something after"
``` ```
```` ````
...@@ -286,9 +173,6 @@ $ $code ...@@ -286,9 +173,6 @@ $ $code
注意这里的代码中,有一个 `$code` 占位符,它在管道程序处理过程中,会替换成答案和个选项内容中的代码。 注意这里的代码中,有一个 `$code` 占位符,它在管道程序处理过程中,会替换成答案和个选项内容中的代码。
在后续的数据处理流程中,markdown 会被编译为 prepared 类型的习题。
## 技能树合成 ## 技能树合成
......
{
"keywords": []
}
\ No newline at end of file
{
"keywords": []
}
\ No newline at end of file
{
"keywords": []
}
\ No newline at end of file
{
"keywords": []
}
\ No newline at end of file
...@@ -5,6 +5,7 @@ import uuid ...@@ -5,6 +5,7 @@ import uuid
import sys import sys
import re import re
id_set = set()
def load_json(p): def load_json(p):
with open(p, 'r') as f: with open(p, 'r') as f:
...@@ -36,12 +37,26 @@ def parse_no_name(d): ...@@ -36,12 +37,26 @@ def parse_no_name(d):
return no, dir_name return no, dir_name
def check_export(base, cfg):
flag = False
exports = []
for export in cfg.get('export', []):
ecfg_path = os.path.join(base, export)
if os.path.exists(ecfg_path):
exports.append(export)
else:
flag = True
if flag:
cfg["export"] = exports
return flag
def gen_tree(data_path): def gen_tree(data_path):
root = {} root = {}
def gen_node_id(): def gen_node_id():
return ''.join(str(uuid.uuid5(uuid.NAMESPACE_URL, 'skill_tree')).split('-')) # return ''.join(str(uuid.uuid5(uuid.NAMESPACE_URL, 'skill_tree')).split('-'))
return "c-" + uuid.uuid4().hex
def list_dir(p): def list_dir(p):
v = os.listdir(p) v = os.listdir(p)
...@@ -51,10 +66,42 @@ def gen_tree(data_path): ...@@ -51,10 +66,42 @@ def gen_tree(data_path):
if os.path.isdir(no_dir): if os.path.isdir(no_dir):
yield no_dir, no_name yield no_dir, no_name
def ensure_node_id(cfg_path, cfg): def ensure_id_helper(node):
if cfg.get('node_id') is None: flag = False
cfg['node_id'] = gen_node_id()
dump_json(cfg_path, cfg, exist_ok=True, override=True) if (node.get('node_id') is None) or node.get('node_id') in id_set:
node['node_id'] = gen_node_id()
flag = True
id_set.add(node['node_id'])
if 'children' in node:
for c in node["children"]:
flag = flag or ensure_id_helper(list(c.values())[0])
return flag
def ensure_node_id(cfg):
return ensure_id_helper(cfg)
def ensure_title_helper(node, cfg_path, title=""):
flag = False
if node.get('title') is None:
if cfg_path:
node['title'] = re.sub("^[0-9]{1,3}\.", "", os.path.split(os.path.dirname(cfg_path))[-1])
else:
node['title'] = title
flag = True
if 'children' in node:
for c in node["children"]:
flag = flag or ensure_title_helper(list(c.values())[0], None, list(c.keys())[0])
return flag
def ensure_title(cfg, cfg_path):
return ensure_title_helper(cfg, cfg_path)
def make_node(name, node_id, keywords, children=None): def make_node(name, node_id, keywords, children=None):
node = {} node = {}
...@@ -69,7 +116,12 @@ def gen_tree(data_path): ...@@ -69,7 +116,12 @@ def gen_tree(data_path):
# 根节点 # 根节点
cfg_path = os.path.join(data_path, 'config.json') cfg_path = os.path.join(data_path, 'config.json')
cfg = load_json(cfg_path) cfg = load_json(cfg_path)
ensure_node_id(cfg_path, cfg) if ensure_node_id(cfg):
dump_json(cfg_path, cfg)
if ensure_title(cfg, cfg_path):
cfg["title"] = "C"
dump_json(cfg_path, cfg, exist_ok=True, override=True)
tree_node = { tree_node = {
"node_id": cfg['node_id'], "node_id": cfg['node_id'],
"keywords": cfg['keywords'], "keywords": cfg['keywords'],
...@@ -81,41 +133,59 @@ def gen_tree(data_path): ...@@ -81,41 +133,59 @@ def gen_tree(data_path):
for level_no_dir, level_no_name in list_dir(data_path): for level_no_dir, level_no_name in list_dir(data_path):
print(level_no_dir) print(level_no_dir)
no, level_name = parse_no_name(level_no_name) no, level_name = parse_no_name(level_no_name)
cfg_path = os.path.join(level_no_dir, 'config.json') level_path = os.path.join(level_no_dir, 'config.json')
cfg = load_json(cfg_path) level_cfg = load_json(level_path)
ensure_node_id(cfg_path, cfg) if ensure_node_id(level_cfg) or check_export(level_no_dir, level_cfg):
dump_json(level_path, level_cfg, exist_ok=True, override=True)
if ensure_title(level_cfg, level_path):
dump_json(level_path, level_cfg, exist_ok=True, override=True)
level_node, level_node_children = make_node( level_node, level_node_children = make_node(
level_name, cfg['node_id'], cfg['keywords']) level_name, level_cfg['node_id'], level_cfg['keywords'])
tree_node['children'].append(level_node) tree_node['children'].append(level_node)
# 章节点 # 章节点
for chapter_no_dir, chapter_no_name in list_dir(level_no_dir): for chapter_no_dir, chapter_no_name in list_dir(level_no_dir):
no, chapter_name = parse_no_name(chapter_no_name) no, chapter_name = parse_no_name(chapter_no_name)
cfg_path = os.path.join(chapter_no_dir, 'config.json') chapter_path = os.path.join(chapter_no_dir, 'config.json')
ensure_node_id(cfg_path, cfg) chapter_cfg = load_json(chapter_path)
cfg = load_json(cfg_path) if ensure_node_id(chapter_cfg) or check_export(chapter_no_dir, chapter_cfg):
dump_json(chapter_path, chapter_cfg, exist_ok=True, override=True)
if ensure_title(chapter_cfg, chapter_path):
dump_json(chapter_path, chapter_cfg, exist_ok=True, override=True)
chapter_node, chapter_node_children = make_node( chapter_node, chapter_node_children = make_node(
chapter_name, cfg['node_id'], cfg['keywords']) chapter_name, chapter_cfg['node_id'], chapter_cfg['keywords'])
level_node_children.append(chapter_node) level_node_children.append(chapter_node)
# 知识点 # 知识点
for section_no_dir, section_no_name in list_dir(chapter_no_dir): for section_no_dir, section_no_name in list_dir(chapter_no_dir):
no, section_name = parse_no_name(section_no_name) no, section_name = parse_no_name(section_no_name)
cfg_path = os.path.join(section_no_dir, 'config.json') sec_path = os.path.join(section_no_dir, 'config.json')
ensure_node_id(cfg_path, cfg) sec_cfg = load_json(sec_path)
cfg = load_json(cfg_path) flag = ensure_node_id(sec_cfg) or check_export(section_no_dir, sec_cfg)
section_node, section_node_children = make_node( section_node, section_node_children = make_node(
section_name, cfg['node_id'], cfg['keywords'], cfg['children']) section_name, sec_cfg['node_id'], sec_cfg['keywords'], sec_cfg.get('children', []))
chapter_node_children.append(section_node) chapter_node_children.append(section_node)
# 确保习题分配了习题ID # 确保习题分配了习题ID
for export in cfg['export']:
if export.get('exercise_id') is None: for export in sec_cfg.get("export", []):
export['exercise_id'] = gen_node_id() ecfg_path = os.path.join(section_no_dir, export)
dump_json(cfg_path, cfg, exist_ok=True, override=True) ecfg = load_json(ecfg_path)
if (ecfg.get('exercise_id') is None) or (ecfg.get('exercise_id') in id_set):
ecfg['exercise_id'] = uuid.uuid4().hex
dump_json(ecfg_path, ecfg, exist_ok=True, override=True)
id_set.add(ecfg['exercise_id'])
if flag:
dump_json(sec_path, sec_cfg, exist_ok=True, override=True)
if ensure_title(sec_cfg, sec_path):
dump_json(sec_path, sec_cfg, exist_ok=True, override=True)
# 保存技能树骨架 # 保存技能树骨架
tree_path = os.path.join(data_path, 'tree.json') tree_path = os.path.join(data_path, 'tree.json')
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册