Forum: Ruby Design question: class methods verses initialize

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jason L. (Guest)
on 2009-01-22 17:42
I have a design question for a beginner:

what is better for my case?
I want to access functionality from a library I created.
I've tried class methods like this:

class Calc
  def Calc.velocity_head(v)
    v**2/(2.0*G)
  end
  def Calc.pressure_head(p)
    h = p / Gamma
  end
  def etc...
end

This is nice because now I can create many "velocity_head" objects or
"pressure_head" objects as needed by doing vh1 = Calc.velocity_head(4.5)
for example. But what if I have a bunch of methods in a class that all
require the same exact arguments? My first thought was using initialize
and instance variables:

Class Geom
  def initialize(b, y, m)
    @b, @y, @m = b, y, m
  end
  def area
    @a = (@b + @m * @y) * @y
  end
  def hyd_rad
    @r = (@b + @m * @y) * @y / (@b + 2.0 * @y * (1 + @m**2)**0.5)
  end
  def wet_perim
    @p = @b + 2.0 * @y * (1.0 + @m**2)**0.5
  end
  def etc...
end

But now I have to do area1 = Geom.new(4, 1.5, 2) and then area1.area
Is this the only other way to do this:?

Class Geom
  def Geom.area(b, y, m)
    a = (b + m * y) * y
  end
  def Geom.hyd_rad(b, y, m)
    r = (b + m * y) * y / (b + 2.0 * y * (1 + m**2)**0.5)
  end
  def Geom.wet_perim(b, y, m)
    p = b + 2.0 * y * (1.0 + m**2)**0.5
  end
  def etc...
end

I feel like I'm re-stating the arguments more than necessary. Could
someone give me some pointers? Thank you!
Yossef M. (Guest)
on 2009-01-22 23:43
(Received via mailing list)
On Jan 22, 9:40 am, Jason L. <removed_email_address@domain.invalid>
wrote:
> But what if I have a bunch of methods in a class that all
> require the same exact arguments? My first thought was using initialize
> and instance variables:

This is a classic case of the Extract Class pattern (http://
www.refactoring.com/catalog/extractClass.html). It's a good first
thought to have, Jason. (Or on second thought, it'd be Extract Class
if this functionality were already present in a separate class. Is
there a refactoring pattern called "Use Instances of Already-Present
Class"? I purport this is a classic case of a pattern whose name I
can't think of right now.)

o< snip example >o

>   def Geom.wet_perim(b, y, m)
>     p = b + 2.0 * y * (1.0 + m**2)**0.5
>   end
>   def etc...
> end
>
> I feel like I'm re-stating the arguments more than necessary. Could
> someone give me some pointers? Thank you!

So, as you realized, there's some trouble with only using instances of
a class. Here's one solution:

class Geom
  def initialize(b, y, m)
    @b, @y, @m = b, y, m
  end

  def area
    (@b + @m * @y) * @y
  end

  def hyd_rad
    (@b + @m * @y) * @y / (@b + 2.0 * @y * (1 + @m**2)**0.5)
  end

  def wet_perim
    @b + 2.0 * @y * (1.0 + @m**2)**0.5
  end

  class << self
    def area(b, y, m)
      new(b, y, m).area
    end

    def hyd_rad(b, y, m)
      new(b, y, m).hyd_rad
    end

    def wet_perim(b, y, m)
      new(b, y, m).wet_perim
    end
  end
end

I'm sure you see the pattern there. You have your instance methods
that can take advantage of storing away the variables upon
initialization, but you also have your class methods for convenience
if area1 = Geom.new(b, y, m).area offends you. And if the repetition
there is a concern, it's just a SMOMP away from cleanliness.

Hope that helps. Have a nice day.

Also, as a side note not entirely relevant to the topic at hand, I'm
not quite familiar with some of these variables and calculations.
Maybe it's been too long for me, but I can't figure out what kind of
area equation needs to have two multiplications. And I can't figure
out what b, y, and m stand for.
Jason L. (Guest)
on 2009-01-23 00:01
> Maybe it's been too long for me, but I can't figure out what kind of
> area equation needs to have two multiplications. And I can't figure
> out what b, y, and m stand for.

I am solving for the area of flow in a trapezoidal shaped ditch
(channel). b is bottom width, y is depth of flow, and m is the side
slope as m:1.

You know, I didn't think of area1 = Geom.new(b, y, m).area

I guess that isn't too bad.
This topic is locked and can not be replied to.