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.
- data/CHANGELOG.md +3 -121
- data/Gemfile +23 -1
- data/Gemfile.lock +32 -28
- data/LICENCE.md +18 -21
- data/Manifest.txt +4 -5
- data/README.md +100 -174
- data/Rakefile +1 -13
- data/bin/wlang +3 -29
- data/lib/wlang.rb +21 -394
- data/lib/wlang/command.rb +94 -0
- data/lib/wlang/compiler.rb +78 -0
- data/lib/wlang/compiler/autospacing.rb +60 -0
- data/lib/wlang/compiler/dialect_enforcer.rb +91 -0
- data/lib/wlang/compiler/filter.rb +32 -0
- data/lib/wlang/compiler/grammar.citrus +67 -0
- data/lib/wlang/compiler/parser.rb +26 -0
- data/lib/wlang/compiler/proc_call_removal.rb +15 -0
- data/lib/wlang/compiler/static_merger.rb +28 -0
- data/lib/wlang/compiler/strconcat_flattener.rb +25 -0
- data/lib/wlang/compiler/to_ruby_abstraction.rb +22 -0
- data/lib/wlang/compiler/to_ruby_code.rb +55 -0
- data/lib/wlang/dialect.rb +40 -237
- data/lib/wlang/dialect/dispatching.rb +51 -0
- data/lib/wlang/dialect/evaluation.rb +30 -0
- data/lib/wlang/dialect/tags.rb +50 -0
- data/lib/wlang/dummy.rb +32 -0
- data/lib/wlang/html.rb +106 -0
- data/lib/wlang/loader.rb +6 -0
- data/lib/wlang/mustang.rb +90 -0
- data/lib/wlang/scope.rb +57 -0
- data/lib/wlang/scope/binding_scope.rb +18 -0
- data/lib/wlang/scope/object_scope.rb +25 -0
- data/lib/wlang/scope/proxy_scope.rb +18 -0
- data/lib/wlang/scope/root_scope.rb +24 -0
- data/lib/wlang/template.rb +16 -86
- data/lib/wlang/version.rb +9 -8
- data/spec/fixtures/dialect/foobar.rb +31 -0
- data/spec/fixtures/dialect/upcasing.rb +13 -0
- data/spec/fixtures/templates/hello.tpl +1 -0
- data/spec/integration/examples/1-basics.txt +65 -0
- data/spec/integration/examples/2-imperative.txt +51 -0
- data/spec/integration/examples/3-partials.txt +76 -0
- data/spec/integration/examples/4-recursion.txt +16 -0
- data/spec/integration/html/test_ampersand.rb +15 -0
- data/spec/integration/html/test_bang.rb +38 -0
- data/spec/integration/html/test_caret.rb +33 -0
- data/spec/integration/html/test_dollar.rb +16 -0
- data/spec/integration/html/test_greater.rb +23 -0
- data/spec/integration/html/test_modulo.rb +16 -0
- data/spec/integration/html/test_plus.rb +48 -0
- data/spec/integration/html/test_question.rb +33 -0
- data/spec/integration/html/test_sharp.rb +21 -0
- data/spec/integration/html/test_slash.rb +16 -0
- data/spec/integration/html/test_star.rb +37 -0
- data/spec/integration/test_dummy.rb +51 -0
- data/spec/integration/test_examples.rb +29 -0
- data/spec/integration/test_mustang.rb +120 -0
- data/spec/integration/test_readme.rb +56 -0
- data/spec/integration/test_upcasing.rb +22 -0
- data/spec/spec_helper.rb +62 -1
- data/spec/test_wlang.rb +101 -0
- data/spec/unit/compiler/autospacing/test_right_strip.rb +30 -0
- data/spec/unit/compiler/autospacing/test_unindent.rb +30 -0
- data/spec/unit/compiler/test_dialect_enforcer.rb +168 -0
- data/spec/unit/compiler/test_grammar.rb +207 -0
- data/spec/unit/compiler/test_parser.rb +69 -0
- data/spec/unit/compiler/test_proc_call_removal.rb +24 -0
- data/spec/unit/compiler/test_static_merger.rb +29 -0
- data/spec/unit/compiler/test_strconcat_flattener.rb +30 -0
- data/spec/unit/compiler/test_to_ruby_abstraction.rb +59 -0
- data/spec/unit/compiler/test_to_ruby_code.rb +24 -0
- data/spec/unit/dialect/test_compile.rb +52 -0
- data/spec/unit/dialect/test_dispatching.rb +19 -0
- data/spec/unit/dialect/test_evaluate.rb +41 -0
- data/spec/unit/dialect/test_render.rb +33 -0
- data/spec/unit/dialect/test_tags.rb +32 -0
- data/spec/unit/dialect/test_with_scope.rb +18 -0
- data/spec/unit/scope/test_binding_scope.rb +27 -0
- data/spec/unit/scope/test_coerce.rb +22 -0
- data/spec/unit/scope/test_object_scope.rb +38 -0
- data/spec/unit/scope/test_proxy_scope.rb +22 -0
- data/spec/unit/scope/test_root_scope.rb +22 -0
- data/spec/unit/test_assumptions.rb +29 -0
- data/spec/unit/test_scope.rb +57 -0
- data/tasks/debug_mail.rake +42 -45
- data/tasks/gem.rake +22 -17
- data/tasks/spec_test.rake +9 -17
- data/tasks/unit_test.rake +11 -12
- data/tasks/yard.rake +13 -13
- data/wlang.gemspec +36 -32
- data/wlang.noespec +27 -35
- metadata +268 -451
- data/doc/specification/about.rdoc +0 -61
- data/doc/specification/analytics.wtpl +0 -13
- data/doc/specification/dialect.wtpl +0 -14
- data/doc/specification/dialects.wtpl +0 -3
- data/doc/specification/examples.rb +0 -3
- data/doc/specification/glossary.wtpl +0 -14
- data/doc/specification/hosting.rdoc +0 -0
- data/doc/specification/overview.rdoc +0 -116
- data/doc/specification/rulesets.wtpl +0 -87
- data/doc/specification/specification.css +0 -53
- data/doc/specification/specification.html +0 -1690
- data/doc/specification/specification.js +0 -8
- data/doc/specification/specification.wtpl +0 -42
- data/doc/specification/specification.yml +0 -432
- data/doc/specification/symbols.wtpl +0 -16
- data/lib/wlang/dialect_dsl.rb +0 -141
- data/lib/wlang/dialect_loader.rb +0 -74
- data/lib/wlang/dialects/bluecloth_dialect.rb +0 -16
- data/lib/wlang/dialects/coderay_dialect.rb +0 -45
- data/lib/wlang/dialects/hosted_dialect.rb +0 -50
- data/lib/wlang/dialects/plain_text_dialect.rb +0 -69
- data/lib/wlang/dialects/rdoc_dialect.rb +0 -33
- data/lib/wlang/dialects/redcloth_dialect.rb +0 -16
- data/lib/wlang/dialects/ruby_dialect.rb +0 -118
- data/lib/wlang/dialects/sql_dialect.rb +0 -38
- data/lib/wlang/dialects/standard_dialects.rb +0 -181
- data/lib/wlang/dialects/xhtml_dialect.rb +0 -63
- data/lib/wlang/dialects/yaml_dialect.rb +0 -30
- data/lib/wlang/encoder.rb +0 -62
- data/lib/wlang/encoder_set.rb +0 -122
- data/lib/wlang/errors.rb +0 -80
- data/lib/wlang/ext/hash_methodize.rb +0 -13
- data/lib/wlang/ext/string.rb +0 -44
- data/lib/wlang/hash_scope.rb +0 -89
- data/lib/wlang/hosted_language.rb +0 -146
- data/lib/wlang/intelligent_buffer.rb +0 -94
- data/lib/wlang/parser.rb +0 -332
- data/lib/wlang/parser_state.rb +0 -94
- data/lib/wlang/rule.rb +0 -66
- data/lib/wlang/rule_set.rb +0 -106
- data/lib/wlang/rulesets/basic_ruleset.rb +0 -83
- data/lib/wlang/rulesets/buffering_ruleset.rb +0 -115
- data/lib/wlang/rulesets/context_ruleset.rb +0 -111
- data/lib/wlang/rulesets/encoding_ruleset.rb +0 -73
- data/lib/wlang/rulesets/imperative_ruleset.rb +0 -132
- data/lib/wlang/rulesets/ruleset_utils.rb +0 -317
- data/lib/wlang/wlang_command.rb +0 -51
- data/lib/wlang/wlang_command_options.rb +0 -163
- data/spec/basic_object.spec +0 -40
- data/spec/coderay_dialect.spec +0 -8
- data/spec/dialect/apply_post_transform.spec +0 -16
- data/spec/global_extensions.rb +0 -2
- data/spec/hash_scope.spec +0 -76
- data/spec/redcloth_dialect.spec +0 -24
- data/spec/test_all.rb +0 -8
- data/spec/wlang.spec +0 -53
- data/spec/wlang_spec.rb +0 -8
- data/spec/xhtml_dialect.spec +0 -22
- data/tasks/genspec.rake +0 -5
- data/test/blackbox/basic/execution_1.exp +0 -1
- data/test/blackbox/basic/execution_1.tpl +0 -1
- data/test/blackbox/basic/execution_2.exp +0 -1
- data/test/blackbox/basic/execution_2.tpl +0 -1
- data/test/blackbox/basic/execution_3.exp +0 -1
- data/test/blackbox/basic/execution_3.tpl +0 -1
- data/test/blackbox/basic/execution_4.exp +0 -1
- data/test/blackbox/basic/execution_4.tpl +0 -1
- data/test/blackbox/basic/inclusion_1.exp +0 -1
- data/test/blackbox/basic/inclusion_1.tpl +0 -1
- data/test/blackbox/basic/inclusion_2.exp +0 -1
- data/test/blackbox/basic/inclusion_2.tpl +0 -1
- data/test/blackbox/basic/injection_1.exp +0 -1
- data/test/blackbox/basic/injection_1.tpl +0 -1
- data/test/blackbox/basic/injection_2.exp +0 -1
- data/test/blackbox/basic/injection_2.tpl +0 -1
- data/test/blackbox/basic/modulation_1.exp +0 -1
- data/test/blackbox/basic/modulation_1.tpl +0 -1
- data/test/blackbox/basic/modulation_2.exp +0 -1
- data/test/blackbox/basic/modulation_2.tpl +0 -1
- data/test/blackbox/basic/recursive_app_1.exp +0 -1
- data/test/blackbox/basic/recursive_app_1.tpl +0 -1
- data/test/blackbox/basic/recursive_app_2.exp +0 -1
- data/test/blackbox/basic/recursive_app_2.tpl +0 -1
- data/test/blackbox/buffering/data_1.rb +0 -1
- data/test/blackbox/buffering/data_assignment_1.exp +0 -1
- data/test/blackbox/buffering/data_assignment_1.tpl +0 -1
- data/test/blackbox/buffering/data_assignment_2.exp +0 -1
- data/test/blackbox/buffering/data_assignment_2.tpl +0 -1
- data/test/blackbox/buffering/data_assignment_3.exp +0 -1
- data/test/blackbox/buffering/data_assignment_3.tpl +0 -1
- data/test/blackbox/buffering/data_assignment_4.exp +0 -1
- data/test/blackbox/buffering/data_assignment_4.tpl +0 -1
- data/test/blackbox/buffering/input_1.exp +0 -1
- data/test/blackbox/buffering/input_1.tpl +0 -1
- data/test/blackbox/buffering/input_2.exp +0 -1
- data/test/blackbox/buffering/input_2.tpl +0 -1
- data/test/blackbox/buffering/input_3.exp +0 -1
- data/test/blackbox/buffering/input_3.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion.exp +0 -1
- data/test/blackbox/buffering/input_inclusion.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_1.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_1.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_2.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_2.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_3.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_3.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_4.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_4.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_5.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_5.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_6.exp +0 -1
- data/test/blackbox/buffering/input_inclusion_6.tpl +0 -1
- data/test/blackbox/buffering/input_inclusion_7.exp +0 -0
- data/test/blackbox/buffering/input_inclusion_7.tpl +0 -1
- data/test/blackbox/buffering/text_1.txt +0 -1
- data/test/blackbox/buffering/wlang.txt +0 -1
- data/test/blackbox/context/assignment_1.exp +0 -1
- data/test/blackbox/context/assignment_1.tpl +0 -1
- data/test/blackbox/context/assignment_2.exp +0 -1
- data/test/blackbox/context/assignment_2.tpl +0 -1
- data/test/blackbox/context/assignment_3.exp +0 -2
- data/test/blackbox/context/assignment_3.tpl +0 -2
- data/test/blackbox/context/assignment_4.exp +0 -1
- data/test/blackbox/context/assignment_4.tpl +0 -1
- data/test/blackbox/context/block_assignment_1.exp +0 -1
- data/test/blackbox/context/block_assignment_1.tpl +0 -1
- data/test/blackbox/context/block_assignment_2.exp +0 -1
- data/test/blackbox/context/block_assignment_2.tpl +0 -1
- data/test/blackbox/context/modulo_assignment_1.exp +0 -1
- data/test/blackbox/context/modulo_assignment_1.tpl +0 -1
- data/test/blackbox/context/modulo_assignment_2.exp +0 -1
- data/test/blackbox/context/modulo_assignment_2.tpl +0 -1
- data/test/blackbox/data_1.rb +0 -1
- data/test/blackbox/postblock/hello.exp +0 -1
- data/test/blackbox/postblock/hello.pre +0 -1
- data/test/blackbox/postblock/hello.tpl +0 -1
- data/test/blackbox/postblock/hello_input_inclusion.exp +0 -1
- data/test/blackbox/postblock/hello_input_inclusion.tpl +0 -1
- data/test/blackbox/postblock/hello_to_authors.exp +0 -1
- data/test/blackbox/postblock/hello_to_authors.tpl +0 -1
- data/test/blackbox/poststring/hello.exp +0 -1
- data/test/blackbox/poststring/hello.tpl +0 -1
- data/test/blackbox/test_all.rb +0 -70
- data/test/standard_dialects/ruby/data.rb +0 -7
- data/test/standard_dialects/ruby/inclusion.exp +0 -6
- data/test/standard_dialects/ruby/inclusion.tpl +0 -6
- data/test/standard_dialects/test_all.rb +0 -29
- data/test/standard_dialects/yaml/assumptions_test.rb +0 -13
- data/test/standard_dialects/yaml/data.rb +0 -3
- data/test/standard_dialects/yaml/inclusion_1.exp +0 -7
- data/test/standard_dialects/yaml/inclusion_1.tpl +0 -2
- data/test/standard_dialects/yaml/inclusion_2.exp +0 -5
- data/test/standard_dialects/yaml/inclusion_2.tpl +0 -3
- data/test/unit/test_all.rb +0 -9
- data/test/unit/wlang/anagram_bugs_test.rb +0 -111
- data/test/unit/wlang/basic_ruleset_test.rb +0 -52
- data/test/unit/wlang/buffering_ruleset_test.rb +0 -102
- data/test/unit/wlang/buffering_template1.wtpl +0 -1
- data/test/unit/wlang/buffering_template2.wtpl +0 -1
- data/test/unit/wlang/buffering_template3.wtpl +0 -1
- data/test/unit/wlang/buffering_template4.wtpl +0 -1
- data/test/unit/wlang/buffering_template5.wtpl +0 -1
- data/test/unit/wlang/context_ruleset_test.rb +0 -32
- data/test/unit/wlang/data.rb +0 -3
- data/test/unit/wlang/encoder_set_test.rb +0 -42
- data/test/unit/wlang/imperative_ruleset_test.rb +0 -107
- data/test/unit/wlang/intelligent_buffer_test.rb +0 -194
- data/test/unit/wlang/othersymbols_test.rb +0 -16
- data/test/unit/wlang/parser_test.rb +0 -88
- data/test/unit/wlang/plain_text_dialect_test.rb +0 -21
- data/test/unit/wlang/ruby_dialect_test.rb +0 -100
- data/test/unit/wlang/ruby_expected.rb +0 -3
- data/test/unit/wlang/ruby_template.wrb +0 -3
- data/test/unit/wlang/ruleset_utils_test.rb +0 -245
- data/test/unit/wlang/specification_examples_test.rb +0 -54
- data/test/unit/wlang/test_utils.rb +0 -25
- data/test/unit/wlang/wlang_test.rb +0 -80
data/lib/wlang/template.rb
CHANGED
@@ -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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
44
|
-
|
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
|
-
|
19
|
+
buffer
|
49
20
|
end
|
50
21
|
end
|
51
|
-
|
52
|
-
|
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
|
data/lib/wlang/version.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
module WLang
|
2
2
|
module Version
|
3
|
-
|
4
|
-
MAJOR =
|
5
|
-
MINOR =
|
6
|
-
TINY =
|
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 @@
|
|
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 <script>injected code</script> !
|
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
|
+
<script>some attacker attempt to inject code</script>
|
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
|
+
<script>injected code</script> is a shortcut for the equivalent expression <script>injected code</script>
|
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://reddit.com/r/programming">Programming</a></li>
|
11
|
+
<li><a href="http://www.music.me/">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://reddit.com/r/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://www.music.me/</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://reddit.com/r/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://www.music.me/</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("<script>")
|
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
|