59875


こんにちは。Rubyに関する質問です。あるクラスに定義されているメソッドを、自動で並び替えたいのですがどうするとよいでしょうか？  
たとえば、下記のようなたくさんのメソッドが定義されているクラスがあったとして、

[code]

    class
      def z
        "z"
      end
    
      def y
        "y"
      end
    
      def x
        "x"
      end
    
      # 中略 ---
    
      def b
        "b"
      end
    
      def a
        "a"
      end
    end
    
[/code]

このコード上のメソッドの順番を名前の順番に並び替えたいとします。

[code]

    class
      def a
        "a"
      end
    
      def b
        "b"
      end
    
      def c
        "c"
      end
    
      # 中略 ---
    
      def y
        "y"
      end
    
      def z
        "z"
      end
    end
    
[/code]

今回はたまたまreverseしているだけですが、メソッドはランダムに並んでいて、並べかえたい順番は別に与えられているとします。どうするのが良いでしょうか？


CC BY-SA 4.0
2019-10-22T06:20:19.380
59870
2019-10-22T11:00:45.433
32772
question
ruby
コード上のRubyのメソッドの順番を並び変える方法


強引な方法ですが、`source_location` と `eval`
を使って処理しています。前提として、対象のソースコードファイルには一つのクラス定義のみが記述されていて、インスタンスメソッド以外の宣言・定義は無視されます(出力されません)。

**TestClass.rb**

[code]

    class TestClass
      def z
        "z"
      end
    
      def y
        "y"
      end
    
      def x
        "x"
      end
    
      def b
        "b"
      end
    
      def a
        "a"
      end
    
      def h
        if true
          puts "h"
        end
      end
    
      def w; "w" end
    end
    
[/code]

**sort_method.rb**

[code]

    src_file = './TestClass.rb'
    src = IO.readlines(src_file)
    
    cls = ObjectSpace.each_object(Class).to_a
    load src_file
    new_cls = (ObjectSpace.each_object(Class).to_a - cls)[0]
    
    printf("class %s\n", new_cls)
    new_cls.instance_methods(false).sort.each {|name|
      _, start = new_cls.instance_method(name).source_location
      next if !start
      start -= 1
      i = 1
      loop do
        begin
          eval src[start, i].join
        rescue SyntaxError
          i += 1  
          next
        end
        break
      end  
      puts src[start, i].join, "\n"
    }
    puts 'end'
    
[/code]

**実行**

[code]

    $ ruby sort_method.rb
    
    class TestClass
      def a
        "a"
      end
    
      def b
        "b"
      end
    
      def h
        if true
          puts "h"
        end
      end
    
      def w; "w" end
    
      def x
        "x"
      end
    
      def y
        "y"
      end
    
      def z
        "z"
      end
    
    end
    
[/code]


CC BY-SA 4.0
2019-10-22T11:00:45.433
59875
2019-10-22T11:00:45.433
59870
answer