convert yield to proc

S

Simon Strandgaard

How do you guys convert yield to block ?

I were hoping to that #mode2 could get same behavier as #mode,
however self is out of control.


server> ruby a.rb
#<ModeInfo:0x8123634 @tabsize=4>
a.rb:18: undefined method `tabsize' for main:Object (NoMethodError)
from a.rb:17:in `mode2'
from a.rb:11:in `instance_eval'
from a.rb:7:in `instance_eval'
from a.rb:7:in `mode'
from a.rb:12:in `mode2'
from a.rb:17
server> expand -t2 a.rb
class ModeInfo
def initialize; @tabsize = 8 end
def tabsize(value); @tabsize = value end
end
def mode(&block)
m = ModeInfo.new
m.instance_eval(&block)
p m
end
def mode2
block = lambda{yield} # attempt to convert yield 2 block
mode(&block)
end
mode do
tabsize 4
end
mode2 do
tabsize 5 # BOOM
end
server>
 
S

Simon Strandgaard

How do you guys convert yield to block ?

I were hoping to that #mode2 could get same behavier as #mode,
however self is out of control.

Figured it out .. Proc.new .. ??? feels awkward

server> ruby a.rb
#<ModeInfo:0x8123634 @tabsize=4>
#<ModeInfo:0x8123440 @tabsize=5>
server> expand -t2 a.rb
class ModeInfo
def initialize; @tabsize = 8 end
def tabsize(value); @tabsize = value end
end
def mode(&block)
m = ModeInfo.new
m.instance_eval(&block)
p m
end
def mode2
mode(&Proc.new)
end
mode do
tabsize 4
end
mode2 do
tabsize 5
end
server>
 
R

Robert Klemme

Simon Strandgaard said:
Figured it out .. Proc.new .. ??? feels awkward

server> ruby a.rb
#<ModeInfo:0x8123634 @tabsize=4>
#<ModeInfo:0x8123440 @tabsize=5>
server> expand -t2 a.rb
class ModeInfo
def initialize; @tabsize = 8 end
def tabsize(value); @tabsize = value end
end
def mode(&block)
m = ModeInfo.new
m.instance_eval(&block)
p m
end
def mode2
mode(&Proc.new)
end
mode do
tabsize 4
end
mode2 do
tabsize 5
end
server>

But what do you need that for? This isn't a real world example, is it?

Just curious...

robert
 
S

Simon Strandgaard

On Mon, 19 Apr 2004 12:00:04 +0200, Robert Klemme wrote:
[snip]
But what do you need that for? This isn't a real world example, is it?

Just curious...

Its a tiny example of a configuration system for AEditor,
where you can have different modes, for instance:
define a ruby mode, where certain key gets bound with
RI, rdoc. Where syntax hiliting gets configured.
Much inspired by Rake.

An example dotfile for AEditor:
server> expand -t2 dotfile.rb
# AEditor preferences for Simon Strandgaard
mode :global do
tabsize 4
#panel_format {|i| "#{i.y},#{i.xcell}-#{i.xchar}"}
end

mode :ruby => :global do
tabsize 2
#on_execute_project {|i| "ruby -v main.rb"}
#on_execute_buffer {|i| "ruby -v #{i.filename}"} # record errors, so we can jump to them
#on_execute_tests "ruby test_all.rb"
#on_execute_builddoc {|i| "rdoc #{i.filename}"}
#on_help_context { |place| "ri place" }
#on_debug_step "gdb"
#mode_selftest do
# check that ruby is working
# check rdoc is present
# check ri is prsent
#end
end
file_suffix %w(rb rbx) => :ruby

mode :rake => :ruby do
# TODO: extract tasks, rules, files.. show choices
#on_execute_buffer {|i| dialog('all', 'run', 'upload', 'validate')}
end
file_match %w(rakefile rakefile.rb) => :ruby

mode :c => :global do
end
file_suffix 'c' => :c

mode :cpp => :c do
end
file_suffix %w(cpp cc) => :cpp

mode :xml => :global do
#on_execute_buffer {|i| "xsltproc --validate #{i.filename}"}
end
file_suffix %w(xml xhtml) => :xml

theme :morning do
end

theme :night do
end
server>


The code for parsing it located here
http://rubyforge.org/cgi-bin/viewcv...cts/experimental/preferences/?cvsroot=aeditor


Its a proof of concept.. Any suggestions?
How would you like preferences to be ?
 
D

Dan Doel

I must admit, I don't understand what you're doing exactly either...

How is your code different from:

def mode2(&blk)
mode(&blk)
end

Or for that matter, how is:

mode2 do
# stuff
end

different from:

mode do
#stuff
end

- Dan
 
S

Simon Strandgaard

I must admit, I don't understand what you're doing exactly either...

How is your code different from:

def mode2(&blk)
mode(&blk)
end

My code can take an optional block. Your above code
must be supplied a block.

Or for that matter, how is:

mode2 do
# stuff
end

different from:

mode do
#stuff
end

No difference there.

However being able to not supply a block is what interest me

mode2 # OK

mode # BOOM



HTH,
 
T

ts

S> My code can take an optional block. Your above code
S> must be supplied a block.

What do you call an optional block ?

svg% cat b.rb
#!/usr/bin/ruby
class ModeInfo
def initialize; @tabsize = 8 end
def tabsize(value); @tabsize = value end
end

def mode(&block)
m = ModeInfo.new
m.instance_eval(&block)
p m
end

def mode2
mode(&Proc.new)
end

mode2
svg%

svg% b.rb
/b.rb:14:in `new': tried to create Proc object without a block (ArgumentError)
from ./b.rb:14:in `mode2'
from ./b.rb:17
svg%



Guy Decoux
 
S

Simon Strandgaard

S> My code can take an optional block. Your above code
S> must be supplied a block.

What do you call an optional block ?

I was hoping that I had made a method which could take
an optional block.. ala

def m
if block_given?
yield
end
end

I wanted to convert that yield into a block, which I could
pass further around (as a block).


[snip]
mode2
svg%

svg% b.rb
/b.rb:14:in `new': tried to create Proc object without a block (ArgumentError)
from ./b.rb:14:in `mode2'
from ./b.rb:17
svg%

Bommer.. your right. I thought I was on to something.


Any idea how to do this?
 
S

Simon Strandgaard

Bommer.. your right. I thought I was on to something.


Any idea how to do this?


Just realized that my knowledge about &block is flawed!

server> ruby a.rb
before
after
before
middle
after
server> expand -t2 a.rb
def m(&block)
puts "before"
if block_given?
block.call
end
puts "after"
end

m

m do
puts "middle"
end
server>


Thanks for correcting me.. I have thought until now,
that the &block was indicating the a block must be
supplied. However I just realized that this is not
the case, which is a pleasant surprise.


Thanks every one.

BTW: Now the conversion problem is wiped away ;-)
 
T

ts

S> Any idea how to do this?

Do what ? Call a method with a block which do nothing ???

Guy Decoux
 
S

Simon Strandgaard

S> Any idea how to do this?

Do what ? Call a method with a block which do nothing ???

Guy Decoux

Solved. My cognitive skills must be broken somehow, I has
never occured to me that &block was optional.


However, yes that what I asked for

mode2 do
# block supplied
end

mode2 # no block supplied
 
R

Robert Klemme

Simon Strandgaard said:
Just realized that my knowledge about &block is flawed!

server> ruby a.rb
before
after
before
middle
after
server> expand -t2 a.rb
def m(&block)
puts "before"
if block_given?
block.call
end
puts "after"
end

m

m do
puts "middle"
end
server>

Even simpler:

def foo(&bl)
bl.call(whatever) if bl
end

def bar(&bl)
foo(&bl)
end

# or

def foo
yield whatever
end

def bar(&bl)
if bl
foo &bl
else
foo() {}
end
end

Regards

robert
 
Z

Zsban Ambrus

I was hoping that I had made a method which could take
an optional block.. ala

def m
if block_given?
yield
end
end

I wanted to convert that yield into a block, which I could
pass further around (as a block).
....
Any idea how to do this?

Ok, so an &-parameter accepts an optional block, but aside from that,
doesn't this convert the block to a proc? I'm not quite sure because of the
other thread going on shows that scoping rules about proces and lambdas are
convoluted, and I don't quite understand how they work.

proc do yield end

It seems that it works, look:

def mypr; if block_given?; then proc do yield; end; else proc do puts
"default"; end; end; end; p= mypr do puts "hi"; end; 5.times(&p); q= mypr;
5.times(&q);

ambrus
 
T

ts

Z> def mypr; if block_given?; then proc do yield; end; else proc do puts
Z> "default"; end; end; end; p= mypr do puts "hi"; end; 5.times(&p); q= mypr;
Z> 5.times(&q);

Well, try this

def mypr; if block_given?; then proc do yield; end; else proc do
puts "default"; break; end; end; end; p= mypr do puts "hi"; break; end;
5.times(&p); q= mypr; 5.times(&q);


This is not me which have tried to obfuscate the code :)))



Guy Decoux
 
Z

Zsban Ambrus

Z> def mypr; if block_given?; then proc do yield; end; else proc do puts
Z> "default"; end; end; end; p= mypr do puts "hi"; end; 5.times(&p); q= mypr;
Z> 5.times(&q);

Well, try this

def mypr; if block_given?; then proc do yield; end; else proc do
puts "default"; break; end; end; end; p= mypr do puts "hi"; break; end;
5.times(&p); q= mypr; 5.times(&q);


This is not me which have tried to obfuscate the code :))) ...
Guy Decoux


0. Sorry for the one-liner.


1. Only the first break causes a problem:

def mypr; if block_given?; then proc do yield; end; else proc
do puts "default"; end; end; end; p= mypr do puts "hi"; break; end;
5.times(&p); q= mypr; 5.times(&q);

works as expected, that is, the "hi" block breaks out.


2. The problem with the first break is that it is not in the lexical scope
of the times loop.

This just shows that ruby has a nice lexical semantics for break, unlike
perl in which the loop control statements act on the innermost dynamically
enclosing block, and if it has a label, it will search for it in the
dynamical scope.

I consider this an advantage. Look. In a perl code like

sub twice (&) {
$_[0]();
$_[0]();
}
# ... later ...
BACK:
print "before twice:\n";
twice { print "hello\n"; rand()<0.5 and goto BACK; };

Although you can jump to the label BACK, you must first make sure that the
sub `twice' (which may be written by someone else) does not have a label
called BACK. Although ruby does not have labeled loop control statements and
gotos, it is still better if the loop control statements work in a lexical
fashion (that is, they will jump only with respect to the visible loop that
is near the jump-control statement in the code), especially because of the
greater role of iterators (as compared to perl).

This is of course only my opinion, you may still think that dynamic control
sturctures are better. And btw, ruby has both: exceptions are dynamic,
callcc and loop control are lexical in this sense.


3. This has nothing to do with making a proc from the yield-block.

def mypr (&f); if block_given?; then f; else proc do puts "default"; end;
end; end; p= mypr do puts "hi"; break; end; 5.times(&p); q= mypr;
5.times(&q);

works the same and

def mypr (&f); if block_given?; then f; else proc do puts "default"; break;
end; end; end; p= mypr do puts "hi"; break; end; 5.times(&p); q= mypr;
5.times(&q);

fails the same as above.


ambrus
 
D

Dan Doel

The original problem with the code was that he was instance_evaling the
block in #mode. So if no block was passed, he'd end up with something like
the following:

instance_eval do
yield
end

And you can't yield in a block given to instance eval (not sure I totally
understand why, but I have a gut feeling that you shouldn't try it :)).

Using an & parameter wraps the given block in a Proc. If no block is given,
it's nil. If you call yield in a block, it will yield to the block given to
the enclosing method.

Hope this helps.

- Dan
 
M

Mauricio Fernández

The original problem with the code was that he was instance_evaling the
block in #mode. So if no block was passed, he'd end up with something like
the following:

instance_eval do
yield
end

And you can't yield in a block given to instance eval (not sure I totally
understand why, but I have a gut feeling that you shouldn't try it :)).

irb(main):002:0> def foo; "aa".instance_eval{ yield } end
=> nil
irb(main):003:0> foo{puts "adsda"}
adsda

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

* JHM wonders what Joey did to earn "I'd just like to say, for the record,
that Joey rules."
-- Seen on #Debian
 
D

Dan Doel

My bad.

Looked at the original post, and here's the problem:

class Bar
def foo
#stuff
end
end

def baz1(&blk)
Bar.new.instance_eval &blk
end

def baz2
baz1 &lambda { yield }
end

baz2 { foo }

When you yield to the block for baz2, it tries to call the method foo of a
Bar object, but it's not actually being instance_evaled, only the { yield }
block is being instance evaled, so you get an undefined method error.

Thanks for correcting me.

- Dan
 
T

ts

Z> 1. Only the first break causes a problem:

This is 1.9

svg% cat b.rb
#!./ruby
def x(&b)
p "before"
b.call
p "after"
end

a = Proc.new { p "a"; break }
b = proc { p "b"; break }

x(&a)
x(&b)
svg%

svg% ruby -v b.rb
ruby 1.9.0 (2004-04-16) [i686-linux]
"before"
"a"
"before"
"b"
"after"
svg%


Guy Decoux
 
Z

Zsban Ambrus

Z> 1. Only the first break causes a problem:

This is 1.9

svg% cat b.rb
#!./ruby
def x(&b)
p "before"
b.call
p "after"
end

a = Proc.new { p "a"; break }
b = proc { p "b"; break }

x(&a)
x(&b)
svg%

svg% ruby -v b.rb
ruby 1.9.0 (2004-04-16) [i686-linux]
"before"
"a"
"before"
"b"
"after"
svg%


Guy Decoux

In ruby 1.8.1, only the first one (x(&b)) works, the first variant (with
Proc.new) fails with `break from proc-closure (LocalJumpError)'. I don't
have an 1.9 ruby installed.

I don't quite understand all this distinction between Proc and proc and the
like. I am now confused. Sorry.

From what loop or iterator does exactly the `break' break out in the
x(&b) call, in ruby 1.9?

ambrus
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,145
Messages
2,570,825
Members
47,371
Latest member
Brkaa

Latest Threads

Top