Changeset 1034
- Timestamp:
- 2008-05-30 14:24:28 (7 months ago)
- Files:
-
- trunk/lib/parser/lib/parser.rb (modified) (4 diffs)
- trunk/lib/parser/lib/rules/zena.rb (modified) (12 diffs)
- trunk/lib/parser/test/parser_test.rb (modified) (3 diffs)
- trunk/test/helpers/zena_parser/basic.yml (modified) (1 diff)
- trunk/test/helpers/zena_parser/errors.yml (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/lib/parser/lib/parser.rb
r997 r1034 282 282 283 283 # Return a has of all descendants. Find a specific descendant with descendant['form'] for example. 284 def descendants285 @ descendants ||= begin284 def all_descendants 285 @all_descendants ||= begin 286 286 d = {} 287 287 @blocks.each do |b| … … 299 299 end 300 300 301 def descendants(key) 302 all_descendants[key] || [] 303 end 304 301 305 def ancestors 302 306 @ancestors ||= begin … … 309 313 end 310 314 311 alias public_descendants descendants315 alias public_descendants all_descendants 312 316 313 317 # Return the last defined parent for the given key. … … 325 329 # Return the last defined descendant for the given key. 326 330 def descendant(key) 327 (descendants[key] || []).last331 descendants(key).last 328 332 end 329 333 trunk/lib/parser/lib/rules/zena.rb
r1033 r1034 122 122 end 123 123 @anchor_param = @params[:anchor] 124 124 125 125 true 126 126 end … … 128 128 def do_method(sym) 129 129 method = sym 130 pre, post = '', '' 131 130 132 if method == :r_unknown 131 133 if @method =~ /^\[(.*)\]$/ … … 142 144 if inc && inc.params[:part] == @name 143 145 @context["#{@name}_method".to_sym] = method_name = get_template_url[1..-1].gsub('/','_') 144 pre ="<% def #{method_name}(depth, node, list); return '' if depth > #{inc.params[:depth] ? [inc.params[:depth].to_i,30].min : 5}; _erbout = '' -%>"145 post ="<% _erbout; end -%><%= #{method_name}(0,#{node},#{list || "[#{node}]"}) %>"146 pre << "<% def #{method_name}(depth, node, list); return '' if depth > #{inc.params[:depth] ? [inc.params[:depth].to_i,30].min : 5}; _erbout = '' -%>" 147 post << "<% _erbout; end -%><%= #{method_name}(0,#{node},#{list || "[#{node}]"}) %>" 146 148 @context[:node] = 'node' 147 149 @context[:list] = 'list' … … 174 176 res ||= super(method) 175 177 176 if pre 177 "#{pre}#{res}#{post}" 178 else 179 res 180 end 178 "#{pre}#{res}#{post}" 181 179 end 182 180 … … 195 193 def r_show 196 194 attribute = @params[:attr] || @params[:tattr] 197 if @params[:tattr] 195 if var_name = @params[:var] 196 return parser_error("var #{@params[:var].inspect} not set") unless @context[:vars] && @context[:vars].include?(var_name) 197 attribute_method = "set_#{var_name}" 198 elsif @params[:eval] 199 return unless attribute_method = parse_eval_parameter(@params[:eval]) 200 elsif @params[:tattr] 198 201 attribute_method = "_(#{node_attribute(attribute, :else=>@params[:else])})" 199 202 elsif @params[:attr] 200 if @params[:format] 201 attribute_method = "sprintf(#{@params[:format].inspect}, #{node_attribute(attribute, :else=>@params[:else])})" 202 else 203 attribute_method = "#{node_attribute(attribute, :else=>@params[:else])}" 204 end 203 attribute_method = node_attribute(attribute, :else=>@params[:else]) 205 204 elsif @params[:date] 206 205 # date can be any attribute v_created_at or updated_at etc. … … 237 236 else 238 237 return parser_error("missing attribute") 238 end 239 240 if !@params[:date] && fmt = @params[:format] 241 begin 242 # test argument 243 sprintf(fmt, 123.45) 244 rescue ArgumentError 245 return parser_error("incorect format #{fmt.inspect}") 246 end 247 if fmt =~ /%[\d\.]*f/ 248 modifier = ".to_f" 249 elsif fmt =~ /%[\d\.]*i/ 250 modifier = ".to_i" 251 else 252 modifier = '' 253 end 254 attribute_method = "sprintf(#{fmt.inspect}, #{attribute_method}#{modifier})" 239 255 end 240 256 … … 322 338 do_list("@nodes") 323 339 end 340 341 342 def r_set 343 return parser_error("'var' missing") unless var_name = @params[:var] 344 return parser_error("bad value for 'var' (#{var_name.inspect})") unless var_name =~ /^[a-zA-Z_]+$/ 345 return '' unless @context[:set] 346 if @params[:value] 347 out "<% set_#{var_name} = #{@params[:value].inspect} -%>" 348 elsif @params[:eval] 349 return unless eval_string = parse_eval_parameter(@params[:eval]) 350 out "<% set_#{var_name} = #{eval_string} -%>" 351 else 352 out "<% set_#{var_name} = capture do %>" 353 out expand_with(:set => false) # do not propagate 354 out "<% end -%>" 355 end 356 end 357 324 358 325 359 # TODO: write a test (please) … … 703 737 set_fields = [] 704 738 var_name = base_class.to_s.underscore 705 ( (descendants['input'] || []) + (descendants['select'] || [])).each do |tag|739 (descendants('input') + descendants('select')).each do |tag| 706 740 set_fields << "#{var_name}[#{tag.params[:name]}]" 707 741 end … … 873 907 add_btn = make(:void, :method=>'add_btn', :params=>@params.dup, :text=>'') 874 908 add_btn.blocks = blocks 875 remove_instance_variable(:@ descendants)909 remove_instance_variable(:@all_descendants) 876 910 end 877 911 … … 1162 1196 return expand_with(:in_if => false) 1163 1197 elsif cond == 'false' 1164 if (descendants['else'] || descendants['elsif'])1198 if descendant('else') || descendant('elsif') 1165 1199 return expand_with(:in_if=>true, :only=>['else', 'elsif']) 1166 1200 else … … 2270 2304 end 2271 2305 2306 def parse_eval_parameter(str) 2307 # evaluate an expression. Can only contain vars, '(', ')', '*', '+', '/', '-', '[attr]' 2308 # FIXME: SECURITY (audit this) 2309 vars = @context[:vars] || [] 2310 parts = str.split(/\s+/) 2311 res = [] 2312 test = [] 2313 parts.each do |p| 2314 if p =~ /\[([\w_]+)\]/ 2315 test << 1 2316 res << (node_attribute($1) + '.to_f') 2317 elsif p =~ /^[a-zA-Z_]+$/ 2318 unless vars.include?(p) 2319 out parser_error("var #{p.inspect} not set in eval") 2320 return nil 2321 end 2322 test << 1 2323 res << "set_#{p}.to_f" 2324 elsif ['(', ')', '*', '+', '/', '-'].include?(p) 2325 res << p 2326 test << p 2327 elsif p =~ /^[0-9\.]+$/ 2328 res << p 2329 test << p 2330 else 2331 out parser_error("bad argument #{p.inspect} in eval") 2332 return nil 2333 end 2334 end 2335 begin 2336 begin 2337 eval test.join(' ') 2338 rescue 2339 # rescue evaluation error 2340 out parser_error("error in eval") 2341 return nil 2342 end 2343 "(#{res.join(' ')})" 2344 rescue SyntaxError => err 2345 # rescue compilation error 2346 out parser_error("compilation error in eval") 2347 return nil 2348 end 2349 end 2350 2272 2351 def find_stored(klass, key) 2273 2352 @context["#{klass}_#{key}"] … … 2313 2392 def parser_error(message, tag=@method) 2314 2393 "<span class='parser_error'>[#{tag}] #{message}</span>" 2394 end 2395 2396 def expand_with(acontext={}) 2397 # set variables 2398 context = nil 2399 pre = '' 2400 @blocks.each do |block| 2401 next if block.kind_of?(String) || block.method != 'set' 2402 @context[:vars] ||= [] 2403 context ||= @context.merge(acontext).merge(:set => true) 2404 pre << expand_block(block, context) 2405 @context[:vars] << block.params[:var] 2406 end 2407 2408 pre + super 2315 2409 end 2316 2410 end trunk/lib/parser/test/parser_test.rb
r1006 r1034 96 96 end 97 97 98 def test_all_descendants 99 block = @@test_parsers['zafu'].new( 100 "<r:pages><r:each><b do='test'/></r:each><r:add><p><i do='add_link'/><b do='title'/></p></r:add><b do='title'/></r:pages>", 101 :helper=>ParserModule::DummyHelper.new(@@test_strings['basic'])) 102 assert_equal ['add', 'add_link', 'each', 'pages', 'test', 'title'], block.all_descendants.keys.sort 103 assert_equal 2, block.all_descendants['title'].size 104 assert_equal ['add_link', 'title'], block.descendant('add').all_descendants.keys.sort 105 end 106 98 107 def test_descendants 99 108 block = @@test_parsers['zafu'].new( 100 109 "<r:pages><r:each><b do='test'/></r:each><r:add><p><i do='add_link'/><b do='title'/></p></r:add><b do='title'/></r:pages>", 101 110 :helper=>ParserModule::DummyHelper.new(@@test_strings['basic'])) 102 assert_equal ['add', 'add_link', 'each', 'pages', 'test', 'title'], block.descendants.keys.sort103 assert_equal 2, block.descendants['title'].size104 assert_equal [ 'add_link', 'title'], block.descendant('add').descendants.keys.sort111 assert_equal 2, block.descendants('title').size 112 assert_equal ['test'], block.descendants('each')[0].descendants('test').map {|n| n.method} 113 assert_equal [], block.descendants('each')[0].descendants('foo') 105 114 end 106 115 … … 118 127 "<r:pages><r:each><b do='test'/></r:each><r:add><p><i do='add_link'/><b do='title'/></p></r:add><b do='title'/></r:pages>", 119 128 :helper=>ParserModule::DummyHelper.new(@@test_strings['basic'])) 120 block. descendants.merge('self'=>[block]).each do |k,blocks|129 block.all_descendants.merge('self'=>[block]).each do |k,blocks| 121 130 blocks.each do |b| 122 b.send(:remove_instance_variable, :@ descendants)131 b.send(:remove_instance_variable, :@all_descendants) 123 132 class << b 124 133 def public_descendants … … 132 141 end 133 142 end 134 assert_equal ['add', 'add_link', 'each', 'pages', 'title'], block. descendants.keys.sort135 assert_equal ['test'], block.descendant('each'). descendants.keys.sort143 assert_equal ['add', 'add_link', 'each', 'pages', 'title'], block.all_descendants.keys.sort 144 assert_equal ['test'], block.descendant('each').all_descendants.keys.sort 136 145 end 137 146 trunk/test/helpers/zena_parser/basic.yml
r1033 r1034 712 712 do_not_set_parent_id_if_form_contains_parent_id: 713 713 src: "<r:children><r:each do='[name]'/><r:add/><r:form><r:select name='parent_id' nodes='projects in site'/><input name='v_title'/></r:form></r:children>" 714 res: "!/node\[parent_id\] '\s+value='22'/"714 res: "!/node\[parent_id\].\s+value/" 715 715 716 716 select_nodes_in_ajax: trunk/test/helpers/zena_parser/errors.yml
r1000 r1034 37 37 src: "<r:date select='<% puts \"mean\" %>'/>" 38 38 res: "<span class='parser_error'>[date] bad parameter '<% puts \"mean\" %>'</span>" 39 40 show_var: 41 src: "<r:show var='boo'/>" 42 tem: "<span class='parser_error'>[show] var \"boo\" not set</span>" 43 44 show_bad_sprintf: 45 src: "<p do='show' attr='name' format='%.2f %i hop'/>" 46 res: "<p><span class='parser_error'>[show] incorect format \"%.2f %i hop\"</span></p>" 47 48 division_by_zero_in_eval: 49 src: "<r:set var='foo'>134</r:set><r:show eval='foo / 0'/>" 50 res: "<span class='parser_error'>[show] error in eval</span>" 51 52 division_by_zero_in_eval_on_runtime: 53 src: "<r:set var='foo'>134</r:set><r:show eval='foo / ( 21 - [id].to_f )'/>" 54 res: "Infinity" 55 56 bad_argument_list_in_eval: 57 src: "<r:show eval='3 * / * 5'/>" 58 res: "<span class='parser_error'>[show] compilation error in eval</span>" 59 60 nil_value: 61 src: "<r:show eval='4 * [d_bob]'/>" 62 res: "0.0" 63 64 mean_eval: 65 src: "<r:show eval='puts \"bad\"'/>" 66 tem: "<span class='parser_error'>[show] var \"puts\" not set in eval</span>"
