luobo 0.0.1
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/README.rdoc +7 -0
- data/Rakefile +3 -0
- data/bin/tuzi +12 -0
- data/example/parser.lub +111 -0
- data/lib/luobo.rb +5 -0
- data/lib/luobo/base.rb +211 -0
- data/lib/luobo/driver.rb +46 -0
- data/lib/luobo/token.rb +28 -0
- data/lib/luobo/version.rb +4 -0
- data/luobo.gemspec +18 -0
- data/spec/driver_spec.rb +30 -0
- data/spec/parser_spec.rb +78 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/token_spec.rb +32 -0
- metadata +102 -0
    
        data/README.rdoc
    ADDED
    
    
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/tuzi
    ADDED
    
    
    
        data/example/parser.lub
    ADDED
    
    | @@ -0,0 +1,111 @@ | |
| 1 | 
            +
            DRIVER: ast
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Raw line passed as it is.
         | 
| 4 | 
            +
            AST: Raw line passed as it is.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            ## SPLIT: abc df
         | 
| 7 | 
            +
            AST: abc
         | 
| 8 | 
            +
            AST: df
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Raw line contains ->
         | 
| 11 | 
            +
              fake block
         | 
| 12 | 
            +
            AST: Raw line contains -> ->
         | 
| 13 | 
            +
            AST: 2,fake block
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ## SPEC: a spec blog ->
         | 
| 16 | 
            +
              do that
         | 
| 17 | 
            +
              do this
         | 
| 18 | 
            +
              ## SPEC: nested spec ->
         | 
| 19 | 
            +
                redo that
         | 
| 20 | 
            +
                redo this
         | 
| 21 | 
            +
              doing outside
         | 
| 22 | 
            +
            doing further outside
         | 
| 23 | 
            +
            AST: spec "a spec blog" do
         | 
| 24 | 
            +
            AST: 2,do that
         | 
| 25 | 
            +
            AST: 2,do this
         | 
| 26 | 
            +
            AST: end
         | 
| 27 | 
            +
            AST: 2,spec "nested spec" do
         | 
| 28 | 
            +
            AST: 4,redo that
         | 
| 29 | 
            +
            AST: 4,redo this
         | 
| 30 | 
            +
            AST: 2,end
         | 
| 31 | 
            +
            AST: 2,doing outside
         | 
| 32 | 
            +
            AST: doing further outside
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            % =================
         | 
| 35 | 
            +
            Give me a loop for <%= loop_name %>
         | 
| 36 | 
            +
            SPEC: and has spec <%= loop_spec %> ->
         | 
| 37 | 
            +
              specify a value as <%= value %>
         | 
| 38 | 
            +
            % -----
         | 
| 39 | 
            +
            % loop_name: looper
         | 
| 40 | 
            +
            % loop_spec: spec a loop
         | 
| 41 | 
            +
            % value: 89
         | 
| 42 | 
            +
            % -----
         | 
| 43 | 
            +
            % loop_name: looper again
         | 
| 44 | 
            +
            % loop_spec: spec a loop again
         | 
| 45 | 
            +
            % value: 899090
         | 
| 46 | 
            +
            AST: Give me a loop for looper
         | 
| 47 | 
            +
            AST: spec "and has spec spec a loop" do
         | 
| 48 | 
            +
            AST: 2,specify a value as 89
         | 
| 49 | 
            +
            AST: end
         | 
| 50 | 
            +
            AST: Give me a loop for looper again
         | 
| 51 | 
            +
            AST: spec "and has spec spec a loop again" do
         | 
| 52 | 
            +
            AST: 2,specify a value as 899090
         | 
| 53 | 
            +
            AST: end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            Test a loop inside a block argument
         | 
| 56 | 
            +
            AST: Test a loop inside a block argument
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            SPEC: loop inside ->
         | 
| 59 | 
            +
              % ========================
         | 
| 60 | 
            +
              key value <%= store %>
         | 
| 61 | 
            +
              % -----
         | 
| 62 | 
            +
              % store: factory
         | 
| 63 | 
            +
              % -----
         | 
| 64 | 
            +
              % store: firm
         | 
| 65 | 
            +
              % ------
         | 
| 66 | 
            +
              % store: person
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            AST: spec "loop inside" do
         | 
| 69 | 
            +
            AST: 2, key value factory
         | 
| 70 | 
            +
            AST: 2, key value firm
         | 
| 71 | 
            +
            AST: 2, key value person
         | 
| 72 | 
            +
            AST: end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            Pure raw test in indent
         | 
| 75 | 
            +
              Indent with 1 level
         | 
| 76 | 
            +
                Indent with 2 levels
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                Indent with 2 levels again
         | 
| 79 | 
            +
            Back!
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            AST: Pure raw test in indent
         | 
| 82 | 
            +
            AST: 2,Indent with 1 level
         | 
| 83 | 
            +
            AST: 4,Indent with 2 levels
         | 
| 84 | 
            +
            AST: 4,Indent with 2 levels again
         | 
| 85 | 
            +
            AST: Back!
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            UNKNOWN: unknown processor name treated as it is
         | 
| 88 | 
            +
            AST: UNKNOWN: unknown processor name treated as it is
         | 
| 89 | 
            +
             | 
| 90 | 
            +
            UNKBLOK: unknown with a block ->
         | 
| 91 | 
            +
              This is quite strange!
         | 
| 92 | 
            +
            Send back.
         | 
| 93 | 
            +
            AST: UNKBLOK: unknown with a block -> ->
         | 
| 94 | 
            +
            AST: 2,This is quite strange!
         | 
| 95 | 
            +
            AST: Send back.
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            HASH: key_name: value_name
         | 
| 98 | 
            +
            AST: key: key_name
         | 
| 99 | 
            +
            AST: value: value_name
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            HASH: ->
         | 
| 102 | 
            +
              blockkey: blockvalue
         | 
| 103 | 
            +
              blockkey2: blockvalue2
         | 
| 104 | 
            +
              blockkey3: blockvalue3
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            AST: key: blockkey
         | 
| 107 | 
            +
            AST: value: blockvalue
         | 
| 108 | 
            +
            AST: key: blockkey2
         | 
| 109 | 
            +
            AST: value: blockvalue2
         | 
| 110 | 
            +
            AST: key: blockkey3
         | 
| 111 | 
            +
            AST: value: blockvalue3
         | 
    
        data/lib/luobo.rb
    ADDED
    
    
    
        data/lib/luobo/base.rb
    ADDED
    
    | @@ -0,0 +1,211 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "erubis"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Luobo
         | 
| 6 | 
            +
              ## entry class for the carrot module
         | 
| 7 | 
            +
              class Base    
         | 
| 8 | 
            +
                attr_accessor :driver
         | 
| 9 | 
            +
                def initialize file, output
         | 
| 10 | 
            +
                  @source_file = file
         | 
| 11 | 
            +
                  
         | 
| 12 | 
            +
                  @output = output.is_a?(IO) ? output : File.open(output, "w")
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  # initialize:
         | 
| 15 | 
            +
                  @token_stack = Array.new
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # initialize loop template and examples
         | 
| 18 | 
            +
                  self.reset_loop
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                # initialize the holders for a example based loop,
         | 
| 22 | 
            +
                # or reset after a loop expansion
         | 
| 23 | 
            +
                def reset_loop
         | 
| 24 | 
            +
                  @loop_start_ln = 0
         | 
| 25 | 
            +
                  @loop_template = nil
         | 
| 26 | 
            +
                  @loop_examples = Array.new
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                # extend a loop be examples
         | 
| 30 | 
            +
                def expand_loop
         | 
| 31 | 
            +
                  raise "no examples found for loop start on line #{@loop_start_ln}" unless @loop_examples.size > 0
         | 
| 32 | 
            +
                  loop_n = 0
         | 
| 33 | 
            +
                  @loop_examples.each do |exa|
         | 
| 34 | 
            +
                    loop_n += 1
         | 
| 35 | 
            +
                    vars = YAML.load(exa)
         | 
| 36 | 
            +
                    # erubie the template
         | 
| 37 | 
            +
                    rslt = Erubis::Eruby.new(@loop_template).result(vars)
         | 
| 38 | 
            +
                    li = 0
         | 
| 39 | 
            +
                    rslt.split("\n").each do |line|
         | 
| 40 | 
            +
                      li += 1
         | 
| 41 | 
            +
                      self.process_line line, @loop_start_ln + li, loop_n
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                  
         | 
| 45 | 
            +
                  # clear up holders
         | 
| 46 | 
            +
                  self.reset_loop
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def dump contents
         | 
| 50 | 
            +
                  @output.print contents if contents
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                # travel up through the token stack, close all token with
         | 
| 54 | 
            +
                # indent level larger or equal to the parameter
         | 
| 55 | 
            +
                def close_stack indent_level
         | 
| 56 | 
            +
                  source = ''
         | 
| 57 | 
            +
                  while @token_stack.size > 0 and @token_stack[-1].indent_level >= indent_level
         | 
| 58 | 
            +
                    if @token_stack.size > 1 
         | 
| 59 | 
            +
                      @token_stack[-2].add_block_code @driver.convert(@token_stack[-1])
         | 
| 60 | 
            +
                    else # this is the last token in the stack
         | 
| 61 | 
            +
                      self.dump(@driver.convert(@token_stack[-1]))
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                    @token_stack.pop
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                # add a new line to the existing token if it requires block codes
         | 
| 68 | 
            +
                # or write the last token out before a new token
         | 
| 69 | 
            +
                # this function invokes after a loop expansion.
         | 
| 70 | 
            +
                def process_line line, ln, loop_n = 0
         | 
| 71 | 
            +
                  indent_level = 0
         | 
| 72 | 
            +
                  if /^(?<head_space_>\s+)/ =~ line
         | 
| 73 | 
            +
                    indent_level = head_space_.size
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                  
         | 
| 76 | 
            +
                  # try to close stack if applicable
         | 
| 77 | 
            +
                  self.close_stack indent_level
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  # starts a named_processor or starts a raw_processor 
         | 
| 80 | 
            +
                  processor_name = '_raw'
         | 
| 81 | 
            +
                  line_code = line.gsub(/^\s*/,"")
         | 
| 82 | 
            +
                  block_code = nil
         | 
| 83 | 
            +
                  if matches = /#{regex_proc_line}/.match(line) 
         | 
| 84 | 
            +
                    processor_name = matches["proc_name_"]
         | 
| 85 | 
            +
                    line_code = matches["line_code_"]
         | 
| 86 | 
            +
                    block_code = '' if line_code.gsub!(/#{regex_block_start}/, '')
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                  
         | 
| 89 | 
            +
                  @token_stack << Token.new(ln, line, indent_level, processor_name, line_code, block_code)
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  # unless it opens for block code close it soon, 
         | 
| 92 | 
            +
                  # (dedicate the dump function to close_stack())
         | 
| 93 | 
            +
                  self.close_stack indent_level unless block_code
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                # add a new line to the example, separate examples to array
         | 
| 97 | 
            +
                def add_example_line line
         | 
| 98 | 
            +
                  if /#{regex_new_example}/.match(line)
         | 
| 99 | 
            +
                    # start a new loop example with a placeholder nil        
         | 
| 100 | 
            +
                    @loop_examples << nil
         | 
| 101 | 
            +
                  else
         | 
| 102 | 
            +
                    raise "you need use '#{regex_new_example}' to start a loop example" unless @loop_examples.size > 0
         | 
| 103 | 
            +
                    line.gsub!(/#{regex_example_head}/, '')
         | 
| 104 | 
            +
                    @loop_examples[-1] = @loop_examples[-1] ? @loop_examples[-1] + "\n" + line : line
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                # regex configurations
         | 
| 109 | 
            +
                # match characters before a processor keyword
         | 
| 110 | 
            +
                def regex_proc_head
         | 
| 111 | 
            +
                  "\s*(\#{2,}|\-{2,}|\/{2,})?\s*"
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                def regex_proc_name
         | 
| 115 | 
            +
                  "(?<proc_name_>[A-Z][A-Z0-9_]+)"
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                def regex_proc_end
         | 
| 119 | 
            +
                  "\s*\:?\s*"
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                def regex_proc_line
         | 
| 123 | 
            +
                  "^" + regex_proc_head + regex_proc_name + regex_proc_end + "(?<line_code_>.+)"
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                def regex_block_start
         | 
| 127 | 
            +
                  "\s*(?<block_start_>\-\>)?\s*$"
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                def regex_loop_line
         | 
| 131 | 
            +
                  "^" + regex_proc_head + "\%\s*\=\=\=\=+\s*"
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def regex_new_example
         | 
| 135 | 
            +
                  "^" + regex_proc_head + "\%\s*\-\-\-\-+\s*"
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                def regex_example_head
         | 
| 139 | 
            +
                  "^" + regex_proc_head + "\%\s*"
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                def regex_example_line
         | 
| 143 | 
            +
                  "^" + regex_proc_head + "\%\s*(?<example_>.+)\s*"
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                # parse the file, whenever found a token, use driver to convert
         | 
| 147 | 
            +
                # it and send to output
         | 
| 148 | 
            +
                def process
         | 
| 149 | 
            +
                  in_loop = false
         | 
| 150 | 
            +
                  in_example = false
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                  fh = File.open(@source_file, 'r:utf-8')
         | 
| 153 | 
            +
                  fh.each do |line|
         | 
| 154 | 
            +
                    line.chomp!
         | 
| 155 | 
            +
                    line.gsub!("\t", "  ") # convert tab to 2 spaces
         | 
| 156 | 
            +
                    
         | 
| 157 | 
            +
                    # ensure first line as driver definition
         | 
| 158 | 
            +
                    unless @driver
         | 
| 159 | 
            +
                      if matches = /^#{regex_proc_head}DRIVER#{regex_proc_end}(?<dname_>\w+)\s*$/.match(line)
         | 
| 160 | 
            +
                        @driver = Driver.create(matches["dname_"])
         | 
| 161 | 
            +
                        self.dump(@driver.setup)
         | 
| 162 | 
            +
                        next
         | 
| 163 | 
            +
                      else
         | 
| 164 | 
            +
                        raise "You must specify a driver on the first line"
         | 
| 165 | 
            +
                      end
         | 
| 166 | 
            +
                    end
         | 
| 167 | 
            +
                    
         | 
| 168 | 
            +
                    # interrupt for loops
         | 
| 169 | 
            +
                    if matches = /#{regex_loop_line}/.match(line)
         | 
| 170 | 
            +
                      in_loop = true
         | 
| 171 | 
            +
                      @loop_start_ln = $.
         | 
| 172 | 
            +
                      next
         | 
| 173 | 
            +
                    end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                    # expand and end current loop 
         | 
| 176 | 
            +
                    if in_example
         | 
| 177 | 
            +
                      unless /#{regex_example_head}/.match(line)
         | 
| 178 | 
            +
                        self.expand_loop
         | 
| 179 | 
            +
                        in_example = false
         | 
| 180 | 
            +
                        in_loop = false
         | 
| 181 | 
            +
                      end
         | 
| 182 | 
            +
                    end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                    # end a loop template and start a loop example
         | 
| 185 | 
            +
                    if in_loop
         | 
| 186 | 
            +
                      in_example = true if /#{regex_example_head}/.match(line)
         | 
| 187 | 
            +
                    end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                    # dispatch the current line to different holders
         | 
| 190 | 
            +
                    if in_example
         | 
| 191 | 
            +
                      self.add_example_line line
         | 
| 192 | 
            +
                    elsif in_loop
         | 
| 193 | 
            +
                      @loop_template = @loop_template ? @loop_template + "\n" + line : line
         | 
| 194 | 
            +
                    else
         | 
| 195 | 
            +
                      self.process_line line, $.
         | 
| 196 | 
            +
                    end
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
                  fh.close
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                  # do not forget expand last loop if it reaches over EOF.
         | 
| 201 | 
            +
                  self.expand_loop if @loop_start_ln > 0
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                  # close all remain stacks
         | 
| 204 | 
            +
                  self.close_stack 0
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                  self.dump(@driver.exit)
         | 
| 207 | 
            +
                  @output.close
         | 
| 208 | 
            +
                  self
         | 
| 209 | 
            +
                end
         | 
| 210 | 
            +
              end
         | 
| 211 | 
            +
            end
         | 
    
        data/lib/luobo/driver.rb
    ADDED
    
    | @@ -0,0 +1,46 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Luobo
         | 
| 4 | 
            +
              class Driver 
         | 
| 5 | 
            +
                
         | 
| 6 | 
            +
                ## implements the factory pattern
         | 
| 7 | 
            +
                @@drivers = {}
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def self.create type
         | 
| 10 | 
            +
                  c = @@drivers[type.to_sym]
         | 
| 11 | 
            +
                  raise "No registered driver for type #{type.to_s}" unless c
         | 
| 12 | 
            +
                  c.new
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
                def self.register_driver type
         | 
| 16 | 
            +
                  raise "Driver for #{type.to_s} already registed." if @@drivers[type.to_sym]
         | 
| 17 | 
            +
                  @@drivers[type.to_sym] = self
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                ## cross-drivers methods and callbacks
         | 
| 21 | 
            +
                def convert token
         | 
| 22 | 
            +
                  pname = "do_" + token.processor_name.downcase
         | 
| 23 | 
            +
                  if self.respond_to?(pname)
         | 
| 24 | 
            +
                    self.send(pname.to_sym, token)
         | 
| 25 | 
            +
                  else
         | 
| 26 | 
            +
                    self.do__missing(token)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def exit; end
         | 
| 31 | 
            +
                def setup; end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def indent token
         | 
| 34 | 
            +
                  " " * token.indent_level
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def do__raw token
         | 
| 38 | 
            +
                  indent(token) + token.line_code.gsub(/^\s*/, "") + "\n"
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def do__missing token
         | 
| 42 | 
            +
                  src = indent(token) + token.line
         | 
| 43 | 
            +
                  src += token.block_code + "\n" if token.block_code
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
    
        data/lib/luobo/token.rb
    ADDED
    
    | @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module Luobo
         | 
| 2 | 
            +
              ## this class holds a block of carrot source code tokenized by the parser.
         | 
| 3 | 
            +
              class Token
         | 
| 4 | 
            +
                attr_accessor :ln, :line, :indent_level, :processor_name, :line_code, :block_code
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize ln, line, indent_level, processor_name, line_code, block_code
         | 
| 7 | 
            +
                  @ln, @line, @indent_level, @processor_name, @line_code, @block_code = ln, line, indent_level, processor_name, line_code, block_code
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
                # add a line to current block args, separate each line with "\n"
         | 
| 11 | 
            +
                def add_block_code line
         | 
| 12 | 
            +
                  line.chomp!
         | 
| 13 | 
            +
                  if self.block_code 
         | 
| 14 | 
            +
                    self.block_code += "\n" + line
         | 
| 15 | 
            +
                  else
         | 
| 16 | 
            +
                    self.block_code = line
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def block_args
         | 
| 21 | 
            +
                  YAML.load(block_code)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def line_args
         | 
| 25 | 
            +
                  YAML.load(line_code)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
    
        data/luobo.gemspec
    ADDED
    
    | @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
         | 
| 2 | 
            +
            require 'luobo/version'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Gem::Specification.new 'luobo', Luobo::VERSION do |s|
         | 
| 5 | 
            +
              s.description       = "Luobo is a simple, easy to extend code generator."
         | 
| 6 | 
            +
              s.summary           = "Easy to extend code generator"
         | 
| 7 | 
            +
              s.authors           = ["Huang Wei"]
         | 
| 8 | 
            +
              s.email             = "huangw@pe-po.com"
         | 
| 9 | 
            +
              s.homepage          = "https://github.com/huangw/luobo-gem"
         | 
| 10 | 
            +
              s.executables       << "tuzi"
         | 
| 11 | 
            +
              s.files             = `git ls-files`.split("\n") - %w[.gitignore]
         | 
| 12 | 
            +
              s.test_files        = Dir.glob("{spec,test}/**/*.rb")
         | 
| 13 | 
            +
              s.rdoc_options      = %w[--line-numbers --inline-source --title Luobo --main README.rdoc --encoding=UTF-8]
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              s.add_development_dependency 'rspec', '~> 2.5'
         | 
| 16 | 
            +
              s.add_dependency 'erubis'
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
    
        data/spec/driver_spec.rb
    ADDED
    
    | @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Luobo::Driver do
         | 
| 4 | 
            +
              class TestDriver < Luobo::Driver 
         | 
| 5 | 
            +
                def do_test_met(tk) 
         | 
| 6 | 
            +
                  "test method" 
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
                register_driver :test_driver
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              describe "create test driver" do
         | 
| 12 | 
            +
                subject(:test_driver) do
         | 
| 13 | 
            +
                  Luobo::Driver.create(:test_driver)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                it "is a test driver object" do
         | 
| 17 | 
            +
                  test_driver.is_a?(TestDriver).should be_true
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                its :class do
         | 
| 21 | 
            +
                  should eq(TestDriver)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                it "inherit driver methods" do
         | 
| 25 | 
            +
                  tk = Luobo::Token.new(1, '', 1, 'test_met', '', '')
         | 
| 26 | 
            +
                  test_driver.convert(tk).should eq("test method")
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            end
         | 
    
        data/spec/parser_spec.rb
    ADDED
    
    | @@ -0,0 +1,78 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Luobo::Base do
         | 
| 4 | 
            +
              class OutputHolder < IO
         | 
| 5 | 
            +
                attr_accessor :text
         | 
| 6 | 
            +
                def initialize; @text = {} end
         | 
| 7 | 
            +
                def print(str)
         | 
| 8 | 
            +
                  str.split("\n").each {|t| @text[t] = true}
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
                def close; end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              class AstDriver < Luobo::Driver
         | 
| 14 | 
            +
                attr_accessor :asserts
         | 
| 15 | 
            +
                def initialize
         | 
| 16 | 
            +
                  super()
         | 
| 17 | 
            +
                  @asserts = []
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def do_ast token
         | 
| 21 | 
            +
                  str = ''
         | 
| 22 | 
            +
                  if /(?<ident_>\d+),\s*(?<rm_>.+)/ =~ token.line_code
         | 
| 23 | 
            +
                    str = " "*ident_.to_i + rm_
         | 
| 24 | 
            +
                  else
         | 
| 25 | 
            +
                    str = token.line_code
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  @asserts << str
         | 
| 28 | 
            +
                  nil
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def do_split token
         | 
| 32 | 
            +
                  src = ""
         | 
| 33 | 
            +
                  token.line_code.split(/\s+/).each do |line|
         | 
| 34 | 
            +
                    src += line + "\n"
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  src
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
                
         | 
| 39 | 
            +
                def do_spec token
         | 
| 40 | 
            +
                  src = indent(token) + "spec \"#{token.line_code}\" do"
         | 
| 41 | 
            +
                  src += token.block_code ? token.block_code : ""
         | 
| 42 | 
            +
                  src += "\n" + indent(token) + "end\n"
         | 
| 43 | 
            +
                  src
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def do_hash token
         | 
| 47 | 
            +
                  hash = token.line_args if token.line_code.size > 0
         | 
| 48 | 
            +
                  if token.block_code.size > 0
         | 
| 49 | 
            +
                    hash = hash.is_a?(Hash) ? hash.merge(token.block_args) : token.block_args
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                  src = ""
         | 
| 52 | 
            +
                  hash.each do |k,v|
         | 
| 53 | 
            +
                    src += indent(token) + "key: #{k}\n"
         | 
| 54 | 
            +
                    src += indent(token) + "value: #{v}\n"
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                  src
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
                
         | 
| 59 | 
            +
                register_driver :ast
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              describe "convert" do
         | 
| 63 | 
            +
                oh = OutputHolder.new
         | 
| 64 | 
            +
                base = Luobo::Base.new("example/parser.lub", oh).process
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                it "base should have a AstDriver" do
         | 
| 67 | 
            +
                  base.driver.is_a?(AstDriver)
         | 
| 68 | 
            +
                  p oh.text
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                base.driver.asserts.each do |line|
         | 
| 72 | 
            +
                  it "can parse #{line}" do
         | 
| 73 | 
            +
                    oh.text[line].should be_true
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
    
        data/spec/token_spec.rb
    ADDED
    
    | @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            require "spec_helper"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Luobo::Token do
         | 
| 4 | 
            +
              subject (:token) do
         | 
| 5 | 
            +
                Luobo::Token.new(1, "line", 4, "Echo", "same: hash", "['block', 'in', 'array']") 
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              its :ln do 
         | 
| 9 | 
            +
                should eq(1) 
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              its :line do
         | 
| 13 | 
            +
                should eq("line")
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              its :indent_level do
         | 
| 17 | 
            +
                should eq(4)
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              its :processor_name do
         | 
| 21 | 
            +
                should eq("Echo")
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              its :line_args do
         | 
| 25 | 
            +
                token.line_args["same"].should eq("hash")
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              its :block_args do
         | 
| 29 | 
            +
                token.block_args[2].should eq("array")
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,102 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: luobo
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
              prerelease: 
         | 
| 6 | 
            +
            platform: ruby
         | 
| 7 | 
            +
            authors:
         | 
| 8 | 
            +
            - Huang Wei
         | 
| 9 | 
            +
            autorequire: 
         | 
| 10 | 
            +
            bindir: bin
         | 
| 11 | 
            +
            cert_chain: []
         | 
| 12 | 
            +
            date: 2013-03-17 00:00:00.000000000 Z
         | 
| 13 | 
            +
            dependencies:
         | 
| 14 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 15 | 
            +
              name: rspec
         | 
| 16 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 | 
            +
                none: false
         | 
| 18 | 
            +
                requirements:
         | 
| 19 | 
            +
                - - ~>
         | 
| 20 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            +
                    version: '2.5'
         | 
| 22 | 
            +
              type: :development
         | 
| 23 | 
            +
              prerelease: false
         | 
| 24 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 | 
            +
                none: false
         | 
| 26 | 
            +
                requirements:
         | 
| 27 | 
            +
                - - ~>
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            +
                    version: '2.5'
         | 
| 30 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 31 | 
            +
              name: erubis
         | 
| 32 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 33 | 
            +
                none: false
         | 
| 34 | 
            +
                requirements:
         | 
| 35 | 
            +
                - - ! '>='
         | 
| 36 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 37 | 
            +
                    version: '0'
         | 
| 38 | 
            +
              type: :runtime
         | 
| 39 | 
            +
              prerelease: false
         | 
| 40 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 41 | 
            +
                none: false
         | 
| 42 | 
            +
                requirements:
         | 
| 43 | 
            +
                - - ! '>='
         | 
| 44 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 45 | 
            +
                    version: '0'
         | 
| 46 | 
            +
            description: Luobo is a simple, easy to extend code generator.
         | 
| 47 | 
            +
            email: huangw@pe-po.com
         | 
| 48 | 
            +
            executables:
         | 
| 49 | 
            +
            - tuzi
         | 
| 50 | 
            +
            extensions: []
         | 
| 51 | 
            +
            extra_rdoc_files: []
         | 
| 52 | 
            +
            files:
         | 
| 53 | 
            +
            - README.rdoc
         | 
| 54 | 
            +
            - Rakefile
         | 
| 55 | 
            +
            - bin/tuzi
         | 
| 56 | 
            +
            - example/parser.lub
         | 
| 57 | 
            +
            - lib/luobo.rb
         | 
| 58 | 
            +
            - lib/luobo/base.rb
         | 
| 59 | 
            +
            - lib/luobo/driver.rb
         | 
| 60 | 
            +
            - lib/luobo/token.rb
         | 
| 61 | 
            +
            - lib/luobo/version.rb
         | 
| 62 | 
            +
            - luobo.gemspec
         | 
| 63 | 
            +
            - spec/driver_spec.rb
         | 
| 64 | 
            +
            - spec/parser_spec.rb
         | 
| 65 | 
            +
            - spec/spec_helper.rb
         | 
| 66 | 
            +
            - spec/token_spec.rb
         | 
| 67 | 
            +
            homepage: https://github.com/huangw/luobo-gem
         | 
| 68 | 
            +
            licenses: []
         | 
| 69 | 
            +
            post_install_message: 
         | 
| 70 | 
            +
            rdoc_options:
         | 
| 71 | 
            +
            - --line-numbers
         | 
| 72 | 
            +
            - --inline-source
         | 
| 73 | 
            +
            - --title
         | 
| 74 | 
            +
            - Luobo
         | 
| 75 | 
            +
            - --main
         | 
| 76 | 
            +
            - README.rdoc
         | 
| 77 | 
            +
            - --encoding=UTF-8
         | 
| 78 | 
            +
            require_paths:
         | 
| 79 | 
            +
            - lib
         | 
| 80 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 81 | 
            +
              none: false
         | 
| 82 | 
            +
              requirements:
         | 
| 83 | 
            +
              - - ! '>='
         | 
| 84 | 
            +
                - !ruby/object:Gem::Version
         | 
| 85 | 
            +
                  version: '0'
         | 
| 86 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 87 | 
            +
              none: false
         | 
| 88 | 
            +
              requirements:
         | 
| 89 | 
            +
              - - ! '>='
         | 
| 90 | 
            +
                - !ruby/object:Gem::Version
         | 
| 91 | 
            +
                  version: '0'
         | 
| 92 | 
            +
            requirements: []
         | 
| 93 | 
            +
            rubyforge_project: 
         | 
| 94 | 
            +
            rubygems_version: 1.8.24
         | 
| 95 | 
            +
            signing_key: 
         | 
| 96 | 
            +
            specification_version: 3
         | 
| 97 | 
            +
            summary: Easy to extend code generator
         | 
| 98 | 
            +
            test_files:
         | 
| 99 | 
            +
            - spec/driver_spec.rb
         | 
| 100 | 
            +
            - spec/parser_spec.rb
         | 
| 101 | 
            +
            - spec/spec_helper.rb
         | 
| 102 | 
            +
            - spec/token_spec.rb
         |