On Jan 19, 2011, at 17:47 , Konovalov, Vadim (Vadim)** CTR ** wrote:
> First, I did not liked the name bind_... either.
> create_commands obviously better.
> (or maybe create_tcl_commands?)
>
> However I think the idea could be extended to variables as well, how do
> you think, is it possible to leave this name but add functionality to
> variables also?
Perhaps?
$interp->export_to_tcl(
namespace => "perl",
subs => { ... },
vars => { ... },
subs_from => $ns,
vars_from => $ns,
);
I think you should say it explicitly if you want to export vars from a
namespace as well. You might for instance have some vars in that namespace
that is shared between the perl subs without the intention to access it from
Tcl.
> And having default namespace to be 'perl' also seems reasonable to me.
Fine with me as long as it's possible to pass "" or "::" to signal the root
namespace.
> Please see below the code I suggest, it is not finished, but all ideas are
> expressed.
>
> Opinions welcome.
>
> Best regards,
> Vadim.
>
>
> =comment
> An interpreter method, bind_perl_to_tcl_commands, takes two optional
> arguments - tcl package name (defaults to 'tcl') and perl package name
> (defaults to 'tcl')
>
> Given a number of Perl sub's in said package, which is passed as the
> second parameter, binds all of them into tcl, in the said package, which
> is passed as the first parameter to the bind_perl_to_tcl_commands method.
>
> An example:
>
> use strict;
> use Tcl;
>
> my $int = new Tcl;
>
> $tcl::foo = 'qwerty';
> $int->create_tcl_commands(subs_from=>'tcl');
>
> $int->Eval(<<'EOS');
>
> package require Tk
>
> button .b1 -text {a fluffy button} -command perl::fluffy_sub
> button .b2 -text {a foo button} -command perl::foo
> entry .e -textvariable perl::foo
> pack .b1 .b2 .e
> focus .b2
>
> tkwait window .
> EOS
>
> sub tcl::fluffy_sub {
> print "Hi, I am a fluffy sub\n";
> }
> sub tcl::foo {
> print "Hi, I am foo\n";
> $tcl::foo++;
> }
> =cut
>
> sub create_tcl_commands {
> my $int = shift;
> my %args = @_;
>
> # name of Tcl package to hold tcl commands bound to perl subroutines
> my $tcl_namespace = $args{namespace} || 'perl';
>
> # a batch of perl subroutines which tcl counterparts should be created
> my $subs = $args{subs} || {};
>
> # name of Perl package, which subroutines would be bound to tcl commands
> my $subs_from = $args{subs_from};
>
> if ($subs_from) {
> for my $name (keys %{"$subs_from\::"}) {
> print STDERR "$name;\n";
> if (defined &{"$subs_from\::$name"}) {
> if (exists $sub->{$name}) {
> next;
> }
> # print STDERR "binding sub '$name'\n";
>
> $int->CreateCommand("$tcl_namespace\::$name",\&{"$subs_from\::$name"});
Call CreateCommand($tclname, \&sub, undef, undef, 1) to get avoid getting
passed (undef, $int, $name) as the first 3 arguments to the callback.
> }
> if (defined ${"$subs_from\::$name"}) {
> # print STDERR "binding var '$name'\n";
> local $_ = ${"$subs_from\::$name"};
> tie ${"$subs_from\::$name"}, 'Tcl::Var', $int,
> "$tcl_namespace\::$name";
> ${"$subs_from\::$name"} = $_;
> }
> {
> # array, hash - no need to.
> }
> }
> }
>
> for my $subname (keys %$subs) {
> $int->CreateCommand("$tcl_namespace\::$subname",$subs{$subname});
> }
> }
--Gisle
>
>
>
>> -----Original Message-----
>> From: Gisle Aas [mailto:[email protected]]
>> Sent: Tuesday, January 18, 2011 10:08 PM
>> To: Konovalov, Vadim (Vadim)** CTR **
>> Cc: Jeff Hobbs; [email protected]
>> Subject: Re: bind some said tcl to perl - all at once
>>
>> I don't like to use the name 'bind_...' for this. To me it
>> sounds like this would bind the namespace together so that
>> subs created after the call also become visible to Tcl and
>> perhaps even that commands created on the Tcl side become
>> visible to Perl.
>>
>> My suggestion would be to make a convenience method like this one:
>>
>> $interp->create_commands(
>> namespace => "perl",
>> subs => {
>> foo => sub { .... },
>> bar => sub { .... },
>> }
>> );
>>
>> where the "namespace" argument is optional. It's the Tcl
>> namespace where the commands will be created. If not provided
>> the names will be registered in the root namespace. This
>> would also always call the underlying $interp->CreateCommand
>> with FLAGS=1 in order to suppress the confusing initial
>> legacy arguments. The keys of the subs hash could also use
>> "::ns::foo" style names in which case the namespace argument
>> is ignored for that particular key.
>>
>> Your use case would then be covered by:
>>
>> $interp->create_commands(
>> namespace => "perl",
>> subs => \%{"tcl\::"},
>> );
>>
>> which is a bit ugly to write so you might be able to provide
>> some sugar like:
>>
>> $interp->create_commands(
>> namespace => "perl",
>> subs_from => "tcl",
>> );
>>
>> if 'subs' and 'subs_from' are provided together they both
>> contribute; with 'subs' taking preference in case there are
>> conflicting names. Alternatively croak on conflicting names.
>>
>> I would also suggest a 'only => \@list_of_names' argument to
>> be able to limit the names to export to Tcl.
>>
>> Regards,
>> Gisle
>>
>>
>>
>> On Jan 18, 2011, at 17:20 , Konovalov, Vadim (Vadim)** CTR ** wrote:
>>
>>>> From: Jeff Hobbs [mailto:[email protected]]
>>>> On 15/01/2011 1:35 PM, Konovalov, Vadim (Vadim)** CTR ** wrote:
>>>>> I wonder, is it reasonable for this approach to be
>>>> "standartized" and included to, say, Tcl.pm module?
>>>>>
>>>>> For example - all Tcl names from some predefined Tcl
>>>> namespace could be bound to perl subroutines all at once.
>>>>
>>>> I think it would be good to provide this as a standard convenience
>>>> function, that would tie either a Perl or Tcl namespace to
>> the other
>>>> language. I don't think we'd want to pre-define the
>> namespace (note
>>>> that Tcl.pm already uses ::perl:: on the Tcl side), but
>> let the user
>>>> pick it with a single command invocation.
>>>
>>> Indeed, Tcl.pm uses ::perl:: in Tcl::call.
>>>
>>> All refs in this namespace have names like
>> "SCALAR(0xXXXXXX)" or "CODE(0x######)", and it is very
>> unlikely to have a collision. IOW, the collision could happen
>> if a user have an intention to create a collision, but he/she
>> could just create such a collision anyway, by creating
>> conflicting names using another existing mechanisms.
>>>
>>> Ok, below is my suggestion to include to Tcl.pm,
>>>
>>>
>>> =comment
>>> An interpreter method, bind_perl_to_tcl_commands, takes two optional
>>> arguments - tcl package name (defaults to 'tcl' and perl
>> package name
>>> (defaults to 'tcl')
>>>
>>> Given a number of Perl sub's in said package, which is passed as the
>>> second parameter, binds all of them into tcl, in the said
>> package, which
>>> is passed as the first parameter to the
>> bind_perl_to_tcl_commands method.
>>>
>>> An example:
>>>
>>> use Tcl;
>>>
>>> my $int = new Tcl;
>>>
>>> $int->bind_perl_to_tcl_commands;
>>>
>>> $int->Eval(<<'EOS');
>>>
>>> package require Tk
>>>
>>> button .b1 -text {a fluffy button} -command perl::fluffy_sub
>>> button .b2 -text {a foo button} -command perl::foo
>>> pack .b1 .b2
>>>
>>> tkwait window .
>>> EOS
>>>
>>> sub tcl::fluffy_sub {
>>> print "Hi, I am a fluffy sub\n";
>>> }
>>> sub tcl::foo {
>>> print "Hi, I am foo\n";
>>> }
>>>
>>> =cut
>>>
>>> sub bind_perl_to_tcl_commands {
>>> my $int = shift;
>>>
>>> # name of Tcl package to hold tcl commands bound to perl
>> subroutines
>>> my $tcl_namespace = shift || 'perl';
>>>
>>> # name of Perl package, which subroutines would be bound
>> to tcl commands
>>> my $perl_namespace = shift || 'tcl';
>>>
>>> die "Shouldn't bind to main package"
>>> if $perl_namespace eq "" || $perl_namespace eq "main";
>>>
>>> for my $subname (keys %{"$perl_namespace\::"}) {
>>> # have no need to check if this is a sub name or a var
>> name, as long
>>> # as we're binding to CODE, \&{"..."}
>>>
>> $int->CreateCommand("$tcl_namespace\::$subname",\&{"$perl_name
>> space\::$subname"});
>>> }
>>> }
>>>
>>>
>>> Similar binding of variables could also be added.
>>>
>>> Best regards,
>>> Vadim.
>>
>>