Chris@909
|
1 module CodeRay
|
Chris@909
|
2
|
Chris@909
|
3 # = FileType
|
Chris@909
|
4 #
|
Chris@909
|
5 # A simple filetype recognizer.
|
Chris@909
|
6 #
|
Chris@909
|
7 # == Usage
|
Chris@909
|
8 #
|
Chris@909
|
9 # # determine the type of the given
|
Chris@909
|
10 # lang = FileType[file_name]
|
Chris@909
|
11 #
|
Chris@909
|
12 # # return :text if the file type is unknown
|
Chris@909
|
13 # lang = FileType.fetch file_name, :text
|
Chris@909
|
14 #
|
Chris@909
|
15 # # try the shebang line, too
|
Chris@909
|
16 # lang = FileType.fetch file_name, :text, true
|
Chris@909
|
17 module FileType
|
Chris@909
|
18
|
Chris@909
|
19 UnknownFileType = Class.new Exception
|
Chris@909
|
20
|
Chris@909
|
21 class << self
|
Chris@909
|
22
|
Chris@909
|
23 # Try to determine the file type of the file.
|
Chris@909
|
24 #
|
Chris@909
|
25 # +filename+ is a relative or absolute path to a file.
|
Chris@909
|
26 #
|
Chris@909
|
27 # The file itself is only accessed when +read_shebang+ is set to true.
|
Chris@909
|
28 # That means you can get filetypes from files that don't exist.
|
Chris@909
|
29 def [] filename, read_shebang = false
|
Chris@909
|
30 name = File.basename filename
|
Chris@909
|
31 ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot
|
Chris@909
|
32 ext2 = filename.to_s[/\.(.*)/, 1] # from first dot
|
Chris@909
|
33
|
Chris@909
|
34 type =
|
Chris@909
|
35 TypeFromExt[ext] ||
|
Chris@909
|
36 TypeFromExt[ext.downcase] ||
|
Chris@909
|
37 (TypeFromExt[ext2] if ext2) ||
|
Chris@909
|
38 (TypeFromExt[ext2.downcase] if ext2) ||
|
Chris@909
|
39 TypeFromName[name] ||
|
Chris@909
|
40 TypeFromName[name.downcase]
|
Chris@909
|
41 type ||= shebang(filename) if read_shebang
|
Chris@909
|
42
|
Chris@909
|
43 type
|
Chris@909
|
44 end
|
Chris@909
|
45
|
Chris@909
|
46 # This works like Hash#fetch.
|
Chris@909
|
47 #
|
Chris@909
|
48 # If the filetype cannot be found, the +default+ value
|
Chris@909
|
49 # is returned.
|
Chris@909
|
50 def fetch filename, default = nil, read_shebang = false
|
Chris@909
|
51 if default && block_given?
|
Chris@909
|
52 warn 'Block supersedes default value argument; use either.'
|
Chris@909
|
53 end
|
Chris@909
|
54
|
Chris@909
|
55 if type = self[filename, read_shebang]
|
Chris@909
|
56 type
|
Chris@909
|
57 else
|
Chris@909
|
58 return yield if block_given?
|
Chris@909
|
59 return default if default
|
Chris@909
|
60 raise UnknownFileType, 'Could not determine type of %p.' % filename
|
Chris@909
|
61 end
|
Chris@909
|
62 end
|
Chris@909
|
63
|
Chris@909
|
64 protected
|
Chris@909
|
65
|
Chris@909
|
66 def shebang filename
|
Chris@909
|
67 return unless File.exist? filename
|
Chris@909
|
68 File.open filename, 'r' do |f|
|
Chris@909
|
69 if first_line = f.gets
|
Chris@909
|
70 if type = first_line[TypeFromShebang]
|
Chris@909
|
71 type.to_sym
|
Chris@909
|
72 end
|
Chris@909
|
73 end
|
Chris@909
|
74 end
|
Chris@909
|
75 end
|
Chris@909
|
76
|
Chris@909
|
77 end
|
Chris@909
|
78
|
Chris@909
|
79 TypeFromExt = {
|
Chris@909
|
80 'c' => :c,
|
Chris@909
|
81 'cfc' => :xml,
|
Chris@909
|
82 'cfm' => :xml,
|
Chris@909
|
83 'clj' => :clojure,
|
Chris@909
|
84 'css' => :css,
|
Chris@909
|
85 'diff' => :diff,
|
Chris@909
|
86 'dpr' => :delphi,
|
Chris@909
|
87 'gemspec' => :ruby,
|
Chris@909
|
88 'groovy' => :groovy,
|
Chris@909
|
89 'gvy' => :groovy,
|
Chris@909
|
90 'h' => :c,
|
Chris@909
|
91 'haml' => :haml,
|
Chris@909
|
92 'htm' => :page,
|
Chris@909
|
93 'html' => :page,
|
Chris@909
|
94 'html.erb' => :erb,
|
Chris@909
|
95 'java' => :java,
|
Chris@909
|
96 'js' => :java_script,
|
Chris@909
|
97 'json' => :json,
|
Chris@909
|
98 'mab' => :ruby,
|
Chris@909
|
99 'pas' => :delphi,
|
Chris@909
|
100 'patch' => :diff,
|
Chris@909
|
101 'php' => :php,
|
Chris@909
|
102 'php3' => :php,
|
Chris@909
|
103 'php4' => :php,
|
Chris@909
|
104 'php5' => :php,
|
Chris@909
|
105 'prawn' => :ruby,
|
Chris@909
|
106 'py' => :python,
|
Chris@909
|
107 'py3' => :python,
|
Chris@909
|
108 'pyw' => :python,
|
Chris@909
|
109 'rake' => :ruby,
|
Chris@909
|
110 'raydebug' => :raydebug,
|
Chris@909
|
111 'rb' => :ruby,
|
Chris@909
|
112 'rbw' => :ruby,
|
Chris@909
|
113 'rhtml' => :erb,
|
Chris@909
|
114 'rjs' => :ruby,
|
Chris@909
|
115 'rpdf' => :ruby,
|
Chris@909
|
116 'ru' => :ruby,
|
Chris@909
|
117 'rxml' => :ruby,
|
Chris@909
|
118 # 'sch' => :scheme,
|
Chris@909
|
119 'sql' => :sql,
|
Chris@909
|
120 # 'ss' => :scheme,
|
Chris@909
|
121 'xhtml' => :page,
|
Chris@909
|
122 'xml' => :xml,
|
Chris@909
|
123 'yaml' => :yaml,
|
Chris@909
|
124 'yml' => :yaml,
|
Chris@909
|
125 }
|
Chris@909
|
126 for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu]
|
Chris@909
|
127 TypeFromExt[cpp_alias] = :cpp
|
Chris@909
|
128 end
|
Chris@909
|
129
|
Chris@909
|
130 TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/
|
Chris@909
|
131
|
Chris@909
|
132 TypeFromName = {
|
Chris@909
|
133 'Capfile' => :ruby,
|
Chris@909
|
134 'Rakefile' => :ruby,
|
Chris@909
|
135 'Rantfile' => :ruby,
|
Chris@909
|
136 'Gemfile' => :ruby,
|
Chris@909
|
137 }
|
Chris@909
|
138
|
Chris@909
|
139 end
|
Chris@909
|
140
|
Chris@909
|
141 end
|