wlang 0.8.4
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.
- data/LICENCE.rdoc +25 -0
- data/README.rdoc +111 -0
- data/bin/wlang +24 -0
- data/doc/specification/about.rdoc +61 -0
- data/doc/specification/dialects.wtpl +0 -0
- data/doc/specification/examples.rb +3 -0
- data/doc/specification/glossary.wtpl +14 -0
- data/doc/specification/hosting.rdoc +0 -0
- data/doc/specification/overview.rdoc +116 -0
- data/doc/specification/rulesets.wtpl +87 -0
- data/doc/specification/specification.css +52 -0
- data/doc/specification/specification.html +1361 -0
- data/doc/specification/specification.js +8 -0
- data/doc/specification/specification.wtpl +41 -0
- data/doc/specification/specification.yml +430 -0
- data/doc/specification/symbols.wtpl +16 -0
- data/lib/wlang.rb +186 -0
- data/lib/wlang/basic_object.rb +19 -0
- data/lib/wlang/dialect.rb +230 -0
- data/lib/wlang/dialect_dsl.rb +136 -0
- data/lib/wlang/dialect_loader.rb +69 -0
- data/lib/wlang/dialects/coderay_dialect.rb +35 -0
- data/lib/wlang/dialects/plain_text_dialect.rb +75 -0
- data/lib/wlang/dialects/rdoc_dialect.rb +33 -0
- data/lib/wlang/dialects/ruby_dialect.rb +35 -0
- data/lib/wlang/dialects/sql_dialect.rb +38 -0
- data/lib/wlang/dialects/standard_dialects.rb +113 -0
- data/lib/wlang/dialects/xhtml_dialect.rb +40 -0
- data/lib/wlang/encoder.rb +66 -0
- data/lib/wlang/encoder_set.rb +117 -0
- data/lib/wlang/errors.rb +37 -0
- data/lib/wlang/intelligent_buffer.rb +94 -0
- data/lib/wlang/parser.rb +251 -0
- data/lib/wlang/parser_context.rb +146 -0
- data/lib/wlang/ruby_extensions.rb +21 -0
- data/lib/wlang/rule.rb +66 -0
- data/lib/wlang/rule_set.rb +93 -0
- data/lib/wlang/rulesets/basic_ruleset.rb +75 -0
- data/lib/wlang/rulesets/buffering_ruleset.rb +103 -0
- data/lib/wlang/rulesets/context_ruleset.rb +115 -0
- data/lib/wlang/rulesets/encoding_ruleset.rb +73 -0
- data/lib/wlang/rulesets/imperative_ruleset.rb +132 -0
- data/lib/wlang/rulesets/ruleset_utils.rb +296 -0
- data/lib/wlang/template.rb +79 -0
- data/lib/wlang/wlang_command.rb +54 -0
- data/lib/wlang/wlang_command_options.rb +158 -0
- data/test/sandbox.rb +1 -0
- data/test/test_all.rb +8 -0
- data/test/wlang/anagram_bugs_test.rb +111 -0
- data/test/wlang/basic_ruleset_test.rb +52 -0
- data/test/wlang/buffering_ruleset_test.rb +102 -0
- data/test/wlang/buffering_template1.wtpl +1 -0
- data/test/wlang/buffering_template2.wtpl +1 -0
- data/test/wlang/buffering_template3.wtpl +1 -0
- data/test/wlang/buffering_template4.wtpl +1 -0
- data/test/wlang/buffering_template5.wtpl +1 -0
- data/test/wlang/context_ruleset_test.rb +32 -0
- data/test/wlang/data.rb +3 -0
- data/test/wlang/encoder_set_test.rb +42 -0
- data/test/wlang/imperative_ruleset_test.rb +107 -0
- data/test/wlang/intelligent_buffer_test.rb +194 -0
- data/test/wlang/othersymbols_test.rb +16 -0
- data/test/wlang/parser_context_test.rb +29 -0
- data/test/wlang/parser_test.rb +89 -0
- data/test/wlang/plain_text_dialect_test.rb +21 -0
- data/test/wlang/ruby_dialect_test.rb +100 -0
- data/test/wlang/ruby_expected.rb +3 -0
- data/test/wlang/ruby_template.wrb +3 -0
- data/test/wlang/ruleset_utils_test.rb +245 -0
- data/test/wlang/specification_examples_test.rb +52 -0
- data/test/wlang/test_utils.rb +25 -0
- data/test/wlang/wlang_test.rb +80 -0
- metadata +136 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'wlang/basic_object'
|
2
|
+
module WLang
|
3
|
+
class Parser
|
4
|
+
|
5
|
+
#
|
6
|
+
# Execution context of the Parser for <tt>!{wlang/hosted}</tt> and associated
|
7
|
+
# tags. The execution context defines the semantics of executed code in those
|
8
|
+
# tags as well as utilities to handle semantical scoping.
|
9
|
+
#
|
10
|
+
# TODO: define context and scoping semantics more precisely and extend the
|
11
|
+
# documentation
|
12
|
+
#
|
13
|
+
class Context
|
14
|
+
|
15
|
+
# Common methods of scope instances
|
16
|
+
class Scope < WLang::BasicObject
|
17
|
+
attr_accessor :__parent
|
18
|
+
|
19
|
+
end # module Scope
|
20
|
+
|
21
|
+
# Hash scoping mechanism
|
22
|
+
class HashScope < Scope
|
23
|
+
attr_reader :__hash
|
24
|
+
|
25
|
+
# Decorates a hash as a scope.
|
26
|
+
def initialize(hash={}, parent=nil)
|
27
|
+
@__hash = hash
|
28
|
+
@__parent = parent
|
29
|
+
end
|
30
|
+
|
31
|
+
def nil?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def dup
|
36
|
+
HashScope.new(@__hash.dup, @__parent)
|
37
|
+
end
|
38
|
+
|
39
|
+
def __branch(other)
|
40
|
+
HashScope.new(other, self)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Tries to convert found value to a given variable.
|
44
|
+
def method_missing(symbol, *args)
|
45
|
+
varname = symbol.to_s
|
46
|
+
if @__hash.has_key?(varname)
|
47
|
+
@__hash[varname]
|
48
|
+
elsif @__parent
|
49
|
+
@__parent.method_missing(symbol, *args)
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns underlying object
|
56
|
+
def __underlying
|
57
|
+
return @__hash
|
58
|
+
end
|
59
|
+
|
60
|
+
# See Scope#__evaluate
|
61
|
+
def __evaluate(expr)
|
62
|
+
self.instance_eval(expr)
|
63
|
+
end
|
64
|
+
|
65
|
+
# See Scope#__define
|
66
|
+
def __define(key, value);
|
67
|
+
@__hash[key]=value;
|
68
|
+
end
|
69
|
+
|
70
|
+
def /(symb)
|
71
|
+
s = symb.to_s
|
72
|
+
if @__hash.has_key?(s)
|
73
|
+
return WLang::Parser::Context.to_scope(@__hash[s])
|
74
|
+
else
|
75
|
+
return nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def inspect
|
80
|
+
"#{__underlying.inspect} with parent #{@__parent.inspect}"
|
81
|
+
end
|
82
|
+
|
83
|
+
end # class HashScope
|
84
|
+
|
85
|
+
# Creates an empty context on an init scope object.
|
86
|
+
def initialize(init=nil)
|
87
|
+
if (Scope===init)
|
88
|
+
@current_scope = init
|
89
|
+
else
|
90
|
+
@current_scope = HashScope.new
|
91
|
+
push(init) unless init.nil?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Evaluates a ruby expression on the current context.
|
96
|
+
def evaluate(expression)
|
97
|
+
if "self" == expression.strip
|
98
|
+
@current_scope
|
99
|
+
elsif /[a-z]+(\/[a-z]+)+/ =~ expression
|
100
|
+
expression = ("self/" + expression).gsub(/\//,"/:")
|
101
|
+
expr = @current_scope.__evaluate(expression)
|
102
|
+
expr = expr.__underlying if Scope===expr
|
103
|
+
return expr
|
104
|
+
else
|
105
|
+
@current_scope.__evaluate(expression)
|
106
|
+
end
|
107
|
+
rescue Exception => ex
|
108
|
+
puts "Warning, some wlang exception when evaluating the expression\n#{expression}"
|
109
|
+
puts "Message was: #{ex.message}"
|
110
|
+
puts ex.backtrace.join("\n")
|
111
|
+
puts "Current scope was:\n"
|
112
|
+
puts @current_scope.__underlying.inspect
|
113
|
+
return nil
|
114
|
+
end
|
115
|
+
|
116
|
+
# Pushes a new scope instance.
|
117
|
+
def push(who={})
|
118
|
+
who = WLang::Parser::Context.to_scope(who)
|
119
|
+
who.__parent = @current_scope
|
120
|
+
@current_scope = who
|
121
|
+
end
|
122
|
+
|
123
|
+
# Pops the last added scope.
|
124
|
+
def pop
|
125
|
+
parent = @current_scope.__parent
|
126
|
+
raise "Bad scope usage, nothing to pop" if parent.nil?
|
127
|
+
@current_scope = parent
|
128
|
+
end
|
129
|
+
|
130
|
+
# Defines a variable/value mapping in the current scope.
|
131
|
+
def define(key, value)
|
132
|
+
@current_scope.__define(key,value)
|
133
|
+
end
|
134
|
+
|
135
|
+
# Converts a given instance to a Scope.
|
136
|
+
def self.to_scope(who)
|
137
|
+
return who if Scope===who
|
138
|
+
return who.to_wlang_scope if who.respond_to?(:to_wlang_scope)
|
139
|
+
return HashScope.new(who) if Hash===who
|
140
|
+
return who
|
141
|
+
end
|
142
|
+
|
143
|
+
end # class Context
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Installs _wlang_ utility methods on Ruby String.
|
3
|
+
#
|
4
|
+
class String
|
5
|
+
|
6
|
+
# Converts the string to a wlang template
|
7
|
+
def wlang_template(dialect="wlang/active-string", context=nil, block_symbols=:braces)
|
8
|
+
WLang::Template.new(self, dialect, context, block_symbols)
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# Instantiates the string as a wlang template using
|
13
|
+
# a context object and a dialect.
|
14
|
+
#
|
15
|
+
def wlang_instantiate(context=nil, dialect="wlang/active-string", block_symbols=:braces)
|
16
|
+
wlang_template(dialect, context, block_symbols).instantiate
|
17
|
+
end
|
18
|
+
alias :wlang :wlang_instantiate
|
19
|
+
|
20
|
+
end
|
21
|
+
|
data/lib/wlang/rule.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module WLang
|
2
|
+
|
3
|
+
#
|
4
|
+
# A Rule is designed to perform a replacement job when the special tag associated
|
5
|
+
# with it is found in a Template. Rules are always installed on a RuleSet (using
|
6
|
+
# RuleSet#add_rule), which is itself installed on a Dialect. Note that the method
|
7
|
+
# mentionned previously provides a DRY shortcut, allowing not using this class
|
8
|
+
# directly.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
# # Rule subclassing can be avoided by providing a block to new
|
12
|
+
# # The following rule job is to upcase the text inside +{...} tags:
|
13
|
+
# rule = Rule.new do |parser,offset|
|
14
|
+
# parsed, reached = parser.parse(offset)
|
15
|
+
# [parsed.upcase, reached]
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Creating a a new rule can be made in two ways: by subclassing this class and
|
19
|
+
# overriding the start_tag method or by passing a block to new. In both cases,
|
20
|
+
# <b>rules should always be stateless</b>, to allow reusable dialects that could
|
21
|
+
# even be used in a multi-threading environment. Implementing a rule correctly
|
22
|
+
# must be considered non trivial due to the strong protocol between the parser
|
23
|
+
# and its rules and the stateless convention. Always have a look to helpers
|
24
|
+
# provided by RuleSet (to create simple rules easily) before deciding to implement
|
25
|
+
# a rule using this class.
|
26
|
+
#
|
27
|
+
# == Detailed API
|
28
|
+
class Rule
|
29
|
+
|
30
|
+
#
|
31
|
+
# Creates a new rule. If no block is given, the invocation of new MUST be made
|
32
|
+
# on a subclass overriding start_tag. Otherwise, the block is considered as the
|
33
|
+
# effective stateless implementation of start_tag and will be called with the
|
34
|
+
# same arguments.
|
35
|
+
#
|
36
|
+
def initialize(&block)
|
37
|
+
unless block.nil?
|
38
|
+
raise(ArgumentError, "Expected a rule block of arity 2")\
|
39
|
+
unless block.arity==2
|
40
|
+
end
|
41
|
+
@block = block
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Fired when the parser has reached an offset matching this rule.
|
46
|
+
#
|
47
|
+
# This method MUST return an array [_replacement_, _offset_] where _replacement_
|
48
|
+
# is what replaces the tag itself in the resulting text and _offset_ is the
|
49
|
+
# new offset reached in the source text (where parsing will continue).
|
50
|
+
# _offset_ should always be such that <tt>text[offset,1]=='}'</tt> to allow
|
51
|
+
# higher stages to continue their job correctly. Utility methods for parsing
|
52
|
+
# text parts are provided by the parser itself (see WLang::Parser).
|
53
|
+
#
|
54
|
+
# Arguments:
|
55
|
+
# - parser: WLang parser currently parsing the text.
|
56
|
+
# - offset: offset reached in the text, corresponding to the first character
|
57
|
+
# of the first block associated with the matching tag.
|
58
|
+
#
|
59
|
+
def start_tag(parser, offset)
|
60
|
+
raise(NotImplementedError) unless @block
|
61
|
+
@block.call(parser, offset)
|
62
|
+
end
|
63
|
+
|
64
|
+
end # class Rule
|
65
|
+
|
66
|
+
end # module WLang
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'wlang/rule'
|
2
|
+
module WLang
|
3
|
+
|
4
|
+
#
|
5
|
+
# This class allows grouping matching rules together to build a given dialect.
|
6
|
+
# Rules are always added with add_rule, which also allows creating simple rules
|
7
|
+
# on the fly (that is, without subclassing Rule).
|
8
|
+
#
|
9
|
+
# Examples:
|
10
|
+
# # we will create a simple dialect with a special tag:
|
11
|
+
# # <tt>+{...}</tt> which will uppercase its contents
|
12
|
+
# upcaser = RuleSet.new
|
13
|
+
# upcaser.add_rule '+' do |parser,offset|
|
14
|
+
# parsed, offset = parser.parse(offset)
|
15
|
+
# [parsed.upcase, offset]
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# == Detailed API
|
19
|
+
class RuleSet
|
20
|
+
|
21
|
+
#
|
22
|
+
# Creates an new dialect rule set.
|
23
|
+
#
|
24
|
+
def initialize() @rules, @pattern = {}, nil; end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Adds a tag matching rule to this rule set. _tag_ must be a String with the
|
28
|
+
# tag associated to the rule (without the '{', that is '$' for the tag ${...}
|
29
|
+
# for example. If rule is ommited and a block is given, a new Rule instance is
|
30
|
+
# created on the fly with _block_ as implementation (see Rule#new).
|
31
|
+
# Otherwise rule is expected to be a Rule instance. This method check its
|
32
|
+
# arguments, raising an ArgumentError if incorrect.
|
33
|
+
#
|
34
|
+
def add_rule(tag, rule=nil, &block)
|
35
|
+
if rule.nil?
|
36
|
+
raise(ArgumentError,"Block required") unless block_given?
|
37
|
+
rule = Rule.new(&block)
|
38
|
+
end
|
39
|
+
raise(ArgumentError, "Rule expected") unless Rule===rule
|
40
|
+
@rules[tag] = rule
|
41
|
+
@pattern = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Add rules defined in a given RuleSet module.
|
46
|
+
#
|
47
|
+
def add_rules(mod, pairs=nil)
|
48
|
+
raise(ArgumentError,"Module expected") unless Module===mod
|
49
|
+
pairs = mod::DEFAULT_RULESET if pairs.nil?
|
50
|
+
pairs.each_pair do |symbol,method|
|
51
|
+
meth = mod.method(method)
|
52
|
+
raise(ArgumentError,"No such method: #{method}") if meth.nil?
|
53
|
+
add_rule(symbol, &meth.to_proc)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Returns a Regexp instance with recognizes all tags installed in the rule set.
|
59
|
+
# The returned Regexp is backslashing aware (it matches <tt>\${</tt> for example)
|
60
|
+
# as well as '{' and '}' aware. This pattern is used by WLang::Parser and is
|
61
|
+
# not intended to be used by users themselve.
|
62
|
+
#
|
63
|
+
def pattern(block_symbols)
|
64
|
+
build_pattern(block_symbols);
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Returns the Rule associated with a given tag, _nil_ if no such rule.
|
69
|
+
#
|
70
|
+
def [](tag) @rules[tag]; end
|
71
|
+
|
72
|
+
|
73
|
+
### protected section ######################################################
|
74
|
+
protected
|
75
|
+
|
76
|
+
# Internal implementation of pattern.
|
77
|
+
def build_pattern(block_symbols)
|
78
|
+
start, stop = WLang::Template::BLOCK_SYMBOLS[block_symbols]
|
79
|
+
start, stop = Regexp.escape(start), Regexp.escape(stop)
|
80
|
+
s = '([\\\\]{0,2}('
|
81
|
+
i=0
|
82
|
+
@rules.each_key do |tag|
|
83
|
+
s << '|' if i>0
|
84
|
+
s << '(' << Regexp.escape(tag) << ')'
|
85
|
+
i += 1
|
86
|
+
end
|
87
|
+
s << ")#{start})|[\\\\]{0,2}#{start}|[\\\\]{0,2}#{stop}"
|
88
|
+
Regexp.new(s)
|
89
|
+
end
|
90
|
+
|
91
|
+
end # class RuleSet
|
92
|
+
|
93
|
+
end # module WLang
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'wlang/rulesets/ruleset_utils'
|
2
|
+
module WLang
|
3
|
+
class RuleSet
|
4
|
+
|
5
|
+
#
|
6
|
+
# Basic ruleset, commonly included by any wlang dialect (but some tags, like
|
7
|
+
# <tt>${...}</tt> may be overriden). This ruleset is often installed conjointly
|
8
|
+
# with WLang::RuleSet::Encoding which provides interresting overridings of
|
9
|
+
# <tt>${...}</tt> and <tt>+{...}</tt>.
|
10
|
+
#
|
11
|
+
# For an overview of this ruleset, see the wlang {specification file}[link://files/specification.html].
|
12
|
+
#
|
13
|
+
module Basic
|
14
|
+
U=WLang::RuleSet::Utils
|
15
|
+
|
16
|
+
# Default mapping between tag symbols and methods
|
17
|
+
DEFAULT_RULESET = {'!' => :execution, '%' => :modulation, '^' => :encoding,
|
18
|
+
'+' => :inclusion, '$' => :injection, '%!' => :recursive_application}
|
19
|
+
|
20
|
+
# Rule implementation of <tt>!{wlang/ruby}</tt>.
|
21
|
+
def self.execution(parser, offset)
|
22
|
+
expression, reached = parser.parse(offset, "wlang/ruby")
|
23
|
+
value = parser.evaluate(expression)
|
24
|
+
result = value.nil? ? "" : value.to_s
|
25
|
+
[result, reached]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Rule implementation of <tt>%{wlang/active-string}{...}</tt>.
|
29
|
+
def self.modulation(parser, offset)
|
30
|
+
dialect, reached = parser.parse(offset, "wlang/active-string")
|
31
|
+
result, reached = parser.parse_block(reached, dialect)
|
32
|
+
[result, reached]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Rule implementation of <tt>^{wlang/active-string}{...}</tt>
|
36
|
+
def self.encoding(parser, offset)
|
37
|
+
encoder, reached = parser.parse(offset, "wlang/active-string")
|
38
|
+
result, reached = parser.parse_block(reached)
|
39
|
+
result = parser.encode(result, encoder)
|
40
|
+
[result, reached]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Rule implementation of <tt>${wlang/ruby}</tt>
|
44
|
+
def self.injection(parser, offset)
|
45
|
+
execution(parser, offset)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Rule implementation of <tt>+{wlang/ruby}</tt>
|
49
|
+
def self.inclusion(parser, offset)
|
50
|
+
execution(parser, offset)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Rule implementation of <tt>%!{wlang/ruby using ... with ...}</tt>
|
54
|
+
def self.recursive_application(parser, offset)
|
55
|
+
dialect, reached = parser.parse(offset, "wlang/active-string")
|
56
|
+
text, reached = parser.parse_block(reached)
|
57
|
+
|
58
|
+
# decode expression
|
59
|
+
decoded = U.expr(:qdialect,
|
60
|
+
["using", :expr, false],
|
61
|
+
["with", :with, false]).decode(dialect, parser)
|
62
|
+
parser.syntax_error(offset) if decoded.nil?
|
63
|
+
|
64
|
+
# build context
|
65
|
+
context = U.context_from_using_and_with(decoded)
|
66
|
+
|
67
|
+
# instantiate
|
68
|
+
instantiated = WLang::instantiate(text, context, decoded[:qdialect])
|
69
|
+
[instantiated, reached]
|
70
|
+
end
|
71
|
+
|
72
|
+
end # module Basic
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'wlang/rulesets/ruleset_utils'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module WLang
|
5
|
+
class RuleSet
|
6
|
+
|
7
|
+
#
|
8
|
+
# Buffering ruleset, providing special tags to load/instantiate accessible files
|
9
|
+
# and outputting instantiation results in other files.
|
10
|
+
#
|
11
|
+
# For an overview of this ruleset, see the wlang {specification file}[link://files/specification.html].
|
12
|
+
#
|
13
|
+
module Buffering
|
14
|
+
U=WLang::RuleSet::Utils
|
15
|
+
|
16
|
+
# Default mapping between tag symbols and methods
|
17
|
+
DEFAULT_RULESET = {'<<' => :input, '>>' => :output,
|
18
|
+
'<<=' => :data_assignment, '<<+' => :input_inclusion}
|
19
|
+
|
20
|
+
# Rule implementation of <tt><<{wlang/uri}</tt>
|
21
|
+
def self.input(parser, offset)
|
22
|
+
uri, reached = parser.parse(offset, "wlang/uri")
|
23
|
+
file = parser.template.file_resolve(uri, true)
|
24
|
+
[File.read(file), reached]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Rule implementation of <tt>>>{wlang/uri}</tt>
|
28
|
+
def self.output(parser, offset)
|
29
|
+
uri, reached = parser.parse(offset, "wlang/uri")
|
30
|
+
file = parser.template.file_resolve(uri, false)
|
31
|
+
dir = File.dirname(file)
|
32
|
+
FileUtils.mkdir_p(dir) unless File.exists?(dir)
|
33
|
+
File.open(file, "w") do |file|
|
34
|
+
text, reached = parser.parse_block(reached, nil, file)
|
35
|
+
end
|
36
|
+
["", reached]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Rule implementation of <<={wlang/uri as x}{...}
|
40
|
+
def self.data_assignment(parser, offset)
|
41
|
+
uri, reached = parser.parse(offset, "wlang/uri")
|
42
|
+
|
43
|
+
# decode expression
|
44
|
+
decoded = U.decode_uri_as(uri)
|
45
|
+
parser.syntax_error(offset) if decoded.nil?
|
46
|
+
|
47
|
+
file = parser.template.file_resolve(decoded[:uri], true)
|
48
|
+
data = WLang::load_data(file)
|
49
|
+
|
50
|
+
# handle two different cases
|
51
|
+
if parser.has_block?(reached)
|
52
|
+
parser.context_push(decoded[:variable] => data)
|
53
|
+
text, reached = parser.parse_block(reached)
|
54
|
+
parser.context_pop
|
55
|
+
[text, reached]
|
56
|
+
else
|
57
|
+
parser.context_define(decoded[:variable], data)
|
58
|
+
["", reached]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Rule implementation of <<+{wlang/uri with ...}
|
63
|
+
def self.input_inclusion(parser, offset)
|
64
|
+
uri, reached = parser.parse(offset, "wlang/uri")
|
65
|
+
|
66
|
+
# decode expression
|
67
|
+
decoded = U.expr(:uri,
|
68
|
+
["using", :using, false],
|
69
|
+
["with", :with, false]).decode(uri, parser)
|
70
|
+
parser.syntax_error(offset) if decoded.nil?
|
71
|
+
|
72
|
+
# handle wit
|
73
|
+
context = nil
|
74
|
+
if decoded[:using]
|
75
|
+
raise "<<+ does not support multiple with for now." if decoded[:using].size != 1
|
76
|
+
context = decoded[:using][0]
|
77
|
+
raise "Unexpected nil context when duplicated" if context.nil?
|
78
|
+
else
|
79
|
+
context = {}
|
80
|
+
end
|
81
|
+
|
82
|
+
# handle using now
|
83
|
+
if decoded[:with]
|
84
|
+
case context
|
85
|
+
when WLang::Parser::Context::HashScope
|
86
|
+
context = context.__branch(decoded[:with])
|
87
|
+
when Hash
|
88
|
+
context = context.merge(decoded[:with])
|
89
|
+
else
|
90
|
+
raise "Unexpected context #{context}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
file = parser.template.file_resolve(decoded[:uri], true)
|
95
|
+
instantiated = WLang::file_instantiate(file, context)
|
96
|
+
[instantiated, reached]
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
end # module Buffering
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|