Just for fun: symbolic chmod

I think Ruby’s chmod should operate symbolically as the command line
version does.

To that end, I’ve been playing around. (Yes, I do have a TV, but
nothing is on.)

Here’s some code. It only implements rwx on the righthand side so far.

I test it by calling the OS’s chmod, so your mileage may vary.

In fact, I’m unsure why the last test case is failing. (I added these
more or less randomly.) But given the ugly nature of test12, I’m not
really concerned much.

If you feel like it: Add, refactor, critique.

It’s a small thing, but I’d like to see this functionality added into
the core if Matz should see fit.



def sym2oct(init,str)
left = {“u” => 0700, “g” => 0070, “o” => 0007, “a” => 0777}
right = {“r” => 0444, “w” => 0222, “x” => 0111}
reg = /([ugoa]+)([±=])([rwx]+)/

cmds = str.split(",")
perm = init
cmds.each do |cmd|
match = cmd.match(reg)
junk,who,what,how = match.to_a
who = who.split(//).inject(num=0) {|num,b| num |= left[b]; num }
how = how.split(//).inject(num=0) {|num,b| num |= right[b]; num }
mask = who & how
case what
when “+”; perm = perm | mask
when “-”; perm = perm & ~mask
when “=”; perm = mask

if $0 == FILE

require “test/unit”

def try(str)
File.unlink(“file1”) if File.exist?(“file1”)
File.unlink(“file2”) if File.exist?(“file2”)
File.open(“file1”,“w”) { } # Create files
File.open(“file2”,“w”) { }
init = File.stat(“file1”).mode # Get initial perms (re umask)
perm = sym2oct(init,str)
File.chmod(perm,“file1”) # chmod file1 thru Ruby
system(“chmod #{str} file2”) # chmod file2 thru OS
trial = File.stat(“file1”).mode # and check results
actual = File.stat(“file2”).mode

class Tester < Test::Unit::TestCase

def test01; try(“a+w”); end
def test02; try(“a+rw”); end
def test03; try(“a-w”); end
def test04; try(“u+w”); end
def test05; try(“u-r”); end
def test06; try(“u-rx”); end
def test07; try(“g+rx”); end
def test08; try(“g-rw”); end
def test09; try(“a+w,g+r,o+x”); end
def test10; try(“ugo+w,a-w”); end
def test11; try(“a=rwx”); end
def test12; try(“g=rw,a+x,o-w”); end