Is there such a thing? I have some duplicate methods in my models, can I place them somewhere and call them in to my models, thus keeping DRY? -- Posted via http://www.ruby-forum.com/.
Put them in a superclass? Tony On 2/21/06, James Whittaker <jmwhittaker@gmail.com> wrote:> > Is there such a thing? > > I have some duplicate methods in my models, can I place them somewhere > and call them in to my models, thus keeping DRY? > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060221/48892b63/attachment-0001.html
Hello James, 2006/2/21, James Whittaker <jmwhittaker@gmail.com>:> Is there such a thing?Put them in a module, and include the module in your models. The module should go into lib/, and the file name should reflect Rails conventions so that the simple include will be all you need. Hope that helps ! -- Fran?ois Beausoleil http://blog.teksol.info/
On Feb 21, 2006, at 2:01 PM, James Whittaker wrote:> Is there such a thing? > > I have some duplicate methods in my models, can I place them somewhere > and call them in to my models, thus keeping DRY?This is what inheritance is for. -- Eric Hodel - drbrain@segment7.net - http://segment7.net This implementation is HODEL-HASH-9600 compliant http://trackmap.robotcoop.com
Someone tell Eric about modules :-) -- Posted via http://www.ruby-forum.com/.
Eric Hodel wrote:> On Feb 21, 2006, at 2:01 PM, James Whittaker wrote: > >> Is there such a thing? >> >> I have some duplicate methods in my models, can I place them somewhere >> and call them in to my models, thus keeping DRY? > > > This is what inheritance is for. >Yes, really... I''m still pretty new to rails but this advice of "put your common model behavior in a mixin" while models have to inherit from the framework''s ORM solution just seems absolutely bass-ackwards! Some day I will learn enough rails/ruby to make ActiveRecord (or Og) a mixin and have my simple POROs (plain ol ruby objects) left totally untouched by the framework. :-) b
Another option in an intermediate class: modela < basemodel < activerecord. I think Dave Thomas blogged about doing just such a thing in an import scenario. Jack -- Posted via http://www.ruby-forum.com/.
On Feb 21, 2006, at 10:27 PM, Andy wrote:> Someone tell Eric about modules :-)You must like overly-complex overly-obfuscated code then. You can''t easily add validations with modules, you can with inheritance. You can''t easily add relationships with modules, you can with inheritance. You can''t easily override base class methods via modules, you can with inheritance. I''ve been writing Ruby a long time, and I''ve found that use of included, extended, append_features and alias are best used when you need to be clever and can''t use features like inheritance to accomplish your goals. After all, Ruby is an OO language, so if you treat it as such it will help you accomplish your goals without getting in your way. When you are frequently use append_features or extended or included you add complexity you don''t need which ultimately leads to confusion when you need to figure out what you did last week, last month or last year. You''re also violating DRY when you use the module and class callbacks and alias instead of inheritance because the language built inheritance in for you. There''s no need for you to go behind the language''s back. Compare inheritance: class Mine < Theirs def my_method(some_arg) super(some_arg + 1) end end Simple, elegant, expressive and short, only 5 total lines to override my_method to provide custom behavior. With modules: module AddOne def self.included(klass) klass.class_eval do alias_method :my_method_without_add, :my_method alias_method :my_method, :my_method_with_add end end def my_method_with_add(some_arg) my_method_without_add(some_arg + 1) end end class Theirs include AddOne end This is much longer, 14 lines, and much more difficult to figure out if you want to change the behavior at a future date. This also raises many questions: What classes can AddOne be applied to? By looking at class Theirs, what behavior can I depend upon when calling my_method? What do I do if I want to extend the behavior of my_method twice? Does order of include matter? If I call include from the same file as the module I''ve pushed the dependencies down to the order of require. (This is especially bad, order of requires should not be important to correct functioning of your code, they should just enumerate the transitive closure for your dependencies.) Unlike Comparable or Enumerable which have well-defined and unchanging features, custom modules are likely to incorporate a large set of functionality so you lose information about the functionality of your program because either: You call include from your only class definition so don''t know what include will ultimately do. You call include from the module definition file, so don''t know that include was called at all. Now you have to look in two places to determine what a given method will do, but you may not even know to look. Refactoring is harder because your dependencies are spread out too much. I''d rather reserve my fancy Module and Class callbacks for the places I really need them, like MuffDaddy. -- Eric Hodel - drbrain@segment7.net - http://segment7.net This implementation is HODEL-HASH-9600 compliant http://trackmap.robotcoop.com
Eric Hodel wrote:> I''d rather reserve my fancy Module and Class callbacks for the places > I really need them, like MuffDaddy.OK, I''ll ask: what does MuffDaddy do? Joe -- Posted via http://www.ruby-forum.com/.
Well stated. So, how do you feel about models inheriting from ActiveRecord rather than having persistence mixed-in? b Eric Hodel wrote:> On Feb 21, 2006, at 10:27 PM, Andy wrote: > >> Someone tell Eric about modules :-) > > > You must like overly-complex overly-obfuscated code then. > > You can''t easily add validations with modules, you can with inheritance. > > You can''t easily add relationships with modules, you can with inheritance. > > You can''t easily override base class methods via modules, you can with > inheritance. > > I''ve been writing Ruby a long time, and I''ve found that use of > included, extended, append_features and alias are best used when you > need to be clever and can''t use features like inheritance to accomplish > your goals. After all, Ruby is an OO language, so if you treat it as > such it will help you accomplish your goals without getting in your way. > > When you are frequently use append_features or extended or included you > add complexity you don''t need which ultimately leads to confusion when > you need to figure out what you did last week, last month or last year. > > You''re also violating DRY when you use the module and class callbacks > and alias instead of inheritance because the language built inheritance > in for you. There''s no need for you to go behind the language''s back. > > Compare inheritance: > > class Mine < Theirs > def my_method(some_arg) > super(some_arg + 1) > end > end > > Simple, elegant, expressive and short, only 5 total lines to override > my_method to provide custom behavior. > > With modules: > > module AddOne > def self.included(klass) > klass.class_eval do > alias_method :my_method_without_add, :my_method > alias_method :my_method, :my_method_with_add > end > end > > def my_method_with_add(some_arg) > my_method_without_add(some_arg + 1) > end > end > > class Theirs > include AddOne > end > > This is much longer, 14 lines, and much more difficult to figure out if > you want to change the behavior at a future date. > > This also raises many questions: > > What classes can AddOne be applied to? > > By looking at class Theirs, what behavior can I depend upon when > calling my_method? > > What do I do if I want to extend the behavior of my_method twice? Does > order of include matter? If I call include from the same file as the > module I''ve pushed the dependencies down to the order of require. > > (This is especially bad, order of requires should not be important to > correct functioning of your code, they should just enumerate the > transitive closure for your dependencies.) > > Unlike Comparable or Enumerable which have well-defined and unchanging > features, custom modules are likely to incorporate a large set of > functionality so you lose information about the functionality of your > program because either: > > You call include from your only class definition so don''t know what > include will ultimately do. > > You call include from the module definition file, so don''t know that > include was called at all. > > Now you have to look in two places to determine what a given method > will do, but you may not even know to look. > > Refactoring is harder because your dependencies are spread out too much. > > I''d rather reserve my fancy Module and Class callbacks for the places I > really need them, like MuffDaddy. >
Eric Hodel wrote:> On Feb 21, 2006, at 2:01 PM, James Whittaker wrote: > >> Is there such a thing? >> >> I have some duplicate methods in my models, can I place them somewhere >> and call them in to my models, thus keeping DRY? > > This is what inheritance is for.Hmmmm. I''d suggest this is not what inheritance is *for*. Inheritance is a necessary mechanism for polymorphism is some languages, and a mechanism for varying behaviour. If I need to be able to not care whether its a Person or Company, all I care about is that it has methods for manipulating the address, I can have an Addressable base class and hey presto, polymorphism. I can also vary the behaviour in the subclasses (as you point out in a later post). In removing duplicated code in a class, you can either use "Extract Superclass" or just plain old "Extract Class" and which way I go very much depends on exactly what those duplicate methods are. Inheritance may be the way to go here, if it looks like both those models may need to vary the behaviour (no need to worry about the polymorphic angle thanks to duck typing! :). If, however, the methods are orthogonal to the Model classes, it could be more sensible to pull them out into a class of their own, and aggregate as necessary, or as a Module, and mixin as necessary. I''m not saying you''re wrong, Eric, just that you''re not necessarily right :-) James, are you at liberty to give us a flavour of the nature of the duplication ? A. -- Posted via http://www.ruby-forum.com/.
On Feb 22, 2006, at 4:03 PM, Joe wrote:> Eric Hodel wrote: >> I''d rather reserve my fancy Module and Class callbacks for the places >> I really need them, like MuffDaddy. > > OK, I''ll ask: what does MuffDaddy do?Its the ultimate rapper. http://blog.zenspider.com/archives/2005/02/muffdaddy_the_u.html -- Eric Hodel - drbrain@segment7.net - http://segment7.net This implementation is HODEL-HASH-9600 compliant http://trackmap.robotcoop.com