cheri 0.0.5 → 0.0.6

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.
@@ -71,7 +71,7 @@ end #self
71
71
  # awt([*args] [, &block]) -> AWTProxy if no block given, else result of block
72
72
  #
73
73
  def awt(*r,&k)
74
- if (ctx = __cheri_ctx)
74
+ if ctx = __cheri_ctx
75
75
  if k
76
76
  AWTFrame.new(ctx,*r,&k).run
77
77
  else
@@ -25,7 +25,7 @@
25
25
  module Cheri
26
26
  module Builder
27
27
 
28
- # Frame contains default implementations of the methods required by objects that
28
+ # Frame provides default implementations of the methods required by objects that
29
29
  # will be pushed onto the Cheri::Builder::Context stack. Note that concrete
30
30
  # builders will need to override some of these methods, such as #mod, #parent?
31
31
  # and #child?.
@@ -209,325 +209,5 @@ private
209
209
  end
210
210
  end #BaseBuilder
211
211
 
212
- # Appendable types define to_s, to_str and to_io methods that take an optional
213
- # parameter, to which output is appended. This is essentially a marker interface;
214
- # the supplied implementations do nothing useful.
215
- module Appendable
216
- # Append value (whatever that might be) to the supplied String, or create and
217
- # return a new String if none is supplied. If #esc is overridden, value will
218
- # be escaped first. Delegates to #to_io unless String === str. Note that this
219
- # implementation appends an empty string; override to do something useful.
220
- def to_s(str='')
221
- return to_io(str) unless String === str
222
- esc('',str)
223
- end
224
-
225
- # Calls #to_s(str). Provided so that Appendable objects may be coerced to
226
- # Strings automatically, as in <tt>str << my_appendable_thingy</tt>. Implemented
227
- # this way rather than through alias_method to counter the possibility that
228
- # overriders of #to_s will forget to re-alias to_str.
229
- def to_str(str='')
230
- to_s(str)
231
- end
232
-
233
- # Append value (whatever that might be) to the supplied output stream. If
234
- # #esc is overridden, value will be escaped first. Note that this
235
- # implementation appends an empty string; override to do something useful.
236
- def to_io(ios)
237
- ios << esc('')
238
- end
239
-
240
- # Override to escape values (default implementation appends or returns
241
- # the input value unaltered).
242
- def esc(inp,out=nil)
243
- out ? out << inp : inp
244
- end
245
-
246
- end
247
-
248
- # Methods to support content (primarily intended for use with XML/HTML markup).
249
- # See also EmptyContent, ContentArgs.
250
- module Content
251
- include Appendable
252
-
253
- # Adds +value+ to the content array (@cont) for this object if #content?(+value+)
254
- # returns +true+.
255
- def add(value)
256
- (@cont ||= []) << value if content?(value)
257
- self
258
- end
259
- alias_method :<<, :add
260
-
261
- # Returns the content array (@cont) if present, otherwise +nil+.
262
- def content
263
- @cont
264
- end
265
-
266
- # Iterates over the content array (@cont) for this object. Equivalent to
267
- # calling #content#each.
268
- def each #:yields: content_value
269
- @cont.each do |v|
270
- yield v
271
- end if @cont && block_given?
272
- end
273
-
274
- # Returns truth value if +value+ is valid content for this builder/object,
275
- # +false+/+nil+ otherwise. Called by #add before adding content; +value+ will
276
- # not be added unless content? is true.
277
- #
278
- # This implementation always returns +true+. Override to validate each content
279
- # element before it is added. You may wish to raise an exception or issue a
280
- # warning in the case of invalid content.
281
- def content?(value)
282
- true
283
- end
284
-
285
- # Appends concatenated and escaped content (@cont) to +str+, if supplied, using
286
- # the +<<+ operator. Assumes String === +str+. Use #cont_io to append to IO or Array.
287
- def cont_s(str='')
288
- @cont.each do |v|
289
- case v
290
- when String : esc(v,str)
291
- when Appendable : v.to_s(str)
292
- else esc(v.to_s,str)
293
- end
294
- end if @cont
295
- str
296
- end
297
-
298
- # Appends concatenated and escaped content (@cont) to +ios+, if supplied, using
299
- # the +<<+ operator. Use for appending to IO or Array. Use #cont_s to append more
300
- # efficiently to strings.
301
- def cont_io(ios)
302
- @cont.each do |v|
303
- case v
304
- when String : ios << esc(v)
305
- when Appendable : v.to_io(ios)
306
- else ios << esc(v.to_s)
307
- end
308
- end if @cont
309
- ios
310
- end
311
-
312
- # Override to escape values by appending the escaped +inp+ value to output
313
- # string +out+ (using << or concat). If +out+ is nil, just return the escaped
314
- # string. The default implementation appends or returns the input value unaltered.
315
- def esc(inp,out=nil)
316
- out ? out << inp : inp
317
- end
318
-
319
- end
320
-
321
- # Methods to support attributes (primarily intended for use with XML/HTML markup).
322
- # Note: include before ContentArgs if both are being included.
323
- module Attributes
324
- include Appendable
325
- #:stopdoc:
326
- S = ' '.freeze
327
- Q = '"'.freeze
328
- E = '='.freeze
329
- #:startdoc:
330
- def initialize(*r,&k)
331
- super
332
- if @args && Hash === @args.last
333
- @args.pop.each_pair do |n,v| add_attr(n,v); end
334
- end
335
- end
336
-
337
- # Returns the attibutes hash (@attrs), if any.
338
- def attrs
339
- @attrs
340
- end
341
-
342
- # Add an attribute. Called by #initialize to add/validate attributes passed as
343
- # arguments.
344
- def add_attr(name,value)
345
- (@attrs ||= {})[name] = value if attr?(name,value)
346
- end
347
-
348
- # Override to validate each attribute before it is added. The default
349
- # implementation accepts any name/value.
350
- def attr?(name,value)
351
- true
352
- end
353
-
354
- # Writes attributes to a new string, or appends to an existing string
355
- # (using <<) if supplied.
356
- def attr_s(str='')
357
- @attrs.each_pair do |k,v|
358
- str << 32 << k.to_s << ?= << 34 << v.to_s << 34
359
- end if @attrs
360
- str
361
- end
362
-
363
- # Writes attributes to the supplied IO stream (or Array, etc.) using <<.
364
- def attr_io(ios)
365
- @attrs.each_pair do |k,v|
366
- ios << S << k << E << Q << v << Q
367
- end if @attrs
368
- ios
369
- end
370
- end
371
-
372
- # Calls +add+ to add each argument passed to new/initialize. Use with Content
373
- # module if content values will be passed as arguments. Note: include after
374
- # Attributes if both are being used.
375
- module ContentArgs
376
- def initialize(*r,&k)
377
- super
378
- @args.each do |a| add a; end
379
- end
380
- end #ContentArgs
381
-
382
-
383
- # Methods to support empty content models (primarily intended for use with XML/HTML markup).
384
- # See also Content, ContentArgs.
385
- module EmptyContent
386
- include Appendable
387
- CE = ' />'.freeze #:nodoc:
388
-
389
- # Returns +false+
390
- def content?(value)
391
- false
392
- end
393
-
394
- def empty_s(str='')
395
- str << CE
396
- end
397
-
398
- def empty_io(ios)
399
- ios << CE
400
- end
401
-
402
- end #EmptyContent
403
-
404
- module MarkupWriter
405
- #:stopdoc:
406
- C = '</'.freeze
407
- E = '>'.freeze
408
- EC = '></'.freeze
409
- O = '<'.freeze
410
- #:startdoc:
411
-
412
- # Append this markup to +str+ (or an empty string if +str+ is not supplied),
413
- # and return the result. Redirects to #to_io if +str+ is not a String. Both
414
- # methods use the +<<+ operator to append their output; this method (like the other
415
- # ..._s methods) is faster because Fixnum values can be appended directly, without
416
- # being converted to (or passed as) strings. This takes on particular significance
417
- # when output is being escaped, and values passed one character at a time.
418
- def to_s(str='')
419
- return to_io(str) unless String === str
420
- open_s(str)
421
- attr_s(str) if @attrs
422
- if @cont
423
- str << ?>
424
- cont_s(str)
425
- close_s(str)
426
- else
427
- empty_s(str)
428
- end
429
- str
430
- end
431
-
432
- # Append this markup to +ios+
433
- def to_io(ios)
434
- open_io(ios)
435
- attr_io(ios) if @attrs
436
- if @cont
437
- ios << E
438
- cont_io(ios)
439
- close_io(ios)
440
- else
441
- empty_io(ios)
442
- end
443
- ios
444
- end
445
-
446
- # Append open tag (<tagname) to +str+ using +<<+.
447
- def open_s(str)
448
- str << ?< << (@tag ||= @sym.to_s)
449
- end
450
-
451
- # Append open tag (<tagname) to +ios+ using +<<+.
452
- def open_io(ios)
453
- ios << O << (@tag ||= @sym.to_s)
454
- end
455
-
456
- # Append close tag (</tagname>) to +str+ using +<<+.
457
- def close_s(str)
458
- str << C << @tag << ?>
459
- end
460
-
461
- # Append close tag (</tagname>) to +ios+ using +<<+. (Use slightly faster
462
- # #close_s for strings.)
463
- def close_io(ios)
464
- ios << C << @tag << E
465
- end
466
-
467
- # Append empty close tag (...></tagname>) to +str+. Note that HTML/XML elements
468
- # with empty content models should close with <tt>' />'</tt> instead (see EmptyContent).
469
- def empty_s(str)
470
- str << EC << @tag << ?>
471
- end
472
-
473
- # Append empty close tag (...></tagname>) to +ios+. Note that HTML/XML elements
474
- # with empty content models should close with <tt>' />'</tt> instead (see EmptyContent).
475
- def empty_io(ios)
476
- ios << EC << @tag << E
477
- end
478
-
479
- end #MarkupWriter
480
-
481
- module Markup
482
- include Content
483
- include Attributes
484
- include ContentArgs
485
- include MarkupWriter
486
- end #Markup
487
-
488
- module EmptyMarkup
489
- # We include Content and ContentArgs so that warnings/exceptions may be
490
- # issued (by overriding #add or #content?) if the user attempts to add to this element.
491
- # Otherwise, unconnectable elements would simply be ignored.
492
- include Markup
493
- # include Content
494
- # include Attributes
495
- # include ContentArgs
496
- # include MarkupWriter
497
- include EmptyContent
498
- end #EmptyMarkup
499
-
500
- module MarkupBuilder
501
- include Builder
502
- include Markup
503
-
504
- def object
505
- self
506
- end
507
-
508
- def run
509
- value = @ctx.call(self,&@blk) if @blk
510
- add(value) if String === value
511
- self
512
- end
513
- end #MarkupBuilder
514
-
515
- module EmptyMarkupBuilder
516
- include Builder
517
- include EmptyMarkup
518
-
519
- def object
520
- self
521
- end
522
-
523
- def run
524
- value = @ctx.call(self,&@blk) if @blk
525
- # of course we want this to then fail in #add / #content? e.g., see Cheri::Html::EmptyElem
526
- add(value) if String === value
527
- self
528
- end
529
-
530
- end #EmptyMarkupBuilder
531
-
532
212
  end #Builder
533
213
  end #Cheri
@@ -62,13 +62,11 @@ class Config
62
62
  validate(mod) unless mod == Cheri::Builder
63
63
  extendee = mod.respond_to?(:extends) ? mod.extends : nil
64
64
  raise BuilderException,"extended builder module not included: #{extendee}" if extendee && !@m.include?(extendee)
65
- #puts "config add mod #{mod}"
66
65
  @m << mod
67
66
  @f[mod] = mod.factory if mod.respond_to?(:factory) && mod.factory
68
67
  @c[mod] = mod.connecter if mod.respond_to?(:connecter) && mod.connecter
69
68
  (@n ||= {})[mod] = mod.consumer if mod.respond_to?(:consumer) && mod.consumer
70
69
  (@r ||= {})[mod] = mod.resolver if mod.respond_to?(:resolver) && mod.resolver
71
- #puts "@n = #{@n}"
72
70
  extend_mod(extendee,mod) if extendee
73
71
  self
74
72
  end
@@ -145,6 +143,12 @@ class Config
145
143
  def copy
146
144
  self.class.allocate.copy_from(@m,@f,@c,@n,@r)
147
145
  end
146
+
147
+ # Overrides the default Object#inspect to prevent mind-boggling circular displays in IRB.
148
+ def inspect
149
+ "#<#{self.class}:instance>"
150
+ end
151
+
148
152
  protected
149
153
  def copy_from(m,f,c,n,r)
150
154
  @m = m.dup
@@ -25,15 +25,13 @@
25
25
  module Cheri
26
26
  module Builder
27
27
 
28
-
29
- # !!! TODO: class-level properties
30
-
31
28
  class InstanceContext
32
29
  # TODO: defined?Java pulls it in (same as require 'java' or include Java)
33
30
  # not sure if anyone would object...
34
31
  if (defined?Java) && (defined?JRUBY_VERSION) # JRuby 0.9.9 or later
35
32
  Col = java.util.Collections
36
- Map = java.util.WeakHashMap
33
+ Map = java.util.HashMap
34
+ WMap = java.util.WeakHashMap
37
35
  end
38
36
 
39
37
  # call-seq:
@@ -42,10 +40,15 @@ class InstanceContext
42
40
  def initialize(client,cfg)
43
41
  @c = client
44
42
  @g = cfg
45
-
43
+ # TODO: properties, aliases should probably be threadsafe hashes/maps,
44
+ # though contention would be extremely unlikely given expected usage (any
45
+ # puts likely to be made on the instantiating thread, immediately
46
+ # upon instantiation).
47
+ @p = {} # properties
48
+ @l = {} # aliases
46
49
  # TODO: find a better way to do this
47
50
  if self.class.const_defined?("Map")
48
- @h = Col.synchronized_map Map.new
51
+ @h = Col.synchronized_map WMap.new
49
52
  @t = true # use Thread as key
50
53
  else
51
54
  # TODO: should use weak hash here
@@ -79,14 +82,22 @@ class InstanceContext
79
82
  end
80
83
  end
81
84
 
85
+ def props
86
+ @p
87
+ end
88
+
82
89
  def [](k)
83
- @g[k]
90
+ @p[k]
84
91
  end
85
92
 
86
93
  def []=(k,v)
87
- @g[k] = v
94
+ @p[k] = v
88
95
  end
89
-
96
+
97
+ def aliases
98
+ @l
99
+ end
100
+
90
101
  # call-seq:
91
102
  # current -> context object for the current instance/thread
92
103
  #
@@ -94,6 +105,11 @@ class InstanceContext
94
105
  key = @t ? Thread.current : Thread.current.__id__
95
106
  @h[key] ||= Context.new(self,@c)
96
107
  end
108
+
109
+ # Overrides the default Object#inspect to prevent mind-boggling circular displays in IRB.
110
+ def inspect
111
+ "#<#{self.class}:instance>"
112
+ end
97
113
 
98
114
  end #InstanceContext
99
115
 
@@ -112,6 +128,7 @@ class Context
112
128
  # @g - reference to the class's Config instance (all included Cheri builder modules)
113
129
  # @p - configuration properties hash, used for various purposes
114
130
  # @i - reference to the InstanceContext that created this Context
131
+ # @l - reference to aliases from InstanceConfig
115
132
  # @m - the ConnectionMinder for this context, tracks pending (prepared) connections
116
133
  # @n - reference to the connecters in the class's Config instance
117
134
  # @r - array of ConstantResolver instances, lazily initialized
@@ -128,6 +145,7 @@ class Context
128
145
  if (u = ictx.auto)
129
146
  @u = u.dup
130
147
  end
148
+ @l = ictx.aliases
131
149
  @c = client
132
150
  @m = ConnectionMinder.new
133
151
  @s = [] # stack
@@ -190,6 +208,8 @@ class Context
190
208
  # method_missing (the usual caller) empty-handed.
191
209
  def send(sym,*r,&k)
192
210
  raise Cheri.type_error(sym,Symbol) unless sym.instance_of?(Symbol)
211
+ # substitute sym for alias, if any
212
+ sym = @l[sym] if @l[sym]
193
213
  # check args against pending connections (see note at ConnectionMinder)
194
214
  @m.ck(sym,*r)
195
215
  # first try for a builder matching sym
@@ -213,16 +233,45 @@ class Context
213
233
  # Version of +send+ intended for use by proxy objects. The supplied module's factory
214
234
  # _must_ be able to resolve the symbol; otherwise, a NoMethodError will be raised.
215
235
  def msend(m,sym,*r,&k)
216
- #puts "fsend sym: #{sym}"
217
236
  # ok for stack to be empty for this call, so no check
218
237
  raise Cheri.type_error(sym,Symbol) unless sym.instance_of?(Symbol)
219
238
  raise ArgumentError,"not a valid builder module: #{m}" unless (f = @f[m])
239
+ # substitute sym for alias, if any
240
+ sym = @l[sym] if @l[sym]
241
+ # check args against pending connections (see note at ConnectionMinder)
242
+ @m.ck(sym,*r)
243
+ # the factory _must_ be able to return a matching builder
244
+ unless (b = f.builder(self,sym,*r,&k))
245
+ raise NoMethodError,"undefined method '#{sym}' for #{m}"
246
+ end
247
+ # run it
248
+ res = b.run
249
+ # connect it
250
+ ctc(b)
251
+ res
252
+ end
253
+
254
+ # call-seq:
255
+ # ctx.nsend(builder_module, namespace_sym, sym, *args, &block) -> result
256
+ #
257
+ # Version of +send+ intended for use by namespace objects. The supplied module's factory
258
+ # _must_ be able to resolve the symbol; otherwise, a NoMethodError will be raised. The
259
+ # resulting builder _must_ supply a +ns=+ method; otherwise a TypeError will be raised.
260
+ def nsend(m,ns,sym,*r,&k)
261
+ # ok for stack to be empty for this call, so no check
262
+ raise Cheri.type_error(ns,Symbol) unless Symbol === ns
263
+ raise Cheri.type_error(sym,Symbol) unless Symbol === sym
264
+ raise ArgumentError,"not a valid builder module: #{m}" unless (f = @f[m])
265
+ # substitute sym for alias, if any
266
+ sym = @l[sym] if @l[sym]
220
267
  # check args against pending connections (see note at ConnectionMinder)
221
268
  @m.ck(sym,*r)
222
269
  # the factory _must_ be able to return a matching builder
223
270
  unless (b = f.builder(self,sym,*r,&k))
224
271
  raise NoMethodError,"undefined method '#{sym}' for #{m}"
225
272
  end
273
+ raise Cheri.type_error(b,Markup) unless b.respond_to?(:ns=)
274
+ b.ns = ns
226
275
  # run it
227
276
  res = b.run
228
277
  # connect it
@@ -498,11 +547,18 @@ class Context
498
547
  end
499
548
 
500
549
  # 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)
550
+ if @a
551
+ @ax = true
552
+ begin
553
+ @a.reverse_each do |a|
554
+ if a.object && (n = @n[a.mod])
555
+ n.prepare(self,a,obj,sym,props)
556
+ end
557
+ end
558
+ ensure
559
+ @ax = nil
504
560
  end
505
- end if @a
561
+ end
506
562
 
507
563
  nil
508
564
  end
@@ -530,7 +586,19 @@ class Context
530
586
  def []=(k,v)
531
587
  @p[k]=v
532
588
  end
533
-
589
+
590
+ # call-seq:
591
+ # ctx.aliases -> aliases hash
592
+ # ctx.als -> aliases hash
593
+ #
594
+ def als
595
+ @l
596
+ end
597
+ # :stopdoc:
598
+ alias_method :aliases, :als
599
+ # :startdoc:
600
+
601
+
534
602
  # call-seq:
535
603
  # prepared(connecter,builder,obj,sym,props=nil) -> true
536
604
  # ppd(connecter,builder,obj,sym,props=nil) -> true
@@ -546,16 +614,13 @@ class Context
546
614
  # Note that if you are using TypeConnecter (highly recommended where appropriate), this all
547
615
  # takes place behind the scenes, so you don't need to call this method directly.
548
616
  def ppd(ctr,bldr,obj,sym,props=nil)
549
- @m.ppd(ctr,bldr,obj,sym,props)
617
+ unless @ax
618
+ @m.ppd(ctr,bldr,obj,sym,props)
619
+ else
620
+ @m.ppda(ctr,bldr,obj,sym,props)
621
+ end
550
622
  end
551
623
  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
624
 
560
625
  # Overrides the default Object#inspect to prevent mind-boggling circular displays in IRB.
561
626
  def inspect
@@ -567,9 +632,10 @@ class Context
567
632
  # being called will do whatever is needed (except for cherify,
568
633
  # which _wants_ its arg connected). Note that we can only catch
569
634
  # those passed to cheri-invoked ctors/methods.
570
- class ConnectionMinder #:nodoc: all
635
+ class ConnectionMinder # :nodoc: all
571
636
  def initialize
572
637
  @c = {} # pending connections. indexed by builder.__id__
638
+ #@a = {} # pending 'any' connections. indexed by builder.__id__
573
639
  @o = {} # pending builder(object)s. indexed by object.__id__
574
640
  end
575
641
 
@@ -577,7 +643,6 @@ class Context
577
643
  # an array to hold pending connections for that builder
578
644
  def pu(b)
579
645
  @c[b.__id__] = []
580
- #@a
581
646
  end
582
647
  alias_method :pushed, :pu #:nodoc:
583
648
 
@@ -585,6 +650,11 @@ class Context
585
650
  # pending (prepared) connections, and remove each builder/object
586
651
  # associated with a connection from the pending objects hash.
587
652
  def po(b)
653
+ if @a && (ac = @a.delete b.__id__)
654
+ ac.each do |c|
655
+ c.connect rescue nil
656
+ end
657
+ end
588
658
  if (cs = @c.delete b.__id__)
589
659
  begin
590
660
  cs.each do |c| c.connect; end
@@ -604,6 +674,13 @@ class Context
604
674
  end
605
675
  alias_method :prepared, :ppd #:nodoc:
606
676
 
677
+ # store a prepared 'any' connection.
678
+ def ppda(ctr,bldr,obj,sym,props=nil)
679
+ ((@a ||= {})[bldr.__id__] ||= []) << Con.new(ctr,bldr.object,obj,sym,props)
680
+ true
681
+ end
682
+ alias_method :prepared_any, :ppda # :nodoc:
683
+
607
684
  # check args passed to ctors/methods against the pending objects hash,
608
685
  # and remove any matches from the pending connections/objects hashes.
609
686
  def ck(y,*r)
@@ -637,7 +714,7 @@ class Context
637
714
  end
638
715
  alias_method :check, :ck #:nodoc:
639
716
 
640
- class Con #:nodoc: all
717
+ class Con # :nodoc: all
641
718
  def initialize(ctr,par,obj,sym,props)
642
719
  @c = ctr
643
720
  @p = par