Find which widget has focus in Ruby 2.3.3 - ruby

In Python, I use:
who = widget.focus_get()
and in Perl:
$who = $widget->focusCurrent;
to tell me which widget has the focus. So:
What is the equivalent code in Ruby under Linux?
Is there a good book or article about low-level Ruby Tk? All the articles I have seen only cover the simplistic stuff.

[T]o tell me which widget has the focus[...w]hat is the equivalent code in Ruby under Linux?
Fairly equivalently, if you have three Tk objects (for example), then you can say (in Ruby):
array = [tk_object_1, tk_object_2, tk_object_3]
path = Tk.focus.path
index = array.find_index {|e| e.path == path}
object = array.at index
EDIT: Or, more simply:
object = Tk.focus
Here's how to determine which object (of your many Tk objects) this is:
array = [tk_object_1, tk_object_2, tk_object_3]
index = array.find_index {|e| e == object}
(End of edit.)
I managed to locate documentation for the focus method (in both the
Ruby wrapper
and the original
Tcl)
and for the path method (in the
Ruby wrapper).
I wrote a program which demonstrates setting and getting the focus:
require 'tk'
def focus_array
#focus_array ||= [
f_content, e_content,
to_one, e_one,
to_two, e_two,
]
end
def focus_array_class_width_max
#focus_array_class_width_max ||= focus_array.map {|e| e.class.to_s.length}.max
end
def focus_delay
milliseconds = 1000
Tk.after milliseconds, lambda_focus_rotate
nil
end
def focus_force(object)
force = true
Tk.focus_to object, force
nil
end
def focus_print
path = Tk.focus.path
index = focus_array.find_index {|e| e.path == path}
s = klass_justified index
puts "Item #{index}'s class and path are: #{s} #{path}"
nil
end
def focus_rotate
#counter += 1
index = #counter % focus_array.length
puts '' if 0 == index
focus_force focus_array.at index
nil
end
def klass_justified(index)
focus_array.at(index).class.to_s.ljust focus_array_class_width_max
end
def lambda_focus_rotate
#lambda_focus_rotate ||= Kernel.lambda do
focus_rotate
focus_print
focus_delay
end
end
def main
root.title = 'Root'
objects_create
#counter = -1 # Start before first.
focus_delay
Tk.mainloop
nil
end
def objects_create
# Keep order:
e_content
e_one
e_two
nil
end
def spacing_set(object)
object.width 7
object.grid padx: 40
end
#-------------
# Tk objects:
def e_content
#e_content ||= begin
e = Tk::Tile::Entry.new f_content
spacing_set e
end
end
def e_one
#e_one ||= begin
e = Tk::Tile::Entry.new to_one
spacing_set e
end
end
def e_two
#e_two ||= begin
e = Tk::Tile::Entry.new to_two
spacing_set e
end
end
def f_content
$f_content ||= begin
f = Tk::Tile::Frame.new root
f.grid
end
end
def root
$root ||= TkRoot.new
end
def to_one
#to_one ||= TkToplevel.new f_content
end
def to_two
#to_two ||= TkToplevel.new f_content
end
main
It works for me using Ruby 2.2.5 (with Tk 8.5.12) on Windows 7.
Is there a good book or article about low-level Ruby Tk? All the articles I have seen only cover the simplistic stuff.
To my knowledge, no one has written a thorough description of Ruby's wrapper for Tk (at least, not in English). However, we have the wrapper's
RDoc
documentation, and we can read books describing how to use Tk from other languages. I think the best one (for Ruby purposes) is Learning Perk/Tk by Nancy Walsh (1999). Here are its links at
Amazon,
Alibris
and
O'Reilly (along with its example code).
Also we can grep the wrapper's library source code (since it's installed on our computers).
Doing so for the constant TkToplevel (for example) leads to the file /Ruby/lib/ruby/2.2.0/tk/toplevel.rb (or wherever that file resides on your system).
In that file, searching (for the string TkToplevel) reveals that the constant seems to be defined as an alias for class Tk::Toplevel, which is documented
here.
Ultimately it takes fairly difficult effort to investigate how to do unusual things in Ruby with Tk.
Good results regarding particular issues have been obtained by asking on the
Ruby forum.
The
TkDocs
tutorial is very helpful, along with the Tcl-language
Tk commands
reference documentation.

Related

Capybara.page not in scope after extending capybara-screenshot's after_failed_example method

I'm trying to override the after_failed_example method so I can inflict some custom file naming on our screenshots. I'm loading the module as an initializer.
So far, so good, but the Capybara.page.current_url is blank, making me think I need to require something additional?
require "capybara-screenshot/rspec"
module Capybara
module Screenshot
module RSpec
class << self
attr_accessor :use_description_as_filename
attr_accessor :save_html_file
end
self.use_description_as_filename = true
self.save_html_file = true
def self.after_failed_example(example)
if example.example_group.include?(Capybara::DSL) # Capybara DSL method has been included for a feature we can snapshot
Capybara.using_session(Capybara::Screenshot.final_session_name) do
puts ">>>> Capybara.page.current_url: " + Capybara.page.current_url.to_s
if Capybara::Screenshot.autosave_on_failure && failed?(example) && Capybara.page.current_url != ''
saver = Capybara::Screenshot.new_saver(Capybara, Capybara.page, Capybara::Screenshot.save_html_file?, set_saver_filename_prefix(example))
saver.save
example.metadata[:screenshot] = {}
example.metadata[:screenshot][:html] = saver.html_path if saver.html_saved?
example.metadata[:screenshot][:image] = saver.screenshot_path if saver.screenshot_saved?
end
end
end
private
def self.set_saver_filename_prefix(example)
return example.description.to_s.gsub(" ", "-") if Capybara::Screenshot.use_description_as_filename?
return Capybara::Screenshot.filename_prefix_for(:rspec, example)
end
end
end
end
end
This is successfully overriding the capybara-screenshot/rspec method, and any of the Capybara::Screenshot static information is accessible, but not Capybara session related information (afa I can tell).
For example, Capybara.page.current_url.to_s is null when overridden, but present when not.
I was missing a require (kind of silly mistake):
require 'capybara/rspec'

pry inspect method not working

I have the following code from understanding computation book. The intention is to change the inspect behavior.
class Number < Struct.new(:value)
def inspect
"<<#{self}>>"
end
def to_s
value.to_s
end
end
It works as expected when I use irb:
irb(main):014:0> Number.new(1)
=> <<1>>
but it does not when I use pry:
[8] pry(main)> n = Number.new(1)
=> #<struct Number value=1>
The Pry is version 0.10.3 on Ruby 2.0.0. Why does it not work?
Pry doesn't just use inspect to display the return value. It calls a proc called print object that is defined in configuration. In lib/pry.rb, you can find that it is set to:
class Pry
# The default print
DEFAULT_PRINT = proc do |output, value, _pry_|
_pry_.pager.open do |pager|
pager.print _pry_.config.output_prefix
Pry::ColorPrinter.pp(value, pager, Pry::Terminal.width! - 1)
end
end
end
In order to use inspect as in irb, set it like this as instructed here:
Pry.config.print = proc {|output, value| output.puts "=> #{value.inspect}"}
Then you will get:
pry(main)> n = Number.new(1)
=> <<1>>
I use Pry version 0.10.4.
I've just added the following lines in my .pryrc file (I think, that is a good
place for such code):
if defined?(BigDecimal)
BigDecimal.class_eval do
def inspect
"<#{to_s('+3F')}>"
end
end
end
And result:
balance: <+100.0>,
commission_amount: <+0.15>
Sawa is right in that Pry uses its own printer, but if you look closer at the source you can see that it actually uses Ruby's PP behind the scenes, and PP defines its own behaviour for pretty printing Structs:
class Struct # :nodoc:
def pretty_print(q) # :nodoc:
q.group(1, sprintf("#<struct %s", PP.mcall(self, Kernel, :class).name), '>') {
q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
q.breakable
q.text member.to_s
q.text '='
q.group(1) {
q.breakable ''
q.pp self[member]
}
}
}
end
def pretty_print_cycle(q) # :nodoc:
q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name)
end
end
It's worth checking out the documentation (though it is only brief) if you are interested in learning more about this.
So in your struct you could also define your own pretty_print and pretty_print_cycle methods, which would mean Pry could print these how you want, without having to override their DEFAULT_PRINT proc.

Struggling to write code and tests for my Tube System program, TDD using Rspec and Ruby

I am writing a small program for a train system.
I have a passenger, coach, train and station class (and thus, a spec test for each).
My test for my passenger class is as such:
let (:passenger) {Passenger.new}
it "should not be touched in to a station when initialized" do
expect(passenger.touchedin?).to be false
end
it "should be able to enter coach" do
coach = Coach.new
passenger.enter(coach)
expect{coach.to receive(:enter)}
end
it "should be able to alight coach" do
coach = Coach.new
passenger.alight(coach)
expect{coach.to receive(:alight)}
end
it "should be able to touch into station" do
station = Station.new
passenger.touchin(station)
expect{station.to receive(:touchin)}
end
it "should be able to touch out of station" do
station = Station.new
passenger.touchout(station)
expect{station.to receive(:touchout)}
end
end
And my passenger class is like this (at the moment :p):
class Passenger
def initialize
#touchedin = false
end
def enter(coach)
end
def touchedin?
#touchedin
end
def alight(coach)
end
def touchin(station)
end
def touchout(station)
end
end
I am unsure how to satisfy my tests, if my tests are even correct in the first place.
Any help is really appreciated!
You've not really said how you're modeling the relationship between coaches and passengers, but one way I could think of could be as follows. I'm just putting enough for the coach/passenger relationship (so nothing about touching in as this involves the station) - and I'm using minitest syntax, but I think you can get the idea of what's happening.
class Coach
def initialize
#passengers = []
end
...
end
class Passenger
def initialize
#touched_in = false
end
def alight(coach)
coach.passengers << self.uid # or self, if you want the whole passenger object available
end
...
end
coach = Coach.new
assert_empty coach.passengers
joe = Passenger.new
refute_includes coach.passengers, joe.uid # or joe
joe.alight(coach)
assert_includes coach.passengers, joe.uid # or joe

Ruby - Method call to object in array

I'm working with a Ruby project for school, and have sadly not been able to find an answer to this question in my literature.
I have an array of camping lots, each containing a guest. I initialize the lots like this:
lots = Array.new
for i in (1..36)
lots[i] = Lot.new(i)
end
Further down I create a Guest object, initialize it, and now I want to add the Guest to my Lot. The method in the class Lot looks like this:
def AddGuest(guest)
#guest = guest
end
The problem comes when I want to call the method, as the Lot is in an Array.
lots[lotnumber].AddGuest(guest)
This call gives me the error:
undefined method `+#' for #<Guest:0x2c1ff14> (NoMethodError)
I have used require, so the classes know about each other. I've had quite a hard time understanding Ruby, could my error be that I try to access the AddGuest method in the Array class? I'm used to doing things like this in C++.
Below is the full source (the relevant parts at least).
Entire Lot class:
class Lot
def initialize(number)
#gauge = rand(2000) + 2000
#number = number
#guest = false
end
def Occupied()
return #guest
end
def AddGuest(guest)
#guest = guest
end
def RemoveGuest()
#guest = false
end
end
Parts of main.rb
#includes
require 'guest'
require 'lot'
#initiate comparison variables
userInput = "0"
numberOfGuests = 0
foundLot = false
guests = Array.new
lots = Array.new
#initialize lot list
for i in (1..36)
lots[i] = Lot.new(i)
end
Player input omitted
#make sure lot is not taken
while foundLot == false do
lotnumber = rand(35)+1
if lots[lotnumber].Occupied() == false then
foundLot = "true"
end
end
foundLot = false
guest = Guest.new(firstName, lastName, adress, phone, arrival, lotnumber)
guests.insert(numberOfGuests, guest)
numberOfGuests++
lots[lotnumber].AddGuest(guest) #this is where error hits
end
end
end
The error appears to be related to your use of the ++ operator, which is, quite naturally, supported in C++, but is not supported in Ruby.
The equivalent is:
numberOfGuests += 1
A couple little tips...
[1]
A slightly more idiomatic way to write this...
for i in (1..36)
lots[i] = Lot.new(i)
end
would be...
(1..36).each { |i| lots[i] << Lot.new(i) }
[2]
To remove a Guest from a Lot, you might want to set it to nil rather than false. This would be my suggestion...
class Lot
def initialize(number)
#gauge = rand(2000) + 2000
#number = number
# Don't need to set #guest -- it's nil by default.
end
# In Ruby, methods that return a boolean often have a "?".
# Makes it "read better" when you call the method. (See
# usage sample.)
def occupied?
! #guest.nil?
end
# There's a more commonplace way to do this. See below...
def add_guest(guest)
#guest = guest
end
def remove_guest()
#guest = nil
end
end
Example of usage:
>> lot = Lot.new(2)
=> #<Lot:0x1300920 #number=2, #gauge=3444>
>> lot.occupied
=> false
>> lot.add_guest('A guest')
=> "A guest"
>> lot.occupied?
=> true
>> lot.remove_guest
=> nil
>> lot.occupied?
=> false
Take two...
It's conventional to use attr_accessor methods in your class definition. They automatically add getter and setter methods to your class. You could do that instead of add_guest and remove_guest if you wanted to follow the common Ruby pattern...
class Lot
attr_accessor :number, :gauge, :guest
def initialize(number)
#gauge = rand(2000) + 2000
#number = number
end
def occupied?
! #guest.nil?
end
end
Usage...
irb(main):017:0> lot = Lot.new(3)
=> #<Lot:0xb7f7fca8 #gauge=3186, #number=3>
Set the Guest of a Lot (like add_guest)...
irb(main):019:0> lot.guest = 'A guest'
=> "A guest"
irb(main):020:0> lot.occupied?
=> true
Get the Guest for a Lot...
irb(main):025:0> lot.guest
=> "A guest"
Remove the Guest...
irb(main):021:0> lot.guest = nil
=> nil
irb(main):023:0> lot.occupied?
=> false
Generally Ruby method names are not capitalized. The convention are simply: ClassName, CONSTANT, method_name.
Since you have an Array of Lot objects, the following should be true:
lots.class # => Array
lots[1].class # => Lot
The method called should be defined for Lot.

How could metaprogramming be used to reduce redundancy in this Ruby code?

class Device
def initialize(device_id, data_resource)
#id = device_id
#data_resource = data_resource
end
def display_device
mode = #data_resource.get_display_device_mode(#id)
presets = #data_resource.get_display_device_presets(#id)
summary = "display_device: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
def chip
mode = #data_resource.get_chip_mode(#id)
presets = #data_resource.get_chip_presets(#id)
summary = "chip: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
def input_device
mode = #data_resource.get_input_device_mode(#id)
presets = #data_resource.get_input_device_presets(#id)
summary = "input_device: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
end
As you can see from the code above, there is quite a bit of redundancy within the methods. Regardless of whether metaprogramming is the best way to reduce this redundancy, I am hoping to learn how to use metaprogramming in Ruby to reduce some of the repetitiveness here if someone could provide some suggestions.
Here's a version that uses metaprogramming, though I'd also remove the duplication by putting it in a method where it belongs.
class Device
def initialize(device_id, data_resource)
#id = device_id
#data_resource = data_resource
end
def resource_summary(resource_name)
mode = #data_resource.send("get_#{resource_name}_mode", #id)
presets = #data_resource.send("get_#{resource_name}_presets", #id)
summary = "#{resource_name}: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
def self.resource_accessor(*names)
names.each {|resource| define_method(resource) {resource_summary resource}}
end
resource_accessor :display_device, :chip, :input_device
end
If you really didn't want to make a method for that functionality, you could just replace the resource_summary method call with the body of the resource_summary method.
Something like this could work so you can define 'components' (or whatever they are) declaratively. This is overkill for this sort of example, but you can use it when you need to define dozens/hundreds of these things, or you're putting it as part of some framework (like rails does).
The component class level method would usually live in some other module that gets included into the class rather than declaring it inline where it's used like this.
class Device
class << self
def component(component_name)
define_method(component_name) do
mode = #data_resource.send("get_#{component_name}_mode", #id)
presets = #data_resource.send("get_#{component_name}_presets", #id)
summary = "#{component_name} : #{mode} ($#{presets})"
presets == "XTC909" ? "* #{summary}" : summary
end
end
end
component :display_device
component :chip
component :input_device
def initialize(device_id, data_resource)
#id = device_id
#data_resource = data_resource
end
end
You can drive it with something like:
class DataResource
def method_missing(method, *args)
# puts "called #{method} with:#{args.inspect}"
"#{method}-#{args.join(':')}"
end
end
device = Device.new("ID123", DataResource.new)
puts device.display_device
puts device.chip
puts device.input_device
Obviously, some names should change...
def display_device
i_heart_meta_programming("display_device")
end
def chip
i_heart_meta_programming("chip")
end
def input_device
i_heart_meta_programming("input_device")
end
def i_heart_meta_programming(what_to_get)
mode = #data_resource.send("get_#{what_to_get}_mode", #id)
mode = #data_resource.send("get_#{what_to_get}_presets", #id)
summary = "#{what_to_get}: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
Are you sure that you need to reduce redundancy here at all? It's certainly possible, but anything you do will just make the code harder to understand and will not necessarily be a net win.
I guess u probably solve this alreaday, anyway this is my alternative:
class Device
def initialize(device_id, data_resource)
#id,#data_resource = device_id, data_resource
end
%w{display_device chip input_device}.each do |met|
define_method met do
mode = #data_resource.send("get_#{met}_mode", #id)
presets = #data_resource.send("get_#{met}_presets",#id)
summary = "#{met}: #{mode} ($#{presets})"
return "* #{summary}" if presets == "XTC909"
summary
end
end
end
Can you come up with a better example?
As I said your previous version of this, metaprogramming is hardly needed here. Basic encapsulation of functionality in methods would work.
Any examples that people give would be contrived and not really representative of real world usage of metaprogramming.

Resources