Changing method behavior depending on context

Assume there is class A with method save which takes one param with
default value (e.g. true). Class A instance gets save and behaves
depending on true value.
Assume there is class B with a field of type A. Calling save on this
field it should behave as if save(false) was called.
Outside of class B scope save method should behave originally.
Something like override, but just inside of one scope.

Here is some piece of code:
class A
def save(validate = true)
validate? «INVALID»: «VALID»
end
end

class B

something very crazy

def initialize
@a = A.new
end
def save
@a.save
end
end

A.new.save # => «INVALID»
B.new.save # => «VALID»
A.new.save # => «INVALID»

It is meant to be used in Rails application with ActiveRecord objects,
but it really doesn’t matter much.
The most simple way here is probably examining caller list, but is there
a way to redef a method inside of other class’ scope?

On Fri, Mar 26, 2010 at 5:11 PM, Marat K. [email protected]
wrote:

def save(validate = true)
@a.save
a way to redef a method inside of other class’ scope?
I have no clue if this works or not with ActiveRecord objects, but in
case it does, I would do this:

irb(main):006:0> class A
irb(main):007:1> def save(validate=true)
irb(main):008:2> validate ? “INVALID” : “VALID”
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> class B
irb(main):012:1> def initialize
irb(main):013:2> @a = A.new
irb(main):014:2> def @a.save(validate=true)
irb(main):015:3> super false
irb(main):016:3> end
irb(main):017:2> end
irb(main):018:1> def save
irb(main):019:2> @a.save
irb(main):020:2> end
irb(main):021:1> end
=> nil
irb(main):022:0> B.new.save
=> “VALID”
irb(main):023:0> A.new.save
=> “INVALID”

Although if this works for you, you could also change the save method
in class B to pass a false…

irb(main):001:0> class A
irb(main):002:1> def save(validate=true)
irb(main):003:2> validate ? “INVALID” : “VALID”
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> class B
irb(main):007:1> def initialize
irb(main):008:2> @a = A.new
irb(main):009:2> end
irb(main):010:1> def save
irb(main):011:2> @a.save false
irb(main):012:2> end
irb(main):013:1> end
=> nil
irb(main):014:0> A.new.save
=> “INVALID”
irb(main):015:0> B.new.save
=> “VALID”

Jesus.

On 03/26/2010 05:11 PM, Marat K. wrote:

def save(validate = true)
@a.save
a way to redef a method inside of other class’ scope?
What’s wrong with doing

class B

something very crazy

def initialize
@a = A.new
end
def save
@a.save false
end
end

as Jesus suggested? Even if you don’t do that you could do

class A
def initialize(owner = nil)
@owner = owner
end

def save
B === @owner ? “VALID” : “INVALID”
end
end

class B

something not so crazy

def initialize
@a = A.new self
end
def save
@a.save
end
end

Note: meta programming magic also makes code harder to read.

Kind regards

robert

Thanks Jesus and Robert! But the case is quite more complex because (I
forgot to mention in original message) I’m not calling B#save directly -
it’s a part of a big class which builds many objects and the option is
either replace all .save with .save(false) or to make some monkey magic.
The B class might go into some lib or plugin (but not sure yet) so I
need to find a way for this case also.

My friend and I came to this kind of solution:
class B
def initialize
@a=A.new
@a.instance_eval <<-EOF
alias :old_save :save
def save(validate = false)
old_save(validate)
end
EOF
end

The only thing that this would save without validation only one time, if
there’d be smth like
class B
def initialize
@a1 = A.new
@a2 = A.new
end
def save
@a1.save
@a2.save # it wouldn’t work here or I’d need to define same methods
n times
end
end

I will agree if you say that doesn’t worth that but that becomes a ruby
riddle - is it powerful enough to change behaviour depending on context?
I think it is. Curious how.

Robert K. wrote:

On 03/26/2010 05:11 PM, Marat K. wrote:

def save(validate = true)
@a.save
a way to redef a method inside of other class’ scope?
What’s wrong with doing

class B

something very crazy

def initialize
@a = A.new
end
def save
@a.save false
end
end

as Jesus suggested? Even if you don’t do that you could do

class A
def initialize(owner = nil)
@owner = owner
end

def save
B === @owner ? “VALID” : “INVALID”
end
end

class B

something not so crazy

def initialize
@a = A.new self
end
def save
@a.save
end
end

Note: meta programming magic also makes code harder to read.

Kind regards

robert