REBOL layout: How to create layout words automatic

2019-06-17 18:34发布

问题:

Using the REBOL/View 2.7.8 Core, I would like to prepare a view layout beforehand by automatically assigning words to various layout items, as in the following example. Instead of

prepared-view: [across 
                cb1: check 
                label "Checkbox 1"
                cb2: check
                label "Checkbox 2"
                cb3: check
                label "Checkbox 3"
                cb4: check
                label "Checkbox 4"
                ]
    view layout prepared-view

I would thus like the words cb1 thru cb5 to be created automatically, e.g.:

prepared-view2: [ across ]
    for i 1 4 1 [
        cbi: join "cb" i
        cbi: join cbi ":"
        cbi: join cbi " check"
        append prepared-view2 to-block cbi
        append prepared-view2 [
        label ]
        append prepared-view2 to-string join "Checkbox " i 
        ]
    view layout prepared-view2

However, while difference prepared-view prepared-view2 shows no differences in the block being parsed (== []), the second script leads to an error:

    ** Script Error: cb1 word has no context
    ** Where: forever
    ** Near: new/var: bind to-word :var :var

I've spent hours trying to understand why, and I think somehow the new words need to be bound to the specific context, but I have not yet found any solution to the problem.

What do I need to do?

回答1:

bind prepared-view2 'view  
view layout prepared-view2

creates the correct bindings.

And here's another way to dynamically create layouts

>> l: [ across ]
== [across]
>> append l to-set-word 'check
== [across check:]
>> append l 'check
== [across check: check]
>> append l "test"
== [across check: check "test"]
>> view layout l

And then you can use loops to create different variables to add to your layout.



回答2:

When you use TO-BLOCK to convert a string to a block, that's a low-level operation that doesn't go through the "ordinary" binding to "default" contexts. All words will be unbound:

>> x: 10      
== 10

>> code: to-block "print [x]"
== [print [x]]

>> do code
** Script Error: print word has no context
** Where: halt-view
** Near: print [x]

So when you want to build code from raw strings at runtime whose lookups will work, one option is to use LOAD and it will do something default-ish, and that might work for some code (the loader is how the bindings were made for the code you're running that came from source):

>> x: 10
== 10

>> code: load "print [x]"
== [print [x]]

>> do code
10

Or you can name the contexts/objects explicitly (or by way of an exemplar word bound into that context) and use BIND.