scratch – Blame information for rev 75

Subversion Repositories:
Rev:
Rev Author Line No. Line
75 office 1  
2 Pattern = require './Pattern'
3  
4 # A bunch of utility methods
5 #
6 class Utils
7  
8 @REGEX_LEFT_TRIM_BY_CHAR: {}
9 @REGEX_RIGHT_TRIM_BY_CHAR: {}
10 @REGEX_SPACES: /\s+/g
11 @REGEX_DIGITS: /^\d+$/
12 @REGEX_OCTAL: /[^0-7]/gi
13 @REGEX_HEXADECIMAL: /[^a-f0-9]/gi
14  
15 # Precompiled date pattern
16 @PATTERN_DATE: new Pattern '^'+
17 '(?<year>[0-9][0-9][0-9][0-9])'+
18 '-(?<month>[0-9][0-9]?)'+
19 '-(?<day>[0-9][0-9]?)'+
20 '(?:(?:[Tt]|[ \t]+)'+
21 '(?<hour>[0-9][0-9]?)'+
22 ':(?<minute>[0-9][0-9])'+
23 ':(?<second>[0-9][0-9])'+
24 '(?:\.(?<fraction>[0-9]*))?'+
25 '(?:[ \t]*(?<tz>Z|(?<tz_sign>[-+])(?<tz_hour>[0-9][0-9]?)'+
26 '(?::(?<tz_minute>[0-9][0-9]))?))?)?'+
27 '$', 'i'
28  
29 # Local timezone offset in ms
30 @LOCAL_TIMEZONE_OFFSET: new Date().getTimezoneOffset() * 60 * 1000
31  
32 # Trims the given string on both sides
33 #
34 # @param [String] str The string to trim
35 # @param [String] _char The character to use for trimming (default: '\\s')
36 #
37 # @return [String] A trimmed string
38 #
39 @trim: (str, _char = '\\s') ->
40 return str.trim()
41 regexLeft = @REGEX_LEFT_TRIM_BY_CHAR[_char]
42 unless regexLeft?
43 @REGEX_LEFT_TRIM_BY_CHAR[_char] = regexLeft = new RegExp '^'+_char+''+_char+'*'
44 regexLeft.lastIndex = 0
45 regexRight = @REGEX_RIGHT_TRIM_BY_CHAR[_char]
46 unless regexRight?
47 @REGEX_RIGHT_TRIM_BY_CHAR[_char] = regexRight = new RegExp _char+''+_char+'*$'
48 regexRight.lastIndex = 0
49 return str.replace(regexLeft, '').replace(regexRight, '')
50  
51  
52 # Trims the given string on the left side
53 #
54 # @param [String] str The string to trim
55 # @param [String] _char The character to use for trimming (default: '\\s')
56 #
57 # @return [String] A trimmed string
58 #
59 @ltrim: (str, _char = '\\s') ->
60 regexLeft = @REGEX_LEFT_TRIM_BY_CHAR[_char]
61 unless regexLeft?
62 @REGEX_LEFT_TRIM_BY_CHAR[_char] = regexLeft = new RegExp '^'+_char+''+_char+'*'
63 regexLeft.lastIndex = 0
64 return str.replace(regexLeft, '')
65  
66  
67 # Trims the given string on the right side
68 #
69 # @param [String] str The string to trim
70 # @param [String] _char The character to use for trimming (default: '\\s')
71 #
72 # @return [String] A trimmed string
73 #
74 @rtrim: (str, _char = '\\s') ->
75 regexRight = @REGEX_RIGHT_TRIM_BY_CHAR[_char]
76 unless regexRight?
77 @REGEX_RIGHT_TRIM_BY_CHAR[_char] = regexRight = new RegExp _char+''+_char+'*$'
78 regexRight.lastIndex = 0
79 return str.replace(regexRight, '')
80  
81  
82 # Checks if the given value is empty (null, undefined, empty string, string '0')
83 #
84 # @param [Object] value The value to check
85 #
86 # @return [Boolean] true if the value is empty
87 #
88 @isEmpty: (value) ->
89 return not(value) or value is '' or value is '0' or (value instanceof Array and value.length is 0)
90  
91  
92 # Counts the number of occurences of subString inside string
93 #
94 # @param [String] string The string where to count occurences
95 # @param [String] subString The subString to count
96 # @param [Integer] start The start index
97 # @param [Integer] length The string length until where to count
98 #
99 # @return [Integer] The number of occurences
100 #
101 @subStrCount: (string, subString, start, length) ->
102 c = 0
103  
104 string = '' + string
105 subString = '' + subString
106  
107 if start?
108 string = string[start..]
109 if length?
110 string = string[0...length]
111  
112 len = string.length
113 sublen = subString.length
114 for i in [0...len]
115 if subString is string[i...sublen]
116 c++
117 i += sublen - 1
118  
119 return c
120  
121  
122 # Returns true if input is only composed of digits
123 #
124 # @param [Object] input The value to test
125 #
126 # @return [Boolean] true if input is only composed of digits
127 #
128 @isDigits: (input) ->
129 @REGEX_DIGITS.lastIndex = 0
130 return @REGEX_DIGITS.test input
131  
132  
133 # Decode octal value
134 #
135 # @param [String] input The value to decode
136 #
137 # @return [Integer] The decoded value
138 #
139 @octDec: (input) ->
140 @REGEX_OCTAL.lastIndex = 0
141 return parseInt((input+'').replace(@REGEX_OCTAL, ''), 8)
142  
143  
144 # Decode hexadecimal value
145 #
146 # @param [String] input The value to decode
147 #
148 # @return [Integer] The decoded value
149 #
150 @hexDec: (input) ->
151 @REGEX_HEXADECIMAL.lastIndex = 0
152 input = @trim(input)
153 if (input+'')[0...2] is '0x' then input = (input+'')[2..]
154 return parseInt((input+'').replace(@REGEX_HEXADECIMAL, ''), 16)
155  
156  
157 # Get the UTF-8 character for the given code point.
158 #
159 # @param [Integer] c The unicode code point
160 #
161 # @return [String] The corresponding UTF-8 character
162 #
163 @utf8chr: (c) ->
164 ch = String.fromCharCode
165 if 0x80 > (c %= 0x200000)
166 return ch(c)
167 if 0x800 > c
168 return ch(0xC0 | c>>6) + ch(0x80 | c & 0x3F)
169 if 0x10000 > c
170 return ch(0xE0 | c>>12) + ch(0x80 | c>>6 & 0x3F) + ch(0x80 | c & 0x3F)
171  
172 return ch(0xF0 | c>>18) + ch(0x80 | c>>12 & 0x3F) + ch(0x80 | c>>6 & 0x3F) + ch(0x80 | c & 0x3F)
173  
174  
175 # Returns the boolean value equivalent to the given input
176 #
177 # @param [String|Object] input The input value
178 # @param [Boolean] strict If set to false, accept 'yes' and 'no' as boolean values
179 #
180 # @return [Boolean] the boolean value
181 #
182 @parseBoolean: (input, strict = true) ->
183 if typeof(input) is 'string'
184 lowerInput = input.toLowerCase()
185 if not strict
186 if lowerInput is 'no' then return false
187 if lowerInput is '0' then return false
188 if lowerInput is 'false' then return false
189 if lowerInput is '' then return false
190 return true
191 return !!input
192  
193  
194  
195 # Returns true if input is numeric
196 #
197 # @param [Object] input The value to test
198 #
199 # @return [Boolean] true if input is numeric
200 #
201 @isNumeric: (input) ->
202 @REGEX_SPACES.lastIndex = 0
203 return typeof(input) is 'number' or typeof(input) is 'string' and !isNaN(input) and input.replace(@REGEX_SPACES, '') isnt ''
204  
205  
206 # Returns a parsed date from the given string
207 #
208 # @param [String] str The date string to parse
209 #
210 # @return [Date] The parsed date or null if parsing failed
211 #
212 @stringToDate: (str) ->
213 unless str?.length
214 return null
215  
216 # Perform regular expression pattern
217 info = @PATTERN_DATE.exec str
218 unless info
219 return null
220  
221 # Extract year, month, day
222 year = parseInt info.year, 10
223 month = parseInt(info.month, 10) - 1 # In javascript, january is 0, february 1, etc...
224 day = parseInt info.day, 10
225  
226 # If no hour is given, return a date with day precision
227 unless info.hour?
228 date = new Date Date.UTC(year, month, day)
229 return date
230  
231 # Extract hour, minute, second
232 hour = parseInt info.hour, 10
233 minute = parseInt info.minute, 10
234 second = parseInt info.second, 10
235  
236 # Extract fraction, if given
237 if info.fraction?
238 fraction = info.fraction[0...3]
239 while fraction.length < 3
240 fraction += '0'
241 fraction = parseInt fraction, 10
242 else
243 fraction = 0
244  
245 # Compute timezone offset if given
246 if info.tz?
247 tz_hour = parseInt info.tz_hour, 10
248 if info.tz_minute?
249 tz_minute = parseInt info.tz_minute, 10
250 else
251 tz_minute = 0
252  
253 # Compute timezone delta in ms
254 tz_offset = (tz_hour * 60 + tz_minute) * 60000
255 if '-' is info.tz_sign
256 tz_offset *= -1
257  
258 # Compute date
259 date = new Date Date.UTC(year, month, day, hour, minute, second, fraction)
260 if tz_offset
261 date.setTime date.getTime() + tz_offset
262  
263 return date
264  
265  
266 # Repeats the given string a number of times
267 #
268 # @param [String] str The string to repeat
269 # @param [Integer] number The number of times to repeat the string
270 #
271 # @return [String] The repeated string
272 #
273 @strRepeat: (str, number) ->
274 res = ''
275 i = 0
276 while i < number
277 res += str
278 i++
279 return res
280  
281  
282 # Reads the data from the given file path and returns the result as string
283 #
284 # @param [String] path The path to the file
285 # @param [Function] callback A callback to read file asynchronously (optional)
286 #
287 # @return [String] The resulting data as string
288 #
289 @getStringFromFile: (path, callback = null) ->
290 xhr = null
291 if window?
292 if window.XMLHttpRequest
293 xhr = new XMLHttpRequest()
294 else if window.ActiveXObject
295 for name in ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]
296 try
297 xhr = new ActiveXObject(name)
298  
299 if xhr?
300 # Browser
301 if callback?
302 # Async
303 xhr.onreadystatechange = ->
304 if xhr.readyState is 4
305 if xhr.status is 200 or xhr.status is 0
306 callback(xhr.responseText)
307 else
308 callback(null)
309 xhr.open 'GET', path, true
310 xhr.send null
311  
312 else
313 # Sync
314 xhr.open 'GET', path, false
315 xhr.send null
316  
317 if xhr.status is 200 or xhr.status == 0
318 return xhr.responseText
319  
320 return null
321 else
322 # Node.js-like
323 req = require
324 fs = req('fs') # Prevent browserify from trying to load 'fs' module
325 if callback?
326 # Async
327 fs.readFile path, (err, data) ->
328 if err
329 callback null
330 else
331 callback String(data)
332  
333 else
334 # Sync
335 data = fs.readFileSync path
336 if data?
337 return String(data)
338 return null
339  
340  
341  
342 module.exports = Utils