
# AntPathMatcher

`AntPathMatcher` は `config/dev/app.properties` のようなパスを `config/**/*.properties` のような Ant 形式のパターンと照合し、そこから値を取り出します。

## 使う理由

リソースパターン(`resources:mail/*.txt`)と `@PropertySource` のロケーションはすでにこれを使っているため、ほとんどのアプリケーションは自分で作りません。独自のコードでパスやドット区切りの名前を照合するときに直接使います。たとえば、アップロードされたファイルのうちスタイルシートはどれか、どのキーがあるグループに属するか、どのルートパターンが最も合うか、といった判定です。

構文:

- `?` は 1 文字に一致します。
- `*` は 1 つのセグメント内の 0 文字以上に一致します。
- `**` は 0 個以上のセグメント全体に一致します。
- `{name}` はセグメントの一部を取り出します。`{name:regex}` は正規表現に一致するときだけ取り出します。

## 例

```dart
import 'package:spring_core_dart/spring_core_dart.dart';

const log = SpringLog('neon.static');

final matcher = AntPathMatcher();

// 要求されたファイルがスタイルシートかどうか。
bool isStylesheet(String path) => matcher.match('/static/**/*.css', path);

void main() {
  log.info(isStylesheet('/static/css/app.css')); // true

  // パスから変数を取り出す。
  final vars = matcher.extractUriTemplateVariables(
    '/users/{id:[0-9]+}',
    '/users/42',
  );
  log.info(vars['id']); // 42

  // 一致する複数のパターンから最も具体的なものを選ぶ。
  final patterns = ['/**', '/hotels/*', '/hotels/{id}']
    ..sort(matcher.getPatternComparator('/hotels/1'));
  log.info(patterns.first); // /hotels/{id}

  // 同じマッチャーはドット区切りの名前にも使える。
  final dots = AntPathMatcher(pathSeparator: '.');
  log.info(dots.match('app.*.enabled', 'app.cache.enabled')); // true
}
```

## パラメーター

コンストラクターのパラメーター:

| 名前 | 型 | デフォルト | 意味 |
|---|---|---|---|
| `pathSeparator` | `String` | `'/'` | セグメント間の区切り文字列。 |
| `caseSensitive` | `bool` | `true` | セグメントを大文字小文字を区別して比較するか。 |
| `trimTokens` | `bool` | `false` | セグメント前後の空白を無視するか。 |

`PathMatcher` のメソッド:

| 名前 | 戻り値 | 意味 |
|---|---|---|
| `isPattern(path)` | `bool` | テキストに `*`、`?`、`{name}` 変数が含まれるか。 |
| `match(pattern, path)` | `bool` | パス全体が一致するか。 |
| `matchStart(pattern, path)` | `bool` | パスがパターンの先頭部分に一致し、より長いパスなら一致しうるか。 |
| `extractPathWithinPattern(pattern, path)` | `String` | ワイルドカードが一致した部分。`/docs/*` と `/docs/a/b.html` なら `a/b.html`。 |
| `extractUriTemplateVariables(pattern, path)` | `Map<String, String>` | `{name}` の値。パスが一致しなければ `StateError`。 |
| `getPatternComparator(path)` | `Comparator<String>` | パスに対して具体的なものから順にパターンを並べる。 |
| `combine(pattern1, pattern2)` | `String` | 2 つのパターンを結合する。`/hotels` と `{hotel}` で `/hotels/{hotel}`。 |

## Spring (Java) との対応

```java
var matcher = new AntPathMatcher();
matcher.match("/static/**/*.css", "/static/css/app.css");
matcher.extractUriTemplateVariables("/users/{id:[0-9]+}", "/users/42");

var dots = new AntPathMatcher(".");
dots.match("app.*.enabled", "app.cache.enabled");
```

重要な違い:

- オプションはセッター(`setCaseSensitive`、`setTrimTokens`)ではなく、名前付きのコンストラクター引数です。
- `{name:regex}` は Dart の `RegExp` 構文を使います。リソースのロケーションでは `\` が `/` に正規化されるため(Spring と同じ)、そこでは `\d` ではなく `[0-9]` のような文字クラスを書いてください。

## 関連項目

- [Resource](resource.md)
- [@PropertySource](../config/property-source.md)
- [Resources](index.md)
