من الفكرة إلى أداة CLI بلغة Go: نكتب، نُجمّع، ننشر

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا Go هي اللغة المثالية لأدوات CLI؟

\n\n

تخيل: تحتاج إلى كتابة أداة سيتم تشغيلها في وحدة التحكم، ومعالجة الملفات، والاتصال بـ API، أو ببساطة أتمتة المهام الروتينية. يمكنك اختيار Python أو Node.js أو Bash. ولكن إذا كانت السرعة وحجم الملف الثنائي وسهولة التوزيع أمورًا حاسمة - فإن اختيارك هو أدوات CLI بلغة Go.

\n\n

يتم تجميع Go في ملف ثنائي ثابت واحد. لا تبعيات، ولا أسئلة مثل "هل لديك Python 3.8 مثبت؟". قم بالتنزيل والتشغيل. هذا يجعل أدوات Golang CLI المعيار الفعلي في عالم DevOps (تذكر Docker و Kubernetes و Hugo - كلها مكتوبة بلغة Go).

\n\n

في هذه المقالة، لن نتحدث فقط عن النظرية. سنقوم بإنشاء أداة وحدة تحكم بلغة Go حقيقية من الصفر، والتي ستقوم بتحليل JSON والعمل مع HTTP وعرض جداول جميلة. ستتعلم كيفية هيكلة المشروع ومعالجة الأخطاء والتجميع لأي منصة.

\n\n

إعداد البيئة وهيكل المشروع

\n\n

قبل كتابة الكود، تأكد من تثبيت Go (الإصدار 1.21+). يمكنك التحقق ببساطة:

\n\n
go version
\n\n

لنقم بإنشاء دليل لمشروعنا. سنسمي الأداة json2table - ستقوم بقراءة JSON من stdin أو ملف وعرض البيانات في شكل جدول.

\n\n
mkdir json2table\ncd json2table\ngo mod init github.com/your-username/json2table
\n\n

سيكون هيكل المشروع كلاسيكيًا لـ التطوير بلغة Go:

\n\n
    \n
  • main.go - نقطة الدخول
  • \n
  • internal/ - المنطق الداخلي (التحليل، العرض)
  • \n
  • cmd/ - كود معالجة الأوامر (إذا استخدمنا Cobra)
  • \n
\n\n

سنبدأ ببساطة، بدون أطر عمل، ثم سنضيف الأعلام والمساعدة.

\n\n

كتابة جوهر الأداة: تحليل JSON وعرض الجدول

\n\n

قم بإنشاء ملف internal/parser.go. هنا سنقوم بتحليل JSON وتحويله إلى هيكل.

\n\n
package internal\n\nimport (\n    "encoding/json"\n    "fmt"\n    "io"\n)\n\n// Record يمثل صفًا واحدًا في الجدول\ntype Record map[string]interface{}\n\n// ParseJSON يقرأ JSON من القارئ ويعيد شريحة من السجلات\nfunc ParseJSON(r io.Reader) ([]Record, error) {\n    var data []Record\n    decoder := json.NewDecoder(r)\n    if err := decoder.Decode(&data); err != nil {\n        return nil, fmt.Errorf("خطأ في تحليل JSON: %w", err)\n    }\n    return data, nil\n}
\n\n

الآن لننشئ internal/table.go للإخراج المنسق:

\n\n
package internal\n\nimport (\n    "fmt"\n    "strings"\n    "text/tabwriter"\n    "os"\n)\n\n// PrintTable يعرض السجلات في شكل جدول مع محاذاة\nfunc PrintTable(records []Record) {\n    if len(records) == 0 {\n        fmt.Println("لا توجد بيانات للعرض")\n        return\n    }\n\n    // نجمع جميع المفاتيح الفريدة (عناوين الأعمدة)\n    headers := make([]string, 0)\n    seen := make(map[string]bool)\n    for _, rec := range records {\n        for key := range rec {\n            if !seen[key] {\n                headers = append(headers, key)\n                seen[key] = true\n            }\n        }\n    }\n\n    // نستخدم tabwriter للإخراج الجميل\n    w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)\n\n    // العنوان\n    fmt.Fprintln(w, strings.Join(headers, "\\t"))\n\n    // الفاصل\n    sep := make([]string, len(headers))\n    for i, h := range headers {\n        sep[i] = strings.Repeat("-", len(h))\n    }\n    fmt.Fprintln(w, strings.Join(sep, "\\t"))\n\n    // البيانات\n    for _, rec := range records {\n        row := make([]string, len(headers))\n        for i, h := range headers {\n            if val, ok := rec[h]; ok {\n                row[i] = fmt.Sprintf("%v", val)\n            } else {\n                row[i] = ""\n            }\n        }\n        fmt.Fprintln(w, strings.Join(row, "\\t"))\n    }\n\n    w.Flush()\n}
\n\n

تجميع كل شيء في main.

المدونات

توصيات الكتب