Ruby Hash.has_key? returning false for the first key on Windows - ruby

I'm having a weird issue with Ruby hashes on windows. I'm loading the following YAML file and parsing it as a hash:
tasks:
- clone_skeleton, <skeleton_path>
- summit_capify, <skeleton_path>
I'm using YAML.load() to load the file into a hash. If I print out hash.keys tasks is listed as a key but if I do hash.has_key?("tasks") I get back false. However if I change the yaml to this
directory_structure:
tasks:
- clone_skeleton, <skeleton_path>
- summit_capify, <skeleton_path>
hash.has_key?("tasks") returns true but hash.has_key?("directory_structure") returns false. I haven't tested in Linux but I don't seem to be having this problem on OS X, just Windows. I'm using Ruby 1.9.2 and have tested in Cygwin and using the standard command prompt.
I don't know if this is a ruby bug, a problem with my YAML or something else. Any ideas?
UPDATE: Looks like this is fixed in Ruby 1.9.3

Is it possible the keys are Symbols and not Strings? Trying has_key?(:tasks).

Whenever you're debugging, don't do puts hash.keys, but do puts hash.keys.inspect - the latter indicates exactly what's going on.
Or you may want to do puts hash.inspect.

Related

ASCII incompatible encoding with normal run, not in debug mode

I'm really confused on this one, and maybe it's a bug in Ruby 2.6.2. I have files that were written as UTF-8 with BOM, so I'm using the following:
filelist = Dir.entries(#input_dirname).join(' ')
filelist = filelist.split(' ').grep(/xml/)
filelist.each do |indfile|
filecontents_tmp = File.read("#{#input_dirname}/#{indfile}", :encoding =>'bom|utf-8')
puts filecontents_tmp
end
If I put a debug breakpoint at the puts line, my file is read in properly. If I just run the simple script, I get the following error:
in `read': ASCII incompatible encoding needs binmode (ArgumentError)
I'm confused as to why this would work in debug, but not when run normally. Ideas?
Have you tried printing the default encoding when you run the file as opposed to when you debug the file? There are 3 ways to set / change the encoding in Ruby (that I'm aware of), so I wonder if it's different between running the file and debugging. You should be able to tell by printing the default encoding: puts Encoding.default_external.
As for actually fixing the issue, I ran into a similar problem and found this answer which said to add bin mode as an option to the File.open call and it worked for me.

Ruby 1.8 vs 2.3 handling YAML config arrays differently

I'm trying to upgrade a server that has ruby scripts developed by another person. I'm a perl/php developer and no little about ruby, just trying to get the scripts to work that was developed with Ruby 1.8 and the scripts seems to behave differently handling arrays in the newer version. The script was not matching iterated folders with a config file array with the folder names and I believe I've boiled it down to the way the YAML config file is converted to an array. I put together this simple script:
require 'rubygems'
require 'yaml'
config_filename = File.expand_path(File.dirname(__FILE__) + "/testruby.yml")
#config = YAML.load(File.open(config_filename))
puts #config
The YAML testruby.yml config file looks like this:
1_01:
name: Monday Show
suffix: showM
program_id: 123
segment: 1
dated: false
1_02:
name: Monday Show
suffix: showM
program_id: 123
segment: 2
dated: false
1_03:
name: Tuesday Show
suffix: showT
program_id: 124
segment: 1
dated: true
When I run this on the original server with Ruby 1.8, the result is:
1_03program_id124nameTuesday Showsegment1suffixshowTdatedtrue1_02program_id123nameMonday Showsegment2suffixshowMdatedfalse1_01program_id123nameMonday Showsegment1suffixshowMdatedfalse
But when ran on the new server with Ruby 2.3 I get a array:
{101=>{"name"=>"Monday Show", "suffix"=>"showM", "program_id"=>123, "segment"=>1, "dated"=>false}, 102=>{"name"=>"Monday Show", "suffix"=>"showM", "program_id"=>123, "segment"=>2, "dated"=>false}, 103=>{"name"=>"Tuesday Show", "suffix"=>"showT", "program_id"=>124, "segment"=>1, "dated"=>true}}
It even removes the underscore from the folder name key in the config file. For this reason, later in the script, calls to #config[1_01] does not match of course. Is there a way to get the array to build like version 1.9 so the rest of the script works as designed?
One more thing to note, not sure if it related to the issue. The require 'yaml' line was not present in the script, I added after receiving this error when ran:
testruby.rb:4:in `<main>': uninitialized constant YAML (NameError)
Well, it seems all I had to do was enclose the YAML keys in quotes and now the hash object includes the underscore in the keys and the rest of the script works!

JSON Parser Acts Differently

I am trying to parse the following string called result:
{
"status":0,
"id":"faxxxxx-1",
"hypotheses":[
{"utterance":"skateboard","confidence":0.90466744},
{"utterance":"skate board"},
{"utterance":"skateboarding"},
{"utterance":"skateboards"},
{"utterance":"skate bored"}
]
}
Using obj = JSON.parse(result) in Ruby 1.8 with the json gem.
The command in question is:
puts "#{obj['hypotheses'][0]}"
My old workstation (whose harddrive died) gave me:
{"utterance" => "skateboard", "confidence" => 0.90466744}
My current workstation gives me:
confidence0.90466744utteranceskateboard
The old workstation was not set up by me, so I don't know what kind of packages were installed, while this current one was.
Why is there a difference in the output of the exact same script?
How can I make the current one look like the old one?
I am completely new to this btw.
In Ruby 1.8, Hash#to_s simply joins all of the elements together without spaces, equivalent to to_a.flatten.join('').
In Ruby 1.9, Hash#to_s is an alias to inspect and produces well-formatted output.
To get the equivalent thing in both cases:
puts obj['hypotheses'][0].inspect
The same thing applies to Array.

A ruby script to run tail on a log file?

I want to write a ruby script that read from a config file that will have filenames, and then when I run the script it will take the tail of each file and output the console.
What's the best way to go about doing this?
Take a look at File::Tail gem.
You can invoke linux tail -number_of_lines file_name command from your ruby script and let it print on console or capture output and print it yourself (if you need to do something with these lines before you print it)
We have a configuration file that contain a list of the log files; for example, like this:
---
- C:\fe\logs\front_end.log
- C:\mt\logs\middle_tier.log
- C:\be\logs\back_end.log
The format of the configuration file is a yaml simple sequence , therefore suppose we named this file 'settings.yaml'
The ruby script that take the tail of each file and output the console could be like this:
require 'yaml'
require 'file-tail'
logs = YAML::load(File.open('settings.yaml'))
threads = []
logs.each do |the_log|
threads << Thread.new(the_log) { |log_filename|
File.open(log_filename) do |log|
log.extend(File::Tail)
log.interval = 10
log.backward(10)
log.tail { |line| p "#{File.basename(the_log,".log")} - #{line}" }
end
}
end
threads.each { |the_thread| the_thread.join }
Note: displaying each line I wanted to prefix it with the name of the file from which it originates, ...this for me is a good option but you can edit the script to change as you like ; is the same for the tails parameters.
if file-tail is missing in your environment, follow the link as #Mark Thomas posts in his answear; i.e you need to:
> gem install file-tail
I found the file-tail gem to be a bit buggy. I would write to a file and it would read the entire file again instead of just thelines appended. This happened even though I had log.backward set to 0. I ended up writing my own and figured that I would share it here in case any one else is looking for a Ruby alternative to the file-tail gem. You can find the repo here. It uses non_blocking io, so it will catch amendments to the file immediately. There is one caveat that can be easily fixed if you can program in the Ruby programming language; log.backward is hard coded to be -1.

Unicode filenames on Windows in Ruby

I have a piece of code that looks like this:
Dir.new(path).each do |entry|
puts entry
end
The problem comes when I have a file named こんにちは世界.txt in the directory that I list.
On a Windows 7 machine I get the output:
???????.txt
From googling around, properly reading this filename on windows seems to be an impossible task. Any suggestions?
I had the same problem & just figured out how to get the entries of a directory in UTF-8 in Windows. The following worked for me (using Ruby 1.9.2p136):
opts = {}
opts[:encoding] = "UTF-8"
entries = Dir.entries(path, opts)
entries.each do |entry|
# example
stat = File::stat(entry)
puts "Size: " + String(stat.size)
end
You're out of luck with pure ruby (either 1.8 or 1.9.1) since it uses the ANSI versions of the Windows API.
It seems like Ruby 1.9.2 will support Unicode filenames on Windows. This bug report has 1.9.2 as target. According to this announcement Ruby 1.9.2 will be released at the end of July 2010.
If you really need it earlier you could try to use FindFirstFileW etc. directly via Win32API.new or win32-api.
My solution was to use Dir.glob instead of Dir.entries. But it only works with * parameter. It does not work when passing a path (c:/dir/*). Tested in 1.9.2p290 and 1.9.3p0 on Windows 7.
There are many other issues with unicode paths on Windows. It is still an open issue. The patches are currently targeted at Ruby 2.0, which is rumored to be released in 2013.

Resources