Ruby block scope, Tk object constructors, and the tutorial

23 views
Skip to first unread message

Mark D Blackwell

unread,
Apr 24, 2019, 3:11:36 PM4/24/19
to Tk Documentation and Resources
Admittedly this implies a fairly big change, but for new Ruby Tk learners, I think it's important. :)

Often, when Ruby programmers are learning Tk from various tutorials, they encounter code examples which pass literals to Tk object constructors.

Eventually, however, they stumble over the fact that they cannot extend that paradigm to their own instance variables and method calls.

For example:

def my_fancy_function
  puts
"hello, world!"
end

@prompt = "Press me"

my_fancy_button
= TkButton.new(frame) do
  text
@prompt
  command
{my_fancy_function}
  grid
end

fails on two counts, because it passes both an instance variable and a method. Ultimately, it fails because Ruby's Tk wrapper uses `self.instance_eval` in the manner of a domain-specific language (DSL). Never mind, if you don't know what that means. :)

This is a subtle point, difficult and confusing for new learners.

Instead, for the TkDocs tutorial, better would be to edit all of its Ruby code in a simple and mechanical manner, to eliminate passing any blocks to Tk constructors, while maintaining readability, as follows:

def my_fancy_function
  puts
"hello, world!"
end

@prompt = "Press me"

my_fancy_button
= begin
  b
= TkButton.new(frame)
  b
.text @prompt
  b
.command {my_fancy_function}
  b
.grid
end

This rewritten code works fine.

See also this StackOverflow post.

Mark D Blackwell

unread,
Apr 24, 2019, 3:35:40 PM4/24/19
to Tk Documentation and Resources
Well, to make it actually work, I had to add a few more lines:

require 'tk'


def my_fancy_function
  puts
"hello, world!"
end

@prompt = "Press me"


frame
= TkFrame.new
frame
.grid

my_fancy_button
= begin

  b
= TkButton.new(frame)
  b
.text @prompt
  b
.command {my_fancy_function}
  b
.grid
end

Tk.mainloop



Reply all
Reply to author
Forward
0 new messages