When using a Connection class and setting variables via instance_eval, they are nil in post_init, but available in receive_data. Where is the best place to initialize per connection variables that depend on the variables I created via instance_eval? Chris
On 11/6/06, snacktime <snacktime at gmail.com> wrote:> When using a Connection class and setting variables via instance_eval, > they are nil in post_init, but available in receive_data. Where is > the best place to initialize per connection variables that depend on > the variables I created via instance_eval? > > Chrisbest way to achieve this..to use class_eval and defer the evaluation...till the class is intantiated or inherited as _why has demonstrated in Dwemthy''s Army. Though..i am no expert in meta programming...i may be able to help..if you post the code snippet. -- There was only one Road; that it was like a great river: its springs were at every doorstep, and every path was its tributary.
On 11/6/06, hemant <gethemant at gmail.com> wrote:> On 11/6/06, snacktime <snacktime at gmail.com> wrote: > > When using a Connection class and setting variables via instance_eval, > > they are nil in post_init, but available in receive_data. Where is > > the best place to initialize per connection variables that depend on > > the variables I created via instance_eval? > > > > Chris > > best way to achieve this..to use class_eval and defer the > evaluation...till the class is intantiated or inherited as _why has > demonstrated in Dwemthy''s Army. > > Though..i am no expert in meta programming...i may be able to help..if > you post the code snippet. >Something like this: class Foobar < EventMachine::Connection def self.metaclass;class <<self;self;end;end; def self.traits # initialize your instance variables here..with instance_eval of preferably class_eval end traits :variables end -- There was only one Road; that it was like a great river: its springs were at every doorstep, and every path was its tributary.
Francis Cianfrocca
2006-Nov-06 05:04 UTC
[Eventmachine-talk] Why instance variables not visible in
On 11/6/06, snacktime <snacktime at gmail.com> wrote:> When using a Connection class and setting variables via instance_eval, > they are nil in post_init, but available in receive_data. Where is > the best place to initialize per connection variables that depend on > the variables I created via instance_eval?Chris, I''d add this to Hemant''s good suggestion: There is a defined protocol for how these methods get called, and I''ve tried to be careful about not changing it. For example, I found the following comment in the source code for EventMachine::connect: # Ok, added support for a user-defined block, 13Apr06. # This leads us to an interesting choice because of the # presence of the post_init call, which happens in the # initialize method of the new object. We call the user''s # block and pass the new object to it. This is a great # way to do protocol-specific initiation. It happens # AFTER post_init has been called on the object, which I # certainly hope is the right choice. # Don''t change this lightly, because accepted connections # are different from connected ones and we don''t want # to have them behave differently with respect to post_init # if at all possible.
On 11/6/06, hemant <gethemant at gmail.com> wrote:> On 11/6/06, snacktime <snacktime at gmail.com> wrote: > > When using a Connection class and setting variables via instance_eval, > > they are nil in post_init, but available in receive_data. Where is > > the best place to initialize per connection variables that depend on > > the variables I created via instance_eval? > > > > Chris > > best way to achieve this..to use class_eval and defer the > evaluation...till the class is intantiated or inherited as _why has > demonstrated in Dwemthy''s Army. > > Though..i am no expert in meta programming...i may be able to help..if > you post the code snippet.Basically what I want is to pass server specific variables to the Connection class like what host/port it is running on, and there can be multiple servers using the same Connection class. If I use class variables, then as far as my understanding goes they are global across all instances of that class, which I don''t want. I can access instance variables in receive_data, but then I end up with something like this: def receive_data data getconfig if connected? # process data end
Well the solution was to call a method in the Connection class via instance_eval instead of just setting the variables, that way I can run the setup code that is needed before receive_data is called, like so: server1 = EmProxy::ServerConfig.new(''localhost'',8080) server1.add_backend(''localhost'',80) EventMachine.start_server(server1.host, server1.port, EmProxy::HttpServer) {|c| c.instance_eval {setconfig(server1)} }
On 11/7/06, snacktime <snacktime at gmail.com> wrote:> On 11/6/06, hemant <gethemant at gmail.com> wrote: > > On 11/6/06, snacktime <snacktime at gmail.com> wrote: > > > When using a Connection class and setting variables via instance_eval, > > > they are nil in post_init, but available in receive_data. Where is > > > the best place to initialize per connection variables that depend on > > > the variables I created via instance_eval? > > > > > > Chris > > > > best way to achieve this..to use class_eval and defer the > > evaluation...till the class is intantiated or inherited as _why has > > demonstrated in Dwemthy''s Army. > > > > Though..i am no expert in meta programming...i may be able to help..if > > you post the code snippet. > > Basically what I want is to pass server specific variables to the > Connection class like what host/port it is running on, and there can > be multiple servers using the same Connection class. If I use class > variables, then as far as my understanding goes they are global across > all instances of that class, which I don''t want. I can access > instance variables in receive_data, but then I end up with something > like this: > > def receive_data data > getconfig if connected? > # process data > endYes true..class variables are global to class. But you didn''t get my point. What I was saying is: class IntelligentLife def IntelligentLife.home_planet class_eval("@@home_planet") end def IntelligentLife.home_planet=(x) class_eval("@@home_planet = #{ x} ") end #... end class Terran < IntelligentLife @@home_planet = "Earth" #... end class Martian < IntelligentLife @@home_planet = "Mars" #... end puts Terran.home_planet # Earth puts Martian.home_planet # Mars You remove class_eval and both your puts will return the same thing.(example is from Hal fulton''s Ruby way) Another approach could be: class Class def initialize(klass, &block) block = Proc.new class_eval(&block) end end class IntelligentLife def IntelligentLife.home_planet class_eval("@@home_planet") end def IntelligentLife.home_planet=(x) class_eval("@@home_planet = #{ x} ") end #... end Terran = Class.new(IntelligentLife) do @@home_planet = "Earth" end Martian = Class.new(IntelligentLife) do @@home_planet = "Mars" end I am already using it for writting connection classes. Where server and client both classes will derive from this ConnectionClass and override some of the defaults. I will dynamically hookup couple of parsers and ready to go. Anyway..in the end, whatever works for you. -- There was only one Road; that it was like a great river: its springs were at every doorstep, and every path was its tributary.
On 11/7/06, hemant <gethemant at gmail.com> wrote:> On 11/7/06, snacktime <snacktime at gmail.com> wrote: > > On 11/6/06, hemant <gethemant at gmail.com> wrote: > > > On 11/6/06, snacktime <snacktime at gmail.com> wrote: > > > > When using a Connection class and setting variables via instance_eval, > > > > they are nil in post_init, but available in receive_data. Where is > > > > the best place to initialize per connection variables that depend on > > > > the variables I created via instance_eval? > > > > > > > > Chris > > > > > > best way to achieve this..to use class_eval and defer the > > > evaluation...till the class is intantiated or inherited as _why has > > > demonstrated in Dwemthy''s Army. > > > > > > Though..i am no expert in meta programming...i may be able to help..if > > > you post the code snippet. > > > > Basically what I want is to pass server specific variables to the > > Connection class like what host/port it is running on, and there can > > be multiple servers using the same Connection class. If I use class > > variables, then as far as my understanding goes they are global across > > all instances of that class, which I don''t want. I can access > > instance variables in receive_data, but then I end up with something > > like this: > > > > def receive_data data > > getconfig if connected? > > # process data > > end > > Yes true..class variables are global to class. But you didn''t get my > point. What I was saying is: > > class IntelligentLife > > def IntelligentLife.home_planet > class_eval("@@home_planet") > end > > def IntelligentLife.home_planet=(x) > class_eval("@@home_planet = #{ x} ") > end > > #... > end > > class Terran < IntelligentLife > @@home_planet = "Earth" > #... > end > > class Martian < IntelligentLife > @@home_planet = "Mars" > #... > end > > puts Terran.home_planet # Earth > puts Martian.home_planet # Mars > > You remove class_eval and both your puts will return the same > thing.(example is from Hal fulton''s Ruby way) > > Another approach could be: > > class Class > > def initialize(klass, &block) > block = Proc.new > class_eval(&block) > end > > end > > > class IntelligentLife > > def IntelligentLife.home_planet > class_eval("@@home_planet") > end > > def IntelligentLife.home_planet=(x) > class_eval("@@home_planet = #{ x} ") > end > > #... > > end > > Terran = Class.new(IntelligentLife) do > @@home_planet = "Earth" > end > > Martian = Class.new(IntelligentLife) do > @@home_planet = "Mars" > end > > I am already using it for writting connection classes. Where server > and client both classes will derive from this ConnectionClass and > override some of the defaults. I will dynamically hookup couple of > parsers and ready to go. > > Anyway..in the end, whatever works for you. > > -- > There was only one Road; that it was like a great river: its springs > were at every doorstep, and every path was its tributary. >If you update your local EM code...you may find that Francis has added a reconnect method in EventMachine::Connection class. I find it pretty useful. So..i have reconnect hook defined in ConnectionClass itself. I define an attribute like: class ClientClass < ActiveTcp::ConnectionClass acts_as_client true end note that..though acts_as_client is a class method, but it sets corresponding instance variable in derived class. So, whenever ConnectionClass finds that acts_as_client is true for the current object..and if connection is lost it will automatically try to reconnect. ClientClass, won''t be even aware of this. -- There was only one Road; that it was like a great river: its springs were at every doorstep, and every path was its tributary.
Thanks for the explanation, I didn''t understand it until your example. But what happens if you are using the same class for multiple servers, like so: class TcpConnection < EventMachine::Connection def TcpConnection.config class_eval("@@config") end def TcpConnection.config=(config) class_eval("@@config = #{config}") end end class HttpServer < TcpConnection end And then you have multiple http servers: EventMachine.start_server(host, port, EmProxy::HttpServer) {|c| c.class_eval {@@config=config1} } EventMachine.start_server(host, port, EmProxy::HttpServer) {|c| c.class_eval {@@config=config2} } Will that work, or will @@config = config2 for both instances of HttpServer? Chris