TheAny 1

Yetkin
Katılım
24 Ocak 2024
Mesajlar
345
Çözümler
5
Beğeniler
327
Yer
Dubai
Aylar önce Python’daki argparse kütüphanesinden etkilenip C++’ta da benzer bir şey geliştirmek istemiştim. Bir iki gün içinde dandirik bir şey yapmış ve bırakmıştım. Şimdi aklıma geldi, eski fikrin üstüne ekleme yapmak istedim.

GitHub Linki

Fikir, temel olarak geliştiricinin CLI argümanlarını parse etmesine yardımcı olmaya yarıyor. Platforma bağlı olarak üç parser var: MacOS, Linux ve Windows. (Windows’u daha implemente etmedim; Linux olanı da biraz düzeltme istiyor.) Ayrıca test için Fake Parser var; argüman listesini elle veriyorsunuz. Diğerleri platformdan kendi alıyor.

Daha çok eksik var ama en azından multi-type parameter desteğini daha düzgün ve özelleştirilebilir hâle getirince paylaşmak istedim. Özellikle help kısmı ve required arg kısmına biraz daha düzenleme yapmam gerekiyor. Ayrıca flagleri sadece action değil store’da yapabilmek lazım, özellikle liste/multi-token parse’de eklemeli. Musait bir zamanda daha da geliştirebilirim.

Özellikler:
  1. Custom type → Kendi parametre tiplerinizi ekleyebiliyorsunuz. Örneğin main.cpp dosyasında Point sınıfı için type-trait oluşturup ona özel bir echo aksiyonu ekledim. Böylece CLI’dan gelen 3,2 direkt Point sınıfına dönüp fonksiyonunuza geliyor. Tabii ki parser mantığını sizin yazmanız gerekiyor custom typelar için.
  2. Custom convention + multi convention → Convention, argümanların konsolda nasıl ifade edildiği. Örnek olarak GNU’nun convention’ını yaptım: uzun formda --, kısa formda - ile başlar, değerler genelde bir sonraki tokendedir. = işareti ile olan varyasyonu da var. Custom convention mantığıyla kendi conventionlarınızı ekleyebiliyorsunuz. Birden fazla convention varsa, başarısız olanı diğerine devrediyor; aynı kurala sahip iki tane varsa listedeki ilki kazanır.
Farklı fikirleriniz varsa paylaşabilirsiniz. Saygı çerçevesinde eleştiriye de açığım.

Guncelleme; Argumanlari artik boolean flag gibi veya depo gibi kullanabiliyoruz. Custom typelari da depolayabiliyor. Ornekler src/main.cpp icerisinde var.
 
Son düzenleme:
Aylar önce Python’daki argparse kütüphanesinden etkilenip C++’ta da benzer bir şey geliştirmek istemiştim. Bir iki gün içinde dandirik bir şey yapmış ve bırakmıştım. Şimdi aklıma geldi, eski fikrin üstüne ekleme yapmak istedim.

GitHub Linki

Fikir, temel olarak geliştiricinin CLI argümanlarını parse etmesine yardımcı olmaya yarıyor. Platforma bağlı olarak üç parser var: MacOS, Linux ve Windows. (Windows’u daha implemente etmedim; Linux olanı da biraz düzeltme istiyor.) Ayrıca test için Fake Parser var; argüman listesini elle veriyorsunuz. Diğerleri platformdan kendi alıyor.

Daha çok eksik var ama en azından multi-type parameter desteğini daha düzgün ve özelleştirilebilir hâle getirince paylaşmak istedim. Özellikle help kısmı ve required arg kısmına biraz daha düzenleme yapmam gerekiyor. Ayrıca flagleri sadece action değil store’da yapabilmek lazım, özellikle liste/multi-token parse’de eklemeli. Musait bir zamanda daha da geliştirebilirim.

Özellikler:
  1. Custom type → Kendi parametre tiplerinizi ekleyebiliyorsunuz. Örneğin main.cpp dosyasında Point sınıfı için type-trait oluşturup ona özel bir echo aksiyonu ekledim. Böylece CLI’dan gelen 3,2 direkt Point sınıfına dönüp fonksiyonunuza geliyor. Tabii ki parser mantığını sizin yazmanız gerekiyor custom typelar için.
  2. Custom convention + multi convention → Convention, argümanların konsolda nasıl ifade edildiği. Örnek olarak GNU’nun convention’ını yaptım: uzun formda --, kısa formda - ile başlar, değerler genelde bir sonraki tokendedir. = işareti ile olan varyasyonu da var. Custom convention mantığıyla kendi conventionlarınızı ekleyebiliyorsunuz. Birden fazla convention varsa, başarısız olanı diğerine devrediyor; aynı kurala sahip iki tane varsa listedeki ilki kazanır.
Farklı fikirleriniz varsa paylaşabilirsiniz. Saygı çerçevesinde eleştiriye de açığım.

Guncelleme; Argumanlari artik boolean flag gibi veya depo gibi kullanabiliyoruz. Custom typelari da depolayabiliyor. Ornekler src/main.cpp icerisinde var.
Bu, C++ ile CLI argümanlarını işlemek için geliştirdiğiniz ilginç bir yaklaşım. Özellikle özelleştirilmiş türler ve konvansiyonlar ekleme yeteneği, aracı daha esnek hale getiriyor.

Projenizle ilgili birkaç öneri:

1. Dokümantasyon: Kullanıcıların kütüphanenizi nasıl kullanacağını anlamalarına yardımcı olmak için kapsamlı bir dokümantasyon eklemeyi düşünebilirsiniz. Örnek kullanım senaryoları ve açıklayıcı notlar ile zenginleştirilmiş bir README dosyası, kullanıcıların projeyi benimsemesini kolaylaştırabilir.

2. Test Kapsamı: Tüm özellikleri test eden birim testleri yazmak, kütüphanenin güvenilirliğini arttırır. Özellikle çoklu argüman desteği ve özelleştirilmiş türlerin işlenmesi için senaryolar oluşturabilirsiniz.

3. Platform Bağımlılığı: Her platformda uyumluluğu sağlamak için, özellikle Windows üzerinde çalışır durumda olduğunuzdan emin olmalısınız. Kullanıcılarınızın farklı platformlarda karşılaştıkları sorunları en aza indirmek için, detaylı bir yol haritası belirlemekte fayda var.

4. Topluluk Geri Bildirimi: Kullanıcıların projeyi geliştirmek için katkıda bulunmasına olanak tanımak, geliştirme sürecine olumlu etki yapabilir. Bunun için bir katkı kılavuzu ve sorun bildirme şablonu eklemek iyi bir adım olacaktır.

Fikirlerinizi geliştirmek için umarım bu geri bildirimler yararlı olur! Projenizi geliştirmeye devam edin.
 
Public API'i degistirdim biraz daha;

C++:
using namespace argument_parser::v2::flags;

argument_parser::v2::macos_parser parser;

parser.add_argument<std::string>({
    { ShortArgument, "e" },
    { LongArgument, "echo" },
    { Action, echo },
    { HelpText, "echoes given variable." }
});

parser.add_argument({
    { ShortArgument, "s" },
    { LongArgument, "store-flag" },
    { HelpText, "stores a flag" }
});


parser.add_argument<Point>({
    { ShortArgument, "sp" },
    { LongArgument, "store-point" },
    { HelpText, "stores a point" }
});

Onceden su sekildeydi;
C++:
argument_parser::parser parser;

parser.add_argument("e", "echo", "echoes given variable", echo, false);
parser.add_argument("s", "store-flag", "stores a flag", false);
parser.add_argument<Point>("sp", "store-point", "stores a point", false);

Daha okunakli oldugunu dusunuyorum. Eger bi argumani required yapmak gerekiyorsa, { Required, true } eklendiginde onu required yapiyor.

Bu konuyu bayadır güncellememiştim.

Öne Çıkan Değişiklikler ve Yeni Özellikler:
  • on_complete Desteği: Parse işlemi başarıyla tamamlandıktan sonra tetiklenecek fonksiyonları artık doğrudan parser üzerinde ekleyebiliyorsunuz.
  • Doğrudan Referansa Yazma: Bir argümanın değerini almak için sürekli store ile manuel kaydetmeye çalışmak yerine, doğrudan ilgili değişkene (int, std::string vb.) referans vererek değerin otomatik yazılmasını sağlayabiliyorsunuz.
  • Pozisyonel Argümanlar: Argümanları flag veya isim bağımlı olmaktan çıkarıp, komut satırındaki sırasına (index) göre tanımlayabilme özelliği eklendi.
  • Otomatik Help Text Üretimi: Tanımlanan argümanlara, kısa/uzun adlara ve help_text içeriklerine göre parser artık otomatik olarak temiz bir yardım çıktısı oluşturuyor. Üstelik parser'ı kurarken parametre ile bu çıktının ardından uygulamanın hemen kapanıp kapanmayacağını da kontrol edebiliyorsunuz.
  • CMake Entegrasyonu: Projeyi artık bir CMake kütüphanesi olarak doğrudan import edip projelerinize dahil edebilirsiniz.
Geliştirme süreci devam ediyor. Ek özellik veya mevcut yapısı hakkında önerileriniz ve eleştirileriniz varsa paylaşabilirsiniz.

C++:
#include <argparse>
#include <iostream>
#include <string>

using argument = argument_parser::builder::argument<>;

argument_parser::v2::parser parser(false); // --help prints without exiting immediately

int threshold = 0;

argument::start()
    .short_argument("e")
    .long_argument("echo")
    .action<std::string>([](std::string const& text) {
        std::cout << text << '\n';
    })
    .build(parser);

argument::start()
    .long_argument("file")
    .store<std::string>()
    .required()
    .help_text("Input file to process.")
    .build(parser);

argument::start()
    .long_argument("threshold")
    .reference(threshold)
    .build(parser);

argument::start()
    .short_argument("v")
    .long_argument("verbose")
    .flag()
    .help_text("Enable verbose output.")
    .build(parser);

argument::start()
    .positional("output")
    .position(0)
    .help_text("Output file.")
    .build(parser);

parser.on_complete([](auto const& state) {
    if (auto file = state.template get_optional<std::string>("file")) {
        std::cout << "completed for: " << *file << '\n';
    }
});
 
Son düzenleme: