Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interleave blocks, or make object out of two blocks (field names and values)

Instead of creating objects by writing:

obj: object [
    name: "Fork"
    id: 1020
]

I'd like to write something like...

obj: something-or-another [name id] ["Fork" 1020]

...and get the same result. An ideal solution would also permit:

obj: something-or-another [name: id:] ["Fork" 1020]

Easy enough to write a something-or-another, but does this fit something already "in the box"?

like image 916
HostileFork says dont trust SE Avatar asked Aug 21 '13 02:08

HostileFork says dont trust SE


3 Answers

I don't believe there's a baked-in way to do this. Not difficult though:

func [words values][
    set words: context append map-each word words [to set-word! word] none values
    words
]

I suppose I could break this down a little:

func [
    "Creates an Object From a Block of Words, Assigns Values"
    words [block!] "Words used to create object"
    values "Value(s) to assign"
][
    words: map-each word words [to set-word! word] ; The requisite set-words
    append words none ; Initial value for all words
    words: context words ; Create our object
    set words values ; Assigns our value(s) to the object
    words ; returns the object
]

You might employ a different method to interleave blocks, such as:

func [words [block!] values [block!]][
    collect [
        repeat index max length? words length? values [
            keep words/:index
            keep values/:index
        ]
    ]
]
like image 180
rgchris Avatar answered Nov 08 '22 22:11

rgchris


Here's something that requires at least Rebol 3:

func [
    "Create an object based on some words and values."
    words [any-word! block!] "Word or block of words"
    values [any-type!] "Value or block of values"
    /local object
][
    object: make object! either block? words [length? words] [1]
    set bind/copy/new :words object :values
    object
]

If you want to also allow setting unset values, try this:

func [
    "Create an object based on some words and values."
    words [any-word! block!] "Word or block of words"
    values [any-type!] "Value or block of values"
    /any "Allows setting words to any value, including unset"
    /local object
][
    object: make object! either block? words [length? words] [1]
    apply :set [bind/copy/new :words object :values any]
    object
]

Both of these create objects with self, so if you want to create an object without self you have to do some fancier tricks. See the selfless proposal for details.

like image 24
BrianH Avatar answered Nov 09 '22 00:11

BrianH


I wrote a similar function (Rebol2) just a few days ago:

build-object: func [
    "Builds an object from a block"
    names [block!] "Field names"
    /values val [block!] "Initial values"
    /local o name value
] [
    o: copy []
    names: compose names
    o: either values [
        parse names [
            some [
                set name [word! | set-word!]
                (append o to-set-word name)
                | skip
            ]
        ]
        set/pad reflect o: context append o none 'words val
        o
    ] [
        if any [
            parse names [
                some [
                    set name [word! | set-word!]
                    (append o reduce [to-set-word name none])
                ]
            ]
            parse names [
                (clear o) some [
                    set name [word! | set-word!] set value any-type!
                    (append o reduce [to-set-word name :value])
                ]
            ]
        ] [context o]
    ]
    o
]

To build your object you could write any of: (create a function as f: does ["x"])

  • build-object [name "Fork" id 1020]
  • build-object [name: "Fork" id: 1020]
  • build-object/values [name id] ["Fork" 1020]
  • build-object/values [name: id:] ["Fork" 1020]
  • build-object [name f]
  • build-object [name (f)] ;block is composed
  • build-object [name 5 id f]
  • build-object [name 5 id 'f]

You can also make objects with fields set to none if you leave the values out, e.g. with

build-object [name id]
like image 42
endo64 Avatar answered Nov 09 '22 00:11

endo64