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.
- 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/Rakefile
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
begin
|
|
2
|
-
gem "bundler", "~> 1.0"
|
|
3
|
-
require "bundler/setup"
|
|
4
|
-
rescue LoadError => ex
|
|
5
|
-
puts ex.message
|
|
6
|
-
abort "Bundler failed to load, (did you run 'gem install bundler' ?)"
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
# Dynamically load the gem spec
|
|
10
|
-
$gemspec_file = File.expand_path('../wlang.gemspec', __FILE__)
|
|
11
|
-
$gemspec = Kernel.eval(File.read($gemspec_file))
|
|
12
|
-
|
|
13
1
|
# We run tests by default
|
|
14
2
|
task :default => :test
|
|
15
3
|
|
|
@@ -19,5 +7,5 @@ task :default => :test
|
|
|
19
7
|
# See .rake files there for complete documentation.
|
|
20
8
|
#
|
|
21
9
|
Dir["tasks/*.rake"].each do |taskfile|
|
|
22
|
-
|
|
10
|
+
load taskfile
|
|
23
11
|
end
|
data/bin/wlang
CHANGED
|
@@ -1,30 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# Copyright (c) 2009 University of Louvain, Bernard & Louis Lambeau
|
|
7
|
-
# Released under a MIT or Ruby licence
|
|
8
|
-
#
|
|
9
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
10
|
-
require 'wlang'
|
|
11
|
-
require 'wlang/wlang_command'
|
|
12
|
-
|
|
13
|
-
begin
|
|
14
|
-
r = WLang::WLangCommand.new
|
|
15
|
-
r.run ARGV
|
|
16
|
-
rescue ::WLang::Error => e
|
|
17
|
-
$stderr.puts e.message
|
|
18
|
-
$stderr.puts e.wlang_backtrace.join("\n\t")
|
|
19
|
-
$stderr.puts e.backtrace.join("\n\t")
|
|
20
|
-
rescue Interrupt => e
|
|
21
|
-
$stderr.puts
|
|
22
|
-
$stderr.puts "Interrupted"
|
|
23
|
-
raise e
|
|
24
|
-
rescue OptionParser::ParseError => e
|
|
25
|
-
$stderr.puts e.message
|
|
26
|
-
raise e
|
|
27
|
-
rescue => e
|
|
28
|
-
$stderr.puts e.message
|
|
29
|
-
raise e
|
|
30
|
-
end
|
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
|
3
|
+
require 'wlang/command'
|
|
4
|
+
WLang::Command.run(ARGV)
|
data/lib/wlang.rb
CHANGED
|
@@ -1,407 +1,34 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require 'wlang/ext/string'
|
|
4
|
-
require 'stringio'
|
|
5
|
-
require 'wlang/rule'
|
|
6
|
-
require 'wlang/rule_set'
|
|
7
|
-
require 'wlang/encoder_set'
|
|
8
|
-
require 'wlang/dialect'
|
|
9
|
-
require 'wlang/dialect_dsl'
|
|
10
|
-
require 'wlang/dialect_loader'
|
|
11
|
-
require 'wlang/hosted_language'
|
|
12
|
-
require 'wlang/hash_scope'
|
|
13
|
-
require 'wlang/parser'
|
|
14
|
-
require 'wlang/parser_state'
|
|
15
|
-
require 'wlang/intelligent_buffer'
|
|
16
|
-
|
|
1
|
+
require "wlang/version"
|
|
2
|
+
require "wlang/loader"
|
|
17
3
|
#
|
|
18
|
-
#
|
|
19
|
-
# on _wlang_ tools. See also the Roadmap section of {README}[link://files/README.html]
|
|
20
|
-
# to enter the library.
|
|
4
|
+
# WLang is a powerful code generation and templating engine
|
|
21
5
|
#
|
|
22
6
|
module WLang
|
|
23
|
-
|
|
24
|
-
######################################################################## About files and extensions
|
|
25
|
-
|
|
26
|
-
# Regular expression for file extensions
|
|
27
|
-
FILE_EXTENSION_REGEXP = /^\.[a-zA-Z0-9]+$/
|
|
28
|
-
|
|
29
|
-
# Checks that _ext_ is a valid file extension or raises an ArgumentError
|
|
30
|
-
def self.check_file_extension(ext)
|
|
31
|
-
raise ArgumentError, "Invalid file extension #{ext} (/^\.[a-zA-Z-0-9]+$/ expected)", caller\
|
|
32
|
-
unless FILE_EXTENSION_REGEXP =~ ext
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Raises an ArgumentError unless file is a real readable file
|
|
36
|
-
def self.check_readable_file(file)
|
|
37
|
-
raise ArgumentError, "File #{file} is not readable or not a file"\
|
|
38
|
-
unless File.exists?(file) and File.file?(file) and File.readable?(file)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
######################################################################## About dialects
|
|
42
|
-
|
|
43
|
-
# Reusable string for building dialect name based regexps
|
|
44
|
-
DIALECT_NAME_REGEXP_STR = "[-a-z]+"
|
|
45
|
-
|
|
46
|
-
# Regular expression for dialect names.
|
|
47
|
-
DIALECT_NAME_REGEXP = /^([-a-z]+)*$/
|
|
48
|
-
|
|
49
|
-
# Reusable string for building dialect name based regexps
|
|
50
|
-
QUALIFIED_DIALECT_NAME_REGEXP_STR = "[-a-z]+([\/][-a-z]+)*"
|
|
51
|
-
|
|
52
|
-
# Regular expression for dialect qualified names. Dialect qualified names are
|
|
53
|
-
# '/' seperated names, where a name is [-a-z]+.
|
|
54
|
-
#
|
|
55
|
-
# Examples: wlang/xhtml/uri, wlang/plain-text, ...
|
|
56
|
-
QUALIFIED_DIALECT_NAME_REGEXP = /^[-a-z]+([\/][-a-z]+)*$/
|
|
57
|
-
|
|
58
|
-
# Checks that _name_ is a valid qualified dialect name or raises an ArgumentError
|
|
59
|
-
def self.check_qualified_dialect_name(name)
|
|
60
|
-
raise ArgumentError, "Invalid dialect qualified name '#{name}' (/^[-a-z]+([\/][-a-z]+)*$/ expected)", caller\
|
|
61
|
-
unless QUALIFIED_DIALECT_NAME_REGEXP =~ name
|
|
62
|
-
end
|
|
63
7
|
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
# (keys) contain the first dot (like .wtpl, .whtml, ...). Dialects (values) are
|
|
67
|
-
# qualified names, not Dialect instances.
|
|
68
|
-
#
|
|
69
|
-
FILE_EXTENSIONS = {}
|
|
8
|
+
# These are allows block symbols
|
|
9
|
+
SYMBOLS = "!^%\"$&'*+?@~#,-./:;=<>|_".chars.to_a
|
|
70
10
|
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
# which is anonymous because it does not appear in qualified names.
|
|
74
|
-
#
|
|
75
|
-
@dialect = Dialect.new("", nil)
|
|
11
|
+
# Template braces
|
|
12
|
+
BRACES = ['{', '}']
|
|
76
13
|
|
|
77
|
-
#
|
|
78
|
-
def self.dialect_tree
|
|
79
|
-
@dialect
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
#
|
|
83
|
-
# Maps a file extension to a dialect qualified name.
|
|
14
|
+
# Defines an anonymous dialect on the fly.
|
|
84
15
|
#
|
|
85
16
|
# Example:
|
|
86
17
|
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
18
|
+
# d = WLang::dialect do
|
|
19
|
+
# tag('$') do |buf,fn| buf << evaluate(fn) end
|
|
20
|
+
# ...
|
|
90
21
|
# end
|
|
22
|
+
# d.render("Hello ${who}!", :who => "world")
|
|
23
|
+
# # => "Hello world!"
|
|
91
24
|
#
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
#
|
|
95
|
-
# This method raises an ArgumentError if the extension or dialect qualified
|
|
96
|
-
# name is not valid.
|
|
97
|
-
#
|
|
98
|
-
def self.file_extension_map(extension, dialect_qname)
|
|
99
|
-
check_file_extension(extension)
|
|
100
|
-
check_qualified_dialect_name(dialect_qname)
|
|
101
|
-
WLang::FILE_EXTENSIONS[extension] = dialect_qname
|
|
25
|
+
def dialect(superdialect = WLang::Dialect, &defn)
|
|
26
|
+
Class.new(superdialect, &defn)
|
|
102
27
|
end
|
|
28
|
+
module_function :dialect
|
|
103
29
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
#
|
|
110
|
-
def self.infer_dialect(uri)
|
|
111
|
-
WLang::FILE_EXTENSIONS[File.extname(uri)]
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
#
|
|
115
|
-
# Ensures, installs or query a dialect.
|
|
116
|
-
#
|
|
117
|
-
# <b>When name is a Dialect</b>, returns it immediately. This helper is provided
|
|
118
|
-
# for methods that accept both qualified dialect name and dialect instance
|
|
119
|
-
# arguments. Calling <code>WLang::dialect(arg)</code> ensures that the result will
|
|
120
|
-
# be a Dialect instance in all cases (if the arg is valid).
|
|
121
|
-
#
|
|
122
|
-
# Example:
|
|
123
|
-
#
|
|
124
|
-
# # This methods does something with a wlang dialect. _dialect_ argument may
|
|
125
|
-
# # be a Dialect instance or a qualified dialect name.
|
|
126
|
-
# def my_method(dialect = 'wlang/active-string')
|
|
127
|
-
# # ensures the Dialect instance or raises an ArgumentError if the dialect
|
|
128
|
-
# # qualified name is invalid (returns nil otherwise !)
|
|
129
|
-
# dialect = WLang::dialect(dialect)
|
|
130
|
-
# end
|
|
131
|
-
#
|
|
132
|
-
# <b>When called with a block</b>, this method installs a _wlang_ dialect under
|
|
133
|
-
# _name_ (which cannot be qualified). Extensions can be provided to let _wlang_
|
|
134
|
-
# automatically recognize files that are expressed in this dialect. The block
|
|
135
|
-
# is interpreted as code in the dialect DSL (domain specific language, see
|
|
136
|
-
# WLang::Dialect::DSL). Returns nil in this case.
|
|
137
|
-
#
|
|
138
|
-
# Example:
|
|
139
|
-
#
|
|
140
|
-
# # New dialect with 'my_dialect' qualified name and automatically installed
|
|
141
|
-
# # to recognize '.wmyd' file extensions
|
|
142
|
-
# WLang::dialect("my_dialect", '.wmyd') do
|
|
143
|
-
# # see WLang::Dialect::DSL for this part of the code
|
|
144
|
-
# end
|
|
145
|
-
#
|
|
146
|
-
# <b>When called without a block</b> this method returns a Dialect instance
|
|
147
|
-
# installed under name (which can be a qualified name). Extensions are ignored
|
|
148
|
-
# in this case. Returns nil if not found, a Dialect instance otherwise.
|
|
149
|
-
#
|
|
150
|
-
# Example:
|
|
151
|
-
#
|
|
152
|
-
# # Lookup for the 'wlang/xhtml' dialect
|
|
153
|
-
# wxhtml = WLang::dialect('wlang/xhtml')
|
|
154
|
-
#
|
|
155
|
-
# This method raises an ArgumentError if
|
|
156
|
-
# * _name_ is not a valid dialect qualified name
|
|
157
|
-
# * any of the file extension in _extensions_ is invalid
|
|
158
|
-
#
|
|
159
|
-
def self.dialect(name, *extensions, &block)
|
|
160
|
-
# first case, already a dialect
|
|
161
|
-
return name if Dialect===name
|
|
162
|
-
|
|
163
|
-
# other cases, argument validations
|
|
164
|
-
check_qualified_dialect_name(name)
|
|
165
|
-
extensions.each {|ext| check_file_extension(ext)}
|
|
166
|
-
|
|
167
|
-
if block_given?
|
|
168
|
-
# first case, dialect installation
|
|
169
|
-
raise "Unsupported qualified names in dialect installation"\
|
|
170
|
-
unless name.index('/').nil?
|
|
171
|
-
Dialect::DSL.new(@dialect).dialect(name, *extensions, &block)
|
|
172
|
-
else
|
|
173
|
-
# second case, dialect lookup
|
|
174
|
-
@dialect.dialect(name)
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
######################################################################## About encoders
|
|
179
|
-
|
|
180
|
-
# Reusable string for building encoder name based regexps
|
|
181
|
-
ENCODER_NAME_REGEXP_STR = "[-a-z]+"
|
|
182
|
-
|
|
183
|
-
# Regular expression for encoder names.
|
|
184
|
-
ENCODER_NAME_REGEXP = /^([-a-z]+)*$/
|
|
185
|
-
|
|
186
|
-
# Reusable string for building qualified encoder name based regexps
|
|
187
|
-
QUALIFIED_ENCODER_NAME_REGEXP_STR = "[-a-z]+([\/][-a-z]+)*"
|
|
188
|
-
|
|
189
|
-
# Regular expression for encoder qualified names. Encoder qualified names are
|
|
190
|
-
# '/' seperated names, where a name is [-a-z]+.
|
|
191
|
-
#
|
|
192
|
-
# Examples: xhtml/entities-encoding, sql/single-quoting, ...
|
|
193
|
-
QUALIFIED_ENCODER_NAME_REGEXP = /^([-a-z]+)([\/][-a-z]+)*$/
|
|
194
|
-
|
|
195
|
-
# Checks that _name_ is a valid qualified encoder name or raises an ArgumentError
|
|
196
|
-
def self.check_qualified_encoder_name(name)
|
|
197
|
-
raise ArgumentError, "Invalid encoder qualified name #{name} (/^[-a-z]+([\/][-a-z]+)*$/ expected)", caller\
|
|
198
|
-
unless QUALIFIED_ENCODER_NAME_REGEXP =~ name
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
#
|
|
202
|
-
# Returns an encoder installed under a qualified name. Returns nil if not
|
|
203
|
-
# found. If name is already an Encoder instance, returns it immediately.
|
|
204
|
-
#
|
|
205
|
-
# Example:
|
|
206
|
-
#
|
|
207
|
-
# encoder = WLang::encoder('xhtml/entities-encoding')
|
|
208
|
-
# encoder.encode('something that needs html entities escaping')
|
|
209
|
-
#
|
|
210
|
-
# This method raises an ArgumentError if _name_ is not a valid encoder qualified
|
|
211
|
-
# name.
|
|
212
|
-
#
|
|
213
|
-
def self.encoder(name)
|
|
214
|
-
check_qualified_encoder_name(name)
|
|
215
|
-
@dialect.encoder(name)
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
#
|
|
219
|
-
# Shortcut for
|
|
220
|
-
#
|
|
221
|
-
# WLang::encoder(encoder_qname).encode(source, options)
|
|
222
|
-
#
|
|
223
|
-
# This method raises an ArgumentError
|
|
224
|
-
# * if _source_ is not a String
|
|
225
|
-
# * if the encoder qualified name is invalid
|
|
226
|
-
#
|
|
227
|
-
# It raises a WLang::Error if the encoder cannot be found
|
|
228
|
-
#
|
|
229
|
-
def self.encode(source, encoder_qname, options = {})
|
|
230
|
-
raise ArgumentError, "String expected for source" unless String===source
|
|
231
|
-
check_qualified_encoder_name(encoder_qname)
|
|
232
|
-
encoder = WLang::encoder(encoder_qname)
|
|
233
|
-
raise WLang::Error, "Unable to find encoder #{encoder_qname}" if encoder.nil?
|
|
234
|
-
encoder.encode(source, options)
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
######################################################################## About data loading
|
|
238
|
-
|
|
239
|
-
#
|
|
240
|
-
# Provides installed {file extension => data loader} mapping. File extensions
|
|
241
|
-
# (keys) contain the first dot (like .wtpl, .whtml, ...). Data loades are
|
|
242
|
-
# Proc instances that take a single |uri| argument.
|
|
243
|
-
#
|
|
244
|
-
DATA_EXTENSIONS = {}
|
|
245
|
-
|
|
246
|
-
#
|
|
247
|
-
# Adds a data loader for file extensions. A data loader is a block of arity 1,
|
|
248
|
-
# taking a file as parameter and returning data decoded from the file.
|
|
249
|
-
#
|
|
250
|
-
# Example:
|
|
251
|
-
#
|
|
252
|
-
# # We have some MyXMLDataLoader class that is able to create a ruby object
|
|
253
|
-
# # from things expressed .xml files
|
|
254
|
-
# WLang::data_loader('.xml') {|file|
|
|
255
|
-
# MyXMLDataLaoder.parse_file(file)
|
|
256
|
-
# }
|
|
257
|
-
#
|
|
258
|
-
# # Later in a template (see the buffering ruleset that gives you <<={...})
|
|
259
|
-
# <<={resources.xml as resources}
|
|
260
|
-
# <html>
|
|
261
|
-
# *{resources as r}{
|
|
262
|
-
# ...
|
|
263
|
-
# }
|
|
264
|
-
# </html>
|
|
265
|
-
#
|
|
266
|
-
# This method raises an ArgumentError if
|
|
267
|
-
# * no block is given or if the block is not of arity 1
|
|
268
|
-
# * any of the file extensions in _exts_ is invalid
|
|
269
|
-
#
|
|
270
|
-
def self.data_loader(*exts, &block)
|
|
271
|
-
raise(ArgumentError, "WLang::data_loader expects a block") unless block_given?
|
|
272
|
-
raise(ArgumentError, "WLang::data_loader expects a block of arity 1") unless block.arity==1
|
|
273
|
-
exts.each {|ext| check_file_extension(ext) }
|
|
274
|
-
exts.each {|ext| DATA_EXTENSIONS[ext] = block}
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
#
|
|
278
|
-
# Loads data from a given URI. If _extension_ is omitted, tries to infer it
|
|
279
|
-
# from the uri, otherwise use it directly. Returns loaded data.
|
|
280
|
-
#
|
|
281
|
-
# This method raises a WLang::Error if no data loader is installed for the found
|
|
282
|
-
# extension. It raises an ArgumentError if the file extension is invalid.
|
|
283
|
-
#
|
|
284
|
-
def self.load_data(uri, extension=nil)
|
|
285
|
-
check_file_extension(extension = extension.nil? ? File.extname(uri) : extension)
|
|
286
|
-
loader = DATA_EXTENSIONS[extension]
|
|
287
|
-
raise ::WLang::Error, "No data loader for #{extension}" if loader.nil?
|
|
288
|
-
loader.call(uri)
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
######################################################################## About templates and instantiations
|
|
292
|
-
|
|
293
|
-
#
|
|
294
|
-
# Factors a template instance for a given string source, dialect (default to
|
|
295
|
-
# 'wlang/active-string') and block symbols (default to :braces)
|
|
296
|
-
#
|
|
297
|
-
# Example:
|
|
298
|
-
#
|
|
299
|
-
# # The template source code must be interpreted as wlang/xhtml
|
|
300
|
-
# template = WLang::template('<p>Hello ${who}!</p>', 'wlang/xhtml')
|
|
301
|
-
# str = template.instantiate(:hello => 'world')
|
|
302
|
-
#
|
|
303
|
-
# # We may also use other block symbols...
|
|
304
|
-
# template = WLang::template('<p>Hello $(who)!</p>', 'wlang/xhtml', :parentheses)
|
|
305
|
-
# str = template.instantiate(:hello => 'world')
|
|
306
|
-
#
|
|
307
|
-
# This method raises an ArgumentError if
|
|
308
|
-
# * _source_ is not a String
|
|
309
|
-
# * _dialect_ is not a valid dialect qualified name or Dialect instance
|
|
310
|
-
# * _block_symbols_ is not in [:braces, :brackets, :parentheses]
|
|
311
|
-
#
|
|
312
|
-
def self.template(source, dialect = 'wlang/active-string', block_symbols = :braces)
|
|
313
|
-
raise ArgumentError, "String expected for source" unless String===source
|
|
314
|
-
raise ArgumentError, "Invalid symbols for block #{block_symbols}"\
|
|
315
|
-
unless ::WLang::Template::BLOCK_SYMBOLS.keys.include?(block_symbols)
|
|
316
|
-
template = Template.new(source, WLang::dialect(dialect), block_symbols)
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
#
|
|
320
|
-
# Factors a template instance for a given file, optional dialect (if nil is
|
|
321
|
-
# passed, the dialect is infered from the extension) and block symbols
|
|
322
|
-
# (default to :braces)
|
|
323
|
-
#
|
|
324
|
-
# Example:
|
|
325
|
-
#
|
|
326
|
-
# # the file index.wtpl is a wlang source code in 'wlang/xhtml' dialect
|
|
327
|
-
# # (automatically infered from file extension)
|
|
328
|
-
# template = WLang::template('index.wtpl')
|
|
329
|
-
# puts template.instantiate(:who => 'world') # puts 'Hello world!'
|
|
330
|
-
#
|
|
331
|
-
# This method raises an ArgumentError
|
|
332
|
-
# * if _file_ does not exists, is not a file or is not readable
|
|
333
|
-
# * if _dialect_ is not a valid qualified dialect name, Dialect instance, or nil
|
|
334
|
-
# * _block_symbols_ is not in [:braces, :brackets, :parentheses]
|
|
335
|
-
#
|
|
336
|
-
# It raises a WLang::Error
|
|
337
|
-
# * if no dialect can be infered from the file extension (if _dialect_ was nil)
|
|
338
|
-
#
|
|
339
|
-
def self.file_template(file, dialect = nil, block_symbols = :braces)
|
|
340
|
-
check_readable_file(file)
|
|
341
|
-
|
|
342
|
-
# Check the dialect
|
|
343
|
-
dialect = self.infer_dialect(file) if dialect.nil?
|
|
344
|
-
raise WLang::Error, "No known dialect for file extension '#{File.extname(file)}'\n"\
|
|
345
|
-
"Known extensions are: " << WLang::FILE_EXTENSIONS.keys.join(", ") if dialect.nil?
|
|
346
|
-
|
|
347
|
-
# Build the template now
|
|
348
|
-
template = template(File.read(file), dialect, block_symbols)
|
|
349
|
-
template.source_file = file
|
|
350
|
-
template
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
#
|
|
354
|
-
# Instantiates a template written in some _wlang_ dialect, using a given _context_
|
|
355
|
-
# (providing instantiation data). Returns instantiatiation as a String. If you want
|
|
356
|
-
# to instantiate the template in a specific buffer (a file or console for example),
|
|
357
|
-
# use Template. _template_ is expected to be a String and _context_ a Hash. To
|
|
358
|
-
# know available dialects, see WLang::StandardDialects. <em>block_symbols</em>
|
|
359
|
-
# can be <tt>:braces</tt> ('{' and '}' pairs), <tt>:brackets</tt> ('[' and ']'
|
|
360
|
-
# pairs) or <tt>:parentheses</tt> ('(' and ')' pairs).
|
|
361
|
-
#
|
|
362
|
-
# Examples:
|
|
363
|
-
# WLang.instantiate "Hello ${who} !", {"who" => "Mr. Jones"}
|
|
364
|
-
# WLang.instantiate "SELECT * FROM people WHERE name='{name}'", {"who" => "Mr. O'Neil"}, "wlang/sql"
|
|
365
|
-
# WLang.instantiate "Hello $(who) !", {"who" => "Mr. Jones"}, "wlang/active-string", :parentheses
|
|
366
|
-
#
|
|
367
|
-
# This method raises an ArgumentError if
|
|
368
|
-
# * _source_ is not a String
|
|
369
|
-
# * _context_ is not nil or a Hash
|
|
370
|
-
# * _dialect_ is not a valid dialect qualified name or Dialect instance
|
|
371
|
-
# * _block_symbols_ is not in [:braces, :brackets, :parentheses]
|
|
372
|
-
#
|
|
373
|
-
# It raises a WLang::Error
|
|
374
|
-
# * something goes wrong during instantiation (see WLang::Error and subclasses)
|
|
375
|
-
#
|
|
376
|
-
def self.instantiate(source, context = {}, dialect="wlang/active-string", block_symbols = :braces)
|
|
377
|
-
raise ArgumentError, "Hash expected for context argument" unless (context.nil? or Hash===context)
|
|
378
|
-
template(source, dialect, block_symbols).instantiate(context || {}).to_s
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
#
|
|
382
|
-
# Instantiates a file written in some _wlang_ dialect, using a given _context_
|
|
383
|
-
# (providing instantiation data). If _dialect_ is nil, tries to infer it from the file
|
|
384
|
-
# extension; otherwise _dialect_ is expected to be a qualified dialect name or a Dialect
|
|
385
|
-
# instance. See instantiate about <tt>block_symbols</tt>.
|
|
386
|
-
#
|
|
387
|
-
# Examples:
|
|
388
|
-
# Wlang.file_instantiate "template.wtpl", {"who" => "Mr. Jones"}
|
|
389
|
-
# Wlang.file_instantiate "template.xxx", {"who" => "Mr. Jones"}, "wlang/xhtml"
|
|
390
|
-
#
|
|
391
|
-
# This method raises an ArgumentError if
|
|
392
|
-
# * _file_ is not a readable file
|
|
393
|
-
# * _context_ is not nil or a Hash
|
|
394
|
-
# * _dialect_ is not a valid dialect qualified name, Dialect instance or nil
|
|
395
|
-
# * _block_symbols_ is not in [:braces, :brackets, :parentheses]
|
|
396
|
-
#
|
|
397
|
-
# It raises a WLang::Error
|
|
398
|
-
# * if no dialect can be infered from the file extension (if _dialect_ was nil)
|
|
399
|
-
# * something goes wrong during instantiation (see WLang::Error and subclasses)
|
|
400
|
-
#
|
|
401
|
-
def self.file_instantiate(file, context = nil, dialect = nil, block_symbols = :braces)
|
|
402
|
-
raise ArgumentError, "Hash expected for context argument" unless (context.nil? or Hash===context)
|
|
403
|
-
file_template(file, dialect, block_symbols).instantiate(context || {}).to_s
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
end
|
|
407
|
-
require 'wlang/dialects/standard_dialects'
|
|
30
|
+
end # module WLang
|
|
31
|
+
require 'wlang/compiler'
|
|
32
|
+
require 'wlang/template'
|
|
33
|
+
require 'wlang/dialect'
|
|
34
|
+
require 'wlang/scope'
|