ext/attribute_builder/attribute_builder.c in faml-0.3.1 vs ext/attribute_builder/attribute_builder.c in faml-0.3.2

- old
+ new

@@ -1,17 +1,19 @@ #include <ruby.h> +#include <ruby/encoding.h> #include <ruby/version.h> +#include "houdini.h" #if (RUBY_API_VERSION_MAJOR > 2) || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 1) /* define nothing */ #else # define RARRAY_AREF(a, i) RARRAY_PTR(a)[i] # define rb_ary_new_capa rb_ary_new2 #endif VALUE rb_mAttributeBuilder; -static ID id_keys, id_sort_bang, id_uniq_bang, id_merge_bang, id_temple, id_utils, id_escape_html, id_gsub, id_to_s; +static ID id_keys, id_sort_bang, id_uniq_bang, id_merge_bang, id_to_s; static ID id_id, id_class, id_underscore, id_hyphen, id_space, id_equal; static void concat_array_attribute(VALUE attributes, VALUE hash, VALUE key) { @@ -47,17 +49,43 @@ struct normalize_data_i2_arg { VALUE key, normalized; }; +static VALUE +substitute_underscores(VALUE str) +{ + int frozen; + long i, len; + + /* gsub('_', '-') */ + Check_Type(str, T_STRING); + len = RSTRING_LEN(str); + frozen = OBJ_FROZEN(str); + for (i = 0; i < len; i++) { + if (RSTRING_PTR(str)[i] == '_') { + if (frozen) { + str = rb_str_dup(str); + frozen = 0; + } + rb_str_update(str, i, 1, rb_const_get(rb_mAttributeBuilder, id_hyphen)); + } + } + + return str; +} + static int normalize_data_i2(VALUE key, VALUE value, VALUE ptr) { struct normalize_data_i2_arg *arg = (struct normalize_data_i2_arg *)ptr; VALUE k = rb_funcall(arg->key, id_to_s, 0); - k = rb_funcall(k, id_gsub, 2, rb_const_get(rb_mAttributeBuilder, id_underscore), rb_const_get(rb_mAttributeBuilder, id_hyphen)); + k = substitute_underscores(k); + if (OBJ_FROZEN(k)) { + k = rb_str_dup(k); + } rb_str_cat(k, "-", 1); rb_str_append(k, key); rb_hash_aset(arg->normalized, k, value); return ST_CONTINUE; } @@ -72,11 +100,11 @@ arg.key = key; arg.normalized = normalized; rb_hash_foreach(normalize_data(value), normalize_data_i2, (VALUE)(&arg)); } else { key = rb_funcall(key, id_to_s, 0); - key = rb_funcall(key, id_gsub, 2, rb_const_get(rb_mAttributeBuilder, id_underscore), rb_const_get(rb_mAttributeBuilder, id_hyphen)); + key = substitute_underscores(key); rb_hash_aset(normalized, key, value); } return ST_CONTINUE; } @@ -89,38 +117,42 @@ normalized = rb_hash_new(); rb_hash_foreach(data, normalize_data_i, normalized); return normalized; } +static int +put_data_attribute(VALUE key, VALUE val, VALUE hash) +{ + VALUE k = rb_str_buf_new(5 + RSTRING_LEN(key)); + rb_str_buf_cat(k, "data-", 5); + rb_str_buf_append(k, key); + rb_hash_aset(hash, k, val); + return ST_CONTINUE; +} + static void normalize(VALUE hash) { VALUE keys = rb_funcall(hash, id_keys, 0); const long len = RARRAY_LEN(keys); long i; for (i = 0; i < len; i++) { VALUE key = RARRAY_AREF(keys, i); - const char *key_cstr = StringValueCStr(key); VALUE value = rb_hash_lookup(hash, key); - if (RB_TYPE_P(value, T_HASH) && strcmp(key_cstr, "data") == 0) { - VALUE data, data_keys; - long data_len, j; + VALUE key_str = key; + if (!RB_TYPE_P(key, T_STRING)) { + key_str = rb_funcall(key, id_to_s, 0); + } + if (RB_TYPE_P(value, T_HASH) && RSTRING_LEN(key_str) == 4 && memcmp(RSTRING_PTR(key_str), "data", 4) == 0) { + VALUE data; + rb_hash_delete(hash, key); data = normalize_data(value); - data_keys = rb_funcall(data, id_keys, 0); - rb_funcall(data_keys, id_sort_bang, 0); - data_len = RARRAY_LEN(data_keys); - for (j = 0; j < data_len; j++) { - VALUE data_key = RARRAY_AREF(data_keys, j); - VALUE k = rb_str_buf_new(5 + RSTRING_LEN(data_key)); - rb_str_buf_cat(k, "data-", 5); - rb_str_buf_append(k, data_key); - rb_hash_aset(hash, k, rb_hash_lookup(data, data_key)); - } + rb_hash_foreach(data, put_data_attribute, hash); } else if (!(RB_TYPE_P(value, T_TRUE) || RB_TYPE_P(value, T_FALSE) || NIL_P(value))) { - rb_hash_aset(hash, key, rb_funcall(value, id_to_s, 0)); + rb_hash_aset(hash, key_str, rb_funcall(value, id_to_s, 0)); } } } static void @@ -141,15 +173,18 @@ } static void put_attribute(VALUE buf, VALUE attr_quote, VALUE key, VALUE value) { - VALUE utils_class; + gh_buf ob = GH_BUF_INIT; value = rb_funcall(value, id_to_s, 0); - utils_class = rb_const_get(rb_const_get(rb_cObject, id_temple), id_utils); - value = rb_funcall(utils_class, id_escape_html, 1, value); + Check_Type(value, T_STRING); + if (houdini_escape_html(&ob, (const uint8_t *)RSTRING_PTR(value), RSTRING_LEN(value))) { + value = rb_enc_str_new(ob.ptr, ob.size, rb_utf8_encoding()); + gh_buf_free(&ob); + } rb_ary_push(buf, rb_const_get(rb_mAttributeBuilder, id_space)); rb_ary_push(buf, key); rb_ary_push(buf, rb_const_get(rb_mAttributeBuilder, id_equal)); rb_ary_push(buf, attr_quote); @@ -158,12 +193,15 @@ } static void build_attribute(VALUE buf, VALUE attr_quote, int is_html, VALUE key, VALUE value) { - const char *key_cstr = StringValueCStr(key); - if (strcmp(key_cstr, "class") == 0) { + if (!RB_TYPE_P(key, T_STRING)) { + key = rb_funcall(key, id_to_s, 0); + } + Check_Type(key, T_STRING); + if (RSTRING_LEN(key) == 5 && memcmp(RSTRING_PTR(key), "class", 5) == 0) { long len; Check_Type(value, T_ARRAY); len = RARRAY_LEN(value); if (len != 0) { @@ -175,11 +213,11 @@ } rb_funcall(ary, id_sort_bang, 0); rb_funcall(ary, id_uniq_bang, 0); put_attribute(buf, attr_quote, key, rb_ary_join(ary, rb_const_get(rb_mAttributeBuilder, id_space))); } - } else if (strcmp(key_cstr, "id") == 0) { + } else if (RSTRING_LEN(key) == 2 && memcmp(RSTRING_PTR(key), "id", 2) == 0) { long len = RARRAY_LEN(value); Check_Type(value, T_ARRAY); len = RARRAY_LEN(value); if (len != 0) { @@ -248,27 +286,21 @@ id_keys = rb_intern("keys"); id_sort_bang = rb_intern("sort!"); id_uniq_bang = rb_intern("uniq!"); id_merge_bang = rb_intern("merge!"); - id_temple = rb_intern("Temple"); - id_utils = rb_intern("Utils"); - id_escape_html = rb_intern("escape_html"); - id_gsub = rb_intern("gsub"); id_to_s = rb_intern("to_s"); id_id = rb_intern("ID"); id_class = rb_intern("CLASS"); id_underscore = rb_intern("UNDERSCORE"); id_hyphen = rb_intern("HYPHEN"); id_space = rb_intern("SPACE"); - id_equal = rb_intern("="); + id_equal = rb_intern("EQUAL"); rb_const_set(rb_mAttributeBuilder, id_id, rb_obj_freeze(rb_str_new_cstr("id"))); rb_const_set(rb_mAttributeBuilder, id_class, rb_obj_freeze(rb_str_new_cstr("class"))); rb_const_set(rb_mAttributeBuilder, id_underscore, rb_obj_freeze(rb_str_new_cstr("_"))); rb_const_set(rb_mAttributeBuilder, id_hyphen, rb_obj_freeze(rb_str_new_cstr("-"))); rb_const_set(rb_mAttributeBuilder, id_space, rb_obj_freeze(rb_str_new_cstr(" "))); rb_const_set(rb_mAttributeBuilder, id_equal, rb_obj_freeze(rb_str_new_cstr("="))); - - rb_require("temple"); }