From djlewis at acm.org Tue Aug 1 14:06:13 2006 From: djlewis at acm.org (Deb Lewis) Date: Tue, 1 Aug 2006 11:06:13 -0700 Subject: [Masterview-devel] Revised and simplified directive base - would like your input on syntax and approach as soon as possible In-Reply-To: <19cda190607311402r4e82925fq95794b789f0dc92e@mail.gmail.com> Message-ID: <200608011806.k71I6C3V000631@squirrel.dmpriest.net.uk> Jeff - I like the general direction, not entirely convinced about some of the specifics yet in the initial proposal. I'll do a little brain-dumping and thinking-through-email here. Background context: my mental model of template and directive processing (and how I've been writing the developer document so far) is essentially that of XSLT - what's happening is a tree transformation process on a source DOM tree from the xhtml doc with mv markup into a target rhtml doc with html and erb markup. The default transformation of an element in the source tree is to simply copy the element and its attributes to the destination tree. Directive attribute markup allows for modifying or overriding this default transformation process. A directive is an element attribute with a (string) value containing some encoding of its processing instructions. It's instantiated at the start of the element to which it's attached, with its (string) attribute value provided in the constructor; it can perform processing at element start and/or element end, with access to the source DOM via the dcs arg to stag/etag methods. Processing may involve modifications to the source DOM state (say, add/change/delete attribute values), with normal transformation rendering contining thereafter, or the directive implementation can take control of the output rendering of its element. Two thoughts relative to your arg() service. First, I think I'd like to generally think of the attribute value along similar lines as an args list to a ruby method: one or more comma separated values, which are the positional args, optionally with some trailing set of key => value pairs that get collected into a hash. With sort of a yaml-ish interpretation, though, so that you don't have to be strict about wrapping quotes in the markup to get a string literal, etc. (?maybe your :quote => true option could be dropped? superfluous if we can just "do the right thing" for strings and numbers and then allow the block processing arg from client to supplement) Second, the arg markup done w/in the method implementation seems quite cryptic to me and somewhat inappropriate - auto-stuffing inst vars may be overkill, why not return the value and let me decide on temp vs. inst var w/in my method impl, and actually the declarative-style notation at that point just seems a bit odd. [side remark: i'm a bit skeptical about the current passion to label any and all form of framework and library protocol design as "a DSL", thereby attributing Goodness ] But if you shift the placement of the arg service into the class declaration rather than w/in the s/etag processing method then it starts to feel better to me. Then it *is* a more declarative style notation - it describes the signature of the directive attribute: I expect some number of positional args and for each I can state processing options (:quote) or default value (:default => 'foo'). Then allow last attr_arg to collect a hash - your :merge option name seems ok for that. Such an attr_arg method implementation in DirectiveBase takes the declarations and builds a spec that's used when the directive is instantiated to process the attribute value string into useful form, and then it *does* make sense to be popping the arg values off and putting them in inst vars for the processing method(s) in the directive implementation to access. class MySpecialDirective < DirectiveBase attr_arg :obj, :quote => true attr_arg :method, :quote => true attr_arg :foo, { 'override with this value'} attr_arg :bar, { |x| x.downcase } # lowercasing the arg before setting it to @bar attr_arg :options, :merge => [:common_html, :size, :maxlength] def etag(dcs) ...do some init or munging of the source DOM here... end def etag(dcs) ...output rendering stuff here... end end >> To access the full directive attribute value use attr_value >> To access or set element attributes, use attr[:class] or attr['class'] >> To access content of element, use content to get array, or content_str to get joined version I'd say just go with the symbol version of the attr service: attr[:class], don't bother with attr['class'] variation. For accessing element content, maybe better name is element_content and element_content_str. And element_content should return the form that you normally want, which I think might be the string content. I need to think a bit more about the rendering methods portions of the proposal; I still need to wrap my brain around the dcs value that's provided as the argument to stag and etag methods in a directive implementation. What I want when I'm writing a method in a directive implementation is clean protocol for accessing the source DOM - access or manipulate the element I'm attached to and its attributes, which I think you've almost got now. And then I want simple operations which specify the effect I want to produce on the output tree (with default being the copy-to-dest behavior of SimpleRenderHandler if I do nothing to specify rendering output) I'm not sure if it makes sense to break up SimpleRenderHandler and recast it as a mixin-module (StandardRenderHandler or somesuch) which establishes the default behavior - include in DirectiveBase and the backstop SimpleRenderHandler in parser.rb. RE: render_nothing - could/should this be done as a declarative statement on the directive class? RE: render continue - think I'd like something closer to the controller/view style behavior. If the directive doesn't explicitly invoke a render operation to specify what it wants to produce in the output, then the default is to do the standard copy-src-to-dst behavior. RE: transition/upgrade strategy - I'm inclined to say this is a good time to just break directive implementations and "do it right" - get rid of the old junk, or maybe keep existing guy as as a separate (renamed) transition upgrade class but *ONLY* if a poll of our existing MV users indicates they really want and need this. I just don't think there's enough of an installed base in place to muddle the path forward with backwards compat. If I have directive impls at this early stage in MV's life cycle, I think I'd want to get them cleaned up and simplified. So let's work this out and send out an advance warning notice on the mailing lists, if there's major upset then we can revisit. ~ Deb -----Original Message----- From: Jeff Barczewski [mailto:jeff.barczewski at gmail.com] Sent: Monday, July 31, 2006 2:02 PM To: masterview-devel at rubyforge.org; djlewis at acm.org Subject: Re: Revised and simplified directive base - would like your input on syntax and approach as soon as possible To implement this DSL I created some powerful methods arg(instance_var_name, options) - gets a subargument out of the attr_value, shifting that subarg off the array so that subsequent calls will get the next subarg. Peform quoting or merging with html attributes. Define optional_default which will be used if the value is empty but needed when building a method call and post params are non-null. Stores this to an instance_var_name. erb_content and erb_eval can now take a string and a *args and it contains all the logic to build up the appropriate erb calls. I also added a method render which can be used to easily allow the developer to package up multiple outputs from a method. So rather than building up an array themselves and returning it, they can simply call render as many times as necessary and it will return the complete collection of outputs. The only gotcha is that it needs to be called as the last method in the event (so that the results are returned from the event). (This avoided us having to go to a more complicated block dsl which I think has its own issues, but is this too risky or can it be handled with simple documentation and examples). For completeness I added a method called render_nothing which returns nil, this is used when for the events that don't want to render anything. I added a method called continue which calls the dcs.render which allows continuation of rendering down the directive call stack. So if you want to do this and to output it then you can do 'render continue' or of course set the results to a variable and manipulate. The resulting syntax looks like this def etag(dcs) arg :obj, :quote => true arg :method, :quote => true arg :foo, { 'override with this value'} arg :bar, { |x| x.downcase } # lowercasing the arg before setting it to @bar arg :options, :merge => [:common_html, :size, :maxlength] render erb_content 'text_field', :obj, :method, :options render continue render erb_eval 'end' end To access the full directive attribute value use attr_value To access or set element attributes, use attr[:class] or attr['class'] To access content of element, use content to get array, or content_str to get joined version How does this look to you? It really cleans things up considerably from the old code and should be much more foolproof to user not understanding the complexities. Are my naming conventions ok? (arg, render, continue, :quote, :merge, :optional_default) Once this is in place I would like to get rid of the old cludgy methods that are no longer needed in directive_base and directive_helpers. However what is the best approach to doing this? Do I make these methods in a new base class SimplifiedDirectiveBase? Does it inherit from DirectiveBase? or do I add them directly to DirectiveBase? Do I try to remove the methods that I don't want in there after making sure nothing in our system or any submitted directives are using? Not sure the best approach to cleaning this up. I don't want to leave around all those redundant methods which are not fully debugged and are tricky to use properly. I want to have a clean minimal set of methods that make it clear how to operate. Obviously we will document whatever we do and increment version when we make such an api jump. Need your input on this as soon as you get a chance since I am just about ready to rewrite the directives using the new api once you confirm the naming and the upgrade approach. Or if you think that we really need to move towards a block dsl (to get around the need for render to be last call in method) then I'll have to work on that (using these method calls to get us most of the way there was really easy). Thanks, Jeff From djlewis at acm.org Tue Aug 1 14:12:27 2006 From: djlewis at acm.org (Deb Lewis) Date: Tue, 1 Aug 2006 11:12:27 -0700 Subject: [Masterview-devel] Work in progress Message-ID: <200608011812.k71ICQQp006162@squirrel.dmpriest.net.uk> Jeff - I'm going to stay out of directives stuff as much as possble while you work out all the new stuff. The one area I do want to sort out is the multiple-namespaces mechanisms and a mechanism for the notion we started talking about recently for metadata/info about directive - I should be able to do that without getting in your way, I'll work it out and then integrate into whatever you do. Docs nit: need a shorter label in the nav bar for "Media (Videos/Ilustrations)"! I'm going to be adding an entry for the developer doc soon so we've got doc on directive implementations and the nav link label bar is getting too long. Requests/suggestions?! ~ Deb From jeff.barczewski at gmail.com Tue Aug 1 14:58:50 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Tue, 1 Aug 2006 13:58:50 -0500 Subject: [Masterview-devel] Revised and simplified directive base - would like your input on syntax and approach as soon as possible In-Reply-To: <200608011806.k71I6C3V000631@squirrel.dmpriest.net.uk> References: <19cda190607311402r4e82925fq95794b789f0dc92e@mail.gmail.com> <200608011806.k71I6C3V000631@squirrel.dmpriest.net.uk> Message-ID: <19cda190608011158u15b7fc39sd0f218ddfbebfe32@mail.gmail.com> Thanks for the feedback, that helps. I think it is helping to flush out the best approach here. I think your idea about moving the attr_arg to the class level definition make sense it should be at that level. I did just get through coding up a CaseInsensitiveHash that allows you to access values using symbol or string and it will work case independent. It will preserve the case though since that can be important for attributes. If you are setting a value for the first time then you may want to specify the case, subsequent access or even resetting a value keeps the original case. I think this will work well for us in the way we are using attributes. I agree with your assesment on rendering, it probably should work more like rails. I will try to think through some scenarios and see what I can come up with. I think to accomplish what we are wanting I will need to go to a block DSL syntax so that I can do the post processing we need. That gives us lots of flexibility for the future too (we can do any amount of pre or post processing). Some brainstorming and thinking out loud here... So syntax might be something like class MySpecialDirective < DirectiveBase attr_arg :obj, :quote => true attr_arg :method, :quote => true attr_arg :foo, { 'override with this value'} attr_arg :bar, { |x| x.downcase } # lowercasing the arg before setting it to @bar attr_arg :options, :merge => [:common_html, :size, :maxlength] event :stag do |e| e.render 'something here' e.render erb_content( 'text_area', :obj, :method, :foo, :bar ) end end Only need to figure out how to handle the continue or yield. Like you said it might be declarable. However we need to be able to render before and/or after the yield and sometimes instead of. It might be useful to be able to get at the contents of the yield to manipulate it, though I don't know that we need that for any current directives. We could go with positional render methods something like e.render :before, erb_content( 'text_area', :obj, :method, :foo, :bar ) e.render :after, 'foo bar' e.render :nothing # like rails could be an option, however it doesn't always fit as well since we have needs to render nothing and also render instead of what would normally be rendered. Doesn't make sense used in context with :before and :after, but maybe that's ok, use :replace if trying to do something else?? e.render :replace 'foo bar' # would something like this be used to suppress the output and instead render something else. In the absence of :nothing or :replace then we would copy to destination as planned. If :before, or :after were encountered then their output would preceed or succeed the normal rendering (from dcs.render). If we need to retrieve the dcs.render content for manipulation to we use yield?? That seems to be the new standard in rails views instead of @content_for_layout. Not sure if that would be best or whether that might cause us some issues if we were blocking access to the real yield key word. If we used yield it might be like this localvar = yield # now I can manipulate the contents and output with a render # and since yield was called, we'll know not to call it again later I also agree with the transition/upgrade strategy, if I port all of our directives over and all the ones that were contributed, I think that will suffice for most users. A quick poll could find out if we need to do more with that. Otherwise I like getting a fresh start at this. The directives will for the most part become dead simple with the new api. Thanks for your input Deb. I want this to be a much simplified api to make directive creation as easy as possible for the 80% of needs out there. I think we are getting close. (now I just need to learn about doing block DSL's. I will get Jim Weirich's slides back out, was looking at them the other day. I also looked at Neal Ford's that you mentioned.) Jeff On 8/1/06, Deb Lewis wrote: > Jeff - I like the general direction, not entirely convinced about some of > the specifics yet in the initial proposal. > > I'll do a little brain-dumping and thinking-through-email here. > > Background context: my mental model of template and directive processing > (and how I've been writing the developer document so far) is essentially > that of XSLT - what's happening is a tree transformation process on a source > DOM tree from the xhtml doc with mv markup into a target rhtml doc with html > and erb markup. The default transformation of an element in the source tree > is to simply copy the element and its attributes to the destination tree. > Directive attribute markup allows for modifying or overriding this default > transformation process. > > A directive is an element attribute with a (string) value containing some > encoding of its processing instructions. It's instantiated at the start of > the element to which it's attached, with its (string) attribute value > provided in the constructor; it can perform processing at element start > and/or element end, with access to the source DOM via the dcs arg to > stag/etag methods. Processing may involve modifications to the source DOM > state (say, add/change/delete attribute values), with normal transformation > rendering contining thereafter, or the directive implementation can take > control of the output rendering of its element. > > Two thoughts relative to your arg() service. First, I think I'd like to > generally think of the attribute value along similar lines as an args list > to a ruby method: one or more comma separated values, which are the > positional args, optionally with some trailing set of key => value pairs > that get collected into a hash. With sort of a yaml-ish interpretation, > though, so that you don't have to be strict about wrapping quotes in the > markup to get a string literal, etc. (?maybe your :quote => true option > could be dropped? superfluous if we can just "do the right thing" for > strings and numbers and then allow the block processing arg from client to > supplement) > > Second, the arg markup done w/in the method implementation seems quite > cryptic to me and somewhat inappropriate - auto-stuffing inst vars may be > overkill, why not return the value and let me decide on temp vs. inst var > w/in my method impl, and actually the declarative-style notation at that > point just seems a bit odd. > > [side remark: i'm a bit skeptical about the current passion to label any and > all form of framework and library protocol design as "a DSL", thereby > attributing Goodness ] > > But if you shift the placement of the arg service into the class declaration > rather than w/in the s/etag processing method then it starts to feel better > to me. Then it *is* a more declarative style notation - it describes the > signature of the directive attribute: I expect some number of positional > args and for each I can state processing options (:quote) or default value > (:default => 'foo'). Then allow last attr_arg to collect a hash - your > :merge option name seems ok for that. Such an attr_arg method > implementation in DirectiveBase takes the declarations and builds a spec > that's used when the directive is instantiated to process the attribute > value string into useful form, and then it *does* make sense to be popping > the arg values off and putting them in inst vars for the processing > method(s) in the directive implementation to access. > > class MySpecialDirective < DirectiveBase > attr_arg :obj, :quote => true > attr_arg :method, :quote => true > attr_arg :foo, { 'override with this value'} > attr_arg :bar, { |x| x.downcase } # lowercasing the arg before setting it > to @bar > attr_arg :options, :merge => [:common_html, :size, :maxlength] > > def etag(dcs) > ...do some init or munging of the source DOM here... > end > def etag(dcs) > ...output rendering stuff here... > end > > end > > >> To access the full directive attribute value use attr_value > >> To access or set element attributes, use attr[:class] or attr['class'] > >> To access content of element, use content to get array, or content_str to > get joined version > > I'd say just go with the symbol version of the attr service: attr[:class], > don't bother with attr['class'] variation. For accessing element content, > maybe better name is element_content and element_content_str. And > element_content should return the form that you normally want, which I think > might be the string content. > > I need to think a bit more about the rendering methods portions of the > proposal; I still need to wrap my brain around the dcs value that's provided > as the argument to stag and etag methods in a directive implementation. > What I want when I'm writing a method in a directive implementation is clean > protocol for accessing the source DOM - access or manipulate the element I'm > attached to and its attributes, which I think you've almost got now. And > then I want simple operations which specify the effect I want to produce on > the output tree (with default being the copy-to-dest behavior of > SimpleRenderHandler if I do nothing to specify rendering output) > > I'm not sure if it makes sense to break up SimpleRenderHandler and recast it > as a mixin-module (StandardRenderHandler or somesuch) which establishes the > default behavior - include in DirectiveBase and the backstop > SimpleRenderHandler in parser.rb. > > RE: render_nothing - could/should this be done as a declarative statement on > the directive class? > > RE: render continue - think I'd like something closer to the controller/view > style behavior. If the directive doesn't explicitly invoke a render > operation to specify what it wants to produce in the output, then the > default is to do the standard copy-src-to-dst behavior. > > RE: transition/upgrade strategy - I'm inclined to say this is a good time to > just break directive implementations and "do it right" - get rid of the old > junk, or maybe keep existing guy as as a separate (renamed) transition > upgrade class but *ONLY* if a poll of our existing MV users indicates they > really want and need this. I just don't think there's enough of an > installed base in place to muddle the path forward with backwards compat. > If I have directive impls at this early stage in MV's life cycle, I think > I'd want to get them cleaned up and simplified. So let's work this out and > send out an advance warning notice on the mailing lists, if there's major > upset then we can revisit. > > ~ Deb > From jeff.barczewski at gmail.com Tue Aug 1 15:30:06 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Tue, 1 Aug 2006 14:30:06 -0500 Subject: [Masterview-devel] Work in progress In-Reply-To: <200608011812.k71ICQQp006162@squirrel.dmpriest.net.uk> References: <200608011812.k71ICQQp006162@squirrel.dmpriest.net.uk> Message-ID: <19cda190608011230p75c8cefan2fb24491c64ba66f@mail.gmail.com> Sounds good. I plan to get this new API out as soon as we have it firmed up. So hopefully that should happen relatively soon. Rails uses the term 'Screencasts' on rubyonrails.com. Would that be indicative of screen video and screenshots? Seems like it might be close enough to cover us. Or if you think something like Screens/videos would be better that is fine with me too. Jeff On 8/1/06, Deb Lewis wrote: > Jeff - I'm going to stay out of directives stuff as much as possble while > you work out all the new stuff. The one area I do want to sort out is the > multiple-namespaces mechanisms and a mechanism for the notion we started > talking about recently for metadata/info about directive - I should be able > to do that without getting in your way, I'll work it out and then integrate > into whatever you do. > > Docs nit: need a shorter label in the nav bar for "Media > (Videos/Ilustrations)"! I'm going to be adding an entry for the developer > doc soon so we've got doc on directive implementations and the nav link > label bar is getting too long. Requests/suggestions?! > > ~ Deb > > _______________________________________________ > Masterview-devel mailing list > Masterview-devel at rubyforge.org > http://rubyforge.org/mailman/listinfo/masterview-devel > From djlewis at acm.org Tue Aug 1 17:30:44 2006 From: djlewis at acm.org (Deb Lewis) Date: Tue, 1 Aug 2006 14:30:44 -0700 Subject: [Masterview-devel] Work in progress In-Reply-To: <19cda190608011230p75c8cefan2fb24491c64ba66f@mail.gmail.com> Message-ID: <200608012130.k71LUfNn078917@squirrel.dmpriest.net.uk> Let's try Screencasts, it's short and I think conveys the proper sense. We can augment with roadmap/cross-links. I'll swap that in next time I'm in the docs ~ Deb -----Original Message----- From: Jeff Barczewski [mailto:jeff.barczewski at gmail.com] Sent: Tuesday, August 01, 2006 12:30 PM To: djlewis at acm.org; masterview-devel at rubyforge.org Subject: Re: [Masterview-devel] Work in progress Sounds good. I plan to get this new API out as soon as we have it firmed up. So hopefully that should happen relatively soon. Rails uses the term 'Screencasts' on rubyonrails.com. Would that be indicative of screen video and screenshots? Seems like it might be close enough to cover us. Or if you think something like Screens/videos would be better that is fine with me too. Jeff From jeff.barczewski at gmail.com Wed Aug 2 11:00:23 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Wed, 2 Aug 2006 10:00:23 -0500 Subject: [Masterview-devel] simplified directive base - draft 3 Message-ID: <19cda190608020800k3d2719dco2cd26e1b92073728@mail.gmail.com> How about something like this... I have most of this figured out how to code. I was thinking about adding optional hash to the event method so we could do stuff like event :stag, :render => :nothing when we want to eat the content. Also could be useful for other options I can instance_eval the block and that provides access to the instance variables like you would expect without having to prefix or pass in anything to block. I was thinking that the render method would take a 'position' argument indicating whether to append this content to a stack which will be output before or after the middle (dcs.render) which will happen automatically unless indicated otherwise. Using the :render => :nothing option for a block we can easily suppress all output, but how to indicate that we want to suppress it when we want to render other things instead? It seems that when we are in a block, that the indication to prevent that would be done along near the other render commands. maybe using something like render :event, whatever to indicate we are influencing the output from dcs.render, if nil or maybe :nothing then omit, otherwise substitute the content provided. Also how to provide access to the dcs.render content, use a method called yield like rails? So var = yield gets the content and allows you to work with it before outputting if we use yield, then for consistency should our above render position be called render :yield (nil | :nothing | whatever replacement content) Not sure if :event or :yield is better, or whether there is a better term for this nested content? What do you think makes most sense? Are we getting closer? class MySpecialDirective < DirectiveBase attr_arg :obj, :quote => true attr_arg :method, :quote => true attr_arg :foo, { 'override with this value'} attr_arg :bar, { |x| x.downcase } # lowercasing the arg before setting it to @bar attr_arg :options, :merge => [:common_html, :size, :maxlength] event :stag do # outputs before, dcs.render(implied), and after content render :before 'something here' render :before erb_content( 'text_area', :obj, :method, :foo, :bar ) render :after erb_eval( attr[:class] ) end event :content, :render => :nothing # eat all the content, outputting nothing event :etag do # collects the dcs.render and manipulates before outputting con = yield con.gsub!( /foo/, 'bar') render :event con end event :comment do # output the before, eat the dcs.render render :before 'hello' render :event :nothing # or nil end end From jeff.barczewski at gmail.com Wed Aug 2 11:09:41 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Wed, 2 Aug 2006 10:09:41 -0500 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <19cda190608020800k3d2719dco2cd26e1b92073728@mail.gmail.com> References: <19cda190608020800k3d2719dco2cd26e1b92073728@mail.gmail.com> Message-ID: <19cda190608020809w5a68b568w2ec2ec840dd63326@mail.gmail.com> well, trying out defining a method yield but it looks like we'd have to call it using self.yield unless I did something to remove the kernel one. Maybe it would be better to not use yield and come up with a different method name that represents the dcs.render (get serialized output for this event calling all nested directives). Let me know what you think. On 8/2/06, Jeff Barczewski wrote: > How about something like this... > > I have most of this figured out how to code. > > I was thinking about adding optional hash to the event method so we > could do stuff like > event :stag, :render => :nothing > when we want to eat the content. Also could be useful for other options > > I can instance_eval the block and that provides access to the instance > variables like you would expect without having to prefix or pass in > anything to block. > > I was thinking that the render method would take a 'position' argument > indicating whether to append this content to a stack which will be > output before or after the middle (dcs.render) which will happen > automatically unless indicated otherwise. > > Using the :render => :nothing option for a block we can easily > suppress all output, but how to indicate that we want to suppress it > when we want to render other things instead? It seems that when we are > in a block, that the indication to prevent that would be done along > near the other render commands. > > maybe using something like > render :event, whatever > to indicate we are influencing the output from dcs.render, if nil or > maybe :nothing then omit, otherwise substitute the content provided. > > Also how to provide access to the dcs.render content, use a method > called yield like rails? > So var = yield gets the content and allows you to work with it before outputting > > if we use yield, then for consistency should our above render position be called > render :yield (nil | :nothing | whatever replacement content) > > Not sure if :event or :yield is better, or whether there is a better > term for this nested content? What do you think makes most sense? > > Are we getting closer? > > class MySpecialDirective < DirectiveBase > attr_arg :obj, :quote => true > attr_arg :method, :quote => true > attr_arg :foo, { 'override with this value'} > attr_arg :bar, { |x| x.downcase } # lowercasing the arg before setting it > to @bar > attr_arg :options, :merge => [:common_html, :size, :maxlength] > > event :stag do # outputs before, dcs.render(implied), and after content > render :before 'something here' > render :before erb_content( 'text_area', :obj, :method, :foo, :bar ) > render :after erb_eval( attr[:class] ) > end > > event :content, :render => :nothing # eat all the content, outputting nothing > > event :etag do # collects the dcs.render and manipulates before outputting > con = yield > con.gsub!( /foo/, 'bar') > render :event con > end > > event :comment do # output the before, eat the dcs.render > render :before 'hello' > render :event :nothing # or nil > end > > end > From djlewis at acm.org Wed Aug 2 13:12:08 2006 From: djlewis at acm.org (Deb Lewis) Date: Wed, 2 Aug 2006 10:12:08 -0700 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <19cda190608020809w5a68b568w2ec2ec840dd63326@mail.gmail.com> Message-ID: <200608021712.k72HC6cJ095557@squirrel.dmpriest.net.uk> I really hate the choice of "yield" in ruby, so I'm *fine* with a different name! ("yield" and the "rescue" exception terminology are my two real dislikes about ruby; neither of those terms relate to any of the ways I normally talk/think about block evaluation and exception handling) Some other reactions (opinions tempered by not having actually played with sketching this out in some real impl's, which always leads to better instinct about what seems right): o I think I may actually *prefer* to declare the event's block arg rather than having it instance_eval'd. Not sure I *want* my directive to have inst var access - it's got its own inst vars and I think I prefer to think of it as having a distinct interface to the template-processor that's using it, as opposed to being part of that guy. It makes the notation w/in an stag/etag handler less declarative, but I think that's actually ok. The declarative aspect is nicely done by the new scheme we're settling on for declaring intent about the attribute value encoding (attr_arg guys). But writing the processing part seems more like writing an action method in a controller or adding some behavior to a model, where some of what I say in the class implementation fits nicely into a declarative structure but then the part that's actually about *doing* something really is more procedural and thus more like writing "normal code". Then the challenge is to have clean, simple protocol for things you want to access or generate. o I like render as the term to use for the operation which produces an effect on the output document. o render :before/:after are ok, but :event is funky. Maybe an alternative way to come at this is to think about this as hooking the processing events and shift the before/after notion to the handlers; then all you ever do w/in a handler is render (position is now implicit and doesn't need to be specified). e.g., instead of your example event :stag do # outputs before, dcs.render(implied), and after content render :before 'something here' render :before erb_content( 'text_area', :obj, :method, :foo, :bar ) render :after erb_eval( attr[:class] ) end we might have: event :before_stag do # :before positioning of the emitted rendering is implied by when render 'something here' render erb_content( 'text_area', :obj, :method, :foo, :bar ) end ~ Deb -----Original Message----- From: Jeff Barczewski [mailto:jeff.barczewski at gmail.com] Sent: Wednesday, August 02, 2006 8:10 AM To: djlewis at acm.org; masterview-devel at rubyforge.org Subject: Re: simplified directive base - draft 3 well, trying out defining a method yield but it looks like we'd have to call it using self.yield unless I did something to remove the kernel one. Maybe it would be better to not use yield and come up with a different method name that represents the dcs.render (get serialized output for this event calling all nested directives). Let me know what you think. From jeff.barczewski at gmail.com Wed Aug 2 15:11:42 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Wed, 2 Aug 2006 14:11:42 -0500 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <200608021712.k72HC6cJ095557@squirrel.dmpriest.net.uk> References: <19cda190608020809w5a68b568w2ec2ec840dd63326@mail.gmail.com> <200608021712.k72HC6cJ095557@squirrel.dmpriest.net.uk> Message-ID: <19cda190608021211p895dffp76b6a9cf9ffe95f4@mail.gmail.com> Great! I was thinking along the same lines about the before after stuff, I'll take a look at whether most of the attributes do one or the other or a combination. If they stick to one or the other then it makes sense to indicate the position as part of the event, but if they tend to do both then it might get hairy having to go here for that and there for something else. But let me check maybe the directives typically only do one type. As for the instance_eval, I was sort of thinking along those lines, but then I realized that we would be declaring this in a class and it is very close to a method (it is a dedicated block which is wrapped by some other processing). Sort of like you were saying this part is procedural and needs direct access to things, I think we'd want the block to have access to instance variables giving the ability to create new ones etc, because these will be the way that you communicate across the object from one method to another. For instance you might start something in the start tag and then be completing it in the end tag or working on the content or nested tags. Instance variables will keep your state between these events, so need easy way to get at and create them. Seems like if we used a non-instance eval approach that we'd lose some of this freedom (you'd need accessors and would need a way to create new instance vars) and everything that wasn't a class method would need a prefix in front (e.). Seems to me that working in that mode would be more confusing. I think I'd rather be in the instance mode like a normal method call and then do something different to call class methods. You mentioned the block having its own instance vars, but not sure what you meant. It can certainly have local variables, but since it is only a block it wouldn't have instance vars and even if it did they would go away when the block completes, right? Given all this, it seems to make sense to use an instance_eval approach giving us easy access to all instance vars, simplified syntax, elimate the need for the block var decl |x|, feels just like a regular instance method. I still need to define a way to read/eat the event output. Let me take these ideas you presented and see how they would look using some real examples, and maybe the best approach will pop out. Thanks for the feedback. Let me know if I am still missing something regarding the instance_eval discussion. From djlewis at acm.org Wed Aug 2 16:50:30 2006 From: djlewis at acm.org (Deb Lewis) Date: Wed, 2 Aug 2006 13:50:30 -0700 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <19cda190608021211p895dffp76b6a9cf9ffe95f4@mail.gmail.com> Message-ID: <200608022050.k72KoSZ2042754@squirrel.dmpriest.net.uk> ah, maybe we have a disconnect in how we're each thinking about this that's leading to diff notions of blocks and evals and inst vars [terminology: I'm going to talk about "template processor" to stay out of parser/dcs etc details and keep this a bit more abstract] I'm still thinking of a directive implementation as a class, with life cycle: instantiated when template processor processes an element start tag in the source template document. Constructed with the string value of the directive attribute provided (dirProcessor = SomeDirective.new(attr_value)...), with our new parser-aids hooked up to initialize its inst vars from the declarative notation in the class decl that essentially give us the signature - some number of essentially positional args, possibly with defaults, plus optionally has collected for trailing option specs. Template processor is responsible for hanging onto the directive handlers for an element and invoking them at appropriate points during the element processing (stag, etag). Directive processor instance is thrown away when the element is completed. [maybe the template processor itself is also an arg to the directive handler constructor, along with the attribute value - then maybe the block/event-method arg does indeed go away] So that's why I think of the directive guy as having its own state, derived from the attribute value string, and that this is separate from the overall state of the template processing. It gets initialized at the start tag, it can keep whatever it wants, and it's separate from any other directives on that element or other elements in the template. And having sketched out that story, here's another possible wrinkle: we're thinking about 'attr_arg' sort of declarative notation to express the expected signature of the attribute value for this directive. Maybe then there's also a declarative notation which expresses which events it wants to be invoked on and the method to call for each event. Similar to before/after filters on controller actions. Maybe that's the way to the declarative DSL notation for common things, with ability to drop into a method for anything that's really procedural or complicated. ~ Deb From jeff.barczewski at gmail.com Thu Aug 3 08:38:08 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Thu, 3 Aug 2006 07:38:08 -0500 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <200608022050.k72KoSZ2042754@squirrel.dmpriest.net.uk> References: <19cda190608021211p895dffp76b6a9cf9ffe95f4@mail.gmail.com> <200608022050.k72KoSZ2042754@squirrel.dmpriest.net.uk> Message-ID: <19cda190608030538v4df981dbm83773471eb29fb18@mail.gmail.com> Right, I don't think we are too far off in our thoughts. I agree with pretty much what you said, though I would just add a few points. Template processor finds all the directives that are declared in attributes as well as any that are set to auto run (like our inline erb expansion one which allows inline substitution). Then after having that list it goes through and finds out which directives respond to the event it is getting ready to process, it also checks if the directives respond to child_tag_event or descendent_tag_event, as well as wildcarded options child_any_event, descendent_any_event based on the nesting etc (this allows directives to fire when child events are hit). Anyway once it finds directives that respond to any of these it creates a call stack and sorts based on priority and nesting depth, then it proceeds to instantiate and call these. Each directive gets the attr_value as well as access to the attributes and other content. It can create instance variables that will persist between events so that some state can be set in start element and then utilized in end element. Each directive processes the events such that they work like an interceptor, pipeline, or filter where each can affect the input and outcome of each other also choosing whether any further processing occurs on this event. I don't want to change any of the main parser mechanisms right now (other than your multi-namespace enhancement), I am only wanting to simplify the directive class api to make it easier to build these. I still think the main process is sound and accomodates everything we need, just want to simplify building these classes. So the directive DSL we have been discussing is involved in creating the directive classes. We tell the directive how it can parse its attr_value (if necessary), and we respond to events affecting input and outcome. So the attr_arg methods tell the class how to parse its attr_value and the rest is how to process or how to create these event methods and what happens in them. Using a instance_eval block dsl we can simplify and encapsulate some of the necessary processing namely preparing the argument objects initially, calling next interceptor in the chain, and handling post processing to wrap up what gets returned up to next interceptor (and eventually serialized). So this DSL we are describing is used inside the directive class itself for the above purposes. The blocks are all part of what needs to happen in each event call. So yes, if we have a event :before_stag then I will build a instance method called stag and inside of it this block will be invoked at the proper time. If we had an event :stag or a event :after_stag these would also be invoked in that same stag instance method. So I would end up creating one stag method that potentially invokes three blocks (if they exist). Each of these blocks is a sub instance method so that's why I think they need instance_eval access so they can intuitively access everything about the directive instance (vars, methods) without grief. Developers can consider themselves writing actual instance methods with the syntax except that we are doing a little pre an post processing and combining around all this. >From our discussions, the syntax that feels the best so far (thinking about what current and future directives do) is this: class MySpecialDirective < DirectiveBase attr_arg :obj, :quote => true attr_arg :method, :quote => true attr_arg :foo, { 'override with this value'} attr_arg :bar, { |x| x.downcase } # lowercasing the arg before setting it to @bar attr_arg :options, :merge => [:common_html, :size, :maxlength] event :before_stag do # outputs this before any stag output render erb_eval( 'if' attr[:class] ) end event :stag do # outputs this instead of what would be output for stag render erb_content( 'text_area', :obj, :method, :foo, :bar ) # if they hadn't called render here, then the normal output for stag # would still automatically be created, they could have also # called render :nothing if they wanted to suppress or conditionally # suppress. end event :content, :render => :nothing # eat all the content, outputting nothing # if we hadn't put this here then the directive would not have even been called # for a content event, but we acutlly want to be called and we are stopping # any output. event :etag do # collects the dcs.render and manipulates before outputting con = event_result() # get the output that would be rendered con.gsub!( /foo/, 'bar') render :event con # render this modified output instead end event :after_child_td_stag # render something after a child td start tag render 'something after child td tag' end end The above ends up creating a directive class with the following instance methods stag content etag child_td_stag and all the necesary infrastructure to store and call these other blocks at the right time. I like how putting the position into the pseudo event allows us to clean up things and it provides a way to override or simply allow content to be rendered without developer forgetting to call dcs.render (they specifically say when they want to render nothing or to replace the output). It also prevents then from having to build up an array of output to return, this is wrapped up by our render methods. As for getting the output from the other interceptors (directives and serializer), do you like the name event_result() for this method call which will be used whenever you want to get the output and manipulate it?? This is instead of yield and continue ideas we had earlier. It basically allows processing to continue by calling dcs.render and returns that result. How does this feel to you? I think we are getting close. Thanks for your continued input!! Jeff From jeff.barczewski at gmail.com Thu Aug 3 08:42:41 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Thu, 3 Aug 2006 07:42:41 -0500 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <19cda190608030538v4df981dbm83773471eb29fb18@mail.gmail.com> References: <19cda190608021211p895dffp76b6a9cf9ffe95f4@mail.gmail.com> <200608022050.k72KoSZ2042754@squirrel.dmpriest.net.uk> <19cda190608030538v4df981dbm83773471eb29fb18@mail.gmail.com> Message-ID: <19cda190608030542v35ee037djace23ebc5703b700@mail.gmail.com> One typo in my previous post > event :etag do # collects the dcs.render and manipulates before outputting > con = event_result() # get the output that would be rendered > con.gsub!( /foo/, 'bar') > render :event con # render this modified output instead > end > should be event :etag do # collects the dcs.render and manipulates before outputting con = event_result() # get the output that would be rendered con.gsub!( /foo/, 'bar') render con # render this modified output instead end we do not need positioning since that is implied in the pseudo event name. On 8/3/06, Jeff Barczewski wrote: > Right, I don't think we are too far off in our thoughts. > > I agree with pretty much what you said, though I would just add a few > points. Template processor finds all the directives that are declared > in attributes as well as any that are set to auto run (like our inline > erb expansion one which allows inline substitution). Then after having > that list it goes through and finds out which directives respond to > the event it is getting ready to process, it also checks if the > directives respond to child_tag_event or descendent_tag_event, as well > as wildcarded options child_any_event, descendent_any_event based on > the nesting etc (this allows directives to fire when child events are > hit). Anyway once it finds directives that respond to any of these it > creates a call stack and sorts based on priority and nesting depth, > then it proceeds to instantiate and call these. > > Each directive gets the attr_value as well as access to the attributes > and other content. It can create instance variables that will persist > between events so that some state can be set in start element and then > utilized in end element. > > Each directive processes the events such that they work like an > interceptor, pipeline, or filter where each can affect the input and > outcome of each other also choosing whether any further processing > occurs on this event. > > I don't want to change any of the main parser mechanisms right now > (other than your multi-namespace enhancement), I am only wanting to > simplify the directive class api to make it easier to build these. I > still think the main process is sound and accomodates everything we > need, just want to simplify building these classes. > > So the directive DSL we have been discussing is involved in creating > the directive classes. We tell the directive how it can parse its > attr_value (if necessary), and we respond to events affecting input > and outcome. So the attr_arg methods tell the class how to parse its > attr_value and the rest is how to process or how to create these event > methods and what happens in them. > > Using a instance_eval block dsl we can simplify and encapsulate some > of the necessary processing namely preparing the argument objects > initially, calling next interceptor in the chain, and handling post > processing to wrap up what gets returned up to next interceptor (and > eventually serialized). > > So this DSL we are describing is used inside the directive class > itself for the above purposes. The blocks are all part of what needs > to happen in each event call. So yes, if we have a > > event :before_stag > > then I will build a instance method called stag and inside of it this > block will be invoked at the proper time. > > If we had an > > event :stag > or a > event :after_stag > > these would also be invoked in that same stag instance method. So I > would end up creating one stag method that potentially invokes three > blocks (if they exist). Each of these blocks is a sub instance method > so that's why I think they need instance_eval access so they can > intuitively access everything about the directive instance (vars, > methods) without grief. Developers can consider themselves writing > actual instance methods with the syntax except that we are doing a > little pre an post processing and combining around all this. > > From our discussions, the syntax that feels the best so far (thinking > about what current and future directives do) is this: > > class MySpecialDirective < DirectiveBase > attr_arg :obj, :quote => true > attr_arg :method, :quote => true > attr_arg :foo, { 'override with this value'} > attr_arg :bar, { |x| x.downcase } # lowercasing the arg before setting it > to @bar > attr_arg :options, :merge => [:common_html, :size, :maxlength] > > event :before_stag do # outputs this before any stag output > render erb_eval( 'if' attr[:class] ) > end > > event :stag do # outputs this instead of what would be output for stag > render erb_content( 'text_area', :obj, :method, :foo, :bar ) > # if they hadn't called render here, then the normal output for stag > # would still automatically be created, they could have also > # called render :nothing if they wanted to suppress or conditionally > # suppress. > end > > event :content, :render => :nothing # eat all the content, outputting nothing > # if we hadn't put this here then the directive would not have even been called > # for a content event, but we acutlly want to be called and we are stopping > # any output. > > event :etag do # collects the dcs.render and manipulates before outputting > con = event_result() # get the output that would be rendered > con.gsub!( /foo/, 'bar') > render :event con # render this modified output instead > end > > event :after_child_td_stag # render something after a child td start tag > render 'something after child td tag' > end > > end > > > The above ends up creating a directive class with the following instance methods > stag > content > etag > child_td_stag > > and all the necesary infrastructure to store and call these other > blocks at the right time. > > > > I like how putting the position into the pseudo event allows us to > clean up things and it provides a way to override or simply allow > content to be rendered without developer forgetting to call dcs.render > (they specifically say when they want to render nothing or to replace > the output). It also prevents then from having to build up an array of > output to return, this is wrapped up by our render methods. > > As for getting the output from the other interceptors (directives and > serializer), do you like the name event_result() for this method call > which will be used whenever you want to get the output and manipulate > it?? This is instead of yield and continue ideas we had earlier. It > basically allows processing to continue by calling dcs.render and > returns that result. > > How does this feel to you? > > I think we are getting close. Thanks for your continued input!! > > Jeff > From jeff.barczewski at gmail.com Thu Aug 3 10:57:42 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Thu, 3 Aug 2006 09:57:42 -0500 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <19cda190608030542v35ee037djace23ebc5703b700@mail.gmail.com> References: <19cda190608021211p895dffp76b6a9cf9ffe95f4@mail.gmail.com> <200608022050.k72KoSZ2042754@squirrel.dmpriest.net.uk> <19cda190608030538v4df981dbm83773471eb29fb18@mail.gmail.com> <19cda190608030542v35ee037djace23ebc5703b700@mail.gmail.com> Message-ID: <19cda190608030757s49126113p15fa3e097c6463a0@mail.gmail.com> Terminology: 'event' in the context of this discussion are places that one can hook into the rendering process like :before_stag, :stag, :after_stag. These are different (more granular) than the rexml events (stag, etag, ...). They are not actual directive class instance methods, but they are related in that many of these events will be fired under each actual dynamically created instance method. After looking through the existing directives I think the events will work well however we may want to consider a few additional ones to make things easier and make more sense. content - allow straight forward place to override content between start tag and end tag (this is much more useful then the rexml characters event since this will be the accumulated content including all nested tags, comments, etc) tag - allow straight forward way to replace entire tag and all enclosing content, very common usage for many directives that replace all (form helpers). Otherwise they have to capture stag, capture content, and etag. Since this is such a common usage and people could forget to do a step, having a event like this will allow them to easily get the results they expect. Simply render whatever they want to replace everything with. Under the covers this event wraps up stag, after_stag, content, before_etag, etag. One could still also handle :before_stag and :after_etag to add additional wrapper content if necessary but the others will all be accounted for. So our pseudo event structure will be something this: In the order things are called with the number of calls in parens before_stag (1) stag (1) after_stag characters (0..many) comment (0..many) .... nested tags and events ... (0..many) content (1) - rolls up all (characters, comments, nested) - should it include after_stag and before_etag? I can see arguments for both ways. before_etag (1) etag (1) tag (1) - rolls up everything between stag and etag after_etag(1) Event though this looks large in actuallity the code for most directives will only need to hook one or two of these, so what is complex here, simplifies what is done in the directives. Is 'tag' a good name for the event that encapsulates stag to etag data? Should content event exclude after_stag and before_etag or include it? And from previous message so it doesn't get lost is 'event_result()' a good name for the method which allows you to get access to what the event would be rendering (allowing you to modify it before pushing out)? Are things coming together in your mind? I think they are for me and I think the resulting directive code looks like it gets simpler with each iteration we have been doing (which hopefully means we are going in the right direction). I just want to get the terminology and names for things as clear as possible to make it easy for new users to grasp and understand. The easier it is, then the less questions we'll get. Thanks, Jeff From djlewis at acm.org Thu Aug 3 10:59:47 2006 From: djlewis at acm.org (Deb Lewis) Date: Thu, 3 Aug 2006 07:59:47 -0700 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <19cda190608030538v4df981dbm83773471eb29fb18@mail.gmail.com> Message-ID: <200608031459.k73Exi1f009588@squirrel.dmpriest.net.uk> Jeff - ok, I think this is starting to settle into a pretty nice shape. RE: what to call the message for getting at the output (event_result() vs. yield and continue ideas we had earlier) event_result() seems a bit odd to me. maybe something along the lines of render_result() or output_content() - want to convey the sense "I'd like the current result of the output from rendering at this point" ~ Deb From djlewis at acm.org Thu Aug 3 11:19:46 2006 From: djlewis at acm.org (Deb Lewis) Date: Thu, 3 Aug 2006 08:19:46 -0700 Subject: [Masterview-devel] simplified directive base - draft 3 In-Reply-To: <19cda190608030757s49126113p15fa3e097c6463a0@mail.gmail.com> Message-ID: <200608031519.k73FJgAr025147@squirrel.dmpriest.net.uk> content rather than rexml's more detailed characters and comments: yes - logically I just want the element content all/most of the time. I wouldn't even worry about exposing those more detailed events in our directive processing model until there's a justification; can always add later if needed. [can't think offhand why I care about comments, unless someone was using them to embed processing directives via comment annotation conventions] Rather than 'tag', suggest 'element' per the terminology of the DOM model. An element consists of (optional) text content wrapped in start/end tags; may have child elements; may have attributes. So now we have an easy to hook into either the element's content or the entire element, as well as fiddling attributes on the element's (start) tag via the stag event, and I think that captures most of what a directive is likely to be interested in. So the directive processing event structure could be simplified a bit to: before_stag (1) stag (1) after_stag (1) ...nested element events (0 or more) content (0 or 1 - this is just the immediate content, *not* child elements) before_etag (1) etag(1) element (1) - rolls up everything between stag and etag after_etag(1) This looks pretty good, I think it's about right now. BTW it's the nature of this sort of design that it takes at least of few iterations. Every time you do a version, things get clearer and as you get closer to goodness possibilities appear that you couldn't see earlier because the model was too cluttered or too far away from a clean way of characterizing what's going on. ~ Deb From djlewis at acm.org Thu Aug 3 13:38:29 2006 From: djlewis at acm.org (Deb Lewis) Date: Thu, 3 Aug 2006 10:38:29 -0700 Subject: [Masterview-devel] Why :additional_directive_paths option for renderer? Message-ID: <200608031738.k73HcQXq042531@squirrel.dmpriest.net.uk> I'm trying to work out the DirectiveInfo metadata scheme and namespace support and have an old question to bring back up: what's the point of providing option for :additional_directive_paths in the Renderer? Given that directive load paths can be controlled through the config settings, do we need to allow for per-invocation option of specifying additional load paths? I'd rather have this all under the control of the DirectiveRegistry loader if it's sufficient to have a single app-wide directive context. For directive namespace specifications, I'm thinking there's a range of possible points at which one might do this: - declaration in the directive implementation class - declaration in the load path directory (e.g., a config file in the directives dir with a spec for the namespace name of the directives loaded from this directory) - declaration in the load path config entry, e.g., allow [dirName, namespaceName] tuple to be appended to the directive_load_paths as well as a simple dirName as done currently The first flavor is done by the supplier; the second could be done by either a supplier or a consumer (directive developer zips up a directory with some directives + the namespace spec; the developer using these directives in their app could add/change the directory spec file as they wish); the third is strictly in the domain of the consumer, this is part of configuring the usage context for their app. Also need to allow override in the app context so that directive namespace collisions can be resolved in a client app if the two providers create directives with the same name. ??TBD: do we need a per-document mechanism for controlling namespaces? That's provided for in the XML namespace architecture via the xmlns declaration which allows you to say "I'm going to use the following namespace prefix to reference elements from some namespace within this document". But it would be simpler if we could punt on that and for masterview directives just assert that you're going to establish the namespace names once and for all via the config settings for your entire application. ~ Deb From jeff.barczewski at gmail.com Thu Aug 3 14:50:13 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Thu, 3 Aug 2006 13:50:13 -0500 Subject: [Masterview-devel] Fwd: simplified directive base - draft 3 In-Reply-To: <19cda190608031132q2df4967cqd62aba13c3895a55@mail.gmail.com> References: <19cda190608030757s49126113p15fa3e097c6463a0@mail.gmail.com> <200608031519.k73FJgAr025147@squirrel.dmpriest.net.uk> <19cda190608031132q2df4967cqd62aba13c3895a55@mail.gmail.com> Message-ID: <19cda190608031150v2b94a6fbp12c6ec8a456837de@mail.gmail.com> copy for the archive. ---------- Forwarded message ---------- From: Jeff Barczewski Date: Aug 3, 2006 1:32 PM Subject: Re: simplified directive base - draft 3 To: djlewis at acm.org render_result() seems to convey the proper meaning element is fine with me. Yes, comments could be used for embedded processing directives. We aren't currently doing this but there are legitimate cases for this. The content method currently accesses everything in between the since you either are wanting to clear it all, read it including anything that was substituted in from other tags, use it in your processing, or modify the resultant output. Also I don't have any way to only get the non nested tag content, everything rolls up at each level, by the time I get everything there is no distinction between direct text content and output from nested tags. In all the use cases I have currently and the ones on the drawing board this works well since, we always want all the content, for instance when doing a mv:content="hello" we are wanting to wipe out everything inside because it is likely to be sample data. I can however leave the after_stag and before_etag in or out of the content event. Not sure which makes more sense. I don't know that the current directives care much either way. I guess excluding it makes the most sense your primarily talking about the children here not what we just got through adding in. I think everything else is looking pretty good. I'll see how the directives will look with the new syntax, I think it will be a work of art :-) crunching a lot of busy fragile code down to just a few lines of fairly declartive robust code. Thanks for your help in this! Jeff On 8/3/06, Deb Lewis wrote: > content rather than rexml's more detailed characters and comments: yes - > logically I just want the element content all/most of the time. I wouldn't > even worry about exposing those more detailed events in our directive > processing model until there's a justification; can always add later if > needed. > > [can't think offhand why I care about comments, unless someone was using > them to embed processing directives via comment annotation conventions] > > Rather than 'tag', suggest 'element' per the terminology of the DOM model. > An element consists of (optional) text content wrapped in start/end tags; > may have child elements; may have attributes. > > So now we have an easy to hook into either the element's content or the > entire element, as well as fiddling attributes on the element's (start) tag > via the stag event, and I think that captures most of what a directive is > likely to be interested in. > > So the directive processing event structure could be simplified a bit to: > > before_stag (1) > stag (1) > after_stag (1) > ...nested element events (0 or more) > content (0 or 1 - this is just the immediate content, *not* child > elements) > before_etag (1) > etag(1) > element (1) - rolls up everything between stag and etag > after_etag(1) > > This looks pretty good, I think it's about right now. BTW it's the nature > of this sort of design that it takes at least of few iterations. Every time > you do a version, things get clearer and as you get closer to goodness > possibilities appear that you couldn't see earlier because the model was too > cluttered or too far away from a clean way of characterizing what's going > on. > > ~ Deb > > From jeff.barczewski at gmail.com Thu Aug 3 15:01:35 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Thu, 3 Aug 2006 14:01:35 -0500 Subject: [Masterview-devel] Why :additional_directive_paths option for renderer? In-Reply-To: <200608031738.k73HcQXq042531@squirrel.dmpriest.net.uk> References: <200608031738.k73HcQXq042531@squirrel.dmpriest.net.uk> Message-ID: <19cda190608031201h7ec5ba3fsc009fbd507712011@mail.gmail.com> If I remember correctly I just wanted there to be a way for users to configure additional folders to load their directives from. One use would be that if you have a bunch of custom directives that you want to share across all your apps, then you could put them in a shared folder somewhere and add this directory to the :additional_directive_paths in addition to any custom add directory. Not related, but a consideration to note, I wanted to allow users to be able to require in gems that contain directives from us or other users providing another mechanism which might come in handy for sharing and distribution. We could have directive packs in the form of a gem to do specific things. So as long as your directory registry mechanism allows the user to load custom user app specific and site wide shared directives as well as still allowing standard require's then I am fine with however you want to refactor or cleanup. Jeff On 8/3/06, Deb Lewis wrote: > I'm trying to work out the DirectiveInfo metadata scheme and namespace > support and have an old question to bring back up: what's the point of > providing option for :additional_directive_paths in the Renderer? > > Given that directive load paths can be controlled through the config > settings, do we need to allow for per-invocation option of specifying > additional load paths? I'd rather have this all under the control of the > DirectiveRegistry loader if it's sufficient to have a single app-wide > directive context. > > For directive namespace specifications, I'm thinking there's a range of > possible points at which one might do this: > > - declaration in the directive implementation class > > - declaration in the load path directory (e.g., a config file in the > directives dir with a spec for the namespace name of the directives loaded > from this directory) > > - declaration in the load path config entry, e.g., allow [dirName, > namespaceName] tuple to be appended to the directive_load_paths as well as a > simple dirName as done currently > > The first flavor is done by the supplier; the second could be done by either > a supplier or a consumer (directive developer zips up a directory with some > directives + the namespace spec; the developer using these directives in > their app could add/change the directory spec file as they wish); the third > is strictly in the domain of the consumer, this is part of configuring the > usage context for their app. > > Also need to allow override in the app context so that directive namespace > collisions can be resolved in a client app if the two providers create > directives with the same name. > > ??TBD: do we need a per-document mechanism for controlling namespaces? > That's provided for in the XML namespace architecture via the xmlns > declaration which allows you to say "I'm going to use the following > namespace prefix to reference elements from some namespace within this > document". But it would be simpler if we could punt on that and for > masterview directives just assert that you're going to establish the > namespace names once and for all via the config settings for your entire > application. > > ~ Deb > > _______________________________________________ > Masterview-devel mailing list > Masterview-devel at rubyforge.org > http://rubyforge.org/mailman/listinfo/masterview-devel > From jeff.barczewski at gmail.com Fri Aug 11 01:30:24 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Fri, 11 Aug 2006 00:30:24 -0500 Subject: [Masterview-devel] MasterView AdminPages temporary fix for Rails 1.1.6 Message-ID: <19cda190608102230q498bc7fdj27116b9d04839023@mail.gmail.com> Rails 1.1.6 which closes some security holes in Rails also restricts where code can be loaded from. These new restriction prevents the MasterView administration pages to be automagically loaded by enabling the configuration option as they were in the past (since they did not exist in the normal rails app tree). MasterView will still function properly without admin pages, but this aspect was nice for visualization and maintenance. The MasterView rake tasks can still provide similar functionality from the command line. (use rake -T to see all the options or refer to docs). A quick fix to get admin pages up and running again is to copy the MasterView admin pages controller, view code into the normal app tree. To make this easier (especially for gem users), I have created a tar.gz file with the appropriate files. You may simply extract this into your rails web application directory and MasterView admin pages will be functional once again. However extracting these files bypasses the enable_admin_pages configuration option so it will no longer control whether the admin page functionality is available, and as such if these files are installed the functionality is available. We are also looking at additional approaches to this issue and will release a maintenance release as soon as ready. In the meantime users can either extract the tgz file into rails web application directory or simply use the command line rake commands as an alternate option ('rake -T' for list of commands or refer to documentation). Admin pages temporary fix - to restore admin page functionality 1) download http://masterview.org/downloads/MasterViewRails116AdminPages.tgz 2) extract to your web application root directory (so files will be copied into app/controllers, app/views, etc.) 3) By extracting these files MasterView admin pages will be available regardless of the config.enable_admin_pages setting. Remove or rename the MasterView Admin pages 'masterview_controller.rb' when moving to prevent access in production. -OR Alternatively- 1) use rake mv: commands which duplicate that which is available in the admin pages We will announce a MasterView maintenance release for the gem and plugin permanently resolving these problems as soon as it is fully tested. If you have any issues or concerns with anything please let the team know via the masterview-users mailing list so we can track and have archive of discussions. Sorry for any inconvenience brought on by this, Jeff From jeff.barczewski at gmail.com Fri Aug 11 11:22:27 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Fri, 11 Aug 2006 10:22:27 -0500 Subject: [Masterview-devel] Update on progress - MasterView AdminPages permanent fix for Rails 1.1.6 Message-ID: <19cda190608110822n3cf9039eq2e2ad15d9e4f3bc3@mail.gmail.com> Well I was looking into the issue last night and this morning, but this Rails 1.1.5-6 security fix has really restricted quite a few things. So many of the simple fixes I tried just don't work. I think we are going to have to rework how admin pages are loaded to work with in these new restrictions and that is going to be a bit of refactoring. One goal is to not copy much code into the local RAILSAPP/app directory so that things can be upgraded easily simply by updating gem, however it seems that these new security restrictions prevent even something like class MasterViewController < MasterView::AdminPages::AdminPageController where the AdminPageController is not in the local RAILSAPP/app directory. So it is back to the drawing board about how to make this simple, easy, and configurable without simply copying code all over the place. Unfortunately I have to take my daughter on a Girl Scout trip this weekend leaving shortly, so I won't be able to release a better fix until after I return (Sunday). I'm not sure if Deb will have time to work on it either since this was an unexpected situation. However I will stay on this until I get it resolved, hopefully Monday. The good thing (if there is one) is that the only feature broken with MasterView from this rails upgrade (AFAIK) is 'admin pages', which isn't normally needed for production and there are equivalent functionality available via command line with rake mv commands. And of course one can extract the tgz file I made available yesterday evening (I updated it slightly this morning to fix another issue, same location), however as mentioned before installing the tgz file circumvents the config.enable_admin_pages configuration so in production you will want to rename/remove the masterview_controller.rb if you go with this approach. It is a brute force temporary fix, that doesn't keep things as DRY as we'd like, but if you need to use it, then it is there. One would just have to clean up those files when the permanent fix is available to take advantage of new functionality. I apologize for any inconvenience this has caused anyone, we will release a permanent fix as soon as possible. Thanks for your continued patience and support, Jeff From jeff.barczewski at gmail.com Mon Aug 14 13:48:09 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Mon, 14 Aug 2006 12:48:09 -0500 Subject: [Masterview-devel] Update on progress 8/14/06 - MasterView AdminPages permanent fix for Rails 1.1.6 Message-ID: <19cda190608141048r1b4bd90fl7aad7d46e23552ca@mail.gmail.com> I have come up with a solution. We can't subclass a controller but we can mixin the functionality so that will allow us to have a very small shell controller class that mixes in the real code and thus will make it easy to upgrade. I just need to create the code that copies this controller shell into the local rails app and we'll be done. I should be able to wrap this up in the next few days. Jeff On 8/11/06, Jeff Barczewski wrote: > Well I was looking into the issue last night and this morning, but > this Rails 1.1.5-6 security fix has really restricted quite a few > things. So many of the simple fixes I tried just don't work. I think > we are going to have to rework how admin pages are loaded to work with > in these new restrictions and that is going to be a bit of > refactoring. > > One goal is to not copy much code into the local RAILSAPP/app > directory so that things can be upgraded easily simply by updating > gem, however it seems that these new security restrictions prevent > even something like > > class MasterViewController < MasterView::AdminPages::AdminPageController > > where the AdminPageController is not in the local RAILSAPP/app directory. > > So it is back to the drawing board about how to make this simple, > easy, and configurable without simply copying code all over the place. > > Unfortunately I have to take my daughter on a Girl Scout trip this > weekend leaving shortly, so I won't be able to release a better fix > until after I return (Sunday). I'm not sure if Deb will have time to > work on it either since this was an unexpected situation. However I > will stay on this until I get it resolved, hopefully Monday. > > The good thing (if there is one) is that the only feature broken with > MasterView from this rails upgrade (AFAIK) is 'admin pages', which > isn't normally needed for production and there are equivalent > functionality available via command line with rake mv commands. > > And of course one can extract the tgz file I made available yesterday > evening (I updated it slightly this morning to fix another issue, same > location), however as mentioned before installing the tgz file > circumvents the config.enable_admin_pages configuration so in > production you will want to rename/remove the masterview_controller.rb > if you go with this approach. It is a brute force temporary fix, that > doesn't keep things as DRY as we'd like, but if you need to use it, > then it is there. One would just have to clean up those files when the > permanent fix is available to take advantage of new functionality. > > I apologize for any inconvenience this has caused anyone, we will > release a permanent fix as soon as possible. > > Thanks for your continued patience and support, > > Jeff > From jeff.barczewski at gmail.com Wed Aug 16 10:10:01 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Wed, 16 Aug 2006 09:10:01 -0500 Subject: [Masterview-devel] Update on progress for MasterView admin pages, rails 1.1.6 compatibility 8/16/06 Message-ID: <19cda190608160710v74d2b174if92128fa49228b63@mail.gmail.com> Well after further contemplation I thought of a better approach to the Rails 1.1.6 issue. Instead of jumping through all the hoops I was going to do, I realized that we could extend the safe_load_path method that Rails 1.1.6 added for finding controllers. I thought I would also check on how Rails engines patched their code and it turned out they are doing the same thing which confirms the approach. This becomes a much simpler fix, so I will try to have this implemented today. Sorry for the delay in getting this out, my personal schedule had been overflowing, but I am out of crunch now. I will send out the announcement when new release is ready. Thanks, Jeff From jeff.barczewski at gmail.com Sat Aug 19 16:17:00 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Sat, 19 Aug 2006 15:17:00 -0500 Subject: [Masterview-devel] [ANN] MasterView rails-optimized (x)html friendly template engine - Release 0.2.5 Message-ID: <19cda190608191317v6f7f5bd2jbfb643dffb9364e5@mail.gmail.com> MasterView Release 0.2.5 fixes compatibility of AdminPages with Rails 1.1.5+. MasterView is a rails-optimized (x)html friendly template engine plugin that provides another option to the existing rails view templates (rhtml and rxml). The main idea is to provide a template engine that would provide all the power of layouts, partials, and rails helpers but still be editable/styleable in a WYSIWYG editor. It was also a major goal that the syntax of these attribute directives be very similar to rails helpers so that one could intuitively start using MasterView with little learning curve other than knowing rails. MasterView was inspired by Amrita, Kwartz, Tapestry, Zope/PHP TAL, Liquid, and Web Objects but designed with a fresh approach and specifically targetted for rails users. Release Notes Release 0.2.5 The security fix of Rails 1.1.5 and 1.1.6 changed the way that controllers are found by limiting the load path. This caused the configurable MasterView admin page controller to not be located. MasterView release 0.2.5 fixes this incompatibility by extending the safe_load_paths. Fix rake mv:view_rhtml RHTML=foo/_bar.rhtml was not able to find partials Fix rails environment not being passed into configuration Added default generate filter which will add in a default generate directive if none is found in template Changed default_parser_options to be merged in with original set rather than to be absolute replacement Corrected example settings.rb win32 tidy_path to point to tidy.dll not tidy.exe. Release 0.2.4 Fixed apache2 scgi problem where masterview was not being loaded at startup. Added Interactive template console to admin pages for testing/learning how masterview directives worrk. PS. As this email is going out, masterview.org site is down for the addition of more memory, but should be up later today, but this does not affect getting the latest gem or source which is located on Rubyforge.org. Only the docs, pics, and videos reside on that masterview.org. From jeff.barczewski at gmail.com Thu Aug 24 19:23:15 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Thu, 24 Aug 2006 18:23:15 -0500 Subject: [Masterview-devel] Masterview & NVU In-Reply-To: References: Message-ID: <19cda190608241623t117ecf1cs626880ee63ca6df1@mail.gmail.com> Victor, Thanks for the nice comments and for emailing. I believe I know exactly what is going on for you. It turns out that NVU doesn't do a good job of writing out valid xhtml. No matter what you tell it to save as, it writes out html with the difference being that it leaves its tags unclosed. It will write out and never write out the closing tag nor will it close the link tag It does the same thing for many other tags too. So what is written out is not valid xhtml and the rexml parser complains with the error you saw below. Fortunately it is pretty easy to fix by installing Tidy. You can have MasterView run Tidy for you while loading or you can use Tidy manually to clean up the file after you save it in NVU. The latter being somewhat tedious and cutting down on productivity. So I would recommend that you let MasterView do it for you. This is pretty easy to setup. 1) If tidy is not already installed on your system you can get it from http://tidy.sourceforge.net/#binaries Make note of where the library libtidy.so (on *nix) or tidy.dll (on windows) is installed, we will need the path later in step 3. 2) Next you need the ruby gem that interfaces with it called tidy gem install tidy 3) Edit or create the config file in your RAILSAPP/config/masterview/settings.rb and put the following in it to enable tidy. And set the path to what you noted from step 1. config.default_parser_options[:tidy] = true config.tidy_path = '/usr/lib/libtidy.so' # *nix #config.tidy_path = 'c:/tidy/bin/tidy.dll' # Win32 Now when you fire restart your rails app, tidy should be enabled and you shouldn't have any further problems. MasterView will run the html through tidy which will fix those problems producing valid xhtml which can be parsed. This will all happen automatically once you install tidy and configure it for your app. Finally just so you know, I want to make this even easier for people so they don't have to do these steps manually. So just know we are working on simplifying all this. I may even try to open up the NVU source and fix it there, so it will generate xhtml properly and we won't need tidy at all. Of course I haven't seen that code yet, so I don't know what it will take. And for your final question, there are two schools of thought as to whether using WYSIWYG editor is best for ruby. One camp says its easier to just write ruby code directly which is what the rails core team has led people to do. That is fine, however it breaks down in the real world for most of the projects I have been involved in. First, I am slow at styling things manually. So unless you want a bare bones site that looks pretty plain, then it is going to take me a long time to go through and apply styles and formatting through all the various rails pages to get the look I want. Also since things are split out into so many files, you are having to jump over here for one thing then back there for another and you never know how it will look until you run it again. Contrast that to using something like NVU, which shows you exactly what it will look like as you change things. You know how it will layout and can easily manipulate and change things. Plus since MasterView is taking care of splitting it out into disparate files you can efficiently work in one per action. Another strong argument for MasterView is when your boss gives you a prototype html that he wants you to make real. With MV you simply take the prototype and add some directives to it and you are done. Your boss can simply re-edit/style it later if he wants to tweak things. To do this the pure rhtml way, would require you to dice up the file, putting pieces of the html here, and pieces there, you'd probably want to replace all the input tags with rails helpers so that you can take advantage of encapsulated rails functionality, so that is a bit of work, and when you are done, now you have to make each and every style change that is ever wanted... manually in those 20 files. So you can either let wysiwyg editors help you style things or you can do it all manually. Plus if it is as easy as using a wysiwyg editor to change style or wording of labels, then now you can give that to a graphic designer, your boss, or the legal department, you the programmer are no longer required to do the mundane things and can focus on what is fun, the programming and business logic. Even in a small company you might be working with external designers, or even the client themselves providing or tweaking html, they might even need to have their legal department review things before it goes live. So there are the main two arguments as I see them, obviously I am sided towards WYSIWYG editing or I wouldn't spend the time to make the project, but hopefully you can start to understand when it would be useful. Plus we are just getting started with the power of MasterView. The real power is going to be in creating your own custom directives or when people share powerful directives, then it is going to get real fun. (We're just finishing refactoring the directive api to make it dead simple to create directives.) By adding a directive to a piece of html might enable a ton of functionality that you would have had to manually type in. For instance we are planning for some directives that will take an ordinary table and make it a sortable, pageable, ajax'd grid . Even if you were to do this with ajax scaffold generator, it creates a mess of code that I would not want to maintain. With this custom directive, there won't be any mess it will be clean and very simple to enable. So stay tuned, this coming soon :-) Hope that answered your questions. If I can be of further assistance, let me know. And congrats on starting your new company, its fun to be running your own business and doing what you love. Rails is a fun technology to be using for that. Jeff On 8/24/06, Victor wrote: > Hello Jeff, > > My name is Victor and I'm based in NYC. With my partner Simon we recently > started a small 2-person consultancy to be focused on Ruby on Rails. I just > came across Masterview recently and want to thank you for having the > inspiration to write such a piece of software, because I've been thinking, > sure coding manually is said to be so powerful, but if things can be done > visually, why couldn't that be better and faster? > > I actually installed Masterview and NVU after seeing the video (which is > quite good for learning), but I quickly ran into the first error, which I > thought you might be familiar with (while I'm clueless). No matter what a > small change I make to " list.html" (generated by masterview) in NVU, > apparently it ends up being unrecognizable by Ruby: > Missing end tag for 'link' (got "head") Line: Position: Last 80 unconsumed > characters:
mv:replace="@content_for_la > > > I'd appreciate if you had any suggestions. Also, do you think it is > worthwhile using such a WYSIWYG editor with Ruby? > > Thanks Jeff, > Victor > innergysoftware.com > From jeff.barczewski at gmail.com Sun Aug 27 14:02:48 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Sun, 27 Aug 2006 13:02:48 -0500 Subject: [Masterview-devel] MasterView generation from existing rhtml In-Reply-To: <19cda190607070805l317f3e22yfdf41c272e599533@mail.gmail.com> References: <0e5401c698d9$b2aff900$0402a8c0@sergeyl> <19cda190606252222s37b821edk2841f541ddc08abd@mail.gmail.com> <0e6201c698f1$f4e53480$0402a8c0@sergeyl> <19cda190606260930u31de6dfcx523aa7c142fcafdb@mail.gmail.com> <000b01c69963$f00aa7c0$3e01a8c0@sergeyl> <19cda190606261618r3a44f874g95c649da55820b4d@mail.gmail.com> <007f01c6a153$75ab35b0$3e01a8c0@sergeyl> <19cda190607070805l317f3e22yfdf41c272e599533@mail.gmail.com> Message-ID: <19cda190608271102t7e07b6ci2af7169773eb6d59@mail.gmail.com> Sergey, Well I finally got the directive api refactoring done after a detour with the rails security fix and other things. So once I was done, I took a look at your code that you submitted and incorporated the bug fix and other directives into the code base. I rewrote them using hte new api. A couple of them namely text_area_tag and text_field_tag I left out since I thought by adding them would be confusing to people about which to use text_area or text_area_tag ... and I think that you can get the same effect of text_area_tag by simply using a mv:content directive and text_field_tag can be achieved by using mv:attr=":value => 'foo'". I also created an eval directive based off your idea with the silent directive, though I changed it a bit so that it puts the <% foo %> before the start of the elemnt and leaves the rest alone. I have credited your fix and ideas to you in the source. Anyway, thanks again for the submission. Sorry for merging it in, things should pick up now. All this is in subversion head and will go out with next gem/plugin release. Jeff > On 7/6/06, Sergey Shalatskiy wrote: > > Also, I fixed a couple of bugs and wrote some extra directives (mainly by > blatantly cutting and pasting your code). > > > > From jeff.barczewski at gmail.com Wed Aug 30 08:34:03 2006 From: jeff.barczewski at gmail.com (Jeff Barczewski) Date: Wed, 30 Aug 2006 07:34:03 -0500 Subject: [Masterview-devel] There is a minor bug when dealing with multiple directives in svn head of MasterView Message-ID: <19cda190608300534r5180d30ahb34f41a07a5b8087@mail.gmail.com> Deb, FYI. There is a minor bug when dealing with multiple directives in the svn head of MasterView. for instance if you hello what currently happens is that link_to is eating the <% if foo -%> that is supposed to be there. I have added a test case to track and am working on the fix. Shouldn't be too difficult. Jeff