cheri 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README +98 -0
- data/Rakefile +121 -0
- data/examples/hello_world_1.rb +28 -0
- data/examples/table_1.rb +44 -0
- data/lib/cheri/awt.rb +41 -0
- data/lib/cheri/builder.rb +31 -0
- data/lib/cheri/builder/awt/connecter.rb +63 -0
- data/lib/cheri/builder/awt/constants.rb +1003 -0
- data/lib/cheri/builder/awt/main.rb +191 -0
- data/lib/cheri/builder/awt/types.rb +220 -0
- data/lib/cheri/builder/base.rb +533 -0
- data/lib/cheri/builder/config.rb +187 -0
- data/lib/cheri/builder/connecter.rb +386 -0
- data/lib/cheri/builder/context.rb +655 -0
- data/lib/cheri/builder/generator.rb +425 -0
- data/lib/cheri/builder/html/charsets.rb +154 -0
- data/lib/cheri/builder/html/common.rb +32 -0
- data/lib/cheri/builder/html/connecter.rb +57 -0
- data/lib/cheri/builder/html/element.rb +156 -0
- data/lib/cheri/builder/html/main.rb +116 -0
- data/lib/cheri/builder/html/types.rb +123 -0
- data/lib/cheri/builder/main.rb +483 -0
- data/lib/cheri/builder/swing/connecter.rb +141 -0
- data/lib/cheri/builder/swing/constants.rb +420 -0
- data/lib/cheri/builder/swing/main.rb +446 -0
- data/lib/cheri/builder/swing/types.rb +270 -0
- data/lib/cheri/builder/xml/charsets.rb +154 -0
- data/lib/cheri/builder/xml/common.rb +32 -0
- data/lib/cheri/builder/xml/connecter.rb +42 -0
- data/lib/cheri/builder/xml/element.rb +189 -0
- data/lib/cheri/builder/xml/main.rb +130 -0
- data/lib/cheri/builder/xml/types.rb +36 -0
- data/lib/cheri/cheri.rb +70 -0
- data/lib/cheri/cjx.rb +3 -0
- data/lib/cheri/explorer.rb +32 -0
- data/lib/cheri/explorer/explorer.rb +560 -0
- data/lib/cheri/html.rb +31 -0
- data/lib/cheri/image/Delete24.gif +0 -0
- data/lib/cheri/image/Find24.gif +0 -0
- data/lib/cheri/image/FindAgain24.gif +0 -0
- data/lib/cheri/image/Refresh24.gif +0 -0
- data/lib/cheri/image/Search24.gif +0 -0
- data/lib/cheri/image/Thumbs.db +0 -0
- data/lib/cheri/image/cheri_icon_16x16.png +0 -0
- data/lib/cheri/image/cheri_icon_24x24.png +0 -0
- data/lib/cheri/image/cheri_logo_medium.png +0 -0
- data/lib/cheri/image/close_10x10.png +0 -0
- data/lib/cheri/image/close_10x10s.png +0 -0
- data/lib/cheri/image/close_12x12.png +0 -0
- data/lib/cheri/image/close_14x14.png +0 -0
- data/lib/cheri/image/close_24x24.png +0 -0
- data/lib/cheri/image/close_dim2_12x12.png +0 -0
- data/lib/cheri/image/close_dim_12x12.png +0 -0
- data/lib/cheri/image/cls_tree.png +0 -0
- data/lib/cheri/image/con_tree.png +0 -0
- data/lib/cheri/image/jruby_14x16.png +0 -0
- data/lib/cheri/image/jruby_logo.png +0 -0
- data/lib/cheri/image/mod_tree.png +0 -0
- data/lib/cheri/image/obj_tree.png +0 -0
- data/lib/cheri/image/ruby_16x16.png +0 -0
- data/lib/cheri/image/vars_tree.png +0 -0
- data/lib/cheri/java.rb +26 -0
- data/lib/cheri/java/builder.rb +28 -0
- data/lib/cheri/java/builder/main.rb +407 -0
- data/lib/cheri/java/builder/util.rb +480 -0
- data/lib/cheri/java/java.rb +56 -0
- data/lib/cheri/jruby.rb +32 -0
- data/lib/cheri/jruby/explorer.rb +43 -0
- data/lib/cheri/jruby/explorer/common.rb +38 -0
- data/lib/cheri/jruby/explorer/dialogs.rb +383 -0
- data/lib/cheri/jruby/explorer/explorer.rb +904 -0
- data/lib/cheri/jruby/explorer/splash.rb +80 -0
- data/lib/cheri/jruby/explorer/viewer.rb +619 -0
- data/lib/cheri/jruby/explorer/viewers.rb +1057 -0
- data/lib/cheri/jruby/jruby.rb +59 -0
- data/lib/cheri/swing.rb +41 -0
- data/lib/cheri/xml.rb +31 -0
- 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
|
+
|