Why is force_encoding("BINARY") used here? - ruby

When we install Rails, we get this rails "executable":
#!/usr/bin/env ruby
#
# This file was generated by RubyGems.
#
# The application 'railties' 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 'railties', version
load Gem.bin_path('railties', 'rails', version)
I'm wondering what the point of doing force_encoding("BINARY") is on that String. What possible values could it be that force_encoding is necessary? I would think that people would only specify versions using numbers and letters here.

This isn't a rails specific thing - it's a wrapper rubygems will generate for any ruby executable in a gem. The call to force_encoding was added in 6bf71914
The reason for the change is that the first argument might not be a version at all - we want to test if it is a version, but it could be anything and we don't want the regex check to blow up. For example some executables accept a list of file names as arguments, and those file names could be invalid in the default external encoding used by ruby.
There is a bit more discussion on the issue which prompted this change.

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

Programatically get current version of ruby standard library

I looking for a way in my ruby program to determine the version of Ruby that is running my program as well as the version of the Standard Libary?
The version of Ruby is stored in the RUBY_VERSION global constant.
puts RUBY_VERSION
You can compare versions by using classes provided by Rubygems:
min_ruby_version = Gem::Requirement.new(">=2.2.0")
current_ruby_version = Gem::Version.new(RUBY_VERSION)
# check if ruby conforms to version req using =~ operator
if min_ruby_version =~ current_ruby_version
do_this
else
do_that
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.

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

Add Ruby Source Code as HTML to RDoc

How do I include a ruby code file, as is, into RDoc?
I have an example.rb file that documents how to use my gem and I would like to include that as one of the files like the README.rdoc and HISTORY.rdoc.
I've already figured out how to convert the ruby source code into HTML using the Syntax gem but I can't figure out how to make RDoc include the file without parsing it.
When I tell RDoc to include the html file it isn't listed and if I fake it out by using rdoc or txt as the file extension it doesn't display properly (the file is still actually html).
I've got a solution that works it's just incredibly ugly. There has got to be a better way to do this that's native to rdoc but I don't see it.
Here's what I have in my Rakefile:
# Build rdocs
require 'rake/rdoctask'
require 'syntax/convertors/html'
rdoc_dir = 'rdoc'
# This is rdoc1 but it doesn't work unless you DON'T wrap it in a task
# Generate html files from example ruby files
convertor = Syntax::Convertors::HTML.for_syntax "ruby"
replacement_key = "REPLACE_THIS_TEXT_WITH_PROPER_HTML"
# Create dummy files
Dir.glob('examples/*.rb').each do |file|
File.open("#{file}.txt", "w") do |dummy_file|
dummy_file.write(replacement_key)
end
end
# Call the rdoc task
Rake::RDocTask.new(:rdoc2) do |rdoc|
rdoc.rdoc_dir = rdoc_dir
rdoc.title = "pickled_optparse #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('HISTORY*')
rdoc.rdoc_files.include('examples/*.txt')
rdoc.rdoc_files.include('lib/**/*.rb')
end
task :rdoc3 do
# Now use a hammer to replace the dummy text with the
# html we want to use in our ruby example code file.
html_header = File.read('rake_reqs/html_header.html')
Dir.glob('examples/*.rb').each do |file|
html_ruby = convertor.convert(File.read(file))
rdoc_file = "#{rdoc_dir}/examples/#{File.basename(file,".rb")}_rb_txt.html"
fixed_html = File.read(rdoc_file).gsub!(replacement_key, "#{html_header}#{html_ruby}")
File.open(rdoc_file, "w") {|f| f.write(fixed_html)}
File.delete("#{file}.txt")
end
end
task :rdoc => [:rdoc2, :rdoc3]
Sorry I can't give you an actual answer but I'm looking at sdoc myself.
You can install the gem from ruby gems.

Resources