Thread: [Perl-widget-developer] Widget.pm design
Status: Alpha
Brought to you by:
spadkins
From: James G S. <JG...@TA...> - 2001-06-05 04:11:58
|
I'm looking through the code a bit closer finally. I had some thoughts and a diff showing some of the code that comes out of them - plus a few things that might make the code a but more readable (it is fairly readable already, but I had to stop and think through one or two things once in a while). Instead of Widget::HTML::Element, I think I'd prefer to see Widget::Element::HTML. We could think of `Element' as the widget archetype. Pro: (1) Easier widget creation. Instead of having to supply the full class name when using the create method, you can pass the type of element and the create method can build the class name. (2) Easier packaging and distribution of third-party widgets. (3) (1) makes creating aggregate archetypes easier. (4) Consolidation of logic. Con: (1) HTML widgets are spread out, as are XML widgets and WML widgets. No longer are all the widgets for a particular output environment in one namespace. Note (4) above needs some more commentary. If we have Widget::Base as the base object for Widgets, then we can have Widget::Base::HTML as the base for the HTML specialization of Widgets. It could contain the html encoding/ decoding code and other HTML specific functions. Widget::Element is a Widget::Base while Widget::Element::HTML is a Widget::Element and Widget::Base::HTML. Widget::Element has all the processing logic for the widget while the tertiary modules (::HTML, ::WML, etc.) contain the output logic. There might also be good reason for moving the create method to the controller object. It knows more about the environment than Widget does and can create the correct widgets given the archetype requested. See the diff for one possible solution to the problem of a non-existant class. -- James Smith <JG...@TA...>, 979-862-3725 Texas A&M CIS Operating Systems Group, Unix *** Widget.pm.dist Mon Jun 4 22:11:23 2001 --- Widget.pm Mon Jun 4 22:23:28 2001 *************** *** 69,75 **** my $self = shift; my ($args); ! if ($#_ == -1) { $args = {}; } elsif (ref($_[0]) eq "HASH") { --- 69,75 ---- my $self = shift; my ($args); ! if (!@_) { $args = {}; } elsif (ref($_[0]) eq "HASH") { *************** *** 129,139 **** return $self->create($args->{controller}, $args); } sub create { my $self = shift; my $class = shift; # TODO: what should I really do here if the class does not exist? ! return undef if (!Widget->use($class)); return $class->new(@_); } --- 129,148 ---- return $self->create($args->{controller}, $args); } + # Question: Does the create function belong in the controller? + # Re: The controller knows what kind of widgets are needed (HTML, + # XML,Gtk+, etc.) sub create { my $self = shift; my $class = shift; # TODO: what should I really do here if the class does not exist? ! if(!Widget -> use($class)) { ! # TODO: figure out how we want to sub-class Widget::$class... ! # This does assume Widget::Thingy::HTML instead of ! # Widget::HTML::Thingy. ! $class = join("::", "Widget", $class); ! return undef unless Widget -> use($class); ! } return $class->new(@_); } *************** *** 149,156 **** $file = $class; $file =~ s#::#/#g; $file .= ".pm"; ! require $file; ! $ok = 0 if (! defined $INC{$file}); } $ok; } --- 158,164 ---- $file = $class; $file =~ s#::#/#g; $file .= ".pm"; ! $ok = 0 unless require $file; } $ok; } *************** *** 185,191 **** print STDERR "Widget->html() $item => ref=[$ref]\n" if ($Widget::DEBUG); next if ($ref eq "CODE" || $ref eq "GLOB"); # TODO: are there others? ! if ($ref eq "" || $ref eq "SCALAR") { # TODO: find out what other transforms are in the standard $elem = $item; # borrowed from CGI::Util::simple_escape() ... --- 193,199 ---- print STDERR "Widget->html() $item => ref=[$ref]\n" if ($Widget::DEBUG); next if ($ref eq "CODE" || $ref eq "GLOB"); # TODO: are there others? ! if (!$ref || $ref eq "SCALAR") { # TODO: find out what other transforms are in the standard $elem = $item; # borrowed from CGI::Util::simple_escape() ... |
From: Jay L. <Ja...@La...> - 2001-06-05 14:06:07
|
I see this the same way as James - put your generic logic in the parent class and then interface-specific logic in subclasses: Widget::Element.pm -> generic logic Widget::Element::HTML.pm -> HTML-specific When we make widgets I'd expect that Widget::Element ISA Widget::Base and Widget::Element::HTML ISA (Widget::Base::HTML, Widget::Element) Then if the app is in HTML it would make a new Element widget via: $element=Widget::Element::HTML->new( { params } ) OR we could make constructor take a hint as to which context the widget is to be used and return that object type: # pseudocode: Widget::Base sub new { # constructor logic goes here # $class will be "Widget::Element" at this point if ($widget->container->type eq "HTML") { bless $widget, "$class::HTML"; } OR if ($widget->type eq "HTML") { bless $widget, "$class::HTML"; } OR bless $widget, $class."::".$widget->type; } I personally don't advocate putting constructor into controller - instead have the contructor check with the controller. That is the one crucial link that will supply us all of the environmental details needed. J > I'm looking through the code a bit closer finally. I had some > thoughts and a diff showing some of the code that comes out of > them - plus a few things that might make the code a but more > readable (it is fairly readable already, but I had to stop and > think through one or two things once in a while). > > Instead of Widget::HTML::Element, I think I'd prefer to see > Widget::Element::HTML. We could think of `Element' as the widget > archetype. > > Pro: > (1) Easier widget creation. Instead of having to supply the > full class name when using the create method, you can pass the > type of element and the create method can build the class name. > (2) Easier packaging and distribution of third-party widgets. > (3) (1) makes creating aggregate archetypes easier. > (4) Consolidation of logic. > > Con: > (1) HTML widgets are spread out, as are XML widgets and WML > widgets. No longer are all the widgets for a particular output > environment in one namespace. > > Note (4) above needs some more commentary. > > If we have Widget::Base as the base object for Widgets, then we > can have Widget::Base::HTML as the base for the HTML > specialization of Widgets. It could contain the html encoding/ > decoding code and other HTML specific functions. > > Widget::Element is a Widget::Base while > Widget::Element::HTML is a Widget::Element and Widget::Base::HTML. > > Widget::Element has all the processing logic for the widget while > the tertiary modules (::HTML, ::WML, etc.) contain the output > logic. > > > There might also be good reason for moving the create method to > the controller object. It knows more about the environment than > Widget does and can create the correct widgets given the > archetype requested. See the diff for one possible solution to > the problem of a non-existant class. > -- > James Smith <JG...@TA...>, 979-862-3725 > Texas A&M CIS Operating Systems Group, Unix > > *** Widget.pm.dist Mon Jun 4 22:11:23 2001 > --- Widget.pm Mon Jun 4 22:23:28 2001 > *************** > *** 69,75 **** > my $self = shift; > > my ($args); > ! if ($#_ == -1) { > $args = {}; > } > elsif (ref($_[0]) eq "HASH") { > --- 69,75 ---- > my $self = shift; > > my ($args); > ! if (!@_) { > $args = {}; > } > elsif (ref($_[0]) eq "HASH") { > *************** > *** 129,139 **** > return $self->create($args->{controller}, $args); > } > > sub create { > my $self = shift; > my $class = shift; > # TODO: what should I really do here if the class does not exist? > ! return undef if (!Widget->use($class)); > return $class->new(@_); > } > > --- 129,148 ---- > return $self->create($args->{controller}, $args); > } > > + # Question: Does the create function belong in the controller? > + # Re: The controller knows what kind of widgets are needed (HTML, > + # XML,Gtk+, etc.) > sub create { > my $self = shift; > my $class = shift; > # TODO: what should I really do here if the class does not exist? > ! if(!Widget -> use($class)) { > ! # TODO: figure out how we want to sub-class Widget::$class... > ! # This does assume Widget::Thingy::HTML instead of > ! # Widget::HTML::Thingy. > ! $class = join("::", "Widget", $class); > ! return undef unless Widget -> use($class); > ! } > return $class->new(@_); > } > > *************** > *** 149,156 **** > $file = $class; > $file =~ s#::#/#g; > $file .= ".pm"; > ! require $file; > ! $ok = 0 if (! defined $INC{$file}); > } > $ok; > } > --- 158,164 ---- > $file = $class; > $file =~ s#::#/#g; > $file .= ".pm"; > ! $ok = 0 unless require $file; > } > $ok; > } > *************** > *** 185,191 **** > print STDERR "Widget->html() $item => ref=[$ref]\n" if ($Widget::DEBUG); > next if ($ref eq "CODE" || $ref eq "GLOB"); # TODO: are there others? > > ! if ($ref eq "" || $ref eq "SCALAR") { > # TODO: find out what other transforms are in the standard > $elem = $item; > # borrowed from CGI::Util::simple_escape() ... > --- 193,199 ---- > print STDERR "Widget->html() $item => ref=[$ref]\n" if ($Widget::DEBUG); > next if ($ref eq "CODE" || $ref eq "GLOB"); # TODO: are there others? > > ! if (!$ref || $ref eq "SCALAR") { > # TODO: find out what other transforms are in the standard > $elem = $item; > # borrowed from CGI::Util::simple_escape() ... > > _______________________________________________ > Perl-widget-developer mailing list > Per...@li... > http://lists.sourceforge.net/lists/listinfo/perl-widget-developer > |
From: Jay L. <Ja...@La...> - 2001-06-05 14:22:03
|
Hey all, I was looking at the code and noticed one thing that will severely limit our implementation flexibility. It has to do with how properties are accessed in a non-abstracted fashion. When an widget is created (Widget::Base::new) you pass your properties which then get stuffed in the object hash for later use. OK - so you're storing properties like $widget->{'name'} = "button1". (Oh, BTW, shouldn't you enclose hash keys in quotes? I know it generally works but it generates warnings). And you're obtaining it same way ie: print "My name is ".$self->{'name'}; However, if you choose to have a different storage mechanism OR want to get fancy with how properties are resolved you need to use accessor methods. ie/ print "My name is ".$self->name; This way you hide the implementation of the widget (abstraction) from the calling routine. You actually need to use this strategy everywhere. There are a number of ways to handle this: AUTOLOAD - resolve name of method to a property or raise error manual accessor contruction - lots 'n lots of subs automated accessor construction - 1/2 doz packages in CPAN that do the job I know there will be arguments of efficiency vs. flexibility but I do recall Stephen saying that at this stage we'll be thinking more on flexibility than efficiency. But down the road we might be able to trade the expense of a function call with a more efficient storage mechanism like pseudohashs. Jay |
From: Stephen A. <ste...@of...> - 2001-06-05 19:00:16
|
Hi, Yes, we absolutely need accessors. I recommend an AUTOLOAD method implemented on Widget::Base to create accessors automatically (for now, anyway). However, there are two schools of thought on use of accessors vs. accessing the attributes directly. 1. use accessors everywhere, even inside the class 2. use accessors outside the class, access the attribute directly from within the class I prefer #2 for performance. Some people argue #1 so that subclasses are resilient to change in the superclass. I think we just don't have a complex enough code base to make #1 critical. It won't be look before we finalize how to access attributes internally. Then it should be stable. Stephen At 10:22 AM 6/5/2001 -0400, Jay Lawrence wrote: >Hey all, > >I was looking at the code and noticed one thing that will severely limit our >implementation flexibility. It has to do with how properties are accessed in >a non-abstracted fashion. > >When an widget is created (Widget::Base::new) you pass your properties which >then get stuffed in the object hash for later use. > >OK - so you're storing properties like $widget->{'name'} = "button1". (Oh, >BTW, shouldn't you enclose hash keys in quotes? I know it generally works >but it generates warnings). > >And you're obtaining it same way ie: > print "My name is ".$self->{'name'}; > >However, if you choose to have a different storage mechanism OR want to get >fancy with how properties are resolved you need to use accessor methods. ie/ > print "My name is ".$self->name; > >This way you hide the implementation of the widget (abstraction) from the >calling routine. You actually need to use this strategy everywhere. > >There are a number of ways to handle this: > AUTOLOAD - resolve name of method to a property or raise error > manual accessor contruction - lots 'n lots of subs > automated accessor construction - 1/2 doz packages in CPAN that do the >job > >I know there will be arguments of efficiency vs. flexibility but I do recall >Stephen saying that at this stage we'll be thinking more on flexibility than >efficiency. But down the road we might be able to trade the expense of a >function call with a more efficient storage mechanism like pseudohashs. > >Jay > > > >_______________________________________________ >Perl-widget-developer mailing list >Per...@li... >http://lists.sourceforge.net/lists/listinfo/perl-widget-developer > |
From: Gunther B. <gu...@ex...> - 2001-06-05 16:00:02
|
I disagree in general with this. Having coded a lot of WML and HTML myself for a local mobile company, I can say pretty strongly that I do not believe in a 1-1 mapping between elements in WML and HTML except in a very loose sense. You really have to code the whole template very separately for WML vs HTML and the choice you make (eg textfield vs textarea) is very different on WML vs HTML. So you would not want some generic Widget::TextField that rents a WML version for WML and HTML for HTML. It's quite possible that on web you may want to allow the user to type in a lot of info in textarea but on wap, you just restrict it a bit more. I think for most programmers, it will be easier to see HTML widgets and then dive in there and then plainttext widgets and WAP widgets etc as a substructure and then see when they are coding an HTML form what elements are available to them when they are doing so. Later, Gunther At 10:41 PM 6/4/01 -0500, James G Smith wrote: >I'm looking through the code a bit closer finally. I had some >thoughts and a diff showing some of the code that comes out of >them - plus a few things that might make the code a but more >readable (it is fairly readable already, but I had to stop and >think through one or two things once in a while). > >Instead of Widget::HTML::Element, I think I'd prefer to see >Widget::Element::HTML. We could think of `Element' as the widget >archetype. > >Pro: > (1) Easier widget creation. Instead of having to supply the >full class name when using the create method, you can pass the >type of element and the create method can build the class name. > (2) Easier packaging and distribution of third-party widgets. > (3) (1) makes creating aggregate archetypes easier. > (4) Consolidation of logic. > >Con: > (1) HTML widgets are spread out, as are XML widgets and WML >widgets. No longer are all the widgets for a particular output >environment in one namespace. > >Note (4) above needs some more commentary. > >If we have Widget::Base as the base object for Widgets, then we >can have Widget::Base::HTML as the base for the HTML >specialization of Widgets. It could contain the html encoding/ >decoding code and other HTML specific functions. > >Widget::Element is a Widget::Base while >Widget::Element::HTML is a Widget::Element and Widget::Base::HTML. > >Widget::Element has all the processing logic for the widget while >the tertiary modules (::HTML, ::WML, etc.) contain the output >logic. > > >There might also be good reason for moving the create method to >the controller object. It knows more about the environment than >Widget does and can create the correct widgets given the >archetype requested. See the diff for one possible solution to >the problem of a non-existant class. >-- >James Smith <JG...@TA...>, 979-862-3725 >Texas A&M CIS Operating Systems Group, Unix > >*** Widget.pm.dist Mon Jun 4 22:11:23 2001 >--- Widget.pm Mon Jun 4 22:23:28 2001 >*************** >*** 69,75 **** > my $self = shift; > > my ($args); >! if ($#_ == -1) { > $args = {}; > } > elsif (ref($_[0]) eq "HASH") { >--- 69,75 ---- > my $self = shift; > > my ($args); >! if (!@_) { > $args = {}; > } > elsif (ref($_[0]) eq "HASH") { >*************** >*** 129,139 **** > return $self->create($args->{controller}, $args); > } > > sub create { > my $self = shift; > my $class = shift; > # TODO: what should I really do here if the class does not exist? >! return undef if (!Widget->use($class)); > return $class->new(@_); > } > >--- 129,148 ---- > return $self->create($args->{controller}, $args); > } > >+ # Question: Does the create function belong in the controller? >+ # Re: The controller knows what kind of widgets are needed (HTML, >+ # XML,Gtk+, etc.) > sub create { > my $self = shift; > my $class = shift; > # TODO: what should I really do here if the class does not exist? >! if(!Widget -> use($class)) { >! # TODO: figure out how we want to sub-class Widget::$class... >! # This does assume Widget::Thingy::HTML instead of >! # Widget::HTML::Thingy. >! $class = join("::", "Widget", $class); >! return undef unless Widget -> use($class); >! } > return $class->new(@_); > } > >*************** >*** 149,156 **** > $file = $class; > $file =~ s#::#/#g; > $file .= ".pm"; >! require $file; >! $ok = 0 if (! defined $INC{$file}); > } > $ok; > } >--- 158,164 ---- > $file = $class; > $file =~ s#::#/#g; > $file .= ".pm"; >! $ok = 0 unless require $file; > } > $ok; > } >*************** >*** 185,191 **** > print STDERR "Widget->html() $item => ref=[$ref]\n" if > ($Widget::DEBUG); > next if ($ref eq "CODE" || $ref eq "GLOB"); # TODO: are there > others? > >! if ($ref eq "" || $ref eq "SCALAR") { > # TODO: find out what other transforms are in the standard > $elem = $item; > # borrowed from CGI::Util::simple_escape() ... >--- 193,199 ---- > print STDERR "Widget->html() $item => ref=[$ref]\n" if > ($Widget::DEBUG); > next if ($ref eq "CODE" || $ref eq "GLOB"); # TODO: are there > others? > >! if (!$ref || $ref eq "SCALAR") { > # TODO: find out what other transforms are in the standard > $elem = $item; > # borrowed from CGI::Util::simple_escape() ... > >_______________________________________________ >Perl-widget-developer mailing list >Per...@li... >http://lists.sourceforge.net/lists/listinfo/perl-widget-developer __________________________________________________ Gunther Birznieks (gun...@eX...) eXtropia - The Open Web Technology Company http://www.eXtropia.com/ |
From: Stephen A. <ste...@of...> - 2001-06-05 19:01:50
|
Hi, I agree with all these good reasons. This supports my previous recommendation. Stephen At 12:02 AM 6/6/2001 +0800, Gunther Birznieks wrote: >I disagree in general with this. Having coded a lot of WML and HTML myself >for a local mobile company, I can say pretty strongly that I do not believe >in a 1-1 mapping between elements in WML and HTML except in a very loose sense. > >You really have to code the whole template very separately for WML vs HTML >and the choice you make (eg textfield vs textarea) is very different on WML >vs HTML. > >So you would not want some generic Widget::TextField that rents a WML >version for WML and HTML for HTML. It's quite possible that on web you may >want to allow the user to type in a lot of info in textarea but on wap, you >just restrict it a bit more. > >I think for most programmers, it will be easier to see HTML widgets and >then dive in there and then plainttext widgets and WAP widgets etc as a >substructure and then see when they are coding an HTML form what elements >are available to them when they are doing so. > >Later, > Gunther > |
From: Issac G. <ne...@wr...> - 2001-06-06 22:55:34
|
> I disagree in general with this. Having coded a lot of WML and HTML myself > for a local mobile company, I can say pretty strongly that I do not believe > in a 1-1 mapping between elements in WML and HTML except in a very loose sense. > > You really have to code the whole template very separately for WML vs HTML > and the choice you make (eg textfield vs textarea) is very different on WML > vs HTML. > > So you would not want some generic Widget::TextField that rents a WML > version for WML and HTML for HTML. It's quite possible that on web you may > want to allow the user to type in a lot of info in textarea but on wap, you > just restrict it a bit more. Still, it's going to be called the same thing (TextField), so why make it _look_ complicated, too? The fact of the matter is, that the widgets are going to exist (as much as possible) across the board (of rendering environments, that is). Therefore, it's silly to make the developers' lives hard by having them have to start picking different classes for HTML, WML, Curses, etc. It also makes Widget developers' lives hard - if we could come up with some templating language that _WE_ could port across the different rendering environments, then not only could the Widget::Base inheriting class developer not have to worry about porting their widgets across environments, but Widget::Renderer inheriting class developers could easily add Renderers for ALL widgets. IMHO, I think that the Widget::Renderer base class should contain work as follows: it should contain a list of template commands - the list should be seperated into two sets: REQUIRED commands. These are the most basic of basics - basic text input, basic label, etc this list should be as minimal as we can - each Renderer child MUST implement these properly. RECOMMENDED commands - These are more advanced things like buttons. They, too, must be implemented across all inherited objects - BUT, not necessarily as the requested object - they could generate an error of some sort (either via perl, or via the actual output) that warns that there was no way of implementing them (eg - they just have to be there and do SOMETHING - they don't have to do what it was expected). each inherited renderer must contain implementation for the whole list of commands and no more. renderer developers should be discouraged from writing an 'enhanced' language for his/her renderer - this will only cause incompatibility probelms. As long as we're on sourceforge, I'd say that if someone thinks we're missing a template command, it should be brought to the mailing list for a suitable period of time (2 weeks?) for consideration. If accepted, we'll update the base renderer object, and patch all inherited objects to include it. As long as it's a "recommended" command, this is easy - we just patch it to display a warning, until the original developer gets a chance to patch it better... Sorry if I may have bended the "two topics in one post" rule a b it here, but the two were very closely related so I felt it neessary to express it in one post... Issac Internet is a wonderful mechanism for making a fool of yourself in front of a very large audience. --Anonymous Moving the mouse won't get you into trouble... Clicking it might. --Anonymous PGP Key 0xE0FA561B - Fingerprint: 7E18 C018 D623 A57B 7F37 D902 8C84 7675 E0FA 561B |
From: Stephen A. <ste...@of...> - 2001-06-07 17:43:29
|
At 12:50 AM 6/7/2001 +0200, Issac Goldstand wrote: ... >> So you would not want some generic Widget::TextField that rents a WML >> version for WML and HTML for HTML. It's quite possible that on web you may >> want to allow the user to type in a lot of info in textarea but on wap, >you >> just restrict it a bit more. > >Still, it's going to be called the same thing (TextField), so why make it >_look_ complicated, too? > >The fact of the matter is, that the widgets are going to exist (as much as >possible) across the board (of rendering environments, that is). I don't think so. We won't have a Widget::WML::TreeView. Between Widget::HTML::Button and Widget::Gtk::Button, I predict there will be very little code in common. Again. Let's not theorize too much about what might be. Let's go ahead and develop some widgets. Then we can discuss the merits of differing views based on real widgets. ... >IMHO, I think that the Widget::Renderer base class should contain work as >follows: > >it should contain a list of template commands - the list should be seperated >into two sets: > >REQUIRED commands. These are the most basic of basics - basic text input, >basic label, etc >this list should be as minimal as we can - each Renderer child MUST >implement these properly. > >RECOMMENDED commands - These are more advanced things like buttons. They, >too, must be implemented across all inherited objects - BUT, not necessarily >as the requested object - they could generate an error of some sort (either >via perl, or via the actual output) that warns that there was no way of >implementing them (eg - they just have to be there and do SOMETHING - they >don't have to do what it was expected). > You raise good points about questioning the extent to which we can make several widgets interchangeable and proposing how we can do this. Let's continue to think about this as we develop widgets. > > Issac > Stephen |