isomorfeus-preact 23.1.0.rc1 → 23.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,10 @@
1
+ #include "vnode.h"
1
2
  #include <ruby.h>
2
- #define FIO_STR_NAME render_result
3
- #include "fio-stl.h"
4
- #include "isomorfeus_preact_ext.h"
3
+ #include <ruby/encoding.h>
4
+ #include <ruby/re.h>
5
+
6
+ rb_encoding *utf8_encoding;
5
7
 
6
- static ID id_ancestors;
7
8
  static ID id_checked;
8
9
  static ID id_children;
9
10
  static ID id_class;
@@ -20,20 +21,14 @@ static ID id_downcase;
20
21
  static ID id_encode_entities;
21
22
  static ID id_eqeq;
22
23
  static ID id_for;
23
- static ID id_freeze;
24
24
  static ID id_get_child_context;
25
25
  static ID id_get_derived_state_from_props;
26
26
  static ID id_gsub;
27
27
  static ID id_html_for;
28
- static ID id_include;
29
- static ID id_is_a;
30
- static ID id_is_renderable;
28
+
31
29
  static ID id_key;
32
- static ID id_keyq;
33
30
  static ID id_keys;
34
- static ID id_match;
35
31
  static ID id_merge;
36
- static ID id_new;
37
32
  static ID id_props;
38
33
  static ID id_ref;
39
34
  static ID id_render;
@@ -41,10 +36,9 @@ static ID id_render_buffer;
41
36
  static ID id_selected;
42
37
  static ID id_self;
43
38
  static ID id_source;
44
- static ID id_start_withq;
45
- static ID id_state;
46
39
  static ID id_style;
47
40
  static ID id_style_obj_to_css;
41
+ static ID id_to_s;
48
42
  static ID id_validate_props;
49
43
  static ID id_value;
50
44
 
@@ -54,6 +48,8 @@ static ID iv_next_state;
54
48
  static ID iv_props;
55
49
  static ID iv_state;
56
50
 
51
+ static char *str_aria = "aria-";
52
+ static char *str_data = "data-";
57
53
  static char *str_foreign_object = "foreignObject";
58
54
  static char *str_option = "option";
59
55
  static char *str_select = "select";
@@ -61,13 +57,13 @@ static char *str_selected = "selected";
61
57
  static char *str_svg = "svg";
62
58
  static char *str_textarea = "textarea";
63
59
 
64
- static char *str_rve = "^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$";
60
+ static char *str_rve =
61
+ "^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$";
65
62
  static char *str_run = "[\\s\\n\\\\\\/='\"\\0<>]";
66
63
  static char *str_rxl = "^xlink:?.";
67
64
  static char *str_rx2 = "^xlink:?";
68
65
  // static char *str_ree = "[\"&<]";
69
66
 
70
- static VALUE s_aria;
71
67
  static VALUE s_false;
72
68
  static VALUE s_true;
73
69
  static VALUE s_xlink;
@@ -85,8 +81,6 @@ static VALUE sym_value;
85
81
  static VALUE mIsomorfeus;
86
82
  static VALUE mPreact;
87
83
  static VALUE cFragment;
88
- static VALUE cProc;
89
- static VALUE cRegexp;
90
84
 
91
85
  extern VALUE cVNode;
92
86
 
@@ -95,359 +89,400 @@ static VALUE rUnsafe;
95
89
  static VALUE rVoid;
96
90
  static VALUE rXlink2;
97
91
 
98
- int set_default_prop_value(VALUE prop, VALUE value, VALUE props) {
99
- if ((rb_funcall(value, id_keyq, 1, sym_default) == Qtrue) && (rb_funcall(props, id_keyq, 1, prop) == Qfalse)) {
100
- rb_hash_aset(props, props, rb_hash_lookup(value, sym_default));
101
- }
92
+ static int set_default_prop_value(VALUE prop, VALUE value, VALUE props) {
93
+ VALUE def_val = rb_hash_lookup(value, sym_default);
94
+ if ((def_val != Qnil) && (rb_hash_lookup(props, prop) == Qnil))
95
+ rb_hash_aset(props, prop, def_val);
102
96
  return 0;
103
97
  }
104
98
 
105
- ID normalize_prop_name(ID name_id, VALUE is_svg_mode) {
106
- if (name_id == id_class_name || name_id == id_class_name2) { return id_class; }
107
- if (name_id == id_html_for) { return id_for; }
108
- if (name_id == id_default_value) { return id_value; }
109
- if (name_id == id_default_checked) { return id_checked; }
110
- if (name_id == id_default_selected) { return id_selected; }
99
+ static ID normalize_prop_name(ID name_id, VALUE is_svg_mode) {
100
+ if (name_id == id_class_name || name_id == id_class_name2)
101
+ return id_class;
102
+ if (name_id == id_html_for)
103
+ return id_for;
104
+ if (name_id == id_default_value)
105
+ return id_value;
106
+ if (name_id == id_default_checked)
107
+ return id_checked;
108
+ if (name_id == id_default_selected)
109
+ return id_selected;
111
110
  if (is_svg_mode == Qtrue) {
112
111
  VALUE name_s = rb_id2str(name_id);
113
- if (rb_funcall(rXlink, id_match, 1, name_s) == Qtrue) {
112
+ if (rb_reg_match(rXlink, name_s) == Qtrue) {
114
113
  name_s = rb_funcall(name_s, id_downcase, 0);
115
114
  name_s = rb_funcall(name_s, id_gsub, 2, rXlink2, s_xlink);
116
- return SYM2ID(rb_to_symbol(name_s));
115
+ return rb_intern_str(name_s);
117
116
  }
118
117
  }
119
118
  return name_id;
120
119
  }
121
120
 
122
- VALUE normalize_prop_value(ID name_id, VALUE name_s, VALUE value, VALUE self) {
123
- if (name_id == id_style && value != Qnil && TYPE(value) == T_HASH) {
124
- return rb_funcall(self, id_style_obj_to_css, 1, value);
125
- }
126
- // name[0] === 'a' && name[1] === 'r'
127
- if (value == Qtrue && rb_funcall(name_s, id_start_withq, 1, s_aria) == Qtrue) {
128
- // always use string values instead of booleans for aria attributes
129
- // also see https://github.com/preactjs/preact/pull/2347/files
130
- return s_true;
131
- }
132
- if (value == Qfalse && rb_funcall(name_s, id_start_withq, 1, s_aria) == Qtrue) {
133
- // always use string values instead of booleans for aria attributes
134
- // also see https://github.com/preactjs/preact/pull/2347/files
135
- return s_false;
136
- }
137
- return value;
121
+ static VALUE normalize_prop_value(ID name_id, VALUE name_s, VALUE value,
122
+ VALUE self) {
123
+ if (name_id == id_style && TYPE(value) == T_HASH)
124
+ return rb_funcall(self, id_style_obj_to_css, 1, value);
125
+ if (value == Qtrue && RSTRING_LEN(name_s) > 4) {
126
+ if ((0 == strncmp(RSTRING_PTR(name_s), str_aria, 5)) ||
127
+ (0 == strncmp(RSTRING_PTR(name_s), str_data, 5))) {
128
+ // always use string values instead of booleans for aria attributes
129
+ // also see https://github.com/preactjs/preact/pull/2347/files
130
+ return s_true;
131
+ }
132
+ }
133
+ if (value == Qfalse && RSTRING_LEN(name_s) > 4) {
134
+ if ((0 == strncmp(RSTRING_PTR(name_s), str_aria, 5)) ||
135
+ (0 == strncmp(RSTRING_PTR(name_s), str_data, 5))) {
136
+ // always use string values instead of booleans for aria attributes
137
+ // also see https://github.com/preactjs/preact/pull/2347/files
138
+ return s_false;
139
+ }
140
+ }
141
+ return value;
138
142
  }
139
143
 
140
- VALUE get_context(VALUE node_type, VALUE context) {
144
+ static VALUE get_context(VALUE node_type, VALUE context) {
141
145
  VALUE ctx_type = rb_funcall(node_type, id_context_type, 0);
142
- VALUE provider = Qnil;
143
- VALUE cctx = context;
144
146
  if (ctx_type != Qnil) {
145
- provider = rb_hash_lookup(context, rb_funcall(ctx_type, id_context_id, 0));
146
- if (provider != Qnil) {
147
- cctx = rb_hash_lookup(rb_funcall(provider, id_props, 0), sym_value); }
148
- else {
149
- cctx = rb_funcall(ctx_type, id_value, 0); }
147
+ VALUE provider =
148
+ rb_hash_lookup(context, rb_funcall(ctx_type, id_context_id, 0));
149
+ if (provider != Qnil)
150
+ return rb_hash_lookup(rb_funcall(provider, id_props, 0), sym_value);
151
+ else
152
+ return rb_funcall(ctx_type, id_value, 0);
150
153
  }
151
- return cctx;
154
+ return context;
152
155
  }
153
156
 
154
- VALUE render_class_component(VALUE vnode, VALUE context) {
155
- VNode *v = (VNode *)DATA_PTR(vnode);
156
-
157
- VALUE node_type = v->type;
157
+ static VALUE render_class_component(VALUE vnode, VALUE context, VNode *v) {
158
+ VALUE node_type = v->type;
158
159
  VALUE props = v->props;
159
- VALUE state = rb_hash_new();
160
160
 
161
161
  // get context
162
- VALUE cctx = get_context(node_type, context);
162
+ VALUE cctx = get_context(node_type, context);
163
163
 
164
164
  // validate props
165
165
  VALUE declared_props = rb_ivar_get(node_type, iv_declared_props);
166
166
  if (declared_props != Qnil) {
167
167
  rb_hash_foreach(declared_props, set_default_prop_value, props);
168
- if (rb_funcall(mIsomorfeus, id_development, 0) == Qtrue) { rb_funcall(node_type, id_validate_props, 1, props); }
168
+ if (rb_funcall(mIsomorfeus, id_development, 0) == Qtrue)
169
+ rb_funcall(node_type, id_validate_props, 1, props);
169
170
  }
170
171
 
171
172
  // freeze props
172
- rb_funcall(props, id_freeze, 0);
173
+ rb_obj_freeze(props);
173
174
 
174
175
  // instantiate component
175
- VALUE c = rb_funcall(node_type, id_new, 2, props, cctx);
176
- v->component = c;
176
+ const VALUE cargs[2] = {props, cctx};
177
+ VALUE c = rb_class_new_instance(2, (const VALUE *)&cargs, node_type);
178
+ v->component = c;
177
179
 
178
180
  // set state, props, context
179
181
  rb_ivar_set(c, iv_props, props);
180
- if (rb_funcall(c, id_state, 0) == Qnil) { rb_ivar_set(c, iv_state, state); }
181
- if (rb_ivar_get(c, iv_next_state) == Qnil) { rb_ivar_set(c, iv_next_state, rb_funcall(c, id_state, 0)); }
182
+ if (rb_ivar_get(c, iv_state) == Qnil)
183
+ rb_ivar_set(c, iv_state, rb_hash_new());
184
+ if (rb_ivar_get(c, iv_next_state) == Qnil)
185
+ rb_ivar_set(c, iv_next_state, rb_ivar_get(c, iv_state));
182
186
  rb_ivar_set(c, iv_context, cctx);
183
187
 
184
188
  // get_derived_state_from_props
185
189
  if (rb_respond_to(c, id_get_derived_state_from_props)) {
186
- VALUE state = rb_funcall(c, id_state, 0);
187
- VALUE res = rb_funcall(c, id_get_derived_state_from_props, 2, rb_funcall(c, id_props, 0), state);
190
+ VALUE state = rb_ivar_get(c, iv_state);
191
+ VALUE res = rb_funcall(c, id_get_derived_state_from_props, 2,
192
+ rb_funcall(c, id_props, 0), state);
188
193
  rb_ivar_set(c, iv_state, rb_funcall(state, id_merge, res));
189
194
  }
190
195
 
191
196
  // freeze state
192
- rb_funcall(rb_funcall(c, id_state, 0), id_freeze, 0);
197
+ rb_obj_freeze(rb_ivar_get(c, iv_state));
193
198
 
194
199
  // render
195
- return rb_funcall(c, id_render, 0);
200
+ return rb_funcall(c, id_render, 0);
196
201
  }
197
202
 
198
- void internal_render_to_string(VALUE vnode, VALUE context, VALUE is_svg_mode, VALUE select_value, VALUE self, render_result_s *rres) {
199
- VNode *v;
200
- VALUE res;
201
- VALUE node_type, props;
202
- int i, len;
203
+ void internal_render_to_string(VALUE vnode, VALUE context, VALUE is_svg_mode,
204
+ VALUE select_value, VALUE self, VALUE rres) {
205
+ size_t i, len;
203
206
 
204
- if (vnode == Qnil || vnode == Qfalse || vnode == Qtrue || ((TYPE(vnode) == T_STRING) && RSTRING_LEN(vnode) == 0)) {
207
+ if (vnode == Qnil || vnode == Qfalse || vnode == Qtrue)
205
208
  return;
206
- }
207
209
 
208
210
  switch (TYPE(vnode)) {
209
- case T_STRING:
210
- res = rb_funcall(self, id_encode_entities, 1, vnode);
211
- render_result_write(rres, RSTRING_PTR(res), RSTRING_LEN(res));
212
- return;
213
- case T_FIXNUM:
214
- case T_BIGNUM:
215
- res = rb_obj_as_string(vnode);
216
- render_result_write(rres, RSTRING_PTR(res), RSTRING_LEN(res));
217
- return;
218
- case T_ARRAY:
219
- len = RARRAY_LEN(vnode);
220
- for (i = 0; i < len; i++) {
221
- internal_render_to_string(RARRAY_PTR(vnode)[i], context, is_svg_mode, select_value, self, rres);
222
- }
211
+ case T_STRING:
212
+ if (RSTRING_LEN(vnode) == 0)
223
213
  return;
214
+ rb_str_buf_append(rres, rb_funcall(self, id_encode_entities, 1, vnode));
215
+ return;
216
+ case T_FIXNUM:
217
+ case T_BIGNUM:
218
+ rb_str_buf_append(rres, rb_funcall(vnode, id_to_s, 0));
219
+ return;
220
+ case T_ARRAY:
221
+ len = RARRAY_LEN(vnode);
222
+ for (i = 0; i < len; i++) {
223
+ internal_render_to_string(RARRAY_PTR(vnode)[i], context, is_svg_mode,
224
+ select_value, self, rres);
225
+ }
226
+ return;
224
227
  }
225
228
 
226
- v = (VNode *)DATA_PTR(vnode);
227
- node_type = v->type;
228
- props = v->props;
229
+ VNode *v = (VNode *)DATA_PTR(vnode);
230
+ VALUE node_type = v->type;
231
+ VALUE props = v->props;
229
232
 
230
233
  if (TYPE(node_type) != T_STRING) {
231
- // components and Fragments
232
- VALUE rendered;
233
- VALUE ancestors = rb_funcall(node_type, id_ancestors, 0);
234
- rb_funcall(ancestors, id_include, 1, cFragment);
234
+ // Components and Fragments
235
+ VALUE rendered = Qnil;
235
236
 
236
- if (RARRAY_PTR(ancestors)[0] == cFragment) {
237
+ if (node_type == cFragment && RHASH_SIZE(props) > 0) {
237
238
  rendered = rb_hash_lookup(props, sym_children);
238
239
  } else {
239
- rendered = render_class_component(vnode, context);
240
+ rendered = render_class_component(vnode, context, v);
240
241
 
241
242
  VALUE component = v->component;
242
243
  if (rb_respond_to(component, id_get_child_context)) {
243
- context = rb_funcall(context, id_merge, 1, rb_funcall(component, id_get_child_context, 0));
244
+ context = rb_funcall(context, id_merge, 1,
245
+ rb_funcall(component, id_get_child_context, 0));
244
246
  }
245
247
  }
246
248
 
247
- internal_render_to_string(rendered, context, is_svg_mode, select_value, self, rres);
249
+ internal_render_to_string(rendered, context, is_svg_mode, select_value,
250
+ self, rres);
248
251
  return;
249
252
  }
250
253
 
251
- props = v->props;
252
-
253
254
  // render JSX to HTML
254
- VALUE node_type_s = rb_obj_as_string(node_type);
255
- render_result_write(rres, "<", 1);
256
- render_result_write(rres, RSTRING_PTR(node_type_s), RSTRING_LEN(node_type_s));
255
+ rb_str_cat(rres, "<", 1);
256
+ rb_str_buf_append(rres, node_type);
257
257
 
258
258
  VALUE children = Qnil;
259
259
  VALUE html = Qnil;
260
260
 
261
- if (props != Qnil) {
261
+ if (props != Qnil && RHASH_SIZE(props) > 0) {
262
262
  children = rb_hash_lookup(props, sym_children);
263
263
  VALUE attrs = rb_funcall(props, id_keys, 0);
264
264
  len = RARRAY_LEN(attrs);
265
265
  for (i = 0; i < len; i++) {
266
266
  VALUE name = RARRAY_PTR(attrs)[i];
267
- if (TYPE(name) == T_STRING) { name = rb_to_symbol(name); }
268
267
  ID name_id = SYM2ID(name);
269
- VALUE value = rb_hash_lookup(props, name);
270
-
271
- if (name_id == id_key || name_id == id_ref || name_id == id_self || name_id == id_source || name_id == id_children ||
272
- ((name_id == id_class_name || name_id == id_class_name2) && (rb_hash_lookup(props, sym_class) != Qnil)) ||
273
- ((name_id == id_html_for) && (rb_hash_lookup(props, sym_for) != Qnil))) {
268
+ VALUE value = rb_hash_lookup(props, rb_to_symbol(name));
269
+
270
+ if (name_id == id_key || name_id == id_ref || name_id == id_self ||
271
+ name_id == id_source || name_id == id_children ||
272
+ ((name_id == id_class_name || name_id == id_class_name2) &&
273
+ (rb_hash_lookup(props, sym_class) != Qnil)) ||
274
+ ((name_id == id_html_for) &&
275
+ (rb_hash_lookup(props, sym_for) != Qnil)))
274
276
  continue;
275
- }
276
277
 
278
+ VALUE orig_name_id = name_id;
277
279
  VALUE name_s = rb_id2str(name_id);
278
- if (rb_funcall(rUnsafe, id_match, 1, name_s) == Qtrue) {
280
+ if (rb_reg_match(rUnsafe, name_s) == Qtrue)
279
281
  continue;
280
- }
281
282
 
282
283
  name_id = normalize_prop_name(name_id, is_svg_mode);
283
- name_s = rb_id2str(name_id);
284
+ if (name_id != orig_name_id)
285
+ name_s = rb_id2str(name_id);
284
286
  value = normalize_prop_value(name_id, name_s, value, self);
285
287
 
286
288
  if (name_id == id_dangerously_set_inner_html && value != Qnil) {
287
289
  html = rb_hash_lookup(value, sym_html);
288
- } else if (name_id == id_value && strcmp(RSTRING_PTR(node_type_s), str_textarea) == 0) {
290
+ } else if (name_id == id_value &&
291
+ strcmp(RSTRING_PTR(node_type), str_textarea) == 0) {
289
292
  // <textarea value="a&b"> --> <textarea>a&amp;b</textarea>
290
293
  children = value;
291
- } else if (value != Qnil && value != Qfalse && rb_funcall(value, id_is_a, 1, cProc) != Qtrue) {
292
- if (value == Qtrue || ((TYPE(value) == T_STRING) && (RSTRING_PTR(value)[0] == 0))) {
294
+ } else if (value != Qnil && value != Qfalse &&
295
+ rb_obj_is_proc(value) != Qtrue) {
296
+ if (value == Qtrue ||
297
+ ((TYPE(value) == T_STRING) && (RSTRING_PTR(value)[0] == 0))) {
293
298
  // if (name_id == id_class || name_id == id_style) { continue; }
294
299
  value = name_s;
295
- render_result_write(rres, " ", 1);
296
- render_result_write(rres, RSTRING_PTR(name_s), RSTRING_LEN(name_s));
300
+ rb_str_cat(rres, " ", 1);
301
+ rb_str_buf_append(rres, name_s);
297
302
  continue;
298
303
  }
299
304
 
300
305
  if (name_id == id_value) {
301
- if (strcmp(RSTRING_PTR(node_type_s), str_select) == 0) {
306
+ if (strcmp(RSTRING_PTR(node_type), str_select) == 0) {
302
307
  select_value = value;
303
308
  continue;
304
309
  } else if (
305
- // If we're looking at an <option> and it's the currently selected one
306
- strcmp(RSTRING_PTR(node_type_s), str_option) == 0 &&
307
- rb_funcall(select_value, id_eqeq, 1, value) == Qtrue &&
308
- // and the <option> doesn't already have a selected attribute on it
309
- rb_hash_lookup(props, sym_selected) == Qnil
310
- ) {
311
- render_result_write(rres, " ", 1);
312
- render_result_write(rres, str_selected, strlen(str_selected));
310
+ // If we're looking at an <option> and it's the currently selected
311
+ // one
312
+ strcmp(RSTRING_PTR(node_type), str_option) == 0 &&
313
+ rb_funcall(select_value, id_eqeq, 1, value) == Qtrue &&
314
+ // and the <option> doesn't already have a selected attribute on
315
+ // it
316
+ rb_hash_lookup(props, sym_selected) == Qnil) {
317
+ rb_str_cat(rres, " ", 1);
318
+ rb_str_cat(rres, str_selected, strlen(str_selected));
313
319
  }
314
320
  }
315
321
 
316
- render_result_write(rres, " ", 1);
317
- render_result_write(rres, RSTRING_PTR(name_s), RSTRING_LEN(name_s));
318
- render_result_write(rres, "=\"", 2);
319
- res = rb_funcall(self, id_encode_entities, 1, value);
320
- render_result_write(rres, RSTRING_PTR(res), RSTRING_LEN(res));
321
- render_result_write(rres, "\"", 1);
322
+ rb_str_cat(rres, " ", 1);
323
+ rb_str_buf_append(rres, name_s);
324
+ rb_str_cat(rres, "=\"", 2);
325
+ rb_str_buf_append(rres, rb_funcall(self, id_encode_entities, 1, rb_funcall(value, id_to_s, 0)));
326
+ rb_str_cat(rres, "\"", 1);
322
327
  }
323
328
  }
324
329
  }
325
330
 
326
- render_result_write(rres, ">", 1);
331
+ rb_str_cat(rres, ">", 1);
327
332
 
328
- if (rb_funcall(rUnsafe, id_match, 1, node_type_s) == Qtrue) {
329
- rb_raise(rb_eRuntimeError, "%s is not a valid HTML tag name in %s", RSTRING_PTR(node_type_s), render_result2ptr(rres));
330
- }
333
+ if (rb_reg_match(rUnsafe, node_type) == Qtrue)
334
+ rb_raise(rb_eRuntimeError, "%s is not a valid HTML tag name in %s",
335
+ RSTRING_PTR(node_type), RSTRING_PTR(rres));
331
336
 
332
- render_result_s *pieces = render_result_new();
333
337
  VALUE has_children = Qfalse;
334
- int children_type = TYPE(children);
338
+ int children_type = (children == Qnil) ? T_NIL : TYPE(children);
335
339
 
336
340
  if (html != Qnil) {
337
- render_result_write(pieces, RSTRING_PTR(html), RSTRING_LEN(html));
341
+ rb_str_buf_append(rres, html);
338
342
  has_children = Qtrue;
339
343
  } else if (children_type == T_STRING) {
340
- res = rb_funcall(self, id_encode_entities, 1, children);
341
- render_result_write(pieces, RSTRING_PTR(res), RSTRING_LEN(res));
344
+ rb_str_buf_append(rres, rb_funcall(self, id_encode_entities, 1, children));
342
345
  has_children = Qtrue;
343
346
  } else if (children_type == T_ARRAY) {
344
347
  VALUE child;
345
348
  len = RARRAY_LEN(children);
346
- for (i = 0; i < len; i++) {
347
- child = RARRAY_PTR(children)[i];
348
- if (child != Qnil && child != Qfalse) {
349
- VALUE child_svg_mode;
350
- if (strcmp(RSTRING_PTR(node_type_s), str_svg) == 0) {
351
- child_svg_mode = Qtrue;
352
- } else if (strcmp(RSTRING_PTR(node_type_s), str_foreign_object) == 0 && is_svg_mode == Qtrue) {
353
- child_svg_mode = Qfalse;
354
- } else {
355
- child_svg_mode = is_svg_mode;
349
+ if (len > 0) {
350
+ long rres_len;
351
+ for (i = 0; i < len; i++) {
352
+ child = RARRAY_PTR(children)[i];
353
+ if (child != Qnil && child != Qfalse) {
354
+ VALUE child_svg_mode;
355
+ if (strcmp(RSTRING_PTR(node_type), str_svg) == 0)
356
+ child_svg_mode = Qtrue;
357
+ else if (strcmp(RSTRING_PTR(node_type), str_foreign_object) == 0 &&
358
+ is_svg_mode == Qtrue)
359
+ child_svg_mode = Qfalse;
360
+ else
361
+ child_svg_mode = is_svg_mode;
362
+ rres_len = RSTRING_LEN(rres);
363
+ internal_render_to_string(child, context, child_svg_mode,
364
+ select_value, self, rres);
365
+ if (rres_len < RSTRING_LEN(rres))
366
+ has_children = Qtrue;
356
367
  }
357
- size_t len = render_result_len(pieces);
358
- internal_render_to_string(child, context, child_svg_mode, select_value, self, pieces);
359
- if (len < render_result_len(pieces)) { has_children = Qtrue; }
360
368
  }
361
369
  }
362
370
  } else if (children != Qnil && children != Qfalse && children != Qtrue) {
363
371
  VALUE child_svg_mode;
364
- if (strcmp(RSTRING_PTR(node_type_s), str_svg) == 0) {
372
+ if (strcmp(RSTRING_PTR(node_type), str_svg) == 0)
365
373
  child_svg_mode = Qtrue;
366
- } else if (strcmp(RSTRING_PTR(node_type_s), str_foreign_object) == 0 && is_svg_mode == Qtrue) {
374
+ else if (strcmp(RSTRING_PTR(node_type), str_foreign_object) == 0 &&
375
+ is_svg_mode == Qtrue)
367
376
  child_svg_mode = Qfalse;
368
- } else {
377
+ else
369
378
  child_svg_mode = is_svg_mode;
370
- }
371
- size_t len = render_result_len(pieces);
372
- internal_render_to_string(children, context, child_svg_mode, select_value, self, pieces);
373
- if (len < render_result_len(pieces)) { has_children = Qtrue; }
379
+ long rres_len = RSTRING_LEN(rres);
380
+ internal_render_to_string(children, context, child_svg_mode, select_value,
381
+ self, rres);
382
+ if (rres_len < RSTRING_LEN(rres))
383
+ has_children = Qtrue;
374
384
  }
375
385
 
376
- if (has_children == Qtrue) {
377
- render_result_concat(rres, pieces);
378
- } else if (rb_funcall(rVoid, id_match, 1, node_type_s) == Qtrue) {
379
- char *s = render_result2ptr(rres);
380
- char l = s[render_result_len(rres) - 1];
386
+ if (has_children == Qfalse && rb_reg_match(rVoid, node_type) == Qtrue) {
387
+ char l = RSTRING_PTR(rres)[RSTRING_LEN(rres) - 1];
381
388
  if (l == '>') {
382
- render_result_resize(rres, render_result_len(rres) - 1);
383
- render_result_write(rres, " />", 3);
389
+ rb_str_set_len(rres, RSTRING_LEN(rres) - 1);
390
+ rb_str_cat(rres, " />", 3);
384
391
  }
385
392
  return;
386
393
  }
387
394
 
388
- render_result_free(pieces);
389
-
390
- render_result_write(rres, "</", 2);
391
- render_result_write(rres, RSTRING_PTR(node_type_s), RSTRING_LEN(node_type_s));
392
- render_result_write(rres, ">", 1);
395
+ rb_str_cat(rres, "</", 2);
396
+ rb_str_buf_append(rres, node_type);
397
+ rb_str_cat(rres, ">", 1);
393
398
 
394
399
  return;
395
400
  }
396
401
 
397
- VALUE render_to_string(int argc, VALUE *argv, VALUE self) {
398
- VALUE vnode, context, is_svg_mode, select_value, res;
399
- render_result_s *rres = render_result_new();
400
- rb_scan_args(argc, argv, "22", &vnode, &context, &is_svg_mode, &select_value);
401
- internal_render_to_string(vnode, context, is_svg_mode, select_value, self, rres);
402
- res = rb_str_new(render_result2ptr(rres), render_result_len(rres));
403
- render_result_free(rres);
402
+ static VALUE render_to_string(int argc, VALUE *argv, VALUE self) {
403
+ if (argc != 2)
404
+ rb_raise(rb_eArgError,
405
+ "wrong argument count, required args: vnode, context");
406
+ VALUE vnode = argv[0];
407
+ VALUE context = argv[1];
408
+ if (context == Qnil)
409
+ context = rb_hash_new();
410
+ VALUE res = rb_enc_str_new("", 0, utf8_encoding);
411
+ internal_render_to_string(vnode, context, Qfalse, Qnil, self, res);
404
412
  return res;
405
413
  }
406
414
 
407
- VALUE create_element(int argc, VALUE *argv, VALUE self) {
408
- VALUE type, props, children;
409
- rb_scan_args(argc, argv, "12", &type, &props, &children);
410
- VALUE normalized_props, key, ref;
415
+ static VALUE is_renderable_q(VALUE self, VALUE block_result) {
416
+ switch (TYPE(block_result)) {
417
+ case T_BIGNUM:
418
+ case T_FIXNUM:
419
+ case T_FLOAT:
420
+ case T_STRING:
421
+ return Qtrue;
422
+ case T_ARRAY:
423
+ if (RARRAY_LEN(block_result) > 0)
424
+ return is_renderable_q(self, RARRAY_PTR(block_result)[0]);
425
+ return Qfalse;
426
+ case T_DATA:
427
+ if (RBASIC_CLASS(block_result) == cVNode)
428
+ return Qtrue;
429
+ return Qfalse;
430
+ default:
431
+ return Qfalse;
432
+ }
433
+ return Qfalse;
434
+ }
435
+
436
+ static VALUE create_element(int argc, VALUE *argv, VALUE self) {
437
+ if (argc < 1 || argc > 3)
438
+ rb_raise(rb_eArgError, "wrong argument count, required arg: type, optional "
439
+ "args: props, children");
440
+ VALUE type = argv[0];
441
+ VALUE props = (argc > 1) ? argv[1] : Qnil;
442
+ VALUE children = (argc > 2) ? argv[2] : Qnil;
443
+ VALUE normalized_props, key = Qnil, ref = Qnil;
411
444
 
412
445
  if (props != Qnil) {
413
446
  if (TYPE(props) == T_HASH) {
414
447
  normalized_props = rb_hash_dup(props);
415
- key = rb_hash_delete(normalized_props, sym_key);
416
- ref = rb_hash_delete(normalized_props, sym_ref);
448
+ if (RHASH_SIZE(normalized_props) > 0) {
449
+ key = rb_hash_delete(normalized_props, sym_key);
450
+ ref = rb_hash_delete(normalized_props, sym_ref);
451
+ }
417
452
  } else {
418
453
  children = props;
419
454
  normalized_props = rb_hash_new();
420
- key = Qnil;
421
- ref = Qnil;
422
455
  }
423
456
  } else {
424
457
  normalized_props = rb_hash_new();
425
- key = Qnil;
426
- ref = Qnil;
427
458
  }
428
459
 
429
460
  if (rb_block_given_p()) {
430
461
  VALUE pr = rb_funcall(mPreact, id_render_buffer, 0);
431
- pr = rb_ary_push(pr, rb_ary_new());
462
+ rb_ary_push(pr, rb_ary_new());
432
463
  VALUE block_result = rb_yield(Qnil);
433
464
  VALUE c = rb_ary_pop(pr);
434
- if (rb_funcall(mPreact, id_is_renderable, 1, block_result) == Qtrue) {
465
+ if (is_renderable_q(mPreact, block_result) == Qtrue)
435
466
  rb_ary_push(c, block_result);
436
- }
437
- if (RARRAY_LEN(c) > 0) {
467
+ if (RARRAY_LEN(c) > 0)
438
468
  children = c;
439
- }
440
469
  }
441
470
 
442
- if (children != Qnil) {
471
+ if (children != Qnil)
443
472
  rb_hash_aset(normalized_props, sym_children, children);
444
- }
445
473
 
446
- return rb_funcall(cVNode, id_new, 4, type, normalized_props, key, ref);
474
+ const VALUE args[4] = {type, normalized_props, key, ref};
475
+ return rb_class_new_instance(4, (const VALUE *)&args, cVNode);
476
+ }
477
+
478
+ static VALUE render_element(int argc, VALUE *argv, VALUE self) {
479
+ VALUE pr = rb_funcall(self, id_render_buffer, 0);
480
+ rb_ary_push(RARRAY_PTR(pr)[RARRAY_LEN(pr) - 1], create_element(argc, argv, self));
481
+ return Qnil;
447
482
  }
448
483
 
449
484
  void Init_Preact(void) {
450
- id_ancestors = rb_intern("ancestors");
485
+ utf8_encoding = rb_utf8_encoding();
451
486
  id_checked = rb_intern("checked");
452
487
  id_children = rb_intern("children");
453
488
  id_class = rb_intern("class");
@@ -463,21 +498,14 @@ void Init_Preact(void) {
463
498
  id_downcase = rb_intern("downcase");
464
499
  id_encode_entities = rb_intern("_encode_entities");
465
500
  id_eqeq = rb_intern("==");
501
+ id_for = rb_intern("for");
466
502
  id_get_child_context = rb_intern("get_child_context");
467
503
  id_get_derived_state_from_props = rb_intern("get_derived_state_from_props");
468
504
  id_gsub = rb_intern("gsub");
469
505
  id_html_for = rb_intern("html_for");
470
- id_for = rb_intern("for");
471
- id_freeze = rb_intern("freeze");
472
- id_include = rb_intern("include?");
473
- id_is_a = rb_intern("is_a?");
474
- id_is_renderable = rb_intern("is_renderable?");
475
506
  id_key = rb_intern("key");
476
- id_keyq = rb_intern("key?");
477
507
  id_keys = rb_intern("keys");
478
- id_match = rb_intern("match?");
479
508
  id_merge = rb_intern("merge");
480
- id_new = rb_intern("new");
481
509
  id_props = rb_intern("props");
482
510
  id_ref = rb_intern("ref");
483
511
  id_render = rb_intern("render");
@@ -485,10 +513,9 @@ void Init_Preact(void) {
485
513
  id_selected = rb_intern("selected");
486
514
  id_self = rb_intern("__self");
487
515
  id_source = rb_intern("__source");
488
- id_start_withq = rb_intern("start_with?");
489
- id_state = rb_intern("state");
490
516
  id_style = rb_intern("style");
491
517
  id_style_obj_to_css = rb_intern("_style_obj_to_css");
518
+ id_to_s = rb_intern("to_s");
492
519
  id_validate_props = rb_intern("validate_props");
493
520
  id_value = rb_intern("value");
494
521
 
@@ -508,30 +535,25 @@ void Init_Preact(void) {
508
535
  sym_selected = ID2SYM(rb_intern("selected"));
509
536
  sym_value = ID2SYM(id_value);
510
537
 
511
- cProc = rb_const_get(rb_cObject, rb_intern("Proc"));
512
- cRegexp = rb_const_get(rb_cObject, rb_intern("Regexp"));
513
538
  mIsomorfeus = rb_const_get(rb_cObject, rb_intern("Isomorfeus"));
514
539
  mPreact = rb_define_module("Preact");
515
540
  cFragment = rb_define_class("Fragment", rb_cObject);
516
541
 
517
542
  // set instance variables on the module to keep references to these objects
518
- // to prevent garbage colloction
519
- rUnsafe = rb_funcall(cRegexp, id_new, 1, rb_str_new_cstr(str_run));
543
+ // to prevent garbage collection
544
+ rUnsafe = rb_reg_regcomp(rb_str_new_cstr(str_run));
520
545
  rb_obj_freeze(rUnsafe);
521
546
  rb_ivar_set(mPreact, rb_intern("@_r_unsafe"), rUnsafe);
522
- rVoid = rb_funcall(cRegexp, id_new, 1, rb_str_new_cstr(str_rve));
547
+ rVoid = rb_reg_regcomp(rb_str_new_cstr(str_rve));
523
548
  rb_obj_freeze(rVoid);
524
549
  rb_ivar_set(mPreact, rb_intern("@_r_void"), rVoid);
525
- rXlink = rb_funcall(cRegexp, id_new, 1, rb_str_new_cstr(str_rxl));
550
+ rXlink = rb_reg_regcomp(rb_str_new_cstr(str_rxl));
526
551
  rb_obj_freeze(rXlink);
527
552
  rb_ivar_set(mPreact, rb_intern("@_r_xlink"), rXlink);
528
- rXlink2 = rb_funcall(cRegexp, id_new, 1, rb_str_new_cstr(str_rx2));
553
+ rXlink2 = rb_reg_regcomp(rb_str_new_cstr(str_rx2));
529
554
  rb_obj_freeze(rXlink2);
530
555
  rb_ivar_set(mPreact, rb_intern("@_r_xlink2"), rXlink2);
531
556
 
532
- s_aria = rb_str_new_cstr("aria");
533
- rb_obj_freeze(s_aria);
534
- rb_ivar_set(mPreact, rb_intern("@_s_aria"), s_aria);
535
557
  s_false = rb_str_new_cstr("false");
536
558
  rb_obj_freeze(s_false);
537
559
  rb_ivar_set(mPreact, rb_intern("@_s_false"), s_false);
@@ -542,6 +564,8 @@ void Init_Preact(void) {
542
564
  rb_obj_freeze(s_xlink);
543
565
  rb_ivar_set(mPreact, rb_intern("@_s_xlink"), s_xlink);
544
566
 
567
+ rb_define_module_function(mPreact, "_render_element", render_element, -1);
545
568
  rb_define_module_function(mPreact, "_render_to_string", render_to_string, -1);
546
569
  rb_define_module_function(mPreact, "create_element", create_element, -1);
570
+ rb_define_module_function(mPreact, "is_renderable?", is_renderable_q, 1);
547
571
  }