# Changing method behavior depending on context

**URL:** <https://www.ruby-forum.com/t/changing-method-behavior-depending-on-context/185815>\
**Category:** Ruby\
**Created:** [March 26, 2010, 5:11pm UTC](https://www.ruby-forum.com/t/changing-method-behavior-depending-on-context/185815 "2010-03-26T17:11:50Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![maratk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/3e96dc/32.png) [@maratk](https://www.ruby-forum.com/u/maratk)\
**Post date:** [March 26, 2010, 5:11pm UTC](https://www.ruby-forum.com/t/changing-method-behavior-depending-on-context/185815/1 "2010-03-26T17:11:50Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![maratk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/3e96dc/32.png) [@maratk](https://www.ruby-forum.com/u/maratk)\
**Post date:** [March 26, 2010, 9:40pm UTC](https://www.ruby-forum.com/t/changing-method-behavior-depending-on-context/185815/2 "2010-03-26T21:40:32Z")

</div>

On Fri, Mar 26, 2010 at 5:11 PM, Marat K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
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.

---

<div class="post-metadata">

**Author:** ![maratk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/3e96dc/32.png) [@maratk](https://www.ruby-forum.com/u/maratk)\
**Post date:** [March 26, 2010, 11:20pm UTC](https://www.ruby-forum.com/t/changing-method-behavior-depending-on-context/185815/3 "2010-03-26T23:20:39Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![maratk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/3e96dc/32.png) [@maratk](https://www.ruby-forum.com/u/maratk)\
**Post date:** [March 26, 2010, 11:35pm UTC](https://www.ruby-forum.com/t/changing-method-behavior-depending-on-context/185815/4 "2010-03-26T23:35:14Z")

</div>

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
