首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 使用 IronRuby 解析並以樹狀結構顯示 Ruby 類別資訊

     編輯:關於C#

前言:IronRuby 與反射的結合

IronRuby 是 .NET 平台上的 Ruby 實作,利用 DLR (Dynamic Language Runtime) 執行。雖然 Ruby 本身支援反射可取得方法名稱,但無法直接獲取方法參數清單與參數名稱。本文展示如何透過 IronRuby 解析 Ruby 腳本,提取類別名稱、方法名稱與參數資訊,並以樹狀圖形化呈現。

架構設計:雙核心類別

類別圖設計
圖 1:類別關係圖
  • RubyScriptEngine:負責載入 Ruby 檔案,動態解析類別、方法與參數關係。
  • TreeDrawer:負責將解析資料轉換為座標結構,繪製樹狀圖片。

RubyScriptEngine 核心實作

引擎初始化建立 ScriptEngine,提供載入檔案/目錄、取得類別名稱與詳細資訊的方法:

public static class RubyScriptEngine
{
    private static readonly ScriptEngine engine = Ruby.CreateEngine();

    public static bool InitRelativeFiles(string directory) { /* 載入目錄下所有 .rb 檔 */ }
    public static bool InitRelativeFile(string fileName) { /* 載入單一 .rb 檔 */ }
    public static IList<string> GetClassNames() { /* 取得全域變數名稱作為類別名 */ }
    public static IList<ClassItem> GetClassesInfos() { /* 批次取得所有類別資訊 */ }

    public static ClassItem GetClassInfo(string className, params object[] parameters)
    {
        RubyClass rubyClass = engine.Runtime.Globals.GetVariable(className);
        dynamic instance = engine.Operations.CreateInstance(rubyClass, parameters);
        ClassItem classItem = new ClassItem(className);

        foreach (string memberName in engine.Operations.GetMemberNames(instance))
        {
            RubyMethodInfo methodInfo = rubyClass.GetMethod(memberName) as RubyMethodInfo;
            if (methodInfo == null) continue;

            MethodItem methodItem = new MethodItem(memberName, className);
            RubyArray parameterArray = methodInfo.GetRubyParameterArray();
            SimpleAssignmentExpression[] expressions = methodInfo.Parameters.Optional;

            for (int i = 0; i < parameterArray.Count; i++)
            {
                RubyArray vas = parameterArray[i] as RubyArray;
                string type = vas[0].ToString();
                string name = vas[1].ToString();
                ParameterItem parameterItem = new ParameterItem(name);

                if (type == "rest") { parameterItem.DefaultName = "*" + name; parameterItem.Description = RubyResource.ArrayParamDesc; }
                else if (type == "opt") { /* 處理預設值參數 */ }
                else if (type == "block") { parameterItem.DefaultName = "&" + name; parameterItem.Description = RubyResource.BlockParamDesc; }
                else { parameterItem.DefaultName = name; }

                methodItem.Parameters.Add(parameterItem);
            }
            classItem.Methods.Add(methodItem);
        }
        return classItem;
    }
}
類別資訊顯示效果
圖 2:左側顯示類別資訊,右側為編輯器原始碼

TreeDrawer 繪圖邏輯

主要方法 CreateImage 與 CreateCurrentClassBlock:前者負責繪製 Bitmap,後者將資料模型 (ClassItem) 轉換為座標模型 (ClassBlock),自動計算區塊位置與連線。

public Bitmap CreateImage(ClassItem classItem, Font font)
{
    if (classItem == null || font == null) return null;
    ClassBlock classBlock = CreateCurrentClassBlock(classItem);
    AddLinesAndBlockTexts(classBlock, font);
    Bitmap bitmap = new Bitmap(3 * BLOCK_WIDTH + 2 * BLOCK_INNER_WIDTH, this.Height);
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        g.Clear(Color.White);
        Pen pen = new Pen(Color.Blue, 2);
        foreach (Line line in this.Lines)
        {
            g.DrawLine(pen, line.X1, line.Y1, line.X2, line.Y2);
            if (line.HasArrow) DrawArrowHead(g, CreateArrowPoints(...));
        }
        foreach (BlockText content in this.Contents)
            g.DrawString(content.Content, font, Brushes.Black, content.StartX, content.StartY);
    }
    return bitmap;
}
樹狀結構顯示效果
圖 3:自動佈局的樹狀結構圖

動態呼叫對比:DLR vs IronRuby API

若僅需呼叫單一類別方法,.NET 4.0 的 dynamic 更簡潔:

dynamic globals = engine.Runtime.Globals;
dynamic obj = globals.PersonClass.@new();
obj.nonArgsMethod();

本文採用 IronRuby API 係為通用性處理,支援依類別名稱與建構參數動態解析任意結構。

原始碼下載:IronRuby Ruby 類別樹狀結構原始碼

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved