Skip to content

Instantly share code, notes, and snippets.

@balthisar
Last active December 26, 2015 05:30
Show Gist options
  • Save balthisar/439fdf66b13fff5eb417 to your computer and use it in GitHub Desktop.
Save balthisar/439fdf66b13fff5eb417 to your computer and use it in GitHub Desktop.
Portable `which` in Ruby

Portable which in ruby

Forked to prevent gist from disappearing.

Usage

require 'which'

Which('ls')      # => "/bin/ls"

WhichAll('ruby') # => [
                 #     [0] "/usr/local/ruby/ruby-2.2.0/bin/ruby",
                 #     [1] "/usr/bin/ruby"
                 # ]

Installation

Bundler

gem 'which', gist: '439fdf66b13fff5eb417'

Manual installation

git clone https://gist.github.com/balthisar/439fdf66b13fff5eb417.git which
cd which
gem build *.gemspec
gem install *.gem
cd ..
rm -rf
Gem::Specification.new do |s|
s.name = 'which'
s.summary = 'which'
s.description = 'which'
s.version = '0.0.1'
s.platform = Gem::Platform::RUBY
s.files = ['which.rb', '00README.md']
s.require_path = '.'
s.author = 'Barry Allard'
s.email = 'barry.allard@gmail.com'
s.license = 'MIT'
s.homepage = 'https://gist.github.com/steakknife/88b6c3837a5e90a08296'
end
# https://gist.github.com/steakknife/88b6c3837a5e90a08296
# Copyright (c) 2014 Barry Allard <barry.allard@gmail.com>
# License: MIT
#
# inspiration: https://stackoverflow.com/questions/2889720/one-liner-in-ruby-for-displaying-a-prompt-getting-input-and-assigning-to-a-var
#
# Which Bourne shell?
#
# require 'which'
#
# Which 'sh'
#
#
# Or all zsh(es)
#
# require 'which'
#
# WhichAll 'zsh'
#
module Which
# similar to `which {{cmd}}`, except relative paths *are* always expanded
# returns: first match absolute path (String) to cmd (no symlinks followed),
# or nil if no executable found
def which(cmd)
which0(cmd) do |abs_exe|
return abs_exe
end
nil
end
# similar to `which -a {{cmd}}`, except relative paths *are* always expanded
# returns: always an array, or [] if none found
def which_all(cmd)
results = []
which0(cmd) do |abs_exe|
results << abs_exe
end
results
end
def real_executable?(f)
File.executable?(f) && !File.directory?(f)
end
def executable_file_extensions
ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
end
def search_paths
ENV['PATH'].split(File::PATH_SEPARATOR)
end
def find_executable(path, cmd, &_block)
executable_file_extensions.each do |ext|
# rubocop:disable Lint/AssignmentInCondition
if real_executable?(abs_exe = File.expand_path(cmd + ext, path))
yield(abs_exe)
end
# rubocop:enable Lint/AssignmentInCondition
end
end
# internal use only
# +_found_exe+ is yielded to on *all* successful match(es),
# with path to absolute file (String)
def which0(cmd, &found_exe)
# call expand_path(f, nil) == expand_path(f) for relative/abs path cmd
find_executable(nil, cmd, &found_exe) if File.basename(cmd) != cmd
search_paths.each do |path|
find_executable(path, cmd, &found_exe)
end
end
module_function(*public_instance_methods) # `extend self`, sorta
end
# make Which() and WhichAll() work
module Kernel
# rubocop:disable Style/MethodName
# return abs-path to +cmd+
def Which(cmd)
Which.which cmd
end
module_function :Which
# return all abs-path(s) to +cmd+ or [] if none
def WhichAll(cmd)
Which.which_all cmd
end
module_function :WhichAll
# rubocop:enable Style/MethodName
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment