Permalink
Browse files

Implement new horrible 2.0 API for #each_* aliases

  • Loading branch information...
1 parent 997ba3b commit c5b21ca8924248d114746f65feee5fe8530ffbb6 Nikolai Weibull committed Apr 9, 2013
View
@@ -379,15 +379,15 @@ Init_u_string(VALUE mU)
rb_define_method(rb_cUString, "width", rb_u_string_width, 0); /* in ext/u/rb_u_string_width.c */
rb_define_method(rb_cUString, "each_byte", rb_u_string_each_byte, 0); /* in ext/u/rb_u_string_each_byte.c */
- rb_define_alias(rb_cUString, "bytes", "each_byte");
+ rb_define_method(rb_cUString, "bytes", rb_u_string_bytes, 0); /* in ext/u/rb_u_string_each_byte.c */
rb_define_method(rb_cUString, "each_char", rb_u_string_each_char, 0); /* in ext/u/rb_u_string_each_char.c */
- rb_define_alias(rb_cUString, "chars", "each_char");
+ rb_define_method(rb_cUString, "chars", rb_u_string_chars, 0); /* in ext/u/rb_u_string_each_char.c */
rb_define_method(rb_cUString, "each_codepoint", rb_u_string_each_codepoint, 0); /* in ext/u/rb_u_string_each_codepoint.c */
- rb_define_alias(rb_cUString, "codepoints", "each_codepoint");
+ rb_define_method(rb_cUString, "codepoints", rb_u_string_codepoints, 0); /* in ext/u/rb_u_string_each_codepoint.c */
rb_define_method(rb_cUString, "each_grapheme_cluster", rb_u_string_each_grapheme_cluster, 0); /* in ext/u/rb_u_string_each_grapheme_cluster.c */
rb_define_alias(rb_cUString, "grapheme_clusters", "each_grapheme_cluster");
rb_define_method(rb_cUString, "each_line", rb_u_string_each_line, -1); /* in ext/u/rb_u_string_each_line.c */
- rb_define_alias(rb_cUString, "lines", "each_line");
+ rb_define_method(rb_cUString, "lines", rb_u_string_lines, -1); /* in ext/u/rb_u_string_each_line.c */
rb_define_method(rb_cUString, "each_word", rb_u_string_each_word, 0); /* in ext/u/rb_u_string_each_word.c */
rb_define_alias(rb_cUString, "words", "each_word");
View
@@ -69,16 +69,19 @@ VALUE rb_u_string_assigned(VALUE self);
VALUE rb_u_string_aref_m(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_ascii_only(VALUE self);
VALUE rb_u_string_b(VALUE self);
+VALUE rb_u_string_bytes(VALUE self);
VALUE rb_u_string_bytesize(VALUE self);
VALUE rb_u_string_byteslice_m(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_center(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_casecmp(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_cased(VALUE self);
VALUE rb_u_string_case_ignorable(VALUE self);
+VALUE rb_u_string_chars(VALUE self);
VALUE rb_u_string_chomp(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_chop(VALUE self);
VALUE rb_u_string_chr(VALUE self);
VALUE rb_u_string_cntrl(VALUE self);
+VALUE rb_u_string_codepoints(VALUE self);
VALUE rb_u_string_collate(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_collation_key(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_combining_class(VALUE self);
@@ -115,6 +118,7 @@ VALUE rb_u_string_include(VALUE self, VALUE other);
VALUE rb_u_string_inspect(VALUE self);
VALUE rb_u_string_length(VALUE self);
VALUE rb_u_string_line_break(VALUE self);
+VALUE rb_u_string_lines(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_ljust(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_lower(int argc, VALUE *argv, VALUE self);
VALUE rb_u_string_lstrip(VALUE self);
@@ -1,4 +1,14 @@
#include "rb_includes.h"
+#include "yield.h"
+
+static void
+each(VALUE self, struct yield *yield)
+{
+ const struct rb_u_string *string = RVAL2USTRING(self);
+ const char *end = USTRING_END(string);
+ for (const char *p = USTRING_STR(string); p < end; p++)
+ yield_call(yield, INT2FIX(*p & 0xff));
+}
/* @overload each_byte{ |byte| … }
*
@@ -14,15 +24,16 @@ VALUE
rb_u_string_each_byte(VALUE self)
{
RETURN_ENUMERATOR(self, 0, NULL);
-
- const struct rb_u_string *string = RVAL2USTRING(self);
-
- const char *p = USTRING_STR(string);
- const char *end = USTRING_END(string);
- while (p < end) {
- rb_yield(INT2FIX(*p & 0xff));
- p++;
- }
-
+ struct yield y = YIELD_INIT;
+ each(self, &y);
return self;
}
+
+/* @return [Array<Fixnum>] The bytes of the receiver. */
+VALUE
+rb_u_string_bytes(VALUE self)
+{
+ struct yield_array y = YIELD_ARRAY_INIT;
+ each(self, &y.yield);
+ return y.array;
+}
@@ -1,4 +1,17 @@
#include "rb_includes.h"
+#include "yield.h"
+
+static void
+each(VALUE self, struct yield *yield)
+{
+ const struct rb_u_string *string = RVAL2USTRING(self);
+ const char *q;
+ const char *end = USTRING_END(string);
+ for (const char *p = USTRING_STR(string); p < end; p = q) {
+ q = rb_u_next_validated(p, end);
+ yield_call(yield, rb_u_string_new_c(self, p, q - p));
+ }
+}
/* @overload each_char{ |char| … }
*
@@ -14,16 +27,17 @@ VALUE
rb_u_string_each_char(VALUE self)
{
RETURN_ENUMERATOR(self, 0, NULL);
-
- const struct rb_u_string *string = RVAL2USTRING(self);
-
- const char *p = USTRING_STR(string);
- const char *end = USTRING_END(string);
- while (p < end) {
- const char *q = rb_u_next_validated(p, end);
- rb_yield(rb_u_string_new_c(self, p, q - p));
- p = q;
- }
-
+ struct yield y = YIELD_INIT;
+ each(self, &y);
return self;
}
+
+/* @return [Array<U::String>] The characters of the receiver, each inheriting
+ * any taint and untrust. */
+VALUE
+rb_u_string_chars(VALUE self)
+{
+ struct yield_array y = YIELD_ARRAY_INIT;
+ each(self, &y.yield);
+ return y.array;
+}
@@ -1,4 +1,14 @@
#include "rb_includes.h"
+#include "yield.h"
+
+static void
+each(VALUE self, struct yield *yield)
+{
+ const struct rb_u_string *string = RVAL2USTRING(self);
+ const char *end = USTRING_END(string);
+ for (const char *p = USTRING_STR(string); p < end; p = u_next(p))
+ yield_call(yield, UINT2NUM(_rb_u_dref(p, end)));
+}
/* @overload each_codepoint{ |codepoint| … }
*
@@ -13,16 +23,16 @@ VALUE
rb_u_string_each_codepoint(VALUE self)
{
RETURN_ENUMERATOR(self, 0, NULL);
-
- const struct rb_u_string *string = RVAL2USTRING(self);
-
- const char *p = USTRING_STR(string);
- const char *end = USTRING_END(string);
- while (p < end) {
- rb_yield(UINT2NUM(_rb_u_dref(p, end)));
-
- p = u_next(p);
- }
-
+ struct yield y = YIELD_INIT;
+ each(self, &y);
return self;
}
+
+/* @return [Array<U::String>] The code points of the receiver. */
+VALUE
+rb_u_string_codepoints(VALUE self)
+{
+ struct yield_array y = YIELD_ARRAY_INIT;
+ each(self, &y.yield);
+ return y.array;
+}
@@ -1,7 +1,8 @@
#include "rb_includes.h"
+#include "yield.h"
-static VALUE
-rb_u_string_each_line_default(VALUE self)
+static void
+rb_u_string_each_line_default(VALUE self, struct yield *yield)
{
const struct rb_u_string *string = RVAL2USTRING(self);
@@ -16,19 +17,18 @@ rb_u_string_each_line_default(VALUE self)
break;
p++;
- rb_yield(rb_u_string_new_c(self, base, p - base));
+ yield_call(yield, rb_u_string_new_c(self, base, p - base));
base = p;
}
if (base != end)
- rb_yield(rb_u_string_new_c(self, base, end - base));
-
- return self;
+ yield_call(yield, rb_u_string_new_c(self, base, end - base));
}
-static VALUE
-rb_u_string_each_line_separator(VALUE self, const struct rb_u_string *separator)
+static void
+rb_u_string_each_line_separator(VALUE self, const struct rb_u_string *separator,
+ struct yield *yield)
{
const struct rb_u_string *string = RVAL2USTRING(self);
@@ -66,16 +66,33 @@ rb_u_string_each_line_separator(VALUE self, const struct rb_u_string *separator)
(end - p >= separator_length &&
memcmp(USTRING_STR(separator), p, separator_length) == 0))) {
p += separator_length;
- rb_yield(rb_u_string_new_c(self, base, p - base));
+ yield_call(yield, rb_u_string_new_c(self, base, p - base));
base = p;
} else
p = u_next(p);
}
if (base != end)
- rb_yield(rb_u_string_new_c(self, base, end - base));
+ yield_call(yield, rb_u_string_new_c(self, base, end - base));
+}
- return self;
+static void
+each(int argc, VALUE *argv, VALUE self, struct yield *yield)
+{
+ VALUE rs;
+ if (argc == 0)
+ rs = rb_rs;
+ else
+ rb_scan_args(argc, argv, "01", &rs);
+ if (NIL_P(rs)) {
+ yield_call(yield, self);
+ return;
+ }
+ const struct rb_u_string *separator = RVAL2USTRING_ANY(rs);
+ if (rs == rb_default_rs)
+ rb_u_string_each_line_default(self, yield);
+ else
+ rb_u_string_each_line_separator(self, separator, yield);
}
/* @overload each_line(separator = $/){ |lp| … }
@@ -102,20 +119,24 @@ VALUE
rb_u_string_each_line(int argc, VALUE *argv, VALUE self)
{
RETURN_ENUMERATOR(self, argc, argv);
+ struct yield y = YIELD_INIT;
+ each(argc, argv, self, &y);
+ return self;
+}
- VALUE rs;
- if (argc == 0)
- rs = rb_rs;
- else
- rb_scan_args(argc, argv, "01", &rs);
- if (NIL_P(rs)) {
- rb_yield(self);
- return self;
- }
-
- const struct rb_u_string *separator = RVAL2USTRING_ANY(rs);
- if (rs == rb_default_rs)
- return rb_u_string_each_line_default(self);
-
- return rb_u_string_each_line_separator(self, separator);
+/* @overload lines(separator = $/)
+ *
+ * Returns the lines of the receiver, inheriting any taint and untrust.
+ *
+ * If SEPARATOR is nil, yields self. If SEPARATOR is {#empty?}, separates
+ * each line (paragraph) by two or more U+000A LINE FEED characters.
+ *
+ * @param [U::String, #to_str] separator
+ * @return [Array<U::String>] */
+VALUE
+rb_u_string_lines(int argc, VALUE *argv, VALUE self)
+{
+ struct yield_array y = YIELD_ARRAY_INIT;
+ each(argc, argv, self, &y.yield);
+ return y.array;
}
View
@@ -0,0 +1,27 @@
+struct yield {
+ void (*call)(struct yield *, VALUE value);
+};
+
+#define YIELD_INIT { yield };
+
+static void
+yield(UNUSED(struct yield *yield), VALUE value)
+{
+ rb_yield(value);
+}
+
+struct yield_array {
+ struct yield yield;
+ VALUE array;
+};
+
+#define YIELD_ARRAY_INIT { { yield_array }, rb_ary_new() }
+
+static void
+yield_array(struct yield *yield, VALUE value)
+{
+ rb_ary_push(((struct yield_array *)yield)->array, value);
+}
+
+#define yield_call(yield, value) \
+ (((struct yield *)(yield))->call((struct yield *)(yield), (value)))
View
@@ -281,7 +281,8 @@ def sources
u_words.c
utf8.h
word-break.c
- word-break.h'
+ word-break.h
+ yield.h'
end
def additional_files
View
@@ -376,22 +376,39 @@
expect 2 do ''.u.width end
expect 3 do 'a豈'.u.width end
- expect [0x61, 0x62, 0x63, 0x00, 0x64, 0xc3, 0xab, 0x66] do "abc\0dëf".u.bytes.to_a end
+ expect [0x61, 0x62, 0x63, 0x00, 0x64, 0xc3, 0xab, 0x66] do "abc\0dëf".u.each_byte.to_a end
- expect ['h'.u, 'ë'.u, 'l'.u, 'l'.u, 'ö'.u] do 'hëllö'.u.chars.to_a end
+ expect [0x61, 0x62, 0x63, 0x00, 0x64, 0xc3, 0xab, 0x66] do "abc\0dëf".u.bytes end
+
+ expect ['h'.u, 'ë'.u, 'l'.u, 'l'.u, 'ö'.u] do 'hëllö'.u.each_char.to_a end
+ expect result.tainted? do 'a'.u.taint.each_char.first end
+ expect result.untrusted? do 'a'.u.untrust.each_char.first end
+
+ expect ['h'.u, 'ë'.u, 'l'.u, 'l'.u, 'ö'.u] do 'hëllö'.u.chars end
expect result.tainted? do 'a'.u.taint.chars.first end
expect result.untrusted? do 'a'.u.untrust.chars.first end
- expect [0x0068, 0x00eb, 0x006c, 0x006c, 0x00f6] do 'hëllö'.u.codepoints.to_a end
+ expect [0x0068, 0x00eb, 0x006c, 0x006c, 0x00f6] do 'hëllö'.u.each_codepoint.to_a end
+
+ expect [0x0068, 0x00eb, 0x006c, 0x006c, 0x00f6] do 'hëllö'.u.codepoints end
expect ['h'.u, 'ë'.u.normalize(:nfd), 'l'.u, 'l'.u, 'ö'.u.normalize(:nfd)] do 'hëllö'.u.normalize(:nfd).grapheme_clusters.to_a end
- expect ["hello\n".u, 'world'.u] do with_global(:$/, "\n"){ "hello\nworld".u.lines.to_a } end
- expect ["hello\n\n\n".u, 'world'.u] do "hello\n\n\nworld".u.lines('').to_a end
- expect ['hello!'.u, 'world'.u] do with_global(:$/, '!'){ 'hello!world'.u.lines.to_a } end
- expect ["hello\nworld".u] do with_global(:$/, nil){ "hello\nworld".u.lines.to_a } end
- expect ['hëll hëllö'.u, ' world'.u] do 'hëll hëllö world'.u.lines('llö').to_a end
- expect ["hello\0".u, 'world'.u] do "hello\0world".u.lines("\0").to_a end
+ expect ["hello\n".u, 'world'.u] do with_global(:$/, "\n"){ "hello\nworld".u.each_line.to_a } end
+ expect ["hello\n\n\n".u, 'world'.u] do "hello\n\n\nworld".u.each_line('').to_a end
+ expect ['hello!'.u, 'world'.u] do with_global(:$/, '!'){ 'hello!world'.u.each_line.to_a } end
+ expect ["hello\nworld".u] do with_global(:$/, nil){ "hello\nworld".u.each_line.to_a } end
+ expect ['hëll hëllö'.u, ' world'.u] do 'hëll hëllö world'.u.each_line('llö').to_a end
+ expect ["hello\0".u, 'world'.u] do "hello\0world".u.each_line("\0").to_a end
+ expect result.tainted? do 'a'.u.taint.each_line.first end
+ expect result.untrusted? do 'a'.u.untrust.each_line.first end
+
+ expect ["hello\n".u, 'world'.u] do with_global(:$/, "\n"){ "hello\nworld".u.lines } end
+ expect ["hello\n\n\n".u, 'world'.u] do "hello\n\n\nworld".u.lines('') end
+ expect ['hello!'.u, 'world'.u] do with_global(:$/, '!'){ 'hello!world'.u.lines } end
+ expect ["hello\nworld".u] do with_global(:$/, nil){ "hello\nworld".u.lines } end
+ expect ['hëll hëllö'.u, ' world'.u] do 'hëll hëllö world'.u.lines('llö') end
+ expect ["hello\0".u, 'world'.u] do "hello\0world".u.lines("\0") end
expect result.tainted? do 'a'.u.taint.lines.first end
expect result.untrusted? do 'a'.u.untrust.lines.first end

0 comments on commit c5b21ca

Please sign in to comment.