wlang 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/LICENCE.rdoc +25 -0
  2. data/README.rdoc +111 -0
  3. data/bin/wlang +24 -0
  4. data/doc/specification/about.rdoc +61 -0
  5. data/doc/specification/dialects.wtpl +0 -0
  6. data/doc/specification/examples.rb +3 -0
  7. data/doc/specification/glossary.wtpl +14 -0
  8. data/doc/specification/hosting.rdoc +0 -0
  9. data/doc/specification/overview.rdoc +116 -0
  10. data/doc/specification/rulesets.wtpl +87 -0
  11. data/doc/specification/specification.css +52 -0
  12. data/doc/specification/specification.html +1361 -0
  13. data/doc/specification/specification.js +8 -0
  14. data/doc/specification/specification.wtpl +41 -0
  15. data/doc/specification/specification.yml +430 -0
  16. data/doc/specification/symbols.wtpl +16 -0
  17. data/lib/wlang.rb +186 -0
  18. data/lib/wlang/basic_object.rb +19 -0
  19. data/lib/wlang/dialect.rb +230 -0
  20. data/lib/wlang/dialect_dsl.rb +136 -0
  21. data/lib/wlang/dialect_loader.rb +69 -0
  22. data/lib/wlang/dialects/coderay_dialect.rb +35 -0
  23. data/lib/wlang/dialects/plain_text_dialect.rb +75 -0
  24. data/lib/wlang/dialects/rdoc_dialect.rb +33 -0
  25. data/lib/wlang/dialects/ruby_dialect.rb +35 -0
  26. data/lib/wlang/dialects/sql_dialect.rb +38 -0
  27. data/lib/wlang/dialects/standard_dialects.rb +113 -0
  28. data/lib/wlang/dialects/xhtml_dialect.rb +40 -0
  29. data/lib/wlang/encoder.rb +66 -0
  30. data/lib/wlang/encoder_set.rb +117 -0
  31. data/lib/wlang/errors.rb +37 -0
  32. data/lib/wlang/intelligent_buffer.rb +94 -0
  33. data/lib/wlang/parser.rb +251 -0
  34. data/lib/wlang/parser_context.rb +146 -0
  35. data/lib/wlang/ruby_extensions.rb +21 -0
  36. data/lib/wlang/rule.rb +66 -0
  37. data/lib/wlang/rule_set.rb +93 -0
  38. data/lib/wlang/rulesets/basic_ruleset.rb +75 -0
  39. data/lib/wlang/rulesets/buffering_ruleset.rb +103 -0
  40. data/lib/wlang/rulesets/context_ruleset.rb +115 -0
  41. data/lib/wlang/rulesets/encoding_ruleset.rb +73 -0
  42. data/lib/wlang/rulesets/imperative_ruleset.rb +132 -0
  43. data/lib/wlang/rulesets/ruleset_utils.rb +296 -0
  44. data/lib/wlang/template.rb +79 -0
  45. data/lib/wlang/wlang_command.rb +54 -0
  46. data/lib/wlang/wlang_command_options.rb +158 -0
  47. data/test/sandbox.rb +1 -0
  48. data/test/test_all.rb +8 -0
  49. data/test/wlang/anagram_bugs_test.rb +111 -0
  50. data/test/wlang/basic_ruleset_test.rb +52 -0
  51. data/test/wlang/buffering_ruleset_test.rb +102 -0
  52. data/test/wlang/buffering_template1.wtpl +1 -0
  53. data/test/wlang/buffering_template2.wtpl +1 -0
  54. data/test/wlang/buffering_template3.wtpl +1 -0
  55. data/test/wlang/buffering_template4.wtpl +1 -0
  56. data/test/wlang/buffering_template5.wtpl +1 -0
  57. data/test/wlang/context_ruleset_test.rb +32 -0
  58. data/test/wlang/data.rb +3 -0
  59. data/test/wlang/encoder_set_test.rb +42 -0
  60. data/test/wlang/imperative_ruleset_test.rb +107 -0
  61. data/test/wlang/intelligent_buffer_test.rb +194 -0
  62. data/test/wlang/othersymbols_test.rb +16 -0
  63. data/test/wlang/parser_context_test.rb +29 -0
  64. data/test/wlang/parser_test.rb +89 -0
  65. data/test/wlang/plain_text_dialect_test.rb +21 -0
  66. data/test/wlang/ruby_dialect_test.rb +100 -0
  67. data/test/wlang/ruby_expected.rb +3 -0
  68. data/test/wlang/ruby_template.wrb +3 -0
  69. data/test/wlang/ruleset_utils_test.rb +245 -0
  70. data/test/wlang/specification_examples_test.rb +52 -0
  71. data/test/wlang/test_utils.rb +25 -0
  72. data/test/wlang/wlang_test.rb +80 -0
  73. metadata +136 -0
@@ -0,0 +1,79 @@
1
+ module WLang
2
+
3
+ #
4
+ # Template in a given wlang dialect, providing a default context object.
5
+ #
6
+ class Template
7
+
8
+ # Recognized symbols for blocks
9
+ BLOCK_SYMBOLS = {:braces => ['{', '}'],
10
+ :brackets => ['[', ']'],
11
+ :parentheses => ['(', ')']}
12
+
13
+ # Template wlang dialect (wlang/...)
14
+ attr_reader :dialect
15
+
16
+ # Instantiation context
17
+ attr_reader :context
18
+
19
+ # Block symbols
20
+ attr_reader :block_symbols
21
+
22
+ # Attached file source
23
+ attr_accessor :source_file
24
+
25
+ #
26
+ # Creates a template instance.
27
+ #
28
+ def initialize(source, dialect, context=nil, block_symbols = :braces)
29
+ raise(ArgumentError, "Source is mandatory") if source.nil?
30
+ if String===dialect
31
+ dname, dialect = dialect, WLang::dialect(dialect)
32
+ raise(ArgumentError, "Unknown dialect #{dname}") if dialect.nil?
33
+ end
34
+ raise(ArgumentError, "Dialect is mandatory") unless WLang::Dialect===dialect
35
+ @source = source
36
+ @dialect = dialect
37
+ @context = WLang::Parser::Context.new(context)
38
+ @block_symbols = block_symbols
39
+ end
40
+
41
+ # Resolved a relative uri
42
+ def file_resolve(uri, exists=false)
43
+ raise("Unable to resolve #{uri}, this template is not attached to a file")\
44
+ unless @source_file
45
+ target = File.join(File.dirname(@source_file), uri)
46
+ if exists and not(File.exists?(target))
47
+ raise "File '#{uri}' does not exists"
48
+ end
49
+ target
50
+ end
51
+
52
+ # Returns template's source text
53
+ def source_text
54
+ case @source
55
+ when String
56
+ @source
57
+ else
58
+ @source.to_s
59
+ end
60
+ end
61
+
62
+ #
63
+ # Instantiate the template, with an additional context and an output buffer.
64
+ #
65
+ def instantiate(buffer=nil, context=nil)
66
+ unless context.nil?
67
+ @context.push(context)
68
+ end
69
+ parser = WLang::Parser.instantiator(self, buffer)
70
+ instantiated = parser.instantiate
71
+ unless context.nil?
72
+ @context.pop
73
+ end
74
+ instantiated[0]
75
+ end
76
+
77
+ end # class Template
78
+
79
+ end # module WLang
@@ -0,0 +1,54 @@
1
+ require 'wlang'
2
+ require 'wlang/wlang_command_options'
3
+ require 'wlang/dialects/standard_dialects'
4
+ module WLang
5
+
6
+ #
7
+ # Provides the _wlang_ commandline tool. See 'wlang --help' for documentation.
8
+ #
9
+ class WLangCommand
10
+
11
+ # Creates a commandline instance.
12
+ def initialize()
13
+ end
14
+
15
+ # Run _wlang_ commandline on specific arguments
16
+ def run(args)
17
+ # parse the options
18
+ options = Options.new.parse(args)
19
+
20
+ # get output buffer
21
+ buffer = STDOUT
22
+ if options.output_file
23
+ buffer = File.new(options.output_file, "w")
24
+ end
25
+
26
+ source = File.read(options.template_file)
27
+ dialect = options.template_dialect
28
+ braces = options.template_brace
29
+ context = options.context_object
30
+ unless options.context_name.nil?
31
+ context = {options.context_name => context}
32
+ end
33
+ template = WLang::Template.new(source, dialect, context, braces)
34
+ template.source_file = options.template_file
35
+
36
+ if options.verbosity>1
37
+ puts "Instantiating #{options.template_file}"
38
+ puts "Using dialect #{dialect} : #{dialect.class}"
39
+ puts "Block delimiters are " << Template::BLOCK_SYMBOLS[braces].inspect
40
+ puts "Context is " << context.inspect
41
+ end
42
+
43
+ buffer << template.instantiate
44
+
45
+ # Flush and close if needed
46
+ if File===buffer
47
+ buffer.flush
48
+ buffer.close
49
+ end
50
+ end
51
+
52
+ end # class WLang
53
+
54
+ end # module WLang
@@ -0,0 +1,158 @@
1
+ require 'optparse'
2
+ module WLang
3
+ class WLangCommand
4
+
5
+ #
6
+ # Options of the _wlang_ commandline
7
+ #
8
+ class Options
9
+
10
+ # Source template file
11
+ attr_reader :template_file
12
+
13
+ # Template dialect
14
+ attr_reader :template_dialect
15
+
16
+ # Which brace kind used in template (:braces, :brackes, :parentheses)
17
+ attr_reader :template_brace
18
+
19
+ # Context file
20
+ attr_reader :context_file
21
+
22
+ # Context object
23
+ attr_reader :context_object
24
+
25
+ # Context kind [:yaml, :ruby, :dsl]
26
+ attr_reader :context_kind
27
+
28
+ # Name of the context
29
+ attr_reader :context_name
30
+
31
+ # Output file
32
+ attr_reader :output_file
33
+
34
+ # Verbose mode?
35
+ attr_reader :verbosity
36
+
37
+ # Initializes the options with default values
38
+ def initialize
39
+ @verbosity = 0
40
+ @template_brace = :braces
41
+ end
42
+
43
+ #
44
+ # Parses commandline options provided as an array of Strings.
45
+ #
46
+ def parse(argv)
47
+ opts = OptionParser.new do |opt|
48
+ opt.program_name = File.basename $0
49
+ opt.version = WLang::VERSION
50
+ opt.release = nil
51
+ opt.summary_indent = ' ' * 4
52
+ banner = <<-EOF
53
+ # Usage #{opt.program_name} [options] template context-file
54
+
55
+ # Template is parsed as a wlang dialect (based on its extension by default) and
56
+ # instantiated through a given context file.
57
+ EOF
58
+ opt.banner = banner.gsub(/[ \t]+# /, "")
59
+
60
+ opt.separator nil
61
+ opt.separator "Options:"
62
+
63
+ opt.on("-d", "--dialect=DIALECT",
64
+ "Interpret source template as a given wlang dialect") do |value|
65
+ @template_dialect = value
66
+ end
67
+
68
+ opt.on("-o", "--output=OUTPUT",
69
+ "Flush instantiation result in output file") do |value|
70
+ @output_file = value
71
+ end
72
+
73
+ opt.on("--brace=BRACE", ["brace", "parenthesis", "bracket"],
74
+ "Block delimiters used by the template file (braces, brackets, parentheses)") do |value|
75
+ # handle template brace
76
+ case value
77
+ when "brace", "braces", "{"
78
+ @template_brace = :braces
79
+ when "brackets", "bracket", "["
80
+ @template_brace = :brackets
81
+ when "parentheses", "parenthesis", "("
82
+ @template_brace = :parentheses
83
+ else
84
+ raise "Unknown brace kind #{brace}"
85
+ end
86
+ end
87
+
88
+ opt.on("--context-name=NAME",
89
+ "Name of the context object") do |value|
90
+ @context_name = value
91
+ end
92
+
93
+ opt.on("--context-kind=KIND", ["yaml", "ruby", "dsl"],
94
+ "Kind of context object (yaml, ruby, dsl)") do |value|
95
+ @context_kind = '.' + value
96
+ end
97
+
98
+ opt.on("--verbose", "-v",
99
+ "Display extra progress as we parse.") do |value|
100
+ @verbosity = 2
101
+ end
102
+
103
+ # No argument, shows at tail. This will print an options summary.
104
+ # Try it and see!
105
+ opt.on_tail("-h", "--help", "Show this message") do
106
+ puts opts
107
+ exit
108
+ end
109
+
110
+ # Another typical switch to print the version.
111
+ opt.on_tail("--version", "Show version") do
112
+ puts "wlang version " << WLang::VERSION << " (c) University of Louvain, Bernard & Louis Lambeau"
113
+ exit
114
+ end
115
+
116
+ opt.separator nil
117
+ end
118
+
119
+ # handle arguments
120
+ rest = opts.parse!(argv)
121
+ if rest.length<1 or rest.length>2
122
+ puts opts
123
+ exit
124
+ end
125
+
126
+ # handle template file
127
+ @template_file = File.expand_path(rest[0])
128
+ raise("File '#{@template_file}' not readable")\
129
+ unless File.file?(@template_file) and File.readable?(@template_file)
130
+
131
+ # handle context file
132
+ if rest.length==2
133
+ @context_file = rest[1]
134
+ raise("File '#{@context_file}' not readable")\
135
+ unless File.file?(@context_file) and File.readable?(@context_file)
136
+ end
137
+
138
+ # handle template dialect
139
+ unless @template_dialect
140
+ extname = File.extname(@template_file)
141
+ @template_dialect = WLang::FILE_EXTENSIONS[extname]
142
+ raise("No known dialect for file extension '#{extname}'\n"\
143
+ "Known extensions are: " << WLang::FILE_EXTENSIONS.keys.join(", "))\
144
+ if @template_dialect.nil?
145
+ end
146
+
147
+ # handle context object
148
+ if @context_file
149
+ @context_object = WLang::load_data(@context_file, @context_kind)
150
+ end
151
+
152
+ return self
153
+ end
154
+
155
+ end # class Options
156
+
157
+ end # class WLangCommand
158
+ end # module WLang
data/test/sandbox.rb ADDED
@@ -0,0 +1 @@
1
+ puts "blambeau".to_sym
data/test/test_all.rb ADDED
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__),'..', 'lib'))
2
+ require 'wlang'
3
+ require 'test/unit'
4
+ test_files = Dir[File.join(File.dirname(__FILE__), '**/*_test.rb')]
5
+ test_files.each { |file|
6
+ require(file)
7
+ }
8
+
@@ -0,0 +1,111 @@
1
+ require 'test/unit'
2
+ require 'wlang'
3
+ module WLang
4
+
5
+ # Tests the IntelligentBuffer class
6
+ class AnagramBugsTest < Test::Unit::TestCase
7
+ include IntelligentBuffer::Methods
8
+
9
+ def test_on_anagram_spacing_policy
10
+ WLang::dialect("anagram") do
11
+ rule '=~' do |parser,offset|
12
+ match, reached = parser.parse(offset, "wlang/dummy")
13
+ block, reached = parser.parse_block(reached, "wlang/dummy")
14
+
15
+ # puts "Here is the block ==="
16
+ # puts "#{block.gsub(/ /, '.').gsub(/\n/, "\\n\n")}"
17
+ # puts "=== Here is the block"
18
+
19
+ [block, reached]
20
+ end
21
+ end
22
+ template = %q{
23
+ =~{String}{
24
+ this is an anagram template
25
+ }
26
+ }.gsub(/^ {8}/, '').strip
27
+ result = template.wlang_instantiate({}, "anagram")
28
+ assert IntelligentBuffer===result
29
+ # assert_equal("this is an anagram template", result)
30
+
31
+ template = %q{
32
+ =~{String}{
33
+ module MyModule
34
+ end
35
+ }
36
+ }.gsub(/^ {8}/, '').strip
37
+ result = template.wlang_instantiate({}, "anagram")
38
+ assert IntelligentBuffer===result
39
+ assert_equal("module MyModule\nend\n", result)
40
+ end
41
+
42
+ def test_missing_end_bug
43
+ WLang::dialect("anagram") do
44
+ rules WLang::RuleSet::Basic
45
+ rules WLang::RuleSet::Imperative
46
+ rule '=~' do |parser,offset|
47
+ match, reached = parser.parse(offset, "wlang/dummy")
48
+ match = parser.evaluate(match)
49
+ block, reached = parser.parse_block(reached, "wlang/dummy")
50
+ block = block.strip_block(block)
51
+ block = block.tabto(block,0)
52
+ parser.evaluate("matching_rules") << [match, block]
53
+
54
+ # puts "Here is the block ==="
55
+ # puts "#{block.gsub(/ /, '.').gsub(/\n/, "\\n\n")}"
56
+ # puts "=== Here is the block"
57
+
58
+ ["", reached]
59
+ end
60
+ rule '+~' do |parser,offset|
61
+ what, reached = parser.parse(offset, "wlang/dummy")
62
+ evaluated = parser.evaluate(what)
63
+ raise "Unexpected case, #{what} leads to nil" unless evaluated
64
+
65
+ rules = parser.evaluate("matching_rules")
66
+ found = rules.find {|r| r[0]===evaluated}
67
+ raise "Unexpected case: no match for #{what.class}" unless found
68
+
69
+ context = {"n" => evaluated, "matching_rules" => rules}
70
+ inst = found[1].wlang_instantiate(context, "anagram")
71
+
72
+ inst2 = inst.gsub(/ /, '.').gsub(/\n/, "\\n\n")
73
+ # puts "Here is the inst ==="
74
+ # puts "#{inst2}"
75
+ # puts "=== Here is the inst"
76
+
77
+ found = [inst, reached]
78
+ end
79
+ end
80
+ template = %Q{
81
+ =~{Array}{
82
+ module MyModule
83
+ *{n as c}{
84
+ +~{c}
85
+ }
86
+ end
87
+ }
88
+ =~{Integer}{
89
+ +{n}
90
+ }
91
+ +~{n}
92
+ }.gsub(/ {8}/,'').strip
93
+ context = {'n' => [10, 20, 30], 'matching_rules' => []}
94
+ result = template.wlang_instantiate(context, "anagram")
95
+
96
+ # template = template.gsub(/ /, '.').gsub(/\n/, "\\n\n")
97
+ # puts "Here is the template ==="
98
+ # puts "#{template}"
99
+ # puts "=== Here is the template"
100
+
101
+ # result = result.gsub(/ /, '.').gsub(/\n/, "\\n\n")
102
+ # puts "Here is the result ==="
103
+ # puts "#{result}"
104
+ # puts "=== Here is the result"
105
+ result = result.strip
106
+ expected = "module MyModule\n 10\n \n 20\n \n 30\n\nend"
107
+ assert_equal expected, result
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,52 @@
1
+ require 'test/unit'
2
+ require 'wlang'
3
+ require 'wlang/test_utils'
4
+ require 'wlang/rulesets/basic_ruleset'
5
+ require 'wlang/rulesets/context_ruleset'
6
+ require 'wlang/rulesets/buffering_ruleset'
7
+
8
+ # Tests the Basic ruleset
9
+ class WLang::BasicRuleSetTest < Test::Unit::TestCase
10
+ include WLang::TestUtils
11
+
12
+ # Installs a dialect on wlang
13
+ def setup
14
+ WLang::dialect "basic-test" do
15
+ rules WLang::RuleSet::Basic
16
+ rules WLang::RuleSet::Context
17
+ rules WLang::RuleSet::Buffering
18
+ end
19
+ end
20
+
21
+ # tests !{wlang/hosted} operator
22
+ def test_execution
23
+ tests = [
24
+ ["!{name}", "blambeau", {"name" => "blambeau"}],
25
+ ["!{!{var}}", "blambeau", {"var" => "name", "name" => "blambeau"}],
26
+ ["!{'hello'.upcase}", "HELLO", {}]
27
+ ]
28
+ tests.each do |t|
29
+ template, expected, context = t
30
+ result = template.wlang(context, "basic-test")
31
+ assert_equal(expected, result)
32
+ end
33
+ end
34
+
35
+ # Tests recursive_application rule
36
+ def test_recursive_application
37
+ tests = [
38
+ ["#={code}{%{wlang/dummy}{+{variable}}}"\
39
+ "%!{basic-test with variable: 'hello'}{+{code}}", "hello"],
40
+ ["<<={data.rb as context}"\
41
+ "#={code}{%{wlang/dummy}{+{author}}}"\
42
+ "%!{basic-test using context}{+{code}}", "blambeau"]
43
+ ]
44
+ tests.each do |test|
45
+ template, expected = test
46
+ template = relative_template(template, "basic-test", __FILE__)
47
+ result = template.instantiate()
48
+ assert_equal(expected, result)
49
+ end
50
+ end
51
+
52
+ end # class WLang::BasicRuleSetTest