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
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
- instance_eval File.read(taskfile), taskfile
10
+ load taskfile
23
11
  end
data/bin/wlang CHANGED
@@ -1,30 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- #
3
- # WLang: Code generation/Templating engine tool
4
- # (see lib/wlang/wlang.rb for more information)
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)
@@ -1,407 +1,34 @@
1
- require 'wlang/loader'
2
- require 'wlang/version'
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
- # Main module of the _wlang_ code generator/template engine, providing a facade
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
- # Provides installed {file extension => dialect} mappings. File extensions
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
- # Main anonymous dialect. All installed dialects are children of this one,
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
- # Returns the root of the dialect tree
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
- # # We create an 'example' dialect
88
- # WLang::dialect('example') do
89
- # # see WLang::dialect about creating a dialect
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
- # # We map .wex file extensions to our new dialect
93
- # WLang::file_extension_map('.wex', 'example')
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
- # Infers a dialect from a file extension. Returns nil if no dialect is currently
106
- # mapped to the given extension (see file_extension_map)
107
- #
108
- # This method never raises errors.
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'