> +static VALUE
> +rb_str_squish_bang(VALUE str)
> +{
> +    static const char before_regex_source[] = "\\A[[:space:]]+";
> +    static const char after_regex_source[] = "[[:space:]]+\\z";
> +    static const char between_regex_source[] = "[[:space:]]+";
> +    VALUE before_argv[] = {
> +        rb_reg_new(before_regex_source, sizeof before_regex_source - 1, 0),
> +        rb_str_new_cstr("")
> +    };
> +    VALUE after_argv[] = {
> +        rb_reg_new(after_regex_source, sizeof after_regex_source - 1, 0),
> +        rb_str_new_cstr("")
> +    };
> +    VALUE between_argv[] = {
> +        rb_reg_new(between_regex_source, sizeof between_regex_source - 1, 0),
> +        rb_str_new_cstr(" ")
> +    };

You could memoize these Regexps as static variables and use
rb_gc_register_mark_object to keep them around so GC won't eat them.
Allocating 3 regexps and 3 strings every call seems like a waste.
You may also use the same

Writing the equivalent Ruby code would only allocate the Regexps once.

You can also auto-dedupe "" and  " " strings with the magic
"frozen_string_literal: true" comment in Ruby or
rb_fstring_cstr function in C.

> By the way, this is my first patch and my first time writing something
> in C, so there might be something that does not look right to you.
> I'll happy to revise this patch (and learn about C in the process!)
> from your feedback.

No worries; but personally (not speaking for the rest of ruby-core);
I would prefer we use prelude.rb more and implement more things in Ruby
rather than C.



Also (definitely not speaking for anybody else in ruby-core);
but the Redmine <-> ruby-core ML integration is the only reason
I've been willing to participate in Ruby development.  I'm not touching
proprietary websites or running any GUI/JavaScript at all to work on
Ruby or any other Free Software.