hello, given: 1. class C that implements some arbitrary methods 2. a database with code fragments stored as text i create a variable 'var' of class C and then read some code fragments from the database. each fragment i read is evaluated in a dynamic anonymous module, and this module is used to extend 'var': var = C.new .. . . m = Module.new m.module_eval(code_fragment) .. . . var.extend(m) so if a fragment implements some methods that are already defined in C mixing in effectively replaces the original methods with the ones defined in the fragment. the problem: class C defines an instance variable @x: class C def initialize; @x = 'C'; end def to_s; @x; end end i want to override 'to_s' method. but the new implementation that i have in my fragment still needs to refer to @x. so i do this: fragment = "def to_s; foo(@x); end" this works fine. but this does not seem like a good programming style. a module refers to a variable that is defined in the object that this module happens to be mixed in to. can anyone comment on this? basically the problem is to be able to override the behaviour of 'var' at run time as code fragments are read. to give a concrete example of what i am trying to do, suppose you have a database with text fields. each field is represented at run time by class C that can be converted to a string. the basic to_s implementation just outputs the value of the text field. but i want to also store text fields that contain textile markup, or eruby markup or whatever, in other words i want to associate a type with each text field and i want the to_s method to behave differently depending on the type. but for to_s to be able to run it needs to get the value of the text field from C. thanks konstantin
on 2006-02-08 05:03
on 2006-02-08 20:38
hello, let me rephrase the question, may be this will get more responses: is it a bad programming style in ruby to use 'super' in a module definition? that is, is it bad to invoke methods that will be defined in the object that will mix in this module? thanks konstantin
on 2006-02-08 21:18
konsu wrote: > class C defines an instance variable @x: > > class C > def initialize; @x = 'C'; end > def to_s; @x; end > end > > i want to override 'to_s' method. but the new implementation that i have > in my fragment still needs to refer to @x. I don't see a (stylistic or whatever) problem in directly referring to @x from the module. Since it works, it must be supposed to be done like this, I guess. Malte
on 2006-02-08 22:25
On 2/8/06, konsu <email@example.com> wrote: > is it a bad programming style in ruby to use 'super' in a module definition? I don't think so. I myself haven't yet run into the need to call super in a module method, but I don't see why you shouldn't be able to, as long as you make that expectation clear in the documentation for anyone that might try and mix it in. > that is, is it bad to invoke methods that will be defined in the object that > will mix in this module? Definitely not. The implementation of the methods provided by enumerable are based on the assumption that the class that is mixing in Enumerable will provide a few bootstrap methods, such as each. If you try and mix in Enumerable without defining each, things just won't work. The important thing is that this dependency/expectation is provided up front in the documentation. Regarding your original question on using @instance_vars in module methods, I skipped over it at first since I wasn't fully sure about which part of your question was about modules in general and which was about eval'ing code from the DB. I'll try to answer the general portion now... There is nothing wrong with using @instance_vars in module methods that are intended to be mixed in. You need to be careful though. I consider two types of instance vars that a module method might use: * variables used exclusively by the module * variables the module expects the class to provide In the first case, the module is keeping its own state for its operations. The class that's mixing in the module should not care about these instance variables and should leave them alone. As such, you need to be very careful that you don't stomp on any of the class' instance variables, and that it won't stomp on yours. This requires very careful naming. In the second case, I'd consider refactoring the module method to use accessor methods on the class and thus abstract away the implementation. This makes it easier to then adapt other classes which may have different implementations to use the same mixin. Then, of course, document the required *interface* (as opposed to required instance variables) as mentioned above. Jacob F.
on 2006-02-08 23:17
DÅ?a Streda 08 FebruÃ¡r 2006 19:38 konsu napÃsal: > is it a bad programming style in ruby to use 'super' in a module > definition? that is, is it bad to invoke methods that will be defined in > the object that will mix in this module? > Actually, I'll go a bit further than Jacob and say that is -exactly- what mixins are supposed to do - enhance the functionality by providing some extra methods that build on existing class functionality. Mixins that are completely independent from the class would best be separated into stand-alone classes in the most cases. As far as instance variables go, I tend to avoid making stateful mixins myself, and prefer using accessor methods instead of directly accessing the including class. I could go on about decoupling logic in here, but it pretty much boils down to a matter of taste / religion. David V.