scratch – Blame information for rev 125

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