From f1a6f2256d9c123e91ab274eb370ffa2cafa3d85 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Mon, 25 Aug 2025 01:26:19 +0200 Subject: [PATCH] Class implementation of simple-ini. --- class.rkt | 92 +++++++++++++++++++++++++++++++++++++++++++ info.rkt | 3 +- main.rkt | 35 ++++++++++------ scribblings/ini.scrbl | 71 ++++++++++++++++++++++++++++++++- 4 files changed, 185 insertions(+), 16 deletions(-) create mode 100644 class.rkt diff --git a/class.rkt b/class.rkt new file mode 100644 index 0000000..b29ed94 --- /dev/null +++ b/class.rkt @@ -0,0 +1,92 @@ +#lang racket/base + +(require racket/class) +(require "main.rkt") + +(provide ini% + (all-from-out racket/class)) + +(define-syntax i-set! + (syntax-rules () + ((_ a b) + (set! a b)))) + + + +(define ini% + (class object% + (init-field [file #f] [fail #f]) + + (define content #f) + + (define/public (get-file) + file) + + (define/public (set-file! f) + (i-set! file (get-ini-file f)) + this) + + (define/public (set-fail! f) + (i-set! fail f) + this) + + (define/public (get-fail) + fail) + + (define/public (get-contents) + content) + + (define/public (contents) + content) + + (define/public (reload) + (i-set! content (if (eq? file #f) + (make-ini) + (if (file-exists? file) + (file->ini file) + (make-ini)))) + this) + + (define/public (set! section key value) + (begin + (ini-set! content section key value) + (if (eq? file #f) + (when fail + (error "ini: No filename set, cannot write ini after set!")) + (ini->file content file)) + this)) + + (define/public (get section key . default-value) + (let* ((rnd (string->symbol (format "@@no-value-~a-@@" (random 400000000)))) + (def-val (if (null? default-value) rnd (car (default-value))))) + (let ((r (ini-get content section key def-val))) + (when fail + (when (eq? r rnd) + (error (string-append + "ini: No default value set and no value found for section '" + (symbol->string section) + "' and key '" + (symbol->string key) + "'")) + ) + ) + (if (eq? r rnd) + #f + r)))) + + (super-new) + + (begin + (if (eq? file #f) + (i-set! content (make-ini)) + (begin + (i-set! file (get-ini-file file)) + (if (file-exists? file) + (i-set! content (file->ini file)) + (i-set! content (make-ini))))) + ) + + ) + ) + + \ No newline at end of file diff --git a/info.rkt b/info.rkt index 85c649a..3decac9 100644 --- a/info.rkt +++ b/info.rkt @@ -1,9 +1,8 @@ #lang info (define pkg-authors '(hnmdijkema)) -(define version "0.2.2") +(define version "0.3.0") (define license 'Apache-2.0) -;(define collection "simple-ini") (define pkg-desc "A Simple .ini file reader/writer for racket") (define scribblings diff --git a/main.rkt b/main.rkt index 45b5b3d..f2a8843 100644 --- a/main.rkt +++ b/main.rkt @@ -2,6 +2,7 @@ (require racket/string) (require racket/file) +(require racket/port) (provide file->ini ini->file @@ -48,7 +49,8 @@ (set! last-is-newline #f) (display (cadr line) out) (display "=" out) - (display (caddr line) out) + (display"VALUE:" out) + (write (caddr line) out) (newline out)) (error "Unknown line format"))))) lines)))) @@ -58,19 +60,26 @@ (define (make-ini) (mcons 'ini (list))) +(define re-num #px"^([+]|[-])?([0-9]+([.]([0-9]+))?)$") +(define re-bool #px"^(#f|#t|true|false)$") +(define re-value #px"^VALUE:(.*)$") + (define (interpret s) - (let ((re-num #px"^([+]|[-])?([0-9]+([.]([0-9]+))?)$") - (re-bool #px"^(#f|#t|true|false)$")) - (let ((ss (string-downcase (string-trim s)))) - (let ((m-num (regexp-match re-num ss))) - (if m-num - (string->number (car m-num)) - (let ((m-b (regexp-match re-bool ss))) - (if m-b - (if (or (string=? ss "#t") (string=? ss "true")) - #t - #f) - s))))))) + (let ((m (regexp-match re-value s))) + (if (eq? m #f) + (let ((ss (string-downcase (string-trim s)))) + (let ((m-num (regexp-match re-num ss))) + (if (eq? m-num #f) + (let ((m-b (regexp-match re-bool ss))) + (if (eq? m-b #f) + s + (if (or (string=? ss "#t") (string=? ss "true")) + #t + #f) + )) + (string->number (car m-num))))) + (let* ((content (cadr m))) + (with-input-from-string content read))))) (define (file->ini file*) (let* ((file (get-ini-file file*)) diff --git a/scribblings/ini.scrbl b/scribblings/ini.scrbl index 496ec0a..d9b1525 100644 --- a/scribblings/ini.scrbl +++ b/scribblings/ini.scrbl @@ -2,8 +2,10 @@ @(require scribble/example + scribble/core (for-label racket/base racket/string + racket/class racket/file)) (define myeval @@ -73,9 +75,76 @@ mc-pair?]{ Sets the value of @racket[key] in the specified @racket[section] of the INI structure. If the section or key does not exist, it is created. Returns the modified INI structure.} + +@section{The @racket[ini%] Racket Class} + +@defmodule[simple-ini/class] + +Require this module for the OO implementation of this Simple INI implementation + + +@defclass[ini% object% ()]{ + +An OO wrapper around the ini functions. + +@defconstructor[([file (or/c symbol? string? path? boolean?) #f] + [fail (or/c boolean?) #f] + )]{ + Creates the ini from the given file. + * If (eq? file #f), an empty ini will be made. + * if (symbol? file), an ini will be made or read in the users preferences folder with the given (format "~a.ini" file) as name. + * Otherwise, the file will be made or read at the given location. + + The fail flag determines if methods of the class will fail when some value in the ini file is written while there is no file to write to + or if some non existing key is read. +} + +@defmethod*[([(get-file) path?])]{ + Gets the current ini file. See constructor for more information. +} + +@defmethod*[([(set-file! [file (or/c symbol? string? path?)]) this])]{ + Sets the ini file to be used. See constructor for more information. +} + +@defmethod*[([(get-fail) boolean?])]{ + Gets the value of the 'fail' flag. See constructor for more information. +} + +@defmethod*[([(set-fail! [fail boolean?]) this])]{ + Sets the value of the 'fail' flag. See constructor for more information. +} + +@defmethod*[([(get-contents) list?])]{ + Gets the contents of the ini structure as stored in memory. +} + +@defmethod*[([(contents) list?])]{ + See get-contents. +} + +@defmethod*[([(reload) this])]{ + Reloads the ini file in memory, or empties the ini structure (eq? file #f). +} + +@defmethod*[([(set! [section (or/c symbol? string?)] [key (or/c symbol? string?)] [value any/c?]) this])]{ + Sets the value of the key in the given section. After the set! operation, the ini structure will be written to file. + Note. Although ini files can be read from standard .ini formats, the simple-ini format will be enhanced. It wil store values in racket format, so that 'read' can be used to read in the racket value. +} + +@defmethod*[([(get [section (or/c symbol? string?)] [key (or/c symbol? string?)] [default-value any/c?]) any/c?] + [(get [section (or/c symbol? string?)] [key (or/c symbol? string)]) any/c] + )]{ + Returns the value for the given section and key combination. If this combination does not exist in the ini structure, it will return the default-value. However, if default-value is not given, it will return #f. +} + +} ; end class + + + @section{The @racket[ini] Roos Class} -@defmodule[simple-ini/roos]{Require this module for the OO implementation of this Simple INI implementation +@defmodule[simple-ini/roos]{Require this module for the OO implementation of this Simple INI implementation in the ROOS OO framework Provides a @seclink["top" #:doc '(lib "roos/scribblings/roos.scrbl")]{Roos class} that gives object-oriented access to INI files using the underlying @racket[file->ini] parser system. The class offers methods to load, query, and update INI files using familiar object-style interactions.}