wlang 0.10.2 → 2.0.0.beta

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 (269) hide show
  1. data/CHANGELOG.md +3 -121
  2. data/Gemfile +23 -1
  3. data/Gemfile.lock +32 -28
  4. data/LICENCE.md +18 -21
  5. data/Manifest.txt +4 -5
  6. data/README.md +100 -174
  7. data/Rakefile +1 -13
  8. data/bin/wlang +3 -29
  9. data/lib/wlang.rb +21 -394
  10. data/lib/wlang/command.rb +94 -0
  11. data/lib/wlang/compiler.rb +78 -0
  12. data/lib/wlang/compiler/autospacing.rb +60 -0
  13. data/lib/wlang/compiler/dialect_enforcer.rb +91 -0
  14. data/lib/wlang/compiler/filter.rb +32 -0
  15. data/lib/wlang/compiler/grammar.citrus +67 -0
  16. data/lib/wlang/compiler/parser.rb +26 -0
  17. data/lib/wlang/compiler/proc_call_removal.rb +15 -0
  18. data/lib/wlang/compiler/static_merger.rb +28 -0
  19. data/lib/wlang/compiler/strconcat_flattener.rb +25 -0
  20. data/lib/wlang/compiler/to_ruby_abstraction.rb +22 -0
  21. data/lib/wlang/compiler/to_ruby_code.rb +55 -0
  22. data/lib/wlang/dialect.rb +40 -237
  23. data/lib/wlang/dialect/dispatching.rb +51 -0
  24. data/lib/wlang/dialect/evaluation.rb +30 -0
  25. data/lib/wlang/dialect/tags.rb +50 -0
  26. data/lib/wlang/dummy.rb +32 -0
  27. data/lib/wlang/html.rb +106 -0
  28. data/lib/wlang/loader.rb +6 -0
  29. data/lib/wlang/mustang.rb +90 -0
  30. data/lib/wlang/scope.rb +57 -0
  31. data/lib/wlang/scope/binding_scope.rb +18 -0
  32. data/lib/wlang/scope/object_scope.rb +25 -0
  33. data/lib/wlang/scope/proxy_scope.rb +18 -0
  34. data/lib/wlang/scope/root_scope.rb +24 -0
  35. data/lib/wlang/template.rb +16 -86
  36. data/lib/wlang/version.rb +9 -8
  37. data/spec/fixtures/dialect/foobar.rb +31 -0
  38. data/spec/fixtures/dialect/upcasing.rb +13 -0
  39. data/spec/fixtures/templates/hello.tpl +1 -0
  40. data/spec/integration/examples/1-basics.txt +65 -0
  41. data/spec/integration/examples/2-imperative.txt +51 -0
  42. data/spec/integration/examples/3-partials.txt +76 -0
  43. data/spec/integration/examples/4-recursion.txt +16 -0
  44. data/spec/integration/html/test_ampersand.rb +15 -0
  45. data/spec/integration/html/test_bang.rb +38 -0
  46. data/spec/integration/html/test_caret.rb +33 -0
  47. data/spec/integration/html/test_dollar.rb +16 -0
  48. data/spec/integration/html/test_greater.rb +23 -0
  49. data/spec/integration/html/test_modulo.rb +16 -0
  50. data/spec/integration/html/test_plus.rb +48 -0
  51. data/spec/integration/html/test_question.rb +33 -0
  52. data/spec/integration/html/test_sharp.rb +21 -0
  53. data/spec/integration/html/test_slash.rb +16 -0
  54. data/spec/integration/html/test_star.rb +37 -0
  55. data/spec/integration/test_dummy.rb +51 -0
  56. data/spec/integration/test_examples.rb +29 -0
  57. data/spec/integration/test_mustang.rb +120 -0
  58. data/spec/integration/test_readme.rb +56 -0
  59. data/spec/integration/test_upcasing.rb +22 -0
  60. data/spec/spec_helper.rb +62 -1
  61. data/spec/test_wlang.rb +101 -0
  62. data/spec/unit/compiler/autospacing/test_right_strip.rb +30 -0
  63. data/spec/unit/compiler/autospacing/test_unindent.rb +30 -0
  64. data/spec/unit/compiler/test_dialect_enforcer.rb +168 -0
  65. data/spec/unit/compiler/test_grammar.rb +207 -0
  66. data/spec/unit/compiler/test_parser.rb +69 -0
  67. data/spec/unit/compiler/test_proc_call_removal.rb +24 -0
  68. data/spec/unit/compiler/test_static_merger.rb +29 -0
  69. data/spec/unit/compiler/test_strconcat_flattener.rb +30 -0
  70. data/spec/unit/compiler/test_to_ruby_abstraction.rb +59 -0
  71. data/spec/unit/compiler/test_to_ruby_code.rb +24 -0
  72. data/spec/unit/dialect/test_compile.rb +52 -0
  73. data/spec/unit/dialect/test_dispatching.rb +19 -0
  74. data/spec/unit/dialect/test_evaluate.rb +41 -0
  75. data/spec/unit/dialect/test_render.rb +33 -0
  76. data/spec/unit/dialect/test_tags.rb +32 -0
  77. data/spec/unit/dialect/test_with_scope.rb +18 -0
  78. data/spec/unit/scope/test_binding_scope.rb +27 -0
  79. data/spec/unit/scope/test_coerce.rb +22 -0
  80. data/spec/unit/scope/test_object_scope.rb +38 -0
  81. data/spec/unit/scope/test_proxy_scope.rb +22 -0
  82. data/spec/unit/scope/test_root_scope.rb +22 -0
  83. data/spec/unit/test_assumptions.rb +29 -0
  84. data/spec/unit/test_scope.rb +57 -0
  85. data/tasks/debug_mail.rake +42 -45
  86. data/tasks/gem.rake +22 -17
  87. data/tasks/spec_test.rake +9 -17
  88. data/tasks/unit_test.rake +11 -12
  89. data/tasks/yard.rake +13 -13
  90. data/wlang.gemspec +36 -32
  91. data/wlang.noespec +27 -35
  92. metadata +268 -451
  93. data/doc/specification/about.rdoc +0 -61
  94. data/doc/specification/analytics.wtpl +0 -13
  95. data/doc/specification/dialect.wtpl +0 -14
  96. data/doc/specification/dialects.wtpl +0 -3
  97. data/doc/specification/examples.rb +0 -3
  98. data/doc/specification/glossary.wtpl +0 -14
  99. data/doc/specification/hosting.rdoc +0 -0
  100. data/doc/specification/overview.rdoc +0 -116
  101. data/doc/specification/rulesets.wtpl +0 -87
  102. data/doc/specification/specification.css +0 -53
  103. data/doc/specification/specification.html +0 -1690
  104. data/doc/specification/specification.js +0 -8
  105. data/doc/specification/specification.wtpl +0 -42
  106. data/doc/specification/specification.yml +0 -432
  107. data/doc/specification/symbols.wtpl +0 -16
  108. data/lib/wlang/dialect_dsl.rb +0 -141
  109. data/lib/wlang/dialect_loader.rb +0 -74
  110. data/lib/wlang/dialects/bluecloth_dialect.rb +0 -16
  111. data/lib/wlang/dialects/coderay_dialect.rb +0 -45
  112. data/lib/wlang/dialects/hosted_dialect.rb +0 -50
  113. data/lib/wlang/dialects/plain_text_dialect.rb +0 -69
  114. data/lib/wlang/dialects/rdoc_dialect.rb +0 -33
  115. data/lib/wlang/dialects/redcloth_dialect.rb +0 -16
  116. data/lib/wlang/dialects/ruby_dialect.rb +0 -118
  117. data/lib/wlang/dialects/sql_dialect.rb +0 -38
  118. data/lib/wlang/dialects/standard_dialects.rb +0 -181
  119. data/lib/wlang/dialects/xhtml_dialect.rb +0 -63
  120. data/lib/wlang/dialects/yaml_dialect.rb +0 -30
  121. data/lib/wlang/encoder.rb +0 -62
  122. data/lib/wlang/encoder_set.rb +0 -122
  123. data/lib/wlang/errors.rb +0 -80
  124. data/lib/wlang/ext/hash_methodize.rb +0 -13
  125. data/lib/wlang/ext/string.rb +0 -44
  126. data/lib/wlang/hash_scope.rb +0 -89
  127. data/lib/wlang/hosted_language.rb +0 -146
  128. data/lib/wlang/intelligent_buffer.rb +0 -94
  129. data/lib/wlang/parser.rb +0 -332
  130. data/lib/wlang/parser_state.rb +0 -94
  131. data/lib/wlang/rule.rb +0 -66
  132. data/lib/wlang/rule_set.rb +0 -106
  133. data/lib/wlang/rulesets/basic_ruleset.rb +0 -83
  134. data/lib/wlang/rulesets/buffering_ruleset.rb +0 -115
  135. data/lib/wlang/rulesets/context_ruleset.rb +0 -111
  136. data/lib/wlang/rulesets/encoding_ruleset.rb +0 -73
  137. data/lib/wlang/rulesets/imperative_ruleset.rb +0 -132
  138. data/lib/wlang/rulesets/ruleset_utils.rb +0 -317
  139. data/lib/wlang/wlang_command.rb +0 -51
  140. data/lib/wlang/wlang_command_options.rb +0 -163
  141. data/spec/basic_object.spec +0 -40
  142. data/spec/coderay_dialect.spec +0 -8
  143. data/spec/dialect/apply_post_transform.spec +0 -16
  144. data/spec/global_extensions.rb +0 -2
  145. data/spec/hash_scope.spec +0 -76
  146. data/spec/redcloth_dialect.spec +0 -24
  147. data/spec/test_all.rb +0 -8
  148. data/spec/wlang.spec +0 -53
  149. data/spec/wlang_spec.rb +0 -8
  150. data/spec/xhtml_dialect.spec +0 -22
  151. data/tasks/genspec.rake +0 -5
  152. data/test/blackbox/basic/execution_1.exp +0 -1
  153. data/test/blackbox/basic/execution_1.tpl +0 -1
  154. data/test/blackbox/basic/execution_2.exp +0 -1
  155. data/test/blackbox/basic/execution_2.tpl +0 -1
  156. data/test/blackbox/basic/execution_3.exp +0 -1
  157. data/test/blackbox/basic/execution_3.tpl +0 -1
  158. data/test/blackbox/basic/execution_4.exp +0 -1
  159. data/test/blackbox/basic/execution_4.tpl +0 -1
  160. data/test/blackbox/basic/inclusion_1.exp +0 -1
  161. data/test/blackbox/basic/inclusion_1.tpl +0 -1
  162. data/test/blackbox/basic/inclusion_2.exp +0 -1
  163. data/test/blackbox/basic/inclusion_2.tpl +0 -1
  164. data/test/blackbox/basic/injection_1.exp +0 -1
  165. data/test/blackbox/basic/injection_1.tpl +0 -1
  166. data/test/blackbox/basic/injection_2.exp +0 -1
  167. data/test/blackbox/basic/injection_2.tpl +0 -1
  168. data/test/blackbox/basic/modulation_1.exp +0 -1
  169. data/test/blackbox/basic/modulation_1.tpl +0 -1
  170. data/test/blackbox/basic/modulation_2.exp +0 -1
  171. data/test/blackbox/basic/modulation_2.tpl +0 -1
  172. data/test/blackbox/basic/recursive_app_1.exp +0 -1
  173. data/test/blackbox/basic/recursive_app_1.tpl +0 -1
  174. data/test/blackbox/basic/recursive_app_2.exp +0 -1
  175. data/test/blackbox/basic/recursive_app_2.tpl +0 -1
  176. data/test/blackbox/buffering/data_1.rb +0 -1
  177. data/test/blackbox/buffering/data_assignment_1.exp +0 -1
  178. data/test/blackbox/buffering/data_assignment_1.tpl +0 -1
  179. data/test/blackbox/buffering/data_assignment_2.exp +0 -1
  180. data/test/blackbox/buffering/data_assignment_2.tpl +0 -1
  181. data/test/blackbox/buffering/data_assignment_3.exp +0 -1
  182. data/test/blackbox/buffering/data_assignment_3.tpl +0 -1
  183. data/test/blackbox/buffering/data_assignment_4.exp +0 -1
  184. data/test/blackbox/buffering/data_assignment_4.tpl +0 -1
  185. data/test/blackbox/buffering/input_1.exp +0 -1
  186. data/test/blackbox/buffering/input_1.tpl +0 -1
  187. data/test/blackbox/buffering/input_2.exp +0 -1
  188. data/test/blackbox/buffering/input_2.tpl +0 -1
  189. data/test/blackbox/buffering/input_3.exp +0 -1
  190. data/test/blackbox/buffering/input_3.tpl +0 -1
  191. data/test/blackbox/buffering/input_inclusion.exp +0 -1
  192. data/test/blackbox/buffering/input_inclusion.tpl +0 -1
  193. data/test/blackbox/buffering/input_inclusion_1.exp +0 -0
  194. data/test/blackbox/buffering/input_inclusion_1.tpl +0 -1
  195. data/test/blackbox/buffering/input_inclusion_2.exp +0 -1
  196. data/test/blackbox/buffering/input_inclusion_2.tpl +0 -1
  197. data/test/blackbox/buffering/input_inclusion_3.exp +0 -1
  198. data/test/blackbox/buffering/input_inclusion_3.tpl +0 -1
  199. data/test/blackbox/buffering/input_inclusion_4.exp +0 -0
  200. data/test/blackbox/buffering/input_inclusion_4.tpl +0 -1
  201. data/test/blackbox/buffering/input_inclusion_5.exp +0 -1
  202. data/test/blackbox/buffering/input_inclusion_5.tpl +0 -1
  203. data/test/blackbox/buffering/input_inclusion_6.exp +0 -1
  204. data/test/blackbox/buffering/input_inclusion_6.tpl +0 -1
  205. data/test/blackbox/buffering/input_inclusion_7.exp +0 -0
  206. data/test/blackbox/buffering/input_inclusion_7.tpl +0 -1
  207. data/test/blackbox/buffering/text_1.txt +0 -1
  208. data/test/blackbox/buffering/wlang.txt +0 -1
  209. data/test/blackbox/context/assignment_1.exp +0 -1
  210. data/test/blackbox/context/assignment_1.tpl +0 -1
  211. data/test/blackbox/context/assignment_2.exp +0 -1
  212. data/test/blackbox/context/assignment_2.tpl +0 -1
  213. data/test/blackbox/context/assignment_3.exp +0 -2
  214. data/test/blackbox/context/assignment_3.tpl +0 -2
  215. data/test/blackbox/context/assignment_4.exp +0 -1
  216. data/test/blackbox/context/assignment_4.tpl +0 -1
  217. data/test/blackbox/context/block_assignment_1.exp +0 -1
  218. data/test/blackbox/context/block_assignment_1.tpl +0 -1
  219. data/test/blackbox/context/block_assignment_2.exp +0 -1
  220. data/test/blackbox/context/block_assignment_2.tpl +0 -1
  221. data/test/blackbox/context/modulo_assignment_1.exp +0 -1
  222. data/test/blackbox/context/modulo_assignment_1.tpl +0 -1
  223. data/test/blackbox/context/modulo_assignment_2.exp +0 -1
  224. data/test/blackbox/context/modulo_assignment_2.tpl +0 -1
  225. data/test/blackbox/data_1.rb +0 -1
  226. data/test/blackbox/postblock/hello.exp +0 -1
  227. data/test/blackbox/postblock/hello.pre +0 -1
  228. data/test/blackbox/postblock/hello.tpl +0 -1
  229. data/test/blackbox/postblock/hello_input_inclusion.exp +0 -1
  230. data/test/blackbox/postblock/hello_input_inclusion.tpl +0 -1
  231. data/test/blackbox/postblock/hello_to_authors.exp +0 -1
  232. data/test/blackbox/postblock/hello_to_authors.tpl +0 -1
  233. data/test/blackbox/poststring/hello.exp +0 -1
  234. data/test/blackbox/poststring/hello.tpl +0 -1
  235. data/test/blackbox/test_all.rb +0 -70
  236. data/test/standard_dialects/ruby/data.rb +0 -7
  237. data/test/standard_dialects/ruby/inclusion.exp +0 -6
  238. data/test/standard_dialects/ruby/inclusion.tpl +0 -6
  239. data/test/standard_dialects/test_all.rb +0 -29
  240. data/test/standard_dialects/yaml/assumptions_test.rb +0 -13
  241. data/test/standard_dialects/yaml/data.rb +0 -3
  242. data/test/standard_dialects/yaml/inclusion_1.exp +0 -7
  243. data/test/standard_dialects/yaml/inclusion_1.tpl +0 -2
  244. data/test/standard_dialects/yaml/inclusion_2.exp +0 -5
  245. data/test/standard_dialects/yaml/inclusion_2.tpl +0 -3
  246. data/test/unit/test_all.rb +0 -9
  247. data/test/unit/wlang/anagram_bugs_test.rb +0 -111
  248. data/test/unit/wlang/basic_ruleset_test.rb +0 -52
  249. data/test/unit/wlang/buffering_ruleset_test.rb +0 -102
  250. data/test/unit/wlang/buffering_template1.wtpl +0 -1
  251. data/test/unit/wlang/buffering_template2.wtpl +0 -1
  252. data/test/unit/wlang/buffering_template3.wtpl +0 -1
  253. data/test/unit/wlang/buffering_template4.wtpl +0 -1
  254. data/test/unit/wlang/buffering_template5.wtpl +0 -1
  255. data/test/unit/wlang/context_ruleset_test.rb +0 -32
  256. data/test/unit/wlang/data.rb +0 -3
  257. data/test/unit/wlang/encoder_set_test.rb +0 -42
  258. data/test/unit/wlang/imperative_ruleset_test.rb +0 -107
  259. data/test/unit/wlang/intelligent_buffer_test.rb +0 -194
  260. data/test/unit/wlang/othersymbols_test.rb +0 -16
  261. data/test/unit/wlang/parser_test.rb +0 -88
  262. data/test/unit/wlang/plain_text_dialect_test.rb +0 -21
  263. data/test/unit/wlang/ruby_dialect_test.rb +0 -100
  264. data/test/unit/wlang/ruby_expected.rb +0 -3
  265. data/test/unit/wlang/ruby_template.wrb +0 -3
  266. data/test/unit/wlang/ruleset_utils_test.rb +0 -245
  267. data/test/unit/wlang/specification_examples_test.rb +0 -54
  268. data/test/unit/wlang/test_utils.rb +0 -25
  269. data/test/unit/wlang/wlang_test.rb +0 -80
@@ -0,0 +1,30 @@
1
+ module WLang
2
+ class Dialect
3
+ module Evaluation
4
+
5
+ def scope
6
+ @scope ||= Scope.root
7
+ end
8
+
9
+ def with_scope(x)
10
+ @scope = scope.push(x)
11
+ res = yield
12
+ @scope = scope.pop
13
+ res
14
+ end
15
+
16
+ def evaluate(expr, *default)
17
+ case expr
18
+ when Symbol, String
19
+ catch(:fail) do
20
+ return scope.evaluate(expr, *default)
21
+ end
22
+ raise NameError, "Unable to find `#{expr}`"
23
+ else
24
+ evaluate(render(expr), *default)
25
+ end
26
+ end
27
+
28
+ end # module Evaluation
29
+ end # class Dialect
30
+ end # module WLang
@@ -0,0 +1,50 @@
1
+ module WLang
2
+ class Dialect
3
+ module Tags
4
+
5
+ module ClassMethods
6
+
7
+ protected
8
+
9
+ def tag(symbols, dialects = nil, method = nil, &block)
10
+ if block
11
+ tag(symbols, dialects, block)
12
+ else
13
+ dialects, method = nil, dialects if method.nil?
14
+ define_tag_method(symbols, dialects, method)
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ module InstanceMethods
21
+
22
+ protected
23
+
24
+ def render(fn, scope = nil, buffer = "")
25
+ if scope.nil?
26
+ case fn
27
+ when String
28
+ buffer << fn
29
+ when Proc
30
+ fn.call(self, buffer)
31
+ when Template
32
+ fn.call(@scope, buffer)
33
+ else
34
+ raise ArgumentError, "Unable to render `#{fn}`"
35
+ end
36
+ else
37
+ with_scope(scope){ render(fn, nil, buffer) }
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ def self.included(mod)
44
+ mod.instance_eval{ include(InstanceMethods) }
45
+ mod.extend(ClassMethods)
46
+ end
47
+
48
+ end # module Tags
49
+ end # class Dialect
50
+ end # module WLang
@@ -0,0 +1,32 @@
1
+ require 'wlang'
2
+ module WLang
3
+ #
4
+ # The _dummy_ dialect, which has no tag at all.
5
+ #
6
+ # This dialect can be used to parse tag blocks without further interpreting
7
+ # any wlang tag. This is needed to flush wlang output in certain situations
8
+ # as illustrated by the following template:
9
+ #
10
+ # Hello ${who}! This is wlang, a templating language which comes with
11
+ # special tags such as %{ ${who}, +{who}, *{authors}{...}, etc }
12
+ #
13
+ # The special tag %{ } might easily be implemented using the Dummy dialect:
14
+ #
15
+ # require 'wlang/dummy'
16
+ # class MyDialect < WLang::Dialect
17
+ #
18
+ # def dollar(buf, fn)
19
+ # buf << evaluate(fn)
20
+ # end
21
+ #
22
+ # def no_wlang(buf, fn)
23
+ # render(fn)
24
+ # end
25
+ #
26
+ # tag '$', :dollar
27
+ # tag '%', [WLang::Dummy], :no_wlang
28
+ # end
29
+ #
30
+ class Dummy < Dialect
31
+ end # class Dummy
32
+ end # module WLang
@@ -0,0 +1,106 @@
1
+ require 'wlang'
2
+ require 'wlang/dummy'
3
+ module WLang
4
+ class Html < WLang::Dialect
5
+
6
+ module Helpers
7
+
8
+ def value_of(fn)
9
+ evaluate(render(fn).to_s.strip)
10
+ end
11
+ private :value_of
12
+
13
+ def to_html(val)
14
+ val = val.to_html if val.respond_to?(:to_html)
15
+ val = to_html(val.call) if val.is_a?(Proc)
16
+ val.to_s
17
+ end
18
+ private :to_html
19
+
20
+ def escape_html(val)
21
+ Temple::Utils.escape_html(val)
22
+ end
23
+ private :escape_html
24
+
25
+ end
26
+ include Helpers
27
+
28
+ module HighOrderFunctions
29
+
30
+ def bang(buf, fn)
31
+ val = value_of(fn).to_s
32
+ render(val, nil, buf)
33
+ end
34
+
35
+ def plus(buf, fn)
36
+ val = value_of(fn)
37
+ val = to_html(val) unless val.is_a?(Template)
38
+ render(val, nil, buf)
39
+ end
40
+
41
+ def dollar(buf, fn)
42
+ val = escape_html(plus("", fn))
43
+ render(val, nil, buf)
44
+ end
45
+
46
+ def ampersand(buf, fn)
47
+ val = escape_html(render(fn))
48
+ render(val, nil, buf)
49
+ end
50
+
51
+ def slash(buf, fn)
52
+ end
53
+
54
+ def modulo(buf, fn)
55
+ render(fn, nil, buf)
56
+ end
57
+
58
+ def question(buf, fn_if, fn_then, fn_else)
59
+ val = value_of(fn_if) ? fn_then : fn_else
60
+ render(val, nil, buf) if val
61
+ end
62
+
63
+ def caret(buf, fn_if, fn_then, fn_else)
64
+ val = value_of(fn_if) ? fn_else : fn_then
65
+ render(val, nil, buf) if val
66
+ end
67
+
68
+ def star(buf, coll_fn, elm_fn, between_fn)
69
+ collection = value_of(coll_fn)
70
+ collection.each_with_index do |elm,i|
71
+ render(between_fn, elm, buf) if between_fn and (i > 0)
72
+ render(elm_fn, elm, buf)
73
+ end
74
+ end
75
+
76
+ def greater(buf, fn)
77
+ val = value_of(fn)
78
+ val = Html.compile(val) unless Template === val
79
+ render(val, nil, buf)
80
+ end
81
+
82
+ def sharp(buf, who_fn, then_fn)
83
+ val = value_of(who_fn)
84
+ if val and not(val.respond_to?(:empty?) and val.empty?)
85
+ render(then_fn, val, buf)
86
+ end
87
+ end
88
+
89
+ end
90
+ include HighOrderFunctions
91
+
92
+ default_options :autospacing => true
93
+ tag '!', :bang
94
+ tag '+', :plus
95
+ tag '$', :dollar
96
+ tag '&', :ampersand
97
+ tag '/', :slash
98
+ tag '%', [WLang::Dummy], :modulo
99
+ tag '?', :question
100
+ tag '^', :caret
101
+ tag '*', :star
102
+ tag '>', :greater
103
+ tag '#', :sharp
104
+
105
+ end # class Html
106
+ end # module WLang
@@ -0,0 +1,6 @@
1
+ require "citrus"
2
+ require "temple"
3
+ if RUBY_VERSION < "1.9"
4
+ require 'backports'
5
+ require "backports/basic_object" unless defined?(BasicObject)
6
+ end
@@ -0,0 +1,90 @@
1
+ require 'wlang'
2
+ require 'wlang/dummy'
3
+ module WLang
4
+ #
5
+ # A WLang dialect mimicing the excellent Mustache.
6
+ #
7
+ # This dialect installs the following high-order functions:
8
+ #
9
+ # * `${...}` mimics mustache's `{{ ... }}` that is, it evaluates the variable and
10
+ # returns the HTML-escaped string
11
+ # * `+{...}` mimics mustache's `{{{ ... }}}` that is, it evaluates the variable and
12
+ # returns its string representation (through `to_s`)
13
+ # * `#{..1..}{..2..}` mimics mustache's `{{#..1..}}..2..{{/..1..}}`. For false and nil,
14
+ # it returns nil. For scopes and ranges, it instantiates the second block in the scope
15
+ # of each element in turn and returns the concatenation of instantiation results. For
16
+ # a Proc, it calls it, passing a rendering continuation as first argument. Every other
17
+ # object is used as a new scope in which the second block is instantiated.
18
+ # * `^{..1..}{..2..}` mimics mustache's `{{^..1..}}..2..{{/..1..}}`, instantiating the
19
+ # second only if the evaluation of the first yields false, nil, an empty list or an
20
+ # unbound variable.
21
+ # * `>{...}` mimics mustache's `{{>...}}`, instantiating the partial denoted by the
22
+ # evaluated expression.
23
+ # * `!{...}` mimics mustache's `{{!...}}`, taking the block content as a comment
24
+ # therefore skipping it.
25
+ #
26
+ class Mustang < WLang::Dialect
27
+
28
+ module HighOrderFunctions
29
+
30
+ def plus(buf, fn)
31
+ if x = evaluate(fn)
32
+ buf << x.to_s
33
+ end
34
+ end
35
+
36
+ def escape(buf, fn)
37
+ buf << Temple::Utils.escape_html(evaluate(fn))
38
+ end
39
+
40
+ def section(buf, fn1, fn2)
41
+ case x = evaluate(fn1)
42
+ when FalseClass, NilClass
43
+ nil
44
+ when Array, Range
45
+ x.each{|item|
46
+ render(fn2, item, buf)
47
+ }
48
+ when Proc
49
+ buf << x.call(lambda{ render(fn2) })
50
+ else
51
+ render(fn2, x, buf)
52
+ end
53
+ end
54
+
55
+ def inverted(buf, fn1, fn2)
56
+ case x = evaluate(fn1)
57
+ when FalseClass, NilClass
58
+ render(fn2, scope, buf)
59
+ when Array
60
+ render(fn2, scope, buf) if x.empty?
61
+ end
62
+ end
63
+
64
+ def comment(buf, fn)
65
+ end
66
+
67
+ def partial(buf, fn)
68
+ if x = Mustang.compile(evaluate(fn))
69
+ render(x, scope, buf)
70
+ end
71
+ end
72
+
73
+ end
74
+ include HighOrderFunctions
75
+
76
+ def evaluate(expr)
77
+ super
78
+ rescue
79
+ nil
80
+ end
81
+
82
+ tag '+', :plus
83
+ tag '$', :escape
84
+ tag '#', :section
85
+ tag '^', :inverted
86
+ tag '>', :partial
87
+ tag '!', [WLang::Dummy], :comment
88
+
89
+ end # class Mustang
90
+ end # module WLang
@@ -0,0 +1,57 @@
1
+ module WLang
2
+ class Scope
3
+
4
+ attr_reader :subject
5
+ attr_reader :parent
6
+
7
+ def initialize(subject, parent)
8
+ @subject, @parent = subject, parent
9
+ end
10
+
11
+ def self.root
12
+ @root ||= RootScope.new
13
+ end
14
+
15
+ def self.coerce(arg, parent = root)
16
+ clazz = case arg
17
+ when Binding
18
+ BindingScope
19
+ when Scope
20
+ ProxyScope
21
+ else
22
+ ObjectScope
23
+ end
24
+ clazz.new(arg, parent)
25
+ end
26
+
27
+ def push(x)
28
+ Scope.coerce(x, self)
29
+ end
30
+
31
+ def pop
32
+ @parent
33
+ end
34
+
35
+ def with(x)
36
+ yield(self.push(x))
37
+ end
38
+
39
+ def evaluate(expr, *default)
40
+ unfound = lambda{ default.empty? ? throw(:fail) : default.first }
41
+ expr = expr.to_s.strip
42
+ if expr.to_s.index('.').nil?
43
+ fetch(expr.to_sym, &unfound)
44
+ else
45
+ keys = expr.split('.').map(&:to_sym)
46
+ keys.inject(self){|scope,key|
47
+ Scope.coerce(scope.fetch(key, &unfound))
48
+ }.subject
49
+ end
50
+ end
51
+
52
+ end # class Scope
53
+ end # module WLang
54
+ require 'wlang/scope/root_scope'
55
+ require 'wlang/scope/proxy_scope'
56
+ require 'wlang/scope/object_scope'
57
+ require 'wlang/scope/binding_scope'
@@ -0,0 +1,18 @@
1
+ module WLang
2
+ class Scope
3
+ class BindingScope < Scope
4
+
5
+ def fetch(k, &blk)
6
+ subject.eval(k.to_s)
7
+ rescue NameError
8
+ parent.fetch(k, &blk)
9
+ end
10
+
11
+ def inspect
12
+ "BindingScope(#{subject.inspect})"
13
+ end
14
+ alias :to_s :inspect
15
+
16
+ end # class ProxyScope
17
+ end # class Scope
18
+ end # module WLang
@@ -0,0 +1,25 @@
1
+ module WLang
2
+ class Scope
3
+ class ObjectScope < Scope
4
+
5
+ def fetch(k, &blk)
6
+ s = subject
7
+ return s if k == :self
8
+ if s.respond_to?(:has_key?)
9
+ return s[k] if s.has_key?(k)
10
+ return s[k.to_s] if s.has_key?(k.to_s)
11
+ end
12
+ return s.send(k) if s.respond_to?(k)
13
+ parent.fetch(k, &blk)
14
+ rescue NameError
15
+ parent.fetch(k, &blk)
16
+ end
17
+
18
+ def inspect
19
+ "ObjectScope(#{subject.inspect})"
20
+ end
21
+ alias :to_s :inspect
22
+
23
+ end # class ProxyScope
24
+ end # class Scope
25
+ end # module WLang
@@ -0,0 +1,18 @@
1
+ module WLang
2
+ class Scope
3
+ class ProxyScope < Scope
4
+
5
+ def fetch(key, &blk)
6
+ subject.fetch(key) do
7
+ parent.fetch(key, &blk)
8
+ end
9
+ end
10
+
11
+ def inspect
12
+ subject.inspect
13
+ end
14
+ alias :to_s :inspect
15
+
16
+ end # class ProxyScope
17
+ end # class Scope
18
+ end # module WLang
@@ -0,0 +1,24 @@
1
+ module WLang
2
+ class Scope
3
+ class RootScope < Scope
4
+
5
+ def initialize
6
+ super(nil,nil)
7
+ end
8
+
9
+ def pop
10
+ raise "Unable to pop from root scope"
11
+ end
12
+
13
+ def fetch(key)
14
+ block_given? ? yield : throw(:fail)
15
+ end
16
+
17
+ def inspect
18
+ "RootScope"
19
+ end
20
+ alias :to_s :inspect
21
+
22
+ end # class RootScope
23
+ end # class Scope
24
+ end # module WLang