language_sniffer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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