Reputation: 4792
I am using Ruby on Rails 3.2.9 and Ruby 1.9.3. I have many model classes implementing similar methods as-like the following:
class ClassName_1 < ActiveRecord::Base
def great_method
self.method_1
end
def method_1 ... end
end
class ClassName_2 < ActiveRecord::Base
def great_method
result_1 = self.method_1
result_2 = self.method_2
result_1 && result_2
end
def method_1 ... end
def method_2 ... end
end
...
class ClassName_N < ActiveRecord::Base
def great_method
result_1 = self.method_1
result_2 = self.method_2
...
result_N = self.method_N
result_1 && result_2 && ... && result_N
end
def method_1 ... end
def method_2 ... end
...
def method_N ... end
end
Those model classes behaves almost the same (not the same) since some of those has an interface with some less or more methods. All methods are differently named (for instance, method_1
could be named bar
and method_2
could be named foo
), all return true
or false
, are always the same in each class and there is no relation between them.
What is the proper way to refactor those classes?
Note: At this time I am thinking to refactor classes by including the following module in each one:
module MyModule
def great_method
result_1 = self.respond_to?(:method_1) ? self.method_1 : true
result_2 = self.respond_to?(:method_2) ? self.method_2 : true
...
result_N = self.respond_to?(:method_N) ? self.method_N : true
result_1 && result_2 && ... && result_N
end
end
But I don't know if it is the proper way to accomplish what I am looking for. Furthermore, I am not sure of related advantages and disadvantages...
Upvotes: 0
Views: 821
Reputation: 32126
I would use a metaprogramming solution to clean this up somewhat.
module BetterCode
extend ActiveSupport::Concern
module ClassMethods
def boolean_method(name, *components)
define_method name do
components.all? { |c| send c }
end
end
end
end
And in your models:
class MyModel < ActiveRecord::Base
include BetterCode
boolean_method :great_method, :foo, :bar, :baz, :quux
end
Instances of MyModel
will then respond to great_method
with a boolean value indicating whether or not foo
, bar
, baz
and quux
are all true.
Upvotes: 1
Reputation: 7403
You can abstract out the great_method
with something like this:
require 'active_support/concern'
module Greatest
extend ActiveSupport::Concern
module ClassMethods
attr_accessor :num_great_methods
def has_great_methods(n)
@num_great_methods = n
end
end
def great_method
(1..self.class.num_great_methods).each do |n|
return false unless self.__send__("method_#{n}")
end
true
end
end
class ClassName_3
include Greatest
has_great_method 3
# stub out the "method_*" methods
(1..3).each do |n|
define_method "method_#{n}" do
puts "method_#{n}"
true
end
end
end
puts ClassName_1.new.greatest
Upvotes: 0
Reputation: 21
Looks like you're on the right track. If the method_n methods are unique to your classes then just build the module that you already have into a superclass that each ClassNameN inherits from:
class SuperClassName < ActiveRecord::Base
def great_method
#... what you have in your module
end
end
class ClassNameN < SuperClassName
def method_1 ... end
def method_2 ... end
end
There may be additional ways for you to factor out code depending on what goes on in your method_n methods, but it's impossible to say without more detail.
Upvotes: 1