ruby file locking error Errno::EBADF in solaris - ruby

Am trying to lock one executable script to make sure it doesn't run second time when there is another process running. Here is my code,
if $0 == __FILE__
if File.new(__FILE__).flock(File::LOCK_EX | File::LOCK_NB)
main()
end
end
and getting below error,
# ruby /tmp/test.rb
/tmp/test.rb:397:in `flock': Bad file number - /tmp/test.rb (Errno::EBADF)
from /tmp/test.rb:397:in `<main>'
#
Am using ruby version 1.9.3,
# ruby --version
ruby 1.9.3p551 (2014-11-13 revision 48407) [sparc-solaris2.11]
#
But its working perfect in Linux environments.

Found the solution. In Solaris we need to open file with read/write mode only then the exclusive lock will happen.
if $0 == __FILE__
if File.new(__FILE__, 'r+').flock(File::LOCK_EX | File::LOCK_NB)
main()
end
end

Related

Force .rb file running under specific ruby versions

I write a ruby script in a .rb file. It uses latest Ruby features (version 2.7). Is there any way to force this .rb file can only be executed in a specific Ruby version range? For example, the first line of a .rb file could be:
#! ruby 2.7+
# This .rb file can only be run with Ruby version 2.7 or above
Use the gem semantic to handle parsing the current Ruby version:
require 'semantic'
# Require >= 2.7 < 3
exit unless Semantic::Version.new(RUBY_VERSION).satisfies?('~> 2.7')
# Require >= 2.7, including 3 and above
exit unless Semantic::Version.new(RUBY_VERSION).satisfies?('>= 2.7')
This requires you to use bundler and a Gemfile with your app.
Other comparators are listed in the source code for the gem:
if ['<', '>', '<=', '>='].include?(comparator)
satisfies_comparator? comparator, pad_version_string(other_version_string)
elsif comparator == '~>'
pessimistic_match? other_version_string
else
tilde_matches? other_version_string
end
This will allow you to fine-tune your version requirements.
Naively,
unless RUBY_VERSION[0, 3] == "2.7"
puts "You need 2.7")
exit
end

Installed gem much slower than source

Running an installed gem is much slower than running its local source counterpart.
Installed gem:
$ time wmctile switch_to Thunderbird
real 0m0.682s
user 0m0.491s
sys 0m0.091s
Local source:
$ time ./work/wmctile/bin/wmctile switch_to Thunderbird
real 0m0.197s
user 0m0.118s
sys 0m0.064s
Why? Could it be because of RVM, or is this a "feature" of Ruby gems in general? Is there a way to speed it up?
This is the generated bin file:
$ which wmctile
/home/some_user_name/.rvm/gems/ruby-2.1.2/bin/wmctile
$ cat $( which wmctile )
#!/usr/bin/env ruby_executable_hooks
#
# This file was generated by RubyGems.
#
# The application 'wmctile' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first
str = ARGV.first
str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
if str =~ /\A_(.*)_\z/ and Gem::Version.correct?($1) then
version = $1
ARGV.shift
end
end
gem 'wmctile', version
load Gem.bin_path('wmctile', 'wmctile', version)
RVM puts the proper directories for your Ruby version and gemset in the path whenever the RVM Ruby is set. My PATH begins with this:
/Users/kbennett/.rvm/gems/ruby-2.3.0/bin
/Users/kbennett/.rvm/gems/ruby-2.3.0#global/bin
/Users/kbennett/.rvm/rubies/ruby-2.3.0/bin
/Users/kbennett/.rvm/bin
So, I think it's the OS and not Ruby itself that is responsible for the delay. You could test this by putting a simple shell script file in that gem bin directory, and calling it with and without its absolute location to see if you get the same difference.

Array#to_s in Ruby 2.1 broke my code

This code broke on Ruby 2.1
class Test
def to_s()
"hi"
end
end
puts [Test.new(), Test.new()].to_s
Ruby 1.9.3:
$ ruby --version
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]
$ /opt/chef/embedded/bin/ruby test.rb
[hi, hi]
Ruby 2.1:
$ ruby --version
ruby 2.1.4p265 (2014-10-27 revision 48166) [x86_64-linux]
$ ruby test.rb
[#<Test:0x000000022ac400>, #<Test:0x000000022ac3d8>]
Is this documented somewhere? How can the old behavior be preserved?
Your code:
puts [Test.new(), Test.new()].to_s
is a questionable use of Array.to_s. Instead I'd use:
puts [Test.new(), Test.new()].map(&:to_s)
While I can see that the first use makes sense, the second use makes more sense and should work in any version of Ruby.
On ruby 2.1.5:
class Test
def to_s
"hi"
end
alias inspect to_s # add this line
end
puts [Test.new, Test.new].to_s
#=> [hi, hi]
This seems like a bug to me. If it is intended behavior, that is really annoying.
You don't need to_s. puts does the work for you
puts [Test.new(), Test.new()]
# hi
# hi
If you want the brackets, that's what inspect is for (in which case it makes sense that you would need to define Test#inspect).

Ruby hash.key error

I feel like I'm overlooking something here. When I try to use the Hash.key(keytolookfor) method, I get an error.
Is this method deprecated?
pete#Vader:~/tmp$ ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
pete#Vader:~/tmp$ ./hashtest.rb
./hashtest.rb:8: undefined method `key' for {"firstkey"=>"firstvalue", "secondkey"=>"secondvalue"}:Hash (NoMethodError)
pete#Vader:~/tmp$
The script is as follows.
#!/usr/bin/ruby
testHash = Hash.new
testHash["firstkey"] = "firstvalue"
testHash["secondkey"] = "secondvalue"
if testHash.has_value?("secondvalue")
keyvalue = testHash.key("secondvalue")
puts "match found with key #{keyvalue}"
else
puts "no match found"
end
My wild guess is that your system ruby /usr/bin/ruby is 1.8.7 which doesn't have Hash#key method. ruby -v most probably shows rvm version which is located in ~/.rvm/..., but first line in your script calls /usr/bin/ruby.
Use the heap record for script as follows:
#/usr/bin/env ruby
This picks up the default ruby version specified by the system, rvm, or rbenv. Since Ruby 1.8.7 has no Hash#key, make sure that you're running at least Ruby 1.9.1:
$ /usr/bin/ruby -v
1.9.1p0
Alternatively, use Hash#[] instead:
keyvalue = testHash["secondvalue"]

Need to call different Ruby method depending on what version is installed

I have a Ruby script that iterates over each line of a text file.
In Ruby 1.8.* using content.each do |line| works fine, but in Ruby 1.9.* that does not work, and I need to use content.each_line do |line|.
Since this script will be used by several different people, I need to be able to use the right method depending on their version of Ruby.
Is there a way to do this?
The global constant RUBY_VERSION contains the version of the currently running Ruby. So this script will do what you want:
if RUBY_VERSION < "1.9.2"
# code for 1.8.7
else
# code for 1.9.2+
end
If the inner code of the each_line is equal with 1.8.* and 1.9.*, the following approach is more DRY:
each_selector = RUBY_VERSION < "1.9.2" ? :each : :each_line
content.send(each_selector) do | line|
# ...
end

Resources