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.
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