Repository navigation
fix: support named captures #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
16a4b46
a3a7de3
aecf835
f9e9510
cd5c2c5
d8178c0
1e1bf0f
666f22b
7380bda
83d1655
617c3f9
83f042e
aecf844
30fb1b4
f63639c
aa60ea8
a139d4d
4ed10e4
171a940
af71c09
5b11f73
5def9c2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -763,6 +763,14 @@ def test_fixed_anchor_false | |||||||||
| assert_equal(false, StringScanner.new("a", fixed_anchor: nil).fixed_anchor?) | ||||||||||
| assert_equal(false, StringScanner.new("a", fixed_anchor: false).fixed_anchor?) | ||||||||||
| end | ||||||||||
|
|
||||||||||
| def test_named_captures | ||||||||||
|
ericgpks marked this conversation as resolved.
|
||||||||||
| s = "foobarbaz" | ||||||||||
| re = /(?<f>foo)(?<r>bar)(?<z>baz)/ | ||||||||||
| scan = StringScanner.new(s) | ||||||||||
| scan.match? re | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can use
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it to be
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general, no. But we can't use So we should use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wow! I thought that it returns a boolean value because its name ends with You're right. We should use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I fixed this test.
ericgpks marked this conversation as resolved.
Outdated
|
||||||||||
| assert_equal({"f"=>"foo", "r"=>"bar", "z"=>"baz"}, scan.named_captures) | ||||||||||
|
ericgpks marked this conversation as resolved.
Outdated
|
||||||||||
| end | ||||||||||
| end | ||||||||||
|
|
||||||||||
| class TestStringScannerFixedAnchor < TestStringScanner | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is a template for the next step:
I'll explain this later...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. I explain this in Japanese...
onig_foreach_name()の第2引数は各名前ごとに実行される関数を指定します。たとえば、/(?<a>.)(?<b>.)/ならaに対して1回、bに対して1回、計2回指定した関数が実行されます。第3引数はその関数が実行されるときにその関数にそのまま渡されます。↑のコードで言えば、第3引数に指定した&dataがnamed_captures_iter()の最後の引数void *argになります。では、なぜこんなことをしないといけないのでしょうか。それは、Cにはクロージャー機能がないからです。
Rubyにはクロージャー機能があるので次のようにブロックの中からブロックの外にある変数にアクセスできます。
しかし、Cにはクロージャー機能がないのでブロックの外の変数にアクセスできません。ここで言えば
named_captures_iter()の中から結果を入れるために用意したrb_hash_new()(VALUE capturesに入っているやつ)にはアクセスできません。そのため、関数内で使いたい値は明示的に渡さないといけません。そういうことができるようにするためにonig_foreach_name()の第3引数があります。さらにしかし!今回は渡したい値が2つあります。
struct strscanner *pとVALUE captures = rb_hash_new()です。あ、いや、strcut strscanner *pじゃだめだな。。。VALUE selfの方じゃないとだめだな。。。さーせん、やっぱりこんな感じで。
で、複数の値を渡したいときは1つの値にしないといけないんです。そのためのCの機能が
structです。Rubyで言えばインスタンス変数だけがあるクラスみたいなもんです。structを使うと複数の値を1つにまとめることができます。なので、↓のようにすると1つの値にまとめることができます。ということで、
structを使ってselfとcapturesをnamed_captures_iter()に渡しています。onig_foreach_name(RREGEXP_PTR(p->regex), named_captures_iter, &data);の&dataの&ってなに!?と思うと思いますが、ポインターの話になるので、今回はなにも考えずに&を使っておいてください。で、この渡した値をどうやって
named_captures_iter()で受け取るかと言うとです。
void *argなのでargはvoid *型なのですが、void *型は単なるポインター型です。一方、named_captures_data *もポインター型なのですが、named_captures_dataのポインター型です。void *型は任意のポインター型に変換できるのでで、
named_captures_dataのポインターとして扱うよという意味になります。argがonig_foreach_name(RREGEXP_PTR(p->regex), named_captures_iter, &data);の&dataに相当するので、onig_foreach_name()に渡した値を元に戻しているくらいに思ってもらえれば十分です。ここまでは、とりあえず、大丈夫ですか?
ここまでわかったら後は
named_captures_iter()の中身を実装していくだけになります。具体的にはこんな感じになるんですが、後でまた説明するので、とりあえず↑まででわからないところがないか確認してもらえますか!?