From Peter.Bex at solide-ict.nl Fri Aug 17 11:11:29 2007 From: Peter.Bex at solide-ict.nl (Peter Bex) Date: Fri, 17 Aug 2007 17:11:29 +0200 Subject: [Cells-talk] [patch] Cell inheritance Message-ID: <20070817151129.GA16816@darko.solide-ict.nl> Hi there, I'm just getting started with Cells, and I must say it looks very exciting and it seems to be exactly what I need for my project. I have models which represent mostly presentational objects (it's for a wysiwyg editor thing where things can be dragged onto a canvas and get stored in a database). These models form a reasonably complex class inheritance hierarchy and I would like each model to have a corresponding Cell. The Cell hierarchy will mirror the model hierarchy, so you will get class FooCell < BarCell end And only things which differ from the parent class are overridden in the subclass. Now, some cells have views associated with them, so it should be possible to inherit those as well. That is, by not defining a view, a Cell leaves it up to its parent class to define the view. If there's no app/cells/foo/views/blah.rhtml it will look for app/cells/bar/views/blah.rhtml I'm hoping this makes sense to you. Anyway, I created a little patch that implements exactly this functionality. Do you think this is a desirable feature to have in Cells? Another question I'm having is: How can I get anonymous access to the subversion repository? I would very much like to be able to keep track of the most recent developments in trunk. I tried to checkout from the rubyforge account, but this is an empty repository. I assume you're working off the repository that http://nick.smt.de/trac/nick/wiki/Cells provides a view on? I couldn't find any documentation on how to connect to that repository. Regards, Peter Bex Solide ICT - http://www.solide-ict.nl -------------- next part -------------- --- cell.rb.orig 2007-08-17 16:28:50.000000000 +0200 +++ cell.rb 2007-08-17 17:09:13.000000000 +0200 @@ -5,13 +5,11 @@ ### DISCUSS: is it ok as class var? can rendering happen parallel? cattr_reader :current_cell - attr_accessor :path attr_accessor :controller - - - def initialize(controller, path, options={}) + + def initialize(controller, name, options={}) @controller = controller - @path = path + @name = name @opts = options end @@ -50,16 +48,31 @@ end def render_view_for_state(state) + view_file = self.class.find_view_file(state) + if view_file + # this is the worst part: + render_string_from_view(view_file) + else + ### DISCUSS: do we need that for our beloved users? + "ATTENTION: cell view #{self.class.view_for_state(state)} + or any of its parent class view files is not readable/existing. + Further on, your cell method did not return a String." + end + end + + def self.find_view_file(state) view_file = view_for_state(state) - - ### DISCUSS: do we need that for our beloved users? - unless File.readable?(view_file) - return "ATTENTION: cell view #{view_file} is not readable/existing. - Further on, your cell method did not return a String." + + # puts "CHECKING: #{view_file}" + + if File.readable?(view_file) + # puts "FOUND! #{view_file}" + view_file + elsif superclass != Cell::Base + superclass.find_view_file(state) + else + nil end - - # this is the worst part: - return render_string_from_view(view_file) end def render_string_from_view(view_file) @@ -69,8 +82,13 @@ return content end + + def self.path + cell_name = self.name.underscore.sub(/_cell$/, '') + Cell::Registry.path(cell_name) + end - def view_for_state(state) + def self.view_for_state(state) "#{path}/views/#{state}.rhtml" end -------------- next part -------------- --- cell_registry.rb.orig 2007-08-17 16:28:58.000000000 +0200 +++ cell_registry.rb 2007-08-17 16:41:33.000000000 +0200 @@ -57,7 +57,7 @@ class Factory def self.create(controller, cell_name, opts={}) - Cell::Registry[cell_name].new(controller, Cell::Registry.path(cell_name), opts) + Cell::Registry[cell_name].new(controller, opts) end end From Peter.Bex at solide-ict.nl Mon Aug 20 07:55:00 2007 From: Peter.Bex at solide-ict.nl (Peter Bex) Date: Mon, 20 Aug 2007 13:55:00 +0200 Subject: [Cells-talk] Patch for ticket #1 Message-ID: <20070820115500.GB3491@darko.solide-ict.nl> Hi there, It turns out that ticket #1 runs deeper than simply being unable to use the instance variables of a cell. The way Cells currently renders a template is via the controller and it's @template instance of ActionView::Base. This means that instance variables need to be copied from the Cell into the current Controller. This is a breach of abstraction. Have a look at this example to see how it will break code in subtle ways: In app/controllers/foo_controller.rb: def test @one = 1 @two = 2 end In app/views/foo/test.rhtml: one = <%= @one %> two = <%= @two %> three = <%= @three %> <%= render_cell :bar, :clobber %> one = <%= @one %> two = <%= @two %> three = <%= @three %> In app/cells/bar_cell/bar_cell.rb: def clobber # no @one declared! @two = 200 @three = 300 end In app/cells/bar_cell/views/clobber.rhtml: In cell one = <%= @one %> In cell two = <%= @two %> In cell three = <%= @three %> This will render as follows: one = 1 two = 2 three = In cell one = 1 In cell two = 200 In cell three = 300 one = 1 two = 200 three = 300 This is NOT a good idea as it requires all cell makers to know all application makers' instance variables they will ever, possibly use in their controllers and the other way around. Here's a patch that both fixes ticket #1 and this bug, so the output will look like this: one = 1 two = 2 three = In cell one = In cell two = 200 In cell three = 300 one = 1 two = 2 three = Unfortunately, I haven't had the time to remove the contents from my previous mail from it. That means this patch applies to the clean cells version from RubyForge. Regards, Peter Bex Solide ICT - http://www.solide-ict.nl -------------- next part -------------- --- cell.rb.orig 2007-08-17 16:28:50.000000000 +0200 +++ cell.rb 2007-08-20 13:40:43.000000000 +0200 @@ -5,13 +5,11 @@ ### DISCUSS: is it ok as class var? can rendering happen parallel? cattr_reader :current_cell - attr_accessor :path attr_accessor :controller - - def initialize(controller, path, options={}) + def initialize(controller, name, options={}) @controller = controller - @path = path + @name = name @opts = options end @@ -37,7 +35,8 @@ ### DISCUSS: this is also a fix for bug#1, but is not needed ### in controller context. - #@controller.send :forget_variables_added_to_assigns + @controller.send :forget_variables_added_to_assigns + @controller.send :reset_variables_added_to_assigns content = send(state) @@ -50,27 +49,49 @@ end def render_view_for_state(state) - view_file = view_for_state(state) - + view_file = self.class.find_view_file(state) + if view_file + # this is the worst part: + render_string_from_view(view_file) + else ### DISCUSS: do we need that for our beloved users? - unless File.readable?(view_file) - return "ATTENTION: cell view #{view_file} is not readable/existing. + "ATTENTION: cell view #{self.class.view_for_state(state)} + or any of its parent class view files is not readable/existing. Further on, your cell method did not return a String." end + end - # this is the worst part: - return render_string_from_view(view_file) + def self.find_view_file(state) + view_file = view_for_state(state) + + # puts "CHECKING: #{view_file}" + + if File.readable?(view_file) + # puts "FOUND! #{view_file}" + view_file + elsif superclass != Cell::Base + superclass.find_view_file(state) + else + nil + end end def render_string_from_view(view_file) - clone_ivars_to(@controller) - content = @controller.send :render_to_string, :file => view_file - reset_ivars_in(@controller) + action_view = ActionView::Base.new(view_file, {}, @controller) + class << action_view + include ApplicationHelper + end + + clone_ivars_to(action_view) + action_view.render_template(File.extname(view_file)[1..-1], nil, view_file) + end - return content + def self.path + cell_name = self.name.underscore.sub(/_cell$/, '') + Cell::Registry.path(cell_name) end - def view_for_state(state) + def self.view_for_state(state) "#{path}/views/#{state}.rhtml" end @@ -83,12 +104,6 @@ end end - def reset_ivars_in(obj) - template_var_names.each do |var| - obj.instance_variable_set(var, nil) - end - end - def template_var_names ignore_list = ivars_to_ignore self.instance_variables.reject do |ivar| From nick at tesbo.com Tue Aug 28 10:11:02 2007 From: nick at tesbo.com (Nick Sutterer) Date: Tue, 28 Aug 2007 16:11:02 +0200 Subject: [Cells-talk] Patch for ticket #1 In-Reply-To: <20070820115500.GB3491@darko.solide-ict.nl> References: <20070820115500.GB3491@darko.solide-ict.nl> Message-ID: <200708281611.02114.nick@tesbo.com> hey peter, thanks a lot, your code looks really good and i'm very happy you provided a solution. :-) > The way Cells currently renders a template is via the controller and it's > @template instance of ActionView::Base. ?This means that instance variables > need to be copied from the Cell into the current Controller. ?This is a > breach of abstraction. ?Have a look at this example to see how it will > break code in subtle ways: > > This is NOT a good idea as it requires all cell makers to know all > application makers' instance variables they will ever, possibly use in > their controllers and the other way around. ?Here's a patch that both > fixes ticket #1 and this bug, so the output will look like this: > i was aware of this, and i also feeled ashamed for this problem. > Unfortunately, I haven't had the time to remove the contents from my > previous mail from it. ?That means this patch applies to the clean cells > version from RubyForge. > will apply and test, and release if all good. further on i will manage the svn access issue. do you want write access? nick From Peter.Bex at solide-ict.nl Tue Aug 28 10:33:15 2007 From: Peter.Bex at solide-ict.nl (Peter Bex) Date: Tue, 28 Aug 2007 16:33:15 +0200 Subject: [Cells-talk] Patch for ticket #1 In-Reply-To: <200708281611.02114.nick@tesbo.com> References: <20070820115500.GB3491@darko.solide-ict.nl> <200708281611.02114.nick@tesbo.com> Message-ID: <20070828143315.GE846@darko.solide-ict.nl> On Tue, Aug 28, 2007 at 04:11:02PM +0200, Nick Sutterer wrote: > > Unfortunately, I haven't had the time to remove the contents from my > > previous mail from it. ??That means this patch applies to the clean cells > > version from RubyForge. > > > will apply and test, and release if all good. further on i will manage the svn > access issue. do you want write access? That could make things considerably easier. Cheers, Peter Bex Solide ICT - http://www.solide-ict.nl