2007年 10月 08日

URI::FILE Ruby / file: スキームと Pathname のあれそれ

なんかなにをしようとしていたか忘れた……ねむくなってきた。ついでにお腹痛い。Win 環境でもシームレスにつかえるようにするにはどうしたらいいのかなぁ。URI::File.path(path) を定義して URI 化とかかなぁ。でもあんま意味ない気がしてきた。

require "uri"
require "pathname"

# file scheme syntax:
#     file://<host>/<path>
class URI::FILE < URI::Generic
	DEFAULT_PORT = nil
	COMPONENT = [:scheme, :host, :path].freeze

	def self.build(args)
		tmp = Util::make_components_hash(self, args)
		super(tmp)
	end

	def initialize(*args)
		super(*args)
		@pathname = Pathname.new(@path)
		# delegate
		(@pathname.methods - self.methods).each do |m|
			instance_eval <<-EOS
				def #{m}(*args, &block)
					r = @pathname.__send__(:#{m}, *args, &block)
					if r.class == Pathname
						@path = r.to_s
						self
					else
						r
					end
				end
			EOS
		end
	end

	def to_s
		"#{scheme}://#{host}#{path}"
	end
	alias :to_str :to_s

	def set_path=(s)
		@pathname = Pathname.new(s)
		@path = s
	end

	def set_host(s)
		@host = s
		if !s.nil? && !s.empty?
			raise NotImplementedError, "Host is not supported"
		else
			@host = nil
		end
	end

	def check_host(s)
		if s.empty? || HOST =~ s
			true
		else
			raise InvalidComponentError, "bad component(expected host component): #{v}"
		end
	end

	@@schemes['FILE'] = URI::FILE
end

if $0 == __FILE__
	require "test/unit"

	class TC_URI_FILE < Test::Unit::TestCase
		def setup
		end

		def test_windows
			uri = URI("file:///c:/Windows")
			assert_equal nil, uri.host
			assert_equal nil,  uri.port
			assert_equal "/c:/Windows",  uri.path
			assert_equal "file", uri.scheme
			assert_equal "file:///c:/Windows",  uri.to_s

			uri = URI("file:///c:")
			assert_equal nil, uri.host
			assert_equal nil,  uri.port
			assert_equal "/c:",  uri.path
			assert_equal "file", uri.scheme
			assert_equal "file:///c:",  uri.to_s

			uri = URI("file:///c:/Documents%20and%20Settings/")
			assert_equal nil, uri.host
			assert_equal nil,  uri.port
			assert_equal "/c:/Documents%20and%20Settings/",  uri.path
			assert_equal "file", uri.scheme
			assert_equal "file:///c:/Documents%20and%20Settings/",  uri.to_s
		end

		def test_delegate
			uri = URI("file:///Users/cho45")
			assert_equal URI("file:///Users"), uri.parent
			assert_equal false, uri.root?

			uri = URI("file:///c:/Documents%20and%20Settings/cho45")
			assert_equal URI("file:///c:/Documents%20and%20Settings"), uri.parent
		end

		def test_inteface
			assert_equal URI("file:///path/to"), URI::FILE.build(["", "/path/to"])
			uri = URI("file:///Users/cho45")
			uri.path = "/hoge/hoge"
			assert_equal URI("file:///hoge/hoge"), uri

			uri = URI("file:///Users/cho45/tmp/")
			assert_equal URI("file:///Users/cho45/tmp/test"),  uri + "test"
		end

		def test_with_host
			assert_raise(NotImplementedError) do
				URI::FILE.build(["host", "/path/to"])
			end
			assert_raise(NotImplementedError) do
				uri = URI("file://host/Users/cho45")
			end
		end
	end
end