herb 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/config.yml +156 -0
  3. data/ext/herb/error_helpers.c +168 -0
  4. data/ext/herb/extension.c +4 -0
  5. data/ext/herb/extension_helpers.c +1 -0
  6. data/ext/herb/nodes.c +110 -0
  7. data/lib/herb/ast/nodes.rb +393 -17
  8. data/lib/herb/engine.rb +55 -26
  9. data/lib/herb/errors.rb +245 -0
  10. data/lib/herb/parser_options.rb +6 -1
  11. data/lib/herb/prism_inspect.rb +5 -1
  12. data/lib/herb/version.rb +1 -1
  13. data/lib/herb/visitor.rb +10 -0
  14. data/sig/herb/ast/nodes.rbs +132 -0
  15. data/sig/herb/engine.rbs +4 -0
  16. data/sig/herb/errors.rbs +114 -0
  17. data/sig/herb/parser_options.rbs +4 -0
  18. data/sig/herb/visitor.rbs +6 -0
  19. data/sig/rubyvm.rbs +5 -0
  20. data/sig/serialized_ast_errors.rbs +28 -0
  21. data/sig/serialized_ast_nodes.rbs +31 -0
  22. data/src/analyze/action_view/attribute_extraction_helpers.c +14 -1
  23. data/src/analyze/action_view/content_tag.c +19 -11
  24. data/src/analyze/action_view/link_to.c +25 -1
  25. data/src/analyze/action_view/registry.c +23 -0
  26. data/src/analyze/action_view/tag.c +14 -8
  27. data/src/analyze/action_view/tag_helpers.c +78 -11
  28. data/src/analyze/analyze.c +3 -0
  29. data/src/analyze/prism_annotate.c +4 -2
  30. data/src/analyze/render_nodes.c +761 -0
  31. data/src/analyze/transform.c +7 -0
  32. data/src/ast_nodes.c +97 -0
  33. data/src/ast_pretty_print.c +74 -0
  34. data/src/errors.c +379 -0
  35. data/src/include/analyze/action_view/tag_helper_handler.h +2 -0
  36. data/src/include/analyze/render_nodes.h +11 -0
  37. data/src/include/ast_nodes.h +37 -0
  38. data/src/include/errors.h +58 -0
  39. data/src/include/parser.h +1 -0
  40. data/src/include/version.h +1 -1
  41. data/src/parser.c +1 -0
  42. data/src/parser_match_tags.c +20 -0
  43. data/src/visitor.c +20 -0
  44. data/templates/lib/herb/ast/nodes.rb.erb +8 -2
  45. data/templates/rust/src/ast/nodes.rs.erb +1 -1
  46. data/templates/rust/src/nodes.rs.erb +1 -1
  47. metadata +4 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10b9ca3614ee3b23c37caf0f7d7363a434c15a39b27e3dc8c83023ec4f0587b1
4
- data.tar.gz: 4be0d44ce17912901556481b7fb21ee18c5f7b71165c98f4e2cee6961614c626
3
+ metadata.gz: a552819ddaf0c50275110d19455609f491dfb3298da4b76e898eb996bc458e4a
4
+ data.tar.gz: 835fc30e2530c8c98aa2077d607f061f78f5ae4030e3c3d449bc2ac9796a6ea4
5
5
  SHA512:
6
- metadata.gz: '00879b8718267317125d050da50cc6423f33e1765c236c470c5ea5ff1da8e8ad57b1c0c35a8d7a3a4b75200f3f00beacfbc17d14b6d44886cdf8b5e67ac033f0'
7
- data.tar.gz: b7f7583d3dd1cce9bf9021cc8a33d1936bab1e3e1cd681d77bf6e4f4d9e6be25b332b742ad9c1e5c079f13f363d3a21a3188affbac96f84a77f4160cbb9498a2
6
+ metadata.gz: 3b9e9362ffce00e457a3df27e834419f5a8a0351ef313b7b73b0ae7a0f44dd4689dde96586342ed11ea736ac16baff2473fbab23f141b8f51bdc92aef7cc9d44
7
+ data.tar.gz: e76c844b40670b773106547cefd1955fb42867f08f49134557946b24f008187a1cdea4c5f010c40e27505c6dd4bdd4c4f5fa1aae16f92ab45f3a2dbff867d082
data/config.yml CHANGED
@@ -336,6 +336,80 @@ errors:
336
336
  - name: nested_tag_column
337
337
  type: size_t
338
338
 
339
+ - name: RenderAmbiguousLocalsError
340
+ message:
341
+ template: "Did you mean `render partial: '%s', locals: { ... }`? Using `render '%s', locals: { ... }` passes a local variable named `locals` to the partial instead of setting the `locals:` option."
342
+ arguments:
343
+ - partial
344
+ - partial
345
+
346
+ fields:
347
+ - name: partial
348
+ type: string
349
+
350
+ - name: RenderMissingLocalsError
351
+ message:
352
+ template: "Wrap `%s` in `locals: { ... }` when using `partial:`. Use `render partial: '%s', locals: { %s }` instead. Without `locals:`, these keyword arguments are ignored."
353
+ arguments:
354
+ - keywords
355
+ - partial
356
+ - keywords
357
+
358
+ fields:
359
+ - name: partial
360
+ type: string
361
+
362
+ - name: keywords
363
+ type: string
364
+
365
+ - name: RenderNoArgumentsError
366
+ message:
367
+ template: "No arguments passed to `render`. It needs a partial name, a keyword argument like `partial:`, `template:`, or `layout:`, or a renderable object."
368
+ arguments: []
369
+
370
+ fields: []
371
+
372
+ - name: RenderConflictingPartialError
373
+ message:
374
+ template: "Both a positional partial `'%s'` and a keyword `partial: '%s'` were passed to `render`. Use one form or the other, not both."
375
+ arguments:
376
+ - positional_partial
377
+ - keyword_partial
378
+
379
+ fields:
380
+ - name: positional_partial
381
+ type: string
382
+
383
+ - name: keyword_partial
384
+ type: string
385
+
386
+ - name: RenderInvalidAsOptionError
387
+ message:
388
+ template: "The `as:` value `'%s'` is not a valid Ruby identifier. Use a name that starts with a lowercase letter or underscore, like `as: :item`."
389
+ arguments:
390
+ - as_value
391
+
392
+ fields:
393
+ - name: as_value
394
+ type: string
395
+
396
+ - name: RenderObjectAndCollectionError
397
+ message:
398
+ template: "The `object:` and `collection:` options are mutually exclusive. Use one or the other in your `render` call."
399
+ arguments: []
400
+
401
+ fields: []
402
+
403
+ - name: RenderLayoutWithoutBlockError
404
+ message:
405
+ template: "Layout rendering needs a block. Use `render layout: '%s' do ... end` so the layout has content to wrap."
406
+ arguments:
407
+ - layout
408
+
409
+ fields:
410
+ - name: layout
411
+ type: string
412
+
339
413
  warnings:
340
414
  fields: []
341
415
  types: []
@@ -1013,6 +1087,88 @@ nodes:
1013
1087
  type: node
1014
1088
  kind: ERBEndNode
1015
1089
 
1090
+ - name: RubyRenderLocalNode
1091
+ fields:
1092
+ - name: name
1093
+ type: token
1094
+
1095
+ - name: value
1096
+ type: node
1097
+ kind: RubyLiteralNode
1098
+
1099
+ - name: ERBRenderNode
1100
+ fields:
1101
+ - name: tag_opening
1102
+ type: token
1103
+
1104
+ - name: content
1105
+ type: token
1106
+
1107
+ - name: tag_closing
1108
+ type: token
1109
+
1110
+ - name: analyzed_ruby
1111
+ type: analyzed_ruby
1112
+
1113
+ - name: prism_node
1114
+ type: prism_node
1115
+
1116
+ - name: partial
1117
+ type: token
1118
+
1119
+ - name: template_path
1120
+ type: token
1121
+
1122
+ - name: layout
1123
+ type: token
1124
+
1125
+ - name: file
1126
+ type: token
1127
+
1128
+ - name: inline_template
1129
+ type: token
1130
+
1131
+ - name: body
1132
+ type: token
1133
+
1134
+ - name: plain
1135
+ type: token
1136
+
1137
+ - name: html
1138
+ type: token
1139
+
1140
+ - name: renderable
1141
+ type: token
1142
+
1143
+ - name: collection
1144
+ type: token
1145
+
1146
+ - name: object
1147
+ type: token
1148
+
1149
+ - name: as_name
1150
+ type: token
1151
+
1152
+ - name: spacer_template
1153
+ type: token
1154
+
1155
+ - name: formats
1156
+ type: token
1157
+
1158
+ - name: variants
1159
+ type: token
1160
+
1161
+ - name: handlers
1162
+ type: token
1163
+
1164
+ - name: content_type
1165
+ type: token
1166
+
1167
+ - name: locals
1168
+ type: array
1169
+ kind:
1170
+ - RubyRenderLocalNode
1171
+
1016
1172
  - name: ERBYieldNode
1017
1173
  fields:
1018
1174
  - name: tag_opening
@@ -39,6 +39,13 @@ static VALUE cMissingAttributeValueError;
39
39
  static VALUE cUnclosedERBTagError;
40
40
  static VALUE cStrayERBClosingTagError;
41
41
  static VALUE cNestedERBTagError;
42
+ static VALUE cRenderAmbiguousLocalsError;
43
+ static VALUE cRenderMissingLocalsError;
44
+ static VALUE cRenderNoArgumentsError;
45
+ static VALUE cRenderConflictingPartialError;
46
+ static VALUE cRenderInvalidAsOptionError;
47
+ static VALUE cRenderObjectAndCollectionError;
48
+ static VALUE cRenderLayoutWithoutBlockError;
42
49
 
43
50
  void rb_init_error_classes(void) {
44
51
  mErrors = rb_define_module_under(mHerb, "Errors");
@@ -66,6 +73,13 @@ void rb_init_error_classes(void) {
66
73
  cUnclosedERBTagError = rb_define_class_under(mErrors, "UnclosedERBTagError", cError);
67
74
  cStrayERBClosingTagError = rb_define_class_under(mErrors, "StrayERBClosingTagError", cError);
68
75
  cNestedERBTagError = rb_define_class_under(mErrors, "NestedERBTagError", cError);
76
+ cRenderAmbiguousLocalsError = rb_define_class_under(mErrors, "RenderAmbiguousLocalsError", cError);
77
+ cRenderMissingLocalsError = rb_define_class_under(mErrors, "RenderMissingLocalsError", cError);
78
+ cRenderNoArgumentsError = rb_define_class_under(mErrors, "RenderNoArgumentsError", cError);
79
+ cRenderConflictingPartialError = rb_define_class_under(mErrors, "RenderConflictingPartialError", cError);
80
+ cRenderInvalidAsOptionError = rb_define_class_under(mErrors, "RenderInvalidAsOptionError", cError);
81
+ cRenderObjectAndCollectionError = rb_define_class_under(mErrors, "RenderObjectAndCollectionError", cError);
82
+ cRenderLayoutWithoutBlockError = rb_define_class_under(mErrors, "RenderLayoutWithoutBlockError", cError);
69
83
  }
70
84
 
71
85
  static VALUE rb_unexpected_error_from_c_struct(UNEXPECTED_ERROR_T* unexpected_error) {
@@ -582,6 +596,153 @@ static VALUE rb_nested_erb_tag_error_from_c_struct(NESTED_ERB_TAG_ERROR_T* neste
582
596
  return rb_class_new_instance(6, args, cNestedERBTagError);
583
597
  };
584
598
 
599
+ static VALUE rb_render_ambiguous_locals_error_from_c_struct(RENDER_AMBIGUOUS_LOCALS_ERROR_T* render_ambiguous_locals_error) {
600
+ if (render_ambiguous_locals_error == NULL) { return Qnil; }
601
+
602
+ ERROR_T* error = &render_ambiguous_locals_error->base;
603
+
604
+ VALUE type = rb_string_from_hb_string(error_type_to_string(error));
605
+ VALUE location = rb_location_from_c_struct(error->location);
606
+ VALUE message = rb_string_from_hb_string(error->message);
607
+
608
+ VALUE render_ambiguous_locals_error_partial = rb_utf8_str_new(render_ambiguous_locals_error->partial.data, render_ambiguous_locals_error->partial.length);
609
+
610
+ VALUE args[4] = {
611
+ type,
612
+ location,
613
+ message,
614
+ render_ambiguous_locals_error_partial
615
+ };
616
+
617
+ return rb_class_new_instance(4, args, cRenderAmbiguousLocalsError);
618
+ };
619
+
620
+ static VALUE rb_render_missing_locals_error_from_c_struct(RENDER_MISSING_LOCALS_ERROR_T* render_missing_locals_error) {
621
+ if (render_missing_locals_error == NULL) { return Qnil; }
622
+
623
+ ERROR_T* error = &render_missing_locals_error->base;
624
+
625
+ VALUE type = rb_string_from_hb_string(error_type_to_string(error));
626
+ VALUE location = rb_location_from_c_struct(error->location);
627
+ VALUE message = rb_string_from_hb_string(error->message);
628
+
629
+ VALUE render_missing_locals_error_partial = rb_utf8_str_new(render_missing_locals_error->partial.data, render_missing_locals_error->partial.length);
630
+ VALUE render_missing_locals_error_keywords = rb_utf8_str_new(render_missing_locals_error->keywords.data, render_missing_locals_error->keywords.length);
631
+
632
+ VALUE args[5] = {
633
+ type,
634
+ location,
635
+ message,
636
+ render_missing_locals_error_partial,
637
+ render_missing_locals_error_keywords
638
+ };
639
+
640
+ return rb_class_new_instance(5, args, cRenderMissingLocalsError);
641
+ };
642
+
643
+ static VALUE rb_render_no_arguments_error_from_c_struct(RENDER_NO_ARGUMENTS_ERROR_T* render_no_arguments_error) {
644
+ if (render_no_arguments_error == NULL) { return Qnil; }
645
+
646
+ ERROR_T* error = &render_no_arguments_error->base;
647
+
648
+ VALUE type = rb_string_from_hb_string(error_type_to_string(error));
649
+ VALUE location = rb_location_from_c_struct(error->location);
650
+ VALUE message = rb_string_from_hb_string(error->message);
651
+
652
+
653
+ VALUE args[3] = {
654
+ type,
655
+ location,
656
+ message
657
+ };
658
+
659
+ return rb_class_new_instance(3, args, cRenderNoArgumentsError);
660
+ };
661
+
662
+ static VALUE rb_render_conflicting_partial_error_from_c_struct(RENDER_CONFLICTING_PARTIAL_ERROR_T* render_conflicting_partial_error) {
663
+ if (render_conflicting_partial_error == NULL) { return Qnil; }
664
+
665
+ ERROR_T* error = &render_conflicting_partial_error->base;
666
+
667
+ VALUE type = rb_string_from_hb_string(error_type_to_string(error));
668
+ VALUE location = rb_location_from_c_struct(error->location);
669
+ VALUE message = rb_string_from_hb_string(error->message);
670
+
671
+ VALUE render_conflicting_partial_error_positional_partial = rb_utf8_str_new(render_conflicting_partial_error->positional_partial.data, render_conflicting_partial_error->positional_partial.length);
672
+ VALUE render_conflicting_partial_error_keyword_partial = rb_utf8_str_new(render_conflicting_partial_error->keyword_partial.data, render_conflicting_partial_error->keyword_partial.length);
673
+
674
+ VALUE args[5] = {
675
+ type,
676
+ location,
677
+ message,
678
+ render_conflicting_partial_error_positional_partial,
679
+ render_conflicting_partial_error_keyword_partial
680
+ };
681
+
682
+ return rb_class_new_instance(5, args, cRenderConflictingPartialError);
683
+ };
684
+
685
+ static VALUE rb_render_invalid_as_option_error_from_c_struct(RENDER_INVALID_AS_OPTION_ERROR_T* render_invalid_as_option_error) {
686
+ if (render_invalid_as_option_error == NULL) { return Qnil; }
687
+
688
+ ERROR_T* error = &render_invalid_as_option_error->base;
689
+
690
+ VALUE type = rb_string_from_hb_string(error_type_to_string(error));
691
+ VALUE location = rb_location_from_c_struct(error->location);
692
+ VALUE message = rb_string_from_hb_string(error->message);
693
+
694
+ VALUE render_invalid_as_option_error_as_value = rb_utf8_str_new(render_invalid_as_option_error->as_value.data, render_invalid_as_option_error->as_value.length);
695
+
696
+ VALUE args[4] = {
697
+ type,
698
+ location,
699
+ message,
700
+ render_invalid_as_option_error_as_value
701
+ };
702
+
703
+ return rb_class_new_instance(4, args, cRenderInvalidAsOptionError);
704
+ };
705
+
706
+ static VALUE rb_render_object_and_collection_error_from_c_struct(RENDER_OBJECT_AND_COLLECTION_ERROR_T* render_object_and_collection_error) {
707
+ if (render_object_and_collection_error == NULL) { return Qnil; }
708
+
709
+ ERROR_T* error = &render_object_and_collection_error->base;
710
+
711
+ VALUE type = rb_string_from_hb_string(error_type_to_string(error));
712
+ VALUE location = rb_location_from_c_struct(error->location);
713
+ VALUE message = rb_string_from_hb_string(error->message);
714
+
715
+
716
+ VALUE args[3] = {
717
+ type,
718
+ location,
719
+ message
720
+ };
721
+
722
+ return rb_class_new_instance(3, args, cRenderObjectAndCollectionError);
723
+ };
724
+
725
+ static VALUE rb_render_layout_without_block_error_from_c_struct(RENDER_LAYOUT_WITHOUT_BLOCK_ERROR_T* render_layout_without_block_error) {
726
+ if (render_layout_without_block_error == NULL) { return Qnil; }
727
+
728
+ ERROR_T* error = &render_layout_without_block_error->base;
729
+
730
+ VALUE type = rb_string_from_hb_string(error_type_to_string(error));
731
+ VALUE location = rb_location_from_c_struct(error->location);
732
+ VALUE message = rb_string_from_hb_string(error->message);
733
+
734
+ VALUE render_layout_without_block_error_layout = rb_utf8_str_new(render_layout_without_block_error->layout.data, render_layout_without_block_error->layout.length);
735
+
736
+ VALUE args[4] = {
737
+ type,
738
+ location,
739
+ message,
740
+ render_layout_without_block_error_layout
741
+ };
742
+
743
+ return rb_class_new_instance(4, args, cRenderLayoutWithoutBlockError);
744
+ };
745
+
585
746
 
586
747
  VALUE rb_error_from_c_struct(ERROR_T* error) {
587
748
  if (!error) { return Qnil; }
@@ -610,6 +771,13 @@ VALUE rb_error_from_c_struct(ERROR_T* error) {
610
771
  case UNCLOSED_ERB_TAG_ERROR: return rb_unclosed_erb_tag_error_from_c_struct((UNCLOSED_ERB_TAG_ERROR_T*) error); break;
611
772
  case STRAY_ERB_CLOSING_TAG_ERROR: return rb_stray_erb_closing_tag_error_from_c_struct((STRAY_ERB_CLOSING_TAG_ERROR_T*) error); break;
612
773
  case NESTED_ERB_TAG_ERROR: return rb_nested_erb_tag_error_from_c_struct((NESTED_ERB_TAG_ERROR_T*) error); break;
774
+ case RENDER_AMBIGUOUS_LOCALS_ERROR: return rb_render_ambiguous_locals_error_from_c_struct((RENDER_AMBIGUOUS_LOCALS_ERROR_T*) error); break;
775
+ case RENDER_MISSING_LOCALS_ERROR: return rb_render_missing_locals_error_from_c_struct((RENDER_MISSING_LOCALS_ERROR_T*) error); break;
776
+ case RENDER_NO_ARGUMENTS_ERROR: return rb_render_no_arguments_error_from_c_struct((RENDER_NO_ARGUMENTS_ERROR_T*) error); break;
777
+ case RENDER_CONFLICTING_PARTIAL_ERROR: return rb_render_conflicting_partial_error_from_c_struct((RENDER_CONFLICTING_PARTIAL_ERROR_T*) error); break;
778
+ case RENDER_INVALID_AS_OPTION_ERROR: return rb_render_invalid_as_option_error_from_c_struct((RENDER_INVALID_AS_OPTION_ERROR_T*) error); break;
779
+ case RENDER_OBJECT_AND_COLLECTION_ERROR: return rb_render_object_and_collection_error_from_c_struct((RENDER_OBJECT_AND_COLLECTION_ERROR_T*) error); break;
780
+ case RENDER_LAYOUT_WITHOUT_BLOCK_ERROR: return rb_render_layout_without_block_error_from_c_struct((RENDER_LAYOUT_WITHOUT_BLOCK_ERROR_T*) error); break;
613
781
  }
614
782
 
615
783
  return Qnil;
data/ext/herb/extension.c CHANGED
@@ -136,6 +136,10 @@ static VALUE Herb_parse(int argc, VALUE* argv, VALUE self) {
136
136
  }
137
137
  if (!NIL_P(action_view_helpers) && RTEST(action_view_helpers)) { parser_options.action_view_helpers = true; }
138
138
 
139
+ VALUE render_nodes = rb_hash_lookup(options, rb_utf8_str_new_cstr("render_nodes"));
140
+ if (NIL_P(render_nodes)) { render_nodes = rb_hash_lookup(options, ID2SYM(rb_intern("render_nodes"))); }
141
+ if (!NIL_P(render_nodes) && RTEST(render_nodes)) { parser_options.render_nodes = true; }
142
+
139
143
  VALUE prism_nodes = rb_hash_lookup(options, rb_utf8_str_new_cstr("prism_nodes"));
140
144
  if (NIL_P(prism_nodes)) { prism_nodes = rb_hash_lookup(options, ID2SYM(rb_intern("prism_nodes"))); }
141
145
  if (!NIL_P(prism_nodes) && RTEST(prism_nodes)) { parser_options.prism_nodes = true; }
@@ -89,6 +89,7 @@ VALUE create_parse_result(AST_DOCUMENT_NODE_T* root, VALUE source, const parser_
89
89
  rb_hash_aset(kwargs, ID2SYM(rb_intern("track_whitespace")), options->track_whitespace ? Qtrue : Qfalse);
90
90
  rb_hash_aset(kwargs, ID2SYM(rb_intern("analyze")), options->analyze ? Qtrue : Qfalse);
91
91
  rb_hash_aset(kwargs, ID2SYM(rb_intern("action_view_helpers")), options->action_view_helpers ? Qtrue : Qfalse);
92
+ rb_hash_aset(kwargs, ID2SYM(rb_intern("render_nodes")), options->render_nodes ? Qtrue : Qfalse);
92
93
  rb_hash_aset(kwargs, ID2SYM(rb_intern("prism_nodes")), options->prism_nodes ? Qtrue : Qfalse);
93
94
  rb_hash_aset(kwargs, ID2SYM(rb_intern("prism_nodes_deep")), options->prism_nodes_deep ? Qtrue : Qfalse);
94
95
  rb_hash_aset(kwargs, ID2SYM(rb_intern("prism_program")), options->prism_program ? Qtrue : Qfalse);
data/ext/herb/nodes.c CHANGED
@@ -53,6 +53,8 @@ static VALUE cERBRescueNode;
53
53
  static VALUE cERBEnsureNode;
54
54
  static VALUE cERBBeginNode;
55
55
  static VALUE cERBUnlessNode;
56
+ static VALUE cRubyRenderLocalNode;
57
+ static VALUE cERBRenderNode;
56
58
  static VALUE cERBYieldNode;
57
59
  static VALUE cERBInNode;
58
60
 
@@ -95,6 +97,8 @@ void rb_init_node_classes(void) {
95
97
  cERBEnsureNode = rb_define_class_under(mAST, "ERBEnsureNode", cNode);
96
98
  cERBBeginNode = rb_define_class_under(mAST, "ERBBeginNode", cNode);
97
99
  cERBUnlessNode = rb_define_class_under(mAST, "ERBUnlessNode", cNode);
100
+ cRubyRenderLocalNode = rb_define_class_under(mAST, "RubyRenderLocalNode", cNode);
101
+ cERBRenderNode = rb_define_class_under(mAST, "ERBRenderNode", cNode);
98
102
  cERBYieldNode = rb_define_class_under(mAST, "ERBYieldNode", cNode);
99
103
  cERBInNode = rb_define_class_under(mAST, "ERBInNode", cNode);
100
104
  }
@@ -1260,6 +1264,110 @@ static VALUE rb_erb_unless_node_from_c_struct(AST_ERB_UNLESS_NODE_T* erb_unless_
1260
1264
  return rb_class_new_instance(11, args, cERBUnlessNode);
1261
1265
  };
1262
1266
 
1267
+ static VALUE rb_ruby_render_local_node_from_c_struct(AST_RUBY_RENDER_LOCAL_NODE_T* ruby_render_local_node) {
1268
+ if (ruby_render_local_node == NULL) { return Qnil; }
1269
+
1270
+ AST_NODE_T* node = &ruby_render_local_node->base;
1271
+
1272
+ VALUE type = rb_string_from_hb_string(ast_node_type_to_string(node));
1273
+ VALUE location = rb_location_from_c_struct(node->location);
1274
+ VALUE errors = rb_errors_array_from_c_array(node->errors);
1275
+
1276
+ VALUE ruby_render_local_node_name = rb_token_from_c_struct(ruby_render_local_node->name);
1277
+ VALUE ruby_render_local_node_value = rb_node_from_c_struct((AST_NODE_T*) ruby_render_local_node->value);
1278
+
1279
+ VALUE args[5] = {
1280
+ type,
1281
+ location,
1282
+ errors,
1283
+ ruby_render_local_node_name,
1284
+ ruby_render_local_node_value
1285
+ };
1286
+
1287
+ return rb_class_new_instance(5, args, cRubyRenderLocalNode);
1288
+ };
1289
+
1290
+ static VALUE rb_erb_render_node_from_c_struct(AST_ERB_RENDER_NODE_T* erb_render_node) {
1291
+ if (erb_render_node == NULL) { return Qnil; }
1292
+
1293
+ AST_NODE_T* node = &erb_render_node->base;
1294
+
1295
+ VALUE type = rb_string_from_hb_string(ast_node_type_to_string(node));
1296
+ VALUE location = rb_location_from_c_struct(node->location);
1297
+ VALUE errors = rb_errors_array_from_c_array(node->errors);
1298
+
1299
+ VALUE erb_render_node_tag_opening = rb_token_from_c_struct(erb_render_node->tag_opening);
1300
+ VALUE erb_render_node_content = rb_token_from_c_struct(erb_render_node->content);
1301
+ VALUE erb_render_node_tag_closing = rb_token_from_c_struct(erb_render_node->tag_closing);
1302
+ /* analyzed_ruby is internal parser state, not exposed to Ruby */
1303
+ VALUE erb_render_node_analyzed_ruby = Qnil;
1304
+ VALUE erb_render_node_prism_node;
1305
+ if (erb_render_node->prism_node.node != NULL && erb_render_node->prism_node.parser != NULL) {
1306
+ pm_buffer_t pm_buffer = { 0 };
1307
+ pm_serialize(erb_render_node->prism_node.parser, erb_render_node->prism_node.node, &pm_buffer);
1308
+
1309
+ if (pm_buffer.length > 0) {
1310
+ erb_render_node_prism_node = rb_str_new(pm_buffer.value, pm_buffer.length);
1311
+ rb_enc_associate(erb_render_node_prism_node, rb_ascii8bit_encoding());
1312
+ OBJ_FREEZE(erb_render_node_prism_node);
1313
+ } else {
1314
+ erb_render_node_prism_node = Qnil;
1315
+ }
1316
+ pm_buffer_free(&pm_buffer);
1317
+ } else {
1318
+ erb_render_node_prism_node = Qnil;
1319
+ }
1320
+ VALUE erb_render_node_partial = rb_token_from_c_struct(erb_render_node->partial);
1321
+ VALUE erb_render_node_template_path = rb_token_from_c_struct(erb_render_node->template_path);
1322
+ VALUE erb_render_node_layout = rb_token_from_c_struct(erb_render_node->layout);
1323
+ VALUE erb_render_node_file = rb_token_from_c_struct(erb_render_node->file);
1324
+ VALUE erb_render_node_inline_template = rb_token_from_c_struct(erb_render_node->inline_template);
1325
+ VALUE erb_render_node_body = rb_token_from_c_struct(erb_render_node->body);
1326
+ VALUE erb_render_node_plain = rb_token_from_c_struct(erb_render_node->plain);
1327
+ VALUE erb_render_node_html = rb_token_from_c_struct(erb_render_node->html);
1328
+ VALUE erb_render_node_renderable = rb_token_from_c_struct(erb_render_node->renderable);
1329
+ VALUE erb_render_node_collection = rb_token_from_c_struct(erb_render_node->collection);
1330
+ VALUE erb_render_node_object = rb_token_from_c_struct(erb_render_node->object);
1331
+ VALUE erb_render_node_as_name = rb_token_from_c_struct(erb_render_node->as_name);
1332
+ VALUE erb_render_node_spacer_template = rb_token_from_c_struct(erb_render_node->spacer_template);
1333
+ VALUE erb_render_node_formats = rb_token_from_c_struct(erb_render_node->formats);
1334
+ VALUE erb_render_node_variants = rb_token_from_c_struct(erb_render_node->variants);
1335
+ VALUE erb_render_node_handlers = rb_token_from_c_struct(erb_render_node->handlers);
1336
+ VALUE erb_render_node_content_type = rb_token_from_c_struct(erb_render_node->content_type);
1337
+ VALUE erb_render_node_locals = rb_nodes_array_from_c_array(erb_render_node->locals);
1338
+
1339
+ VALUE args[26] = {
1340
+ type,
1341
+ location,
1342
+ errors,
1343
+ erb_render_node_tag_opening,
1344
+ erb_render_node_content,
1345
+ erb_render_node_tag_closing,
1346
+ erb_render_node_analyzed_ruby,
1347
+ erb_render_node_prism_node,
1348
+ erb_render_node_partial,
1349
+ erb_render_node_template_path,
1350
+ erb_render_node_layout,
1351
+ erb_render_node_file,
1352
+ erb_render_node_inline_template,
1353
+ erb_render_node_body,
1354
+ erb_render_node_plain,
1355
+ erb_render_node_html,
1356
+ erb_render_node_renderable,
1357
+ erb_render_node_collection,
1358
+ erb_render_node_object,
1359
+ erb_render_node_as_name,
1360
+ erb_render_node_spacer_template,
1361
+ erb_render_node_formats,
1362
+ erb_render_node_variants,
1363
+ erb_render_node_handlers,
1364
+ erb_render_node_content_type,
1365
+ erb_render_node_locals
1366
+ };
1367
+
1368
+ return rb_class_new_instance(26, args, cERBRenderNode);
1369
+ };
1370
+
1263
1371
  static VALUE rb_erb_yield_node_from_c_struct(AST_ERB_YIELD_NODE_T* erb_yield_node) {
1264
1372
  if (erb_yield_node == NULL) { return Qnil; }
1265
1373
 
@@ -1355,6 +1463,8 @@ VALUE rb_node_from_c_struct(AST_NODE_T* node) {
1355
1463
  case AST_ERB_ENSURE_NODE: return rb_erb_ensure_node_from_c_struct((AST_ERB_ENSURE_NODE_T*) node); break;
1356
1464
  case AST_ERB_BEGIN_NODE: return rb_erb_begin_node_from_c_struct((AST_ERB_BEGIN_NODE_T*) node); break;
1357
1465
  case AST_ERB_UNLESS_NODE: return rb_erb_unless_node_from_c_struct((AST_ERB_UNLESS_NODE_T*) node); break;
1466
+ case AST_RUBY_RENDER_LOCAL_NODE: return rb_ruby_render_local_node_from_c_struct((AST_RUBY_RENDER_LOCAL_NODE_T*) node); break;
1467
+ case AST_ERB_RENDER_NODE: return rb_erb_render_node_from_c_struct((AST_ERB_RENDER_NODE_T*) node); break;
1358
1468
  case AST_ERB_YIELD_NODE: return rb_erb_yield_node_from_c_struct((AST_ERB_YIELD_NODE_T*) node); break;
1359
1469
  case AST_ERB_IN_NODE: return rb_erb_in_node_from_c_struct((AST_ERB_IN_NODE_T*) node); break;
1360
1470
  }