Index: re.c
===================================================================
--- re.c (revision 27799)
+++ re.c (working copy)
@@ -725,6 +725,28 @@
return hash;
}
+/*
+ * call-seq:
+ * rxp.ncaptures => fixnum
+ *
+ * Returns number of captures of rxp.
+ *
+ * /foo/.ncaptures #=> 0
+ * /bar(baz)/.ncaptures #=> 1
+ * /bar(b)a(z)/.ncaptures #=> 2
+ * /bar(b(az))/.ncaptures #=> 2
+ * /bar(?:baz)/.ncaptures #=> 0
+ * /(?foo)bar(baz)/.ncaptures #=> 1
+ */
+
+static VALUE
+rb_reg_ncaptures(VALUE re)
+{
+ regex_t *reg = RREGEXP(re)->ptr;
+ int ncapts = onig_number_of_captures(reg);
+ return INT2NUM(ncapts);
+}
+
static int
onig_new_with_source(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
OnigOptionType option, OnigEncoding enc, const OnigSyntaxType* syntax,
@@ -3519,6 +3541,7 @@
rb_define_method(rb_cRegexp, "fixed_encoding?", rb_reg_fixed_encoding_p, 0);
rb_define_method(rb_cRegexp, "names", rb_reg_names, 0);
rb_define_method(rb_cRegexp, "named_captures", rb_reg_named_captures, 0);
+ rb_define_method(rb_cRegexp, "ncaptures", rb_reg_ncaptures, 0);
rb_define_const(rb_cRegexp, "IGNORECASE", INT2FIX(ONIG_OPTION_IGNORECASE));
rb_define_const(rb_cRegexp, "EXTENDED", INT2FIX(ONIG_OPTION_EXTEND));
Index: test/ruby/test_regexp.rb
===================================================================
--- test/ruby/test_regexp.rb (revision 27799)
+++ test/ruby/test_regexp.rb (working copy)
@@ -816,4 +816,13 @@
bug2547 = '[ruby-core:27374]'
assert_raise(SyntaxError, bug2547) {eval('/#{"\\\\"}y/')}
end
+
+ def test_ncaptures
+ assert_equal(0, /foo/.ncaptures)
+ assert_equal(1, /bar(baz)/.ncaptures)
+ assert_equal(2, /bar(b)a(z)/.ncaptures)
+ assert_equal(2, /bar(b(az))/.ncaptures)
+ assert_equal(0, /bar(?:baz)/.ncaptures)
+ assert_equal(1, /(?foo)bar(baz)/.ncaptures)
+ end
end