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

document; data basic structure init

上级 1bb7d17f
......@@ -62,7 +62,7 @@ pip install -r requirements.txt
{
// ...
"export": [
// TODO ...
"hello.sh"
]
}
```
......@@ -74,137 +74,17 @@ pip install -r requirements.txt
## `知识节点` 的导出习题选项配置编辑
首先,在知识节点下增加一个习题代码,例如在 `data/1.toolchains初阶/1.git/4.push修改到远程创库` 下增加一个`HelloWord.sh`代码:
```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`代码:
如前内容,我们在知识节点下增加一个习题定义,例如在 `data/1.toolchains初阶/1.git/4.push修改到远程创库` 下增加一个`hello.json`代码:
```json
{
"type": "code_options",
"author": "刘鑫",
"source": "HelloWorld.md",
"exercise_id":"1190bb7834904da0b1f20915960714d5",
"notebook_enable": true
"source": "hello.md",
"notebook_enable": false
}
```
其中 type 字段目前都固定是 `code_options`exercise_id 可以不写,处理程序会自动填补这个数据。根据具体情况写好其它字段,注意这里 source 的文件名,我们指定了一个 markdwon 文件。现在我们新建一个 HelloWorld.md 并编辑为:
其中 type 字段目前都固定是 `code_options`。根据具体情况写好其它字段,注意这里 source 的文件名,我们指定了一个 markdwon 文件。现在我们新建一个 HelloWorld.md 并编辑为:
````markdown
# Hello World
......@@ -222,7 +102,7 @@ $ git push origin master
## 选项
### A
### add 子命令错误
```console
// HelloWord.1.sh
......@@ -231,7 +111,7 @@ $ git commit -a "first modify README.txt"
$ git push origin master
```
### B
### commit 子命令错误
```console
$ git add README.txt
......@@ -239,6 +119,13 @@ $ git base -m "first modify README.txt"
$ 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
### before
```console
```shell
echo "do something before"
```
### after
```console
```shell
echo "do something after"
```
````
......@@ -286,9 +173,6 @@ $ $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
import sys
import re
id_set = set()
def load_json(p):
with open(p, 'r') as f:
......@@ -36,12 +37,26 @@ def parse_no_name(d):
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):
root = {}
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):
v = os.listdir(p)
......@@ -51,10 +66,42 @@ def gen_tree(data_path):
if os.path.isdir(no_dir):
yield no_dir, no_name
def ensure_node_id(cfg_path, cfg):
if cfg.get('node_id') is None:
cfg['node_id'] = gen_node_id()
dump_json(cfg_path, cfg, exist_ok=True, override=True)
def ensure_id_helper(node):
flag = False
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):
node = {}
......@@ -69,7 +116,12 @@ def gen_tree(data_path):
# 根节点
cfg_path = os.path.join(data_path, 'config.json')
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 = {
"node_id": cfg['node_id'],
"keywords": cfg['keywords'],
......@@ -81,41 +133,59 @@ def gen_tree(data_path):
for level_no_dir, level_no_name in list_dir(data_path):
print(level_no_dir)
no, level_name = parse_no_name(level_no_name)
cfg_path = os.path.join(level_no_dir, 'config.json')
cfg = load_json(cfg_path)
ensure_node_id(cfg_path, cfg)
level_path = os.path.join(level_no_dir, 'config.json')
level_cfg = load_json(level_path)
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_name, cfg['node_id'], cfg['keywords'])
level_name, level_cfg['node_id'], level_cfg['keywords'])
tree_node['children'].append(level_node)
# 章节点
for chapter_no_dir, chapter_no_name in list_dir(level_no_dir):
no, chapter_name = parse_no_name(chapter_no_name)
cfg_path = os.path.join(chapter_no_dir, 'config.json')
ensure_node_id(cfg_path, cfg)
cfg = load_json(cfg_path)
chapter_path = os.path.join(chapter_no_dir, 'config.json')
chapter_cfg = load_json(chapter_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_name, cfg['node_id'], cfg['keywords'])
chapter_name, chapter_cfg['node_id'], chapter_cfg['keywords'])
level_node_children.append(chapter_node)
# 知识点
for section_no_dir, section_no_name in list_dir(chapter_no_dir):
no, section_name = parse_no_name(section_no_name)
cfg_path = os.path.join(section_no_dir, 'config.json')
ensure_node_id(cfg_path, cfg)
cfg = load_json(cfg_path)
sec_path = os.path.join(section_no_dir, 'config.json')
sec_cfg = load_json(sec_path)
flag = ensure_node_id(sec_cfg) or check_export(section_no_dir, sec_cfg)
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)
# 确保习题分配了习题ID
for export in cfg['export']:
if export.get('exercise_id') is None:
export['exercise_id'] = gen_node_id()
dump_json(cfg_path, cfg, exist_ok=True, override=True)
for export in sec_cfg.get("export", []):
ecfg_path = os.path.join(section_no_dir, export)
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')
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册