views:

45

answers:

1

I have two classes, Task and Subtask. Subtask varies very little from Task except for one important thing, it must include a different module.

The included modules, subtask_module and task_module, both have the same methods and aliases for my purposes, but internally they function a little differently once the included module extends its methods. There is no way around this for me because I'm using a plugin.

For instance, below, you see belongs_to in Task. belongs_to is extended from the included module, however its function differs slightly based on which module I include.

class Subtask < Task
  include subtask_module 
end

class Task
  include task_module

  # methods and aliases both classes use (defined in included file) 
  # but behavior changes based on
  # included file
  belongs_to :template    
end

What is the best way to do something like this? Right now it works as it is now. But it seems bloated because there will be unused things declared in Task that I don't need.

What is the best way?

+1  A: 

You could either turn Task into a subclass also, then have each inherit from something common (using your names from above wherever possible)

class Task
  belongs_to :template    
end

class Subtask1 < Task
  include subtask_file 
end

# this used to be Task, now is Subtask2
class Subtask2 < Task
  include task_file
end

Or, you move the shared functionality out to its own module, then include that, and avoid superclass / subclass altogether (I would opt for this one).

module TaskShared
  belongs_to :template    
end

class Task
  include TaskShared
  include task_file
end

class Subtask
  include TaskShared
  include subtask_file 
end

(The belongs_to might give you difficulty. If so, try adding it in the included hook)

module TaskShared
  def self.included(klass)
    klass.belongs_to :template
  end
end

Note that there are some circumstances where this gets sticky, such as inheriting from ActiveRecord::Base classes.

Joshua Cheek
I've tried the last method as well. Actually, I would like to inherit from ActiveRecord::Base, MongoMapper, Mongoid, etc, I was just trying to keep the question as non-library specific as possible.Indeed, I do get get errors with the aliases such as belongs_to and validate.
Dex
I think I would need more information to help you out. It has been a long time since I tried to subclass an AR::B class, because it ended up being an enormous hacky buggy pain. If I remember, the biggest problem is that most of the magic relies on various reflective methods that change when you subclass. I got around it by overriding a bunch of methods to basically lie to AR. Without knowing your specific implementation, I can't give advice, but generally, I think I would duplicate the schema, then move shared functionality out to a module and include it. (ie I implement enums this way)
Joshua Cheek
I agree, it's going to be a huge pain and I'm going to split it out into two files.
Dex