Scott
Scott

Reputation: 694

string conversions and substrings in Ruby have me baffled

I am trying to learn ruby(1.8.7). I have programmed in php for some time and I consider myself proficient in that language. I have a book which I reference, and I have looked at many introductory ruby tutorials, but I cannot figure this out.

myFiles = ['/Users/', '/bin/bash', 'Phantom.file']
myFiles.each do |cFile|
  puts "File Name: #{cFile}"
  if File.exists?(cFile)
    puts "#{cFile} is a file"
    cFileStats = File.stat(cFile)
    puts cFileStats.inspect
    cFileMode = cFileStats.mode.to_s()
    puts "cFileMode Class: " + cFileMode.class.to_s()
    puts "length of string: " + cFileMode.length.to_s()
    printf("Mode: %o\n",  cFileMode)
    puts "User: " + cFileMode[3,1]
    puts "Group: " + cFileMode[4,1]
    puts "World: " + cFileMode[5,1]
  else
    puts "Could not find file: #{cFile}"    
  end
  puts
  puts
end

produces the following output:

File Name: /Users/
/Users/ is a file
#<File::Stat dev=0xe000004, ino=48876, mode=040755, nlink=6, uid=0, gid=80, rdev=0x0, size=204, blksize=4096, blocks=0, atime=Sun Sep 04 12:20:09 -0400 2011, mtime=Thu Sep 01 21:29:08 -0400 2011, ctime=Thu Sep 01 21:29:08 -0400 2011>
cFileMode Class: String
length of string: 5
Mode: 40755
User: 7
Group: 7
World: 


File Name: /bin/bash
/bin/bash is a file
#<File::Stat dev=0xe000004, ino=8672, mode=0100555, nlink=1, uid=0, gid=0, rdev=0x0, size=1371648, blksize=4096, blocks=1272, atime=Sun Sep 04 16:24:09 -0400 2011, mtime=Mon Jul 11 14:05:45 -0400 2011, ctime=Mon Jul 11 14:05:45 -0400 2011>
cFileMode Class: String
length of string: 5
Mode: 100555
User: 3
Group: 3
World: 


File Name: Phantom.file
Could not find file: Phantom.file

Wh is the string length different than expected? (Should be 5 for users, 6 for /bin/bash)? Why are the substrings not puling the correct characters. I understand World not being populated when referencing a 5 character string, but the offsets seem off, and in the case of /bin/bash 3 does not even appear in the string.

Thanks

Scott

Upvotes: 1

Views: 129

Answers (2)

Gazler
Gazler

Reputation: 84180

This is a nice one.

When a number is preceeded by a 0, it is represented as octal. What you are actually getting for bin/bash:

0100755 to decimal = 33261
"33261".length = 5

And for /Users:

040755 to decimal = 16877
"16877".length = 5

Add the following line:

puts cFileMode

And you will see the error.

to_s takes an argument which is the base. If you call to_s(8) then it should work.

cFileMode = cFileStats.mode.to_s(8)

EDIT

files = ['/home/', '/bin/bash', 'filetest.rb']
files.each do |file|
  puts "File Name: #{file}"
  if File.exists?(file)
    puts "#{file} is a file"
    file_stats = File.stat(file)
    puts file_stats.inspect
    file_mode = file_stats.mode.to_s(8)
    puts "cFileMode Class: #{file_mode.class}"
    p file_mode
    puts "length of string: #{file_mode.length}"
    printf("Mode: #{file_mode}")
    puts "User: #{file_mode[-3,1]}"
    puts "Group: #{file_mode[-2,1]}"
    puts "World: #{file_mode[-1,1]}"
  else
    puts "Could not find file: #{file}"    
  end
  puts
  puts
end

Upvotes: 3

Maur&#237;cio Linhares
Maur&#237;cio Linhares

Reputation: 40333

Instead of this:

puts "length of string: " + cFileMode.length.to_s()

What you want is this:

puts "length of string: #{cFile.length}"

Please do not use camel case for variables in Ruby, camel case is used on class names only, method and variable names should be written with underscores to separate multiple words.

It's also a good practice to avoid adding parameters to method calls that do not have parameters, so, instead of calling to_s() you should use to_s only.

Upvotes: 1

Related Questions