Forum: Ruby Finding methods inside a scope

Posted by Dipesh Gtm (dipeshgtm)
on 2012-08-22 13:20
Suppose I have a scope

  plate do
    serve do |d|
      d.pizza 2
      d.momo 5
    end

    eat do |d|
      d.pizza 1
      d.momo 2
    end
  end

Is there a way to find that exactly two methods, namely serve and eat
have been defined under plate's scope.
Posted by Jan E. (jacques1)
on 2012-08-22 13:45
Hi,

Those are method *calls*, not method definitions.

I'm pretty sure listing method calls is complicated and requires a deep 
analysis of Ruby internals. What do you need that for?
Posted by Dipesh Gtm (dipeshgtm)
on 2012-08-22 18:04
I'm instance_eval-ing the plate block and then trying to hook up method 
missing to call serve and eat methods. The problem is that this is on a 
class level scope so every-undefined-method passes on to method missing. 
I could get away with defining a pattern and then using a regex but 
since it is enclosed in the plate block, I was wondering if there was a 
more natural way available to infer methods/method calls that happen 
inside the block scope. Does this make sense?
Posted by Robert Klemme (robert_k78)
on 2012-08-27 14:01
(Received via mailing list)
On Wed, Aug 22, 2012 at 6:04 PM, Dipesh Gtm <lists@ruby-forum.com> 
wrote:
> I'm instance_eval-ing the plate block and then trying to hook up method
> missing to call serve and eat methods. The problem is that this is on a
> class level scope so every-undefined-method passes on to method missing.

Yes, that's regular behavior for every object.

> I could get away with defining a pattern and then using a regex but
> since it is enclosed in the plate block, I was wondering if there was a
> more natural way available to infer methods/method calls that happen
> inside the block scope. Does this make sense?

I still do not understand what your issue is: if you know where you
want to invoke those methods then method_missing can simply delegate
to the instance.  Other than that, what else do you want to do with
methods which are not defined and of which you do not know where they
are?

Can you show more code, namely the code which invokes instance_eval
and demonstrate what it is supposed to do?

Cheers

robert
Posted by Robert Klemme (robert_k78)
on 2012-08-27 14:01
(Received via mailing list)
On Wed, Aug 22, 2012 at 1:45 PM, Jan E. <lists@ruby-forum.com> wrote:
> Those are method *calls*, not method definitions.

Also the call to #plate does not introduce a scope.  If at all the
scope is opened by the block passed to #plate.

> I'm pretty sure listing method calls is complicated and requires a deep
> analysis of Ruby internals.

For a first start one can do

  plate do
    p method(:serve), method(:eat)

    serve do |d|
      d.pizza 2
      d.momo 5
    end

    eat do |d|
      d.pizza 1
      d.momo 2
    end
  end

The output will tell you something about the class in which the method
is defined.

> What do you need that for?

I second that question.

Kind regards

robert
Posted by Dipesh Gtm (dipeshgtm)
on 2012-08-27 16:12
Sorry, I should have posted more code. The code below does not work but
I
think you will get the idea.

class Food
 def plate(&block)
  extend Operators
  include Operations
  instance_eval(&block)
 end


 plate do
  eat do |d|
   d.pepsi, 20
   d.coke, 10
  end
 end

end

module Operations
 attr_accessor :bloc
 def serve(&block)
  @bloc[:serve] = block
 end
 def eat(&block)
  @bloc[:eat] = block
 end
end

module Operators
 def serve!
  @bloc[:serve].call(self)
 end
end

Then, when I do
 Food.new.serve!

I wanted it to trigger the pepsi and coke methods on instance level with
corresponding
arguments. I have not included those methods here though.

I wanted to define my methods inside the Operations module via method
missing. But since it was extended, I was looking for a scope to tie up
to.

But, I got it wrong there. Later, I got around it by doing something
like:

class Food

 def plate(&block)
  @current_scope = __method__
  instance_eval(&block)
  @current_scope = nil
 end

end

module Operations
 def method_missing(m,*a,&b)
  if @current_scope == :plate
   @bloc[:m] = b
  else
   super
  end
 end
end

Hope that made sense. And Thanks. If you guys say there's a better way 
available, I would be happy to post the working code.
Posted by Robert Klemme (robert_k78)
on 2012-08-27 16:32
(Received via mailing list)
On Mon, Aug 27, 2012 at 4:12 PM, Dipesh Gtm <lists@ruby-forum.com> 
wrote:
> Sorry, I should have posted more code. The code below does not work but
> I
> think you will get the idea.
>
> class Food
>  def plate(&block)
>   extend Operators
>   include Operations

That line above does not make sense since you can only include a
module in a class or module.  Also, it's a questionable habit to
extend multiple times with the same module.  That is inefficient.

>   instance_eval(&block)
>  end
>
>
>  plate do
>   eat do |d|
>    d.pepsi, 20
>    d.coke, 10
>   end
>  end

Method plate is not defined for the class.  Also it's a bad idea to
have similarly named methods for class and instance.

> end
> I wanted it to trigger the pepsi and coke methods on instance level with
> corresponding
> arguments. I have not included those methods here though.

Why?  How are we supposed to understand your use case?

> I wanted to define my methods inside the Operations module via method
> missing. But since it was extended, I was looking for a scope to tie up
> to.

> Hope that made sense.

Frankly, no - at least not to me.

> And Thanks. If you guys say there's a better way
> available, I would be happy to post the working code.

I would need to understand what your goal is.  It's not clear to me
yet.  Can you describe your use case more abstractly than with a
solution in mind?  What are your requirements and goals?

Cheers

robert
Posted by Dipesh Gtm (dipeshgtm)
on 2012-08-27 17:02
https://gist.github.com/3489255

What I was trying to do was to define methods inside Events via 
method_missing.
Posted by Jan E. (jacques1)
on 2012-08-27 18:34
Hi,

To put it bluntly: I think you've kind of got lost in all that
metaprogramming magic and forgot what you actually want to do. We've
asked you again and again about your goal, and you could never give a
concrete answer (and your code doesn't tell either).

Your code is so packed with obscure techniques (like all that module
extending) and strange dependencies
that I find it almost impossible to read. When I see something like
this, I immediately think: This guy (or gal) doesn't think clearly.

Even complex algorithms usually don't use metaprogramming that heavily.
So I think there's something wrong with how you program. You've almost
developed your own "pseudo-OOP" where you use modules and extending
instead of classes and inheritance.

I know this doesn't sound nice, but what I would do is completely dump
the code and start from scratch. First you should ask yourself: What do
I want to achieve? Why do I even need the code? Then you should create
an appropriate and *simple* object model. Use metaprogramming only when
it's actually necessary. The normal way of doing things is using classes
and fixed methods.

Of course we can also help you with the concept. But then we'll need a
concrete goal. Something like "I want to write a database wrapper" or "I
want to write a text-based adventure game".
Posted by Dipesh Gtm (dipeshgtm)
on 2012-08-27 19:37
Hmm...
At certain events of my program, I send an email(whose template differs
on what event just happened), update some redis statistics, create and
update some database entries and do some other calculations. I do this
set of actions repetitively for 12-15 events, for some events, I might 
not need to send an email or create a db entry and such. I wanted to 
create a nice
DSL and then keep the actual methods separate from the class which was
turning into a hell of method calls. I was thinking the DSL would serve
as a easy place to change things on a higher level, that was what I had 
in mind.

And no, it actually sounds nice to dump the code but I fear I will
somehow be going along the same path again.
Posted by Robert Klemme (robert_k78)
on 2012-08-27 23:08
(Received via mailing list)
On Mon, Aug 27, 2012 at 7:37 PM, Dipesh Gtm <lists@ruby-forum.com> 
wrote:
> Hmm...
> At certain events of my program, I send an email(whose template differs
> on what event just happened), update some redis statistics, create and
> update some database entries and do some other calculations. I do this
> set of actions repetitively for 12-15 events.

Do you mean 12-15 different types of events?

> I wanted to create a nice
> DSL and then keep the actual methods separate from the class which was
> turning into a hell of method calls. I was thinking the DSL would serve
> as a point of contact, that was what I had in mind.

Are users supposed to change the handling of events?

> And no, it actually sounds nice to dump the code but I fear I will
> somehow be going along the same path again.

:-)  Maybe we can counsel you to some clarifications of what you are
trying to do.  I found that lacking clarity is one source for badly
structured code.  And talking to others - especially from the same
field - helps in finding clarity in one's own mind.  I can only speak
for me of course but I have observed the phenomenon with a few
colleagues as well so I reckon it must be generally helpful to
communicate about ideas and code.

Kind regards

robert
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.