hamlit 2.10.0

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 (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +47 -0
  4. data/CHANGELOG.md +702 -0
  5. data/Gemfile +30 -0
  6. data/LICENSE.txt +44 -0
  7. data/README.md +150 -0
  8. data/REFERENCE.md +272 -0
  9. data/Rakefile +117 -0
  10. data/benchmark/boolean_attribute.haml +6 -0
  11. data/benchmark/class_attribute.haml +5 -0
  12. data/benchmark/common_attribute.haml +3 -0
  13. data/benchmark/data_attribute.haml +4 -0
  14. data/benchmark/dynamic_attributes/boolean_attribute.haml +4 -0
  15. data/benchmark/dynamic_attributes/class_attribute.haml +4 -0
  16. data/benchmark/dynamic_attributes/common_attribute.haml +2 -0
  17. data/benchmark/dynamic_attributes/data_attribute.haml +2 -0
  18. data/benchmark/dynamic_attributes/id_attribute.haml +2 -0
  19. data/benchmark/dynamic_boolean_attribute.haml +4 -0
  20. data/benchmark/dynamic_merger/benchmark.rb +25 -0
  21. data/benchmark/dynamic_merger/hello.haml +50 -0
  22. data/benchmark/dynamic_merger/hello.string +50 -0
  23. data/benchmark/etc/attribute_builder.haml +5 -0
  24. data/benchmark/etc/real_sample.haml +888 -0
  25. data/benchmark/etc/real_sample.rb +11 -0
  26. data/benchmark/etc/static_analyzer.haml +1 -0
  27. data/benchmark/etc/string_interpolation.haml +2 -0
  28. data/benchmark/etc/tags.haml +3 -0
  29. data/benchmark/etc/tags_loop.haml +2 -0
  30. data/benchmark/ext/build_data.rb +17 -0
  31. data/benchmark/ext/build_id.rb +13 -0
  32. data/benchmark/id_attribute.haml +3 -0
  33. data/benchmark/plain.haml +4 -0
  34. data/benchmark/script.haml +4 -0
  35. data/benchmark/slim/LICENSE +21 -0
  36. data/benchmark/slim/context.rb +11 -0
  37. data/benchmark/slim/run-benchmarks.rb +94 -0
  38. data/benchmark/slim/view.erb +23 -0
  39. data/benchmark/slim/view.haml +18 -0
  40. data/benchmark/slim/view.slim +17 -0
  41. data/benchmark/utils/benchmark_ips_extension.rb +43 -0
  42. data/bin/bench +77 -0
  43. data/bin/console +11 -0
  44. data/bin/ruby +3 -0
  45. data/bin/setup +7 -0
  46. data/bin/stackprof +27 -0
  47. data/bin/test +24 -0
  48. data/exe/hamlit +6 -0
  49. data/ext/hamlit/extconf.rb +10 -0
  50. data/ext/hamlit/hamlit.c +555 -0
  51. data/ext/hamlit/hescape.c +108 -0
  52. data/ext/hamlit/hescape.h +20 -0
  53. data/hamlit.gemspec +47 -0
  54. data/lib/hamlit.rb +11 -0
  55. data/lib/hamlit/attribute_builder.rb +175 -0
  56. data/lib/hamlit/attribute_compiler.rb +125 -0
  57. data/lib/hamlit/attribute_parser.rb +110 -0
  58. data/lib/hamlit/cli.rb +130 -0
  59. data/lib/hamlit/compiler.rb +97 -0
  60. data/lib/hamlit/compiler/children_compiler.rb +112 -0
  61. data/lib/hamlit/compiler/comment_compiler.rb +36 -0
  62. data/lib/hamlit/compiler/doctype_compiler.rb +46 -0
  63. data/lib/hamlit/compiler/script_compiler.rb +106 -0
  64. data/lib/hamlit/compiler/silent_script_compiler.rb +24 -0
  65. data/lib/hamlit/compiler/tag_compiler.rb +76 -0
  66. data/lib/hamlit/dynamic_merger.rb +67 -0
  67. data/lib/hamlit/engine.rb +38 -0
  68. data/lib/hamlit/error.rb +15 -0
  69. data/lib/hamlit/escapable.rb +13 -0
  70. data/lib/hamlit/filters.rb +75 -0
  71. data/lib/hamlit/filters/base.rb +12 -0
  72. data/lib/hamlit/filters/cdata.rb +20 -0
  73. data/lib/hamlit/filters/coffee.rb +17 -0
  74. data/lib/hamlit/filters/css.rb +33 -0
  75. data/lib/hamlit/filters/erb.rb +10 -0
  76. data/lib/hamlit/filters/escaped.rb +22 -0
  77. data/lib/hamlit/filters/javascript.rb +33 -0
  78. data/lib/hamlit/filters/less.rb +20 -0
  79. data/lib/hamlit/filters/markdown.rb +10 -0
  80. data/lib/hamlit/filters/plain.rb +29 -0
  81. data/lib/hamlit/filters/preserve.rb +22 -0
  82. data/lib/hamlit/filters/ruby.rb +10 -0
  83. data/lib/hamlit/filters/sass.rb +15 -0
  84. data/lib/hamlit/filters/scss.rb +15 -0
  85. data/lib/hamlit/filters/text_base.rb +25 -0
  86. data/lib/hamlit/filters/tilt_base.rb +49 -0
  87. data/lib/hamlit/force_escapable.rb +29 -0
  88. data/lib/hamlit/helpers.rb +15 -0
  89. data/lib/hamlit/html.rb +14 -0
  90. data/lib/hamlit/identity.rb +13 -0
  91. data/lib/hamlit/object_ref.rb +30 -0
  92. data/lib/hamlit/parser.rb +49 -0
  93. data/lib/hamlit/parser/MIT-LICENSE +20 -0
  94. data/lib/hamlit/parser/README.md +30 -0
  95. data/lib/hamlit/parser/haml_buffer.rb +348 -0
  96. data/lib/hamlit/parser/haml_compiler.rb +553 -0
  97. data/lib/hamlit/parser/haml_error.rb +61 -0
  98. data/lib/hamlit/parser/haml_helpers.rb +727 -0
  99. data/lib/hamlit/parser/haml_options.rb +286 -0
  100. data/lib/hamlit/parser/haml_parser.rb +800 -0
  101. data/lib/hamlit/parser/haml_util.rb +288 -0
  102. data/lib/hamlit/parser/haml_xss_mods.rb +109 -0
  103. data/lib/hamlit/rails_helpers.rb +51 -0
  104. data/lib/hamlit/rails_template.rb +59 -0
  105. data/lib/hamlit/railtie.rb +10 -0
  106. data/lib/hamlit/ruby_expression.rb +32 -0
  107. data/lib/hamlit/string_splitter.rb +19 -0
  108. data/lib/hamlit/template.rb +28 -0
  109. data/lib/hamlit/utils.rb +20 -0
  110. data/lib/hamlit/version.rb +4 -0
  111. metadata +392 -0
@@ -0,0 +1,24 @@
1
+ #!/bin/bash
2
+
3
+ VERSIONS=(
4
+ 2.1.10
5
+ 2.2.5
6
+ 2.3.1
7
+ )
8
+
9
+ set -e
10
+ trap 'echo "${VERSIONS[2]}" > .ruby-version' 0
11
+
12
+ function test_with() {
13
+ version=$1
14
+ rbenv local $version
15
+ if ! bundle check > /dev/null; then
16
+ bundle install
17
+ fi
18
+ ruby -v
19
+ bundle exec rake test
20
+ }
21
+
22
+ for version in ${VERSIONS[@]}; do
23
+ test_with $version
24
+ done
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'hamlit/cli'
5
+
6
+ Hamlit::CLI.start(ARGV)
@@ -0,0 +1,10 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS << ' -Wall -Wextra'
4
+
5
+ $srcs = %w[
6
+ hamlit.c
7
+ hescape.c
8
+ ]
9
+
10
+ create_makefile('hamlit/hamlit')
@@ -0,0 +1,555 @@
1
+ #include <ruby.h>
2
+ #include <ruby/encoding.h>
3
+ #ifndef TRUFFLERUBY
4
+ #include "hescape.h"
5
+ #include "string.h"
6
+
7
+ VALUE mAttributeBuilder, mObjectRef;
8
+ static ID id_flatten, id_keys, id_parse, id_prepend, id_tr, id_uniq_bang;
9
+ static ID id_aria, id_data, id_equal, id_hyphen, id_space, id_underscore;
10
+ static ID id_boolean_attributes, id_xhtml;
11
+
12
+ static VALUE str_aria() { return rb_const_get(mAttributeBuilder, id_aria); }
13
+ static VALUE str_data() { return rb_const_get(mAttributeBuilder, id_data); }
14
+ static VALUE str_equal() { return rb_const_get(mAttributeBuilder, id_equal); }
15
+ static VALUE str_hyphen() { return rb_const_get(mAttributeBuilder, id_hyphen); }
16
+ static VALUE str_space() { return rb_const_get(mAttributeBuilder, id_space); }
17
+ static VALUE str_underscore() { return rb_const_get(mAttributeBuilder, id_underscore); }
18
+
19
+ static void
20
+ delete_falsey_values(VALUE values)
21
+ {
22
+ VALUE value;
23
+ long i;
24
+
25
+ for (i = RARRAY_LEN(values) - 1; 0 <= i; i--) {
26
+ value = rb_ary_entry(values, i);
27
+ if (!RTEST(value)) {
28
+ rb_ary_delete_at(values, i);
29
+ }
30
+ }
31
+ }
32
+
33
+ static int
34
+ str_eq(VALUE str, const char *cstr, long n)
35
+ {
36
+ return RSTRING_LEN(str) == n && memcmp(RSTRING_PTR(str), cstr, n) == 0;
37
+ }
38
+
39
+ static VALUE
40
+ to_s(VALUE value)
41
+ {
42
+ return rb_convert_type(value, T_STRING, "String", "to_s");
43
+ }
44
+
45
+ static VALUE
46
+ hyphenate(VALUE str)
47
+ {
48
+ long i;
49
+
50
+ if (OBJ_FROZEN(str)) str = rb_str_dup(str);
51
+
52
+ for (i = 0; i < RSTRING_LEN(str); i++) {
53
+ if (RSTRING_PTR(str)[i] == '_') {
54
+ rb_str_update(str, i, 1, str_hyphen());
55
+ }
56
+ }
57
+ return str;
58
+ }
59
+
60
+ static VALUE
61
+ escape_html(VALUE str)
62
+ {
63
+ char *buf;
64
+ unsigned int size;
65
+ Check_Type(str, T_STRING);
66
+
67
+ size = hesc_escape_html(&buf, RSTRING_PTR(str), RSTRING_LEN(str));
68
+ if (size > RSTRING_LEN(str)) {
69
+ str = rb_enc_str_new(buf, size, rb_utf8_encoding());
70
+ free((void *)buf);
71
+ }
72
+
73
+ return str;
74
+ }
75
+
76
+ static VALUE
77
+ escape_attribute(VALUE escape_attrs, VALUE str)
78
+ {
79
+ if (RTEST(escape_attrs)) {
80
+ return escape_html(str);
81
+ } else {
82
+ return str;
83
+ }
84
+ }
85
+
86
+ static VALUE
87
+ rb_escape_html(RB_UNUSED_VAR(VALUE self), VALUE value)
88
+ {
89
+ return escape_html(to_s(value));
90
+ }
91
+
92
+ static VALUE
93
+ hamlit_build_id(VALUE escape_attrs, VALUE values)
94
+ {
95
+ VALUE attr_value;
96
+
97
+ values = rb_funcall(values, id_flatten, 0);
98
+ delete_falsey_values(values);
99
+
100
+ attr_value = rb_ary_join(values, str_underscore());
101
+ return escape_attribute(escape_attrs, attr_value);
102
+ }
103
+
104
+ static VALUE
105
+ hamlit_build_single_class(VALUE escape_attrs, VALUE value)
106
+ {
107
+ switch (TYPE(value)) {
108
+ case T_STRING:
109
+ break;
110
+ case T_ARRAY:
111
+ value = rb_funcall(value, id_flatten, 0);
112
+ delete_falsey_values(value);
113
+ value = rb_ary_join(value, str_space());
114
+ break;
115
+ default:
116
+ if (RTEST(value)) {
117
+ value = to_s(value);
118
+ } else {
119
+ return rb_str_new_cstr("");
120
+ }
121
+ break;
122
+ }
123
+ return escape_attribute(escape_attrs, value);
124
+ }
125
+
126
+ static VALUE
127
+ hamlit_build_multi_class(VALUE escape_attrs, VALUE values)
128
+ {
129
+ long i, j;
130
+ VALUE value, buf;
131
+
132
+ buf = rb_ary_new2(RARRAY_LEN(values));
133
+
134
+ for (i = 0; i < RARRAY_LEN(values); i++) {
135
+ value = rb_ary_entry(values, i);
136
+ switch (TYPE(value)) {
137
+ case T_STRING:
138
+ rb_ary_concat(buf, rb_str_split(value, " "));
139
+ break;
140
+ case T_ARRAY:
141
+ value = rb_funcall(value, id_flatten, 0);
142
+ delete_falsey_values(value);
143
+ for (j = 0; j < RARRAY_LEN(value); j++) {
144
+ rb_ary_push(buf, to_s(rb_ary_entry(value, j)));
145
+ }
146
+ break;
147
+ default:
148
+ if (RTEST(value)) {
149
+ rb_ary_push(buf, to_s(value));
150
+ }
151
+ break;
152
+ }
153
+ }
154
+
155
+ rb_ary_sort_bang(buf);
156
+ rb_funcall(buf, id_uniq_bang, 0);
157
+
158
+ return escape_attribute(escape_attrs, rb_ary_join(buf, str_space()));
159
+ }
160
+
161
+ static VALUE
162
+ hamlit_build_class(VALUE escape_attrs, VALUE array)
163
+ {
164
+ if (RARRAY_LEN(array) == 1) {
165
+ return hamlit_build_single_class(escape_attrs, rb_ary_entry(array, 0));
166
+ } else {
167
+ return hamlit_build_multi_class(escape_attrs, array);
168
+ }
169
+ }
170
+
171
+ struct merge_data_attrs_var {
172
+ VALUE merged;
173
+ VALUE key_str;
174
+ };
175
+
176
+ static int
177
+ merge_data_attrs_i(VALUE key, VALUE value, VALUE ptr)
178
+ {
179
+ struct merge_data_attrs_var *arg = (struct merge_data_attrs_var *)ptr;
180
+ VALUE merged = arg->merged;
181
+ VALUE key_str = arg->key_str;
182
+
183
+ if (NIL_P(key)) {
184
+ rb_hash_aset(merged, key_str, value);
185
+ } else {
186
+ key = rb_str_concat(rb_str_concat(rb_str_dup(key_str), rb_str_new_cstr("-")), to_s(key));
187
+ rb_hash_aset(merged, key, value);
188
+ }
189
+ return ST_CONTINUE;
190
+ }
191
+
192
+ static VALUE
193
+ merge_data_attrs(VALUE values, VALUE key_str)
194
+ {
195
+ long i;
196
+ VALUE value, merged = rb_hash_new();
197
+
198
+ for (i = 0; i < RARRAY_LEN(values); i++) {
199
+ struct merge_data_attrs_var arg;
200
+ arg.merged = merged;
201
+ arg.key_str = key_str;
202
+
203
+ value = rb_ary_entry(values, i);
204
+ switch (TYPE(value)) {
205
+ case T_HASH:
206
+ rb_hash_foreach(value, merge_data_attrs_i, (VALUE)&arg);
207
+ break;
208
+ default:
209
+ rb_hash_aset(merged, key_str, value);
210
+ break;
211
+ }
212
+ }
213
+ return merged;
214
+ }
215
+
216
+ struct flatten_data_attrs_i2_arg {
217
+ VALUE flattened;
218
+ VALUE key;
219
+ };
220
+
221
+ static int
222
+ flatten_data_attrs_i2(VALUE k, VALUE v, VALUE ptr)
223
+ {
224
+ VALUE key;
225
+ struct flatten_data_attrs_i2_arg *arg = (struct flatten_data_attrs_i2_arg *)ptr;
226
+
227
+ if (!RTEST(v)) return ST_CONTINUE;
228
+
229
+ if (k == Qnil) {
230
+ rb_hash_aset(arg->flattened, arg->key, v);
231
+ } else {
232
+ key = rb_str_dup(arg->key);
233
+ rb_str_cat(key, "-", 1);
234
+ rb_str_concat(key, to_s(k));
235
+
236
+ rb_hash_aset(arg->flattened, key, v);
237
+ }
238
+ return ST_CONTINUE;
239
+ }
240
+
241
+ static VALUE flatten_data_attrs(VALUE attrs);
242
+
243
+ static int
244
+ flatten_data_attrs_i(VALUE key, VALUE value, VALUE flattened)
245
+ {
246
+ struct flatten_data_attrs_i2_arg arg;
247
+ key = hyphenate(to_s(key));
248
+
249
+ switch (TYPE(value)) {
250
+ case T_HASH:
251
+ value = flatten_data_attrs(value);
252
+ arg.key = key;
253
+ arg.flattened = flattened;
254
+ rb_hash_foreach(value, flatten_data_attrs_i2, (VALUE)(&arg));
255
+ break;
256
+ default:
257
+ if (RTEST(value)) rb_hash_aset(flattened, key, value);
258
+ break;
259
+ }
260
+ return ST_CONTINUE;
261
+ }
262
+
263
+ static VALUE
264
+ flatten_data_attrs(VALUE attrs)
265
+ {
266
+ VALUE flattened = rb_hash_new();
267
+ rb_hash_foreach(attrs, flatten_data_attrs_i, flattened);
268
+
269
+ return flattened;
270
+ }
271
+
272
+ static VALUE
273
+ hamlit_build_data(VALUE escape_attrs, VALUE quote, VALUE values, VALUE key_str)
274
+ {
275
+ long i;
276
+ VALUE attrs, buf, keys, key, value;
277
+
278
+ attrs = merge_data_attrs(values, key_str);
279
+ attrs = flatten_data_attrs(attrs);
280
+ keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0));
281
+ buf = rb_str_new("", 0);
282
+
283
+ for (i = 0; i < RARRAY_LEN(keys); i++) {
284
+ key = rb_ary_entry(keys, i);
285
+ value = rb_hash_aref(attrs, key);
286
+
287
+ switch (value) {
288
+ case Qtrue:
289
+ rb_str_concat(buf, str_space());
290
+ rb_str_concat(buf, key);
291
+ break;
292
+ case Qnil:
293
+ break; // noop
294
+ case Qfalse:
295
+ break; // noop
296
+ default:
297
+ rb_str_concat(buf, str_space());
298
+ rb_str_concat(buf, key);
299
+ rb_str_concat(buf, str_equal());
300
+ rb_str_concat(buf, quote);
301
+ rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value)));
302
+ rb_str_concat(buf, quote);
303
+ break;
304
+ }
305
+ }
306
+
307
+ return buf;
308
+ }
309
+
310
+ static VALUE
311
+ parse_object_ref(VALUE object_ref)
312
+ {
313
+ return rb_funcall(mObjectRef, id_parse, 1, object_ref);
314
+ }
315
+
316
+ static int
317
+ merge_all_attrs_i(VALUE key, VALUE value, VALUE merged)
318
+ {
319
+ VALUE array;
320
+
321
+ key = to_s(key);
322
+ if (str_eq(key, "id", 2) || str_eq(key, "class", 5) || str_eq(key, "data", 4) || str_eq(key, "aria", 4)) {
323
+ array = rb_hash_aref(merged, key);
324
+ if (NIL_P(array)) {
325
+ array = rb_ary_new2(1);
326
+ rb_hash_aset(merged, key, array);
327
+ }
328
+ rb_ary_push(array, value);
329
+ } else {
330
+ rb_hash_aset(merged, key, value);
331
+ }
332
+ return ST_CONTINUE;
333
+ }
334
+
335
+ static VALUE
336
+ merge_all_attrs(VALUE hashes)
337
+ {
338
+ long i;
339
+ VALUE hash, merged = rb_hash_new();
340
+
341
+ for (i = 0; i < RARRAY_LEN(hashes); i++) {
342
+ hash = rb_ary_entry(hashes, i);
343
+ if (!RB_TYPE_P(hash, T_HASH)) {
344
+ rb_raise(rb_eArgError, "Non-hash object is given to attributes!");
345
+ }
346
+ rb_hash_foreach(hash, merge_all_attrs_i, merged);
347
+ }
348
+ return merged;
349
+ }
350
+
351
+ int
352
+ is_boolean_attribute(VALUE key)
353
+ {
354
+ VALUE boolean_attributes;
355
+ if (str_eq(rb_str_substr(key, 0, 5), "data-", 5)) return 1;
356
+ if (str_eq(rb_str_substr(key, 0, 5), "aria-", 5)) return 1;
357
+
358
+ boolean_attributes = rb_const_get(mAttributeBuilder, id_boolean_attributes);
359
+ return RTEST(rb_ary_includes(boolean_attributes, key));
360
+ }
361
+
362
+ void
363
+ hamlit_build_for_id(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
364
+ {
365
+ rb_str_cat(buf, " id=", 4);
366
+ rb_str_concat(buf, quote);
367
+ rb_str_concat(buf, hamlit_build_id(escape_attrs, values));
368
+ rb_str_concat(buf, quote);
369
+ }
370
+
371
+ void
372
+ hamlit_build_for_class(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
373
+ {
374
+ rb_str_cat(buf, " class=", 7);
375
+ rb_str_concat(buf, quote);
376
+ rb_str_concat(buf, hamlit_build_class(escape_attrs, values));
377
+ rb_str_concat(buf, quote);
378
+ }
379
+
380
+ void
381
+ hamlit_build_for_data(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
382
+ {
383
+ rb_str_concat(buf, hamlit_build_data(escape_attrs, quote, values, str_data()));
384
+ }
385
+
386
+ void
387
+ hamlit_build_for_aria(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
388
+ {
389
+ rb_str_concat(buf, hamlit_build_data(escape_attrs, quote, values, str_aria()));
390
+ }
391
+
392
+ void
393
+ hamlit_build_for_others(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE key, VALUE value)
394
+ {
395
+ rb_str_cat(buf, " ", 1);
396
+ rb_str_concat(buf, key);
397
+ rb_str_cat(buf, "=", 1);
398
+ rb_str_concat(buf, quote);
399
+ rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value)));
400
+ rb_str_concat(buf, quote);
401
+ }
402
+
403
+ void
404
+ hamlit_build_for_boolean(VALUE escape_attrs, VALUE quote, VALUE format, VALUE buf, VALUE key, VALUE value)
405
+ {
406
+ switch (value) {
407
+ case Qtrue:
408
+ rb_str_cat(buf, " ", 1);
409
+ rb_str_concat(buf, key);
410
+ if ((TYPE(format) == T_SYMBOL || TYPE(format) == T_STRING) && rb_to_id(format) == id_xhtml) {
411
+ rb_str_cat(buf, "=", 1);
412
+ rb_str_concat(buf, quote);
413
+ rb_str_concat(buf, key);
414
+ rb_str_concat(buf, quote);
415
+ }
416
+ break;
417
+ case Qfalse:
418
+ break; // noop
419
+ case Qnil:
420
+ break; // noop
421
+ default:
422
+ hamlit_build_for_others(escape_attrs, quote, buf, key, value);
423
+ break;
424
+ }
425
+ }
426
+
427
+ static VALUE
428
+ hamlit_build(VALUE escape_attrs, VALUE quote, VALUE format, VALUE object_ref, VALUE hashes)
429
+ {
430
+ long i;
431
+ VALUE attrs, buf, key, keys, value;
432
+
433
+ if (!NIL_P(object_ref)) rb_ary_push(hashes, parse_object_ref(object_ref));
434
+ attrs = merge_all_attrs(hashes);
435
+ buf = rb_str_new("", 0);
436
+ keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0));
437
+
438
+ for (i = 0; i < RARRAY_LEN(keys); i++) {
439
+ key = rb_ary_entry(keys, i);
440
+ value = rb_hash_aref(attrs, key);
441
+ if (str_eq(key, "id", 2)) {
442
+ hamlit_build_for_id(escape_attrs, quote, buf, value);
443
+ } else if (str_eq(key, "class", 5)) {
444
+ hamlit_build_for_class(escape_attrs, quote, buf, value);
445
+ } else if (str_eq(key, "data", 4)) {
446
+ hamlit_build_for_data(escape_attrs, quote, buf, value);
447
+ } else if (str_eq(key, "aria", 4)) {
448
+ hamlit_build_for_aria(escape_attrs, quote, buf, value);
449
+ } else if (is_boolean_attribute(key)) {
450
+ hamlit_build_for_boolean(escape_attrs, quote, format, buf, key, value);
451
+ } else {
452
+ hamlit_build_for_others(escape_attrs, quote, buf, key, value);
453
+ }
454
+ }
455
+
456
+ return buf;
457
+ }
458
+
459
+ static VALUE
460
+ rb_hamlit_build_id(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
461
+ {
462
+ VALUE array;
463
+
464
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
465
+ rb_scan_args(argc - 1, argv + 1, "*", &array);
466
+
467
+ return hamlit_build_id(argv[0], array);
468
+ }
469
+
470
+ static VALUE
471
+ rb_hamlit_build_class(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
472
+ {
473
+ VALUE array;
474
+
475
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
476
+ rb_scan_args(argc - 1, argv + 1, "*", &array);
477
+
478
+ return hamlit_build_class(argv[0], array);
479
+ }
480
+
481
+ static VALUE
482
+ rb_hamlit_build_aria(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
483
+ {
484
+ VALUE array;
485
+
486
+ rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
487
+ rb_scan_args(argc - 2, argv + 2, "*", &array);
488
+
489
+ return hamlit_build_data(argv[0], argv[1], array, str_aria());
490
+ }
491
+
492
+ static VALUE
493
+ rb_hamlit_build_data(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
494
+ {
495
+ VALUE array;
496
+
497
+ rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
498
+ rb_scan_args(argc - 2, argv + 2, "*", &array);
499
+
500
+ return hamlit_build_data(argv[0], argv[1], array, str_data());
501
+ }
502
+
503
+ static VALUE
504
+ rb_hamlit_build(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
505
+ {
506
+ VALUE array;
507
+
508
+ rb_check_arity(argc, 4, UNLIMITED_ARGUMENTS);
509
+ rb_scan_args(argc - 4, argv + 4, "*", &array);
510
+
511
+ return hamlit_build(argv[0], argv[1], argv[2], argv[3], array);
512
+ }
513
+
514
+ void
515
+ Init_hamlit(void)
516
+ {
517
+ VALUE mHamlit, mUtils;
518
+
519
+ mHamlit = rb_define_module("Hamlit");
520
+ mObjectRef = rb_define_module_under(mHamlit, "ObjectRef");
521
+ mUtils = rb_define_module_under(mHamlit, "Utils");
522
+ mAttributeBuilder = rb_define_module_under(mHamlit, "AttributeBuilder");
523
+
524
+ rb_define_singleton_method(mUtils, "escape_html", rb_escape_html, 1);
525
+ rb_define_singleton_method(mAttributeBuilder, "build", rb_hamlit_build, -1);
526
+ rb_define_singleton_method(mAttributeBuilder, "build_id", rb_hamlit_build_id, -1);
527
+ rb_define_singleton_method(mAttributeBuilder, "build_class", rb_hamlit_build_class, -1);
528
+ rb_define_singleton_method(mAttributeBuilder, "build_aria", rb_hamlit_build_aria, -1);
529
+ rb_define_singleton_method(mAttributeBuilder, "build_data", rb_hamlit_build_data, -1);
530
+
531
+ id_flatten = rb_intern("flatten");
532
+ id_keys = rb_intern("keys");
533
+ id_parse = rb_intern("parse");
534
+ id_prepend = rb_intern("prepend");
535
+ id_tr = rb_intern("tr");
536
+ id_uniq_bang = rb_intern("uniq!");
537
+
538
+ id_aria = rb_intern("ARIA");
539
+ id_data = rb_intern("DATA");
540
+ id_equal = rb_intern("EQUAL");
541
+ id_hyphen = rb_intern("HYPHEN");
542
+ id_space = rb_intern("SPACE");
543
+ id_underscore = rb_intern("UNDERSCORE");
544
+
545
+ id_boolean_attributes = rb_intern("BOOLEAN_ATTRIBUTES");
546
+ id_xhtml = rb_intern("xhtml");
547
+
548
+ rb_const_set(mAttributeBuilder, id_aria, rb_obj_freeze(rb_str_new_cstr("aria")));
549
+ rb_const_set(mAttributeBuilder, id_data, rb_obj_freeze(rb_str_new_cstr("data")));
550
+ rb_const_set(mAttributeBuilder, id_equal, rb_obj_freeze(rb_str_new_cstr("=")));
551
+ rb_const_set(mAttributeBuilder, id_hyphen, rb_obj_freeze(rb_str_new_cstr("-")));
552
+ rb_const_set(mAttributeBuilder, id_space, rb_obj_freeze(rb_str_new_cstr(" ")));
553
+ rb_const_set(mAttributeBuilder, id_underscore, rb_obj_freeze(rb_str_new_cstr("_")));
554
+ }
555
+ #endif