Ruby Equivalent to VB's "With"?

I’ve looked around but I couldn’t find anything helpful on this,
although I’m sure it’s been covered before:
Does Ruby have an equivalent to the “With / End With” syntax helper in
VB? It would be quite helpful when I need to execute a series of methods
on an object, but for various reasons (e.g. testing individual returns
or methods which may return nil) I don’t want to chain them together.

To illustrate, here’s the VB syntax I’m referring to:

With my_object
.do1
.do2
.do3
End With

The current Ruby approaches I know about:

my_object.do1.do2.do3

my_object.do1
my_object.do2
my_object.do3

Thanks Robert that looks like exactly what I needed.

It works with “@” variables, remembers changes to the object, and should
be great for my attempts to “DRY” my code.

On Sun, Feb 10, 2013 at 9:25 PM, Joel P. [email protected]
wrote:

.do1
.do2
.do3
End With

my_object.instance_eval do

self points to my_object here

do1
do2
do3
end

You can of course use a different method name, i.e. alias
#instance_eval to #with.

However, there is one gotcha

foo.bar = 99

cannot be translated to

foo.instance_eval do
bar = 99
end

because bar will be a local variable then. Instead you have to use

foo.instance_eval do
self.bar = 99
end

Kind regards

robert

On 11/02/2013, at 9:25 AM, Joel P. [email protected] wrote:

.do1
.do2
.do3
End With

tap?

my_object.tap do |mo|
mo.do1
mo.do2
mo.do3
end

Henry

Nice one Henry. As usual Ruby has more than one way to do everything :slight_smile:

On Mon, Feb 11, 2013 at 10:04 AM, Joel P. [email protected]
wrote:

Nice one Henry. As usual Ruby has more than one way to do everything :slight_smile:

IMHO #tap is only called for in these situations

  • The value to be tapped is the result of evaluating an expression
    (and not already stored in a variable) AND
  • It should be used as the result of the larger expression.

Typical example:

module Enumerable
def group_by
{}.tap do |groups|
each do |e|
(groups[yield(e)] ||= []) << e
end
end
end
end

In all other cases doing a simple assignment like

mo = my_object
mo = my.complicated.expression

is probably easier, cleaner and faster.

Kind regards

robert

On Thu, Mar 7, 2013 at 12:26 PM, Joel P. [email protected]
wrote:

irb(main):005:0> A.new.instance_eval do
irb(main):006:1* puts B
irb(main):007:1> end
NameError: uninitialized constant B
from (irb):6:in block in irb_binding' from (irb):5:in instance_eval’
from (irb):5
from C:/Ruby193/bin/irb:12:in `’

Const lookup works differently from other identifiers (IIRC it’s done
via lexical scope). Having said that you can do

irb(main):007:0> A.new.instance_eval { self.class.const_get :B }
=> 1

Well, probably not what you wanted. :slight_smile:

How do you want to use that feature (if it existed)? Maybe there’s
another elegant solution.

Kind regards

robert

Can this work for constants as well? I have a several constants within a
long class name and I was wondering whether I can use this approach, but
it doesn’t seem to be working for me:

irb(main):001:0> class A
irb(main):002:1> B = 1
irb(main):003:1> end
=> 1
irb(main):004:0> A::B
=> 1
irb(main):005:0> A.new.instance_eval do
irb(main):006:1* puts B
irb(main):007:1> end
NameError: uninitialized constant B
from (irb):6:in block in irb_binding' from (irb):5:ininstance_eval’
from (irb):5
from C:/Ruby193/bin/irb:12:in `’

It’s part of my continual effort to combine minimialism with readability
in my code.
Here’s the snippet of code which is affected:


class XL; end
WIN32OLE.const_load( excel, XL )

#Purdy it up

#Align left 2 columns to left
sht.range(‘A:B’).HorizontalAlignment = XL::XlLeft

#Add a thin grid
( Consts = [ XL::XlEdgeLeft, XL::XlEdgeTop, XL::XlEdgeBottom,
XL::XlEdgeRight, XL::XlInsideVertical, XL::XlInsideHorizontal ] ).each {
|const| sht.usedrange.Borders( const ).weight = XL::XlThin }


“XL” as a class name is my own attempt at simplifying the original
“ExcelConst”. I was just wondering whether I could use these constants
without repeating “XL::” all the time. I don’t know how to make them
“main” constants, and I assumed that that sort of thing would be bad
practice anyway.

This is more about trying to work with Excel’s awkward API, and the way
it insists on specifying every border as a seperate
constant.

On Thu, Mar 7, 2013 at 2:07 PM, Joel P. [email protected]
wrote:

sht.range(‘A:B’).HorizontalAlignment = XL::XlLeft
“main” constants, and I assumed that that sort of thing would be bad
practice anyway.

This is more about trying to work with Excel’s awkward API, and the way
it insists on specifying every border of every cell as a seperate
constant.

With a module you can use include

$ ruby -e ‘module X;Y=1;end;include X;p Y’
1

With a class you could manually copy them over

$ ruby -e ‘class X;Y=1;end;X.constants.each{|c| Object.const_set(c,
X.const_get(c))};p Y’
1

Kind regards

robert

Ah I see. I’ve only used include within classes before, I didn’t think
of doing this at main level. Thanks!