language_sniffer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,345 @@
1
+ require 'yaml'
2
+
3
+ module LanguageSniffer
4
+ # Language names that are recognizable by GitHub. Defined languages
5
+ # can be highlighted, searched and listed under the Top Languages page.
6
+ #
7
+ # Languages are defined in `lib/language_sniffer/languages.yml`.
8
+ class Language
9
+ @languages = []
10
+ @overrides = {}
11
+ @index = {}
12
+ @name_index = {}
13
+ @alias_index = {}
14
+ @extension_index = {}
15
+ @filename_index = {}
16
+
17
+ # Valid Languages types
18
+ TYPES = [:data, :markup, :programming]
19
+
20
+ # Internal: Test if extension maps to multiple Languages.
21
+ #
22
+ # Returns true or false.
23
+ def self.ambiguous?(extension)
24
+ @overrides.include?(extension)
25
+ end
26
+
27
+ # Include?: Return overridden extensions.
28
+ #
29
+ # Returns extensions Array.
30
+ def self.overridden_extensions
31
+ @overrides.keys
32
+ end
33
+
34
+ # Internal: Create a new Language object
35
+ #
36
+ # attributes - A hash of attributes
37
+ #
38
+ # Returns a Language object
39
+ def self.create(attributes = {})
40
+ language = new(attributes)
41
+
42
+ @languages << language
43
+
44
+ # All Language names should be unique. Warn if there is a duplicate.
45
+ if @name_index.key?(language.name)
46
+ warn "Duplicate language name: #{language.name}"
47
+ end
48
+
49
+ # Language name index
50
+ @index[language.name] = @name_index[language.name] = language
51
+
52
+ language.aliases.each do |name|
53
+ # All Language aliases should be unique. Warn if there is a duplicate.
54
+ if @alias_index.key?(name)
55
+ warn "Duplicate alias: #{name}"
56
+ end
57
+
58
+ @index[name] = @alias_index[name] = language
59
+ end
60
+
61
+ language.extensions.each do |extension|
62
+ if extension !~ /^\./
63
+ warn "Extension is missing a '.': #{extension.inspect}"
64
+ end
65
+
66
+ unless ambiguous?(extension)
67
+ # Index the extension with a leading ".": ".rb"
68
+ @extension_index[extension] = language
69
+
70
+ # Index the extension without a leading ".": "rb"
71
+ @extension_index[extension.sub(/^\./, '')] = language
72
+ end
73
+ end
74
+
75
+ language.overrides.each do |extension|
76
+ if extension !~ /^\./
77
+ warn "Extension is missing a '.': #{extension.inspect}"
78
+ end
79
+
80
+ @overrides[extension] = language
81
+ end
82
+
83
+ language.filenames.each do |filename|
84
+ @filename_index[filename] = language
85
+ end
86
+
87
+ language
88
+ end
89
+
90
+ # Public: Get all Languages
91
+ #
92
+ # Returns an Array of Languages
93
+ def self.all
94
+ @languages
95
+ end
96
+
97
+ # Public: Look up Language by its proper name.
98
+ #
99
+ # name - The String name of the Language
100
+ #
101
+ # Examples
102
+ #
103
+ # Language.find_by_name('Ruby')
104
+ # # => #<Language name="Ruby">
105
+ #
106
+ # Returns the Language or nil if none was found.
107
+ def self.find_by_name(name)
108
+ @name_index[name]
109
+ end
110
+
111
+ # Public: Look up Language by one of its aliases.
112
+ #
113
+ # name - A String alias of the Language
114
+ #
115
+ # Examples
116
+ #
117
+ # Language.find_by_alias('cpp')
118
+ # # => #<Language name="C++">
119
+ #
120
+ # Returns the Language or nil if none was found.
121
+ def self.find_by_alias(name)
122
+ @alias_index[name]
123
+ end
124
+
125
+ # Public: Look up Language by extension.
126
+ #
127
+ # extension - The extension String. May include leading "."
128
+ #
129
+ # Examples
130
+ #
131
+ # Language.find_by_extension('.rb')
132
+ # # => #<Language name="Ruby">
133
+ #
134
+ # Returns the Language or nil if none was found.
135
+ def self.find_by_extension(extension)
136
+ @extension_index[extension]
137
+ end
138
+
139
+ # Public: Look up Language by filename.
140
+ #
141
+ # filename - The path String.
142
+ #
143
+ # Examples
144
+ #
145
+ # Language.find_by_filename('foo.rb')
146
+ # # => #<Language name="Ruby">
147
+ #
148
+ # Returns the Language or nil if none was found.
149
+ def self.find_by_filename(filename)
150
+ basename, extname = File.basename(filename), File.extname(filename)
151
+ @filename_index[basename] || @extension_index[extname]
152
+ end
153
+
154
+ # Public: Look up Language by its name.
155
+ #
156
+ # name - The String name of the Language
157
+ #
158
+ # Examples
159
+ #
160
+ # Language['Ruby']
161
+ # # => #<Language name="Ruby">
162
+ #
163
+ # Language['ruby']
164
+ # # => #<Language name="Ruby">
165
+ #
166
+ # Returns the Language or nil if none was found.
167
+ def self.[](name)
168
+ @index[name]
169
+ end
170
+
171
+ # Internal: Initialize a new Language
172
+ #
173
+ # attributes - A hash of attributes
174
+ def initialize(attributes = {})
175
+ # @name is required
176
+ @name = attributes[:name] || raise(ArgumentError, "missing name")
177
+
178
+ # Set type
179
+ @type = attributes[:type] ? attributes[:type].to_sym : nil
180
+
181
+ # Set aliases
182
+ @aliases = [default_alias_name] + (attributes[:aliases] || [])
183
+
184
+ # Set pygments lexer
185
+ @lexer = attributes[:lexer] || name
186
+
187
+ # Set legacy search term
188
+ @search_term = attributes[:search_term] || default_alias_name
189
+
190
+ # Set extensions or default to [].
191
+ @extensions = attributes[:extensions] || []
192
+ @overrides = attributes[:overrides] || []
193
+ @filenames = attributes[:filenames] || []
194
+
195
+ @primary_extension = attributes[:primary_extension] || default_primary_extension || extensions.first
196
+
197
+ # Prepend primary extension unless its already included
198
+ if primary_extension && !extensions.include?(primary_extension)
199
+ @extensions = [primary_extension] + extensions
200
+ end
201
+
202
+ # If group name is set, save the name so we can lazy load it later
203
+ if attributes[:group_name]
204
+ @group = nil
205
+ @group_name = attributes[:group_name]
206
+
207
+ # Otherwise we can set it to self now
208
+ else
209
+ @group = self
210
+ end
211
+ end
212
+
213
+ # Public: Get proper name
214
+ #
215
+ # Examples
216
+ #
217
+ # # => "Ruby"
218
+ # # => "Python"
219
+ # # => "Perl"
220
+ #
221
+ # Returns the name String
222
+ attr_reader :name
223
+
224
+ # Public: Get type.
225
+ #
226
+ # Returns a type Symbol or nil.
227
+ attr_reader :type
228
+
229
+ # Public: Get pygments lexer name.
230
+ #
231
+ # Returns a lexer name or nil.
232
+ attr_reader :lexer
233
+
234
+ # Public: Get aliases
235
+ #
236
+ # Examples
237
+ #
238
+ # Language['C++'].aliases
239
+ # # => ["cpp"]
240
+ #
241
+ # Returns an Array of String names
242
+ attr_reader :aliases
243
+
244
+ # Deprecated: Get code search term
245
+ #
246
+ # Examples
247
+ #
248
+ # # => "ruby"
249
+ # # => "python"
250
+ # # => "perl"
251
+ #
252
+ # Returns the name String
253
+ attr_reader :search_term
254
+
255
+ # Public: Get extensions
256
+ #
257
+ # Examples
258
+ #
259
+ # # => ['.rb', '.rake', ...]
260
+ #
261
+ # Returns the extensions Array
262
+ attr_reader :extensions
263
+
264
+ # Deprecated: Get primary extension
265
+ #
266
+ # Defaults to the first extension but can be overriden
267
+ # in the languages.yml.
268
+ #
269
+ # The primary extension can not be nil. Tests should verify this.
270
+ #
271
+ # This attribute is only used by app/helpers/gists_helper.rb for
272
+ # creating the language dropdown. It really should be using `name`
273
+ # instead. Would like to drop primary extension.
274
+ #
275
+ # Returns the extension String.
276
+ attr_reader :primary_extension
277
+
278
+ # Internal: Get overridden extensions.
279
+ #
280
+ # Returns the extensions Array.
281
+ attr_reader :overrides
282
+
283
+ # Public: Get filenames
284
+ #
285
+ # Examples
286
+ #
287
+ # # => ['Rakefile', ...]
288
+ #
289
+ # Returns the extensions Array
290
+ attr_reader :filenames
291
+
292
+ # Internal: Get default alias name
293
+ #
294
+ # Returns the alias name String
295
+ def default_alias_name
296
+ name.downcase.gsub(/\s/, '-')
297
+ end
298
+
299
+ # Internal: Get default primary extension.
300
+ #
301
+ # Returns the extension String.
302
+ def default_primary_extension
303
+ extensions.first
304
+ end
305
+
306
+ # Public: Get Language group
307
+ #
308
+ # Returns a Language
309
+ def group
310
+ @group ||= Language.find_by_name(@group_name)
311
+ end
312
+
313
+ # Public: Return name as String representation
314
+ def to_s
315
+ name
316
+ end
317
+
318
+ def ==(other)
319
+ eql?(other)
320
+ end
321
+
322
+ def eql?(other)
323
+ equal?(other)
324
+ end
325
+
326
+ def hash
327
+ name.hash
328
+ end
329
+ end
330
+
331
+ YAML.load_file(File.expand_path("../languages.yml", __FILE__)).each do |name, options|
332
+ Language.create(
333
+ :name => name,
334
+ :type => options['type'],
335
+ :aliases => options['aliases'],
336
+ :lexer => options['lexer'],
337
+ :group_name => options['group'],
338
+ :search_term => options['search_term'],
339
+ :extensions => options['extensions'],
340
+ :primary_extension => options['primary_extension'],
341
+ :overrides => options['overrides'],
342
+ :filenames => options['filenames']
343
+ )
344
+ end
345
+ end