As this originally was Refinements, it needed some fiddling:

; method creator
meth: func [
    {defines a user method with given spec and body}
    spec [block!]
    body [block!]
] [
    ; use copies of the original spec and body blocks
    spec: copy spec
    body: copy/deep body
    ; find the right place to insert the Self specification
    while [
        all [
            not tail? spec
            any [string? first spec block? first spec]
        ]
    ] [spec: next spec]
    ; insert the Self specification
    insert spec copy/deep [self [object!]]
    func head spec compose/deep [
        do bind/copy [(body)] in self 'self
    ]
]

; method calling dialect:

!: func [
    {method caller}
    [catch]
    message [block!] {
        The structure of a message is as follows:

        method-path
        object
        additional arguments according to the method spec
    }
    /local method-path method-name self position cls
] [
    if not (length? message) > 1 [
        throw make error! {invalid message}
    ]
    if not any [
        word? set/any 'method-path first message
        path? get/any 'method-path
    ] [
        throw make error!
            {invalid method - must be a word or a path}
    ]
    if not path? :method-path [
        method-path: to path! method-path
    ]
    method-name: first :method-path
    position: next message
    set/any [self position] do/next position
    if not object? get/any 'self [
        throw make error! {self is not an object}
    ]
    if not cls: in self 'class [
        throw make error! {incompatible object}
    ]
    if not object? set/any 'cls get/any get cls [
        throw make error! {incompatible class}
    ]
    if not method-name: in cls method-name [
        throw make error! {no such method}
    ]
    change :method-path method-name
    do compose [(:method-path) (self) (position)]
]

; sample class, feel free to change it as you please:

sample-class: make object! [
    ; a method returning the object type
    type: meth [] [
        class
    ]
    ; a static value - counter
    counter: 0
    ; a counting method
    count: meth [] [
        counter: counter + 1
    ]
    reftest: meth [/ref] [
        either ref [
            print "Ref"
        ] [
            print "No ref"
       ]
    ]
]

; sample objects of a sample-class

sample-object1: make object! [
    class: 'sample-class
    number: ! [count self]
]

sample-object2: make sample-object [
    number: ! [count self]
]

; sample method calls
! [type sample-object1]
! [type sample-object2]
! [nonsense sample-object1]
! [reftest sample-object2]
! [reftest/ref sample-object2]


Reply via email to