From: Massimiliano Mirra Date: 2002-01-13T11:51:09+09:00 Subject: FileHandle (was: Re: Dir.entries have no home) On Sun, Jan 13, 2002 at 10:00:07AM +0900, Massimiliano Mirra wrote: > Some afterthoughts... > log = FileHandle.new('/home/joe', 'program.log') > > log.location => "/home/joe" > log.name => "program.log" > log.path => "/home/joe/program.log" > > log.location = '/home/joe/subdir' > > log.location => "/home/joe" > log.commit => true > log.location => "/home/joe/subdir" > > log.path = '/home/joe/otherdir/othername' > log.commit => true > > log.location => "/home/joe/otherdir" > log.name => "othername" > > log.location = '/file_in_root_dir' > log.commit => false > > log.location => "/home/joe/otherdir" Still talking to myself. LOL I sketched an implementation. This month's Ruby slogan for me is ``...makes it faster to code it than to talk about it.'' I apologize for the length. I didn't just upload somewhere and put a link in the RAA because I still consider this matter worthy of brainstorming. See the test at the end for an example of usage. Massimiliano require 'ftools' class FileHandle def initialize(*args) case args.size when 1 # Initialized with a path # path = args.shift location, name = File.dirname(path), File.basename(path) when 2 # Initialized with a location directory and a file name # location, name = args.shift, args.shift path = File.join(location, name) else raise ArgumentError end @stat = File.stat(path) @info = { :location => fill(location), :name => fill(name), :path => fill(path), :mode => fill(@stat.mode), :gid => fill(@stat.gid), :uid => fill(@stat.uid) } end def fill(with) { :old => with, :new => with } end private :fill def location=(new) @info[:location][:new] = new @info[:path][:new] = File.join(@info[:location][:new], @info[:name][:new]) end def name=(new) @info[:name][:new] = new @info[:path][:new] = File.join(@info[:location][:new], @info[:name][:new]) end def path=(new) @info[:path][:new] = new @info[:name][:new] = File.basename(@info[:path][:new]) @info[:location][:new] = File.dirname(@info[:path][:new]) end def method_missing(method_id, *args, &block) if @info.keys.include? method_id # Read from @info hash # which = args.shift || :old @info[method_id][which] elsif method_id.to_s =~ /(\w+)=/ and @info.keys.include?($1.intern) # Assign to new values in @info hash # @info[$1.intern][:new] = args.shift elsif @stat.respond_to? method_id # Act as a proxy for @stat # @stat.send(method_id, *args, &block) else super end end def commit @info.each do |what, entry| if entry[:old] != entry[:new] case what when :path File.mkpath location(:new) unless FileTest.exists? location(:new) File.move path(:old), path(:new) when :mode File.chmod mode(:new), path(:old) when :gid File.chown nil, gid(:new), path(:old) when :uid File.chown uid(:new), nil, path(:old) end entry[:old] = entry[:new] end end @stat = File.stat(@info[:path][:old]) end end if $0 == __FILE__ require 'Lapidary/TestCase' class TestFileHandle < Lapidary::TestCase def testLocationChangesPath home = ENV['HOME'] system("touch #{home}/testfile") Dir.mkdir("#{home}/testdir") unless FileTest.exists?("#{home}/testdir") h = FileHandle.new("#{home}/testfile") # can also be written as new(home, "test") assert_equal home, h.location assert_equal 'testfile', h.name assert_equal "#{home}/testfile", h.path h.location = "#{home}/testdir" h.commit assert_equal "#{home}/testdir", h.location assert_equal 'testfile', h.name assert_equal "#{home}/testdir/testfile", h.path end end require 'Lapidary/UI/Console/TestRunner' Lapidary::UI::Console::TestRunner.run(TestFileHandle) end