Rahul
Rahul

Reputation: 321

Reduce number of instance methods

I am modelling a report as a class and each column value as an accessor. Each value in the report needs to be accessed from the database. But this makes the class look quite fat and RubyMine warns me of too many methods in class.

class Report

attr_accessor :name, :col1, :col2, :col3 .... :col15

def col1
 db.find({x: 1})['some_var']
end

def col2
 db.find({y: 4})['some_other_var']
end

and so forth for each attribute...

end

Since each getter is essentially single line that makes call to database, is there a simpler way to declare these vars without being in a method?

I don't want to set these in the initialize method as these reports will be subclassed and child reports will not have all/some of these attributes.

Upvotes: 0

Views: 166

Answers (2)

Mosab Muhammad
Mosab Muhammad

Reputation: 104

You can use meta-programming to create attr_accessor like methods on the fly.

For Example:

class Report
  def initialize(attributes)
    attributes.each do |attribute|
      define_singleton_method :"#{attribute}" do |hash_param, string_param|
        db.find(hash_param)[string_param]
      end
    end
  end
end

Then you can create new report object and pass attribute names as follow:

r = Report.new(["n","m"])

Now you can call n and m methods on the r object

r.m({val1: "val1"}, "val2")
r.n({val2: "val1"}, "val2")

Upvotes: 1

lacostenycoder
lacostenycoder

Reputation: 11216

@Rahul based on answer to my question, the only advice I can give here then is to use best OOP design principles. Subclass and modularize where possible as well as using ruby meta-programming. If you need the methods, they have to be written somewhere. But if you only need getters, consider attr_reader instead, unless you'll need setters too.

If you can get the column names you can use dynamic method definition with something like this assuming db is magically defined somewhere you have not made clear, we'll assume it's a connection to the database.

class Report

  db.column_names.each do |col|
    define_method(col.to_sym) { db.find(options={}) }
  end

end

If you just want RubyMine to stop nagging you, I assume it's using rubocop and you can see this post for how to override rules.

https://www.jetbrains.com/help/ruby/2017.1/rubocop.html

or

https://github.com/rubocop-hq/rubocop

Upvotes: 0

Related Questions