hamlit 1.7.2 → 2.0.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 (283) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -3
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +25 -37
  5. data/CHANGELOG.md +18 -0
  6. data/Gemfile +16 -0
  7. data/LICENSE.txt +23 -2
  8. data/README.md +106 -48
  9. data/REFERENCE.md +222 -0
  10. data/Rakefile +77 -19
  11. data/benchmark/boolean_attribute.haml +6 -0
  12. data/benchmark/class_attribute.haml +5 -0
  13. data/benchmark/common_attribute.haml +3 -0
  14. data/benchmark/data_attribute.haml +4 -0
  15. data/benchmark/dynamic_attributes/boolean_attribute.haml +4 -0
  16. data/benchmark/dynamic_attributes/class_attribute.haml +4 -0
  17. data/benchmark/dynamic_attributes/common_attribute.haml +2 -0
  18. data/benchmark/dynamic_attributes/data_attribute.haml +2 -0
  19. data/benchmark/dynamic_attributes/id_attribute.haml +2 -0
  20. data/benchmark/etc/attribute_builder.haml +5 -0
  21. data/benchmark/etc/real_sample.haml +888 -0
  22. data/benchmark/etc/real_sample.rb +11 -0
  23. data/benchmark/etc/static_analyzer.haml +1 -0
  24. data/benchmark/etc/tags.haml +3 -0
  25. data/benchmark/ext/build_data.rb +15 -0
  26. data/benchmark/ext/build_id.rb +13 -0
  27. data/benchmark/id_attribute.haml +3 -0
  28. data/benchmark/plain.haml +4 -0
  29. data/benchmark/script.haml +4 -0
  30. data/benchmark/slim/LICENSE +21 -0
  31. data/{benchmarks → benchmark/slim}/context.rb +2 -4
  32. data/benchmark/slim/run-benchmarks.rb +94 -0
  33. data/{benchmarks → benchmark/slim}/view.erb +3 -3
  34. data/{benchmarks → benchmark/slim}/view.haml +0 -0
  35. data/{benchmarks/view.escaped.slim → benchmark/slim/view.slim} +1 -1
  36. data/benchmark/string_interpolation.haml +2 -0
  37. data/benchmark/utils/benchmark_ips_extension.rb +43 -0
  38. data/bin/bench +85 -0
  39. data/bin/clone +14 -0
  40. data/bin/console +11 -0
  41. data/bin/lineprof +48 -0
  42. data/bin/ruby +3 -0
  43. data/bin/setup +7 -0
  44. data/bin/stackprof +27 -0
  45. data/{test → bin/test} +6 -10
  46. data/{bin → exe}/hamlit +0 -0
  47. data/ext/hamlit/extconf.rb +14 -0
  48. data/ext/hamlit/hamlit.c +512 -0
  49. data/ext/hamlit/houdini/.gitignore +3 -0
  50. data/ext/hamlit/houdini/COPYING +7 -0
  51. data/ext/hamlit/houdini/Makefile +79 -0
  52. data/ext/hamlit/houdini/README.md +59 -0
  53. data/ext/hamlit/houdini/buffer.c +249 -0
  54. data/ext/hamlit/houdini/buffer.h +113 -0
  55. data/ext/hamlit/houdini/houdini.h +46 -0
  56. data/ext/hamlit/houdini/houdini_href_e.c +115 -0
  57. data/ext/hamlit/houdini/houdini_html_e.c +90 -0
  58. data/ext/hamlit/houdini/houdini_html_u.c +122 -0
  59. data/ext/hamlit/houdini/houdini_js_e.c +90 -0
  60. data/ext/hamlit/houdini/houdini_js_u.c +60 -0
  61. data/ext/hamlit/houdini/houdini_uri_e.c +107 -0
  62. data/ext/hamlit/houdini/houdini_uri_u.c +68 -0
  63. data/ext/hamlit/houdini/houdini_xml_e.c +136 -0
  64. data/ext/hamlit/houdini/html_unescape.gperf +258 -0
  65. data/ext/hamlit/houdini/html_unescape.h +754 -0
  66. data/ext/hamlit/houdini/tools/build_table.py +13 -0
  67. data/ext/hamlit/houdini/tools/build_tables.c +51 -0
  68. data/ext/hamlit/houdini/tools/wikipedia_table.txt +2025 -0
  69. data/hamlit.gemspec +30 -31
  70. data/lib/hamlit.rb +3 -1
  71. data/lib/hamlit/attribute_builder.rb +12 -0
  72. data/lib/hamlit/cli.rb +44 -43
  73. data/lib/hamlit/compiler.rb +92 -16
  74. data/lib/hamlit/compiler/attribute_compiler.rb +148 -0
  75. data/lib/hamlit/compiler/children_compiler.rb +111 -0
  76. data/lib/hamlit/compiler/comment_compiler.rb +36 -0
  77. data/lib/hamlit/compiler/doctype_compiler.rb +45 -0
  78. data/lib/hamlit/compiler/script_compiler.rb +97 -0
  79. data/lib/hamlit/compiler/silent_script_compiler.rb +24 -0
  80. data/lib/hamlit/compiler/tag_compiler.rb +69 -0
  81. data/lib/hamlit/engine.rb +12 -7
  82. data/lib/hamlit/error.rb +14 -0
  83. data/lib/hamlit/escapable.rb +12 -0
  84. data/lib/hamlit/filters.rb +65 -0
  85. data/lib/hamlit/filters/base.rb +4 -62
  86. data/lib/hamlit/filters/coffee.rb +9 -7
  87. data/lib/hamlit/filters/css.rb +25 -8
  88. data/lib/hamlit/filters/erb.rb +4 -6
  89. data/lib/hamlit/filters/escaped.rb +11 -9
  90. data/lib/hamlit/filters/javascript.rb +25 -8
  91. data/lib/hamlit/filters/less.rb +9 -7
  92. data/lib/hamlit/filters/markdown.rb +5 -6
  93. data/lib/hamlit/filters/plain.rb +11 -15
  94. data/lib/hamlit/filters/preserve.rb +15 -5
  95. data/lib/hamlit/filters/ruby.rb +3 -5
  96. data/lib/hamlit/filters/sass.rb +9 -7
  97. data/lib/hamlit/filters/scss.rb +9 -7
  98. data/lib/hamlit/filters/text_base.rb +24 -0
  99. data/lib/hamlit/filters/tilt_base.rb +47 -0
  100. data/lib/hamlit/hash_parser.rb +107 -0
  101. data/lib/hamlit/html.rb +9 -6
  102. data/lib/hamlit/identity.rb +12 -0
  103. data/lib/hamlit/object_ref.rb +29 -0
  104. data/lib/hamlit/parser.rb +25 -142
  105. data/lib/hamlit/parser/MIT-LICENSE +20 -0
  106. data/lib/hamlit/parser/README.md +28 -0
  107. data/lib/hamlit/parser/haml_buffer.rb +348 -0
  108. data/lib/hamlit/parser/haml_compiler.rb +553 -0
  109. data/lib/hamlit/parser/haml_error.rb +61 -0
  110. data/lib/hamlit/parser/haml_helpers.rb +727 -0
  111. data/lib/hamlit/parser/haml_options.rb +286 -0
  112. data/lib/hamlit/parser/haml_parser.rb +801 -0
  113. data/lib/hamlit/parser/haml_util.rb +283 -0
  114. data/lib/hamlit/parser/haml_xss_mods.rb +109 -0
  115. data/lib/hamlit/{helpers.rb → rails_helpers.rb} +2 -7
  116. data/lib/hamlit/rails_template.rb +30 -0
  117. data/lib/hamlit/railtie.rb +1 -12
  118. data/lib/hamlit/ruby_expression.rb +31 -0
  119. data/lib/hamlit/static_analyzer.rb +49 -0
  120. data/lib/hamlit/string_interpolation.rb +69 -0
  121. data/lib/hamlit/template.rb +8 -0
  122. data/lib/hamlit/utils.rb +9 -0
  123. data/lib/hamlit/version.rb +1 -1
  124. metadata +116 -324
  125. data/.rspec +0 -2
  126. data/benchmarks/benchmark.rb +0 -110
  127. data/benchmarks/view.slim +0 -17
  128. data/doc/README.md +0 -19
  129. data/doc/engine/indent.md +0 -48
  130. data/doc/engine/new_attribute.md +0 -77
  131. data/doc/engine/old_attributes.md +0 -198
  132. data/doc/engine/silent_script.md +0 -97
  133. data/doc/engine/tag.md +0 -48
  134. data/doc/engine/text.md +0 -64
  135. data/doc/faml/README.md +0 -16
  136. data/doc/faml/engine/indent.md +0 -48
  137. data/doc/faml/engine/old_attributes.md +0 -111
  138. data/doc/faml/engine/silent_script.md +0 -97
  139. data/doc/faml/engine/text.md +0 -59
  140. data/doc/faml/filters/erb.md +0 -24
  141. data/doc/faml/filters/javascript.md +0 -27
  142. data/doc/faml/filters/less.md +0 -57
  143. data/doc/faml/filters/plain.md +0 -25
  144. data/doc/filters/erb.md +0 -31
  145. data/doc/filters/javascript.md +0 -83
  146. data/doc/filters/less.md +0 -57
  147. data/doc/filters/markdown.md +0 -31
  148. data/doc/filters/plain.md +0 -25
  149. data/doc/haml/README.md +0 -15
  150. data/doc/haml/engine/new_attribute.md +0 -77
  151. data/doc/haml/engine/old_attributes.md +0 -142
  152. data/doc/haml/engine/tag.md +0 -48
  153. data/doc/haml/engine/text.md +0 -29
  154. data/doc/haml/filters/erb.md +0 -26
  155. data/doc/haml/filters/javascript.md +0 -76
  156. data/doc/haml/filters/markdown.md +0 -31
  157. data/lib/hamlit/attribute.rb +0 -78
  158. data/lib/hamlit/compilers/attributes.rb +0 -108
  159. data/lib/hamlit/compilers/comment.rb +0 -13
  160. data/lib/hamlit/compilers/doctype.rb +0 -39
  161. data/lib/hamlit/compilers/filter.rb +0 -53
  162. data/lib/hamlit/compilers/new_attribute.rb +0 -115
  163. data/lib/hamlit/compilers/old_attribute.rb +0 -241
  164. data/lib/hamlit/compilers/runtime_attribute.rb +0 -58
  165. data/lib/hamlit/compilers/script.rb +0 -31
  166. data/lib/hamlit/compilers/strip.rb +0 -19
  167. data/lib/hamlit/compilers/text.rb +0 -111
  168. data/lib/hamlit/concerns/attribute_builder.rb +0 -22
  169. data/lib/hamlit/concerns/balanceable.rb +0 -68
  170. data/lib/hamlit/concerns/deprecation.rb +0 -20
  171. data/lib/hamlit/concerns/error.rb +0 -31
  172. data/lib/hamlit/concerns/escapable.rb +0 -17
  173. data/lib/hamlit/concerns/included.rb +0 -28
  174. data/lib/hamlit/concerns/indentable.rb +0 -117
  175. data/lib/hamlit/concerns/lexable.rb +0 -32
  176. data/lib/hamlit/concerns/line_reader.rb +0 -62
  177. data/lib/hamlit/concerns/registerable.rb +0 -24
  178. data/lib/hamlit/concerns/string_interpolation.rb +0 -48
  179. data/lib/hamlit/concerns/whitespace.rb +0 -91
  180. data/lib/hamlit/filters/tilt.rb +0 -41
  181. data/lib/hamlit/parsers/attribute.rb +0 -71
  182. data/lib/hamlit/parsers/comment.rb +0 -30
  183. data/lib/hamlit/parsers/doctype.rb +0 -18
  184. data/lib/hamlit/parsers/filter.rb +0 -18
  185. data/lib/hamlit/parsers/multiline.rb +0 -58
  186. data/lib/hamlit/parsers/script.rb +0 -126
  187. data/lib/hamlit/parsers/tag.rb +0 -83
  188. data/lib/hamlit/parsers/text.rb +0 -28
  189. data/lib/hamlit/temple.rb +0 -9
  190. data/release +0 -6
  191. data/spec/Rakefile +0 -72
  192. data/spec/hamlit/engine/comment_spec.rb +0 -56
  193. data/spec/hamlit/engine/doctype_spec.rb +0 -19
  194. data/spec/hamlit/engine/error_spec.rb +0 -135
  195. data/spec/hamlit/engine/indent_spec.rb +0 -42
  196. data/spec/hamlit/engine/multiline_spec.rb +0 -44
  197. data/spec/hamlit/engine/new_attribute_spec.rb +0 -110
  198. data/spec/hamlit/engine/old_attributes_spec.rb +0 -404
  199. data/spec/hamlit/engine/script_spec.rb +0 -116
  200. data/spec/hamlit/engine/silent_script_spec.rb +0 -213
  201. data/spec/hamlit/engine/tag_spec.rb +0 -295
  202. data/spec/hamlit/engine/text_spec.rb +0 -239
  203. data/spec/hamlit/engine_spec.rb +0 -58
  204. data/spec/hamlit/filters/coffee_spec.rb +0 -60
  205. data/spec/hamlit/filters/css_spec.rb +0 -33
  206. data/spec/hamlit/filters/erb_spec.rb +0 -16
  207. data/spec/hamlit/filters/javascript_spec.rb +0 -82
  208. data/spec/hamlit/filters/less_spec.rb +0 -37
  209. data/spec/hamlit/filters/markdown_spec.rb +0 -30
  210. data/spec/hamlit/filters/plain_spec.rb +0 -15
  211. data/spec/hamlit/filters/ruby_spec.rb +0 -24
  212. data/spec/hamlit/filters/sass_spec.rb +0 -33
  213. data/spec/hamlit/filters/scss_spec.rb +0 -37
  214. data/spec/hamlit/haml_spec.rb +0 -910
  215. data/spec/rails/.gitignore +0 -18
  216. data/spec/rails/.rspec +0 -2
  217. data/spec/rails/Gemfile +0 -19
  218. data/spec/rails/README.rdoc +0 -28
  219. data/spec/rails/Rakefile +0 -6
  220. data/spec/rails/app/assets/images/.keep +0 -0
  221. data/spec/rails/app/assets/javascripts/application.js +0 -15
  222. data/spec/rails/app/assets/stylesheets/application.css +0 -15
  223. data/spec/rails/app/controllers/application_controller.rb +0 -8
  224. data/spec/rails/app/controllers/concerns/.keep +0 -0
  225. data/spec/rails/app/controllers/users_controller.rb +0 -23
  226. data/spec/rails/app/helpers/application_helper.rb +0 -2
  227. data/spec/rails/app/mailers/.keep +0 -0
  228. data/spec/rails/app/models/.keep +0 -0
  229. data/spec/rails/app/models/concerns/.keep +0 -0
  230. data/spec/rails/app/views/application/index.html.haml +0 -18
  231. data/spec/rails/app/views/layouts/application.html.haml +0 -12
  232. data/spec/rails/app/views/users/capture.html.haml +0 -5
  233. data/spec/rails/app/views/users/capture_haml.html.haml +0 -5
  234. data/spec/rails/app/views/users/form.html.haml +0 -2
  235. data/spec/rails/app/views/users/helpers.html.haml +0 -10
  236. data/spec/rails/app/views/users/index.html.haml +0 -9
  237. data/spec/rails/app/views/users/inline.html.haml +0 -6
  238. data/spec/rails/app/views/users/old_attributes.html.haml +0 -5
  239. data/spec/rails/app/views/users/safe_buffer.html.haml +0 -4
  240. data/spec/rails/app/views/users/whitespace.html.haml +0 -4
  241. data/spec/rails/bin/bundle +0 -3
  242. data/spec/rails/bin/rails +0 -8
  243. data/spec/rails/bin/rake +0 -8
  244. data/spec/rails/bin/setup +0 -29
  245. data/spec/rails/bin/spring +0 -15
  246. data/spec/rails/config.ru +0 -4
  247. data/spec/rails/config/application.rb +0 -34
  248. data/spec/rails/config/boot.rb +0 -3
  249. data/spec/rails/config/database.yml +0 -25
  250. data/spec/rails/config/environment.rb +0 -5
  251. data/spec/rails/config/environments/development.rb +0 -41
  252. data/spec/rails/config/environments/production.rb +0 -79
  253. data/spec/rails/config/environments/test.rb +0 -42
  254. data/spec/rails/config/initializers/assets.rb +0 -11
  255. data/spec/rails/config/initializers/backtrace_silencers.rb +0 -7
  256. data/spec/rails/config/initializers/cookies_serializer.rb +0 -3
  257. data/spec/rails/config/initializers/filter_parameter_logging.rb +0 -4
  258. data/spec/rails/config/initializers/inflections.rb +0 -16
  259. data/spec/rails/config/initializers/mime_types.rb +0 -4
  260. data/spec/rails/config/initializers/session_store.rb +0 -3
  261. data/spec/rails/config/initializers/wrap_parameters.rb +0 -14
  262. data/spec/rails/config/locales/en.yml +0 -24
  263. data/spec/rails/config/routes.rb +0 -16
  264. data/spec/rails/config/secrets.yml +0 -22
  265. data/spec/rails/db/schema.rb +0 -16
  266. data/spec/rails/db/seeds.rb +0 -7
  267. data/spec/rails/lib/assets/.keep +0 -0
  268. data/spec/rails/lib/tasks/.keep +0 -0
  269. data/spec/rails/log/.keep +0 -0
  270. data/spec/rails/public/404.html +0 -67
  271. data/spec/rails/public/422.html +0 -67
  272. data/spec/rails/public/500.html +0 -66
  273. data/spec/rails/public/favicon.ico +0 -0
  274. data/spec/rails/public/robots.txt +0 -5
  275. data/spec/rails/spec/hamlit_spec.rb +0 -123
  276. data/spec/rails/spec/rails_helper.rb +0 -56
  277. data/spec/rails/spec/spec_helper.rb +0 -91
  278. data/spec/rails/vendor/assets/javascripts/.keep +0 -0
  279. data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
  280. data/spec/spec_helper.rb +0 -36
  281. data/spec/spec_helper/document_generator.rb +0 -93
  282. data/spec/spec_helper/render_helper.rb +0 -120
  283. data/spec/spec_helper/test_case.rb +0 -55
data/bin/ruby ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ bundle exec ruby -Ilib:test -rtest_helper $@
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/bin/stackprof ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'hamlit'
5
+ require 'stackprof'
6
+
7
+ def open_flamegraph(report)
8
+ temp = `mktemp /tmp/stackflame-XXXXXXXX`.strip
9
+ data_path = "#{temp}.js"
10
+ system("mv #{temp} #{data_path}")
11
+
12
+ File.open(data_path, 'w') do |f|
13
+ report.print_flamegraph(f)
14
+ end
15
+
16
+ viewer_path = File.join(`bundle show stackprof`.strip, 'lib/stackprof/flamegraph/viewer.html')
17
+ url = "file://#{viewer_path}?data=#{data_path}"
18
+ system(%Q[osascript -e 'open location "#{url}"'])
19
+ end
20
+
21
+ haml = File.read(ARGV.first)
22
+ StackProf.start(mode: :wall, interval: 1, raw: false)
23
+ Hamlit::Engine.new.call(haml)
24
+ StackProf.stop
25
+
26
+ report = StackProf::Report.new(StackProf.results)
27
+ report.print_text(false)
data/{test → bin/test} RENAMED
@@ -1,14 +1,14 @@
1
1
  #!/bin/bash
2
2
 
3
- set -e
4
- trap 'rm .ruby-version' 0
5
-
6
3
  VERSIONS=(
7
4
  2.0.0
8
- 2.1.6
9
- 2.2.2
5
+ 2.1.7
6
+ 2.2.3
10
7
  )
11
8
 
9
+ set -e
10
+ trap 'echo "${VERSIONS[2]}" > .ruby-version' 0
11
+
12
12
  function test_with() {
13
13
  version=$1
14
14
  rbenv local $version
@@ -16,13 +16,9 @@ function test_with() {
16
16
  bundle install
17
17
  fi
18
18
  ruby -v
19
- rake spec
19
+ rake test
20
20
  }
21
21
 
22
22
  for version in ${VERSIONS[@]}; do
23
23
  test_with $version
24
24
  done
25
-
26
- rbenv local ${VERSIONS[2]}
27
- ruby -v
28
- rake rails:spec
data/{bin → exe}/hamlit RENAMED
File without changes
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ houdini_dir = File.expand_path('./houdini', __dir__)
4
+ $INCFLAGS << " -I#{houdini_dir}"
5
+ $CFLAGS << ' -Wall -Wextra'
6
+
7
+ $srcs = %w[hamlit.c]
8
+ Dir[File.join(houdini_dir, '*.c')].each do |path|
9
+ src = File.basename(path)
10
+ FileUtils.ln_s(path, src, force: true)
11
+ $srcs << src
12
+ end
13
+
14
+ create_makefile('hamlit/hamlit')
@@ -0,0 +1,512 @@
1
+ #include <ruby.h>
2
+ #include <ruby/encoding.h>
3
+ #include "houdini.h"
4
+ #include "string.h"
5
+
6
+ VALUE mAttributeBuilder, mObjectRef;
7
+ static ID id_flatten, id_keys, id_parse, id_prepend, id_tr, id_uniq_bang;
8
+ static ID id_data, id_equal, id_hyphen, id_space, id_underscore;
9
+ static ID id_boolean_attributes, id_xhtml;
10
+
11
+ static VALUE str_data() { return rb_const_get(mAttributeBuilder, id_data); }
12
+ static VALUE str_equal() { return rb_const_get(mAttributeBuilder, id_equal); }
13
+ static VALUE str_hyphen() { return rb_const_get(mAttributeBuilder, id_hyphen); }
14
+ static VALUE str_space() { return rb_const_get(mAttributeBuilder, id_space); }
15
+ static VALUE str_underscore() { return rb_const_get(mAttributeBuilder, id_underscore); }
16
+
17
+ static void
18
+ delete_falsey_values(VALUE values)
19
+ {
20
+ VALUE value;
21
+ long i;
22
+
23
+ for (i = RARRAY_LEN(values) - 1; 0 <= i; i--) {
24
+ value = rb_ary_entry(values, i);
25
+ if (!RTEST(value)) {
26
+ rb_ary_delete_at(values, i);
27
+ }
28
+ }
29
+ }
30
+
31
+ static int
32
+ str_eq(VALUE str, const char *cstr)
33
+ {
34
+ return strcmp(RSTRING_PTR(str), cstr) == 0;
35
+ }
36
+
37
+ static VALUE
38
+ to_s(VALUE value)
39
+ {
40
+ return rb_convert_type(value, T_STRING, "String", "to_s");
41
+ }
42
+
43
+ static VALUE
44
+ hyphenate(VALUE str)
45
+ {
46
+ long i;
47
+
48
+ if (OBJ_FROZEN(str)) str = rb_str_dup(str);
49
+
50
+ for (i = 0; i < RSTRING_LEN(str); i++) {
51
+ if (RSTRING_PTR(str)[i] == '_') {
52
+ rb_str_update(str, i, 1, str_hyphen());
53
+ }
54
+ }
55
+ return str;
56
+ }
57
+
58
+ static VALUE
59
+ escape_html(VALUE str)
60
+ {
61
+ gh_buf buf = GH_BUF_INIT;
62
+
63
+ Check_Type(str, T_STRING);
64
+
65
+ if (houdini_escape_html0(&buf, (const uint8_t *)RSTRING_PTR(str), RSTRING_LEN(str), 0)) {
66
+ str = rb_enc_str_new(buf.ptr, buf.size, rb_utf8_encoding());
67
+ gh_buf_free(&buf);
68
+ }
69
+
70
+ return str;
71
+ }
72
+
73
+ static VALUE
74
+ escape_attribute(VALUE escape_attrs, VALUE str)
75
+ {
76
+ if (RTEST(escape_attrs)) {
77
+ return escape_html(str);
78
+ } else {
79
+ return str;
80
+ }
81
+ }
82
+
83
+ static VALUE
84
+ rb_escape_html(RB_UNUSED_VAR(VALUE self), VALUE value)
85
+ {
86
+ return escape_html(to_s(value));
87
+ }
88
+
89
+ static VALUE
90
+ hamlit_build_id(VALUE escape_attrs, VALUE values)
91
+ {
92
+ VALUE attr_value;
93
+
94
+ values = rb_funcall(values, id_flatten, 0);
95
+ delete_falsey_values(values);
96
+
97
+ attr_value = rb_ary_join(values, str_underscore());
98
+ return escape_attribute(escape_attrs, attr_value);
99
+ }
100
+
101
+ static VALUE
102
+ hamlit_build_single_class(VALUE escape_attrs, VALUE value)
103
+ {
104
+ switch (TYPE(value)) {
105
+ case T_STRING:
106
+ break;
107
+ case T_ARRAY:
108
+ value = rb_funcall(value, id_flatten, 0);
109
+ delete_falsey_values(value);
110
+ value = rb_ary_join(value, str_space());
111
+ break;
112
+ default:
113
+ if (RTEST(value)) {
114
+ value = to_s(value);
115
+ } else {
116
+ return rb_str_new_cstr("");
117
+ }
118
+ break;
119
+ }
120
+ return escape_attribute(escape_attrs, value);
121
+ }
122
+
123
+ static VALUE
124
+ hamlit_build_multi_class(VALUE escape_attrs, VALUE values)
125
+ {
126
+ long i, j;
127
+ VALUE value, buf;
128
+
129
+ buf = rb_ary_new2(RARRAY_LEN(values));
130
+
131
+ for (i = 0; i < RARRAY_LEN(values); i++) {
132
+ value = rb_ary_entry(values, i);
133
+ switch (TYPE(value)) {
134
+ case T_STRING:
135
+ rb_ary_concat(buf, rb_str_split(value, " "));
136
+ break;
137
+ case T_ARRAY:
138
+ value = rb_funcall(value, id_flatten, 0);
139
+ delete_falsey_values(value);
140
+ for (j = 0; j < RARRAY_LEN(value); j++) {
141
+ rb_ary_push(buf, to_s(rb_ary_entry(value, j)));
142
+ }
143
+ break;
144
+ default:
145
+ if (RTEST(value)) {
146
+ rb_ary_push(buf, to_s(value));
147
+ }
148
+ break;
149
+ }
150
+ }
151
+
152
+ rb_ary_sort_bang(buf);
153
+ rb_funcall(buf, id_uniq_bang, 0);
154
+
155
+ return escape_attribute(escape_attrs, rb_ary_join(buf, str_space()));
156
+ }
157
+
158
+ static VALUE
159
+ hamlit_build_class(VALUE escape_attrs, VALUE array)
160
+ {
161
+ if (RARRAY_LEN(array) == 1) {
162
+ return hamlit_build_single_class(escape_attrs, rb_ary_entry(array, 0));
163
+ } else {
164
+ return hamlit_build_multi_class(escape_attrs, array);
165
+ }
166
+ }
167
+
168
+ static int
169
+ merge_data_attrs_i(VALUE key, VALUE value, VALUE merged)
170
+ {
171
+ if (NIL_P(key)) {
172
+ rb_hash_aset(merged, str_data(), value);
173
+ } else {
174
+ key = rb_str_concat(rb_str_new_cstr("data-"), to_s(key));
175
+ rb_hash_aset(merged, key, value);
176
+ }
177
+ return ST_CONTINUE;
178
+ }
179
+
180
+ static VALUE
181
+ merge_data_attrs(VALUE values)
182
+ {
183
+ long i;
184
+ VALUE value, merged = rb_hash_new();
185
+
186
+ for (i = 0; i < RARRAY_LEN(values); i++) {
187
+ value = rb_ary_entry(values, i);
188
+ switch (TYPE(value)) {
189
+ case T_HASH:
190
+ rb_hash_foreach(value, merge_data_attrs_i, merged);
191
+ break;
192
+ default:
193
+ rb_hash_aset(merged, str_data(), value);
194
+ break;
195
+ }
196
+ }
197
+ return merged;
198
+ }
199
+
200
+ struct flatten_data_attrs_i2_arg {
201
+ VALUE flattened;
202
+ VALUE key;
203
+ };
204
+
205
+ static int
206
+ flatten_data_attrs_i2(VALUE k, VALUE v, VALUE ptr)
207
+ {
208
+ VALUE key;
209
+ struct flatten_data_attrs_i2_arg *arg = (struct flatten_data_attrs_i2_arg *)ptr;
210
+
211
+ if (!RTEST(v)) return ST_CONTINUE;
212
+
213
+ if (k == Qnil) {
214
+ rb_hash_aset(arg->flattened, arg->key, v);
215
+ } else {
216
+ key = rb_str_dup(arg->key);
217
+ rb_str_cat(key, "-", 1);
218
+ rb_str_concat(key, to_s(k));
219
+
220
+ rb_hash_aset(arg->flattened, key, v);
221
+ }
222
+ return ST_CONTINUE;
223
+ }
224
+
225
+ static VALUE flatten_data_attrs(VALUE attrs);
226
+
227
+ static int
228
+ flatten_data_attrs_i(VALUE key, VALUE value, VALUE flattened)
229
+ {
230
+ struct flatten_data_attrs_i2_arg arg;
231
+ key = hyphenate(to_s(key));
232
+
233
+ switch (TYPE(value)) {
234
+ case T_HASH:
235
+ value = flatten_data_attrs(value);
236
+ arg.key = key;
237
+ arg.flattened = flattened;
238
+ rb_hash_foreach(value, flatten_data_attrs_i2, (VALUE)(&arg));
239
+ break;
240
+ default:
241
+ if (RTEST(value)) rb_hash_aset(flattened, key, value);
242
+ break;
243
+ }
244
+ return ST_CONTINUE;
245
+ }
246
+
247
+ static VALUE
248
+ flatten_data_attrs(VALUE attrs)
249
+ {
250
+ VALUE flattened = rb_hash_new();
251
+ rb_hash_foreach(attrs, flatten_data_attrs_i, flattened);
252
+
253
+ return flattened;
254
+ }
255
+
256
+ static VALUE
257
+ hamlit_build_data(VALUE escape_attrs, VALUE quote, VALUE values)
258
+ {
259
+ long i;
260
+ VALUE attrs, buf, keys, key, value;
261
+
262
+ attrs = merge_data_attrs(values);
263
+ attrs = flatten_data_attrs(attrs);
264
+ keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0));
265
+ buf = rb_str_new("", 0);
266
+
267
+ for (i = 0; i < RARRAY_LEN(keys); i++) {
268
+ key = rb_ary_entry(keys, i);
269
+ value = rb_hash_aref(attrs, key);
270
+
271
+ switch (value) {
272
+ case Qtrue:
273
+ rb_str_concat(buf, str_space());
274
+ rb_str_concat(buf, key);
275
+ break;
276
+ case Qnil:
277
+ break; // noop
278
+ case Qfalse:
279
+ break; // noop
280
+ default:
281
+ rb_str_concat(buf, str_space());
282
+ rb_str_concat(buf, key);
283
+ rb_str_concat(buf, str_equal());
284
+ rb_str_concat(buf, quote);
285
+ rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value)));
286
+ rb_str_concat(buf, quote);
287
+ break;
288
+ }
289
+ }
290
+
291
+ return buf;
292
+ }
293
+
294
+ static VALUE
295
+ parse_object_ref(VALUE object_ref)
296
+ {
297
+ return rb_funcall(mObjectRef, id_parse, 1, object_ref);
298
+ }
299
+
300
+ static int
301
+ merge_all_attrs_i(VALUE key, VALUE value, VALUE merged)
302
+ {
303
+ VALUE array;
304
+
305
+ key = to_s(key);
306
+ if (str_eq(key, "id") || str_eq(key, "class") || str_eq(key, "data")) {
307
+ array = rb_hash_aref(merged, key);
308
+ if (NIL_P(array)) {
309
+ array = rb_ary_new2(1);
310
+ rb_hash_aset(merged, key, array);
311
+ }
312
+ rb_ary_push(array, value);
313
+ } else {
314
+ rb_hash_aset(merged, key, value);
315
+ }
316
+ return ST_CONTINUE;
317
+ }
318
+
319
+ static VALUE
320
+ merge_all_attrs(VALUE hashes)
321
+ {
322
+ long i;
323
+ VALUE hash, merged = rb_hash_new();
324
+
325
+ for (i = 0; i < RARRAY_LEN(hashes); i++) {
326
+ hash = rb_ary_entry(hashes, i);
327
+ rb_hash_foreach(hash, merge_all_attrs_i, merged);
328
+ }
329
+ return merged;
330
+ }
331
+
332
+ int
333
+ is_boolean_attribute(VALUE key)
334
+ {
335
+ VALUE boolean_attributes;
336
+ if (str_eq(rb_str_substr(key, 0, 5), "data-")) return 1;
337
+
338
+ boolean_attributes = rb_const_get(mAttributeBuilder, id_boolean_attributes);
339
+ return RTEST(rb_ary_includes(boolean_attributes, key));
340
+ }
341
+
342
+ void
343
+ hamlit_build_for_id(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
344
+ {
345
+ rb_str_cat(buf, " id=", 4);
346
+ rb_str_concat(buf, quote);
347
+ rb_str_concat(buf, hamlit_build_id(escape_attrs, values));
348
+ rb_str_concat(buf, quote);
349
+ }
350
+
351
+ void
352
+ hamlit_build_for_class(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
353
+ {
354
+ rb_str_cat(buf, " class=", 7);
355
+ rb_str_concat(buf, quote);
356
+ rb_str_concat(buf, hamlit_build_class(escape_attrs, values));
357
+ rb_str_concat(buf, quote);
358
+ }
359
+
360
+ void
361
+ hamlit_build_for_data(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
362
+ {
363
+ rb_str_concat(buf, hamlit_build_data(escape_attrs, quote, values));
364
+ }
365
+
366
+ void
367
+ hamlit_build_for_others(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE key, VALUE value)
368
+ {
369
+ rb_str_cat(buf, " ", 1);
370
+ rb_str_concat(buf, key);
371
+ rb_str_cat(buf, "=", 1);
372
+ rb_str_concat(buf, quote);
373
+ rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value)));
374
+ rb_str_concat(buf, quote);
375
+ }
376
+
377
+ void
378
+ hamlit_build_for_boolean(VALUE escape_attrs, VALUE quote, VALUE format, VALUE buf, VALUE key, VALUE value)
379
+ {
380
+ switch (value) {
381
+ case Qtrue:
382
+ rb_str_cat(buf, " ", 1);
383
+ rb_str_concat(buf, key);
384
+ if ((TYPE(format) == T_SYMBOL || TYPE(format) == T_STRING) && rb_to_id(format) == id_xhtml) {
385
+ rb_str_cat(buf, "=", 1);
386
+ rb_str_concat(buf, quote);
387
+ rb_str_concat(buf, key);
388
+ rb_str_concat(buf, quote);
389
+ }
390
+ break;
391
+ case Qfalse:
392
+ break; // noop
393
+ case Qnil:
394
+ break; // noop
395
+ default:
396
+ hamlit_build_for_others(escape_attrs, quote, buf, key, value);
397
+ break;
398
+ }
399
+ }
400
+
401
+ static VALUE
402
+ hamlit_build(VALUE escape_attrs, VALUE quote, VALUE format, VALUE object_ref, VALUE hashes)
403
+ {
404
+ long i;
405
+ VALUE attrs, buf, key, keys, value;
406
+
407
+ if (!NIL_P(object_ref)) rb_ary_push(hashes, parse_object_ref(object_ref));
408
+ attrs = merge_all_attrs(hashes);
409
+ buf = rb_str_new("", 0);
410
+ keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0));
411
+
412
+ for (i = 0; i < RARRAY_LEN(keys); i++) {
413
+ key = rb_ary_entry(keys, i);
414
+ value = rb_hash_aref(attrs, key);
415
+ if (str_eq(key, "id")) {
416
+ hamlit_build_for_id(escape_attrs, quote, buf, value);
417
+ } else if (str_eq(key, "class")) {
418
+ hamlit_build_for_class(escape_attrs, quote, buf, value);
419
+ } else if (str_eq(key, "data")) {
420
+ hamlit_build_for_data(escape_attrs, quote, buf, value);
421
+ } else if (is_boolean_attribute(key)) {
422
+ hamlit_build_for_boolean(escape_attrs, quote, format, buf, key, value);
423
+ } else {
424
+ hamlit_build_for_others(escape_attrs, quote, buf, key, value);
425
+ }
426
+ }
427
+
428
+ return buf;
429
+ }
430
+
431
+ static VALUE
432
+ rb_hamlit_build_id(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
433
+ {
434
+ VALUE array;
435
+
436
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
437
+ rb_scan_args(argc - 1, argv + 1, "*", &array);
438
+
439
+ return hamlit_build_id(argv[0], array);
440
+ }
441
+
442
+ static VALUE
443
+ rb_hamlit_build_class(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
444
+ {
445
+ VALUE array;
446
+
447
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
448
+ rb_scan_args(argc - 1, argv + 1, "*", &array);
449
+
450
+ return hamlit_build_class(argv[0], array);
451
+ }
452
+
453
+ static VALUE
454
+ rb_hamlit_build_data(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
455
+ {
456
+ VALUE array;
457
+
458
+ rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
459
+ rb_scan_args(argc - 2, argv + 2, "*", &array);
460
+
461
+ return hamlit_build_data(argv[0], argv[1], array);
462
+ }
463
+
464
+ static VALUE
465
+ rb_hamlit_build(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
466
+ {
467
+ VALUE array;
468
+
469
+ rb_check_arity(argc, 4, UNLIMITED_ARGUMENTS);
470
+ rb_scan_args(argc - 4, argv + 4, "*", &array);
471
+
472
+ return hamlit_build(argv[0], argv[1], argv[2], argv[3], array);
473
+ }
474
+
475
+ void
476
+ Init_hamlit(void)
477
+ {
478
+ VALUE mHamlit, mUtils;
479
+
480
+ mHamlit = rb_define_module("Hamlit");
481
+ mObjectRef = rb_define_module_under(mHamlit, "ObjectRef");
482
+ mUtils = rb_define_module_under(mHamlit, "Utils");
483
+ mAttributeBuilder = rb_define_module_under(mHamlit, "AttributeBuilder");
484
+
485
+ rb_define_singleton_method(mUtils, "escape_html", rb_escape_html, 1);
486
+ rb_define_singleton_method(mAttributeBuilder, "build", rb_hamlit_build, -1);
487
+ rb_define_singleton_method(mAttributeBuilder, "build_id", rb_hamlit_build_id, -1);
488
+ rb_define_singleton_method(mAttributeBuilder, "build_class", rb_hamlit_build_class, -1);
489
+ rb_define_singleton_method(mAttributeBuilder, "build_data", rb_hamlit_build_data, -1);
490
+
491
+ id_flatten = rb_intern("flatten");
492
+ id_keys = rb_intern("keys");
493
+ id_parse = rb_intern("parse");
494
+ id_prepend = rb_intern("prepend");
495
+ id_tr = rb_intern("tr");
496
+ id_uniq_bang = rb_intern("uniq!");
497
+
498
+ id_data = rb_intern("DATA");
499
+ id_equal = rb_intern("EQUAL");
500
+ id_hyphen = rb_intern("HYPHEN");
501
+ id_space = rb_intern("SPACE");
502
+ id_underscore = rb_intern("UNDERSCORE");
503
+
504
+ id_boolean_attributes = rb_intern("BOOLEAN_ATTRIBUTES");
505
+ id_xhtml = rb_intern("xhtml");
506
+
507
+ rb_const_set(mAttributeBuilder, id_data, rb_obj_freeze(rb_str_new_cstr("data")));
508
+ rb_const_set(mAttributeBuilder, id_equal, rb_obj_freeze(rb_str_new_cstr("=")));
509
+ rb_const_set(mAttributeBuilder, id_hyphen, rb_obj_freeze(rb_str_new_cstr("-")));
510
+ rb_const_set(mAttributeBuilder, id_space, rb_obj_freeze(rb_str_new_cstr(" ")));
511
+ rb_const_set(mAttributeBuilder, id_underscore, rb_obj_freeze(rb_str_new_cstr("_")));
512
+ }