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.
- 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
|
+
|