cheri 0.0.2

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.
Files changed (79) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README +98 -0
  3. data/Rakefile +121 -0
  4. data/examples/hello_world_1.rb +28 -0
  5. data/examples/table_1.rb +44 -0
  6. data/lib/cheri/awt.rb +41 -0
  7. data/lib/cheri/builder.rb +31 -0
  8. data/lib/cheri/builder/awt/connecter.rb +63 -0
  9. data/lib/cheri/builder/awt/constants.rb +1003 -0
  10. data/lib/cheri/builder/awt/main.rb +191 -0
  11. data/lib/cheri/builder/awt/types.rb +220 -0
  12. data/lib/cheri/builder/base.rb +533 -0
  13. data/lib/cheri/builder/config.rb +187 -0
  14. data/lib/cheri/builder/connecter.rb +386 -0
  15. data/lib/cheri/builder/context.rb +655 -0
  16. data/lib/cheri/builder/generator.rb +425 -0
  17. data/lib/cheri/builder/html/charsets.rb +154 -0
  18. data/lib/cheri/builder/html/common.rb +32 -0
  19. data/lib/cheri/builder/html/connecter.rb +57 -0
  20. data/lib/cheri/builder/html/element.rb +156 -0
  21. data/lib/cheri/builder/html/main.rb +116 -0
  22. data/lib/cheri/builder/html/types.rb +123 -0
  23. data/lib/cheri/builder/main.rb +483 -0
  24. data/lib/cheri/builder/swing/connecter.rb +141 -0
  25. data/lib/cheri/builder/swing/constants.rb +420 -0
  26. data/lib/cheri/builder/swing/main.rb +446 -0
  27. data/lib/cheri/builder/swing/types.rb +270 -0
  28. data/lib/cheri/builder/xml/charsets.rb +154 -0
  29. data/lib/cheri/builder/xml/common.rb +32 -0
  30. data/lib/cheri/builder/xml/connecter.rb +42 -0
  31. data/lib/cheri/builder/xml/element.rb +189 -0
  32. data/lib/cheri/builder/xml/main.rb +130 -0
  33. data/lib/cheri/builder/xml/types.rb +36 -0
  34. data/lib/cheri/cheri.rb +70 -0
  35. data/lib/cheri/cjx.rb +3 -0
  36. data/lib/cheri/explorer.rb +32 -0
  37. data/lib/cheri/explorer/explorer.rb +560 -0
  38. data/lib/cheri/html.rb +31 -0
  39. data/lib/cheri/image/Delete24.gif +0 -0
  40. data/lib/cheri/image/Find24.gif +0 -0
  41. data/lib/cheri/image/FindAgain24.gif +0 -0
  42. data/lib/cheri/image/Refresh24.gif +0 -0
  43. data/lib/cheri/image/Search24.gif +0 -0
  44. data/lib/cheri/image/Thumbs.db +0 -0
  45. data/lib/cheri/image/cheri_icon_16x16.png +0 -0
  46. data/lib/cheri/image/cheri_icon_24x24.png +0 -0
  47. data/lib/cheri/image/cheri_logo_medium.png +0 -0
  48. data/lib/cheri/image/close_10x10.png +0 -0
  49. data/lib/cheri/image/close_10x10s.png +0 -0
  50. data/lib/cheri/image/close_12x12.png +0 -0
  51. data/lib/cheri/image/close_14x14.png +0 -0
  52. data/lib/cheri/image/close_24x24.png +0 -0
  53. data/lib/cheri/image/close_dim2_12x12.png +0 -0
  54. data/lib/cheri/image/close_dim_12x12.png +0 -0
  55. data/lib/cheri/image/cls_tree.png +0 -0
  56. data/lib/cheri/image/con_tree.png +0 -0
  57. data/lib/cheri/image/jruby_14x16.png +0 -0
  58. data/lib/cheri/image/jruby_logo.png +0 -0
  59. data/lib/cheri/image/mod_tree.png +0 -0
  60. data/lib/cheri/image/obj_tree.png +0 -0
  61. data/lib/cheri/image/ruby_16x16.png +0 -0
  62. data/lib/cheri/image/vars_tree.png +0 -0
  63. data/lib/cheri/java.rb +26 -0
  64. data/lib/cheri/java/builder.rb +28 -0
  65. data/lib/cheri/java/builder/main.rb +407 -0
  66. data/lib/cheri/java/builder/util.rb +480 -0
  67. data/lib/cheri/java/java.rb +56 -0
  68. data/lib/cheri/jruby.rb +32 -0
  69. data/lib/cheri/jruby/explorer.rb +43 -0
  70. data/lib/cheri/jruby/explorer/common.rb +38 -0
  71. data/lib/cheri/jruby/explorer/dialogs.rb +383 -0
  72. data/lib/cheri/jruby/explorer/explorer.rb +904 -0
  73. data/lib/cheri/jruby/explorer/splash.rb +80 -0
  74. data/lib/cheri/jruby/explorer/viewer.rb +619 -0
  75. data/lib/cheri/jruby/explorer/viewers.rb +1057 -0
  76. data/lib/cheri/jruby/jruby.rb +59 -0
  77. data/lib/cheri/swing.rb +41 -0
  78. data/lib/cheri/xml.rb +31 -0
  79. metadata +135 -0
@@ -0,0 +1,655 @@
1
+ #--
2
+ # Copyright (C) 2007 William N Dortch <bill.dortch@gmail.com>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+ #
24
+
25
+ module Cheri
26
+ module Builder
27
+
28
+
29
+ # !!! TODO: class-level properties
30
+
31
+ class InstanceContext
32
+ # TODO: defined?Java pulls it in (same as require 'java' or include Java)
33
+ # not sure if anyone would object...
34
+ if (defined?Java) && (defined?JRUBY_VERSION) # JRuby 0.9.9 or later
35
+ Col = java.util.Collections
36
+ Map = java.util.WeakHashMap
37
+ end
38
+
39
+ # call-seq:
40
+ # InstanceContext.new(client,builder_modules) -> anInstanceContext
41
+ #
42
+ def initialize(client,cfg)
43
+ @c = client
44
+ @g = cfg
45
+
46
+ # TODO: find a better way to do this
47
+ if self.class.const_defined?("Map")
48
+ @h = Col.synchronized_map Map.new
49
+ @t = true # use Thread as key
50
+ else
51
+ # TODO: should use weak hash here
52
+ # TODO: threadsafe Ruby Hash implementation?
53
+ @h = {}
54
+ end
55
+ end
56
+
57
+ def client
58
+ @c
59
+ end
60
+
61
+ def cfg
62
+ @g
63
+ end
64
+
65
+ def auto
66
+ @u
67
+ end
68
+
69
+ def auto?(m)
70
+ @u && @u.include?(m)
71
+ end
72
+
73
+ def auto!(m)
74
+ raise BuilderException,"not an included builder module: #{m}" unless @g.include?(m)
75
+ if @u
76
+ @u << m unless @u.include?(m)
77
+ else
78
+ @u = [m]
79
+ end
80
+ end
81
+
82
+ def [](k)
83
+ @g[k]
84
+ end
85
+
86
+ def []=(k,v)
87
+ @g[k] = v
88
+ end
89
+
90
+ # call-seq:
91
+ # current -> context object for the current instance/thread
92
+ #
93
+ def current
94
+ key = @t ? Thread.current : Thread.current.__id__
95
+ @h[key] ||= Context.new(self,@c)
96
+ end
97
+
98
+ end #InstanceContext
99
+
100
+
101
+ class Context
102
+
103
+ # call-seq:
104
+ # Context.new(instance_context,client) -> aContext
105
+ #
106
+ #--
107
+ # Key to the cryptic instance variable names:
108
+ #
109
+ # @a - any? hash - active builders (on the stack) for which any? -> true
110
+ # @c - the client (normally instance of class that included Cheri builder modules)
111
+ # @f - reference to the factories in the class's Config instance
112
+ # @g - reference to the class's Config instance (all included Cheri builder modules)
113
+ # @p - configuration properties hash, used for various purposes
114
+ # @i - reference to the InstanceContext that created this Context
115
+ # @m - the ConnectionMinder for this context, tracks pending (prepared) connections
116
+ # @n - reference to the connecters in the class's Config instance
117
+ # @r - array of ConstantResolver instances, lazily initialized
118
+ # @s - the stack, holds active builders and builder frames
119
+ # @u - auto-factories array, lazily initialized
120
+ ##### TODO: REMOVE @v - flag used to prevent reentrant calls to #consume (aka #csm)
121
+ # @x - flag indicating whether instance_exec is supported, lazily initialized
122
+ #++
123
+ def initialize(ictx,client)
124
+ @i = ictx
125
+ cfg = @g = ictx.cfg
126
+ @f = cfg.factories
127
+ @n = cfg.connecters
128
+ if (u = ictx.auto)
129
+ @u = u.dup
130
+ end
131
+ @c = client
132
+ @m = ConnectionMinder.new
133
+ @s = [] # stack
134
+ @p = {} # configuration properties
135
+ end
136
+
137
+ def ictx
138
+ @i
139
+ end
140
+
141
+ def client
142
+ @c
143
+ end
144
+
145
+ def auto
146
+ # same mods or both nil
147
+ if (u = @u) == (iu = @i.auto)
148
+ return u
149
+ end
150
+ # TODO: save ref to iu to compare? otherwise we'll do this every time if
151
+ # thread-only auto is set for one mod and instance auto is set for another.
152
+ if iu
153
+ if u
154
+ u.concat(iu - u)
155
+ else
156
+ u = @u = iu.dup
157
+ end
158
+ end
159
+ u
160
+ end
161
+
162
+ def auto!(m)
163
+ raise BuilderException,"not an included builder module: #{m}" unless @g.include?(m)
164
+ (@u ||= []) << m unless @u && @u.include?(m)
165
+ end
166
+
167
+ # call-seq:
168
+ # ctx.run(builder) -> result of builder.run
169
+ #
170
+ # TODO: this description sucks, rewrite.
171
+ #
172
+ # Runs the specified builder. This method should be called if a builder was not created through
173
+ # the normal Cheri factory mechanism. This method should be called, rather than calling
174
+ # builder.run directly, to ensure that the builder's object gets properly connected.
175
+ def run(b)
176
+ # run the builder
177
+ res = b.run
178
+ # connect it's object
179
+ ctc(b)
180
+ res
181
+ end
182
+
183
+ # call-seq:
184
+ # ctx.send(sym, *args, &block) -> matched?, result
185
+ #
186
+ # Find and run a builder corresponding to +sym+. If no match is found, try
187
+ # to consume +sym+ as a method on the topmost object on the stack. No exception
188
+ # is raised by this method if a match is not found (contrast with #msend), but
189
+ # normally an exception _will_ subsequently be raised if this method returns to
190
+ # method_missing (the usual caller) empty-handed.
191
+ def send(sym,*r,&k)
192
+ raise Cheri.type_error(sym,Symbol) unless sym.instance_of?(Symbol)
193
+ # check args against pending connections (see note at ConnectionMinder)
194
+ @m.ck(sym,*r)
195
+ # first try for a builder matching sym
196
+ if (b = bld(sym,*r,&k))
197
+ # run it
198
+ res = b.run
199
+ # connect it
200
+ ctc(b)
201
+ return true, res
202
+ elsif @s.empty?
203
+ return false, nil
204
+ else
205
+ # no matching builder, try to consume sym as a method
206
+ csm(sym,*r,&k)
207
+ end
208
+ end
209
+
210
+ # call-seq:
211
+ # ctx.msend(builder_module, sym, *args, &block) -> result
212
+ #
213
+ # Version of +send+ intended for use by proxy objects. The supplied module's factory
214
+ # _must_ be able to resolve the symbol; otherwise, a NoMethodError will be raised.
215
+ def msend(m,sym,*r,&k)
216
+ #puts "fsend sym: #{sym}"
217
+ # ok for stack to be empty for this call, so no check
218
+ raise Cheri.type_error(sym,Symbol) unless sym.instance_of?(Symbol)
219
+ raise ArgumentError,"not a valid builder module: #{m}" unless (f = @f[m])
220
+ # check args against pending connections (see note at ConnectionMinder)
221
+ @m.ck(sym,*r)
222
+ # the factory _must_ be able to return a matching builder
223
+ unless (b = f.builder(self,sym,*r,&k))
224
+ raise NoMethodError,"undefined method '#{sym}' for #{m}"
225
+ end
226
+ # run it
227
+ res = b.run
228
+ # connect it
229
+ ctc(b)
230
+ res
231
+ end
232
+
233
+ # call-seq:
234
+ # ctx.call(builder, *args, &block) -> result
235
+ #
236
+ # Pushes builder onto the stack, then calls the block/proc, passing the builder's object
237
+ # and any other arguments supplied: <tt>block.call(builder.object,*args)</tt>
238
+ # Then pops the builder from the stack and returns the result of the call.
239
+ #
240
+ # <tt>Context#call</tt> ensures that the stack is always popped, even if an exception is raised
241
+ # in the called block. If you choose to call the block directly, be sure to do the
242
+ # same, otherwise failures and/or (possibly subtle) bugs will ensue.
243
+ def call(b,*r,&k)
244
+ push(b)
245
+ k.call(b.object,*r)
246
+ ensure
247
+ pop
248
+ end
249
+
250
+ # call-seq:
251
+ # ctx.eval(instance, builder, &block) -> result
252
+ #
253
+ # Pushes builder onto the stack, then calls <tt>instance.instance_eval(&block)</tt>.
254
+ # Then pops the builder from the stack and returns the result of the <tt>instance_eval</tt>.
255
+ #
256
+ # <tt>Context#eval</tt> ensures that the stack is always popped, even if an exception is raised
257
+ # in the executed block. If you choose to do your own instance_eval, be sure to do the
258
+ # same, otherwise failures and/or (possibly subtle) bugs will ensue.
259
+ def eval(i,b,&k)
260
+ push(b)
261
+ i.instance_eval(&k)
262
+ ensure
263
+ pop
264
+ end
265
+
266
+ # call-seq:
267
+ # ctx.exec(instance, builder, *args, &block) -> result
268
+ #
269
+ # Pushes builder onto the stack, then calls
270
+ # <tt>instance.instance_exec(builder.object,*args,&block)</tt>.
271
+ # Then pops the builder from the stack and returns the result of the <tt>instance_exec</tt>.
272
+ #
273
+ # <tt>Context#exec</tt> ensures that the stack is always popped, even if an exception is raised
274
+ # in the executed block. If you choose to do your own <tt>instance_exec</tt>, be sure to do the
275
+ # same, otherwise failures and/or (possibly subtle) bugs will ensue.
276
+ #
277
+ # If <tt>instance_exec</tt> is not supported on a system, the call is redirected to <tt>Context#eval</tt>
278
+ # (<tt>instance_eval</tt>). Note that parameters will not be passed to blocks in that case.
279
+ #--
280
+ # TODO: need a good default instance_exec, (the one in active_support\core_ext\object\extending.rb?)
281
+ #++
282
+ def exec(i,b,*r,&k)
283
+ return eval(i,b,&k) unless @x ||= (defined?instance_exec)
284
+ push(b)
285
+ i.instance_exec(b.object,*r,&k)
286
+ ensure
287
+ pop
288
+ end
289
+
290
+ def push(f)
291
+ # TODO: more checks of f (frame/builder)
292
+ raise ArgumentError,"invalid argument - can't push: #{f}" unless f
293
+ @s << f
294
+ @m.pu f
295
+ (@a ||= []) << f if f.any?
296
+ self
297
+ end
298
+ alias_method :push_frame, :push
299
+
300
+ def pop
301
+ f = @s.pop
302
+ @m.po f
303
+ @a.pop if f.any?
304
+ f
305
+ end
306
+ alias_method :pop_frame, :pop
307
+
308
+ def top
309
+ @s.last
310
+ end
311
+ alias_method :peek, :top
312
+
313
+ def bottom
314
+ @s.first
315
+ end
316
+
317
+ def each #:yields: frame
318
+ @s.reverse_each {|v| yield v } if block_given?
319
+ end
320
+ alias_method :each_frame, :each
321
+
322
+ def reach #:yields: frame
323
+ @s.each {|v| yield v } if block_given?
324
+ end
325
+ alias_method :reverse_each, :reach
326
+ alias_method :reverse_each_frame, :reach
327
+
328
+ # call-seq:
329
+ # ctx.stack_size -> Fixnum
330
+ # ctx.size -> Fixnum
331
+ # ctx.length -> Fixnum
332
+ #
333
+ # Returns the number of frames on the context stack.
334
+ def size
335
+ @s.length
336
+ end
337
+ alias_method :length, :size #:nodoc:
338
+ alias_method :stack_size, :size #:nodoc:
339
+
340
+ # call-seq:
341
+ # ctx.stack_empty? -> true/false
342
+ # ctx.empty? -> true/false
343
+ #
344
+ # Returns true if the context stack is empty.
345
+ def empty?
346
+ @s.empty?
347
+ end
348
+ alias_method :stack_empty?, :empty?
349
+
350
+ # call-seq:
351
+ # ctx.active? -> true/false
352
+ #
353
+ # Returns true if the context stack is not empty.
354
+ def active?
355
+ !@s.empty?
356
+ end
357
+
358
+ # call-seq:
359
+ # ctx.type_on_stack?(class_or_module) -> true/false
360
+ # ctx.tos(class_or_module) -> true/false
361
+ #
362
+ # Returns true if a stack frame matches the specified class_or_module, as evaluated
363
+ # by class_or_module === frame.
364
+ def tos(t)
365
+ @s.reverse_each do |f|
366
+ return true if t === f
367
+ end
368
+ false
369
+ end
370
+ alias_method :type_on_stack?, :tos #:nodoc:
371
+
372
+ # call-seq:
373
+ # ctx.builder(symbol, *args [, &block]) -> aBuilder or nil
374
+ # ctx.bld(symbol, *args [, &block]) -> aBuilder or nil
375
+ #
376
+ # Searches the stack for a builder/frame whose associated factory can supply a
377
+ # builder for the specified symbol (usually originating in the client's +method_missing+ method).
378
+ # If no stack frame can supply a builder, any auto-enabled builder modules are searched
379
+ # in the order they were enabled. Returns nil if no builder is found.
380
+ def bld(*r,&k)
381
+ #puts "bld args: #{[r.join(',')]}"
382
+ fs = nil # lazily-allocated array to hold factories we've already queried
383
+ b = nil # builder
384
+
385
+ # search stack for a frame whose module's factory can supply a matching builder
386
+ @s.reverse_each do |s|
387
+ if (f = @f[s.mod])
388
+ unless fs && fs.include?(f)
389
+ return b if (b = f.builder(self,*r,&k))
390
+ (fs ||= []) << f
391
+ end
392
+ end
393
+ end
394
+
395
+ # try auto-enabled builders
396
+ if (u = auto)
397
+ u.each do |m|
398
+ if (f = @f[m])
399
+ unless fs && fs.include?(f)
400
+ return b if (b = f.builder(self,*r,&k))
401
+ (fs ||= []) << f
402
+ end
403
+ end
404
+ end
405
+ end
406
+
407
+ # no matches
408
+ nil
409
+ end
410
+ alias_method :builder, :bld #:nodoc:
411
+
412
+ # call-seq:
413
+ # ctx.consume(sym, *args, &block) -> consumed?, result
414
+ # ctx.csm(sym, *args, &block) -> consumed?, result
415
+ #
416
+ # Attempts to consume the specified +sym+, usually as a method on a built object (though
417
+ # not necessarily; the Java on_xxx handlers are implemented through a consumer). This is
418
+ # normally called when no builder is found matching +sym+ (which normally originates in the
419
+ # client's method_missing method). Only the topmost stack frame is eligible to consume.
420
+ #
421
+ # This method is primarily intended for internal use by Context.
422
+ def csm(*r,&k)
423
+ # methods are not passed up the stack; if it can't be consumed
424
+ # by the last builder/frame, it's an error
425
+ return false,nil unless (b = @s.last) # TODO: error if !b
426
+
427
+ # offer the builder/object the opportunity to consume the method directly
428
+ #puts "csm b=#{b}, b.o=#{b.object}, b.mod=#{b.mod}"
429
+ if b.respond_to?(:consume)
430
+ return b.consume(*r,&k)
431
+ # must have object for standard consumers
432
+ elsif b.object && (c = @g.consumers[b.mod])
433
+ return c.consume(self,b,*r,&k)
434
+ else
435
+ return false, nil
436
+ end
437
+ end
438
+ alias_method :consume, :csm #:nodoc:
439
+
440
+ # call-seq:
441
+ # ctx.resolve_meth(object, method_name, args) -> resolved?
442
+ # ctx.mrz(object, method_name, args) -> resolved?
443
+ #
444
+ # Attempts to resolve any <tt>:Constant</tt> symbols found in +args+ for the specified
445
+ # +object+ and +method_name+. Note that +args+ must be passed as an array, not as <tt>*args</tt>,
446
+ # as substitutions will be made directly in the array.
447
+ def mrz(mod,o,y,a)
448
+ if (z = @g.resolvers[mod])
449
+ return true if z.resolve_meth(o,y,a)
450
+ end
451
+ false
452
+ end
453
+ alias_method :resolve_meth, :mrz #:nodoc:
454
+
455
+ # call-seq:
456
+ # ctx.resolve_ctor(clazz, args) -> resolved?
457
+ # ctx.crz(clazz, args) -> resolved?
458
+ #
459
+ # Attempts to resolve any <tt>:Constant</tt> symbols found in +args+ for the specified
460
+ # +clazz+. Note that +args+ must be passed as an array, not as <tt>*args</tt>,
461
+ # as substitutions will be made directly in the array.
462
+ def crz(mod,c,a)
463
+ #puts "resolving: m=#{mod}, c=#{c}, a=[#{a.join(',')}]"
464
+ if (z = @g.resolvers[mod])
465
+ return true if z.resolve_ctor(c,a)
466
+ end
467
+ false
468
+ end
469
+ alias_method :resolve_ctor, :crz #:nodoc:
470
+
471
+
472
+ def ctc(frame)
473
+ # make sure there's something to connect to, and the frame wants to connect
474
+ return if @s.empty? || !frame.child?
475
+
476
+ # offer the builder/object the opportunity to connect itself
477
+ return if frame.respond_to?(:connect) && frame.connect(self)
478
+
479
+ # we need sym and object for standard connecters
480
+ return unless (sym = frame.sym) && (obj = frame.object)
481
+
482
+ # connect properties are optional (used in swing/awt for add constraints, etc.)
483
+ props = frame.respond_to?(:props) ? frame.props : nil
484
+
485
+ # find the first (closest) frame/builder on the stack that has an object
486
+ # we can connect to
487
+ parent = nil
488
+ @s.reverse_each do |b|
489
+ if b.parent? && b.object
490
+ parent = b
491
+ break
492
+ end
493
+ end
494
+
495
+ # if we got a builder (parent), attempt to connect it
496
+ if parent && (n = @n[parent.mod])
497
+ n.prepare(self,parent,obj,sym,props)
498
+ end
499
+
500
+ # now attempt connections for any 'any' objects on the stack
501
+ @a.reverse_each do |a|
502
+ if a.object && (n = @n[a.mod])
503
+ n.prepare(self,a,obj,sym,props)
504
+ end
505
+ end if @a
506
+
507
+ nil
508
+ end
509
+ private :ctc
510
+ alias_method :connect, :ctc
511
+
512
+ def cfg
513
+ @g
514
+ end
515
+
516
+ def props
517
+ @p
518
+ end
519
+
520
+ # call-seq:
521
+ # ctx[key] -> value
522
+ #
523
+ def [](k)
524
+ @p[k]
525
+ end
526
+
527
+ # call-seq:
528
+ # ctx[key] = value -> value
529
+ #
530
+ def []=(k,v)
531
+ @p[k]=v
532
+ end
533
+
534
+ # call-seq:
535
+ # prepared(connecter,builder,obj,sym,props=nil) -> true
536
+ # ppd(connecter,builder,obj,sym,props=nil) -> true
537
+ #
538
+ # Called by a Connecter (normally) from its +prepare+ method (normally) to indicate
539
+ # that it is prepared to connect +obj+ to the parent object hosted by +builder+. The
540
+ # context will later call the connecter's +connect+ method to perform the actual
541
+ # connection, provided the pending connection has not been invalidated. (A pending
542
+ # connection will be invalidated if +obj+ is passed as a parameter to a method or
543
+ # constructor <em>invoked via Cheri</em>; the assumption is that the receiver will
544
+ # have performed any connection necessary.)
545
+ #
546
+ # Note that if you are using TypeConnecter (highly recommended where appropriate), this all
547
+ # takes place behind the scenes, so you don't need to call this method directly.
548
+ def ppd(ctr,bldr,obj,sym,props=nil)
549
+ @m.ppd(ctr,bldr,obj,sym,props)
550
+ end
551
+ alias_method :prepared, :ppd #:nodoc:
552
+
553
+ # TODO: this is internal now, don't need a method ?
554
+ # def ck(*r)
555
+ # @m.check(*r)
556
+ # end
557
+ # alias_method :check, :ck
558
+ #
559
+
560
+ # We want to prevent built objects passed as parameters from
561
+ # being dynamically connected, since presumably the method/ctor
562
+ # being called will do whatever is needed (except for cherify,
563
+ # which _wants_ its arg connected). Note that we can only catch
564
+ # those passed to cheri-invoked ctors/methods.
565
+ class ConnectionMinder #:nodoc: all
566
+ def initialize
567
+ @c = {} # pending connections. indexed by builder.__id__
568
+ @o = {} # pending builder(object)s. indexed by object.__id__
569
+ end
570
+
571
+ # a builder has been pushed onto the stack. create
572
+ # an array to hold pending connections for that builder
573
+ def pu(b)
574
+ @c[b.__id__] = []
575
+ #@a
576
+ end
577
+ alias_method :pushed, :pu #:nodoc:
578
+
579
+ # a builder has been popped from the stack. connect any
580
+ # pending (prepared) connections, and remove each builder/object
581
+ # associated with a connection from the pending objects hash.
582
+ def po(b)
583
+ if (cs = @c.delete b.__id__)
584
+ begin
585
+ cs.each do |c| c.connect; end
586
+ ensure
587
+ o = @o
588
+ cs.each do |c| o.delete c.obj.__id__; end
589
+ end
590
+ end
591
+ end
592
+ alias_method :popped, :po #:nodoc:
593
+
594
+ # store a prepared connection.
595
+ def ppd(ctr,bldr,obj,sym,props=nil)
596
+ @o[obj.__id__] = bldr
597
+ @c[bldr.__id__] << Con.new(ctr,bldr.object,obj,sym,props)
598
+ true
599
+ end
600
+ alias_method :prepared, :ppd #:nodoc:
601
+
602
+ # check args passed to ctors/methods against the pending objects hash,
603
+ # and remove any matches from the pending connections/objects hashes.
604
+ def ck(y,*r)
605
+ unless r.empty? || y == :cheri_yield || y == :cherify
606
+ o = @o
607
+ r.each do |a|
608
+ if (b = o[a.__id__])
609
+ cs = @c[b.__id__]
610
+ cs.reverse_each do |c|
611
+ if a.equal?(c.obj)
612
+ cs.delete(c)
613
+ o.delete(a.__id__)
614
+ end
615
+ end
616
+ end
617
+ end
618
+ if Hash === r.last
619
+ r.last.each_value do |a|
620
+ if (b = o[a.__id__])
621
+ cs = @c[b.__id__]
622
+ cs.reverse_each do |c|
623
+ if a.equal?(c.obj)
624
+ cs.delete(c)
625
+ o.delete(a.__id__)
626
+ end
627
+ end
628
+ end
629
+ end
630
+ end
631
+ end
632
+ end
633
+ alias_method :check, :ck #:nodoc:
634
+
635
+ class Con #:nodoc: all
636
+ def initialize(ctr,par,obj,sym,props)
637
+ @c = ctr
638
+ @p = par
639
+ @o = obj
640
+ @y = sym if sym
641
+ @r = props if props
642
+ end
643
+ def obj
644
+ @o
645
+ end
646
+ def connect
647
+ @c.connect(@p,@o,@y,@r)
648
+ end
649
+ end #Con
650
+ end #ConnectionMinder
651
+ end #Context
652
+
653
+ end #Builder
654
+ end #Cheri
655
+