cheri 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
+