Hi,

below some funcs and a mechanism to avoid name clobbering:
if you execute this script and you already have defined some words
this script wants to introduce, you will be asked if you want to abort
the execution before your definitions would be lost.


Any suggestions are welcomed,


Oliver Schaefer ([EMAIL PROTECTED])


REBOL [
  Title:   "Toolbox"
  Date:    10-Dec-1999
  Author:  "many Rebols"
  File:    %toolbox.r
  Purpose: {
    some useful funcs.
  }
]

;[registry]-----------------------------------------------------------------
;
; Purpose: to avoid name clobbering
;
if any [not value? 'registry registry/debug == true] [
  use [old_words] [
    either value? 'registry [
      old_words: registry/words
    ][
      old_words: copy []
    ]
    registry: make object! [
      debug:    true      ; change this if you aren't testing any more...
      warnings: false
      words:    old_words ; use 'copy if you have a GC problem...
      register: func ['word /local found] [
        found: not none? find self/words word
        either found [
          either self/debug [
            if self/warnings [
              print ["Warning: word is already defined [registered]:" :word]
            ]
            true  ; means: overwriting 'word is okay,
                  ; since we are testing...
          ][
            false ; don't overwrite !
          ]
        ][
          either value? word [
            ; warning handled in self/setup below
            false ; means: don't clobber others words or builtins ...
          ][
            insert tail self/words word
            true
          ]
        ]
      ] ; register [function!]
      setup: func ["register global words"
        words_to_register [block!] /local forbidden_words [block!]
      ][
        forbidden_words: copy []
        foreach word words_to_register [
          if not self/register :word [
            insert forbidden_words word
          ]
        ]
        if not empty? forbidden_words [
          print ["Warning: some words are already defined,"
            "but not registered:" mold forbidden_words
          ]
          if confirm "Abort execution? " [
            print "Execution aborted."
            halt
          ]
        ]
      ] ; setup [function!]
    ] ; registry [object!]
  ] ; use
]

; [registry setup]----------------------------------------------------------
;
; Purpose: registers global words
;
use [words_to_register] [
  words_to_register: [
    composite range map mapper filter-diff filter list-dirs bench
    copy-func ++ -- inc round printf
  ]
  if not value? 'unset! [
    insert registry/words 'unset!
    unset!: (type?)
  ]
  registry/setup words_to_register
]

; [global funcs]------------------------------------------------------------
;
; Purpose: some utilities ...
;
composite: func ["f(g(x))" :f "func f [x] [...]" :g "func g [x] [...]"] [
  func [x] compose [(:f) (:g) :x]
]

range: func ["[start .. end]"
  start [number!] end [number!] /local result [block!]
][
  result: make block! (end - start + 1)
  either start < end [
    for i end (start - 1) -1 [ ; strange: "for i start end 1" is equivalent
      insert result i
    ]
  ][
    for i end (start + 1) 1 [
      insert result i
    ]
  ]
]

map: func ["maps a function to a block"
  :f [any-function!] block [block!] /local result [block!]
][
  result: make block! (length? block)
  foreach element block [
    insert/only tail result f element
  ]
  head result
]

; Example:
; print mold map odd? range 1 20

mapper: func ["map function"
  f [any-function! paren! any-word!]
][
  func [block [block!] /local result [block!]] compose/deep [
    result: make block! length? block
    foreach element block [
      insert/only tail result (:f) element
    ]
    head result
  ]
]

; Example:
; map-odd?: mapper 'odd?
; print mold map-odd? range 1 20

; faster than 'filter && 'difference/only (especially for large blocks)
filter-diff: func ["filter function - returns [[... filtered ...] [...
unfiltered ...]]"
  :f [any-function!] block [block!] /local result [block!] diff [block!]] [
  result: copy []
  diff:   copy []
  foreach element block [
    either f element [
      insert/only tail result element
    ][
      insert/only tail diff   element
    ]
  ]
  reduce [result diff]
]

filter: func ["filter function"
  :f [any-function!] block [block!] /local result [block!]
][
  result: copy []
  foreach element block [
    if f element [
      insert/only tail result element
    ]
  ]
  result
]

; adapted from a code snippet
; see "[REBOL] file list" (03-Dec-1999)
; author: Thomas Johnson <[EMAIL PROTECTED]>
list-dirs: func ["directory listing - subdirs included"
  dir [file!] /filtered :filter-func [any-function!]
  /local indent [string!] result [block!] _list-dirs [function!]
][
  indent: copy ""
  result: copy []
  _list-dirs: func [dir [file!] /local files [block!]] [
    files: filter-diff dir? sort read dir ; [[dirs] [files]]
    foreach subdir first files [
      insert tail result rejoin [indent subdir newline]
      insert indent tab
      _list-dirs dir/:subdir
      remove indent
    ]
    either filtered [
      files: filter filter-func second files
    ][
      files: second files
    ]
    foreach file files [
      insert tail result rejoin [indent file newline]
    ]
    result
  ]
  _list-dirs dir
]

comment {
  Examples:
  print rejoin list-dirs %./
  filter-func: func [file] [found? find file ".r"]
  print rejoin list-dirs/filtered %./ filter-func
}

bench: func ["wants to be a benchmark func"
  block [block!] loops [integer!] /verbose [logic!] /local t [time!]
][
  t: now/time
  loop loops [
    if verbose [prin #"-"] ; this hurts...
    do block               ; this too
  ]
  if verbose [prin newline]
  now/time - t
]

copy-func: func ["copies a function" :f [any-function!]] [
  make function! first :f second :f
]

; I'm a C++ fan, after all...
; (just kidding)
++: func ['x] [
  set x (get x) + 1
]

--: func ['x] [
  set x (get x) - 1
]

inc: func ['x y] [
  set x (get x) + y
]

round: func [n [number!]] [
  to-integer n + pick [-.5 .5] negative? n
]

; from Gabriele Santilli <[EMAIL PROTECTED]>
printf: func ["format function"
  number "thing to format"
  numdigits [integer! unset!] fillchar [char! string! unset!]
][
  if not value? 'numdigits [
    numdigits: 6
  ]
  if not value? 'fillchar [
    fillchar: #" "
  ]
  skip
    insert
      insert/dup
        make string! numdigits
        fillchar
        numdigits
      number
    negate numdigits
]

comment {
  *wow*
  Examples:
  >> printf 3000
  == "  3000"
  >> printf 3000 6 "0"
  == "003000"
  >> printf "3000" 6 "-"
  == "--3000"
  >> printf "this works" 5
  == "works"
}




Reply via email to