spring 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ module Spring
2
+ module Commands
3
+ class Cucumber
4
+ def env(*)
5
+ "test"
6
+ end
7
+
8
+ def exec_name
9
+ "cucumber"
10
+ end
11
+ end
12
+
13
+ Spring.register_command "cucumber", Cucumber.new
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ module Spring
2
+ module Commands
3
+ class Rails
4
+ def call
5
+ ARGV.unshift command_name
6
+ Object.const_set(:APP_PATH, ::Rails.root.join('config/application'))
7
+ require "rails/commands"
8
+ end
9
+
10
+ def description
11
+ nil
12
+ end
13
+ end
14
+
15
+ class RailsConsole < Rails
16
+ def env(args)
17
+ args.first if args.first && !args.first.index("-")
18
+ end
19
+
20
+ def command_name
21
+ "console"
22
+ end
23
+ end
24
+
25
+ class RailsGenerate < Rails
26
+ def command_name
27
+ "generate"
28
+ end
29
+ end
30
+
31
+ class RailsRunner < Rails
32
+ def env(tail)
33
+ previous_option = nil
34
+ tail.reverse.each do |option|
35
+ case option
36
+ when /--environment=(\w+)/ then return $1
37
+ when '-e' then return previous_option
38
+ end
39
+ previous_option = option
40
+ end
41
+ nil
42
+ end
43
+
44
+ def command_name
45
+ "runner"
46
+ end
47
+ end
48
+
49
+ Spring.register_command "rails_console", RailsConsole.new
50
+ Spring.register_command "rails_generate", RailsGenerate.new
51
+ Spring.register_command "rails_runner", RailsRunner.new
52
+ end
53
+ end
@@ -0,0 +1,26 @@
1
+ module Spring
2
+ module Commands
3
+ class Rake
4
+ class << self
5
+ attr_accessor :environment_matchers
6
+ end
7
+
8
+ self.environment_matchers = {
9
+ /^(test|spec|cucumber)($|:)/ => "test"
10
+ }
11
+
12
+ def env(args)
13
+ self.class.environment_matchers.each do |matcher, environment|
14
+ return environment if matcher === args.first
15
+ end
16
+ nil
17
+ end
18
+
19
+ def exec_name
20
+ "rake"
21
+ end
22
+ end
23
+
24
+ Spring.register_command "rake", Rake.new
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ module Spring
2
+ module Commands
3
+ class RSpec
4
+ def env(*)
5
+ "test"
6
+ end
7
+
8
+ def exec_name
9
+ "rspec"
10
+ end
11
+ end
12
+
13
+ Spring.register_command "rspec", RSpec.new
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ module Spring
2
+ module Commands
3
+ class TestUnit
4
+ def env(*)
5
+ "test"
6
+ end
7
+
8
+ def call
9
+ $LOAD_PATH.unshift "test"
10
+ ARGV << "test" if ARGV.empty?
11
+ ARGV.each do |arg|
12
+ break if arg.start_with?("-")
13
+ require_test(File.expand_path(arg))
14
+ end
15
+ end
16
+
17
+ def require_test(path)
18
+ if File.directory?(path)
19
+ Dir[File.join path, "**", "*_test.rb"].each { |f| require f }
20
+ else
21
+ require path
22
+ end
23
+ end
24
+
25
+ def description
26
+ "Execute a Test::Unit test."
27
+ end
28
+ end
29
+
30
+ Spring.register_command "testunit", TestUnit.new
31
+ end
32
+ end
@@ -4,6 +4,10 @@ module Spring
4
4
  class << self
5
5
  attr_accessor :application_root
6
6
 
7
+ def gemfile
8
+ ENV['BUNDLE_GEMFILE'] || "Gemfile"
9
+ end
10
+
7
11
  def after_fork_callbacks
8
12
  @after_fork_callbacks ||= []
9
13
  end
@@ -27,7 +31,7 @@ module Spring
27
31
  private
28
32
 
29
33
  def find_project_root(current_dir = Pathname.new(Dir.pwd))
30
- if current_dir.join("Gemfile").exist?
34
+ if current_dir.join(gemfile).exist?
31
35
  current_dir
32
36
  elsif current_dir.root?
33
37
  raise UnknownProject.new(Dir.pwd)
@@ -6,7 +6,6 @@ require "spring/sid"
6
6
 
7
7
  module Spring
8
8
  IGNORE_SIGNALS = %w(INT QUIT)
9
- BINFILE = File.expand_path("../../../bin/spring", __FILE__)
10
9
 
11
10
  class Env
12
11
  attr_reader :root
@@ -0,0 +1,621 @@
1
+ # encoding: UTF-8
2
+
3
+ # ### WHY SPRING VENDORS A JSON LIBRARY ###
4
+ #
5
+ # Spring is designed to be able to run outside of bundler. Ruby has a
6
+ # built-in "json" library, which we could use. However if we require
7
+ # that, and somebody has a different (perhaps newer) version of the
8
+ # json *gem* in their Gemfile, it will never get used since we already
9
+ # required the older version of the json library from the stdlib.
10
+ # Therefore, we are vendoring a json library for our own use in order to
11
+ # not interfere.
12
+
13
+ module Spring
14
+ module JSON
15
+ def self.load(string)
16
+ string.force_encoding("utf-8")
17
+ OkJson.decode(string)
18
+ end
19
+
20
+ def self.dump(data)
21
+ OkJson.encode(data)
22
+ end
23
+ end
24
+ end
25
+
26
+ #
27
+ # Copyright 2011, 2012 Keith Rarick
28
+ #
29
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ # of this software and associated documentation files (the "Software"), to deal
31
+ # in the Software without restriction, including without limitation the rights
32
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ # copies of the Software, and to permit persons to whom the Software is
34
+ # furnished to do so, subject to the following conditions:
35
+ #
36
+ # The above copyright notice and this permission notice shall be included in
37
+ # all copies or substantial portions of the Software.
38
+ #
39
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
+ # THE SOFTWARE.
46
+
47
+ # See https://github.com/kr/okjson for updates.
48
+
49
+ require 'stringio'
50
+
51
+ # Some parts adapted from
52
+ # http://golang.org/src/pkg/json/decode.go and
53
+ # http://golang.org/src/pkg/utf8/utf8.go
54
+ module Spring
55
+ module OkJson
56
+ Upstream = '42'
57
+ extend self
58
+
59
+
60
+ # Decodes a json document in string s and
61
+ # returns the corresponding ruby value.
62
+ # String s must be valid UTF-8. If you have
63
+ # a string in some other encoding, convert
64
+ # it first.
65
+ #
66
+ # String values in the resulting structure
67
+ # will be UTF-8.
68
+ def decode(s)
69
+ ts = lex(s)
70
+ v, ts = textparse(ts)
71
+ if ts.length > 0
72
+ raise Error, 'trailing garbage'
73
+ end
74
+ v
75
+ end
76
+
77
+
78
+ # Encodes x into a json text. It may contain only
79
+ # Array, Hash, String, Numeric, true, false, nil.
80
+ # (Note, this list excludes Symbol.)
81
+ # X itself must be an Array or a Hash.
82
+ # No other value can be encoded, and an error will
83
+ # be raised if x contains any other value, such as
84
+ # Nan, Infinity, Symbol, and Proc, or if a Hash key
85
+ # is not a String.
86
+ # Strings contained in x must be valid UTF-8.
87
+ def encode(x)
88
+ case x
89
+ when Hash then objenc(x)
90
+ when Array then arrenc(x)
91
+ else
92
+ raise Error, 'root value must be an Array or a Hash'
93
+ end
94
+ end
95
+
96
+
97
+ def valenc(x)
98
+ case x
99
+ when Hash then objenc(x)
100
+ when Array then arrenc(x)
101
+ when String then strenc(x)
102
+ when Numeric then numenc(x)
103
+ when true then "true"
104
+ when false then "false"
105
+ when nil then "null"
106
+ else
107
+ raise Error, "cannot encode #{x.class}: #{x.inspect}"
108
+ end
109
+ end
110
+
111
+
112
+ private
113
+
114
+
115
+ # Parses a "json text" in the sense of RFC 4627.
116
+ # Returns the parsed value and any trailing tokens.
117
+ # Note: this is almost the same as valparse,
118
+ # except that it does not accept atomic values.
119
+ def textparse(ts)
120
+ if ts.length <= 0
121
+ raise Error, 'empty'
122
+ end
123
+
124
+ typ, _, val = ts[0]
125
+ case typ
126
+ when '{' then objparse(ts)
127
+ when '[' then arrparse(ts)
128
+ else
129
+ raise Error, "unexpected #{val.inspect}"
130
+ end
131
+ end
132
+
133
+
134
+ # Parses a "value" in the sense of RFC 4627.
135
+ # Returns the parsed value and any trailing tokens.
136
+ def valparse(ts)
137
+ if ts.length <= 0
138
+ raise Error, 'empty'
139
+ end
140
+
141
+ typ, _, val = ts[0]
142
+ case typ
143
+ when '{' then objparse(ts)
144
+ when '[' then arrparse(ts)
145
+ when :val,:str then [val, ts[1..-1]]
146
+ else
147
+ raise Error, "unexpected #{val.inspect}"
148
+ end
149
+ end
150
+
151
+
152
+ # Parses an "object" in the sense of RFC 4627.
153
+ # Returns the parsed value and any trailing tokens.
154
+ def objparse(ts)
155
+ ts = eat('{', ts)
156
+ obj = {}
157
+
158
+ if ts[0][0] == '}'
159
+ return obj, ts[1..-1]
160
+ end
161
+
162
+ k, v, ts = pairparse(ts)
163
+ obj[k] = v
164
+
165
+ if ts[0][0] == '}'
166
+ return obj, ts[1..-1]
167
+ end
168
+
169
+ loop do
170
+ ts = eat(',', ts)
171
+
172
+ k, v, ts = pairparse(ts)
173
+ obj[k] = v
174
+
175
+ if ts[0][0] == '}'
176
+ return obj, ts[1..-1]
177
+ end
178
+ end
179
+ end
180
+
181
+
182
+ # Parses a "member" in the sense of RFC 4627.
183
+ # Returns the parsed values and any trailing tokens.
184
+ def pairparse(ts)
185
+ (typ, _, k), ts = ts[0], ts[1..-1]
186
+ if typ != :str
187
+ raise Error, "unexpected #{k.inspect}"
188
+ end
189
+ ts = eat(':', ts)
190
+ v, ts = valparse(ts)
191
+ [k, v, ts]
192
+ end
193
+
194
+
195
+ # Parses an "array" in the sense of RFC 4627.
196
+ # Returns the parsed value and any trailing tokens.
197
+ def arrparse(ts)
198
+ ts = eat('[', ts)
199
+ arr = []
200
+
201
+ if ts[0][0] == ']'
202
+ return arr, ts[1..-1]
203
+ end
204
+
205
+ v, ts = valparse(ts)
206
+ arr << v
207
+
208
+ if ts[0][0] == ']'
209
+ return arr, ts[1..-1]
210
+ end
211
+
212
+ loop do
213
+ ts = eat(',', ts)
214
+
215
+ v, ts = valparse(ts)
216
+ arr << v
217
+
218
+ if ts[0][0] == ']'
219
+ return arr, ts[1..-1]
220
+ end
221
+ end
222
+ end
223
+
224
+
225
+ def eat(typ, ts)
226
+ if ts[0][0] != typ
227
+ raise Error, "expected #{typ} (got #{ts[0].inspect})"
228
+ end
229
+ ts[1..-1]
230
+ end
231
+
232
+
233
+ # Scans s and returns a list of json tokens,
234
+ # excluding white space (as defined in RFC 4627).
235
+ def lex(s)
236
+ ts = []
237
+ while s.length > 0
238
+ typ, lexeme, val = tok(s)
239
+ if typ == nil
240
+ raise Error, "invalid character at #{s[0,10].inspect}"
241
+ end
242
+ if typ != :space
243
+ ts << [typ, lexeme, val]
244
+ end
245
+ s = s[lexeme.length..-1]
246
+ end
247
+ ts
248
+ end
249
+
250
+
251
+ # Scans the first token in s and
252
+ # returns a 3-element list, or nil
253
+ # if s does not begin with a valid token.
254
+ #
255
+ # The first list element is one of
256
+ # '{', '}', ':', ',', '[', ']',
257
+ # :val, :str, and :space.
258
+ #
259
+ # The second element is the lexeme.
260
+ #
261
+ # The third element is the value of the
262
+ # token for :val and :str, otherwise
263
+ # it is the lexeme.
264
+ def tok(s)
265
+ case s[0]
266
+ when ?{ then ['{', s[0,1], s[0,1]]
267
+ when ?} then ['}', s[0,1], s[0,1]]
268
+ when ?: then [':', s[0,1], s[0,1]]
269
+ when ?, then [',', s[0,1], s[0,1]]
270
+ when ?[ then ['[', s[0,1], s[0,1]]
271
+ when ?] then [']', s[0,1], s[0,1]]
272
+ when ?n then nulltok(s)
273
+ when ?t then truetok(s)
274
+ when ?f then falsetok(s)
275
+ when ?" then strtok(s)
276
+ when Spc, ?\t, ?\n, ?\r then [:space, s[0,1], s[0,1]]
277
+ else
278
+ numtok(s)
279
+ end
280
+ end
281
+
282
+
283
+ def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
284
+ def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
285
+ def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
286
+
287
+
288
+ def numtok(s)
289
+ m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
290
+ if m && m.begin(0) == 0
291
+ if !m[2] && !m[3]
292
+ [:val, m[0], Integer(m[0])]
293
+ elsif m[2]
294
+ [:val, m[0], Float(m[0])]
295
+ else
296
+ [:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))]
297
+ end
298
+ else
299
+ []
300
+ end
301
+ end
302
+
303
+
304
+ def strtok(s)
305
+ m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s)
306
+ if ! m
307
+ raise Error, "invalid string literal at #{abbrev(s)}"
308
+ end
309
+ [:str, m[0], unquote(m[0])]
310
+ end
311
+
312
+
313
+ def abbrev(s)
314
+ t = s[0,10]
315
+ p = t['`']
316
+ t = t[0,p] if p
317
+ t = t + '...' if t.length < s.length
318
+ '`' + t + '`'
319
+ end
320
+
321
+
322
+ # Converts a quoted json string literal q into a UTF-8-encoded string.
323
+ # The rules are different than for Ruby, so we cannot use eval.
324
+ # Unquote will raise an error if q contains control characters.
325
+ def unquote(q)
326
+ q = q[1...-1]
327
+ a = q.dup # allocate a big enough string
328
+ # In ruby >= 1.9, a[w] is a codepoint, not a byte.
329
+ if rubydoesenc?
330
+ a.force_encoding('UTF-8')
331
+ end
332
+ r, w = 0, 0
333
+ while r < q.length
334
+ c = q[r]
335
+ if c == ?\\
336
+ r += 1
337
+ if r >= q.length
338
+ raise Error, "string literal ends with a \"\\\": \"#{q}\""
339
+ end
340
+
341
+ case q[r]
342
+ when ?",?\\,?/,?'
343
+ a[w] = q[r]
344
+ r += 1
345
+ w += 1
346
+ when ?b,?f,?n,?r,?t
347
+ a[w] = Unesc[q[r]]
348
+ r += 1
349
+ w += 1
350
+ when ?u
351
+ r += 1
352
+ uchar = begin
353
+ hexdec4(q[r,4])
354
+ rescue RuntimeError => e
355
+ raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}"
356
+ end
357
+ r += 4
358
+ if surrogate? uchar
359
+ if q.length >= r+6
360
+ uchar1 = hexdec4(q[r+2,4])
361
+ uchar = subst(uchar, uchar1)
362
+ if uchar != Ucharerr
363
+ # A valid pair; consume.
364
+ r += 6
365
+ end
366
+ end
367
+ end
368
+ if rubydoesenc?
369
+ a[w] = '' << uchar
370
+ w += 1
371
+ else
372
+ w += ucharenc(a, w, uchar)
373
+ end
374
+ else
375
+ raise Error, "invalid escape char #{q[r]} in \"#{q}\""
376
+ end
377
+ elsif c == ?" || c < Spc
378
+ raise Error, "invalid character in string literal \"#{q}\""
379
+ else
380
+ # Copy anything else byte-for-byte.
381
+ # Valid UTF-8 will remain valid UTF-8.
382
+ # Invalid UTF-8 will remain invalid UTF-8.
383
+ # In ruby >= 1.9, c is a codepoint, not a byte,
384
+ # in which case this is still what we want.
385
+ a[w] = c
386
+ r += 1
387
+ w += 1
388
+ end
389
+ end
390
+ a[0,w]
391
+ end
392
+
393
+
394
+ # Encodes unicode character u as UTF-8
395
+ # bytes in string a at position i.
396
+ # Returns the number of bytes written.
397
+ def ucharenc(a, i, u)
398
+ if u <= Uchar1max
399
+ a[i] = (u & 0xff).chr
400
+ 1
401
+ elsif u <= Uchar2max
402
+ a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
403
+ a[i+1] = (Utagx | (u&Umaskx)).chr
404
+ 2
405
+ elsif u <= Uchar3max
406
+ a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
407
+ a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
408
+ a[i+2] = (Utagx | (u&Umaskx)).chr
409
+ 3
410
+ else
411
+ a[i+0] = (Utag4 | ((u>>18)&0xff)).chr
412
+ a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr
413
+ a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr
414
+ a[i+3] = (Utagx | (u&Umaskx)).chr
415
+ 4
416
+ end
417
+ end
418
+
419
+
420
+ def hexdec4(s)
421
+ if s.length != 4
422
+ raise Error, 'short'
423
+ end
424
+ (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3])
425
+ end
426
+
427
+
428
+ def subst(u1, u2)
429
+ if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3
430
+ return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself
431
+ end
432
+ return Ucharerr
433
+ end
434
+
435
+
436
+ def surrogate?(u)
437
+ Usurr1 <= u && u < Usurr3
438
+ end
439
+
440
+
441
+ def nibble(c)
442
+ if ?0 <= c && c <= ?9 then c.ord - ?0.ord
443
+ elsif ?a <= c && c <= ?z then c.ord - ?a.ord + 10
444
+ elsif ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
445
+ else
446
+ raise Error, "invalid hex code #{c}"
447
+ end
448
+ end
449
+
450
+
451
+ def objenc(x)
452
+ '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
453
+ end
454
+
455
+
456
+ def arrenc(a)
457
+ '[' + a.map{|x| valenc(x)}.join(',') + ']'
458
+ end
459
+
460
+
461
+ def keyenc(k)
462
+ case k
463
+ when String then strenc(k)
464
+ else
465
+ raise Error, "Hash key is not a string: #{k.inspect}"
466
+ end
467
+ end
468
+
469
+
470
+ def strenc(s)
471
+ t = StringIO.new
472
+ t.putc(?")
473
+ r = 0
474
+
475
+ while r < s.length
476
+ case s[r]
477
+ when ?" then t.print('\\"')
478
+ when ?\\ then t.print('\\\\')
479
+ when ?\b then t.print('\\b')
480
+ when ?\f then t.print('\\f')
481
+ when ?\n then t.print('\\n')
482
+ when ?\r then t.print('\\r')
483
+ when ?\t then t.print('\\t')
484
+ else
485
+ c = s[r]
486
+ # In ruby >= 1.9, s[r] is a codepoint, not a byte.
487
+ if rubydoesenc?
488
+ begin
489
+ c.ord # will raise an error if c is invalid UTF-8
490
+ t.write(c)
491
+ rescue
492
+ t.write(Ustrerr)
493
+ end
494
+ elsif Spc <= c && c <= ?~
495
+ t.putc(c)
496
+ else
497
+ n = ucharcopy(t, s, r) # ensure valid UTF-8 output
498
+ r += n - 1 # r is incremented below
499
+ end
500
+ end
501
+ r += 1
502
+ end
503
+ t.putc(?")
504
+ t.string
505
+ end
506
+
507
+
508
+ def numenc(x)
509
+ if ((x.nan? || x.infinite?) rescue false)
510
+ raise Error, "Numeric cannot be represented: #{x}"
511
+ end
512
+ "#{x}"
513
+ end
514
+
515
+
516
+ # Copies the valid UTF-8 bytes of a single character
517
+ # from string s at position i to I/O object t, and
518
+ # returns the number of bytes copied.
519
+ # If no valid UTF-8 char exists at position i,
520
+ # ucharcopy writes Ustrerr and returns 1.
521
+ def ucharcopy(t, s, i)
522
+ n = s.length - i
523
+ raise Utf8Error if n < 1
524
+
525
+ c0 = s[i].ord
526
+
527
+ # 1-byte, 7-bit sequence?
528
+ if c0 < Utagx
529
+ t.putc(c0)
530
+ return 1
531
+ end
532
+
533
+ raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
534
+
535
+ raise Utf8Error if n < 2 # need continuation byte
536
+ c1 = s[i+1].ord
537
+ raise Utf8Error if c1 < Utagx || Utag2 <= c1
538
+
539
+ # 2-byte, 11-bit sequence?
540
+ if c0 < Utag3
541
+ raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
542
+ t.putc(c0)
543
+ t.putc(c1)
544
+ return 2
545
+ end
546
+
547
+ # need second continuation byte
548
+ raise Utf8Error if n < 3
549
+
550
+ c2 = s[i+2].ord
551
+ raise Utf8Error if c2 < Utagx || Utag2 <= c2
552
+
553
+ # 3-byte, 16-bit sequence?
554
+ if c0 < Utag4
555
+ u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
556
+ raise Utf8Error if u <= Uchar2max
557
+ t.putc(c0)
558
+ t.putc(c1)
559
+ t.putc(c2)
560
+ return 3
561
+ end
562
+
563
+ # need third continuation byte
564
+ raise Utf8Error if n < 4
565
+ c3 = s[i+3].ord
566
+ raise Utf8Error if c3 < Utagx || Utag2 <= c3
567
+
568
+ # 4-byte, 21-bit sequence?
569
+ if c0 < Utag5
570
+ u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
571
+ raise Utf8Error if u <= Uchar3max
572
+ t.putc(c0)
573
+ t.putc(c1)
574
+ t.putc(c2)
575
+ t.putc(c3)
576
+ return 4
577
+ end
578
+
579
+ raise Utf8Error
580
+ rescue Utf8Error
581
+ t.write(Ustrerr)
582
+ return 1
583
+ end
584
+
585
+
586
+ def rubydoesenc?
587
+ ::String.method_defined?(:force_encoding)
588
+ end
589
+
590
+
591
+ class Utf8Error < ::StandardError
592
+ end
593
+
594
+
595
+ class Error < ::StandardError
596
+ end
597
+
598
+
599
+ Utagx = 0b1000_0000
600
+ Utag2 = 0b1100_0000
601
+ Utag3 = 0b1110_0000
602
+ Utag4 = 0b1111_0000
603
+ Utag5 = 0b1111_1000
604
+ Umaskx = 0b0011_1111
605
+ Umask2 = 0b0001_1111
606
+ Umask3 = 0b0000_1111
607
+ Umask4 = 0b0000_0111
608
+ Uchar1max = (1<<7) - 1
609
+ Uchar2max = (1<<11) - 1
610
+ Uchar3max = (1<<16) - 1
611
+ Ucharerr = 0xFFFD # unicode "replacement char"
612
+ Ustrerr = "\xef\xbf\xbd" # unicode "replacement char"
613
+ Usurrself = 0x10000
614
+ Usurr1 = 0xd800
615
+ Usurr2 = 0xdc00
616
+ Usurr3 = 0xe000
617
+
618
+ Spc = ' '[0]
619
+ Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
620
+ end
621
+ end