From e3e96dd149c4aeb423639c8da6ed8704180f5b00 Mon Sep 17 00:00:00 2001 From: hudanursner Date: Mon, 30 Mar 2026 10:23:44 +0300 Subject: [PATCH 1/9] Create REadME.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hüdanur Şener --- REadME.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 REadME.md diff --git a/REadME.md b/REadME.md new file mode 100644 index 00000000..40d70159 --- /dev/null +++ b/REadME.md @@ -0,0 +1,5 @@ +# Komut Tamamlama: V0 sürümünde sadece taslak (placeholder) olan init ve add komutları V1 sürümünde tamamen işlevsel hale getirildi[cite: 32]. +# Dinamik Veri Yönetimi: Bookmarklar artık .minibookmark/links.dat dosyasına "id|title|url|date" formatında otomatik olarak kaydediliyor[cite: 2, 4]. +# Otomatik ID Sistemi: Her yeni eklenen bookmark için dosya satır sayısı kontrol edilerek otomatik artan benzersiz bir ID atama mantığı entegre edildi[cite: 4, 32]. +# Gelişmiş Hata Yönetimi: SPEC gereksinimleri doğrultusunda, sistem başlatılmadan komut çalıştırıldığında "Not initialized" uyarısı veren ve bilinmeyen komutlarda kullanıcıyı bilgilendiren kontrol mekanizmaları eklendi. +# Bonus Arama Özelliği: Codex desteği ile geliştirilen "search" komutu sayesinde, kayıtlı bookmarklar arasında başlığa göre anahtar kelime araması yapma imkanı projeye dahil edildi[cite: 42]. From a75f9c6a945eb9e39a6309197fa48a291b9e32d8 Mon Sep 17 00:00:00 2001 From: hudanursner Date: Mon, 30 Mar 2026 10:28:59 +0300 Subject: [PATCH 2/9] Update REadME.md hudanur sener --- REadME.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/REadME.md b/REadME.md index 40d70159..49f96faf 100644 --- a/REadME.md +++ b/REadME.md @@ -1,5 +1,8 @@ -# Komut Tamamlama: V0 sürümünde sadece taslak (placeholder) olan init ve add komutları V1 sürümünde tamamen işlevsel hale getirildi[cite: 32]. -# Dinamik Veri Yönetimi: Bookmarklar artık .minibookmark/links.dat dosyasına "id|title|url|date" formatında otomatik olarak kaydediliyor[cite: 2, 4]. -# Otomatik ID Sistemi: Her yeni eklenen bookmark için dosya satır sayısı kontrol edilerek otomatik artan benzersiz bir ID atama mantığı entegre edildi[cite: 4, 32]. -# Gelişmiş Hata Yönetimi: SPEC gereksinimleri doğrultusunda, sistem başlatılmadan komut çalıştırıldığında "Not initialized" uyarısı veren ve bilinmeyen komutlarda kullanıcıyı bilgilendiren kontrol mekanizmaları eklendi. -# Bonus Arama Özelliği: Codex desteği ile geliştirilen "search" komutu sayesinde, kayıtlı bookmarklar arasında başlığa göre anahtar kelime araması yapma imkanı projeye dahil edildi[cite: 42]. +#Ne değiştirdim? +SPEC dosyasını güncelledim ve "search" komutu gereksinimini ekledim. Ayrıca V1 aşaması için temel kodları yazdım. + +#Neden değiştirdim? +Sistemin daha işlevsel olması ve kullanıcıların bookmarklar arasında arama yapabilmesi için. + +#Test ettim mi? +Evet, tüm komutlar ve hata mesajları SPEC ve test dosyalarına uygun şekilde kontrol edildi. From c21bb86894e125f8e71e2214d173424e360c72ee Mon Sep 17 00:00:00 2001 From: hudanursner Date: Mon, 30 Mar 2026 10:44:47 +0300 Subject: [PATCH 3/9] Version 1 includes a search feature. The SPEC file has been updated, the add and init functions have been completed, and a search feature has been added as a bonus. --- SPEC.txt | 49 +++++++++++++++++++++++ SPEC0.txt | 0 minibookmark.py | 92 ++++++++++++++++++++++++++++++++++++++++++ solution_v0.py | 82 ++++++++++++++++++++++++++++++++++++++ test_spec.py | 86 ++++++++++++++++++++++++++++++++++++++++ test_spec1.py | 103 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 412 insertions(+) create mode 100644 SPEC.txt create mode 100644 SPEC0.txt create mode 100644 minibookmark.py create mode 100644 solution_v0.py create mode 100644 test_spec.py create mode 100644 test_spec1.py diff --git a/SPEC.txt b/SPEC.txt new file mode 100644 index 00000000..c7f503aa --- /dev/null +++ b/SPEC.txt @@ -0,0 +1,49 @@ +PROJECT: mini-bookmark +AUTHOR: Hüdanur Şener (251478066) +VERSION: v0 +DATE: 2026-03-16 + +======================================== +OVERVIEW +======================================== +mini-bookmark is a CLI tool to save and manage web URLs. +It stores bookmarks in a plain text file. +All data is kept in a directory named .minibookmark/ + +======================================== +COMMANDS +======================================== + +--- init --- +Usage: python minibookmark.py init +Creates .minibookmark/ directory and an empty links.dat file. +If it exists, prints "Already initialized." + +--- add --- +Usage: python minibookmark.py add "Google" "https://google.com" +Saves a new bookmark with an auto-increment ID. +Format: id|title|url|date +Prints: "Added bookmark #: " + +--- list --- +Usage: python minibookmark.py list +(To be implemented) +Will show all saved bookmarks. + +--- delete --- +Usage: python minibookmark.py delete <id> +(To be implemented) +Will remove a bookmark by ID. + +======================================== +DATA FORMAT +======================================== +File: .minibookmark/links.dat +Format: id|title|url|2026-03-16 + +======================================== +ERROR HANDLING +======================================== +- Running without init: "Not initialized. Run: python minibookmark.py init" +- Unknown command: "Unknown command: <command>" +- Missing arguments: "Usage: python minibookmark.py <command> [args]" \ No newline at end of file diff --git a/SPEC0.txt b/SPEC0.txt new file mode 100644 index 00000000..e69de29b diff --git a/minibookmark.py b/minibookmark.py new file mode 100644 index 00000000..73860630 --- /dev/null +++ b/minibookmark.py @@ -0,0 +1,92 @@ +""" +PROJECT: mini-bookmark V1 +STUDENT: Hüdanur Şener (251478066) + +V1 GÖREV LİSTESİ (Ödev 4.2 Gereksinimi): +1. 'init' komutu tamamlandı: .minibookmark/ klasörü ve veri dosyası oluşturuluyor. +2. 'add' komutu id|title|url|date formatında kayıt yapacak şekilde geliştirildi. +3. 'search' komutu Codex desteğiyle ek puan görevi olarak projeye eklendi. +""" + +import sys +import os + +# Veri saklama yolları [cite: 2, 6] +DB_DIR = ".minibookmark" +DB_FILE = os.path.join(DB_DIR, "links.dat") + + +def init(): + """Projeyi başlatır ve gerekli dosyayı oluşturur[cite: 3].""" + if os.path.exists(DB_DIR): + print("Already initialized.") + else: + os.makedirs(DB_DIR) + open(DB_FILE, "w").close() + print("Project initialized.") + + +def add(title, url): + """Yeni bir bookmark ekler[cite: 4].""" + if not os.path.exists(DB_DIR): + print("Not initialized. Run: python minibookmark.py init") + else: + try: + with open(DB_FILE, "r") as f: + new_id = len(f.readlines()) + 1 + except FileNotFoundError: + new_id = 1 + + date_str = "2026-03-16" # SPEC'teki sabit tarih formatı [cite: 6] + entry = f"{new_id}|{title}|{url}|{date_str}\n" + + with open(DB_FILE, "a") as f: + f.write(entry) + print(f"Added bookmark #{new_id}: {title}") + + +def search(keyword): + """BONUS: Codex ile üretilen arama fonksiyonu[cite: 42].""" + if not os.path.exists(DB_FILE): + print("Not initialized.") + return + with open(DB_FILE, "r") as f: + found = False + for line in f: + if keyword.lower() in line.split('|')[1].lower(): + print(line.strip()) + found = True + if not found: + print("No bookmarks found.") + + +def main(): + args = sys.argv[1:] + + if not args: + print("Usage: python minibookmark.py <command> [args]") + return + + command = args[0] + + if command == "init": + init() + elif command == "add": + if len(args) < 3: + print("Usage: python minibookmark.py add <title> <url>") + else: + add(args[1], args[2]) + elif command == "search": + if len(args) < 2: + print("Usage: python minibookmark.py search <keyword>") + else: + search(args[1]) + elif command in ["list", "delete"]: + # Gelecek haftalar için yer tutucu mesaj + print("This feature will be implemented in future weeks.") + else: + print(f"Unknown command: {command}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/solution_v0.py b/solution_v0.py new file mode 100644 index 00000000..88589a2a --- /dev/null +++ b/solution_v0.py @@ -0,0 +1,82 @@ +""" +mini-bookmark v0 — Basitlestirilmis implementasyon +Ogrenci: Hüdanur Şener (251478066) +Proje: mini-bookmark + +Kapsam: Sadece init ve add komutlari. +Sinirlamalar: Dongu (for/while) ve liste ([]) kesinlikle kullanilmadi. +""" +import sys +import os + + +def initialize(): + """Bookmark dizini ve bos veri dosyasini olusturur.""" + if os.path.exists(".minibookmark"): + return "Already initialized." + + os.mkdir(".minibookmark") + # Bos bir dosya acip kapatmak onu olusturmak demektir + f = open(".minibookmark/links.dat", "w") + f.close() + return "Initialized empty bookmark folder." + + +def add_bookmark(title, url): + """Yeni bir link ekler. ID tespiti satir sayilarini sayarak yapilir.""" + # Klasor yoksa hata dondur + if not os.path.exists(".minibookmark"): + return "Not initialized. Run: python minibookmark.py init" + + # Mevcut dosyayi oku (ID tespiti icin) + f = open(".minibookmark/links.dat", "r") + content = f.read() + f.close() + + # YASAK: Dongu ve liste kullanmadan satir sayisi bulma: + # Dosyadaki her '\n' (yeni satir) karakteri bir kaydi temsil eder. + bookmark_id = content.count("\n") + 1 + + # Dosyaya ekleme yap (Append modu) + f = open(".minibookmark/links.dat", "a") + f.write(str(bookmark_id) + "|" + title + "|" + url + "|2026-03-16\n") + f.close() + + return "Added bookmark #" + str(bookmark_id) + ": " + title + + +def show_not_implemented(command_name): + """Henuz kodlanmamis ozellikler icin standart bir mesaj dondurur.""" + return "Command '" + command_name + "' will be implemented in future weeks." + + +# --- Ana Program Akisi --- + +# Kullanici hicbir sey yazmadan programi calistirirsa +if len(sys.argv) < 2: + print("Usage: python minibookmark.py <command> [args]") + +# init komutu +elif sys.argv[1] == "init": + print(initialize()) + +# add komutu +elif sys.argv[1] == "add": + # Eger title veya url eksikse (python + dosya_adi + komut + 2 arguman = 4) + if len(sys.argv) < 4: + print("Usage: python minibookmark.py add <title> <url>") + else: + # Argumanlari fonksiyonumuza gonderiyoruz + print(add_bookmark(sys.argv[2], sys.argv[3])) + +# list komutu (Henuz implemente edilmedi) +elif sys.argv[1] == "list": + print(show_not_implemented("list")) + +# delete komutu (Henuz implemente edilmedi) +elif sys.argv[1] == "delete": + print(show_not_implemented("delete")) + +# Gecersiz bir komut girilirse +else: + print("Unknown command: " + sys.argv[1]) \ No newline at end of file diff --git a/test_spec.py b/test_spec.py new file mode 100644 index 00000000..6a3c24a6 --- /dev/null +++ b/test_spec.py @@ -0,0 +1,86 @@ +""" +mini-bookmark SPEC test cases +Student:Hüdanur Şener (251478066) +Project: mini-bookmark +""" +import subprocess +import os +import shutil + +# --- Helper Function --- +def run_cmd(args): + """Runs the script and returns the output.""" + result = subprocess.run( + ["python", "minibookmark.py"] + args, + capture_output=True, + text=True + ) + return result.stdout.strip() + +def setup_function(): + """Clean start for each test.""" + if os.path.exists(".minibookmark"): + shutil.rmtree(".minibookmark") + +# --- 1. init COMMAND TESTS --- +def test_init_creates_directory(): + # Normal durum: İlk kez init yapilir + run_cmd(["init"]) + assert os.path.exists(".minibookmark") == True + +def test_init_already_initialized(): + # Hata durumu: Zaten init yapilmisken tekrar yapilir + run_cmd(["init"]) + output = run_cmd(["init"]) + assert "Already initialized" in output + +# --- 2. add COMMAND TESTS --- +def test_add_single_bookmark(): + # Normal durum: Bir link basariyla eklenir + run_cmd(["init"]) + output = run_cmd(["add", "Google", "https://google.com"]) + assert "Added bookmark #1" in output + +def test_add_multiple_bookmarks(): + # Normal durum: İkinci link eklenir ve ID artar + run_cmd(["init"]) + run_cmd(["add", "A", "a.com"]) + output = run_cmd(["add", "B", "b.com"]) + assert "#2" in output + +def test_add_missing_arguments(): + # Hata durumu: Eksik arguman (sadece isim) + run_cmd(["init"]) + output = run_cmd(["add", "OnlyName"]) + assert "Usage" in output + +# --- 3. ERROR HANDLING & FLOW TESTS --- +def test_command_before_init(): + # Hata durumu: Klasor yokken add komutu calismaz + output = run_cmd(["add", "Test", "test.com"]) + assert "Not initialized" in output + +def test_unknown_command_error(): + # Hata durumu: SPEC'te olmayan bir komut + run_cmd(["init"]) + output = run_cmd(["jump"]) + assert "Unknown command" in output + +# --- 4. FUTURE IMPLEMENTATION TESTS (SPEC Status) --- +def test_list_not_implemented_yet(): + # SPEC Uyumu: list komutu henuz hazir degil mesaji vermeli + run_cmd(["init"]) + output = run_cmd(["list"]) + assert "future weeks" in output + +def test_delete_not_implemented_yet(): + # SPEC Uyumu: delete komutu henuz hazir degil mesaji vermeli + run_cmd(["init"]) + output = run_cmd(["delete", "1"]) + assert "future weeks" in output + +# --- 5. USAGE TESTS --- +def test_no_arguments_usage(): + # Hata durumu: Hicbir arguman girilmezse kullanim kilavuzu basilir + output = run_cmd([]) + assert "Usage" in output \ No newline at end of file diff --git a/test_spec1.py b/test_spec1.py new file mode 100644 index 00000000..40fccb5b --- /dev/null +++ b/test_spec1.py @@ -0,0 +1,103 @@ +""" +PROJECT: mini-bookmark V1 +STUDENT: Hüdanur Şener (251478066) + +V1 GÖREV LİSTESİ (Ödev 4.2 Gereksinimi): +1. 'init' komutu tamamlandı: .minibookmark/ klasörü ve veri dosyası oluşturuluyor. +2. 'add' komutu id|title|url|date formatında kayıt yapacak şekilde geliştirildi. +3. 'search' komutu Codex desteğiyle ek puan görevi olarak projeye eklendi. +""" + +import sys +import os + +# Veri saklama ayarları +DB_DIR = ".minibookmark" +DB_FILE = os.path.join(DB_DIR, "links.dat") + + +def init(): + """Projeyi başlatır ve gerekli dizinleri oluşturur.""" + if os.path.exists(DB_DIR): + print("Already initialized.") + else: + os.makedirs(DB_DIR) + with open(DB_FILE, "w") as f: + pass + print("Project initialized.") + + +def add(title, url): + """Yeni bir bookmark ekler ve ID'yi otomatik artırır.""" + if not os.path.exists(DB_DIR): + print("Not initialized. Run: python minibookmark.py init") + return + + # Otomatik ID artırma (Satır sayısına göre) + try: + with open(DB_FILE, "r") as f: + lines = f.readlines() + new_id = len(lines) + 1 + except FileNotFoundError: + new_id = 1 + + # SPEC'te istenen tarih formatı + date_str = "2026-03-16" + entry = f"{new_id}|{title}|{url}|{date_str}\n" + + with open(DB_FILE, "a") as f: + f.write(entry) + + print(f"Added bookmark #{new_id}: {title}") + + +def search(keyword): + """BONUS: Codex tarafından üretilen arama fonksiyonu.""" + if not os.path.exists(DB_FILE): + print("Not initialized.") + return + with open(DB_FILE, "r") as f: + found = False + for line in f: + # Başlık (index 1) içinde arama yapar + parts = line.strip().split('|') + if len(parts) > 1 and keyword.lower() in parts[1].lower(): + print(line.strip()) + found = True + if not found: + print("No bookmarks found.") + + +def main(): + args = sys.argv[1:] + + # 5. USAGE TESTS Uyumu + if not args: + print("Usage: python minibookmark.py <command> [args]") + return + + command = args[0] + + if command == "init": + init() + elif command == "add": + # 2. add COMMAND TESTS Uyumu (Eksik argüman kontrolü) + if len(args) < 3: + print("Usage: python minibookmark.py add <title> <url>") + else: + add(args[1], args[2]) + elif command == "search": + if len(args) < 2: + print("Usage: python minibookmark.py search <keyword>") + else: + search(args[1]) + elif command in ["list", "delete"]: + # 4. FUTURE IMPLEMENTATION TESTS Uyumu + print("This feature will be implemented in future weeks.") + else: + # 3. ERROR HANDLING & FLOW TESTS Uyumu (Bilinmeyen komut) + print(f"Unknown command: {command}") + + +if __name__ == "__main__": + main() \ No newline at end of file From 0d73d0ea15d5eefd2c7d712d0b2e8131d5d53f35 Mon Sep 17 00:00:00 2001 From: hudanursner <hudanursner@gmail.com> Date: Mon, 30 Mar 2026 19:19:25 +0300 Subject: [PATCH 4/9] =?UTF-8?q?problem.json=20dosyas=C4=B1=20eklendi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proje meta verilerini ve tamamlanan görev listesini içeren problem.json dosyası kök dizine eklendi. --- problem.json.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 problem.json.txt diff --git a/problem.json.txt b/problem.json.txt new file mode 100644 index 00000000..e69de29b From 0ca5ebbdb745c49657f0557deea689e0753c76b0 Mon Sep 17 00:00:00 2001 From: hudanursner <hudanursner@gmail.com> Date: Mon, 20 Apr 2026 17:58:34 +0300 Subject: [PATCH 5/9] Update problem.json.txt --- problem.json.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/problem.json.txt b/problem.json.txt index e69de29b..6f057ed0 100644 --- a/problem.json.txt +++ b/problem.json.txt @@ -0,0 +1,14 @@ +{ + "project_name": "mini-bookmark", + "version": "v1", + "student_name": "Hüdanur Şener", + "student_id": "251478066", + "description": "A CLI tool for managing web bookmarks with search functionality.", + "repository": "https://github.com/seyyah/which-language", + "tasks_completed": [ + "Project initialization with init command", + "Adding bookmarks with auto-increment ID", + "Search functionality implemented with AI assistance", + "Error handling for uninitialized states" + ] +} From 3f265f4f86d1e2e9edb9b637c1c76c3cde71cb3c Mon Sep 17 00:00:00 2001 From: hudanursner <hudanursner@gmail.com> Date: Mon, 20 Apr 2026 20:59:52 +0300 Subject: [PATCH 6/9] Mini-bookmark V3 projesi --- SPEC v3.txt | 57 +++++++++++++++++++++ TEST-v3.py | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 SPEC v3.txt create mode 100644 TEST-v3.py diff --git a/SPEC v3.txt b/SPEC v3.txt new file mode 100644 index 00000000..390793b4 --- /dev/null +++ b/SPEC v3.txt @@ -0,0 +1,57 @@ +PROJECT: mini-bookmark +AUTHOR: Hüdanur Şener (251478066) +VERSION: v3 +DATE: 2026-04-20 + +======================================== +OVERVIEW +======================================== +mini-bookmark is a CLI tool to save and manage web URLs[cite: 13]. +It stores bookmarks in a plain text file. +All data is kept in a directory named .minibookmark/[cite: 14]. + +======================================== +COMMANDS +======================================== + +--- init --- +Usage: python minibookmark.py init +Creates .minibookmark/ directory and an empty links.dat file[cite: 15]. +If it exists, prints "Already initialized." + +--- add --- +Usage: python minibookmark.py add "Title" "URL" +(V2 Update) Saves a new bookmark with an auto-increment ID. +URL must start with "http" or "https"[cite: 16]. +Format: id|title|url|date +Prints: "Added bookmark #<id>: <title>" + +--- list --- +Usage: python minibookmark.py list +(V2 Update: Implemented) Shows all saved bookmarks in a formatted table[cite: 17]. +Displays ID, Title, URL, and Date columns. + +--- delete --- +Usage: python minibookmark.py delete <id> +(V2 Update: Implemented) Removes a bookmark by its specific ID from links.dat[cite: 18]. +Prints: "Bookmark #<id> deleted." if successful. + +--- search --- +Usage: python minibookmark.py search <keyword> +Searches for bookmarks by title keyword (Case-insensitive)[cite: 19]. + +======================================== +DATA FORMAT +======================================== +File: .minibookmark/links.dat +Format: id|title|url|YYYY-MM-DD +Example: 1|Google|http://google.com|2026-04-20 + +======================================== +ERROR HANDLING +======================================== +- Running without init: "Not initialized. Run: python minibookmark.py init" +- Unknown command: "Unknown command: <command>" +- Missing arguments: "Usage: python minibookmark.py <command> [args]" +- Invalid URL (V2): "Error: URL must start with 'http' or 'https'." +- ID Not Found (V2): "Bookmark #<id> not found." \ No newline at end of file diff --git a/TEST-v3.py b/TEST-v3.py new file mode 100644 index 00000000..18943d77 --- /dev/null +++ b/TEST-v3.py @@ -0,0 +1,142 @@ +""" +PROJECT: mini-bookmark V3 +AUTHOR: Hüdanur Şener (251478066) +DATE: 2026-04-20 + +V2 TASK LIST: +1. 'list' command completed: Displays all records in a formatted table. +2. 'delete' command implemented: Added logic to remove a record by ID. +3. URL Validation: Added a check to ensure links start with 'http'. +""" + +import sys +import os + +# Data storage paths [cite: 14] +DB_DIR = ".minibookmark" +DB_FILE = os.path.join(DB_DIR, "links.dat") + + +def init(): + """Initializes the project and creates necessary directory/file[cite: 15].""" + if os.path.exists(DB_DIR): + print("Already initialized.") + else: + os.makedirs(DB_DIR) + open(DB_FILE, "w").close() + print("Project initialized.") + + +def add(title, url): + """Adds a new bookmark with URL validation[cite: 16].""" + if not url.startswith("http"): + print("Error: URL must start with 'http' or 'https'.") + return + + if not os.path.exists(DB_DIR): + print("Not initialized. Run: python minibookmark.py init") + return + + try: + with open(DB_FILE, "r") as f: + lines = f.readlines() + new_id = len(lines) + 1 + except FileNotFoundError: + new_id = 1 + + date_str = "2026-04-20" + entry = f"{new_id}|{title}|{url}|{date_str}\n" + + with open(DB_FILE, "a") as f: + f.write(entry) + print(f"Added bookmark #{new_id}: {title}") + + +def list_bookmarks(): + """V2: Lists all saved bookmarks in a clean format.""" + if not os.path.exists(DB_FILE) or os.path.getsize(DB_FILE) == 0: + print("No bookmarks found.") + return + + # Table Header + print(f"{'ID':<4} | {'TITLE':<20} | {'URL':<30} | {'DATE'}") + print("-" * 75) + with open(DB_FILE, "r") as f: + for line in f: + parts = line.strip().split('|') + if len(parts) == 4: + print(f"{parts[0]:<4} | {parts[1]:<20} | {parts[2]:<30} | {parts[3]}") + + +def delete(bookmark_id): + """V2: Removes a bookmark based on its ID.""" + if not os.path.exists(DB_FILE): + print("Not initialized.") + return + + lines = [] + found = False + with open(DB_FILE, "r") as f: + lines = f.readlines() + + with open(DB_FILE, "w") as f: + for line in lines: + # Check if the line starts with the target ID + if not line.startswith(f"{bookmark_id}|"): + f.write(line) + else: + found = True + + if found: + print(f"Bookmark #{bookmark_id} deleted successfully.") + else: + print(f"Error: Bookmark #{bookmark_id} not found.") + + +def search(keyword): + """Searches for bookmarks by title keyword[cite: 18].""" + if not os.path.exists(DB_FILE): + print("Not initialized.") + return + with open(DB_FILE, "r") as f: + found = False + for line in f: + if keyword.lower() in line.split('|')[1].lower(): + print(line.strip()) + found = True + if not found: + print("No bookmarks found matching the keyword.") + + +def main(): + args = sys.argv[1:] + if not args: + print("Usage: python minibookmark.py <command> [args]") + return + + command = args[0] + if command == "init": + init() + elif command == "add": + if len(args) < 3: + print("Usage: python minibookmark.py add <title> <url>") + else: + add(args[1], args[2]) + elif command == "list": + list_bookmarks() + elif command == "delete": + if len(args) < 2: + print("Usage: python minibookmark.py delete <id>") + else: + delete(args[1]) + elif command == "search": + if len(args) < 2: + print("Usage: python minibookmark.py search <keyword>") + else: + search(args[1]) + else: + print(f"Unknown command: {command}") + + +if __name__ == "__main__": + main() \ No newline at end of file From 91ad500f060800325e548241ce0a72dbce004af4 Mon Sep 17 00:00:00 2001 From: hudanursner <hudanursner@gmail.com> Date: Thu, 7 May 2026 12:42:08 +0300 Subject: [PATCH 7/9] Add mini-bookmark project files --- problems/minibookmark/SPEC v1.txt | 49 +++++++++ problems/minibookmark/SPEC v2.txt | 54 ++++++++++ problems/minibookmark/SPEC v3.txt | 57 +++++++++++ problems/minibookmark/TEST-v1 (2).py | 86 ++++++++++++++++ problems/minibookmark/TEST-v2.py | 92 +++++++++++++++++ problems/minibookmark/TEST-v3.py | 142 +++++++++++++++++++++++++++ problems/minibookmark/solution_v0.py | 82 ++++++++++++++++ 7 files changed, 562 insertions(+) create mode 100644 problems/minibookmark/SPEC v1.txt create mode 100644 problems/minibookmark/SPEC v2.txt create mode 100644 problems/minibookmark/SPEC v3.txt create mode 100644 problems/minibookmark/TEST-v1 (2).py create mode 100644 problems/minibookmark/TEST-v2.py create mode 100644 problems/minibookmark/TEST-v3.py create mode 100644 problems/minibookmark/solution_v0.py diff --git a/problems/minibookmark/SPEC v1.txt b/problems/minibookmark/SPEC v1.txt new file mode 100644 index 00000000..f8f5b366 --- /dev/null +++ b/problems/minibookmark/SPEC v1.txt @@ -0,0 +1,49 @@ +PROJECT: mini-bookmark +AUTHOR: Hüdanur Şener (251478066) +VERSION: v0 +DATE: 2026-03-16 + +======================================== +OVERVIEW +======================================== +mini-bookmark is a CLI tool to save and manage web URLs. +It stores bookmarks in a plain text file. +All data is kept in a directory named .minibookmark/ + +======================================== +COMMANDS +======================================== + +--- init --- +Usage: python minibookmark.py init +Creates .minibookmark/ directory and an empty links.dat file. +If it exists, prints "Already initialized." + +--- add --- +Usage: python minibookmark.py add "Google" "https://google.com" +Saves a new bookmark with an auto-increment ID. +Format: id|title|url|date +Prints: "Added bookmark #<id>: <title>" + +--- list --- +Usage: python minibookmark.py list +(To be implemented) +Will show all saved bookmarks. + +--- delete --- +Usage: python minibookmark.py delete <id> +(To be implemented) +Will remove a bookmark by ID. + +======================================== +DATA FORMAT +======================================== +File: .minibookmark/links.dat +Format: id|title|url|2026-03-16 + +======================================== +ERROR HANDLING +======================================== +- Running without init: "Not initialized. Run: python minibookmark.py init" +- Unknown command: "Unknown command: <command>" +- Missing arguments: "Usage: python minibookmark.py <command> [args]" diff --git a/problems/minibookmark/SPEC v2.txt b/problems/minibookmark/SPEC v2.txt new file mode 100644 index 00000000..aa428846 --- /dev/null +++ b/problems/minibookmark/SPEC v2.txt @@ -0,0 +1,54 @@ +PROJECT: mini-bookmark +AUTHOR: Hüdanur Şener (251478066) +VERSION: v1 +DATE: 2026-03-29 + +======================================== +OVERVIEW +======================================== +mini-bookmark is a CLI tool to save and manage web URLs. +It stores bookmarks in a plain text file. [cite: 2] +All data is kept in a directory named .minibookmark/ + +======================================== +COMMANDS +======================================== + +--- init --- +Usage: python minibookmark.py init +Creates .minibookmark/ directory and an empty links.dat file. +If it exists, prints "Already initialized." [cite: 3] + +--- add --- +Usage: python minibookmark.py add "Title" "URL" +Saves a new bookmark with an auto-increment ID. [cite: 4] +Format: id|title|url|date +Prints: "Added bookmark #<id>: <title>" + +--- list --- +Usage: python minibookmark.py list +(To be implemented) +Will show all saved bookmarks. + +--- delete --- +Usage: python minibookmark.py delete <id> +(To be implemented) +Will remove a bookmark by ID. [cite: 5] + +--- search --- +Usage: python minibookmark.py search <keyword> +(V1 Update) Searches for bookmarks by title keyword. +[Note: This command was added to meet Assignment 4.2 requirements.] + +======================================== +DATA FORMAT +======================================== +File: .minibookmark/links.dat +Format: id|title|url|2026-03-16 [cite: 6] + +======================================== +ERROR HANDLING +======================================== +- Running without init: "Not initialized. Run: python minibookmark.py init" +- Unknown command: "Unknown command: <command>" +- Missing arguments: "Usage: python minibookmark.py <command> [args]" \ No newline at end of file diff --git a/problems/minibookmark/SPEC v3.txt b/problems/minibookmark/SPEC v3.txt new file mode 100644 index 00000000..1cb114f8 --- /dev/null +++ b/problems/minibookmark/SPEC v3.txt @@ -0,0 +1,57 @@ +PROJECT: mini-bookmark +AUTHOR: Hüdanur Şener (251478066) +VERSION: v3 +DATE: 2026-04-20 + +======================================== +OVERVIEW +======================================== +mini-bookmark is a CLI tool to save and manage web URLs[cite: 13]. +It stores bookmarks in a plain text file. +All data is kept in a directory named .minibookmark/[cite: 14]. + +======================================== +COMMANDS +======================================== + +--- init --- +Usage: python minibookmark.py init +Creates .minibookmark/ directory and an empty links.dat file[cite: 15]. +If it exists, prints "Already initialized." + +--- add --- +Usage: python minibookmark.py add "Title" "URL" +(V2 Update) Saves a new bookmark with an auto-increment ID. +URL must start with "http" or "https"[cite: 16]. +Format: id|title|url|date +Prints: "Added bookmark #<id>: <title>" + +--- list --- +Usage: python minibookmark.py list +(V2 Update: Implemented) Shows all saved bookmarks in a formatted table[cite: 17]. +Displays ID, Title, URL, and Date columns. + +--- delete --- +Usage: python minibookmark.py delete <id> +(V2 Update: Implemented) Removes a bookmark by its specific ID from links.dat[cite: 18]. +Prints: "Bookmark #<id> deleted." if successful. + +--- search --- +Usage: python minibookmark.py search <keyword> +Searches for bookmarks by title keyword (Case-insensitive)[cite: 19]. + +======================================== +DATA FORMAT +======================================== +File: .minibookmark/links.dat +Format: id|title|url|YYYY-MM-DD +Example: 1|Google|http://google.com|2026-04-20 + +======================================== +ERROR HANDLING +======================================== +- Running without init: "Not initialized. Run: python minibookmark.py init" +- Unknown command: "Unknown command: <command>" +- Missing arguments: "Usage: python minibookmark.py <command> [args]" +- Invalid URL (V2): "Error: URL must start with 'http' or 'https'." +- ID Not Found (V2): "Bookmark #<id> not found." \ No newline at end of file diff --git a/problems/minibookmark/TEST-v1 (2).py b/problems/minibookmark/TEST-v1 (2).py new file mode 100644 index 00000000..1652b74c --- /dev/null +++ b/problems/minibookmark/TEST-v1 (2).py @@ -0,0 +1,86 @@ +""" +mini-bookmark SPEC test cases +Student:Hüdanur Şener (251478066) +Project: mini-bookmark +""" +import subprocess +import os +import shutil + +# --- Helper Function --- +def run_cmd(args): + """Runs the script and returns the output.""" + result = subprocess.run( + ["python", "minibookmark.py"] + args, + capture_output=True, + text=True + ) + return result.stdout.strip() + +def setup_function(): + """Clean start for each test.""" + if os.path.exists(".minibookmark"): + shutil.rmtree(".minibookmark") + +# --- 1. init COMMAND TESTS --- +def test_init_creates_directory(): + # Normal durum: İlk kez init yapilir + run_cmd(["init"]) + assert os.path.exists(".minibookmark") == True + +def test_init_already_initialized(): + # Hata durumu: Zaten init yapilmisken tekrar yapilir + run_cmd(["init"]) + output = run_cmd(["init"]) + assert "Already initialized" in output + +# --- 2. add COMMAND TESTS --- +def test_add_single_bookmark(): + # Normal durum: Bir link basariyla eklenir + run_cmd(["init"]) + output = run_cmd(["add", "Google", "https://google.com"]) + assert "Added bookmark #1" in output + +def test_add_multiple_bookmarks(): + # Normal durum: İkinci link eklenir ve ID artar + run_cmd(["init"]) + run_cmd(["add", "A", "a.com"]) + output = run_cmd(["add", "B", "b.com"]) + assert "#2" in output + +def test_add_missing_arguments(): + # Hata durumu: Eksik arguman (sadece isim) + run_cmd(["init"]) + output = run_cmd(["add", "OnlyName"]) + assert "Usage" in output + +# --- 3. ERROR HANDLING & FLOW TESTS --- +def test_command_before_init(): + # Hata durumu: Klasor yokken add komutu calismaz + output = run_cmd(["add", "Test", "test.com"]) + assert "Not initialized" in output + +def test_unknown_command_error(): + # Hata durumu: SPEC'te olmayan bir komut + run_cmd(["init"]) + output = run_cmd(["jump"]) + assert "Unknown command" in output + +# --- 4. FUTURE IMPLEMENTATION TESTS (SPEC Status) --- +def test_list_not_implemented_yet(): + # SPEC Uyumu: list komutu henuz hazir degil mesaji vermeli + run_cmd(["init"]) + output = run_cmd(["list"]) + assert "future weeks" in output + +def test_delete_not_implemented_yet(): + # SPEC Uyumu: delete komutu henuz hazir degil mesaji vermeli + run_cmd(["init"]) + output = run_cmd(["delete", "1"]) + assert "future weeks" in output + +# --- 5. USAGE TESTS --- +def test_no_arguments_usage(): + # Hata durumu: Hicbir arguman girilmezse kullanim kilavuzu basilir + output = run_cmd([]) + assert "Usage" in output \ No newline at end of file diff --git a/problems/minibookmark/TEST-v2.py b/problems/minibookmark/TEST-v2.py new file mode 100644 index 00000000..e8049af7 --- /dev/null +++ b/problems/minibookmark/TEST-v2.py @@ -0,0 +1,92 @@ +""" +PROJECT: mini-bookmark V1 +STUDENT: Hüdanur Şener (251478066) + +V1 GÖREV LİSTESİ (Ödev 4.2 Gereksinimi): +1. 'init' komutu tamamlandı: .minibookmark/ klasörü ve veri dosyası oluşturuluyor. +2. 'add' komutu id|title|url|date formatında kayıt yapacak şekilde geliştirildi. +3. 'search' komutu Codex desteğiyle ek puan görevi olarak projeye eklendi. +""" + +import sys +import os + +# Veri saklama yolları [cite: 2, 6] +DB_DIR = ".minibookmark" +DB_FILE = os.path.join(DB_DIR, "links.dat") + + +def init(): + """Projeyi başlatır ve gerekli dosyayı oluşturur[cite: 3].""" + if os.path.exists(DB_DIR): + print("Already initialized.") + else: + os.makedirs(DB_DIR) + open(DB_FILE, "w").close() + print("Project initialized.") + + +def add(title, url): + """Yeni bir bookmark ekler[cite: 4].""" + if not os.path.exists(DB_DIR): + print("Not initialized. Run: python minibookmark.py init") + else: + try: + with open(DB_FILE, "r") as f: + new_id = len(f.readlines()) + 1 + except FileNotFoundError: + new_id = 1 + + date_str = "2026-03-16" # SPEC'teki sabit tarih formatı [cite: 6] + entry = f"{new_id}|{title}|{url}|{date_str}\n" + + with open(DB_FILE, "a") as f: + f.write(entry) + print(f"Added bookmark #{new_id}: {title}") + + +def search(keyword): + """BONUS: Codex ile üretilen arama fonksiyonu[cite: 42].""" + if not os.path.exists(DB_FILE): + print("Not initialized.") + return + with open(DB_FILE, "r") as f: + found = False + for line in f: + if keyword.lower() in line.split('|')[1].lower(): + print(line.strip()) + found = True + if not found: + print("No bookmarks found.") + + +def main(): + args = sys.argv[1:] + + if not args: + print("Usage: python minibookmark.py <command> [args]") + return + + command = args[0] + + if command == "init": + init() + elif command == "add": + if len(args) < 3: + print("Usage: python minibookmark.py add <title> <url>") + else: + add(args[1], args[2]) + elif command == "search": + if len(args) < 2: + print("Usage: python minibookmark.py search <keyword>") + else: + search(args[1]) + elif command in ["list", "delete"]: + # Gelecek haftalar için yer tutucu mesaj + print("This feature will be implemented in future weeks.") + else: + print(f"Unknown command: {command}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/problems/minibookmark/TEST-v3.py b/problems/minibookmark/TEST-v3.py new file mode 100644 index 00000000..d08b9a54 --- /dev/null +++ b/problems/minibookmark/TEST-v3.py @@ -0,0 +1,142 @@ +""" +PROJECT: mini-bookmark V3 +AUTHOR: Hüdanur Şener (251478066) +DATE: 2026-04-20 + +V2 TASK LIST: +1. 'list' command completed: Displays all records in a formatted table. +2. 'delete' command implemented: Added logic to remove a record by ID. +3. URL Validation: Added a check to ensure links start with 'http'. +""" + +import sys +import os + +# Data storage paths [cite: 14] +DB_DIR = ".minibookmark" +DB_FILE = os.path.join(DB_DIR, "links.dat") + + +def init(): + """Initializes the project and creates necessary directory/file[cite: 15].""" + if os.path.exists(DB_DIR): + print("Already initialized.") + else: + os.makedirs(DB_DIR) + open(DB_FILE, "w").close() + print("Project initialized.") + + +def add(title, url): + """Adds a new bookmark with URL validation[cite: 16].""" + if not url.startswith("http"): + print("Error: URL must start with 'http' or 'https'.") + return + + if not os.path.exists(DB_DIR): + print("Not initialized. Run: python minibookmark.py init") + return + + try: + with open(DB_FILE, "r") as f: + lines = f.readlines() + new_id = len(lines) + 1 + except FileNotFoundError: + new_id = 1 + + date_str = "2026-04-20" + entry = f"{new_id}|{title}|{url}|{date_str}\n" + + with open(DB_FILE, "a") as f: + f.write(entry) + print(f"Added bookmark #{new_id}: {title}") + + +def list_bookmarks(): + """V2: Lists all saved bookmarks in a clean format.""" + if not os.path.exists(DB_FILE) or os.path.getsize(DB_FILE) == 0: + print("No bookmarks found.") + return + + # Table Header + print(f"{'ID':<4} | {'TITLE':<20} | {'URL':<30} | {'DATE'}") + print("-" * 75) + with open(DB_FILE, "r") as f: + for line in f: + parts = line.strip().split('|') + if len(parts) == 4: + print(f"{parts[0]:<4} | {parts[1]:<20} | {parts[2]:<30} | {parts[3]}") + + +def delete(bookmark_id): + """V2: Removes a bookmark based on its ID.""" + if not os.path.exists(DB_FILE): + print("Not initialized.") + return + + lines = [] + found = False + with open(DB_FILE, "r") as f: + lines = f.readlines() + + with open(DB_FILE, "w") as f: + for line in lines: + # Check if the line starts with the target ID + if not line.startswith(f"{bookmark_id}|"): + f.write(line) + else: + found = True + + if found: + print(f"Bookmark #{bookmark_id} deleted successfully.") + else: + print(f"Error: Bookmark #{bookmark_id} not found.") + + +def search(keyword): + """Searches for bookmarks by title keyword[cite: 18].""" + if not os.path.exists(DB_FILE): + print("Not initialized.") + return + with open(DB_FILE, "r") as f: + found = False + for line in f: + if keyword.lower() in line.split('|')[1].lower(): + print(line.strip()) + found = True + if not found: + print("No bookmarks found matching the keyword.") + + +def main(): + args = sys.argv[1:] + if not args: + print("Usage: python minibookmark.py <command> [args]") + return + + command = args[0] + if command == "init": + init() + elif command == "add": + if len(args) < 3: + print("Usage: python minibookmark.py add <title> <url>") + else: + add(args[1], args[2]) + elif command == "list": + list_bookmarks() + elif command == "delete": + if len(args) < 2: + print("Usage: python minibookmark.py delete <id>") + else: + delete(args[1]) + elif command == "search": + if len(args) < 2: + print("Usage: python minibookmark.py search <keyword>") + else: + search(args[1]) + else: + print(f"Unknown command: {command}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/problems/minibookmark/solution_v0.py b/problems/minibookmark/solution_v0.py new file mode 100644 index 00000000..e4bc768e --- /dev/null +++ b/problems/minibookmark/solution_v0.py @@ -0,0 +1,82 @@ +""" +mini-bookmark v0 — Basitlestirilmis implementasyon +Ogrenci: Hüdanur Şener (251478066) +Proje: mini-bookmark + +Kapsam: Sadece init ve add komutlari. +Sinirlamalar: Dongu (for/while) ve liste ([]) kesinlikle kullanilmadi. +""" +import sys +import os + + +def initialize(): + """Bookmark dizini ve bos veri dosyasini olusturur.""" + if os.path.exists(".minibookmark"): + return "Already initialized." + + os.mkdir(".minibookmark") + # Bos bir dosya acip kapatmak onu olusturmak demektir + f = open(".minibookmark/links.dat", "w") + f.close() + return "Initialized empty bookmark folder." + + +def add_bookmark(title, url): + """Yeni bir link ekler. ID tespiti satir sayilarini sayarak yapilir.""" + # Klasor yoksa hata dondur + if not os.path.exists(".minibookmark"): + return "Not initialized. Run: python minibookmark.py init" + + # Mevcut dosyayi oku (ID tespiti icin) + f = open(".minibookmark/links.dat", "r") + content = f.read() + f.close() + + # YASAK: Dongu ve liste kullanmadan satir sayisi bulma: + # Dosyadaki her '\n' (yeni satir) karakteri bir kaydi temsil eder. + bookmark_id = content.count("\n") + 1 + + # Dosyaya ekleme yap (Append modu) + f = open(".minibookmark/links.dat", "a") + f.write(str(bookmark_id) + "|" + title + "|" + url + "|2026-03-16\n") + f.close() + + return "Added bookmark #" + str(bookmark_id) + ": " + title + + +def show_not_implemented(command_name): + """Henuz kodlanmamis ozellikler icin standart bir mesaj dondurur.""" + return "Command '" + command_name + "' will be implemented in future weeks." + + +# --- Ana Program Akisi --- + +# Kullanici hicbir sey yazmadan programi calistirirsa +if len(sys.argv) < 2: + print("Usage: python minibookmark.py <command> [args]") + +# init komutu +elif sys.argv[1] == "init": + print(initialize()) + +# add komutu +elif sys.argv[1] == "add": + # Eger title veya url eksikse (python + dosya_adi + komut + 2 arguman = 4) + if len(sys.argv) < 4: + print("Usage: python minibookmark.py add <title> <url>") + else: + # Argumanlari fonksiyonumuza gonderiyoruz + print(add_bookmark(sys.argv[2], sys.argv[3])) + +# list komutu (Henuz implemente edilmedi) +elif sys.argv[1] == "list": + print(show_not_implemented("list")) + +# delete komutu (Henuz implemente edilmedi) +elif sys.argv[1] == "delete": + print(show_not_implemented("delete")) + +# Gecersiz bir komut girilirse +else: + print("Unknown command: " + sys.argv[1]) \ No newline at end of file From 26e084df9287d88fed600b2230640eeec53c8119 Mon Sep 17 00:00:00 2001 From: hudanursner <hudanursner@gmail.com> Date: Thu, 7 May 2026 13:14:12 +0300 Subject: [PATCH 8/9] Fix mini-bookmark problem structure --- REadME.md | 72 ++++++++- SPEC v3.txt | 57 ------- SPEC.txt | 49 ------ SPEC0.txt | 0 TEST-v3.py | 142 ------------------ minibookmark.py | 92 ------------ problem.json.txt | 14 -- .../minibookmark/{SPEC v1.txt => SPEC-v1.txt} | 0 .../minibookmark/{SPEC v2.txt => SPEC-v2.txt} | 0 .../minibookmark/{SPEC v3.txt => SPEC-v3.txt} | 0 solution_v0.py | 82 ---------- test_spec.py | 86 ----------- test_spec1.py | 103 ------------- 13 files changed, 66 insertions(+), 631 deletions(-) delete mode 100644 SPEC v3.txt delete mode 100644 SPEC.txt delete mode 100644 SPEC0.txt delete mode 100644 TEST-v3.py delete mode 100644 minibookmark.py delete mode 100644 problem.json.txt rename problems/minibookmark/{SPEC v1.txt => SPEC-v1.txt} (100%) rename problems/minibookmark/{SPEC v2.txt => SPEC-v2.txt} (100%) rename problems/minibookmark/{SPEC v3.txt => SPEC-v3.txt} (100%) delete mode 100644 solution_v0.py delete mode 100644 test_spec.py delete mode 100644 test_spec1.py diff --git a/REadME.md b/REadME.md index 49f96faf..97b0cfb1 100644 --- a/REadME.md +++ b/REadME.md @@ -1,8 +1,68 @@ -#Ne değiştirdim? -SPEC dosyasını güncelledim ve "search" komutu gereksinimini ekledim. Ayrıca V1 aşaması için temel kodları yazdım. +mini-bookmark V2 + +A CLI tool to save and manage web URLs, developed as part of a university assignment at Samsun Üniversitesi. + +Student Information + +Name: Hüdanur Şener + +Student ID: 251478066 + +Overview + +mini-bookmark is a lightweight command-line interface tool that allows users to store, list, search, and delete web bookmarks. All data is persisted in a plain text file (links.dat) located within a hidden .minibookmark/ directory. + +V1 vs V2: What's New? + +The project has evolved from V1 to V2 with the following key improvements: + +Command Completion: In V1, list and delete were placeholders. In V2, they are fully functional. + +URL Validation: V2 introduces a safety check ensuring all added URLs start with 'http' or 'https'. + +Formatted Output: The list command now presents data in a clean, professional table format. + +Enhanced Error Handling: Improved feedback for missing arguments, invalid IDs, and uninitialized states. + +V2 Task List + +List Command: Implemented full listing of bookmarks with a formatted header and aligned columns. + +Delete Command: Added functionality to remove a specific bookmark entry using its ID number. + +Validation Logic: Integrated a prefix check for URLs to prevent malformed data entry. + +Installation \& Usage + +1\. Initialize the Project + +python minibookmark.py init + +2\. Add a Bookmark + +python minibookmark.py add "Google" "https://google.com" + +3\. List All Bookmarks + +python minibookmark.py list + +4\. Search Bookmarks + +python minibookmark.py search "keyword" + +5\. Delete a Bookmark + +python minibookmark.py delete <id> + +Data Format + +Data is stored in .minibookmark/links.dat using the following structure: + +id|title|url|date + +License + +Educational purpose only. + -#Neden değiştirdim? -Sistemin daha işlevsel olması ve kullanıcıların bookmarklar arasında arama yapabilmesi için. -#Test ettim mi? -Evet, tüm komutlar ve hata mesajları SPEC ve test dosyalarına uygun şekilde kontrol edildi. diff --git a/SPEC v3.txt b/SPEC v3.txt deleted file mode 100644 index 390793b4..00000000 --- a/SPEC v3.txt +++ /dev/null @@ -1,57 +0,0 @@ -PROJECT: mini-bookmark -AUTHOR: Hüdanur Şener (251478066) -VERSION: v3 -DATE: 2026-04-20 - -======================================== -OVERVIEW -======================================== -mini-bookmark is a CLI tool to save and manage web URLs[cite: 13]. -It stores bookmarks in a plain text file. -All data is kept in a directory named .minibookmark/[cite: 14]. - -======================================== -COMMANDS -======================================== - ---- init --- -Usage: python minibookmark.py init -Creates .minibookmark/ directory and an empty links.dat file[cite: 15]. -If it exists, prints "Already initialized." - ---- add --- -Usage: python minibookmark.py add "Title" "URL" -(V2 Update) Saves a new bookmark with an auto-increment ID. -URL must start with "http" or "https"[cite: 16]. -Format: id|title|url|date -Prints: "Added bookmark #<id>: <title>" - ---- list --- -Usage: python minibookmark.py list -(V2 Update: Implemented) Shows all saved bookmarks in a formatted table[cite: 17]. -Displays ID, Title, URL, and Date columns. - ---- delete --- -Usage: python minibookmark.py delete <id> -(V2 Update: Implemented) Removes a bookmark by its specific ID from links.dat[cite: 18]. -Prints: "Bookmark #<id> deleted." if successful. - ---- search --- -Usage: python minibookmark.py search <keyword> -Searches for bookmarks by title keyword (Case-insensitive)[cite: 19]. - -======================================== -DATA FORMAT -======================================== -File: .minibookmark/links.dat -Format: id|title|url|YYYY-MM-DD -Example: 1|Google|http://google.com|2026-04-20 - -======================================== -ERROR HANDLING -======================================== -- Running without init: "Not initialized. Run: python minibookmark.py init" -- Unknown command: "Unknown command: <command>" -- Missing arguments: "Usage: python minibookmark.py <command> [args]" -- Invalid URL (V2): "Error: URL must start with 'http' or 'https'." -- ID Not Found (V2): "Bookmark #<id> not found." \ No newline at end of file diff --git a/SPEC.txt b/SPEC.txt deleted file mode 100644 index c7f503aa..00000000 --- a/SPEC.txt +++ /dev/null @@ -1,49 +0,0 @@ -PROJECT: mini-bookmark -AUTHOR: Hüdanur Şener (251478066) -VERSION: v0 -DATE: 2026-03-16 - -======================================== -OVERVIEW -======================================== -mini-bookmark is a CLI tool to save and manage web URLs. -It stores bookmarks in a plain text file. -All data is kept in a directory named .minibookmark/ - -======================================== -COMMANDS -======================================== - ---- init --- -Usage: python minibookmark.py init -Creates .minibookmark/ directory and an empty links.dat file. -If it exists, prints "Already initialized." - ---- add --- -Usage: python minibookmark.py add "Google" "https://google.com" -Saves a new bookmark with an auto-increment ID. -Format: id|title|url|date -Prints: "Added bookmark #<id>: <title>" - ---- list --- -Usage: python minibookmark.py list -(To be implemented) -Will show all saved bookmarks. - ---- delete --- -Usage: python minibookmark.py delete <id> -(To be implemented) -Will remove a bookmark by ID. - -======================================== -DATA FORMAT -======================================== -File: .minibookmark/links.dat -Format: id|title|url|2026-03-16 - -======================================== -ERROR HANDLING -======================================== -- Running without init: "Not initialized. Run: python minibookmark.py init" -- Unknown command: "Unknown command: <command>" -- Missing arguments: "Usage: python minibookmark.py <command> [args]" \ No newline at end of file diff --git a/SPEC0.txt b/SPEC0.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/TEST-v3.py b/TEST-v3.py deleted file mode 100644 index 18943d77..00000000 --- a/TEST-v3.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -PROJECT: mini-bookmark V3 -AUTHOR: Hüdanur Şener (251478066) -DATE: 2026-04-20 - -V2 TASK LIST: -1. 'list' command completed: Displays all records in a formatted table. -2. 'delete' command implemented: Added logic to remove a record by ID. -3. URL Validation: Added a check to ensure links start with 'http'. -""" - -import sys -import os - -# Data storage paths [cite: 14] -DB_DIR = ".minibookmark" -DB_FILE = os.path.join(DB_DIR, "links.dat") - - -def init(): - """Initializes the project and creates necessary directory/file[cite: 15].""" - if os.path.exists(DB_DIR): - print("Already initialized.") - else: - os.makedirs(DB_DIR) - open(DB_FILE, "w").close() - print("Project initialized.") - - -def add(title, url): - """Adds a new bookmark with URL validation[cite: 16].""" - if not url.startswith("http"): - print("Error: URL must start with 'http' or 'https'.") - return - - if not os.path.exists(DB_DIR): - print("Not initialized. Run: python minibookmark.py init") - return - - try: - with open(DB_FILE, "r") as f: - lines = f.readlines() - new_id = len(lines) + 1 - except FileNotFoundError: - new_id = 1 - - date_str = "2026-04-20" - entry = f"{new_id}|{title}|{url}|{date_str}\n" - - with open(DB_FILE, "a") as f: - f.write(entry) - print(f"Added bookmark #{new_id}: {title}") - - -def list_bookmarks(): - """V2: Lists all saved bookmarks in a clean format.""" - if not os.path.exists(DB_FILE) or os.path.getsize(DB_FILE) == 0: - print("No bookmarks found.") - return - - # Table Header - print(f"{'ID':<4} | {'TITLE':<20} | {'URL':<30} | {'DATE'}") - print("-" * 75) - with open(DB_FILE, "r") as f: - for line in f: - parts = line.strip().split('|') - if len(parts) == 4: - print(f"{parts[0]:<4} | {parts[1]:<20} | {parts[2]:<30} | {parts[3]}") - - -def delete(bookmark_id): - """V2: Removes a bookmark based on its ID.""" - if not os.path.exists(DB_FILE): - print("Not initialized.") - return - - lines = [] - found = False - with open(DB_FILE, "r") as f: - lines = f.readlines() - - with open(DB_FILE, "w") as f: - for line in lines: - # Check if the line starts with the target ID - if not line.startswith(f"{bookmark_id}|"): - f.write(line) - else: - found = True - - if found: - print(f"Bookmark #{bookmark_id} deleted successfully.") - else: - print(f"Error: Bookmark #{bookmark_id} not found.") - - -def search(keyword): - """Searches for bookmarks by title keyword[cite: 18].""" - if not os.path.exists(DB_FILE): - print("Not initialized.") - return - with open(DB_FILE, "r") as f: - found = False - for line in f: - if keyword.lower() in line.split('|')[1].lower(): - print(line.strip()) - found = True - if not found: - print("No bookmarks found matching the keyword.") - - -def main(): - args = sys.argv[1:] - if not args: - print("Usage: python minibookmark.py <command> [args]") - return - - command = args[0] - if command == "init": - init() - elif command == "add": - if len(args) < 3: - print("Usage: python minibookmark.py add <title> <url>") - else: - add(args[1], args[2]) - elif command == "list": - list_bookmarks() - elif command == "delete": - if len(args) < 2: - print("Usage: python minibookmark.py delete <id>") - else: - delete(args[1]) - elif command == "search": - if len(args) < 2: - print("Usage: python minibookmark.py search <keyword>") - else: - search(args[1]) - else: - print(f"Unknown command: {command}") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/minibookmark.py b/minibookmark.py deleted file mode 100644 index 73860630..00000000 --- a/minibookmark.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -PROJECT: mini-bookmark V1 -STUDENT: Hüdanur Şener (251478066) - -V1 GÖREV LİSTESİ (Ödev 4.2 Gereksinimi): -1. 'init' komutu tamamlandı: .minibookmark/ klasörü ve veri dosyası oluşturuluyor. -2. 'add' komutu id|title|url|date formatında kayıt yapacak şekilde geliştirildi. -3. 'search' komutu Codex desteğiyle ek puan görevi olarak projeye eklendi. -""" - -import sys -import os - -# Veri saklama yolları [cite: 2, 6] -DB_DIR = ".minibookmark" -DB_FILE = os.path.join(DB_DIR, "links.dat") - - -def init(): - """Projeyi başlatır ve gerekli dosyayı oluşturur[cite: 3].""" - if os.path.exists(DB_DIR): - print("Already initialized.") - else: - os.makedirs(DB_DIR) - open(DB_FILE, "w").close() - print("Project initialized.") - - -def add(title, url): - """Yeni bir bookmark ekler[cite: 4].""" - if not os.path.exists(DB_DIR): - print("Not initialized. Run: python minibookmark.py init") - else: - try: - with open(DB_FILE, "r") as f: - new_id = len(f.readlines()) + 1 - except FileNotFoundError: - new_id = 1 - - date_str = "2026-03-16" # SPEC'teki sabit tarih formatı [cite: 6] - entry = f"{new_id}|{title}|{url}|{date_str}\n" - - with open(DB_FILE, "a") as f: - f.write(entry) - print(f"Added bookmark #{new_id}: {title}") - - -def search(keyword): - """BONUS: Codex ile üretilen arama fonksiyonu[cite: 42].""" - if not os.path.exists(DB_FILE): - print("Not initialized.") - return - with open(DB_FILE, "r") as f: - found = False - for line in f: - if keyword.lower() in line.split('|')[1].lower(): - print(line.strip()) - found = True - if not found: - print("No bookmarks found.") - - -def main(): - args = sys.argv[1:] - - if not args: - print("Usage: python minibookmark.py <command> [args]") - return - - command = args[0] - - if command == "init": - init() - elif command == "add": - if len(args) < 3: - print("Usage: python minibookmark.py add <title> <url>") - else: - add(args[1], args[2]) - elif command == "search": - if len(args) < 2: - print("Usage: python minibookmark.py search <keyword>") - else: - search(args[1]) - elif command in ["list", "delete"]: - # Gelecek haftalar için yer tutucu mesaj - print("This feature will be implemented in future weeks.") - else: - print(f"Unknown command: {command}") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/problem.json.txt b/problem.json.txt deleted file mode 100644 index 6f057ed0..00000000 --- a/problem.json.txt +++ /dev/null @@ -1,14 +0,0 @@ -{ - "project_name": "mini-bookmark", - "version": "v1", - "student_name": "Hüdanur Şener", - "student_id": "251478066", - "description": "A CLI tool for managing web bookmarks with search functionality.", - "repository": "https://github.com/seyyah/which-language", - "tasks_completed": [ - "Project initialization with init command", - "Adding bookmarks with auto-increment ID", - "Search functionality implemented with AI assistance", - "Error handling for uninitialized states" - ] -} diff --git a/problems/minibookmark/SPEC v1.txt b/problems/minibookmark/SPEC-v1.txt similarity index 100% rename from problems/minibookmark/SPEC v1.txt rename to problems/minibookmark/SPEC-v1.txt diff --git a/problems/minibookmark/SPEC v2.txt b/problems/minibookmark/SPEC-v2.txt similarity index 100% rename from problems/minibookmark/SPEC v2.txt rename to problems/minibookmark/SPEC-v2.txt diff --git a/problems/minibookmark/SPEC v3.txt b/problems/minibookmark/SPEC-v3.txt similarity index 100% rename from problems/minibookmark/SPEC v3.txt rename to problems/minibookmark/SPEC-v3.txt diff --git a/solution_v0.py b/solution_v0.py deleted file mode 100644 index 88589a2a..00000000 --- a/solution_v0.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -mini-bookmark v0 — Basitlestirilmis implementasyon -Ogrenci: Hüdanur Şener (251478066) -Proje: mini-bookmark - -Kapsam: Sadece init ve add komutlari. -Sinirlamalar: Dongu (for/while) ve liste ([]) kesinlikle kullanilmadi. -""" -import sys -import os - - -def initialize(): - """Bookmark dizini ve bos veri dosyasini olusturur.""" - if os.path.exists(".minibookmark"): - return "Already initialized." - - os.mkdir(".minibookmark") - # Bos bir dosya acip kapatmak onu olusturmak demektir - f = open(".minibookmark/links.dat", "w") - f.close() - return "Initialized empty bookmark folder." - - -def add_bookmark(title, url): - """Yeni bir link ekler. ID tespiti satir sayilarini sayarak yapilir.""" - # Klasor yoksa hata dondur - if not os.path.exists(".minibookmark"): - return "Not initialized. Run: python minibookmark.py init" - - # Mevcut dosyayi oku (ID tespiti icin) - f = open(".minibookmark/links.dat", "r") - content = f.read() - f.close() - - # YASAK: Dongu ve liste kullanmadan satir sayisi bulma: - # Dosyadaki her '\n' (yeni satir) karakteri bir kaydi temsil eder. - bookmark_id = content.count("\n") + 1 - - # Dosyaya ekleme yap (Append modu) - f = open(".minibookmark/links.dat", "a") - f.write(str(bookmark_id) + "|" + title + "|" + url + "|2026-03-16\n") - f.close() - - return "Added bookmark #" + str(bookmark_id) + ": " + title - - -def show_not_implemented(command_name): - """Henuz kodlanmamis ozellikler icin standart bir mesaj dondurur.""" - return "Command '" + command_name + "' will be implemented in future weeks." - - -# --- Ana Program Akisi --- - -# Kullanici hicbir sey yazmadan programi calistirirsa -if len(sys.argv) < 2: - print("Usage: python minibookmark.py <command> [args]") - -# init komutu -elif sys.argv[1] == "init": - print(initialize()) - -# add komutu -elif sys.argv[1] == "add": - # Eger title veya url eksikse (python + dosya_adi + komut + 2 arguman = 4) - if len(sys.argv) < 4: - print("Usage: python minibookmark.py add <title> <url>") - else: - # Argumanlari fonksiyonumuza gonderiyoruz - print(add_bookmark(sys.argv[2], sys.argv[3])) - -# list komutu (Henuz implemente edilmedi) -elif sys.argv[1] == "list": - print(show_not_implemented("list")) - -# delete komutu (Henuz implemente edilmedi) -elif sys.argv[1] == "delete": - print(show_not_implemented("delete")) - -# Gecersiz bir komut girilirse -else: - print("Unknown command: " + sys.argv[1]) \ No newline at end of file diff --git a/test_spec.py b/test_spec.py deleted file mode 100644 index 6a3c24a6..00000000 --- a/test_spec.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -mini-bookmark SPEC test cases -Student:Hüdanur Şener (251478066) -Project: mini-bookmark -""" -import subprocess -import os -import shutil - -# --- Helper Function --- -def run_cmd(args): - """Runs the script and returns the output.""" - result = subprocess.run( - ["python", "minibookmark.py"] + args, - capture_output=True, - text=True - ) - return result.stdout.strip() - -def setup_function(): - """Clean start for each test.""" - if os.path.exists(".minibookmark"): - shutil.rmtree(".minibookmark") - -# --- 1. init COMMAND TESTS --- -def test_init_creates_directory(): - # Normal durum: İlk kez init yapilir - run_cmd(["init"]) - assert os.path.exists(".minibookmark") == True - -def test_init_already_initialized(): - # Hata durumu: Zaten init yapilmisken tekrar yapilir - run_cmd(["init"]) - output = run_cmd(["init"]) - assert "Already initialized" in output - -# --- 2. add COMMAND TESTS --- -def test_add_single_bookmark(): - # Normal durum: Bir link basariyla eklenir - run_cmd(["init"]) - output = run_cmd(["add", "Google", "https://google.com"]) - assert "Added bookmark #1" in output - -def test_add_multiple_bookmarks(): - # Normal durum: İkinci link eklenir ve ID artar - run_cmd(["init"]) - run_cmd(["add", "A", "a.com"]) - output = run_cmd(["add", "B", "b.com"]) - assert "#2" in output - -def test_add_missing_arguments(): - # Hata durumu: Eksik arguman (sadece isim) - run_cmd(["init"]) - output = run_cmd(["add", "OnlyName"]) - assert "Usage" in output - -# --- 3. ERROR HANDLING & FLOW TESTS --- -def test_command_before_init(): - # Hata durumu: Klasor yokken add komutu calismaz - output = run_cmd(["add", "Test", "test.com"]) - assert "Not initialized" in output - -def test_unknown_command_error(): - # Hata durumu: SPEC'te olmayan bir komut - run_cmd(["init"]) - output = run_cmd(["jump"]) - assert "Unknown command" in output - -# --- 4. FUTURE IMPLEMENTATION TESTS (SPEC Status) --- -def test_list_not_implemented_yet(): - # SPEC Uyumu: list komutu henuz hazir degil mesaji vermeli - run_cmd(["init"]) - output = run_cmd(["list"]) - assert "future weeks" in output - -def test_delete_not_implemented_yet(): - # SPEC Uyumu: delete komutu henuz hazir degil mesaji vermeli - run_cmd(["init"]) - output = run_cmd(["delete", "1"]) - assert "future weeks" in output - -# --- 5. USAGE TESTS --- -def test_no_arguments_usage(): - # Hata durumu: Hicbir arguman girilmezse kullanim kilavuzu basilir - output = run_cmd([]) - assert "Usage" in output \ No newline at end of file diff --git a/test_spec1.py b/test_spec1.py deleted file mode 100644 index 40fccb5b..00000000 --- a/test_spec1.py +++ /dev/null @@ -1,103 +0,0 @@ -""" -PROJECT: mini-bookmark V1 -STUDENT: Hüdanur Şener (251478066) - -V1 GÖREV LİSTESİ (Ödev 4.2 Gereksinimi): -1. 'init' komutu tamamlandı: .minibookmark/ klasörü ve veri dosyası oluşturuluyor. -2. 'add' komutu id|title|url|date formatında kayıt yapacak şekilde geliştirildi. -3. 'search' komutu Codex desteğiyle ek puan görevi olarak projeye eklendi. -""" - -import sys -import os - -# Veri saklama ayarları -DB_DIR = ".minibookmark" -DB_FILE = os.path.join(DB_DIR, "links.dat") - - -def init(): - """Projeyi başlatır ve gerekli dizinleri oluşturur.""" - if os.path.exists(DB_DIR): - print("Already initialized.") - else: - os.makedirs(DB_DIR) - with open(DB_FILE, "w") as f: - pass - print("Project initialized.") - - -def add(title, url): - """Yeni bir bookmark ekler ve ID'yi otomatik artırır.""" - if not os.path.exists(DB_DIR): - print("Not initialized. Run: python minibookmark.py init") - return - - # Otomatik ID artırma (Satır sayısına göre) - try: - with open(DB_FILE, "r") as f: - lines = f.readlines() - new_id = len(lines) + 1 - except FileNotFoundError: - new_id = 1 - - # SPEC'te istenen tarih formatı - date_str = "2026-03-16" - entry = f"{new_id}|{title}|{url}|{date_str}\n" - - with open(DB_FILE, "a") as f: - f.write(entry) - - print(f"Added bookmark #{new_id}: {title}") - - -def search(keyword): - """BONUS: Codex tarafından üretilen arama fonksiyonu.""" - if not os.path.exists(DB_FILE): - print("Not initialized.") - return - with open(DB_FILE, "r") as f: - found = False - for line in f: - # Başlık (index 1) içinde arama yapar - parts = line.strip().split('|') - if len(parts) > 1 and keyword.lower() in parts[1].lower(): - print(line.strip()) - found = True - if not found: - print("No bookmarks found.") - - -def main(): - args = sys.argv[1:] - - # 5. USAGE TESTS Uyumu - if not args: - print("Usage: python minibookmark.py <command> [args]") - return - - command = args[0] - - if command == "init": - init() - elif command == "add": - # 2. add COMMAND TESTS Uyumu (Eksik argüman kontrolü) - if len(args) < 3: - print("Usage: python minibookmark.py add <title> <url>") - else: - add(args[1], args[2]) - elif command == "search": - if len(args) < 2: - print("Usage: python minibookmark.py search <keyword>") - else: - search(args[1]) - elif command in ["list", "delete"]: - # 4. FUTURE IMPLEMENTATION TESTS Uyumu - print("This feature will be implemented in future weeks.") - else: - # 3. ERROR HANDLING & FLOW TESTS Uyumu (Bilinmeyen komut) - print(f"Unknown command: {command}") - - -if __name__ == "__main__": - main() \ No newline at end of file From b433b8dc0c04900f789591ce3d3d449cac1595fd Mon Sep 17 00:00:00 2001 From: hudanursner <hudanursner@gmail.com> Date: Thu, 7 May 2026 13:17:10 +0300 Subject: [PATCH 9/9] Rename minibookmark to mini-bookmark --- problems/{minibookmark => mini-bookmark}/SPEC-v1.txt | 0 problems/{minibookmark => mini-bookmark}/SPEC-v2.txt | 0 problems/{minibookmark => mini-bookmark}/SPEC-v3.txt | 0 problems/{minibookmark => mini-bookmark}/TEST-v1 (2).py | 0 problems/{minibookmark => mini-bookmark}/TEST-v2.py | 0 problems/{minibookmark => mini-bookmark}/TEST-v3.py | 0 problems/{minibookmark => mini-bookmark}/solution_v0.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename problems/{minibookmark => mini-bookmark}/SPEC-v1.txt (100%) rename problems/{minibookmark => mini-bookmark}/SPEC-v2.txt (100%) rename problems/{minibookmark => mini-bookmark}/SPEC-v3.txt (100%) rename problems/{minibookmark => mini-bookmark}/TEST-v1 (2).py (100%) rename problems/{minibookmark => mini-bookmark}/TEST-v2.py (100%) rename problems/{minibookmark => mini-bookmark}/TEST-v3.py (100%) rename problems/{minibookmark => mini-bookmark}/solution_v0.py (100%) diff --git a/problems/minibookmark/SPEC-v1.txt b/problems/mini-bookmark/SPEC-v1.txt similarity index 100% rename from problems/minibookmark/SPEC-v1.txt rename to problems/mini-bookmark/SPEC-v1.txt diff --git a/problems/minibookmark/SPEC-v2.txt b/problems/mini-bookmark/SPEC-v2.txt similarity index 100% rename from problems/minibookmark/SPEC-v2.txt rename to problems/mini-bookmark/SPEC-v2.txt diff --git a/problems/minibookmark/SPEC-v3.txt b/problems/mini-bookmark/SPEC-v3.txt similarity index 100% rename from problems/minibookmark/SPEC-v3.txt rename to problems/mini-bookmark/SPEC-v3.txt diff --git a/problems/minibookmark/TEST-v1 (2).py b/problems/mini-bookmark/TEST-v1 (2).py similarity index 100% rename from problems/minibookmark/TEST-v1 (2).py rename to problems/mini-bookmark/TEST-v1 (2).py diff --git a/problems/minibookmark/TEST-v2.py b/problems/mini-bookmark/TEST-v2.py similarity index 100% rename from problems/minibookmark/TEST-v2.py rename to problems/mini-bookmark/TEST-v2.py diff --git a/problems/minibookmark/TEST-v3.py b/problems/mini-bookmark/TEST-v3.py similarity index 100% rename from problems/minibookmark/TEST-v3.py rename to problems/mini-bookmark/TEST-v3.py diff --git a/problems/minibookmark/solution_v0.py b/problems/mini-bookmark/solution_v0.py similarity index 100% rename from problems/minibookmark/solution_v0.py rename to problems/mini-bookmark/solution_v0.py