0

Using Ruby 2.0. Here's my code:

module Test
  class A
    def initialize(x)
      @x = x
      foo
    end

    def foo
      p @x
      update(@x) # only if it's a Test::C object or called from Test::C
    end
  end
end

module Test
  class B < A
    def foo
      @x += 2
      super
    end
  end
end

module Test
  class C < A
    def foo
      @x += 1
      super
    end
  end
end

def update(x)
  if x > 100
    Test::B.new(x)
  else
    Test::C.new(x)
  end
end

x = 100
update(x)

Here's what I am trying to achieve:

In Test::A#foo, update(@x) should be called only if it were called from Test::C#foo or it's a Test::C object.

The first time update(x) is called, x = 100, so the operation should +1 and then move on to Test::B#foo once. How do I achieve this?

2
  • What is "it" in "...or it's a Test::C object"? Commented Jun 10, 2015 at 18:28
  • 1
    This question is very unclear since you specify update at the highest level but then call it inside Test::A#foo and you never actually call the foo method anywhere so nothing is actually happening here. If Test::A#foo should only be called from Test::C#foo then that is where you implement it. If Test::A does not need to update and Test::B does not need to update why would you put the logic at such a high level? Also this does not seem to have anything to do with recursion at all Commented Jun 10, 2015 at 18:36

1 Answer 1

1

The parent class should not have to care about subclasses. This design you have here implies it needs to know, which is broken and over-complicates things.

In any case, if you do need to trap certain cases:

case (self)
when Test::A, Test::B
  # ... Do stuff
  update(@x)
end

If Test::A and Test::B care about that operation, they should call it when necessary:

def foo
  @x += 1
  super
  update(x)
end
Sign up to request clarification or add additional context in comments.

2 Comments

I could probably do this update(@x) if self.is_a?(Test::C), but is there a better way to write it? Actually don't need to worry about the value, but my end goal is: everytime Test::C is initialized, it should run foo based on Test::C once, then run it again as Test::B.
While you can do that, it doesn't mean you should. Generally it's best to put class-specific logic in the subclass and have the parent class unconcerned with those details. Translating your goal to Ruby, that'd imply you do something inside Test::C#initialize, for example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.