From mneumann at ntecs.de Tue Feb 1 15:44:12 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Tue Feb 1 15:41:20 2005 Subject: [Wee-talk] [ANN] Wee 0.7.0 + Tutorial Videos Message-ID: <200502012144.12542.mneumann@ntecs.de> Hi, Wee 0.7.0 is out! In addition, I've recorded three tutorial sessions (screen captures). You can download the MPEGs via BitTorrent here: http://rubyforge.org/frs/?group_id=427&release_id=1528 I'm open for suggestions and thankful for comments. If possible, please let you BitTorrent client open. The first tutorial is about installing Wee, creating an initial skeleton application, simple forms and explains briefly decorations. The second is about subcomponents and backtracking. The third is on using Wee together with Og and a Postgres database. == Philosophy/Features of Wee http://rubytalk.com/128432 == Download and Installation http://rubyforge.org/projects/wee gem install wee Have a look at the 'wee' command! == ChangeLog Major changes (compared to 0.5.0) are: * Added ERB-templating. Example: # file: ~/components/main.rb class Test < Wee::Component # use template '~/components/main.tpl' template :render # use template '~/components/main.tpl-buttons' template :render_buttons end This allows you to use ERB-templates instead of the render_XXX methods. You can also call render_XXX methods from ERB, back and forth. The template file is relative to the file from which the 'template :symbol' call is executed. The template method optionally takes the two hash-parameters :file and :property. * Added "Pageless" mode. In pageless mode, the URL displayed in your browser always looks like "/app". The session id is stored as cookie and there is no page_id, hence "pageless" mode. No backtracking is performed! Example: require 'wee/pageless' app = Wee::Utils.app_for(YourMainComponent, :session => Wee::PagelessSession, :application => Wee::PagelessApplication) Wee::WEBrickAdaptor. request_class(Wee::PagelessRequest). register('/app' => app). start * Added named callbacks. Example: r.anchor.named_callback('test') { ... } will use 'test' as callback_id instead of a generic one. * added 'wee' binary which generates a sample application and recommended directory structure for you (similar to the 'rails' command). * Wee::Request: Refactored a lot. Use =/ instead of @ as delimeter for the request_handler_id/page_id part ('@' looks ugly in Konqueror, as it is displayed as '%40') * Implemented a new OgScaffolder, which now is more like the Rails one. Changes that break compatibility: * Wee::LiteralMethodCallback and Component#call: Additional arguments are now prepended instead of appended. Example: call MessageBox.new('msg'), :confirm, 1 def confirm(one, msgbox_result) end * Methods ImageTag#src_for and GenericTagBrush#css_class_for no more prepend 'img.' or 'css.' in front of the property name. * Method Wee::Utils.app_for: Removed the id_seed option. Use id_gen instead, which expects a IdGenerator object (default is now the much more secure Md5IdGenerator). * SelectListTag (r.select_list): NON-backwards-compatible change!!! If it's NOT a multiple select list, then the callback is called with the choosen value (instead of an array of one element). Method #selected requires a single value in the same way. No changes if it's a multiple-select list! For the full list of changes see: http://www.ntecs.de/viewcvs/viewcvs/Wee/trunk/ChangeLog?view=auto == Hello World require 'wee' class HelloWorld < Wee::Component def click @clicks = (@clicks || 0) + 1 end def render r.h1.onclick_callback(:click).with("Hello World!") r.text "#{ @clicks || 'No' } clicks" end end # And start the WEBrick web-server require 'wee/utils' require 'wee/adaptors/webrick' app = Wee::Utils.app_for { HelloWorld.new.add_decoration(Wee::PageDecoration.new("Hello World")) } Wee::WEBrickAdaptor.register('/app' => app).start Make sure you run this application with the -rubygems option. Then point your browser to http://localhost:2000/app and click on the h1-header. Every time you click on it, you should see that the number of clicks increases. Have fun! == Future? I'd like improve the integration of models with Wee. Regards, Michael From mneumann at ntecs.de Fri Feb 4 04:33:56 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Fri Feb 4 04:30:50 2005 Subject: [Wee-talk] Re: [Borges-users] setup w/ fcgi In-Reply-To: <42033C95.1030708@space.ch> References: <13104C637676A041A322C68134DE0FA8022A8E@helium.bcnm.majikoz.com> <4200A9CE.5050408@ntecs.de> <4200F682.1090607@space.ch> <4200FB31.2000606@ntecs.de> <4201004D.9040707@space.ch> <4201143F.2040101@ntecs.de> <42033C95.1030708@space.ch> Message-ID: <42034184.9070006@ntecs.de> CCing to wee-talk. Kaspar Schiess wrote: > Hello Michael, > >> Do you know how serious the memory "leaks" in Borges are? Is it just a >> few kb per click or much more. Do this memory get freed if the session >> terminates....? How did you test for the memory leak? Was it a simple >> "call" to another component, was it chained? > > > Actually we had gotten to the point of knowing more or less exactly what > sequence of clicks initiated the problem. If you are interested in the > gory details, I have archived them here, I can forward you 3-4 messages > that resume the issue concisely. > > Basically it's got something to do with this: > > require 'weakref' > class A > attr_accessor :child > > def foo > @child = B.new > @child.call > end > end > class B > def call > callcc do |cc| > @cont = cc > end > end > > def answer(obj) > @cont.call(obj) > end > end > def purge(array) > array.delete_if {|x| not x.weakref_alive?} > end > a = A.new > arr = [] > loop { a.foo; arr << WeakRef.new(a.child); purge(arr)} > > Be prepared to hit Ctrl+C quickly unless you like memory trashing for > hours on end. Ah thanks. I remember this one. Do you have an example where this memory leak occurs where no weakrefs are involved? Wee doesn't use weakrefs at all. The Seaside-way of snapshotting itself seems to have a "leak" BTW. > By repeating this sequence of clicks, you can basically consume any > amount of memory, thereby killing the server. So no, not just a few kbs. > I have a productive Borges server running where this is no issue since > users rarely hit the 'good' sequence - nevertheless I have to restart > the process every now and then. > > Still, I can't really say that I will program the web ever again without > continuations. Its the single best idea we've come up with in centuries. Yeah, that's good to hear. >> Well, Alexander Kellet is working on Rubydium. Everthing is pure Ruby. >> Of course progress is very slow, and I don't think it will ever become >> main-stream. > > That doesn't solve the issue, unless you are prepared to rewrite all the > extensions in Ruby. Which is probably difficult/impossible for a large > number of extensions. The trouble is that you can dump a continuation > easily, but then you won't be able to load it back in since stack might > look different; the c extensions might have allocated heap memory that > you'd have to allocate again (at the very same addresses), etc.. I guess > dumping a process image (ie: core) would be a solution, albeit a very > heavy weighted one. Well, his plan is to write the whole interpreter in Ruby itself, optimizing on the fly. And yes, C extensions would have to be rewritten (that's why he's interested in Ruby2C, which will make it easier to port them to Rubyidium). Regards, Michael From ruby at roblally.plus.com Fri Feb 4 18:28:10 2005 From: ruby at roblally.plus.com (Rob Lally) Date: Fri Feb 4 18:25:11 2005 Subject: [Wee-talk] TDD and Wee Message-ID: <4204050A.1000601@roblally.plus.com> I've been playing around with Wee and I like what I see. I am a big fan of TDD and I've been trying to figure out how I would go about writing unit tests for components in a Wee application. Any suggestions or experience reports? R. From dlvl at mail.kz Wed Feb 9 02:04:55 2005 From: dlvl at mail.kz (Vladimir) Date: Wed Feb 9 02:07:11 2005 Subject: [Wee-talk] Upload file? Message-ID: Hello I for a long time studied prospects of development of continuations and have come to that what is it the most actual system. I "lamer" in ruby and consequently at me will be many questions:) I was interested by yours ??c???? wee with reference to web and consequently I began studying from it. Has done as it is written in "readme": 1) gem install wee 2) wee create-og e:\test 3) Has modified db.rb DB_CONFIG = { :address => 'localhost', :database => 'weedemo', :backend => 'mysql', :user => 'root', :password => 'root', :connection_count => 10 } 4) ruby run.rb All has earned hurrah. Further started to study source codes. Now questions: 1) How to make loading a file in mysql having altered your example? 2) How to connect apache and wee (as at rails?)? 3) I can not load your lessons? A server "timeout"? You could not give the direct link? Excuse me for my English:) From mneumann at ntecs.de Sun Feb 13 18:10:20 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Sun Feb 13 18:06:54 2005 Subject: [Wee-talk] Upload file? In-Reply-To: References: Message-ID: <420FDE5C.5070905@ntecs.de> Vladimir wrote: > Hello > I for a long time studied prospects of development of continuations and > have come to that what is it the most actual system. > I "lamer" in ruby and consequently at me will be many questions:) > I was interested by yours ??c???? wee with reference to web and > consequently I began studying from it. > Has done as it is written in "readme": > 1) gem install wee > 2) wee create-og e:\test > 3) Has modified db.rb > DB_CONFIG = { > :address => 'localhost', > :database => 'weedemo', > :backend => 'mysql', > :user => 'root', > :password => 'root', > :connection_count => 10 > } > 4) ruby run.rb > All has earned hurrah. Further started to study source codes. > Now questions: > 1) How to make loading a file in mysql having altered your example? Not sure I understand you correctly. Do you want to a binary file from mysql database? > 2) How to connect apache and wee (as at rails?)? Well, I've not yet written a mod_ruby or CGI adaptor for Wee. But, you could use mod_proxy and pass requests from the apache through a WEBrick server running the Wee application. > 3) I can not load your lessons? A server "timeout"? You could not give > the direct link? What exatcly have your tried? Bittorrent? Regards, Michael From mneumann at ntecs.de Sun Feb 13 18:40:54 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Sun Feb 13 18:37:26 2005 Subject: [Wee-talk] TDD and Wee In-Reply-To: <4204050A.1000601@roblally.plus.com> References: <4204050A.1000601@roblally.plus.com> Message-ID: <420FE586.9060201@ntecs.de> Rob Lally wrote: > I've been playing around with Wee and I like what I see. I am a big fan > of TDD and I've been trying to figure out how I would go about writing > unit tests for components in a Wee application. Any suggestions or > experience reports? I've used my WWW::Mechanize library to test Wee applications. I also plan to avoid running a WEBrick server for testing the application. Maybe take a look at Seaside's Testing Framework. Regards, Michael From mneumann at ntecs.de Thu Feb 17 02:27:09 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Thu Feb 17 02:23:34 2005 Subject: [Wee-talk] Re: Wee web-framework. It's great! In-Reply-To: References: <1108524668.411382.248100@z14g2000cwz.googlegroups.com> <421348F1.8030800@ntecs.de> <42134F27.5040908@mktec.com> <42135525.6000207@ntecs.de> <42135907.60707@ntecs.de> Message-ID: <4214474D.6020707@ntecs.de> Joao Pedrosa wrote: > Hi, > > I think it's important to say that the dynamic nature of Ruby > contributes to a nice development environment for Wee, that is, > whenever we are editing one of the components, and we save it, Wee > tries to reload it. If it had to be compiled it would slow this cycle > a little bit. And worse, because the compiler would complain at the > first sign of incorrectness, making errors appear when we surely new > that the component was not ready yet for compilation. Behind the > scenes, Wee remaps methods and creates components only when it's > necessary (time saving feature!) > > It makes it appear that I'm editing an HTML and not a Ruby file. > That's it! Lovely. > > Actually, it has less to do with editing an HTML and more with > creating the business logic of our application. The HTML is generated > automagically for us. > > Look at this: > > r.text_input.callback{|v| do_something_with v}.value(@original_value) And for assigning it back to @original_value one can use this short-cut: r.text_input.callback{|@original_value|}.value(@original_value) Yeah, this looks ugly ;-) Or alternativly without the need to create a block: r.text_input.callback(:instance_variable_set, :original_value) > That's all that's needed to create the INPUT TYPE=TEXT object and at > the same time fill it with the default value and save its returning > value. > > Add a submit button to it and you have your FORM. > > r.submit_button.callback{save_edition}.value('Save Edition') > > That's how everything is created, generally. There is more to it, > because it needs to support the simple and the complex, so it > "scales." Just want to add, that this is only *one way* to generate HTML in Wee. You can use other renderers simply by overwriting method #renderer_class of your component class. Or you could use ERb-templates directly: # c.rb class MyComponent < Wee::Component template :render end # c.tpl
    <% (1..10).each do |i| %>
  • <%= i %>
  • <% end %>
You can even define "block"-templates (this of course is a bad example, as templates do not accept parameters): # c.rb class MyComponent < Wee::Component template :render tempalte :render_item end # c.tpl
    <% (1..10).each do |@i| %> <% render_item %> <% end %>
# c.tpl-item
  • <%= @i %>
  • Or you can mix templates with programmatic html generation: # c.rb class MyComponent < Wee::Component template :render def render_item(i) r.li.with(i) end end # c.tpl
      <% (1..10).each do |i| %> <% render_item(i) %> <% end %>
    Regards, Michael From matt.bowen at farweststeel.com Thu Feb 17 09:42:10 2005 From: matt.bowen at farweststeel.com (Matt Bowen) Date: Fri Feb 18 03:51:45 2005 Subject: [Wee-talk] RE: Wee web-framework. It's great! Message-ID: Michael: Can I use Wee to access Oracle? I recently checked out Rails and was pretty impressed. The ActiveRecord package has recently been patched to support Oracle -- goods news. You recently mentioned that supporting ActiveRecord wouldn't be terribly difficult, however, advocated trying out Og. Does Og support Oracle? Thanks. - Matt -----Original Message----- From: Michael Neumann [mailto:mneumann@ntecs.de] Sent: Wednesday, February 16, 2005 11:27 PM To: ruby-talk@ruby-lang.org Cc: wee-talk@rubyforge.org Subject: Re: Wee web-framework. It's great! Joao Pedrosa wrote: > Hi, > > I think it's important to say that the dynamic nature of Ruby > contributes to a nice development environment for Wee, that is, > whenever we are editing one of the components, and we save it, Wee > tries to reload it. If it had to be compiled it would slow this cycle > a little bit. And worse, because the compiler would complain at the > first sign of incorrectness, making errors appear when we surely new > that the component was not ready yet for compilation. Behind the > scenes, Wee remaps methods and creates components only when it's > necessary (time saving feature!) > > It makes it appear that I'm editing an HTML and not a Ruby file. > That's it! Lovely. > > Actually, it has less to do with editing an HTML and more with > creating the business logic of our application. The HTML is generated > automagically for us. > > Look at this: > > r.text_input.callback{|v| do_something_with v}.value(@original_value) And for assigning it back to @original_value one can use this short-cut: r.text_input.callback{|@original_value|}.value(@original_value) Yeah, this looks ugly ;-) Or alternativly without the need to create a block: r.text_input.callback(:instance_variable_set, :original_value) > That's all that's needed to create the INPUT TYPE=TEXT object and at > the same time fill it with the default value and save its returning > value. > > Add a submit button to it and you have your FORM. > > r.submit_button.callback{save_edition}.value('Save Edition') > > That's how everything is created, generally. There is more to it, > because it needs to support the simple and the complex, so it > "scales." Just want to add, that this is only *one way* to generate HTML in Wee. You can use other renderers simply by overwriting method #renderer_class of your component class. Or you could use ERb-templates directly: # c.rb class MyComponent < Wee::Component template :render end # c.tpl
      <% (1..10).each do |i| %>
    • <%= i %>
    • <% end %>
    You can even define "block"-templates (this of course is a bad example, as templates do not accept parameters): # c.rb class MyComponent < Wee::Component template :render tempalte :render_item end # c.tpl
      <% (1..10).each do |@i| %> <% render_item %> <% end %>
    # c.tpl-item
  • <%= @i %>
  • Or you can mix templates with programmatic html generation: # c.rb class MyComponent < Wee::Component template :render def render_item(i) r.li.with(i) end end # c.tpl
      <% (1..10).each do |i| %> <% render_item(i) %> <% end %>
    Regards, Michael From matt.bowen at farweststeel.com Thu Feb 17 17:06:16 2005 From: matt.bowen at farweststeel.com (Matt Bowen) Date: Fri Feb 18 03:52:01 2005 Subject: [Wee-talk] Wee + Oracle? Message-ID: Can I use Wee to access Oracle? I'm aware that the ActiveRecord package used by Rails has recently been patched to support Oracle. Michael recently mentioned that supporting ActiveRecord wouldn't be terribly difficult (for Michael :-)), however, advocated trying out Og. It doesn't sound like Og supports Oracle out-of-the-box, but George Moschovitis hinted that writing such an adapter wouldn't be too hard. I apologize for originally asking this question by hijacking a previous Wee thread about how great of a framework it is -- a breach of etiquette I think. Anyway, I work in an Oracle shop and would love to experiment with Wee against some real world data (not mission-critical just yet... *grin*). Thank you. - Matt Bowen mbowen@farweststeel.com From mneumann at ntecs.de Tue Feb 22 06:25:16 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Tue Feb 22 06:21:32 2005 Subject: [Wee-talk] Implementing resources Message-ID: <421B169C.1020308@ntecs.de> Hi Avi, I'm now implementing (again) resources. What makes a resource in Seaside? * content-type * body Anything else? You can't specify an expiration for a resource, right? Will they live forever in Seaside? How about this: You can specify an expires_after (seconds) for a resource, but this is not part of the equality (==) test (only content-type and body), so that the same resource with different expires_after will not generate a new resource object in the applications request_handler cache. Instead the maximum of the expires_after is choosen. Another questions: How do you find an already existing resource with the same content? Do you iterate over the request handlers (that's not so good as it blocks other requests from being handled), or do you store all resources inside another array of an application? Do you distinguish a Resouce from a ResourceHandler (I mean, whether you use two classes)? Regards, Michael From mneumann at ntecs.de Wed Feb 23 09:13:33 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Wed Feb 23 09:09:45 2005 Subject: [Wee-talk] Re: My second Wee example, together with some more things. In-Reply-To: References: <421C4C2F.7000409@ntecs.de> <421C794A.6050101@ntecs.de> Message-ID: <421C8F8D.8050605@ntecs.de> Joao Pedrosa wrote: > Hi, > > >>Well, you call @tread in Topics. If you do this, then of course the >>Topics component will not render itself and will not react on actions >>(until you answer from @tread). >>You should not use call in this situation, use #render and if statements. > > > Done, thanks. :-) Pretty easy once we have decided about it. hehe. 6 > lines have been changed for this. > > About turning off the Session and creating and interpreting custom > URLs, could you give me some direction beforehand? It would be great > to try this out as soon as possible, because URL is a pending issue to > me. :-) I'm not sure what the best way of doing this. Seaside has an updateUrl method, which is called for each component (similar to process_callbacks), and which can be used to modify the URL after an action has occured and processed, but before the redirect to the render phase is done. For example, if you have the following component tree: Topics (topic_id) | |-- Thread (thread_id) the Topics component update_url method, could append "/#{ topic_id }" to the current url, then the Thread component could add "/#{ thread_id }", so at the end we have: /app/1/2/=/session_id/... where 1 is the topic_id and 2 is the thread_id. Of course this is only one part of the story. The other is to reconstruct the component tree from the URL (only neccessary if the session has timed-out). That should be simple to implement, but I've not yet done this (there's no update_url method yet). If you like, take a look at wee/core/session.rb (this file needs refactoring ;-), method handle_new_page_view, the line which starts with "redirect_url". If you use there a different redirect_url, this will show up in your browser. Additionally, you'd need to modify wee/request.rb, methods build_url and parse_path, to remember the extra URL information that you have specified (@app_path is used in build_url, whereas you'd need to use full_app_path of method parse_path). I've currently (the next weeks) not the time to try this out on my own. But I'd like to add this to Wee in the future. Patches are welcome ;-) To turn off displaying the session inside the URL, use Pageless mode. But be aware that this also disabled backtracking. See the ChangeLog for informations on how to use pageless mode. Regards, Michael From mneumann at ntecs.de Thu Feb 24 04:28:38 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Thu Feb 24 04:24:51 2005 Subject: [Wee-talk] Re: My second Wee example, together with some more things. In-Reply-To: <421C8F8D.8050605@ntecs.de> References: <421C4C2F.7000409@ntecs.de> <421C794A.6050101@ntecs.de> <421C8F8D.8050605@ntecs.de> Message-ID: <421D9E46.6090608@ntecs.de> Michael Neumann wrote: > Joao Pedrosa wrote: > >> Hi, >> >> >>> Well, you call @tread in Topics. If you do this, then of course the >>> Topics component will not render itself and will not react on actions >>> (until you answer from @tread). >>> You should not use call in this situation, use #render and if >>> statements. >> >> >> >> Done, thanks. :-) Pretty easy once we have decided about it. hehe. 6 >> lines have been changed for this. >> >> About turning off the Session and creating and interpreting custom >> URLs, could you give me some direction beforehand? It would be great >> to try this out as soon as possible, because URL is a pending issue to >> me. :-) > > > I'm not sure what the best way of doing this. Seaside has an updateUrl > method, which is called for each component (similar to > process_callbacks), and which can be used to modify the URL after an > action has occured and processed, but before the redirect to the render > phase is done. There probably an easier way to accomplish that. Wee already supports named_callbacks: r.anchor.named_callback('test') { ... } All you have to do is, after the action was invoked, to put the action-callback name into the regual URL, e.g. from # before action was invoked (URL generated from render phase) /app/?test to: # after action was invoked (redirected URL) /app/test That should be pretty easy to do. Regards, Michael From joaopedrosa at gmail.com Sat Feb 26 10:15:10 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Sat Feb 26 10:11:14 2005 Subject: [Wee-talk] re: Comparing the underlying models of Wee and Rails Message-ID: Hi, Nice post Michael. I'm almost at the same page as you, now. :-) It was good to learn about the redirection for the rendering phase, because I had seen WEBrick needing to handle the request twice when I submitted an action. A Rails like attitude might be good, so the controller solution might be a good choice. It made me think about making every component a mini-controller, so I just need to give the component a unique name on its creation (or in the simpler case, maybe one could be generated automatically), and use some naming convention for the controller triggered methods. Like: "under_control_#{string}" "uc_#{string}" or whatever. And pass to it the parameter stored in the URL. There could be a default method that tries to handle in the case of the needed "uc_etc" does not exist. "under_control_missing" In case there is a child with the given name, let the child handle the "uc_" call. I would prefer something like this to a more "standard" way. It seems more automatic. But I'm not sure about the WEBrick, URLs and Components interaction yet. :-) Yesterday I was messing with Wee and at a point WEBrick couldn't redirected successfully anymore, after I changed something in the "build_path" and the session expired. I made the session expire after 30 seconds for the tests. So, I don't have a working example of this yet. Cheers, Joao From mneumann at ntecs.de Sat Feb 26 11:45:22 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Sat Feb 26 11:41:13 2005 Subject: [Wee-talk] re: Comparing the underlying models of Wee and Rails In-Reply-To: References: Message-ID: <4220A7A2.4020605@ntecs.de> Joao Pedrosa wrote: > Hi, > > Nice post Michael. I'm almost at the same page as you, now. :-) check out my latest commit or read about it in the ChangeLog: http://www.ntecs.de/viewcvs/viewcvs/Wee/trunk/ChangeLog?rev=585&view=auto * wee/request.rb, test/test_request.rb, wee/pageless/request.rb, wee/session.rb, wee/pageless/session.rb, wee/renderer/html/canvas.rb, wee/renderer/html/brushes.rb: - request delimeter changed to /___/ (looks nicer) - refactored Request#build_url, which now takes a hash and remembers already specified values - A Request knows now itself whether it's a action or a render request. - added Request#info attribute. This is a part of the URL that you can use for your own purposes. It is remembered across requests unless you overwrite its value. This means, that you can now have a userdefined part of the URL for purposes like described in my blog entry: without info field: http://127.0.0.1:2000/app/___/437764/1 with info: http://127.0.0.1:2000/app/userdefined/whatever/you want/___/437764/1 In your root component, you can now read this info field with: context.request.info # => "userdefined/whatever/you want" In lib/wee/renderer/html/*.rb, have a look at: Request#build_url Pass in :info => 'your userdefined info' as additional hash-argument to overwrite the info field. This is the first step towards the goal. Next we need a way to specify this info from our components. One approach is to modify the html renderer, e.g. r.anchor.url(:info => 'blog/list/3') Or we could use Component#update_url, which recursively calls all sub-components, so that each of them can add something to the URL. The second approach needs to know, which 'controller' was last active and which action it has invoked (it's merely oriented on the current state of the component-tree, not the action that was performed). Therefore the first solution is probably easier. In my blog entry, I have told that I'd actually use the URL arguments (e.g. /blog/show/3, use the 3 to query the database). I'm no more sure whether this is the right way to go. Maybe it's better to leave this only for bookmarking purposes (=> use it only in the case the session has timed out)? Regards, Michael From joaopedrosa at gmail.com Sat Feb 26 12:12:45 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Sat Feb 26 12:08:49 2005 Subject: Fwd: [Wee-talk] re: Comparing the underlying models of Wee and Rails In-Reply-To: References: <4220A7A2.4020605@ntecs.de> Message-ID: ---------- Forwarded message ---------- From: Joao Pedrosa Date: Sat, 26 Feb 2005 14:08:01 -0300 Subject: Re: [Wee-talk] re: Comparing the underlying models of Wee and Rails To: Michael Neumann Hi, On Sat, 26 Feb 2005 17:45:22 +0100, Michael Neumann wrote: > Joao Pedrosa wrote: > > Hi, > > > > Nice post Michael. I'm almost at the same page as you, now. :-) > > check out my latest commit or read about it in the ChangeLog: > > http://www.ntecs.de/viewcvs/viewcvs/Wee/trunk/ChangeLog?rev=585&view=auto > > * wee/request.rb, test/test_request.rb, wee/pageless/request.rb, > wee/session.rb, wee/pageless/session.rb, > wee/renderer/html/canvas.rb, wee/renderer/html/brushes.rb: > > - request delimeter changed to /___/ (looks nicer) > > - refactored Request#build_url, which now takes a hash and > remembers already specified values > > - A Request knows now itself whether it's a action or a render > request. > > - added Request#info attribute. This is a part of the URL that > you can use for your own purposes. It is remembered across > requests unless you overwrite its value. > > This means, that you can now have a userdefined part of the URL for > purposes like described in my blog entry: > > without info field: > > http://127.0.0.1:2000/app/___/437764/1 > > with info: > > http://127.0.0.1:2000/app/userdefined/whatever/you want/___/437764/1 > > In your root component, you can now read this info field with: > > context.request.info # => "userdefined/whatever/you want" > > In lib/wee/renderer/html/*.rb, have a look at: > > Request#build_url > > Pass in :info => 'your userdefined info' as additional hash-argument to > overwrite the info field. > > This is the first step towards the goal. Next we need a way to specify > this info from our components. One approach is to modify the html > renderer, e.g. > > r.anchor.url(:info => 'blog/list/3') > > Or we could use Component#update_url, which recursively calls all > sub-components, so that each of them can add something to the URL. > > The second approach needs to know, which 'controller' was last active > and which action it has invoked (it's merely oriented on the current > state of the component-tree, not the action that was performed). > Therefore the first solution is probably easier. > > In my blog entry, I have told that I'd actually use the URL arguments > (e.g. /blog/show/3, use the 3 to query the database). I'm no more sure > whether this is the right way to go. Maybe it's better to leave this > only for bookmarking purposes (=> use it only in the case the session > has timed out)? All this is good. I haven't settled on the mechanics of the URL composition yet. And I need the URLs to still work after the server has been restarted. Yesterday when I was messing with Wee I was approaching it from the r.anchor component. Now I want approach it from the URL. ;-) Your post was very interesting to make me retry this from another standpoint. Cheers, Joao From joaopedrosa at gmail.com Sat Feb 26 23:53:08 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Sat Feb 26 23:49:12 2005 Subject: [Wee-talk] re: Comparing the underlying models of Wee and Rails In-Reply-To: References: <4220A7A2.4020605@ntecs.de> Message-ID: Hi, > All this is good. I haven't settled on the mechanics of the URL > composition yet. And I need the URLs to still work after the server > has been restarted. Yesterday when I was messing with Wee I was > approaching it from the r.anchor component. Now I want approach it > from the URL. ;-) Your post was very interesting to make me retry this > from another standpoint. I have something working already. I will need your help though to get everything 100%. You will need to make a lot of decisions like should the components have parents so we can go backwards to save the URL (it's working like this), what's the best way to trigger the method which will interpret the information saved in the URL (currently, it's triggering at the wrong moment also), what are the best method names, add some code documentation for what has been added. I just tested the bookmark and it worked. Let me remove some redundant debugging code (lots of "p"s) and I will post what has been changed so far. After that I may prepare an independent example because I'm using that JoS forum of mine which is at http://201.9.179.193:81/app (but will change with the dynamic IP :-) Well, give some more time to clean this up. The code that you added yesterday came in handy, btw. :-) Cheers, Joao From joaopedrosa at gmail.com Sun Feb 27 01:49:04 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Sun Feb 27 01:45:06 2005 Subject: [Wee-talk] URL for Wee - Work in Progress In-Reply-To: References: Message-ID: (Wee users shouldn't try to use this yet.) Ok, I'm attaching a diff and my changed Wee. You need to revise it Michael and we need to shakedown the remaining issues. This is the Wee with the changed URL support: http://ruby.com.br/~pedrosa/w_url_dev.tar.gz My goals are very close to be achieved with the current code. They are: 1. Each component has a name which defaults to the name of the class in lower case with "::" substituted to "_". The name of the component can be changed by the user at any time. This allows for some flexibility because this name is going to appear in the new custom URL. If for some reason the user decides to change this name to nil, it should work also, in the name of maximum flexibility. The name of the component is important because it's used to provide the custom URL information to the right child of the component. The only component that does not need a name is the root component, because in these circunstances it's not ambiguous. 2. Each component has a parent component, because it allows for backwards traversal of the components in the construction of the custom URL. The parent component is added automatically in the "add_child" method. I still need to add this to the @children Array, but Michael needs to think about this too. :-) 3. The custom URL can be used by several components which work as (sub)controllers. At current, any component can store and retrieve information of the URL, as long as an action has been triggered on it. So considering a tree of components, where for the next component opens after a click on its parent, the URL information can be stored in the right order, but this is only meaningful for bookmarks and after the session has expired. When the Session is active, Wee takes care of everything for us. ---------------- Current problems: 1. It seems that the Cookie is not being reset properly with the custom URLs on, after the Session expires. I'm not sure how to fix this yet. Only pertinent in the Pageless scenario. 2. After the Session has expired, the custom URL needs to be used, but I don't know what's the right moment to call the handling method. Pageless needs this too. 3. The custom URL is built after actions occur, but I'm not sure if the "active component" can be always detected and used to traverse the components. Currently I'm using what's available in the LiteralCallback "obj". ---------------- Todo: 1. I need to create some examples which use these features. I need at least two. One for the Pageless scenario. ---------------- My personal opinion: It's interesting to use Wee in this dual mode. If this works 100%, it could even be further improved with more syntatic sugar, by combining some methods. Pageless leaves the URL as clean as it gets for your creativity. :-) Maybe farther down the road, the Session ID could be embedded in the HTML. Wee rocks. :-) And now I know a little bit more about it. Cheers, Joao -------------- next part -------------- diff -r wee_verygood/lib/wee/adaptors/webrick.rb wee/lib/wee/adaptors/webrick.rb 77d76 < p 'putttttzzzzzzzzzzzzzzzzzzz webrick' diff -r wee_verygood/lib/wee/application.rb wee/lib/wee/application.rb 53d52 < p '____request_handler_id____', request_handler_id 58,59d56 < p '_____request_handler_id.nil?_____' < 88,89d84 < p '_____request_handler.nil?_____' < 97,98d91 < < p '_____!request_handler.alive?_____' 107,108d99 < p '____request_handler.handle_request(context)_____' < 149,150c140 < p '_____request_handler_expired______' < context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", context.request.build_url.gsub(/\/___.*/, '')) #context.request.application_path) --- > context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", context.request.application_path) diff -r wee_verygood/lib/wee/core/callback.rb wee/lib/wee/core/callback.rb 107,108d106 < attr_reader :obj < diff -r wee_verygood/lib/wee/core/component.rb wee/lib/wee/core/component.rb 68,132d67 < #override to provide custom info handling < def uc info < end < < def handle_uc params < if not params.empty? < handled = false < children.each do |child| < if child.__name == params[0] < params.shift < child.handle_uc params < handled = true < end < end < if not handled < if respond_to?(m = "uc_#{params[0]}".to_sym) < method_params = params.clone < method_params.shift < send(m, method_params) < params.shift < else < send(:uc, params) < end < if not params.empty? < children.each do |child| < if child.__name == params[0] < params.shift < child.handle_uc params < end < end < end < end < end < end < < def __name < @__name < end < < def __name= v < @__name = v < end < < def set_name v < @__name = v < end < < # Override to provide a custom path < def custom_path < [] < end < < def rebuild_custom_path < path = ([self.__name] << custom_path).flatten < component = self < while component = component.__parent < cp = ([component.__name] << component.custom_path).flatten < path = cp + path < end < p "_____paaaaaaaath: #{path}" < path.shift # throws away the root component name < path.compact # any nil in here? not anymore. < path < end < 147,148d81 < @__name = self.class.to_s.downcase.gsub('::', '_') < @__parent = nil 184d116 < child.set_parent = self 187,198d118 < < def __parent= v < @__parent = v < end < < def __parent < @__parent < end < < def set_parent= v < @__parent = v < end diff -r wee_verygood/lib/wee/pageless/application.rb wee/lib/wee/pageless/application.rb 3,5c3 < context.request.request_handler_id = nil #redirection webrick bug? set to nil! < p '_____pageless request_handler_expired______' < context.response = Wee::RedirectResponse.new( context.request.build_url ) #context.request.application_path ) --- > context.response = Wee::RedirectResponse.new(context.request.application_path) diff -r wee_verygood/lib/wee/pageless/session.rb wee/lib/wee/pageless/session.rb 32,34d31 < < p '_____@context.request.fields.empty?______' < p "_____@context.request: #{@context.request.info}" 44,45d40 < url_info = @context.request.info < @root_component.handle_uc url_info ? url_info.split('/') : [] 51,52d45 < p 'else _____@context.request.fields.empty?______' < 84d76 < p '____pageless handle_new_page_view_____' diff -r wee_verygood/lib/wee/requesthandler.rb wee/lib/wee/requesthandler.rb 76c76 < @expire_after = 30 #30*60 # The default is 30 minutes of inactivity --- > @expire_after = 30*60 # The default is 30 minutes of inactivity diff -r wee_verygood/lib/wee/request.rb wee/lib/wee/request.rb 15c15 < attr_accessor :info --- > attr_reader :info diff -r wee_verygood/lib/wee/session.rb wee/lib/wee/session.rb 75d74 < p '______22 process_request______' 77,78d75 < < p '____ 22 @context.request.page_id.nil?_____' 87,88d83 < p '____ 22 @page = @page_store.fetch(@context.request.page_id, false)_____' < 97,98d91 < p '____ 22 @context.request.render?' < 107,108d99 < url_info = @context.request.info < @root_component.handle_uc url_info ? url_info.split('/') : [] 114,115d104 < p '____ 22 else_____' < 121,123d109 < # url_info = @context.request.info < # @root_component.handle_uc url_info ? url_info.split('/') : [] < 136,141d121 < < cb = callback_stream.all_of_type(:action).first.first < if cb.respond_to?(:obj) and active_component = cb.obj < custom_path = active_component.rebuild_custom_path.join('/') < @context.request.info = custom_path.size > 0 ? custom_path : nil < end 197d176 < p '_____handle_new_page_view_____' 203,204d181 < # url_info = @context.request.info < # @root_component.handle_uc url_info ? url_info.split('/') : [] From joaopedrosa at gmail.com Sun Feb 27 01:43:58 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Sun Feb 27 07:35:17 2005 Subject: [Wee-talk] URL for Wee - Work in Progress Message-ID: Wee users shouldn't try to use this yet. Ok, I'm attaching a diff and my changed Wee. You need to revise it Michael and we need to shakedown the remaining issues. My goals are very close to be achieved with the current code. They are: 1. Each component has a name which defaults to the name of the class in lower case with "::" substituted to "_". The name of the component can be changed by the user at any time. This allows for some flexibility because this name is going to appear in the new custom URL. If for some reason the user decides to change this name to nil, it should work also, in the name of maximum flexibility. The name of the component is important because it's used to provide the custom URL information to the right child of the component. The only component that does not need a name is the root component, because in these circunstances it's not ambiguous. 2. Each component has a parent component, because it allows for backwards traversal of the components in the construction of the custom URL. The parent component is added automatically in the "add_child" method. I still need to add this to the @children Array, but Michael needs to think about this too. :-) 3. The custom URL can be used by several components which work as (sub)controllers. At current, any component can store and retrieve information of the URL, as long as an action has been triggered on it. So considering a tree of components, where for the next component opens after a click on its parent, the URL information can be stored in the right order, but this is only meaningful for bookmarks and after the session has expired. When the Session is active, Wee takes care of everything for us. ---------------- Current problems: 1. It seems that the Cookie is not being reset properly with the custom URLs on, after the Session expires. I'm not sure how to fix this yet. Only pertinent in the Pageless scenario. 2. After the Session has expired, the custom URL needs to be used, but I don't know what's the right moment to call the handling method. Pageless needs this too. 3. The custom URL is built after actions occur, but I'm not sure if the "active component" can be always detected and used to traverse the components. Currently I'm using what's available in the LiteralCallback "obj". ---------------- Todo: 1. I need to create some examples which use these features. I need at least two. One for the Pageless scenario. ---------------- My personal opinion: It's interesting to use Wee in this dual mode. If this works 100%, it could even be further improved with more syntatic sugar, by combining some methods. Pageless leaves the URL as clean as it gets for your creativity. :-) Maybe farther down the road, the Session ID could be embedded in the HTML. Wee rocks. :-) And now I know a little bit more about it. Cheers, Joao -------------- next part -------------- diff -r wee_verygood/lib/wee/adaptors/webrick.rb wee/lib/wee/adaptors/webrick.rb 77d76 < p 'putttttzzzzzzzzzzzzzzzzzzz webrick' diff -r wee_verygood/lib/wee/application.rb wee/lib/wee/application.rb 53d52 < p '____request_handler_id____', request_handler_id 58,59d56 < p '_____request_handler_id.nil?_____' < 88,89d84 < p '_____request_handler.nil?_____' < 97,98d91 < < p '_____!request_handler.alive?_____' 107,108d99 < p '____request_handler.handle_request(context)_____' < 149,150c140 < p '_____request_handler_expired______' < context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", context.request.build_url.gsub(/\/___.*/, '')) #context.request.application_path) --- > context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", context.request.application_path) diff -r wee_verygood/lib/wee/core/callback.rb wee/lib/wee/core/callback.rb 107,108d106 < attr_reader :obj < diff -r wee_verygood/lib/wee/core/component.rb wee/lib/wee/core/component.rb 68,132d67 < #override to provide custom info handling < def uc info < end < < def handle_uc params < if not params.empty? < handled = false < children.each do |child| < if child.__name == params[0] < params.shift < child.handle_uc params < handled = true < end < end < if not handled < if respond_to?(m = "uc_#{params[0]}".to_sym) < method_params = params.clone < method_params.shift < send(m, method_params) < params.shift < else < send(:uc, params) < end < if not params.empty? < children.each do |child| < if child.__name == params[0] < params.shift < child.handle_uc params < end < end < end < end < end < end < < def __name < @__name < end < < def __name= v < @__name = v < end < < def set_name v < @__name = v < end < < # Override to provide a custom path < def custom_path < [] < end < < def rebuild_custom_path < path = ([self.__name] << custom_path).flatten < component = self < while component = component.__parent < cp = ([component.__name] << component.custom_path).flatten < path = cp + path < end < p "_____paaaaaaaath: #{path}" < path.shift # throws away the root component name < path.compact # any nil in here? not anymore. < path < end < 147,148d81 < @__name = self.class.to_s.downcase.gsub('::', '_') < @__parent = nil 184d116 < child.set_parent = self 187,198d118 < < def __parent= v < @__parent = v < end < < def __parent < @__parent < end < < def set_parent= v < @__parent = v < end diff -r wee_verygood/lib/wee/pageless/application.rb wee/lib/wee/pageless/application.rb 3,5c3 < context.request.request_handler_id = nil #redirection webrick bug? set to nil! < p '_____pageless request_handler_expired______' < context.response = Wee::RedirectResponse.new( context.request.build_url ) #context.request.application_path ) --- > context.response = Wee::RedirectResponse.new(context.request.application_path) diff -r wee_verygood/lib/wee/pageless/session.rb wee/lib/wee/pageless/session.rb 32,34d31 < < p '_____@context.request.fields.empty?______' < p "_____@context.request: #{@context.request.info}" 44,45d40 < url_info = @context.request.info < @root_component.handle_uc url_info ? url_info.split('/') : [] 51,52d45 < p 'else _____@context.request.fields.empty?______' < 84d76 < p '____pageless handle_new_page_view_____' diff -r wee_verygood/lib/wee/requesthandler.rb wee/lib/wee/requesthandler.rb 76c76 < @expire_after = 30 #30*60 # The default is 30 minutes of inactivity --- > @expire_after = 30*60 # The default is 30 minutes of inactivity diff -r wee_verygood/lib/wee/request.rb wee/lib/wee/request.rb 15c15 < attr_accessor :info --- > attr_reader :info diff -r wee_verygood/lib/wee/session.rb wee/lib/wee/session.rb 75d74 < p '______22 process_request______' 77,78d75 < < p '____ 22 @context.request.page_id.nil?_____' 87,88d83 < p '____ 22 @page = @page_store.fetch(@context.request.page_id, false)_____' < 97,98d91 < p '____ 22 @context.request.render?' < 107,108d99 < url_info = @context.request.info < @root_component.handle_uc url_info ? url_info.split('/') : [] 114,115d104 < p '____ 22 else_____' < 121,123d109 < # url_info = @context.request.info < # @root_component.handle_uc url_info ? url_info.split('/') : [] < 136,141d121 < < cb = callback_stream.all_of_type(:action).first.first < if cb.respond_to?(:obj) and active_component = cb.obj < custom_path = active_component.rebuild_custom_path.join('/') < @context.request.info = custom_path.size > 0 ? custom_path : nil < end 197d176 < p '_____handle_new_page_view_____' 203,204d181 < # url_info = @context.request.info < # @root_component.handle_uc url_info ? url_info.split('/') : [] -------------- next part -------------- A non-text attachment was scrubbed... Name: w_url_dev.tar.gz Type: application/x-gzip Size: 50087 bytes Desc: not available Url : http://rubyforge.org/pipermail/wee-talk/attachments/20050227/a6b02516/w_url_dev.tar-0001.bin From joaopedrosa at gmail.com Sun Feb 27 12:07:55 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Sun Feb 27 12:03:56 2005 Subject: [Wee-talk] URL update :-) Message-ID: Hi, I've prepared an example based on the Forum idea. It's great for bookmarks. It can be loaded with Pageless as well, so it's good to test both URL cases. I noted that Pageless Session didn't have all the needed code to handle these new APIs so I fixed it as well. I created a new diff of both directories and have updated my Wee again: http://ruby.com.br/~pedrosa/w_url_dev.tar.gz (it includes the example, BTW.) It's generally working. I'm comfortable with the API decisions, too. Though I'm always open to new ideas. :-) Cheers, Joao -------------- next part -------------- A non-text attachment was scrubbed... Name: forum_components.rb Type: application/octet-stream Size: 2798 bytes Desc: not available Url : http://rubyforge.org/pipermail/wee-talk/attachments/20050227/276ea031/forum_components.obj -------------- next part -------------- A non-text attachment was scrubbed... Name: forum_example.rb Type: application/octet-stream Size: 324 bytes Desc: not available Url : http://rubyforge.org/pipermail/wee-talk/attachments/20050227/276ea031/forum_example.obj -------------- next part -------------- A non-text attachment was scrubbed... Name: forum_pageless_example.rb Type: application/octet-stream Size: 403 bytes Desc: not available Url : http://rubyforge.org/pipermail/wee-talk/attachments/20050227/276ea031/forum_pageless_example.obj -------------- next part -------------- diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/application.rb /home/dewd/t_/latest_wee/wee/lib/wee/application.rb 140c140,141 < context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", context.request.application_path) --- > context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", > context.request.build_url.gsub(/\/___.*/, '')) #context.request.application_path) diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/core/callback.rb /home/dewd/t_/latest_wee/wee/lib/wee/core/callback.rb 106a107,109 > > attr_reader :obj > diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/core/component.rb /home/dewd/t_/latest_wee/wee/lib/wee/core/component.rb 66a67,130 > > #override to provide custom info handling > def uc info > end > > def handle_uc params > if not params.empty? > handled = false > children.each do |child| > if child.__name == params[0] > params.shift > child.handle_uc params > handled = true > end > end > if not handled > if respond_to?(m = "uc_#{params[0]}".to_sym) > method_params = params.clone > method_params.shift > send(m, method_params) > params.shift > else > send(:uc, params) > end > if not params.empty? > children.each do |child| > if child.__name == params[0] > params.shift > child.handle_uc params > end > end > end > end > end > end > > def __name > @__name > end > > def __name= v > @__name = v > end > > def set_name v > @__name = v > end > > # Override to provide a custom path > def custom_path > [] > end > > def rebuild_custom_path > path = ([self.__name] << custom_path).flatten > component = self > while component = component.__parent > cp = ([component.__name] << component.custom_path).flatten > path = cp + path > end > path.shift # throws away the root component name > path.compact # any nil in here? not anymore. > path > end 81a146,147 > @__name = self.class.to_s.downcase.gsub('::', '_') > @__parent = nil 116a183 > child.set_parent = self 118a186,197 > > def __parent= v > @__parent = v > end > > def __parent > @__parent > end > > def set_parent= v > @__parent = v > end diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/pageless/application.rb /home/dewd/t_/latest_wee/wee/lib/wee/pageless/application.rb 3c3,4 < context.response = Wee::RedirectResponse.new(context.request.application_path) --- > context.response = Wee::RedirectResponse.new( > context.request.build_url ) #context.request.application_path ) diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/pageless/session.rb /home/dewd/t_/latest_wee/wee/lib/wee/pageless/session.rb 40a41,42 > url_info = @context.request.info > @root_component.handle_uc url_info ? url_info.split('/') : [] 62a65,70 > > cb = callback_stream.all_of_type(:action).first.first > if cb.respond_to?(:obj) and active_component = cb.obj > custom_path = active_component.rebuild_custom_path.join('/') > @context.request.info = custom_path.size > 0 ? custom_path : nil > end diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/requesthandler.rb /home/dewd/t_/latest_wee/wee/lib/wee/requesthandler.rb 76c76 < @expire_after = 30*60 # The default is 30 minutes of inactivity --- > @expire_after = 30 #30*60 # The default is 30 minutes of inactivity diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/request.rb /home/dewd/t_/latest_wee/wee/lib/wee/request.rb 15c15 < attr_reader :info --- > attr_accessor :info diff -r /home/dewd/t_/latest_wee/trunk/lib/wee/session.rb /home/dewd/t_/latest_wee/wee/lib/wee/session.rb 99a100,101 > url_info = @context.request.info > @root_component.handle_uc url_info ? url_info.split('/') : [] 122a125,130 > cb = callback_stream.all_of_type(:action).first.first > if cb.respond_to?(:obj) and active_component = cb.obj > custom_path = active_component.rebuild_custom_path.join('/') > @context.request.info = custom_path.size > 0 ? custom_path : nil > end > From mneumann at ntecs.de Mon Feb 28 08:27:56 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Mon Feb 28 08:23:58 2005 Subject: [Wee-talk] URL for Wee - Work in Progress In-Reply-To: References: Message-ID: <42231C5C.3030904@ntecs.de> Joao Pedrosa wrote: > (Wee users shouldn't try to use this yet.) > > Ok, I'm attaching a diff and my changed Wee. You need to revise it > Michael and we need to shakedown the remaining issues. > > This is the Wee with the changed URL support: > http://ruby.com.br/~pedrosa/w_url_dev.tar.gz > > My goals are very close to be achieved with the current code. They are: > > 1. Each component has a name which defaults to the name of the class > in lower case with "::" substituted to "_". The name of the component > can be changed by the user at any time. This allows for some > flexibility because this name is going to appear in the new custom > URL. If for some reason the user decides to change this name to nil, > it should work also, in the name of maximum flexibility. > > The name of the component is important because it's used to provide > the custom URL information to the right child of the component. The > only component that does not need a name is the root component, > because in these circunstances it's not ambiguous. Would it be possible to have this scenario: Root - Child 1 (named: a) - Child 2 (named: a) How would the URL look like? I just want to generalize this. We could add positional information, like a.1: /a.1=xxx|a.2=yyy We'd need grouping to have something like: Root - Child 1 (named: a) - Child 1.1 (named: b) - Child 2 (named: a) /(a.1=xxx/b=value)|a.2=yyy An alternative approach would be to layout the pathes in the tree flat: /a.1=xxx,a.1/b=value,a.2=yyy Or using [] for positional information, and '/' to separate the name from the value: /a[1]/xxx,a[1].b/value,a[2]/yyy There are numerous ways to go. Any suggestions? > > 2. Each component has a parent component, because it allows for > backwards traversal of the components in the construction of the > custom URL. The parent component is added automatically in the > "add_child" method. I still need to add this to the @children Array, > but Michael needs to think about this too. :-) Yeah, the parent is a thing I'm in need too, for example, if a subcomponent want to replace the parent with another component, it could call: parent.call NewComponent.new Otherwise, I'd need to pass in the parent component in initialize to the child component, which is tedious IMHO. > 3. The custom URL can be used by several components which work as > (sub)controllers. At current, any component can store and retrieve > information of the URL, as long as an action has been triggered on it. > So considering a tree of components, where for the next component > opens after a click on its parent, the URL information can be stored > in the right order, but this is only meaningful for bookmarks and > after the session has expired. When the Session is active, Wee takes > care of everything for us. Last night, I tried to code a Weblog in Wee. I noticed that setting the info argument inside a callback does not work: r.anchor.callback { session.current_context.request.info = 'category/Wee' }.with('Category Wee') If the current URL looks like /category/Ruby, the rendered link above will look show /category/Ruby?callback_id (and not /category/Wee as expected), which is *very* misleading. What we need is to encode some neccessary component state inside the URL. This is important, so that backtracking will still work when using the PagelessSession. What we need is a component tree traversal at the end of the action phase, right before redirecting to the render URL. This encodes the components tree state into the URL. Each component can store a value under its name inside the URL. Before each render phase, there will be a get_arguments_from_url traversal, which assigns the values to the components. I think, this is a very powerful mechanism, which marries both worlds. Components need not store some information inside the URL, but those who want can do it. I'm open to any suggestions. Have you implemented it in this way? I've only briefly looked at your patches. Could you send me unified (diff -u) patches? Best would be if you checkout Wee from subversion, then you're able to easily diff the whole tree (svn diff), if you're not yet doing this. > ---------------- > > Current problems: > > 1. It seems that the Cookie is not being reset properly with the > custom URLs on, after the Session expires. I'm not sure how to fix > this yet. Only pertinent in the Pageless scenario. It would be nice, if we could move the cookie-fied session_id from the PagelessRequest into the Request, and make it available to both pageless and non-pageless mode. How would we tell the system, whether it should use cookies or not? Should be a property of the application, right? A patch for this is *very* welcome (and an updated test/test_request.rb), as this is fiddling around with the URL and hurts my brain ;-) > 2. After the Session has expired, the custom URL needs to be used, but > I don't know what's the right moment to call the handling method. > Pageless needs this too. If I understand you correctly, this will not be neccessary, if we use the arguments encoded inside the URL on each request (and not only for bookmarking purposes when the session has expired, but also for backtracking purposes). > 3. The custom URL is built after actions occur, but I'm not sure if > the "active component" can be always detected and used to traverse the > components. Currently I'm using what's available in the > LiteralCallback "obj". Yeah, that's why it is better to encode the state of the components-tree as described above inside the URL. But I don't think this will work when you use "call" (at least not out of the box), as you'd need to call "call" when the session has expired. Everything that modifies the initial component-tree cannot be done automatically. How about these two method names? feed_arguments_to_url parse_arguments_from_url (or fetch_) Those would be called for each visible component (so we need the _chain version of them, too). Alternatively, we could put parse_arguments_from_url into the process_callbacks chain, and only add update_url (similar to feed_arguements_to_url). > ---------------- > > Todo: > > 1. I need to create some examples which use these features. I need at > least two. One for the Pageless scenario. > > ---------------- > > My personal opinion: > > It's interesting to use Wee in this dual mode. If this works 100%, it > could even be further improved with more syntatic sugar, by combining > some methods. > > Pageless leaves the URL as clean as it gets for your creativity. :-) > Maybe farther down the road, the Session ID could be embedded in the > HTML. Could you give an example how this would look like? > Wee rocks. :-) And now I know a little bit more about it. Yeah, yesterday I wrote my Weblog in Rails ;-) I have to say, Rails is really great (it's easier than Wee for some things), but then when it comes to more complex things, I'm really missing the components concept of Wee. So, I stay with Wee ;-) Regards, Michael From mneumann at ntecs.de Mon Feb 28 10:04:57 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Mon Feb 28 10:00:59 2005 Subject: [Wee-talk] URL for Wee - Work in Progress In-Reply-To: <42231C5C.3030904@ntecs.de> References: <42231C5C.3030904@ntecs.de> Message-ID: <42233319.6060604@ntecs.de> Here's another idea how to implement pretty URLs. We already have the backtrack_state mechanism. Indeed, backtracking and pretty-URLs are both very similar. Imagine, how backtracking looks like: def backtrack_state(snapshot) super snapshot.add(self) end def take_snapshot # we want the @id to be backtracked @id end def restore_snapshot(value) @id = value end Now, why not add an URL version of these methods: def backtrack_state(snapshot) super snapshot.add_url(self) end def take_snapshot_url @id # encode the value appropriately end def restore_snapshot_url(value) @id = value # decode and sanitize the value end The only problem is, that add_url can only take arguments that are components and which are located in the component-tree, as we need to locate the destination component from it's name or position. Well, maybe it's better to use a different method... Regards, Michael From joaopedrosa at gmail.com Mon Feb 28 13:07:51 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Mon Feb 28 13:03:53 2005 Subject: [Wee-talk] URL for Wee - Work in Progress In-Reply-To: <42231C5C.3030904@ntecs.de> References: <42231C5C.3030904@ntecs.de> Message-ID: Hi, > Would it be possible to have this scenario: > > Root > - Child 1 (named: a) > - Child 2 (named: a) Indeed. I chose not to handle this just yet. The order in which they are added to the parent can be used to distinguish them, though. > How would the URL look like? I just want to generalize this. We could > add positional information, like a.1: > > /a.1=xxx|a.2=yyy With this kind of approach you are already deciding more or less how the custom URL will look like. And I'm not sure if you are considering different methods for each object which are stored in the custom URL also. E.g.: * /2005/02/title_of_the_post * /a/list * /a/list/100/0 #lists first 100 queries If the user needs to fallback to encoding the value it wouldn't look a lot with the other solutions that people can come up with in other Web techs. In the simplest scenario the Root component could interpret the custom URL and feed the other components that need some of the informations, for example. > We'd need grouping to have something like: > > Root > - Child 1 (named: a) > - Child 1.1 (named: b) > - Child 2 (named: a) > > /(a.1=xxx/b=value)|a.2=yyy > > An alternative approach would be to layout the pathes in the tree flat: > > /a.1=xxx,a.1/b=value,a.2=yyy > > Or using [] for positional information, and '/' to separate the name > from the value: > > /a[1]/xxx,a[1].b/value,a[2]/yyy > > There are numerous ways to go. Any suggestions? It's harder to store all this info in a good way. Even in other frameworks they store only the minimum necessary in the URL. The difference is that this minimum is important to them so they don't have redundant code to handle this... I would say to create the default name of the object with the order number . E.g.: AComponent - 'acomponent' BComponent - 'bcomponent' With children: AComponent - 'acomponent' BComponent - 'bcomponent1' BComponent - 'bcomponent2' This could be easily handled when adding a new name. I just thought, though: AComponent - 'acomponent' BComponent - 'bcomponent1' Would be a little bit better from the web-app evolution PoV. Because once a new component is added any bookmarks that had reference to the old child still work because the number "1" has been already added to its name, as long as the order in which they are added to the parent does not change, everything would still be ok. > > > 2. Each component has a parent component, because it allows for > > backwards traversal of the components in the construction of the > > custom URL. The parent component is added automatically in the > > "add_child" method. I still need to add this to the @children Array, > > but Michael needs to think about this too. :-) > > Yeah, the parent is a thing I'm in need too, for example, if a > subcomponent want to replace the parent with another component, it could > call: > > parent.call NewComponent.new > > Otherwise, I'd need to pass in the parent component in initialize to the > child component, which is tedious IMHO. I'm not sure what this is about. Maybe parent = NewComponent.new would suffice, though? > Last night, I tried to code a Weblog in Wee. I noticed that setting the > info argument inside a callback does not work: > > r.anchor.callback { > session.current_context.request.info = 'category/Wee' > }.with('Category Wee') > > If the current URL looks like /category/Ruby, the rendered link above > will look show /category/Ruby?callback_id (and not /category/Wee as > expected), which is *very* misleading. The URL perspective needs its own KISS sometimes. hehehe :-) > What we need is to encode some neccessary component state inside the > URL. This is important, so that backtracking will still work when using > the PagelessSession. See above. :-) > What we need is a component tree traversal at the end of the action > phase, right before redirecting to the render URL. This encodes the > components tree state into the URL. Each component can store a value > under its name inside the URL. I'm not sure about making data travelling in the URL. If it's too sensitive (security) it should remain in the server, if not, then maybe it should be embedded in the HTML. If you are like Google you need a super duper URL, i.e., flexible URL. URL needs to be charismatic. > Before each render phase, there will be a get_arguments_from_url > traversal, which assigns the values to the components. > > I think, this is a very powerful mechanism, which marries both worlds. > Components need not store some information inside the URL, but those who > want can do it. This is what these changes allow. These custom URLs can get very eccentric depending on the creator of the site. > I'm open to any suggestions. Have you implemented it in this way? I've > only briefly looked at your patches. Could you send me unified (diff -u) > patches? Best would be if you checkout Wee from subversion, then you're > able to easily diff the whole tree (svn diff), if you're not yet doing this. What I've done is only relevant after the Session expires or after the server is restarted, allowing the users to get back to where they were with the URL, which could be a bookmark. But it needs some assistance of the user to get the right code in place. > > ---------------- > > > > Current problems: > > > > 1. It seems that the Cookie is not being reset properly with the > > custom URLs on, after the Session expires. I'm not sure how to fix > > this yet. Only pertinent in the Pageless scenario. > > It would be nice, if we could move the cookie-fied session_id from the > PagelessRequest into the Request, and make it available to both pageless > and non-pageless mode. How would we tell the system, whether it should > use cookies or not? Should be a property of the application, right? A > patch for this is *very* welcome (and an updated test/test_request.rb), > as this is fiddling around with the URL and hurts my brain ;-) Indeed. I'm not sure if many people like to depend on cookies, though... I don't promise anything on this because once Wee is good with URLs the next step could be to provide a FastCGI interface to it. With two backends somethings could fall into place better. > > 2. After the Session has expired, the custom URL needs to be used, but > > I don't know what's the right moment to call the handling method. > > Pageless needs this too. > > If I understand you correctly, this will not be neccessary, if we use > the arguments encoded inside the URL on each request (and not only for > bookmarking purposes when the session has expired, but also for > backtracking purposes). Does Seaside or IOWA or Borges use it like that in spite of providing components? I don't know what's needed to merge both worlds, Components and URLs. Does Tapestry (Java Tech) provide Backtracking and "Custom URLs"? It deserves a wee look. :-) > > 3. The custom URL is built after actions occur, but I'm not sure if > > the "active component" can be always detected and used to traverse the > > components. Currently I'm using what's available in the > > LiteralCallback "obj". > > Yeah, that's why it is better to encode the state of the components-tree > as described above inside the URL. But I don't think this will work when > you use "call" (at least not out of the box), as you'd need to call > "call" when the session has expired. Everything that modifies the > initial component-tree cannot be done automatically. > > How about these two method names? > > feed_arguments_to_url > parse_arguments_from_url (or fetch_) They are nice. But I hope they won't become a burden to the user. I called them "def custom_path" and "def uc" Respectively. But today I think "def custom_path" could become "attr_accessor custom_path", for example (from the user point of view.) "def uc" is the default Component method to handle the custom URLs. uc = under_control It's used to distinguish the normal Component's methods -- that are callable from a URL, -- from the others. So "def uc_next" "def uc_prior" "def uc_list" "def uc_add" "def uc_etc" could be called from the URL like: "/app/next" "/app/prior" "/app/etc" And if it's a subcomponent: "/app/asubcomponent/next" Though if the root component needs some parameter: "/app/10/asubcomponent/next" Where 10 would be handled by the root component's "def uc" > Those would be called for each visible component (so we need the _chain > version of them, too). > > Alternatively, we could put parse_arguments_from_url into the > process_callbacks chain, and only add update_url (similar to > feed_arguements_to_url). I'm generally disregarding the Backtracking issue, sorry. I know it's an important Wee and Seaside concept, but people don't use Backtracking in other frameworks. This is a wee headache. hehehe. :-) In Portuguese, there is a saying when we lose something but can still keep other thing: "V?o-se os aneis, ficam os dedos" which means something like "The rings go, the fingers stay" > > ---------------- > > > > Todo: > > > > 1. I need to create some examples which use these features. I need at > > least two. One for the Pageless scenario. > > > > ---------------- > > > > My personal opinion: > > > > It's interesting to use Wee in this dual mode. If this works 100%, it > > could even be further improved with more syntatic sugar, by combining > > some methods. > > > > Pageless leaves the URL as clean as it gets for your creativity. :-) > > Maybe farther down the road, the Session ID could be embedded in the > > HTML. > > Could you give an example how this would look like? Not now, maybe in the future. > > Wee rocks. :-) And now I know a little bit more about it. > > Yeah, yesterday I wrote my Weblog in Rails ;-) > I have to say, Rails is really great (it's easier than Wee for some > things), but then when it comes to more complex things, I'm really > missing the components concept of Wee. So, I stay with Wee ;-) I could only "miss Rails for the others." I'm happy with Wee. Though maybe another Wee with less Seaside inheritance could do better against the other frameworks, I'm left wondering, considering that URL is king. I've updated my Wee with URL at: http://ruby.com.br/~pedrosa/w_url_dev.tar.gz It has the following fix: "path.compact" now is "path.compact!" In attach I'm sending the diff. Cheers, Joao -------------- next part -------------- Only in wee/examples: forum_components.rb Only in wee/examples: forum_example.rb Only in wee/examples: forum_pageless_example.rb Only in wee/examples: pageless_and_url.rb diff -ur trunk/lib/wee/application.rb wee/lib/wee/application.rb --- trunk/lib/wee/application.rb 2005-02-28 15:02:50.632418576 -0300 +++ wee/lib/wee/application.rb 2005-02-28 14:53:55.829720944 -0300 @@ -137,7 +137,8 @@ end def request_handler_expired(context) - context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", context.request.application_path) + context.response = Wee::RefreshResponse.new("Invalid or expired request handler!", + context.request.build_url.gsub(/\/___.*/, '')) #context.request.application_path) end end diff -ur trunk/lib/wee/core/callback.rb wee/lib/wee/core/callback.rb --- trunk/lib/wee/core/callback.rb 2005-02-28 15:02:47.722860896 -0300 +++ wee/lib/wee/core/callback.rb 2005-02-28 14:53:55.678743896 -0300 @@ -104,6 +104,9 @@ # A serializable callback. class Wee::LiteralMethodCallback + + attr_reader :obj + def initialize(obj, method_id=:call, *args) @obj, @method_id = obj, method_id @args = args unless args.empty? diff -ur trunk/lib/wee/core/component.rb wee/lib/wee/core/component.rb --- trunk/lib/wee/core/component.rb 2005-02-28 15:02:47.720861200 -0300 +++ wee/lib/wee/core/component.rb 2005-02-28 14:53:55.678743896 -0300 @@ -64,6 +64,70 @@ end end end + + #override to provide custom info handling + def uc info + end + + def handle_uc params + if not params.empty? + handled = false + children.each do |child| + if child.__name == params[0] + params.shift + child.handle_uc params + handled = true + end + end + if not handled + if respond_to?(m = "uc_#{params[0]}".to_sym) + method_params = params.clone + method_params.shift + send(m, method_params) + params.shift + else + send(:uc, params) + end + if not params.empty? + children.each do |child| + if child.__name == params[0] + params.shift + child.handle_uc params + end + end + end + end + end + end + + def __name + @__name + end + + def __name= v + @__name = v + end + + def set_name v + @__name = v + end + + # Override to provide a custom path + def custom_path + [] + end + + def rebuild_custom_path + path = ([self.__name] << custom_path).flatten + component = self + while component = component.__parent + cp = ([component.__name] << component.custom_path).flatten + path = cp + path + end + path.shift # throws away the root component name + path.compact! # any nil in here? not anymore. + path + end # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # :section: Init @@ -79,6 +143,8 @@ def initialize() # :notnew: @__decoration = Wee::ValueHolder.new(self) @__children = [] + @__name = self.class.to_s.downcase.gsub('::', '_') + @__parent = nil end # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -114,8 +180,21 @@ def add_child(child) self.children << child + child.set_parent = self child end + + def __parent= v + @__parent = v + end + + def __parent + @__parent + end + + def set_parent= v + @__parent = v + end # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # :section: Decoration diff -ur trunk/lib/wee/pageless/application.rb wee/lib/wee/pageless/application.rb --- trunk/lib/wee/pageless/application.rb 2005-02-28 15:02:48.815694760 -0300 +++ wee/lib/wee/pageless/application.rb 2005-02-28 14:53:55.713738576 -0300 @@ -1,6 +1,7 @@ class Wee::PagelessApplication < Wee::Application def request_handler_expired(context) - context.response = Wee::RedirectResponse.new(context.request.application_path) + context.response = Wee::RedirectResponse.new( + context.request.build_url ) #context.request.application_path ) # TODO: depends on WEBrick cookie = WEBrick::Cookie.new('SID', '') cookie.max_age = 0 diff -ur trunk/lib/wee/pageless/session.rb wee/lib/wee/pageless/session.rb --- trunk/lib/wee/pageless/session.rb 2005-02-28 15:02:48.814694912 -0300 +++ wee/lib/wee/pageless/session.rb 2005-02-28 14:53:55.719737664 -0300 @@ -38,6 +38,8 @@ # 3. Store the page back into the store new_callbacks = Wee::CallbackRegistry.new(Wee::SimpleIdGenerator.new) + url_info = @context.request.info + @root_component.handle_uc url_info ? url_info.split('/') : [] respond(@context, new_callbacks) # render self.callbacks = new_callbacks @@ -60,6 +62,12 @@ } nil } + + cb = callback_stream.all_of_type(:action).first.first + if cb.respond_to?(:obj) and active_component = cb.obj + custom_path = active_component.rebuild_custom_path.join('/') + @context.request.info = custom_path.size > 0 ? custom_path : nil + end if live_update_response @context.response = live_update_response diff -ur trunk/lib/wee/request.rb wee/lib/wee/request.rb --- trunk/lib/wee/request.rb 2005-02-28 15:02:50.630418880 -0300 +++ wee/lib/wee/request.rb 2005-02-28 14:53:55.829720944 -0300 @@ -12,7 +12,7 @@ attr_reader :page_id, :fields, :cookies # The part of the URL that is user-defineable - attr_reader :info + attr_accessor :info def initialize(app_path, path, headers, fields, cookies) raise ArgumentError if app_path[-1] == ?/ diff -ur trunk/lib/wee/session.rb wee/lib/wee/session.rb --- trunk/lib/wee/session.rb 2005-02-28 15:02:50.623419944 -0300 +++ wee/lib/wee/session.rb 2005-02-28 14:53:55.829720944 -0300 @@ -97,6 +97,8 @@ # 3. Store the page back into the store @page = create_page(@page.snapshot) # remove all action/input handlers + url_info = @context.request.info + @root_component.handle_uc url_info ? url_info.split('/') : [] respond(@context, @page.callbacks) # render @page_store[@context.request.page_id] = @page # store @@ -120,6 +122,12 @@ nil } + cb = callback_stream.all_of_type(:action).first.first + if cb.respond_to?(:obj) and active_component = cb.obj + custom_path = active_component.rebuild_custom_path.join('/') + @context.request.info = custom_path.size > 0 ? custom_path : nil + end + if live_update_response # replace existing page with new snapshot @page.snapshot = self.snapshot From Reid.Thompson at ateb.com Mon Feb 28 13:10:10 2005 From: Reid.Thompson at ateb.com (Reid Thompson) Date: Mon Feb 28 13:30:37 2005 Subject: [Wee-talk] No such file to load -- og/adapters Message-ID: What am I missing..., do i need to provide better path information somewhere? WS-XP-4960: /home/rthompso> $ wee create-og /home/rthompso/weetest /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/run.rb -> /home/rthompso/weetest/run.rb /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/README -> /home/rthompso/weetest/README /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/components/main.rb -> /home/rthompso/weetest/components/main.rb /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/models/recipe.rb -> /home/rthompso/weetest/models/recipe.rb WS-XP-4960: /home/rthompso> $ cd weetest/ WS-XP-4960: /home/rthompso/weetest> $ vi db.rb -> configured db connection parameters WS-XP-4960: /home/rthompso/weetest/conf> $ cd .. WS-XP-4960: /home/rthompso/weetest> $ cat run.rb require 'wee' require 'wee/utils' require 'wee/adaptors/webrick' require 'og' require 'wee/databases/og' # Database configuration require 'conf/db.rb' # Your components require 'components/main' # Your models require 'models/recipe' app = Wee::Utils.app_for(nil, :application => OgApplication, :session => OgSession) { Main.new.add_decoration(Wee::PageDecoration.new('Wee+Og')) } app.db = Og::Database.new(DB_CONFIG) Wee::Utils::autoreload_glob('components/**/*.rb') Wee::WEBrickAdaptor.register('/app' => app).start WS-XP-4960: /home/rthompso/weetest> $ ruby -rubygems run.rb INFO: Connecting to database 'testdb' using the '' adapter. /lib/ruby/site_ruby/1.8/rubygems/loadpath_manager.rb:5:in `require__': No such file to load -- og/adapters/ (LoadError) from /lib/ruby/site_ruby/1.8/rubygems/loadpath_manager.rb:5:in `require' from /lib/ruby/gems/1.8/gems/nitro-0.11.0/lib/og/adapter.rb:27:in `for_name' from /lib/ruby/gems/1.8/gems/nitro-0.11.0/lib/og/database.rb:65:in `initialize' from run.rb:21:in `new' from run.rb:21 From mneumann at ntecs.de Mon Feb 28 13:36:29 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Mon Feb 28 13:32:30 2005 Subject: [Wee-talk] No such file to load -- og/adapters In-Reply-To: References: Message-ID: <422364AD.70508@ntecs.de> Reid Thompson wrote: > What am I missing..., do i need to provide better path information > somewhere? > > WS-XP-4960: /home/rthompso> > $ wee create-og /home/rthompso/weetest > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/run.rb -> > /home/rthompso/weetest/run.rb > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/README -> > /home/rthompso/weetest/README > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/components/main.rb > -> /home/rthompso/weetest/components/main.rb > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/models/recipe.rb > -> /home/rthompso/weetest/models/recipe.rb > WS-XP-4960: /home/rthompso> > $ cd weetest/ > > WS-XP-4960: /home/rthompso/weetest> > $ vi db.rb -> configured db connection parameters Use the newest version of Og please. ("gem install nitro" will do). I think the setting has changed. Regards, Michael From Reid.Thompson at ateb.com Mon Feb 28 13:37:22 2005 From: Reid.Thompson at ateb.com (Reid Thompson) Date: Mon Feb 28 13:33:27 2005 Subject: [Wee-talk] No such file to load -- og/adapters Message-ID: Reid Thompson wrote: > What am I missing..., do i need to provide better path > information somewhere? > > WS-XP-4960: /home/rthompso> > $ wee create-og /home/rthompso/weetest > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/run.rb > -> /home/rthompso/weetest/run.rb > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/README > -> /home/rthompso/weetest/README > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/componen > ts/main.rb -> /home/rthompso/weetest/components/main.rb > /lib/ruby/gems/1.8/gems/wee-0.7.0/lib/wee/skeleton/og/models/recipe.rb > -> /home/rthompso/weetest/models/recipe.rb > WS-XP-4960: /home/rthompso> > $ cd weetest/ > > WS-XP-4960: /home/rthompso/weetest> > $ vi db.rb -> configured db connection parameters > > WS-XP-4960: /home/rthompso/weetest/conf> > $ cd .. > > WS-XP-4960: /home/rthompso/weetest> > $ cat run.rb > require 'wee' > require 'wee/utils' > require 'wee/adaptors/webrick' > require 'og' > require 'wee/databases/og' > > # Database configuration > require 'conf/db.rb' > > # Your components > require 'components/main' > > # Your models > require 'models/recipe' > > > app = Wee::Utils.app_for(nil, :application => OgApplication, > :session => OgSession) { > Main.new.add_decoration(Wee::PageDecoration.new('Wee+Og')) } > app.db = Og::Database.new(DB_CONFIG) > Wee::Utils::autoreload_glob('components/**/*.rb') > Wee::WEBrickAdaptor.register('/app' => app).start > > WS-XP-4960: /home/rthompso/weetest> > $ ruby -rubygems run.rb > INFO: Connecting to database 'testdb' using the '' adapter. > /lib/ruby/site_ruby/1.8/rubygems/loadpath_manager.rb:5:in > `require__': No such file to load -- og/adapters/ (LoadError) > from > /lib/ruby/site_ruby/1.8/rubygems/loadpath_manager.rb:5:in > `require' from > /lib/ruby/gems/1.8/gems/nitro-0.11.0/lib/og/adapter.rb:27:in > `for_name' from > /lib/ruby/gems/1.8/gems/nitro-0.11.0/lib/og/database.rb:65:in > `initialize' from run.rb:21:in `new' from run.rb:21 > > _______________________________________________ > Wee-talk mailing list > Wee-talk@rubyforge.org http://rubyforge.org/mailman/listinfo/wee-talk found it -- db.rb DB_CONFIG = { :address => '127.0.0.1', :database => 'sigcap', :adapter => 'psql', :user => 'sigcap', :password => 'sigcap', :connection_count => 10 } has :backend rather than :adapter. reid From mneumann at ntecs.de Mon Feb 28 17:37:25 2005 From: mneumann at ntecs.de (Michael Neumann) Date: Mon Feb 28 17:33:27 2005 Subject: [Wee-talk] URL for Wee - Work in Progress In-Reply-To: References: <42231C5C.3030904@ntecs.de> Message-ID: <42239D25.7060505@ntecs.de> Joao Pedrosa wrote: > Hi, > > >>Would it be possible to have this scenario: >> >> Root >> - Child 1 (named: a) >> - Child 2 (named: a) > > > Indeed. I chose not to handle this just yet. The order in which they > are added to the parent can be used to distinguish them, though. > > >>How would the URL look like? I just want to generalize this. We could >>add positional information, like a.1: >> >> /a.1=xxx|a.2=yyy > > > With this kind of approach you are already deciding more or less how > the custom URL will look like. And I'm not sure if you are considering > different methods for each object which are stored in the custom URL > also. What do you mean with "different methods"? Only state is stored for each component (or those that want to store the state). BTW, we can't bookmark action URLs (okay, in theory we could, but that would require us to render the page to populate the callbacks array). > E.g.: > * /2005/02/title_of_the_post > * /a/list > * /a/list/100/0 #lists first 100 queries > If the user needs to fallback to encoding the value it wouldn't look a > lot with the other solutions that people can come up with in other Web > techs. Hm, could you quickly explain how your patch would decode this URL? Does the root-component decide which part is assigned to which component? > In the simplest scenario the Root component could interpret the custom > URL and feed the other components that need some of the informations, > for example. Yeah, that's pretty simple. But you have to code it yourself each time, and you need some knowlege of your application ;-) >>We'd need grouping to have something like: >> >> Root >> - Child 1 (named: a) >> - Child 1.1 (named: b) >> - Child 2 (named: a) >> >> /(a.1=xxx/b=value)|a.2=yyy >> >>An alternative approach would be to layout the pathes in the tree flat: >> >> /a.1=xxx,a.1/b=value,a.2=yyy >> >>Or using [] for positional information, and '/' to separate the name >>from the value: >> >> /a[1]/xxx,a[1].b/value,a[2]/yyy >> >>There are numerous ways to go. Any suggestions? > > > It's harder to store all this info in a good way. Even in other > frameworks they store only the minimum necessary in the URL. The > difference is that this minimum is important to them so they don't > have redundant code to handle this... I would say to create the > default name of the object with the order number . E.g.: > AComponent - 'acomponent' > BComponent - 'bcomponent' > > With children: > AComponent - 'acomponent' > BComponent - 'bcomponent1' > BComponent - 'bcomponent2' > > This could be easily handled when adding a new name. I just thought, though: > AComponent - 'acomponent' > BComponent - 'bcomponent1' > Would be a little bit better from the web-app evolution PoV. Because > once a new component is added any bookmarks that had reference to the > old child still work because the number "1" has been already added to > its name, as long as the order in which they are added to the parent > does not change, everything would still be ok. Or you could just assume "the first child", if no order is given. >>>>2. Each component has a parent component, because it allows for >>> >>>backwards traversal of the components in the construction of the >>>custom URL. The parent component is added automatically in the >>>"add_child" method. I still need to add this to the @children Array, >>>but Michael needs to think about this too. :-) >> >>Yeah, the parent is a thing I'm in need too, for example, if a >>subcomponent want to replace the parent with another component, it could >>call: >> >> parent.call NewComponent.new >> >>Otherwise, I'd need to pass in the parent component in initialize to the >>child component, which is tedious IMHO. > > > I'm not sure what this is about. Maybe > parent = NewComponent.new > would suffice, though? I'll explain. Sometimes, it's nice to call methods of the parent. And by adding this: def add_child(child) child.parent = self @__children << child child end attr_accessor :parent def root? @parent.nil? end it gets much easier. >>Last night, I tried to code a Weblog in Wee. I noticed that setting the >>info argument inside a callback does not work: >> >> r.anchor.callback { >> session.current_context.request.info = 'category/Wee' >> }.with('Category Wee') >> >>If the current URL looks like /category/Ruby, the rendered link above >>will look show /category/Ruby?callback_id (and not /category/Wee as >>expected), which is *very* misleading. > > > The URL perspective needs its own KISS sometimes. hehehe :-) > > >>What we need is to encode some neccessary component state inside the >>URL. This is important, so that backtracking will still work when using >> the PagelessSession. > > > See above. :-) > > >>What we need is a component tree traversal at the end of the action >>phase, right before redirecting to the render URL. This encodes the >>components tree state into the URL. Each component can store a value >>under its name inside the URL. > > > I'm not sure about making data travelling in the URL. If it's too > sensitive (security) it should remain in the server, if not, then > maybe it should be embedded in the HTML. If you are like Google you > need a super duper URL, i.e., flexible URL. URL needs to be > charismatic. Agreed. >>Before each render phase, there will be a get_arguments_from_url >>traversal, which assigns the values to the components. >> >>I think, this is a very powerful mechanism, which marries both worlds. >>Components need not store some information inside the URL, but those who >>want can do it. > > > This is what these changes allow. These custom URLs can get very > eccentric depending on the creator of the site. > > >>I'm open to any suggestions. Have you implemented it in this way? I've >>only briefly looked at your patches. Could you send me unified (diff -u) >>patches? Best would be if you checkout Wee from subversion, then you're >>able to easily diff the whole tree (svn diff), if you're not yet doing this. > > > What I've done is only relevant after the Session expires or after the > server is restarted, allowing the users to get back to where they were > with the URL, which could be a bookmark. But it needs some assistance > of the user to get the right code in place. Hm... but imagine you hit the browswers back button... this works e.g. in Rails, as the "state" is encoded in the URL, but it won't work with your patches and a Pageless session. I think now, it makes sense to use these informations not only when the session times out, but on each request. >>>---------------- >>> >>>Current problems: >>> >>>1. It seems that the Cookie is not being reset properly with the >>>custom URLs on, after the Session expires. I'm not sure how to fix >>>this yet. Only pertinent in the Pageless scenario. >> >>It would be nice, if we could move the cookie-fied session_id from the >>PagelessRequest into the Request, and make it available to both pageless >>and non-pageless mode. How would we tell the system, whether it should >>use cookies or not? Should be a property of the application, right? A >>patch for this is *very* welcome (and an updated test/test_request.rb), >>as this is fiddling around with the URL and hurts my brain ;-) > > > Indeed. I'm not sure if many people like to depend on cookies, > though... I don't promise anything on this because once Wee is good > with URLs the next step could be to provide a FastCGI interface to it. > With two backends somethings could fall into place better. Exactly. >>>2. After the Session has expired, the custom URL needs to be used, but >>>I don't know what's the right moment to call the handling method. >>>Pageless needs this too. >> >>If I understand you correctly, this will not be neccessary, if we use >>the arguments encoded inside the URL on each request (and not only for >>bookmarking purposes when the session has expired, but also for >>backtracking purposes). > > > Does Seaside or IOWA or Borges use it like that in spite of providing > components? I don't know what's needed to merge both worlds, > Components and URLs. Does Tapestry (Java Tech) provide Backtracking > and "Custom URLs"? It deserves a wee look. :-) Don't know about Tapestry. Seaside has updateUrl, which can be used to add information to the URL. But I believe it's mainly for bookmarking purposes, and I believe they don't have page-less mode. >>>3. The custom URL is built after actions occur, but I'm not sure if >>>the "active component" can be always detected and used to traverse the >>>components. Currently I'm using what's available in the >>>LiteralCallback "obj". >> >>Yeah, that's why it is better to encode the state of the components-tree >>as described above inside the URL. But I don't think this will work when >>you use "call" (at least not out of the box), as you'd need to call >>"call" when the session has expired. Everything that modifies the >>initial component-tree cannot be done automatically. >> >>How about these two method names? >> >> feed_arguments_to_url >> parse_arguments_from_url (or fetch_) > > > They are nice. But I hope they won't become a burden to the user. > > I called them > "def custom_path" > and > "def uc" > > Respectively. But today I think "def custom_path" could become > "attr_accessor custom_path", for example (from the user point of view.) > > "def uc" is the default Component method to handle the custom URLs. > uc = under_control > It's used to distinguish the normal Component's methods -- > that are callable from a URL, -- from the others. So > "def uc_next" > "def uc_prior" > "def uc_list" > "def uc_add" > "def uc_etc" > could be called from the URL like: > "/app/next" > "/app/prior" > "/app/etc" > And if it's a subcomponent: > "/app/asubcomponent/next" > Though if the root component needs some parameter: > "/app/10/asubcomponent/next" > Where 10 would be handled by the root component's "def uc" Hm, you actually encode actions inside the URL and not state, right? Do we really need actions? >>Those would be called for each visible component (so we need the _chain >>version of them, too). >> >>Alternatively, we could put parse_arguments_from_url into the >>process_callbacks chain, and only add update_url (similar to >>feed_arguements_to_url). > > > I'm generally disregarding the Backtracking issue, sorry. I know it's > an important Wee and Seaside concept, but people don't use > Backtracking in other frameworks. This is a wee headache. hehehe. :-) Hm, in stateless frameworks (like Rails), backtracking is no issue, as everything is encoded inside the URL. But in Wee, this is different, so we need backtracking. This is why I'd like to see some kind of component state inside the URL (be it just /category/1). > In Portuguese, there is a saying when we lose something but can still > keep other thing: > "V?o-se os aneis, ficam os dedos" > which means something like > "The rings go, the fingers stay" Nice ;-) >>>---------------- >>> >>>Todo: >>> >>>1. I need to create some examples which use these features. I need at >>>least two. One for the Pageless scenario. >>> >>>---------------- >>> >>>My personal opinion: >>> >>>It's interesting to use Wee in this dual mode. If this works 100%, it >>>could even be further improved with more syntatic sugar, by combining >>>some methods. >>> >>>Pageless leaves the URL as clean as it gets for your creativity. :-) >>>Maybe farther down the road, the Session ID could be embedded in the >>>HTML. >> >>Could you give an example how this would look like? > > > Not now, maybe in the future. Maybe via meta html tags, that add some HTTP headers? That of course should be damn simple. >>>Wee rocks. :-) And now I know a little bit more about it. >> >>Yeah, yesterday I wrote my Weblog in Rails ;-) >>I have to say, Rails is really great (it's easier than Wee for some >>things), but then when it comes to more complex things, I'm really >>missing the components concept of Wee. So, I stay with Wee ;-) > > > I could only "miss Rails for the others." I'm happy with Wee. Though > maybe another Wee with less Seaside inheritance could do better > against the other frameworks, I'm left wondering, considering that URL > is king. Well, I'm open for changes. I know that especially the backtracking stuff is not something everyone will use, but you need not use it. > I've updated my Wee with URL at: > http://ruby.com.br/~pedrosa/w_url_dev.tar.gz > It has the following fix: "path.compact" now is "path.compact!" > > In attach I'm sending the diff. Thanks. Regards, Michael From joaopedrosa at gmail.com Mon Feb 28 19:57:53 2005 From: joaopedrosa at gmail.com (Joao Pedrosa) Date: Mon Feb 28 19:53:53 2005 Subject: [Wee-talk] URL for Wee - Work in Progress In-Reply-To: <42239D25.7060505@ntecs.de> References: <42231C5C.3030904@ntecs.de> <42239D25.7060505@ntecs.de> Message-ID: Hi, > > E.g.: > > * /2005/02/title_of_the_post > > * /a/list > > * /a/list/100/0 #lists first 100 queries > > If the user needs to fallback to encoding the value it wouldn't look a > > lot with the other solutions that people can come up with in other Web > > techs. > > Hm, could you quickly explain how your patch would decode this URL? Does > the root-component decide which part is assigned to which component? In the "/2005/02/title_of_the_post" case, this URL could be handled by the root component, because a method with the "2005" string wouldn't probably exist in one of its methods ("def uc_2005"), nor would probably be the name of one of its children. So the method "def uc" of the root component will receive "[2005, 02, 'title_of_the_post']" and can do its job. On the other hand, "a" and "list" are more suitable to be the name of a component or of one of its "def uc_..." methods. If "a" is the name of a child of the root component, then this child is supposed to handle the remaining "list" URL command, because the "a" did its job already and is "shifted" (params.shift) away. If "list" is a "def uc..." method of the "a" component, then it will be called. In the "/a/list", this method will be called and it won't get any parameters -- besides an empty array -- passed to it. In the "/a/list/100/0", the "uc_list" method will get "[100, 0]" and will be able to use these parameters in its role. > > In the simplest scenario the Root component could interpret the custom > > URL and feed the other components that need some of the informations, > > for example. > > Yeah, that's pretty simple. But you have to code it yourself each time, > and you need some knowlege of your application ;-) Yes, but this approach scales. Though not in a tree-wise way. That is, each component can handle just what it needs, without getting messy "hrefs" or big method dispatchers. But maybe it's too dynamic for most people's taste, that's a worry of mine. It's relatively simple also, so at current it won't save every components needed state. Not out of the box. For this some planning and custom programming could handle more edge cases. Nonetheless, I think with kind of meaningless URLs this isn't very easy to handle for every component. Which's more important? Querying the database or caring about components? :-) I think Rails chose "querying the database". > > They are nice. But I hope they won't become a burden to the user. > > > > I called them > > "def custom_path" > > and > > "def uc" > > > > Respectively. But today I think "def custom_path" could become > > "attr_accessor custom_path", for example (from the user point of view.) > > > > "def uc" is the default Component method to handle the custom URLs. > > uc = under_control > > It's used to distinguish the normal Component's methods -- > > that are callable from a URL, -- from the others. So > > "def uc_next" > > "def uc_prior" > > "def uc_list" > > "def uc_add" > > "def uc_etc" > > could be called from the URL like: > > "/app/next" > > "/app/prior" > > "/app/etc" > > And if it's a subcomponent: > > "/app/asubcomponent/next" > > Though if the root component needs some parameter: > > "/app/10/asubcomponent/next" > > Where 10 would be handled by the root component's "def uc" > > Hm, you actually encode actions inside the URL and not state, right? Do > we really need actions? In this case I gave more examples than I should have. But that's possible with my patch. Such an interface can be useful when remotely controlling another application. :-) It can come in handy for bigger components that have more ways of answering to similar data. The other way would have been to distinguish the data somehow just so they could be passed along to the right method. As I said in a previous email, I was trying to approach this from the URL point of view. :-) > >>>It's interesting to use Wee in this dual mode. If this works 100%, it > >>>could even be further improved with more syntatic sugar, by combining > >>>some methods. > >>> > >>>Pageless leaves the URL as clean as it gets for your creativity. :-) > >>>Maybe farther down the road, the Session ID could be embedded in the > >>>HTML. > >> > >>Could you give an example how this would look like? > > > > > > Not now, maybe in the future. > > Maybe via meta html tags, that add some HTTP headers? That of course > should be damn simple. As a hidden FORM tag. :-) Is that right? Seems so simple, that I don't know if this is it. > >>>Wee rocks. :-) And now I know a little bit more about it. > >> > >>Yeah, yesterday I wrote my Weblog in Rails ;-) > >>I have to say, Rails is really great (it's easier than Wee for some > >>things), but then when it comes to more complex things, I'm really > >>missing the components concept of Wee. So, I stay with Wee ;-) > > > > > > I could only "miss Rails for the others." I'm happy with Wee. Though > > maybe another Wee with less Seaside inheritance could do better > > against the other frameworks, I'm left wondering, considering that URL > > is king. > > Well, I'm open for changes. I know that especially the backtracking > stuff is not something everyone will use, but you need not use it. Hehe. These "custom URLs" could come in handy then. The default approach of developing with Wee could use a big fat controller, which wouldn't be any different than a big fat Wee component, with the "def uc..." methods. Maybe a goal would be to drop the "uc..." from the components marked as controllers, so the user would see "def list", "def delete", instead of "def uc_list", "def uc_delete". These are database operations, so backtracking is not so important to them. Give them ActiveRecord, ERb, etc. Bind these operations automatically so the user hardly needs to create his own Components. Once they learn more about Wee, then they could try one or two Wee tricks to add their applications, like backtracking, using the Session management, creating their custom Components, etc. It's more or less like treating the Wee users like users. Some may not want to know about Ruby just yet. Etc. Cheers, Joao