aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/FEATURE_DEVELOPMENT_EXAMPLE.md
blob: 838d0c42743b48b1cb1055f96b6ce31ad0f9e1b5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# OneRoll 功能开发示例:注释功能

本文档展示了如何为 OneRoll 项目添加新功能的完整开发流程,以添加注释功能为例。

## 功能需求

添加注释功能,允许用户在骰子表达式末尾使用 `#` 添加注释,返回结果中包含注释信息。

**示例:**
- `3d6 + 2 # 攻击投掷` → 返回 `{'total': 14, 'comment': '攻击投掷', ...}`
- `4d6kh3 # 属性投掷` → 返回 `{'total': 15, 'comment': '属性投掷', ...}`

## 开发步骤

### 1. 更新语法定义 (grammar.pest)

```pest
// 添加注释规则
comment = { "#" ~ (!"\n" ~ ANY)* }

// 修改主表达式规则以支持可选注释
dice_expr = { dice_term ~ (op ~ dice_term)* ~ comment? }
```

### 2. 更新类型定义 (types.rs)

```rust
// 为 DiceResult 添加注释字段
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiceResult {
    pub expression: String,
    pub total: i32,
    pub rolls: Vec<Vec<i32>>,
    pub details: String,
    pub comment: Option<String>,  // 新增字段
}

// 为 Expression 添加注释变体
#[derive(Debug, Clone)]
pub enum Expression {
    // ... 现有变体
    WithComment(Box<Expression>, Option<String>),  // 新增变体
}
```

### 3. 更新解析器 (parser.rs)

```rust
// 添加注释解析函数
fn parse_comment(pair: pest::iterators::Pair<Rule>) -> Result<Option<String>, DiceError> {
    match pair.as_rule() {
        Rule::comment => {
            let comment = pair.as_str().trim_start_matches('#').trim();
            Ok(if comment.is_empty() { None } else { Some(comment.to_string()) })
        }
        _ => Ok(None),
    }
}

// 修改主解析逻辑以处理注释
Rule::dice_expr => {
    let mut pairs = pair.into_inner();
    let mut expr = Self::parse_dice_term(pairs.next().unwrap())?;
    
    while let Some(pair) = pairs.next() {
        match pair.as_rule() {
            Rule::op => {
                // ... 操作符处理逻辑
            }
            Rule::comment => {
                let comment = Self::parse_comment(pair)?;
                if let Some(comment_text) = comment {
                    expr = Expression::WithComment(Box::new(expr), Some(comment_text));
                }
            }
            _ => {}
        }
    }
    Ok(expr)
}
```

### 4. 更新计算器 (calculator.rs)

```rust
// 为所有 DiceResult 创建添加 comment: None
Expression::Number(n) => Ok(DiceResult {
    expression: n.to_string(),
    total: *n,
    rolls: vec![],
    details: format!("{}", n),
    comment: None,  // 新增
}),

// 添加注释处理逻辑
Expression::WithComment(expr, comment) => {
    let mut result = self.evaluate_expression(expr)?;
    result.comment = comment.clone();
    Ok(result)
}
```

### 5. 更新 Python 绑定 (python_bindings.rs)

```rust
// 在所有返回字典中添加注释字段
let dict = PyDict::new(py);
dict.set_item("expression", &result.expression)?;
dict.set_item("total", result.total)?;
dict.set_item("rolls", result.rolls)?;
dict.set_item("details", &result.details)?;
dict.set_item("comment", result.comment.as_deref().unwrap_or(""))?;  // 新增

Ok(dict.into())
```

### 6. 更新类型注解 (_core.pyi)

```python
def roll_dice(expression: str) -> Dict[str, Any]:
    """
    解析并计算骰子表达式
    
    Returns:
        包含以下键的字典:
        - expression: str - 表达式字符串
        - total: int - 总点数
        - rolls: List[List[int]] - 投掷结果列表
        - details: str - 详细信息
        - comment: str - 用户注释  # 新增
    """
    ...
```

### 7. 更新 Python 接口 (__init__.py)

```python
def roll(expression: str) -> Dict[str, Any]:
    """
    解析并计算骰子表达式(便捷函数)
    
    Args:
        expression: 骰子表达式字符串,支持注释
        
    Returns:
        投掷结果字典,包含 comment 字段
        
    Example:
        result = oneroll.roll("3d6 + 2 # 攻击投掷")
        print(result["comment"])  # 输出: "攻击投掷"
    """
    return _roll_dice(expression)
```

### 8. 更新用户界面

#### 命令行界面 (__main__.py)
```python
def print_result(self, result: Dict[str, Any], expression: str = None):
    """美化打印投掷结果"""
    # ... 现有逻辑
    
    # 显示注释
    comment = result.get("comment", "")
    if comment:
        text.append(f"\n注释: ", style="bold")
        text.append(f"{comment}", style="italic blue")
    
    panel = Panel(text, title="投掷结果", border_style=color)
    console.print(panel)
```

#### TUI 界面 (tui.py)
```python
def show_result(self, result: Dict[str, Any], expression: str) -> None:
    """显示投掷结果"""
    # ... 现有逻辑
    
    # 显示注释
    comment = result.get("comment", "")
    if comment:
        display_text += f"\n\n[bold]注释:[/bold] [italic blue]{comment}[/italic blue]"
    
    self.update(display_text)
```

## 构建和测试

### 构建项目
```bash
maturin develop
```

### 测试新功能
```python
# 基本测试
import oneroll
result = oneroll.roll("3d6 + 2 # 攻击投掷")
print(f"总点数: {result['total']}, 注释: {result['comment']}")

# 命令行测试
python -m oneroll "4d6kh3 # 属性投掷"

# 复杂表达式测试
python -c "import oneroll; print(oneroll.roll('2d6! # 爆炸骰子攻击'))"
```

## 测试结果

```
总点数: 14, 注释: 攻击投掷
```

```
╭──────────────────────────────────────────────── 投掷结果 ────────────────────────────────────────────────╮
│ 🎲 4d6                                                                                                   │
│ 总点数: 13                                                                                               │
│ 详情: 4d6kh3 = 13 (详情: [[5], [4], [4]])                                                                │
│ 投掷结果: [[5], [4], [4]]                                                                                │
│ 注释: 属性投掷                                                                                           │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```

## 开发要点

### 1. 模块化开发
- 每个功能都在相应的模块中实现
- 保持代码的清晰结构和职责分离

### 2. 类型安全
- 所有新功能都有完整的类型注解
- 使用 Option<T> 处理可选字段

### 3. 向后兼容
- 新功能不影响现有 API
- 可选字段使用默认值

### 4. 用户体验
- 更新所有用户界面以显示新功能
- 提供清晰的文档和示例

### 5. 错误处理
- 处理边界情况(如空注释)
- 保持现有的错误处理机制

## 扩展建议

### 1. 注释验证
```rust
// 可以添加注释长度限制
if comment.len() > MAX_COMMENT_LENGTH {
    return Err(DiceError::InvalidExpression("注释过长".to_string()));
}
```

### 2. 注释格式化
```rust
// 可以添加注释格式化选项
pub struct CommentOptions {
    pub max_length: usize,
    pub allow_special_chars: bool,
    pub trim_whitespace: bool,
}
```

### 3. 注释统计
```python
# 可以添加注释相关的统计功能
def get_comment_statistics(results: List[Dict[str, Any]]) -> Dict[str, Any]:
    """分析注释使用情况"""
    comments = [r.get('comment', '') for r in results if r.get('comment')]
    return {
        'total_comments': len(comments),
        'unique_comments': len(set(comments)),
        'most_common': max(set(comments), key=comments.count) if comments else None
    }
```

## 总结

这个示例展示了为 OneRoll 项目添加新功能的完整流程:

1. **语法定义** → 定义新语法规则
2. **类型定义** → 添加新的数据结构
3. **解析器** → 实现解析逻辑
4. **计算器** → 处理新功能
5. **Python 绑定** → 暴露给 Python
6. **类型注解** → 提供类型信息
7. **Python 接口** → 更新文档和示例
8. **用户界面** → 在所有界面中支持新功能

这种模块化的开发方式确保了:
- 代码的可维护性
- 功能的完整性
- 用户体验的一致性
- 向后兼容性

通过这个流程,你可以轻松地为 OneRoll 添加更多功能,如自定义修饰符、条件表达式、变量支持等。