2010-03-16 23:29:12 +03:00
|
|
|
#!/usr/bin/env ruby
|
2007-08-16 00:20:18 +04:00
|
|
|
module CodeRay
|
|
|
|
|
|
|
|
# = FileType
|
|
|
|
#
|
|
|
|
# A simple filetype recognizer.
|
|
|
|
#
|
|
|
|
# Copyright (c) 2006 by murphy (Kornelius Kalnbach) <murphy rubychan de>
|
|
|
|
#
|
|
|
|
# License:: LGPL / ask the author
|
|
|
|
# Version:: 0.1 (2005-09-01)
|
|
|
|
#
|
|
|
|
# == Documentation
|
|
|
|
#
|
|
|
|
# # determine the type of the given
|
|
|
|
# lang = FileType[ARGV.first]
|
|
|
|
#
|
|
|
|
# # return :plaintext if the file type is unknown
|
|
|
|
# lang = FileType.fetch ARGV.first, :plaintext
|
|
|
|
#
|
|
|
|
# # try the shebang line, too
|
|
|
|
# lang = FileType.fetch ARGV.first, :plaintext, true
|
|
|
|
module FileType
|
|
|
|
|
|
|
|
UnknownFileType = Class.new Exception
|
|
|
|
|
|
|
|
class << self
|
|
|
|
|
|
|
|
# Try to determine the file type of the file.
|
|
|
|
#
|
|
|
|
# +filename+ is a relative or absolute path to a file.
|
|
|
|
#
|
|
|
|
# The file itself is only accessed when +read_shebang+ is set to true.
|
|
|
|
# That means you can get filetypes from files that don't exist.
|
|
|
|
def [] filename, read_shebang = false
|
|
|
|
name = File.basename filename
|
2010-03-16 23:29:12 +03:00
|
|
|
ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot
|
|
|
|
ext2 = filename.to_s[/\.(.*)/, 1] # from first dot
|
2007-08-16 00:20:18 +04:00
|
|
|
|
|
|
|
type =
|
2009-11-20 18:50:06 +03:00
|
|
|
TypeFromExt[ext] ||
|
2007-08-16 00:20:18 +04:00
|
|
|
TypeFromExt[ext.downcase] ||
|
2010-03-16 23:29:12 +03:00
|
|
|
(TypeFromExt[ext2] if ext2) ||
|
|
|
|
(TypeFromExt[ext2.downcase] if ext2) ||
|
2007-08-16 00:20:18 +04:00
|
|
|
TypeFromName[name] ||
|
|
|
|
TypeFromName[name.downcase]
|
|
|
|
type ||= shebang(filename) if read_shebang
|
|
|
|
|
|
|
|
type
|
|
|
|
end
|
|
|
|
|
|
|
|
def shebang filename
|
|
|
|
begin
|
|
|
|
File.open filename, 'r' do |f|
|
2010-03-16 23:29:12 +03:00
|
|
|
if first_line = f.gets
|
|
|
|
if type = first_line[TypeFromShebang]
|
|
|
|
type.to_sym
|
|
|
|
end
|
|
|
|
end
|
2007-08-16 00:20:18 +04:00
|
|
|
end
|
|
|
|
rescue IOError
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# This works like Hash#fetch.
|
|
|
|
#
|
|
|
|
# If the filetype cannot be found, the +default+ value
|
|
|
|
# is returned.
|
|
|
|
def fetch filename, default = nil, read_shebang = false
|
|
|
|
if default and block_given?
|
|
|
|
warn 'block supersedes default value argument'
|
|
|
|
end
|
|
|
|
|
|
|
|
unless type = self[filename, read_shebang]
|
|
|
|
return yield if block_given?
|
|
|
|
return default if default
|
|
|
|
raise UnknownFileType, 'Could not determine type of %p.' % filename
|
|
|
|
end
|
|
|
|
type
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
TypeFromExt = {
|
|
|
|
'c' => :c,
|
2010-03-16 23:29:12 +03:00
|
|
|
'css' => :css,
|
|
|
|
'diff' => :diff,
|
|
|
|
'dpr' => :delphi,
|
|
|
|
'groovy' => :groovy,
|
|
|
|
'gvy' => :groovy,
|
2007-08-16 00:20:18 +04:00
|
|
|
'h' => :c,
|
|
|
|
'htm' => :html,
|
|
|
|
'html' => :html,
|
2010-03-16 23:29:12 +03:00
|
|
|
'html.erb' => :rhtml,
|
|
|
|
'java' => :java,
|
|
|
|
'js' => :java_script,
|
|
|
|
'json' => :json,
|
|
|
|
'mab' => :ruby,
|
|
|
|
'pas' => :delphi,
|
|
|
|
'patch' => :diff,
|
2008-01-16 23:45:13 +03:00
|
|
|
'php' => :php,
|
|
|
|
'php3' => :php,
|
|
|
|
'php4' => :php,
|
|
|
|
'php5' => :php,
|
2010-03-16 23:29:12 +03:00
|
|
|
'py' => :python,
|
|
|
|
'py3' => :python,
|
|
|
|
'pyw' => :python,
|
|
|
|
'rake' => :ruby,
|
2007-08-16 00:20:18 +04:00
|
|
|
'raydebug' => :debug,
|
2010-03-16 23:29:12 +03:00
|
|
|
'rb' => :ruby,
|
|
|
|
'rbw' => :ruby,
|
2007-08-16 00:20:18 +04:00
|
|
|
'rhtml' => :rhtml,
|
2010-03-16 23:29:12 +03:00
|
|
|
'rxml' => :ruby,
|
2009-11-20 18:50:06 +03:00
|
|
|
'sch' => :scheme,
|
2010-03-16 23:29:12 +03:00
|
|
|
'sql' => :sql,
|
|
|
|
'ss' => :scheme,
|
|
|
|
'xhtml' => :xhtml,
|
|
|
|
'xml' => :xml,
|
2007-08-16 00:20:18 +04:00
|
|
|
'yaml' => :yaml,
|
|
|
|
'yml' => :yaml,
|
|
|
|
}
|
2010-03-16 23:29:12 +03:00
|
|
|
for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu]
|
|
|
|
TypeFromExt[cpp_alias] = :cpp
|
|
|
|
end
|
2007-08-16 00:20:18 +04:00
|
|
|
|
|
|
|
TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/
|
|
|
|
|
|
|
|
TypeFromName = {
|
|
|
|
'Rakefile' => :ruby,
|
|
|
|
'Rantfile' => :ruby,
|
|
|
|
}
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
if $0 == __FILE__
|
|
|
|
$VERBOSE = true
|
2010-03-16 23:29:12 +03:00
|
|
|
eval DATA.read, nil, $0, __LINE__ + 4
|
2007-08-16 00:20:18 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
__END__
|
|
|
|
require 'test/unit'
|
|
|
|
|
2010-03-16 23:29:12 +03:00
|
|
|
class FileTypeTests < Test::Unit::TestCase
|
|
|
|
|
|
|
|
include CodeRay
|
|
|
|
|
2007-08-16 00:20:18 +04:00
|
|
|
def test_fetch
|
|
|
|
assert_raise FileType::UnknownFileType do
|
|
|
|
FileType.fetch ''
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_throws :not_found do
|
|
|
|
FileType.fetch '.' do
|
|
|
|
throw :not_found
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_equal :default, FileType.fetch('c', :default)
|
|
|
|
|
|
|
|
stderr, fake_stderr = $stderr, Object.new
|
|
|
|
$err = ''
|
|
|
|
def fake_stderr.write x
|
|
|
|
$err << x
|
|
|
|
end
|
|
|
|
$stderr = fake_stderr
|
|
|
|
FileType.fetch('c', :default) { }
|
|
|
|
assert_equal "block supersedes default value argument\n", $err
|
|
|
|
$stderr = stderr
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_ruby
|
|
|
|
assert_equal :ruby, FileType['test.rb']
|
2010-03-16 23:29:12 +03:00
|
|
|
assert_equal :ruby, FileType['test.java.rb']
|
|
|
|
assert_equal :java, FileType['test.rb.java']
|
2007-08-16 00:20:18 +04:00
|
|
|
assert_equal :ruby, FileType['C:\\Program Files\\x\\y\\c\\test.rbw']
|
|
|
|
assert_equal :ruby, FileType['/usr/bin/something/Rakefile']
|
|
|
|
assert_equal :ruby, FileType['~/myapp/gem/Rantfile']
|
|
|
|
assert_equal :ruby, FileType['./lib/tasks\repository.rake']
|
|
|
|
assert_not_equal :ruby, FileType['test_rb']
|
|
|
|
assert_not_equal :ruby, FileType['Makefile']
|
|
|
|
assert_not_equal :ruby, FileType['set.rb/set']
|
|
|
|
assert_not_equal :ruby, FileType['~/projects/blabla/rb']
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_c
|
|
|
|
assert_equal :c, FileType['test.c']
|
|
|
|
assert_equal :c, FileType['C:\\Program Files\\x\\y\\c\\test.h']
|
|
|
|
assert_not_equal :c, FileType['test_c']
|
|
|
|
assert_not_equal :c, FileType['Makefile']
|
|
|
|
assert_not_equal :c, FileType['set.h/set']
|
|
|
|
assert_not_equal :c, FileType['~/projects/blabla/c']
|
|
|
|
end
|
|
|
|
|
2010-03-16 23:29:12 +03:00
|
|
|
def test_cpp
|
|
|
|
assert_equal :cpp, FileType['test.c++']
|
|
|
|
assert_equal :cpp, FileType['test.cxx']
|
|
|
|
assert_equal :cpp, FileType['test.hh']
|
|
|
|
assert_equal :cpp, FileType['test.hpp']
|
|
|
|
assert_equal :cpp, FileType['test.cu']
|
|
|
|
assert_equal :cpp, FileType['test.C']
|
|
|
|
assert_not_equal :cpp, FileType['test.c']
|
|
|
|
assert_not_equal :cpp, FileType['test.h']
|
|
|
|
end
|
|
|
|
|
2007-08-16 00:20:18 +04:00
|
|
|
def test_html
|
|
|
|
assert_equal :html, FileType['test.htm']
|
|
|
|
assert_equal :xhtml, FileType['test.xhtml']
|
|
|
|
assert_equal :xhtml, FileType['test.html.xhtml']
|
|
|
|
assert_equal :rhtml, FileType['_form.rhtml']
|
2010-03-16 23:29:12 +03:00
|
|
|
assert_equal :rhtml, FileType['_form.html.erb']
|
2007-08-16 00:20:18 +04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_yaml
|
|
|
|
assert_equal :yaml, FileType['test.yml']
|
|
|
|
assert_equal :yaml, FileType['test.yaml']
|
|
|
|
assert_equal :yaml, FileType['my.html.yaml']
|
|
|
|
assert_not_equal :yaml, FileType['YAML']
|
|
|
|
end
|
|
|
|
|
2010-03-16 23:29:12 +03:00
|
|
|
def test_pathname
|
|
|
|
require 'pathname'
|
|
|
|
pn = Pathname.new 'test.rb'
|
|
|
|
assert_equal :ruby, FileType[pn]
|
|
|
|
dir = Pathname.new '/etc/var/blubb'
|
|
|
|
assert_equal :ruby, FileType[dir + pn]
|
|
|
|
assert_equal :cpp, FileType[dir + 'test.cpp']
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_no_shebang
|
2007-08-16 00:20:18 +04:00
|
|
|
dir = './test'
|
|
|
|
if File.directory? dir
|
|
|
|
Dir.chdir dir do
|
|
|
|
assert_equal :c, FileType['test.c']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2010-03-16 23:29:12 +03:00
|
|
|
|
|
|
|
def test_shebang_empty_file
|
|
|
|
require 'tmpdir'
|
|
|
|
tmpfile = File.join(Dir.tmpdir, 'bla')
|
|
|
|
File.open(tmpfile, 'w') { } # touch
|
|
|
|
assert_equal nil, FileType[tmpfile]
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_shebang
|
|
|
|
require 'tmpdir'
|
|
|
|
tmpfile = File.join(Dir.tmpdir, 'bla')
|
|
|
|
File.open(tmpfile, 'w') { |f| f.puts '#!/usr/bin/env ruby' }
|
|
|
|
assert_equal :ruby, FileType[tmpfile, true]
|
|
|
|
end
|
2007-08-16 00:20:18 +04:00
|
|
|
|
|
|
|
end
|