How to set WM_CLASS on TkRoot in ruby - ruby

I'm trying to set the 'WM_CLASS' attribute for my ruby tk application. I've tried several ways, but I think it should work like that:
TkRoot.new(class: 'Test')
But that will err with:
<internal:kernel>:18:in `class': wrong number of arguments (given 1, expected 0) (ArgumentError)
from /home/ben/.gem/ruby/3.0.0/gems/tk-0.4.0/lib/tk/root.rb:40:in `block in new'
from /home/ben/.gem/ruby/3.0.0/gems/tk-0.4.0/lib/tk/root.rb:36:in `each'
from /home/ben/.gem/ruby/3.0.0/gems/tk-0.4.0/lib/tk/root.rb:36:in `new'
from examples/form.rb:19:in `initialize'
from examples/form.rb:49:in `new'
from examples/form.rb:49:in `<main>'
How to do it correctly?

Tk (C api) is setting the the WM_CLASS values to the value of argv[0] which is the same as $0 in ruby. So to set WM_CLASS, one has to set $0 prior to requiring Tk. i.e.:
$0 = 'myWmClass'
require 'Tk'
# ... rest of the code follows here
This will set the application name (of WM_CLASS) to 'myWmClass' and the application class to 'MyWmClass' (so uppercase is forced here). If one wants to set the application name to something different, this can be done via Tk.appname('someFancyName') after requiring Tk. Note that even though Tk is required, the main window seems not to be created and so the newly created main window will have the correct appname right from the start. Also note, that using an uppercase string as application name may result in errors, as the official tk command reference states.
For any other toplevel window (besides the root window), WM_CLASS can be set on construction, e.i. TkToplevel.new(root, class: 'Toplevel'). Trying to do that on TkRoot will currently result in an exception. (It seems however to work in the python api.)

Related

Rubymine file reference

I'm trying to reference a file to write to it using RubyMine and I'm having trouble figuring it out. When using the full path, the code errors out while running it with RubyMine.
When I use the same code and run it in terminal, the code works fine using the command:
ruby studio_game players.csv
How can I get the file to be recognized without having to designate the full path in RubyMine?
Erring Code:
require_relative 'player'
require_relative 'game'
player1 = Player.new("moe")
player2 = Player.new("larry", 60)
player3 = Player.new("curly", 125)
knuckleheads = Game.new("Knuckleheads")
knuckleheads.load_players(ARGV.shift || 'players.csv')
Error message:
/Users/MNickey/.rvm/rubies/ruby-1.9.3-p448/bin/ruby -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) "/Users/MNickey/RubymineProjects/PragmaticStudio/Stooges Game/studio_game"
/Users/MNickey/RubymineProjects/PragmaticStudio/Stooges Game/game.rb:83:in `readlines': No such file or directory - players.csv (Errno::ENOENT)
from /Users/MNickey/RubymineProjects/PragmaticStudio/Stooges Game/game.rb:83:in `load_players'
from /Users/MNickey/RubymineProjects/PragmaticStudio/Stooges Game/studio_game:9:in `<top (required)>'
from -e:1:in `load'
from -e:1:in `<main>'
knuckleheads.load_players(ARGV.shift || 'players.csv') is almost certainly what is causing the problem. Unless you have configured the launcher for the script with a command line argument, ARGV will be empty and you will be getting plain-old 'players.csv' as the result.
I'm pretty certain you are running the script with an argument when you run it in the command line.
To set a command line parameter in RubyMine, go to Run / Edit Configurations, find the launch configuration for your script, and add the path to your csv file to the Script Arguments input box.

How to load a ruby file in to IRB?

I have a file: options.rb
I open IRB and type:
require './options.rb'
#=> true
Try to call a variable in the options file such as key (yes this variable is there and the file is saved)
NameError: undefined local variable or method `key' for main:Object
from (irb):2
Why is this not working? By the way also tried to load the file as: irb -r ./options.rb
UPDATE
Also tried to do load './options.rb' which does return #=> true but this also does not work.
From the require docs:
Any constants or globals within the loaded source file will be available in the calling program’s global namespace. However, local variables will not be propagated to the loading environment.
So if in options.rb you have something like:
key = something
(i.e. key is a local in the file) then it will not be available in irb. If you make it a global (e.g. $key = 'something') or a constant (e.g. KEY = 'something') it should be available.
If you do not like global variables (as matt suggested) you might also make it an instance variable of the object irb is running on (an instance of Object available through self as ruby always has an object it is operating on) you may also assign
#key='value'
in your file which will give you access to #key in your irb-session afterwards. This will work with either require as with load, but require will only load the file if it has not already done so while load will always execute the code in the file and thus will end up overwriting the contents of your variable if it has been changed in the mean time.
Ruby is a interpreted language, so for the interpreter to notice your declarations you need to actually 'run' them, the corresponding command in irb is
load './options.rb'

Ruby require_relative executing script?

I'm working on a game server in ruby, and during testing I'm having trouble testing components individually. I wasn't getting output from my launcher, just the server, so I commented out the initialisation of the server- yet eclipse still showed output from the server!
I then went to the command line, assuming eclipse was looking at the wrong file (git has messed it around before, but as you can see, the stack trace shows that Server.rb is being executed in its entirety from line 5: require_relative 'Server':
This is the text content of the file:
class Launcher
puts "File saved at #{File.mtime($0)}"
require_relative 'Server'
require_relative 'Game'
#STDOUT.sync = true
puts "Launcher started"
#server = Server.new
print "server made"
game = Game.new
#serverThread = Thread.new{server.start()}
gameThread = Thread.new{game.start()}
while (running)
print "Stop? "
input = gets.chomp
if (input.equals?("yes"))
running = false
end
end
server.stop
game.stop
gameThread.join
serverThread.join
end
and the terminal output:
C:\Users\gossfunkel\git\citadelserver\RubyCitadelServer>ruby Launcher.rb
File saved at 2013-06-22 18:16:44 +0100
Server starting up at 2013-06-22 18:16:47 +0100...
C:/Users/gossfunkel/git/citadelserver/RubyCitadelServer/Server.rb:20:in `recvfro
m': Interrupt
from C:/Users/gossfunkel/git/citadelserver/RubyCitadelServer/Server.rb:2
0:in `run'
from C:/Users/gossfunkel/git/citadelserver/RubyCitadelServer/Server.rb:1
5:in `start'
from C:/Users/gossfunkel/git/citadelserver/RubyCitadelServer/Server.rb:3
0:in `<class:Server>'
from C:/Users/gossfunkel/git/citadelserver/RubyCitadelServer/Server.rb:1
:in `<top (required)>'
from Launcher.rb:5:in `require_relative'
from Launcher.rb:5:in `<class:Launcher>'
from Launcher.rb:1:in `<main>'
How do I require a file without this happening, and should it be?
I can't tell without seeing the classes, but I would guess that either
game.start is doing more than you thought, and is starting the server for itself
You are, as your subject line suggests, running a different file from the one you are editing (or not saving the file once it is changed). Check by putting an obvious puts at the top of the program. Something like
puts "File saved at #{File.mtime($0)}"
should do the trick
After discussion, it seems there's a third option. The code in Server.pm creates and runs a server as well as defining the class. You need to remove the require as well as the lines that use the Server class.

How to execute local functions using code from external file in ruby?

Can a require execute a locally defined function? I guess the easiest way to describe what I need is to show an example.
I'm using ruby 1.9.3, but solutions for 1.8 and 2.0 are also welcome.
I have a file main.rb as the following:
class Stuff
def self.do_stuff(x)
puts x
end
require_relative('./custom.rb')
do_stuff("y")
end
And also have a file custom.rb in the same folder, with the following content:
do_stuff("x")
Running main.rb, I have following output:
/home/fotanus/custom.rb:1:in `<top (required)>': undefined method `do_stuff' for main:Object (NoMethodError)
from main.rb:5:in `require_relative'
from main.rb:5:in `<class:Stuff>'
from main.rb:1:in `<main>'
Note that without the require, the output is y.
I'm not sure if it is the best solution but using eval should do the trick.
class Stuff
def self.do_stuff(x)
puts x
end
eval(File.read('./custom.rb'))
do_stuff("y")
end
The output will be:
pigueiras#pigueiras$ ruby stuff.rb
x
y
In C, #include literally drops the code as-is into the file. require in Ruby is different: it actually runs the code in the required file in its own scope. This is good, since otherwise we could break required code by redefining things before the require.
If you want to read in the contents of a script and evaluate it in the current context, there are methods for doing just that: File.read and eval.

Telling rspec to not load files

I'm trying to add some commit hooks to my git repo. I want to leverage Rspec and create commit message specs that will run each time I commit. I have figured out how to run rspec outside of the 'spec' command, but I now have an interesting problem.
Here is my current code:
.git/hooks/commit-msg
#!/usr/bin/env ruby
require 'rubygems'
require 'spec/autorun'
message = File.read(ARGV[0])
describe "failing" do
it "should fail" do
true.should == false
end
end
This is throwing an error when it gets to the describe call. Basically, it thinks that the commit message it receives is the file to load and run the specs against. Here is the actually error
./.git/COMMIT_EDITMSG:1: undefined local variable or method `commit-message-here' for main:Object (NameError)
from /Users/roykolak/.gem/ruby/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:15:in `load'
from /Users/roykolak/.gem/ruby/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:15:in `load_files'
from /Users/roykolak/.gem/ruby/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `each'
from /Users/roykolak/.gem/ruby/1.8/gems/rspec-1.3.0/lib/spec/runner/example_group_runner.rb:14:in `load_files'
from /Users/roykolak/.gem/ruby/1.8/gems/rspec-1.3.0/lib/spec/runner/options.rb:133:in `run_examples'
from /Users/roykolak/.gem/ruby/1.8/gems/rspec-1.3.0/lib/spec/runner.rb:61:in `run'
from /Users/roykolak/.gem/ruby/1.8/gems/rspec-1.3.0/lib/spec/runner.rb:45:in `autorun'
from .git/hooks/commit-msg:12
I am looking for a way to tell rspec to not load files. I have a suspicion that I will need to create my own spec runner. I came to this conclusion after viewing these lines in rspec-1.3.0/lib/spec/runner/example_group_runner.rb
def load_files(files)
$KCODE = 'u' if RUBY_VERSION.to_f < 1.9
# It's important that loading files (or choosing not to) stays the
# responsibility of the ExampleGroupRunner. Some implementations (like)
# the one using DRb may choose *not* to load files, but instead tell
# someone else to do it over the wire.
files.each do |file|
load file
end
end
But, I would like some feedback before I do that. Any thoughts?
Do you even really need all the special stuff that RSpec provides (should and the various matchers) just to verify the contents of a single file? It really seems like overkill for the problem.
spec/autorun eventually calls Spec::Runner.autorun which parses ARGV as if it held normal arguments for a spec command line.
When you install a bare “spec” file as a Git hook,
it will get arguments that are appropriate for the whatever Git hook is being used,
not spec-style arguments (spec filenames/directories/patterns and spec options).
You might be able to hack around the problem like this:
# Save original ARGV, replace its elements with spec arguments
orig_argv = ARGV.dup
%w(--format nested).inject(ARGV.clear, :<<)
require 'rubygems'
require 'spec/autorun'
# rest of your code/spec
# NOTE: to refer to the Git hook arguments use orig_argv instead of ARGV

Resources