class Object
Constants
- ALL_TYPES
- BOOLEAN
- BOOL_TYPES
- CA_ALIGN_BOOLEAN
- CA_ALIGN_CMPLX128
- CA_ALIGN_CMPLX256
- CA_ALIGN_CMPLX64
- CA_ALIGN_FIXLEN
- CA_ALIGN_FLOAT128
- CA_ALIGN_FLOAT32
- CA_ALIGN_FLOAT64
- CA_ALIGN_INT16
- CA_ALIGN_INT32
- CA_ALIGN_INT64
- CA_ALIGN_INT8
- CA_ALIGN_OBJECT
- CA_ALIGN_VOIDP
- CA_BIG_ENDIAN
- CA_BOOLEAN
- CA_BYTE
- CA_CAST_TABLE
- CA_CMPLX128
- CA_CMPLX256
- CA_CMPLX64
- CA_COMPLEX
- CA_DCOMPLEX
- CA_DOUBLE
- CA_FIXLEN
– data types –
- CA_FLOAT
- CA_FLOAT128
- CA_FLOAT32
- CA_FLOAT64
- CA_INF
- CA_INT
- CA_INT16
- CA_INT32
- CA_INT64
- CA_INT8
- CA_LITTLE_ENDIAN
- CA_NAN
- CA_NIL
- CA_OBJECT
- CA_OBJ_ARRAY
- CA_OBJ_ARRAY_WRAP
- CA_OBJ_BITARRAY
- CA_OBJ_BITFIELD
- CA_OBJ_BLOCK
rb_cCABlock,
CA_OBJ_BLOCK
are defined in rb_carray.c- CA_OBJ_FAKE
- CA_OBJ_FARRAY
- CA_OBJ_FIELD
- CA_OBJ_GRID
- CA_OBJ_MAPPING
- CA_OBJ_OBJECT
- CA_OBJ_OBJECT_MASK
- CA_OBJ_REDUCE
- CA_OBJ_REFER
rb_cCARefer,
CA_OBJ_REFER
are defined in ruby_carray.c- CA_OBJ_REPEAT
rb_cCARepeat,
CA_OBJ_REPEAT
are defined in rb_carray.c- CA_OBJ_SCALAR
- CA_OBJ_SELECT
rb_cCASelect,
CA_OBJ_SELECT
are defined in rb_carray.c- CA_OBJ_SHIFT
- CA_OBJ_TRANSPOSE
- CA_OBJ_UNBOUND_REPEAT
rb_cCAUnboudRepeat,
CA_OBJ_UNBOUND_REPEAT
are defined in rb_carray.c- CA_OBJ_WINDOW
- CA_RANK_MAX
– system –
- CA_REG_ADDRESS
- CA_REG_ADDRESS_COMPLEX
- CA_REG_ALL
- CA_REG_ATTRIBUTE
- CA_REG_BLOCK
- CA_REG_FLATTEN
- CA_REG_GRID
- CA_REG_ITERATOR
- CA_REG_MAPPING
- CA_REG_MEMBER
- CA_REG_METHOD_CALL
- CA_REG_NONE
- CA_REG_POINT
- CA_REG_REPEAT
- CA_REG_SELECT
- CA_REG_UNBOUND_REPEAT
- CA_SHORT
- CA_SIZE
- CA_UINT16
- CA_UINT32
- CA_UINT64
- CA_UINT8
- CI
- CMPLX_TYPES
- CODETEXT
- DEFINITIONS
- EPSILON
- FIXLEN
- FIXLEN_TYPES
- FLOAT_TYPES
- HAVE_COMPLEX
- HEADERS
- INTEGER
- INT_TYPES
- METHODS
- NUMERIC
- OBJECT
- OBJ_TYPES
- POSSIBLE_PREFIX
- RUBY_VERSION_CODE
- TYPEINFO
Public Instance Methods
CA_FIXLEN(val, options = {})
click to toggle source
# File lib/carray/construct.rb, line 224 def CA_FIXLEN (val, options = {}) CArray.__new_fixlen__(options[:bytes], val) end
alias_op(op, name)
click to toggle source
# File ext/mkmath.rb, line 552 def alias_op (op, name) METHODS << %{ rb_define_alias(rb_cCArray, "#{op}", "#{name}"); } end
autoload_method(method, library)
click to toggle source
# File lib/carray/autoload.rb, line 11 def autoload_method (method, library) eval %{ def #{method} (*argv, &block) begin require "#{library}" rescue LoadError raise "error in autoloading '#{library}' hooked by method '#{method}', check gem installation." end #{method}(*argv, &block) end } end
bincmp(op, name, hash)
click to toggle source
# File ext/mkmath.rb, line 405 def bincmp (op, name, hash) io = StringIO.new io.puts io.puts "/*----------------------- #{name} --------------------------*/" hash.each do |types, expr0| if not expr0 next end expr0.gsub!(/#(\d)/, '*p\1') types.each do |type| if type expr = expr0.clone expr.gsub!(/<type>/, type) expr.gsub!(/<epsilon>/, EPSILON[type]||"") if type != "fixlen" omp_ok = ( type != "VALUE" ) ? 1 : 0 io.print %{ static void ca_bincmp_#{name}_#{type} (ca_size_t n, boolean8_t *m, char *ptr1, ca_size_t b1, ca_size_t i1, char *ptr2, ca_size_t b2, ca_size_t i2, char *ptr3, ca_size_t b3, ca_size_t i3) { #{type} *q1 = (#{type} *) ptr1, *q2 = (#{type} *) ptr2; #{type} *p1 = q1, *p2 = q2; boolean8_t *q3 = (boolean8_t *) ptr3; boolean8_t *p3 = q3; ca_size_t k; if ( m ) { boolean8_t *pm = m; #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(pm,p1,p2,p3) #endif for (k=0; k<n; k++) { pm = m + k; if ( ! *pm ) { p1 = q1 + k*i1; p2 = q2 + k*i2; p3 = q3 + k*i3; { #{expr} } } } } else { #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(p1,p2,p3) #endif for (k=0; k<n; k++) { p1=q1+k*i1; p2=q2+k*i2; p3=q3+k*i3; { #{expr} } } } } } else ### fixlen omp_ok = 1 io.print %{ static void ca_bincmp_#{name}_#{type} (ca_size_t n, boolean8_t *m, char *ptr1, ca_size_t b1, ca_size_t i1, char *ptr2, ca_size_t b2, ca_size_t i2, char *ptr3, ca_size_t b3, ca_size_t i3) { char *q1 = ptr1, *q2 = ptr2; char *p1 = q1, *p2 = q2; boolean8_t *q3 = (boolean8_t *) ptr3; boolean8_t *p3 = q3; ca_size_t s1 = b1*i1, s2 = b2*i2, s3 = b3*i3; ca_size_t k; if ( m ) { boolean8_t *pm = m; #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(pm,p1,p2,p3) #endif for (k=0; k<n; k++) { pm = m + k; if ( ! *pm ) { p1 = q1 + k*s1; p2 = q2 + k*s2; p3 = q3 + k*s3; { #{expr} } } } } else { #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(p1,p2,p3) #endif for (k=0; k<n; k++) { p1=q1+k*s1; p2=q2+k*s2; p3=q3+k*s3; { #{expr} } } } } } end end end end io.puts io.puts "ca_bincmp_func_t" io.puts "ca_bincmp_#{name}[CA_NTYPE] = {" ALL_TYPES.each_index do |i| type = nil hash.each do |types, expr| if not expr next end type ||= types[i] end if type io.puts(" ca_bincmp_#{name}_#{type},") else io.puts(" ca_bincmp_not_implement,") end end io.puts "};" io.puts io.print %{ static VALUE rb_ca_#{name} (VALUE self, VALUE other) { if ( ! rb_ca_test_castable(other) ) { return rb_ca_binop_pass_to_other(self, other, rb_intern("#{op}")); } return rb_ca_call_bincmp(self, other, ca_bincmp_#{name}); } } DEFINITIONS << io.string if op METHODS << %{ rb_define_method(rb_cCArray, "#{op}", rb_ca_#{name}, 1); } end end
binop(op, name, hash)
click to toggle source
# File ext/mkmath.rb, line 216 def binop (op, name, hash) io = StringIO.new io.puts io.puts "/*----------------------- #{name} --------------------------*/" hash.each do |types, expr0| if not expr0 next end expr0.gsub!(/#/, '*p') types.each do |type| if type expr = expr0.gsub(/<type>/, type) omp_ok = ( type != "VALUE" ) ? 1 : 0 io.print %{ static void ca_binop_#{name}_#{type} (ca_size_t n, boolean8_t *m, char *ptr1, ca_size_t i1, char *ptr2, ca_size_t i2, char *ptr3, ca_size_t i3) { #{type} *q1 = (#{type} *) ptr1, *q2 = (#{type} *) ptr2, *q3 = (#{type} *) ptr3; #{type} *p1 = q1, *p2 = q2, *p3 = q3; ca_size_t k; if ( m ) { boolean8_t *pm; #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(pm,p1,p2,p3) #endif for (k=0; k<n; k++) { pm = m + k; if ( ! *pm ) { p1 = q1 + k*i1; p2 = q2 + k*i2; p3 = q3 + k*i3; { #{expr} } } } } else { #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(p1,p2,p3) #endif for (k=0; k<n; k++) { p1 = q1 + k*i1; p2 = q2 + k*i2; p3 = q3 + k*i3; { #{expr} } } } } } end end end io.puts io.puts "ca_binop_func_t" io.puts "ca_binop_#{name}[CA_NTYPE] = {" ALL_TYPES.each_index do |i| type = nil hash.each do |types, expr| if not expr next end type ||= types[i] end if type io.puts(" ca_binop_#{name}_#{type},") else io.puts(" ca_binop_not_implement,") end end io.puts "};" io.puts io.print %{ static VALUE rb_ca_#{name} (VALUE self, VALUE other) { if ( ! rb_ca_test_castable(other) ) { return rb_ca_binop_pass_to_other(self, other, rb_intern("#{op}")); } return rb_ca_call_binop(self, other, ca_binop_#{name}); } static VALUE rb_ca_#{name}_bang (VALUE self, VALUE other) { return rb_ca_call_binop_bang(self, other, ca_binop_#{name}); } } DEFINITIONS << io.string if op METHODS << %{ rb_define_method(rb_cCArray, "#{op}", rb_ca_#{name}, 1); } end METHODS << %{ rb_define_method(rb_cCArray, "#{name}!", rb_ca_#{name}_bang, 1); } end
carray_version()
click to toggle source
# File ext/version.rb, line 13 def carray_version io = open(File.join(File.dirname(__FILE__), "version.h")) while line = io.gets case line when /^#define CA_VERSION (.*)$/ ca_version = $1.strip[1..-2] when /^#define CA_VERSION_CODE (.*)$/ ca_version_code = $1.to_i when /^#define CA_VERSION_MAJOR (.*)$/ ca_version_major = $1.to_i when /^#define CA_VERSION_MINOR (.*)$/ ca_version_minor = $1.to_i when /^#define CA_VERSION_TEENY (.*)$/ ca_version_teeny = $1.to_i when /^#define CA_VERSION_DATE (.*)$/ ca_version_date = $1.strip[1..-2] end end io.close ca_version2 = format("%i.%i.%i", ca_version_major, ca_version_minor, ca_version_teeny) ca_version_code2 = 100 * ca_version_major + 10*ca_version_minor + ca_version_teeny if ca_version != ca_version2 or ca_version_code != ca_version_code2 raise "invalid version.h" end return [ca_version, ca_version_date] end
check_fortran()
click to toggle source
# File lib/carray/mkmf.rb, line 51 def check_fortran SRC_EXT << "f" << "f90" << "f95" fortran = with_config("fortran", "gfortran") fflags = with_config("fflags", "") case fortran when /\Ag77/ libdir = File.dirname(`#{fortran} --print-file-name=libg2c.a`) dir_config("g2c", possible_includes, [libdir]+possible_libs) have_library("g2c") fc = fortran fflags << " -O2 -g " when /\Agfortran/ libdir = File.dirname(`#{fortran} --print-file-name=libgfortran.a`) dir_config("gfortran", possible_includes, [libdir]+possible_libs) have_library("gfortran") fc = fortran fflags << " -O2 -g -fPIC " when /\Aintel/, /\Aifort/, /\Aifc/ libdir = File.join(File.dirname(File.dirname(`which ifort`)), "lib") dir_config("ifcore", possible_includes, [libdir]+possible_libs) have_library("ifcore") have_library("ifport") have_library("imf") have_library("irc") have_library("svml") have_library("unwind") fc = "ifort" fflags << " -O2 -fPIC " when /\Afujitsu/, /\Afrt/ libdir = File.join(File.dirname(File.dirname(`which frt`)), "lib") dir_config("fj9f6", nil, libdir) $LIBS = " -lfj9i6 -lfj9f6" fc = "frt" fflags = " -O -fw " else puts "unknown fortran option <#{fortran}>" exit(1) end at_exit { if File.file?("Makefile") makefile = File.read("Makefile") unless makefile =~ /^FC=/ makefile.sub!(/^COPY =.*$/, '\0' + "\n\n" + "FC=#{fc}\n" + "FFLAGS=#{fflags}\n") end open("Makefile", "w") { |io| io.write(makefile) } end } return "--with-fortran='#{fortran}' --with-fflags='#{fflags}'" end
create_code(name, filename)
click to toggle source
# File ext/mkmath.rb, line 731 def create_code (name, filename) code = CODETEXT.clone code.sub!("<name>", name) code.sub!("<headers>", HEADERS) code.sub!("<definitions>", DEFINITIONS) code.sub!("<methods>", METHODS) open(filename, "w") { |io| io.write code } end
create_header(header = "extconf.h")
click to toggle source
from mkmf.rb
# File ext/extconf.rb, line 13 def create_header(header = "extconf.h") message "creating %s\n", header sym = header.tr("a-z./\055", "A-Z___") hdr = ["#ifndef #{sym}\n#define #{sym}\n"] for line in $defs case line when /^-D(SIZEOF_[^=]+)(?:=(.*))?/ hdr << "#ifndef #$1\n#define #$1 #{$2 ? Shellwords.shellwords($2)[0].gsub(/(?=\t+)/, "\ \\n") : 1}\n#endif\n" when /^-D([^=]+)(?:=(.*))?/ hdr << "#define #$1 #{$2 ? Shellwords.shellwords($2)[0].gsub(/(?=\t+)/, "\ \\n") : 1}\n" when /^-U(.*)/ hdr << "#undef #$1\n" end end hdr << "#endif\n" hdr = hdr.join unless (IO.read(header) == hdr rescue false) open(header, "wb") do |hfile| hfile.write(hdr) end end $extconf_h = header end
have_carray()
click to toggle source
# File lib/carray/mkmf.rb, line 13 def have_carray begin require 'carray' rescue LoadError abort "Ruby/CArray is not installed" end $LOAD_PATH.each do |path| if File.exist? File.join(path, 'carray.h') dir_config("carray", path, path) break end end =begin dir_config("carray", $sitearchdir, $sitearchdir) if defined? Gem if Gem::VERSION >= "1.7.0" begin Gem::Specification.find_all_by_name("carray").each do |spec| dir = spec.full_gem_path dir_config("carray", dir, dir) end rescue Gem::LoadError end else Gem.all_load_paths.grep(/narray/).each do |dir| dir_config("carray", dir, dir) end end end =end status = true status &= have_header("carray.h") if /cygwin|mingw/ =~ RUBY_PLATFORM status &= have_library("carray") end status end
macro_expand(text, values)
click to toggle source
# File ext/carray_stat_proc.rb, line 24 def macro_expand (text, values) text = text.clone values.each do |key, val| text.gsub!("<"+key+">", val) end return text end
moncmp(op, name, hash)
click to toggle source
# File ext/mkmath.rb, line 313 def moncmp (op, name, hash) io = StringIO.new io.puts io.puts "/*----------------------- #{name} --------------------------*/" hash.each do |types, expr0| if not expr0 next end expr0.gsub!(/#/, '*p') types.each do |type| if type expr = expr0.gsub(/<type>/, type) omp_ok = ( type != "VALUE" ) ? 1 : 0 io.print %{ static void ca_moncmp_#{name}_#{type} (ca_size_t n, boolean8_t *m, char *ptr1, ca_size_t i1, boolean8_t *ptr2, ca_size_t i2) { #{type} *q1 = (#{type} *) ptr1; #{type} *p1 = q1; boolean8_t *q2 = (boolean8_t *) ptr2; boolean8_t *p2 = q2; ca_size_t k; if ( m ) { boolean8_t *pm = m; #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(pm,p1,p2) #endif for (k=0; k<n; k++) { pm = m + k; if ( ! *pm ) { p1 = q1 + k*i1; p2 = q2 + k*i2; { #{expr} } } } } else { #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(p1,p2) #endif for (k=0; k<n; k++) { p1=q1+k*i1; p2=q2+k*i2; { #{expr} } } } } } end end end io.puts io.puts "ca_moncmp_func_t" io.puts "ca_moncmp_#{name}[CA_NTYPE] = {" ALL_TYPES.each_index do |i| type = nil hash.each do |types, expr| if not expr next end type ||= types[i] end if type io.puts(" ca_moncmp_#{name}_#{type},") else io.puts(" ca_moncmp_not_implement,") end end io.puts "};" io.puts io.print %{ static VALUE rb_ca_#{name} (VALUE self) { return rb_ca_call_moncmp(self, ca_moncmp_#{name}); } } DEFINITIONS << io.string if op METHODS << %{ rb_define_method(rb_cCArray, "#{op}", rb_ca_#{name}, 0); } end end
monfunc(op, name, hash)
click to toggle source
# File ext/mkmath.rb, line 15 def monfunc (op, name, hash) io = StringIO.new io.puts io.puts "/*----------------------- #{name} --------------------------*/" hash.each do |types, expr0| if not expr0 next end expr0.gsub!(/#/, '*p') types.each do |type| if type expr = expr0.gsub(/<type>/, type) omp_ok = ( type != "VALUE" ) ? 1 : 0 io.print %{ static void ca_monop_#{name}_#{type} (ca_size_t n, boolean8_t *m, char *ptr1, ca_size_t i1, char *ptr2, ca_size_t i2) { #{type} *q1 = (#{type} *) ptr1, *q2 = (#{type} *) ptr2; #{type} *p1 = q1, *p2 = q2; ca_size_t k; if ( m ) { boolean8_t *pm; #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(pm,p1,p2) #endif for (k=0; k<n; k++) { pm = m + k; if ( ! *pm ) { p1 = q1 + k*i1; p2 = q2 + k*i2; { #{expr} } } } } else { #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(p1,p2) #endif for (k=0; k<n; k++) { p1 = q1 + k*i1; p2 = q2 + k*i2; { #{expr} } } } } } end end end io.puts io.puts "ca_monop_func_t" io.puts "ca_monop_#{name}[CA_NTYPE] = {" ALL_TYPES.each_index do |i| type = nil hash.each do |types, expr| if not expr next end type ||= types[i] end if type io.puts(" ca_monop_#{name}_#{type},") else io.puts(" ca_monop_not_implement,") end end io.puts "};" io.puts if hash.has_key?(INT_TYPES) or hash.has_key?(ALL_TYPES) io.print %{ static VALUE rb_ca_#{name} (VALUE self) { return rb_ca_call_monop(self, ca_monop_#{name}); } } else io.print %{ static VALUE rb_ca_#{name} (VALUE self) { if ( rb_ca_is_integer_type(self) ) { self = rb_ca_wrap_readonly(self, INT2NUM(CA_FLOAT64)); } return rb_ca_call_monop(self, ca_monop_#{name}); } } end io.print %{ static VALUE rb_ca_#{name}_bang (VALUE self) { return rb_ca_call_monop_bang(self, ca_monop_#{name}); } } DEFINITIONS << io.string if op METHODS << %{ rb_define_method(rb_cCArray, "#{op}", rb_ca_#{name}, 0); } end METHODS << %{ rb_define_method(rb_cCArray, "#{name}!", rb_ca_#{name}_bang, 0); } DEFINITIONS << %{ static VALUE rb_cmath_#{name} (VALUE mod, VALUE arg) { return ca_math_call(mod, arg, rb_intern("#{name}")); } } METHODS << %{ rb_define_module_function(rb_mCAMath, "#{name}", rb_cmath_#{name}, 1); } end
monop(op, name, hash)
click to toggle source
# File ext/mkmath.rb, line 126 def monop (op, name, hash) io = StringIO.new io.puts io.puts "/*----------------------- #{name} --------------------------*/" hash.each do |types, expr0| if not expr0 next end expr0.gsub!(/#/, '*p') types.each do |type| if type expr = expr0.gsub(/<type>/, type) omp_ok = ( type != "VALUE" ) ? 1 : 0 io.print %{ static void ca_monop_#{name}_#{type} (ca_size_t n, boolean8_t *m, char *ptr1, ca_size_t i1, char *ptr2, ca_size_t i2) { #{type} *q1 = (#{type} *) ptr1, *q2 = (#{type} *) ptr2; #{type} *p1 = q1, *p2 = q2; ca_size_t k; if ( m ) { boolean8_t *pm; #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(pm,p1,p2) #endif for (k=0; k<n; k++) { pm = m + k; if ( ! *pm ) { p1 = q1 + k*i1; p2 = q2 + k*i2; { #{expr} } } } } else { #if defined(_OPENMP) && #{omp_ok} #pragma omp parallel for private(p1,p2) #endif for (k=0; k<n; k++) { p1 = q1 + k*i1; p2 = q2 + k*i2; { #{expr} } } } } } end end end io.puts io.puts "ca_monop_func_t" io.puts "ca_monop_#{name}[CA_NTYPE] = {" ALL_TYPES.each_index do |i| type = nil hash.each do |types, expr| if not expr next end type ||= types[i] end if type io.puts(" ca_monop_#{name}_#{type},") else io.puts(" ca_monop_not_implement,") end end io.puts "};" io.puts io.print %{ static VALUE rb_ca_#{name} (VALUE self) { return rb_ca_call_monop(self, ca_monop_#{name}); } static VALUE rb_ca_#{name}_bang (VALUE self) { return rb_ca_call_monop_bang(self, ca_monop_#{name}); } } DEFINITIONS << io.string if op METHODS << %{ rb_define_method(rb_cCArray, "#{op}", rb_ca_#{name}, 0); } end METHODS << %{ rb_define_method(rb_cCArray, "#{name}!", rb_ca_#{name}_bang, 0); } end
nan()
click to toggle source
monkey patch
# File lib/carray/basic.rb, line 19 def nan 0.0/0.0 end
possible_includes(*postfixes)
click to toggle source
# File lib/carray/mkmf.rb, line 143 def possible_includes (*postfixes) dirs = possible_prefix().map{|prefix| File.join(prefix, "include") } if postfixes dirs = postfixes.inject(dirs) { |list, postfix| list + dirs.map{|d| File.join(d, postfix) } } end return dirs.select{|d| File.directory?(d)} end
possible_libs(*postfixes)
click to toggle source
# File lib/carray/mkmf.rb, line 133 def possible_libs (*postfixes) dirs = possible_prefix().map{|prefix| File.join(prefix, "lib") } if postfixes dirs = postfixes.inject(dirs) { |list, postfix| list + dirs.map{|d| File.join(d, postfix) } } end return dirs.select{|d| File.directory?(d)} end
possible_prefix(*postfixes)
click to toggle source
# File lib/carray/mkmf.rb, line 109 def possible_prefix (*postfixes) dirs = [ File.expand_path("~/usr"), ### user's home / usr File.expand_path("~/local"), ### user's home / local File.expand_path("~"), ### user's home "/opt/local", ### MacPorts "/opt", ### UNIX "/sw/local", ### Mac Fink "/sw/", ### Mac Fink "/usr/X11R6", ### UNIX X11 "/usr/local", ### UNIX "/usr", ### UNIX "/" ### UNIX ] if postfixes dirs = postfixes.inject(dirs) { |list, postfix| list + dirs.map{|d| File.join(d, postfix) } } end return dirs.select{|d| File.directory?(d)} end
which(cmd)
click to toggle source
# File lib/carray/info.rb, line 85 def which (cmd) return ENV["PATH"].split(":").detect do |dir| filename = File.join(dir, cmd) File.executable?(filename) end end