[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

lambda/procs and dynamically generated methods

Chris Hall

2/14/2008 5:57:00 PM

I'm not sure one way is technically better than the other, so if anyone
has any input, I'd be glad to hear it.

class Job

def initialize(file = nil)
raise "need file or block" if fil.nil? || !block_given?
@action = block_given? ? lambda { yield } : eval("lambda {
#{IO.read(file)} }")
end

def do
@action.call
end
end

or

class Job

def initialize(file = nil)
raise "need file or block" if fil.nil? || !block_given?
action = block_given? ? lambda { yield } : eval("lambda {
#{IO.read(file)} }")
self.class.send(:define_method, :task, action)
self.class.send(:private, :task)
end

def do
task
end
end
--
Posted via http://www.ruby-....

7 Answers

Chris Hall

2/14/2008 6:02:00 PM

0

please forgive the typos in the original, i should learn not to type the
code directly into the form.


corrected:


class JobA

def initialize(file = nil)
raise "need file or block" if file.nil? && !block_given?
@action = block_given? ? lambda { yield } : eval("lambda {
#{IO.read(file)} }")
end

def do
@action.call
end
end

class JobB

def initialize(file = nil)
raise "need file or block" if file.nil? && !block_given?
action = block_given? ? lambda { yield } : eval("lambda {
#{IO.read(file)} }")
self.class.send(:define_method, :task, action)
self.class.send(:private, :task)
end

def do
task
end
end

--
Posted via http://www.ruby-....

ThoML

2/14/2008 6:31:00 PM

0

This can be done in almost endless different ways of course. Here are
two other options:

class Job
def initialize(file=nil, &block)
raise "need file or block" unless file or block
@file = file
@block = block
end

def do
if @file
File.read @file
else
@block.call
end
end
end


class Job
def initialize(file=nil, &block)
raise "need file or block" unless file or block
@task = block || lambda { File.read file }
end

def do
@task.call
end
end

The second one is a slightly cleaned up version of your first
proposal.

Regards,
Thomas.

Adam Shelly

2/14/2008 6:41:00 PM

0

On 2/14/08, Chris Hall <christopher.k.hall@gmail.com> wrote:
>
> class JobA
>
> def initialize(file = nil)
> raise "need file or block" if file.nil? && !block_given?
> @action = block_given? ? lambda { yield } : eval("lambda {
> #{IO.read(file)} }")
> end
>
> def do
> @action.call
> end
> end
>

I may be missing something important about what you are trying to
accomplish, but
what about simply

class Job
def initialize(file = nil, &block)
raise "need file or block" if file.nil? && !block_given?
@action = block || proc { eval IO.read(file)}
end
def do
@action.call
end
end

(I sure hope you trust the contents of 'file')
-Adam

Chris Hall

2/14/2008 6:57:00 PM

0

Adam Shelly wrote:
> On 2/14/08, Chris Hall <christopher.k.hall@gmail.com> wrote:
>> @action.call
>> end
>> end
>>
>
> I may be missing something important about what you are trying to
> accomplish, but
> what about simply
>
> class Job
> def initialize(file = nil, &block)
> raise "need file or block" if file.nil? && !block_given?
> @action = block || proc { eval IO.read(file)}
> end
> def do
> @action.call
> end
> end
>
> (I sure hope you trust the contents of 'file')
> -Adam

The main reason the code is the way it is, is because I don't want to
used named blocks, see:
http://ola-bini.blogspot.com/2007/12/ruby-closures-and-memory-...


The only really difference between the 2 is that in once instance I am
capturing the block in @action and in the other I am creating a method
from the block. I didn't know if one way was more efficient than the
other.

And yes, I will be trusting the code in file. :)

I'm not necessarily looking for the simplest solution, I'm looking for
the best solution. Both of the examples I posted have the same results,
it's just how they are implemented. I didn't know there was some behind
the scenes mo-jo going on that makes one a better choice than the other.
--
Posted via http://www.ruby-....

ThoML

2/14/2008 7:21:00 PM

0

Okay, I missed the deeper meaning of eval in your example.

eval("lambda {#{IO.read(file)} }")

Maybe:

@task = if file
ruby = file.read file
lambda { eval ruby }
else
block
end

> I'm not necessarily looking for the simplest solution, I'm looking for
> the best solution. Both of the examples I posted have the same results,
> it's just how they are implemented.

The second one creates the method in the class though which most
likely
isn't what you want.

irb(main):032:0> j = JobB.new('test.rb')
=> #<JobB:0x7fec2adc>
irb(main):034:0> JobB.instance_method(:do)
=> #<UnboundMethod: JobB#do>

If you want to minimize the context, create a new method that gets
nothing but the file name as argument and returns the block for the
file. I think that's what's meant in the blog post.

ThoML

2/14/2008 7:23:00 PM

0

> irb(main):034:0> JobB.instance_method(:do)
> => #<UnboundMethod: JobB#do>

This should be :task of course. Sorry.

Chris Hall

2/14/2008 7:49:00 PM

0

ThoML wrote:
> Okay, I missed the deeper meaning of eval in your example.
>
> eval("lambda {#{IO.read(file)} }")
>
> Maybe:
>
> @task = if file
> ruby = file.read file
> lambda { eval ruby }
> else
> block
> end
>
>> I'm not necessarily looking for the simplest solution, I'm looking for
>> the best solution. Both of the examples I posted have the same results,
>> it's just how they are implemented.
>
> The second one creates the method in the class though which most
> likely
> isn't what you want.
>
> irb(main):032:0> j = JobB.new('test.rb')
> => #<JobB:0x7fec2adc>
> irb(main):034:0> JobB.instance_method(:do)
> => #<UnboundMethod: JobB#do>
>
> If you want to minimize the context, create a new method that gets
> nothing but the file name as argument and returns the block for the
> file. I think that's what's meant in the blog post.


so what would be the difference between:

x = eval "lambda { #{IO.read(file)}" }"
x.call

y = lambda { eval IO.read(file) }
y.call


I'm guessing that in the first eval gets called only the one time where
in the second, eval gets called with every y.call. (this is why i did
it the way i did, if i am incorrect, then please let me know)
--
Posted via http://www.ruby-....