feat(m01): /text 줄마다 요소조각 — 로직 부르기 이름 + 인자 글 (PLAN 5장)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8
This commit is contained in:
@@ -468,6 +468,7 @@ def lines(files: dict, key: str, given: dict) -> dict:
|
||||
env["줄"] = {r["이름"]: r["금액"] for r in shown if r["이름"]}
|
||||
for item, line in zip(items, shown):
|
||||
조각 = _formula_pieces(item["수량"], env, master, name_of, alias_by_name)
|
||||
요소 = _item_pieces(item, env, master)
|
||||
for part, money in _shares(line):
|
||||
split = part if len(line["비목"]) > 1 else None
|
||||
one = {
|
||||
@@ -476,6 +477,7 @@ def lines(files: dict, key: str, given: dict) -> dict:
|
||||
"이름글": _line_names(item, line, env, master, split, name_of),
|
||||
"금액": money,
|
||||
"조각": 조각,
|
||||
"요소조각": 요소,
|
||||
}
|
||||
why = _why(item, line)
|
||||
made[part].append({**one, "까닭": why} if why else one)
|
||||
@@ -491,6 +493,7 @@ def lines(files: dict, key: str, given: dict) -> dict:
|
||||
else [item.get("비목")]
|
||||
)
|
||||
조각 = _formula_pieces(item["수량"], env, master, name_of, alias_by_name)
|
||||
요소 = _item_pieces(item, env, master)
|
||||
for part in parts:
|
||||
if part not in mf.COST_ITEMS:
|
||||
continue
|
||||
@@ -502,6 +505,7 @@ def lines(files: dict, key: str, given: dict) -> dict:
|
||||
"이름글": _line_names(item, {}, env, master, split, name_of),
|
||||
"금액": None,
|
||||
"조각": 조각,
|
||||
"요소조각": 요소,
|
||||
}
|
||||
)
|
||||
for extra in row.get("덧줄") or []:
|
||||
@@ -529,6 +533,42 @@ def lines(files: dict, key: str, given: dict) -> dict:
|
||||
return _paired({"ok": True, "groups": groups, "계": 계, "별칭": marks})
|
||||
|
||||
|
||||
def _arg_text(node, env: dict, master) -> str:
|
||||
"""로직 부르기 인자 값을 사람이 읽는 글로 — 요소 키는 이름 · 입력 자리는 지금 값."""
|
||||
try:
|
||||
value = mf.evaluate(node, env, master, 0)
|
||||
except _CALC_ERRORS: # 값 없는 입력 자리 — 이름만
|
||||
return str(node[1]) if node[0] in ("name", "str") else ""
|
||||
if isinstance(value, str):
|
||||
for ref in (value, f"EQ:{value}"): # 기계 입력은 원문번호(0602-0025)
|
||||
try:
|
||||
return mc.plain(master.get(ref).get("이름")) or value
|
||||
except mf.FormulaError:
|
||||
pass
|
||||
return value
|
||||
return fmt(value)
|
||||
|
||||
|
||||
def _item_pieces(item: dict, env: dict, master) -> list[dict]:
|
||||
"""줄의 단가 자리(요소 · 로직 부르기) 조각 — PLAN 3-1 요소조각."""
|
||||
ref = item.get("요소")
|
||||
if item.get("종류") != "로직":
|
||||
name = str(item.get("이름") or "")
|
||||
if isinstance(ref, dict): # 재료 고르기 조건 — 품명만
|
||||
return [{"kind": "요소", "글": name}]
|
||||
piece = _elem_piece(master, ref)
|
||||
return [{**piece, "글": name or piece["글"]}]
|
||||
try:
|
||||
node = mf.parse(ref)
|
||||
key = mf.fill(node[1], env)
|
||||
name = str(master.logic(key).get("이름") or key)
|
||||
except _CALC_ERRORS:
|
||||
return [{"kind": "로직", "글": str(item.get("이름") or "")}]
|
||||
args = " · ".join(f"{k} {_arg_text(v, env, master)}" for k, v in node[2])
|
||||
out = [{"kind": "로직", "글": name, "참조": {"테이블": key[:2], "키": key}}]
|
||||
return out + ([{"kind": "글", "글": args}] if args else [])
|
||||
|
||||
|
||||
def _paired(answer: dict) -> dict:
|
||||
"""줄마다 짝 번호 — 두 칸(이름 꼴 · 값 꼴)이 같은 차례로 놓이게 1 부터."""
|
||||
at = 0
|
||||
@@ -536,6 +576,7 @@ def _paired(answer: dict) -> dict:
|
||||
for one in group["줄"]:
|
||||
at += 1
|
||||
one["짝"] = at
|
||||
one.setdefault("요소조각", [])
|
||||
return answer
|
||||
|
||||
|
||||
|
||||
@@ -358,3 +358,22 @@ def test_이름글_번호_별칭은_별칭표로_되돌려진다() -> None:
|
||||
raw_of = {m["이름"]: m["원문"] for m in got["별칭"]}
|
||||
back = mt.mc._unmask(left, raw_of)
|
||||
assert back.count("찾기(") == 9 and "촌락지대가" not in back
|
||||
|
||||
|
||||
def test_요소조각_로직_부르기는_이름과_인자_글_날식_없음() -> None:
|
||||
"""GC001093 트럭 줄 — 로직 조각(키 GC000268) + 인자 글(기계 이름 · 지역 지금 값)."""
|
||||
files = store.cm.load(folder=REAL)
|
||||
row = store.cm.master(REAL).logic("GC001093")
|
||||
given = dict(store.cm.시험입력(row))
|
||||
for got in (mt.lines(files, "GC001093", given), mt.lines(files, "GC001093", {})):
|
||||
lines = _all_lines(got)
|
||||
assert all("요소조각" in one for one in lines)
|
||||
truck = [one for one in lines if one["이름"].startswith("트럭")]
|
||||
assert truck
|
||||
for one in truck:
|
||||
head, args = one["요소조각"]
|
||||
assert head["kind"] == "로직" and head["참조"]["키"] == "GC000268"
|
||||
assert args["kind"] == "글" and "덤프트럭" in args["글"]
|
||||
assert "GC000268" not in args["글"] and "(" not in args["글"].split("덤프트럭")[0]
|
||||
labor = lines[0]["요소조각"]
|
||||
assert labor[0]["kind"] == "요소" and labor[0]["글"] == "배관공(수도)"
|
||||
|
||||
Reference in New Issue
Block a user