3

I have code like this:

 context = area.window.create_cairo_context

 context.set_source_rgb(0, 0, 0)
 context.set_line_width(0.5)
 context.arc(x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees)
 context.arc(x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees)
 context.arc(x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees)
 context.arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees)
 context.close_path
 context.stroke_preserve
 context.set_source_rgb(0.7, 1.0, 1.0)
 context.fill

Notice that I'm calling methods on the same object over and over again. Is there someway that Ruby will let me change the current object (self) to context so I can just keep calling these methods with no explicit receiver until I change scope?

Or, to put it simply: There must be some way to not have to type context over and over again!

marcusM
  • 574
  • 1
  • 4
  • 8
  • 1
    This brings back painful memorys of Delphis with statement. ***_shudder_***. I think the potential for obfuscating your code by doing this would outweigh any advantages of avoiding a few key strokes. – Mongus Pong Apr 01 '11 at 15:18
  • Possibly related question: http://stackoverflow.com/questions/4341161/is-there-a-ruby-method-that-just-returns-the-value-of-a-block – Andrew Grimm Apr 04 '11 at 00:03

2 Answers2

4

Use instance_exec or instance_eval

area.window.create_cairo_context.instance_exec do
  set_source_rgb(0, 0, 0)
  set_line_width(0.5)
  arc(x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees)
  arc(x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees)
  arc(x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees)
  arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees)
  close_path
  stroke_preserve
  set_source_rgb(0.7, 1.0, 1.0)
  fill
end

Just to note: you can omit the parentheses around the arguments. This makes it look more like a configuration setting than writing a code. Ruby on Rails people, which I am not one of, seem to heavily prefer this way.

area.window.create_cairo_context.instance_exec do
  set_source_rgb  0,   0,   0
  set_line_width  0.5
  arc           x+width-radius, y+radius,        radius, -90*degrees, 0*degrees
  arc           x+width-radius, y+height-radius, radius, 0*degrees,   90*degrees
  arc           x+radius,       y+height-radius, radius, 90*degrees,  180*degrees
  arc           x+radius,       y+radius,        radius, 180*degrees, 270*degrees
  close_path
  stroke_preserve
  set_source_rgb  0.7, 1.0, 1.0
  fill
end
sawa
  • 165,429
  • 45
  • 277
  • 381
  • That worked perfectly! I vaguely remembered instance_exec from the Ruby Metaprograming book (great book, by the way), but I didn't even think of using it like this! – marcusM Apr 01 '11 at 17:05
  • @marcusM I was in pain doing a similar thing when I was trying to use ruby/gnome2. Just added a note. – sawa Apr 02 '11 at 04:04
3

Why don't you just implement method chaining? Return yourself from each method call so that you can do something like:

context.set_source_rgb(0, 0, 0)
       .set_line_width(0.5)
       .arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees)
       .close_path.fill
Nick
  • 6,967
  • 2
  • 34
  • 56
  • -1. Probably these methods are all defined on some GUI toolkit, and in order to do what you suggest, you have to go through the API, and redefine a huge amount of methods, which is not practical. Also a cause of a bug, if you missed redefining some method. If these were your own methods, you can do from the beginning what you suggest. – sawa Apr 01 '11 at 17:19
  • @sawa You've made a big assumption which wasn't mentioned by the OP. – Nick Apr 01 '11 at 18:08
  • +1 to counter the -1 because, while it may not work for the OP's situation, it's a good idea when it's possible. – RHSeeger Apr 01 '11 at 18:14