wlang 0.10.2 → 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,95 +1,25 @@
1
1
  module WLang
2
- #
3
- # Template in a given wlang dialect and expecting :braces, :brackets or
4
- # :parentheses as block delimiters. A template is an abstraction over a
5
- # wlang source text. It also provides utilities to create friendly location
6
- # messages for offsets in the source text.
7
- #
8
2
  class Template
9
-
10
- # Recognized symbols for blocks
11
- BLOCK_SYMBOLS = {:braces => ['{', '}'],
12
- :brackets => ['[', ']'],
13
- :parentheses => ['(', ')']}
14
-
15
- # Template wlang dialect (wlang/...)
16
- attr_reader :dialect
17
3
 
18
- # Block symbols
19
- attr_reader :block_symbols
20
-
21
- # Attached file source
22
- attr_accessor :source_file
23
-
24
- # Creates a template instance.
25
- def initialize(source, dialect, block_symbols = :braces)
26
- dialect = WLang::dialect(dialect)
27
- raise(ArgumentError, "Source is mandatory") if source.nil?
28
- raise(ArgumentError, "Dialect instance expected for dialect, #{dialect} received") unless Dialect===dialect
29
- @source = source
30
- @dialect = dialect
31
- @block_symbols = block_symbols
4
+ attr_reader :dialect, :inner_proc
5
+
6
+ def initialize(dialect, inner_proc)
7
+ @dialect = dialect
8
+ @inner_proc = inner_proc
32
9
  end
33
-
34
- # Resolved a relative uri
35
- def file_resolve(uri, exists=false)
36
- require 'uri'
37
- real_uri = URI::parse(uri)
38
- if real_uri.absolute?
39
- raise WLang::Error, "Unable to resolve #{uri}, absolute uri are not supported"
40
- elsif real_uri.path[0, 1] == '/'
41
- real_uri.path
10
+
11
+ def call(scope = {}, buffer = '')
12
+ case i = inner_proc
13
+ when String
14
+ buffer << i
42
15
  else
43
- raise WLang::Error, "Unable to resolve #{uri}, this template is not attached to a file" unless @source_file
44
- target = File.join(File.dirname(@source_file), uri)
45
- if exists and not(File.exists?(target))
46
- raise WLang::Error, "File '#{uri}' does not exists"
16
+ @dialect.dup.tap do |d|
17
+ d.send(:render, i, scope, buffer)
47
18
  end
48
- target
19
+ buffer
49
20
  end
50
21
  end
51
-
52
- # Returns template's source text
53
- def source_text
54
- case @source
55
- when String
56
- @source
57
- else
58
- @source.to_s
59
- end
60
- end
61
-
62
- # Returns template's block endstart (typically '}{')
63
- def block_endstart
64
- @block_endstart ||= BLOCK_SYMBOLS[block_symbols].reverse.join
65
- end
66
-
67
- # Instantiates the template, with optinal context and hosted language.
68
- def instantiate(context = {}, hosted = ::WLang::HostedLanguage.new)
69
- p = ::WLang::Parser.new(hosted, self, context)
70
- p.instantiate(true)[0]
71
- end
72
-
73
- # Returns a friendly position of an offset in the source text
74
- def where(offset)
75
- src = source_text
76
- source_file = self.source_file ? File.expand_path(self.source_file) : "no source file"
77
- "#{source_file || 'inline template'}:#{src.__wlang_line_of(offset)}:#{src.__wlang_column_of(offset)-1}"
78
- end
79
-
80
- # Raises a WLang::Error for the given offset
81
- def error(offset, msg = "")
82
- raise WLang::Error, "#{where(offset)} #{msg}"
83
- end
84
-
85
- # Raises a friendly ParseError, with positions and so on
86
- def parse_error(offset, msg = "")
87
- src = source_text
88
- ex = ParseError.new("#{where(offset)} #{msg}")
89
- ex.line, ex.column = src.__wlang_line_of(offset), src.__wlang_column_of(offset)-1
90
- raise ex
91
- end
92
-
22
+ alias :render :call
23
+
93
24
  end # class Template
94
-
95
- end # module WLang
25
+ end # module WLang
@@ -1,14 +1,15 @@
1
1
  module WLang
2
2
  module Version
3
-
4
- MAJOR = 0
5
- MINOR = 10
6
- TINY = 2
7
-
3
+
4
+ MAJOR = 2
5
+ MINOR = 0
6
+ TINY = 0
7
+ BETA = "beta"
8
+
8
9
  def self.to_s
9
- [ MAJOR, MINOR, TINY ].join('.')
10
+ [ MAJOR, MINOR, TINY, BETA ].join('.')
10
11
  end
11
-
12
- end
12
+
13
+ end
13
14
  VERSION = Version.to_s
14
15
  end
@@ -0,0 +1,31 @@
1
+ class Foo < WLang::Dialect
2
+
3
+ def _(fn)
4
+ fn ? render(fn) : nil
5
+ end
6
+
7
+ def execution(buf, fn)
8
+ buf << "(foo#execution #{_ fn})"
9
+ end
10
+
11
+ def escaping(buf, fn)
12
+ buf << "(foo#escaping #{_ fn})"
13
+ end
14
+
15
+ tag "!", :execution
16
+ tag "$", :escaping
17
+ tag "@" do |buf,fn| buf << "(foo#link #{_ fn})"; end
18
+ tag "<" do |buf,fn| buf << "(foo#less #{_ fn})"; end
19
+ tag '!@' do |buf,fn| buf << "(foo#bangat #{_ fn})"; end
20
+ end
21
+
22
+ class Bar < Foo
23
+
24
+ def escaping(buf, fn)
25
+ buf << "(bar#escaping #{_ fn})"
26
+ end
27
+
28
+ tag "$", :escaping
29
+ tag "<" do |buf,fn| buf << "(bar#less #{_ fn})"; end
30
+ tag ">" do |buf,fn| buf << "(bar#greater #{_ fn})"; end
31
+ end
@@ -0,0 +1,13 @@
1
+ class Upcasing < WLang::Dialect
2
+
3
+ tag "$" do |buf, fn|
4
+ buf << render(fn).upcase
5
+ end
6
+
7
+ tag "#" do |buf, fn|
8
+ if x = evaluate(fn)
9
+ buf << x
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1 @@
1
+ Hello ${who}!
@@ -0,0 +1,65 @@
1
+ # Three basic tags: bang, plus and dollar
2
+
3
+ Three special tags, bounded to the !, +, $ symbols allow injecting dynamic content. The difference between them is:
4
+
5
+ * bang (!) renders the result of invoking `to_s` on the evaluated expression (see later),
6
+ * plus (+) first tries to render the value through a `to_html` method and falls back to `to_s`
7
+ * dollar ($) escapes html entities of the content that would be returned by +.
8
+
9
+ We do not illustrate the difference between ! and + here, as it is only only useful for already advanced scenarios. The idiomatic way of using WLang::Html is to avoid ! unless strictly needed, to consider + as unsafe but useful, and $ as safe and to use it by default.
10
+
11
+ Users that know Mustache can remember that $ corresponds to {{ ... }} whereas + corresponds to {{{ ... }}}, which some powerful extras (not shown here). For example,
12
+
13
+ Hello &lt;script&gt;injected code&lt;&#47;script&gt; !
14
+
15
+ is clearly safe (instantiate the example to convince yourself), but the following one:
16
+
17
+ Hello <script>injected code</script> !
18
+
19
+ is not safe, unless the `who` variable contains content that you can trust and which must not be escaped.
20
+
21
+ The WLang::Html dialect encourages logic-less templates, but is not as strict as Mustache. Indeed, all tags that rely on some form of variable evaluation (the three above in particular), actually allow simple expressions, restricted to argument-less getters however:
22
+
23
+ Hello wlang, released in 2012!
24
+
25
+ # Ampersand as an introduction to high-level constructs
26
+
27
+ A fourth basic tag is sometimes useful, and allows me to introduce higher-level wlang constructs.
28
+
29
+ * ampersand (&) escapes raw html content. It does not evaluate any expression.
30
+
31
+ For example, the following expression
32
+
33
+ &lt;script&gt;some attacker attempt to inject code&lt;&#47;script&gt;
34
+
35
+ will simply escape its html content.
36
+
37
+ Given the WLang functional semantics and the & and ! tags, one can see + and $ as shortcuts for longer expressions. For instance,
38
+
39
+ &lt;script&gt;injected code&lt;&#47;script&gt; is a shortcut for the equivalent expression &lt;script&gt;injected code&lt;&#47;script&gt;
40
+
41
+ We'll come back to higher-level constructs in other examples later. For now, let just introduce some additional bacic tags.
42
+
43
+ # Slash for comments
44
+
45
+ The slash tag is used for comments. It simply renders nothing at all.
46
+
47
+ * slash (/) can be used for comments.
48
+
49
+ For instance,
50
+
51
+
52
+
53
+ And,
54
+
55
+ # Modulo to disengage wlang
56
+
57
+ The last useful tag allows you to simply disable wlang rendering in specific template portions. For this, use the modulo tag:
58
+
59
+ * modulo (%) disables wlang inside its block.
60
+
61
+ For instance, the following template renders the block text unchanged, even if it contains wlang tags:
62
+
63
+ Hello ${struct.name}, how are you?
64
+
65
+ This is especially useful for writing blog posts explaining wlang, using wlang itself. Therefore, it is a feature mostly needed by me ;-)
@@ -0,0 +1,51 @@
1
+ # Introduction
2
+
3
+ WLang inspires from Mustache and encourages you to write logic-less templates. It does not mean that imperative constructions are not needed. Iterations and conditional sections, in particular are definitely something required.
4
+
5
+ ## Conditional and inverted sections
6
+
7
+ * question (?) provides a if-then-else section, with optional else
8
+ * caret (^) provides a if-else-then section, with optional then
9
+
10
+ The boolean evaluation is based on Ruby's conditions and has the same semantics: nil and false are FALSE, all other values are TRUE. For instance,
11
+
12
+ 'Hello TRUE' renders as 'Hello TRUE'
13
+ 'Hello TRUE' renders as 'Hello TRUE'
14
+ 'Hello FALSE' renders as 'Hello FALSE'
15
+ 'Hello FALSE' renders as 'Hello FALSE'
16
+
17
+ For inverted sections,
18
+
19
+ 'Hello FALSE' renders as 'Hello FALSE'
20
+ 'Hello FALSE' renders as 'Hello FALSE'
21
+ 'Hello TRUE' renders as 'Hello TRUE'
22
+ 'Hello TRUE' renders as 'Hello TRUE'
23
+
24
+ In both cases, the first block relies on an expression evaluation and therefore allows dotted expressions (see 1-basics.md), while also recognizing high-level constructs. Also, the third block is optional. As an example,
25
+
26
+ 'Hello world' renders as 'Hello world' if `vart` contains 'true'
27
+
28
+ whereas,
29
+
30
+ 'Hello ' renders as 'Hello ' if `varf` contains 'false'
31
+
32
+ As usual, use it with parcimony and care but enjoy its powerfulness.
33
+
34
+ ## Iterations
35
+
36
+ A special tag allows you to perform simple iterations. More accurately, the star allows you to render a block for each value of a sequence, joining the results with an optional separator:
37
+
38
+ * star (*) joins the rendering of its second block for each element of a sequence
39
+
40
+ For instance,
41
+
42
+ <ul>
43
+ <li>Bernard</li>
44
+ <li>Louis</li>
45
+ </ul>
46
+
47
+ Renders an HTML list with the authors names. A separator can be specified through the third optional block:
48
+
49
+ Bernard,Louis
50
+
51
+ Will render 'Bernard, Louis'.
@@ -0,0 +1,76 @@
1
+ # Partials
2
+
3
+ Partials allows defining templating sections in external variables, such as the `hobby_entry_partial` variable above. The greater tag allows you to instantiate those partials:
4
+
5
+ * greater (>) renders the partial denotes by an expression in the current scope
6
+
7
+ For instance,
8
+
9
+ <ul>
10
+ <li><a href="http:&#47;&#47;reddit.com&#47;r&#47;programming">Programming</a></li>
11
+ <li><a href="http:&#47;&#47;www.music.me&#47;">Music</a></li>
12
+ </ul>
13
+
14
+ will generate the hobby list with a link for each of my hobbies. As the scope inside the iteration is based on the currently iterated element, the hobby label and url are accessible inside the partial itself.
15
+
16
+ # Advanced scoping example
17
+
18
+ Suppose that, in the example above, you dont statically know what are the keys of an hobby hash. For instance, for each hobby you want to display an HTML table with every (key,value) pair. You could try something like this:
19
+
20
+ <ul>
21
+ <table>
22
+ <tr>
23
+ <th>key</th>
24
+ <th>value</th>
25
+ </tr>
26
+ <tr>
27
+ <td>label</td>
28
+ <td>Programming</td>
29
+ </tr>
30
+ <tr>
31
+ <td>url</td>
32
+ <td>http:&#47;&#47;reddit.com&#47;r&#47;programming</td>
33
+ </tr>
34
+ </table>
35
+ <table>
36
+ <tr>
37
+ <th>key</th>
38
+ <th>value</th>
39
+ </tr>
40
+ <tr>
41
+ <td>label</td>
42
+ <td>Music</td>
43
+ </tr>
44
+ <tr>
45
+ <td>url</td>
46
+ <td>http:&#47;&#47;www.music.me&#47;</td>
47
+ </tr>
48
+ </table>
49
+ </ul>
50
+
51
+ The `hobby_entry_table` partial above iterates the hobby hash through `self`. Following ruby's `Hash#each` The scope inside that iteration is therefore an array of two elements, accessible under `first` and `last`.
52
+
53
+ Another way, that uses wlang higher-level constructions, could be as follows:
54
+
55
+ <ul>
56
+ <table>
57
+ <tr>
58
+ <td>label</td>
59
+ <td>Programming</td>
60
+ </tr>
61
+ <tr>
62
+ <td>url</td>
63
+ <td>http:&#47;&#47;reddit.com&#47;r&#47;programming</td>
64
+ </tr>
65
+ </table>
66
+ <table>
67
+ <tr>
68
+ <td>label</td>
69
+ <td>Music</td>
70
+ </tr>
71
+ <tr>
72
+ <td>url</td>
73
+ <td>http:&#47;&#47;www.music.me&#47;</td>
74
+ </tr>
75
+ </table>
76
+ </ul>
@@ -0,0 +1,16 @@
1
+ Now that we know how to use partials, one might ask how to render a menu in a recursive way. For this, we only need another tag for explicitely manipulating the scope.
2
+
3
+ * sharp (#) renders its second block, in the scope of the value evaluated in first block
4
+
5
+ For the example above, our menu rendering is initiated as follows:
6
+ <ul>
7
+ <li>About</li>
8
+ <li>Products</li>
9
+ <ul>
10
+ <li>WLang</li>
11
+ <li>Alf</li>
12
+ <li>Viiite</li>
13
+ </ul>
14
+ </ul>
15
+
16
+ Note that it is important to keep empty menus in the source data to avoid infinite recursions due the parent scope that already binds a value under `menu`.
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'wlang/html'
3
+ module WLang
4
+ describe Html, "&{...}" do
5
+
6
+ def render(tpl, scope = {})
7
+ Html.render(tpl, scope, "")
8
+ end
9
+
10
+ it 'escapes html' do
11
+ render("&{<script>}", binding).should eq("&lt;script&gt;")
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'wlang/html'
3
+ module WLang
4
+ describe Html, "!{...}" do
5
+
6
+ def render(tpl, scope = {})
7
+ Html.render(tpl, scope, "")
8
+ end
9
+
10
+ it 'invokes to_s' do
11
+ s = Struct.new(:to_s).new("World")
12
+ render("!{hello}", {:hello => s}).should eq("World")
13
+ end
14
+
15
+ it 'works with Numbers' do
16
+ render("!{hello}", {:hello => 12}).should eq("12")
17
+ end
18
+
19
+ it 'does not escape html' do
20
+ render("!{hello}", {:hello => "<script>"}).should eq("<script>")
21
+ end
22
+
23
+ it 'is not too sensitive to spacing' do
24
+ render("!{ hello }", {:hello => "World"}).should eq("World")
25
+ end
26
+
27
+ it 'supports a binding' do
28
+ hello = "World"
29
+ render("!{hello}", binding).should eq("World")
30
+ end
31
+
32
+ it 'supports chain invocations' do
33
+ s = Struct.new(:hello).new("World")
34
+ render("!{s.hello}", binding).should eq("World")
35
+ end
36
+
37
+ end
38
+ end