On Dec 14, 7:03 am, Saladin Mundi <saladin.mu... / gmx.de> wrote: > hey guys > > I'm trying to split an string (which contains various method calls). > The result of the splitting of the string should be an array (or > something like that) which contains a sequence which an interpreter > would have called the methods. > Example > > class X > def test(input) > ... > end > end > > x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))") > > If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be > afterwards an arry like this: > > [0] -> var1 = z.methody() > [1] -> var2 = z.methodx > [2] -> var3 = z.methodz(var2) > [3] -> z.methodx(var1,var3) > > so the call(s on different methods) given by an input string shall be > extracted into the real execution sequence like an interpreter would > excecute this string it. On Dec 14, 7:03 am, Saladin Mundi <saladin.mu... / gmx.de> wrote: > hey guys > > I'm trying to split an string (which contains various method calls). > The result of the splitting of the string should be an array (or > something like that) which contains a sequence which an interpreter > would have called the methods. > Example > > class X > def test(input) > ... > end > end > > x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))") > > If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be > afterwards an arry like this: > > [0] -> var1 = z.methody() > [1] -> var2 = z.methodx > [2] -> var3 = z.methodz(var2) > [3] -> z.methodx(var1,var3) > > so the call(s on different methods) given by an input string shall be > extracted into the real execution sequence like an interpreter would > excecute this string it. > > I hope you can help me with my problem. Wow, that was harder than I expected. The big issue was parsing nested commands; I couldn't use regexps, so I had to create a little stack- based parser. Thanks for the fun challenge. In summary: puts MethodMunger.variable_stack( "z.methodx(z.methody(),z.methodz(z.methodx))" ) #=> var0 = z.methodx() #=> var1 = z.methody() #=> var2 = z.methodz( var0 ) #=> z.methodx( var1, var2 ) And now, the code, all unit tested: # Put MWI in the core! enum_for is retarded! module Enumerable def map_with_index idx = -1 map{ |v| yield v,idx+=1 } end end module MethodMunger require 'strscan' # MethodMunger.parse_method( "z.foo( bar( x ), y )" ) # #=> { # #=> :name=>"z.foo", # #=> :args=>[ # #=> { # #=> :name=>"bar", # #=> :args=>[ # #=> {:name=>"x"} # #=> ] # #=> }, # #=> {:name=>"y"} # #=> ] # #=> } def self.parse_method( source ) stack = [ ] current_method = nil mode = :prepare_method scanner = StringScanner.new( source ) until scanner.eos? case mode when :prepare_method new_method = {} current_method = new_method mode = :find_content when :add_argument new_method = {} (current_method[:args] ||= []) << new_method stack << current_method current_method = new_method mode = :find_content when :find_content if chunk = scanner.scan( /[\w.]+/ ) current_method[ :name ] = chunk elsif chunk = scanner.scan( /\(\s*/ ) mode = :add_argument elsif chunk = scanner.scan( /\s*,\s*/ ) current_method.delete(:args) if current_method[:args] == [{}] current_method = stack.pop mode = :add_argument elsif chunk = scanner.scan( /\s*\)/ ) current_method.delete(:args) if current_method[:args] == [{}] current_method = stack.pop end end end current_method.delete(:args) if current_method[:args] == [{}] current_method end def self.variable_stack( source ) method = parse_method( source ) variable_stack_from_parse( method ) end private def self.variable_stack_from_parse( method ) if method[:args] lines = [] params = method[:args].map{ |arg| var_lines = variable_stack_from_parse( arg ) arg_close = var_lines.pop lines.concat( var_lines ) arg_close } total_lines = lines.length params.each_with_index{ |var,i| lines << "var#{i+total_lines} = #{var}" } lines << "#{method[:name]}( #{ params.map_with_index{ |v,i| "var#{i + total_lines}" }.join(', ') } )" else ["#{method[:name]}()"] end end end puts MethodMunger.variable_stack( "z.methodx(z.methody(),z.methodz(z.methodx))" ) #=> var0 = z.methodx() #=> var1 = z.methody() #=> var2 = z.methodz( var0 ) #=> z.methodx( var1, var2 ) if __FILE__==$0 require 'test/unit' class TestParser < Test::Unit::TestCase def testa_no_arguments result = MethodMunger.parse_method "z.go( )" assert_equal( { :name=>"z.go" }, result ) result = MethodMunger.parse_method "z.go()" assert_equal( { :name=>"z.go" }, result ) result = MethodMunger.parse_method "z.go" assert_equal( { :name=>"z.go" }, result ) end def testb_no_nesting result = MethodMunger.parse_method "z.go( x )" assert_equal( { :name=>"z.go", :args=>[ { :name=>"x" } ] }, result ) result = MethodMunger.parse_method "z.go( x, y )" assert_equal( { :name=>"z.go", :args=>[ { :name=>"x" }, { :name=>"y" }, ] }, result ) result = MethodMunger.parse_method "z.go( w, x, y )" assert_equal( { :name=>"z.go", :args=>[ { :name=>"w" }, { :name=>"x" }, { :name=>"y" }, ] }, result ) end def testc_nesting result = MethodMunger.parse_method "z.go( x( y ) )" assert_equal( { :name=>"z.go", :args=>[ { :name=>"x", :args=>[ { :name=>"y" } ] }, ] }, result ) result = MethodMunger.parse_method "z.go( x( y, w ) )" assert_equal( { :name=>"z.go", :args=>[ { :name=>"x", :args=>[ { :name=>"y" }, { :name=>"w" }, ] }, ] }, result ) result = MethodMunger.parse_method "z.go( foo( bar ),x( y, w ) )" assert_equal( { :name=>"z.go", :args=>[ { :name=>"foo", :args=>[ { :name=>"bar" }, ] }, { :name=>"x", :args=>[ { :name=>"y" }, { :name=>"w" }, ] }, ] }, result ) end end class TestMunger < Test::Unit::TestCase def test_a_no_args result = MethodMunger.variable_stack "z.go()" assert_equal( ["z.go()"], result ) result = MethodMunger.variable_stack "z.go( )" assert_equal( ["z.go()"], result ) result = MethodMunger.variable_stack "z.go" assert_equal( ["z.go()"], result ) end def test_b_one_arg result = MethodMunger.variable_stack "z.go(y.foo)" assert_equal( ["var0 = y.foo()","z.go( var0 )"], result ) result = MethodMunger.variable_stack "z.go( y.foo( ) )" assert_equal( ["var0 = y.foo()","z.go( var0 )"], result ) end def test_c_multi_args result = MethodMunger.variable_stack "z.go(y.foo,x.bar)" assert_equal( [ "var0 = y.foo()", "var1 = x.bar()", "z.go( var0, var1 )" ], result ) result = MethodMunger.variable_stack "z.go( y.foo(), x.bar() )" assert_equal( [ "var0 = y.foo()", "var1 = x.bar()", "z.go( var0, var1 )" ], result ) end def test_d_nest_singles result = MethodMunger.variable_stack "z.go( y.foo( x.bar ) )" assert_equal( [ "var0 = x.bar()", "var1 = y.foo( var0 )", "z.go( var1 )" ], result ) result = MethodMunger.variable_stack "z.go( y.foo( x.bar( w.jim ) ) )" assert_equal( [ "var0 = w.jim()", "var1 = x.bar( var0 )", "var2 = y.foo( var1 )", "z.go( var2 )" ], result ) end def test_e_nest_more result = MethodMunger.variable_stack "z.go( y.foo( x.bar, w.jim ) )" assert_equal( [ "var0 = x.bar()", "var1 = w.jim()", "var2 = y.foo( var0, var1 )", "z.go( var2 )" ], result ) end end end