facets 1.8.0 → 1.8.8
Sign up to get free protection for your applications and to get access to all the features.
- data/PROJECT +4 -4
- data/Rakefile +19 -14
- data/VERSION +1 -1
- data/lib/facet/enumerable/cart.rb +1 -0
- data/lib/facet/enumerable/cartesian_product.rb +1 -0
- data/lib/facet/enumerable/self/cart.rb +1 -0
- data/lib/facet/enumerable/self/cartesian_product.rb +1 -0
- data/lib/facets.rb +2 -1
- data/lib/facets/core/dir/self/multiglob_sum.rb +2 -0
- data/lib/facets/core/enumerable/cart.rb +119 -0
- data/lib/facets/core/enumerable/cartesian_product.rb +8 -0
- data/lib/facets/core/enumerable/self/cart.rb +120 -0
- data/lib/facets/core/enumerable/self/cartesian_product.rb +8 -0
- data/lib/facets/core/string/singular.rb +7 -7
- data/lib/facets/more/ann.rb +6 -5
- data/lib/facets/more/ann_attr.rb +11 -14
- data/lib/facets/more/autovivify.rb +2 -2
- data/lib/facets/more/dictionary.rb +63 -69
- data/lib/facets/more/opencascade.rb +3 -3
- data/lib/facets/more/openobject.rb +318 -9
- data/lib/facets/more/times.rb +129 -43
- data/lib/facets/more/uploadutils.rb +248 -43
- data/work/hash_open.rb +23 -0
- data/work/openobject-temp.rb +45 -0
- metadata +13 -9
- data/lib/facet/enumerable/cross.rb +0 -1
- data/lib/facet/enumerable/self/cross.rb +0 -1
- data/lib/facet/openhash.rb +0 -1
- data/lib/facets/core/enumerable/cross.rb +0 -47
- data/lib/facets/core/enumerable/self/cross.rb +0 -85
- data/lib/facets/more/openhash.rb +0 -350
data/lib/facets/more/ann_attr.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# =
|
1
|
+
# = ann_attr.rb
|
2
2
|
#
|
3
3
|
# == Copyright (c) 2005 Thomas Sawyer
|
4
4
|
#
|
@@ -14,6 +14,7 @@
|
|
14
14
|
# == Authors & Contributors
|
15
15
|
#
|
16
16
|
# * Thomas Sawyer
|
17
|
+
# * George Moschovitis
|
17
18
|
|
18
19
|
# Author:: Thomas Sawyer
|
19
20
|
# Copyright:: Copyright (c) 2005 Thomas Sawyer
|
@@ -86,8 +87,9 @@ class ::Module
|
|
86
87
|
}
|
87
88
|
attributes!.concat( args ) #merge!
|
88
89
|
|
89
|
-
|
90
|
-
|
90
|
+
# Use this callback to customize for your needs.
|
91
|
+
if respond_to?(:attr_callback)
|
92
|
+
attr_callback(self, args, harg)
|
91
93
|
end
|
92
94
|
|
93
95
|
# return the names of the attributes created
|
@@ -100,31 +102,26 @@ class ::Module
|
|
100
102
|
|
101
103
|
class_eval( code )
|
102
104
|
|
105
|
+
# TODO Should attribute alias be kept?
|
103
106
|
alias_method :attribute, :attr_accessor
|
104
|
-
alias_method :property, :attr_accessor # for nitro
|
105
107
|
|
106
|
-
# Return
|
107
|
-
# Serializable are attributes with the class annotation that
|
108
|
-
# are not marked as :serializable => false.
|
108
|
+
# Return list of attributes that have a :class annotation.
|
109
109
|
#
|
110
110
|
# class MyClass
|
111
111
|
# attr_accessor :test
|
112
112
|
# attr_accessor :name, String, :doc => 'Hello'
|
113
113
|
# attr_accessor :age, Fixnum
|
114
|
-
# attr_accessor :body, String, :serialize => false
|
115
114
|
# end
|
116
115
|
#
|
117
116
|
# MyClass.attributes # => [:test, :name, :age, :body]
|
118
|
-
# MyClass.
|
117
|
+
# MyClass.classified_attributes # => [:name, :age]
|
119
118
|
|
120
|
-
def
|
121
|
-
attributes.find_all do |a|
|
122
|
-
|
123
|
-
anno.class? and (anno.serialize != false)
|
119
|
+
def classified_attributes
|
120
|
+
attributes.find_all do |a|
|
121
|
+
self.ann(a, :class)
|
124
122
|
end
|
125
123
|
end
|
126
124
|
|
127
|
-
|
128
125
|
end
|
129
126
|
|
130
127
|
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# autovivify.rb
|
2
2
|
|
3
|
-
require 'facets/more/
|
3
|
+
require 'facets/more/openobject.rb'
|
4
4
|
|
5
5
|
# AutoVivify module houses the +method_missing+ defintion.
|
6
6
|
|
7
7
|
module AutoVivify
|
8
8
|
def method_missing( name, *args, &block )
|
9
|
-
oo =
|
9
|
+
oo = OpenObject.new
|
10
10
|
(class << self; self; end).send( :define_method, name ) { oo }
|
11
11
|
end
|
12
12
|
end
|
@@ -18,13 +18,13 @@
|
|
18
18
|
# Thanks to Andrew Johnson for his suggestions and fixes of Hash[],
|
19
19
|
# merge, to_a, inspect and shift.
|
20
20
|
#
|
21
|
-
# == Authors
|
21
|
+
# == Authors & Contributors
|
22
22
|
#
|
23
23
|
# * Jan Molic
|
24
24
|
# * Thomas Sawyer
|
25
25
|
|
26
|
-
# Author:: Jan Molic
|
27
|
-
# Copyright:: Copyright (c) 2006 Jan Molic
|
26
|
+
# Author:: Jan Molic
|
27
|
+
# Copyright:: Copyright (c) 2006 Jan Molic
|
28
28
|
# License:: Ruby License
|
29
29
|
|
30
30
|
# = Dictionary
|
@@ -77,10 +77,11 @@ class Dictionary < Hash
|
|
77
77
|
#--
|
78
78
|
# TODO is this needed? Doesn't the super class do this?
|
79
79
|
#++
|
80
|
+
|
80
81
|
def []( *args )
|
81
82
|
hsh = new
|
82
83
|
if Hash === args[0]
|
83
|
-
hsh.replace(
|
84
|
+
hsh.replace(args[0])
|
84
85
|
elsif (args.size % 2) != 0
|
85
86
|
raise ArgumentError, "odd number of elements for Hash"
|
86
87
|
else
|
@@ -110,7 +111,7 @@ class Dictionary < Hash
|
|
110
111
|
# Dictionary.new.order_by { |key,value| key }
|
111
112
|
|
112
113
|
def alpha( *args, &block )
|
113
|
-
new( *args, &block ).
|
114
|
+
new( *args, &block ).order_by_key
|
114
115
|
end
|
115
116
|
|
116
117
|
# Alternate to #new which auto-creates sub-dictionaries as needed.
|
@@ -118,32 +119,17 @@ class Dictionary < Hash
|
|
118
119
|
# d = Dictionary.auto
|
119
120
|
# d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}}
|
120
121
|
#
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
# Alternate to #new which auto-creates sub-dictionaries as needed.
|
128
|
-
#
|
129
|
-
# d = Dictionary.autokey
|
130
|
-
# d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}}
|
131
|
-
#
|
132
|
-
#def auto_alpha(*args)
|
133
|
-
# auto(*args).order_by{ |k,v| k }
|
134
|
-
# #AutoDictionary.new(*args).order_by{ |k,v| k }
|
135
|
-
# #leet = lambda { |hsh, key| hsh[key] = new( &leet ) }
|
136
|
-
# #new(*args, &leet).order_by{ |k,v| k }
|
137
|
-
#end
|
138
|
-
|
122
|
+
def auto( *args )
|
123
|
+
#AutoDictionary.new(*args)
|
124
|
+
leet = lambda { |hsh, key| hsh[key] = new( &leet ) }
|
125
|
+
new(*args, &leet)
|
126
|
+
end
|
139
127
|
end
|
140
128
|
|
141
|
-
attr_accessor :order
|
142
|
-
|
143
129
|
def initialize( *args, &blk )
|
144
130
|
@order = []
|
145
131
|
@order_by = nil
|
146
|
-
|
132
|
+
@hash = Hash.new( *args, &blk )
|
147
133
|
end
|
148
134
|
|
149
135
|
def order
|
@@ -151,7 +137,7 @@ class Dictionary < Hash
|
|
151
137
|
@order
|
152
138
|
end
|
153
139
|
|
154
|
-
# Keep dictionary sorted by
|
140
|
+
# Keep dictionary sorted by a specific sort order.
|
155
141
|
|
156
142
|
def order_by( &block )
|
157
143
|
@order_by = block
|
@@ -161,7 +147,7 @@ class Dictionary < Hash
|
|
161
147
|
|
162
148
|
# Keep dictionary sorted by key.
|
163
149
|
#
|
164
|
-
# d = Dictionary.new.
|
150
|
+
# d = Dictionary.new.order_by_key
|
165
151
|
# d["z"] = 1
|
166
152
|
# d["y"] = 2
|
167
153
|
# d["x"] = 3
|
@@ -173,7 +159,7 @@ class Dictionary < Hash
|
|
173
159
|
#
|
174
160
|
# The initializer Dictionary#alpha also provides this.
|
175
161
|
|
176
|
-
def
|
162
|
+
def order_by_key
|
177
163
|
@order_by = lambda { |k,v| k }
|
178
164
|
order
|
179
165
|
self
|
@@ -181,7 +167,7 @@ class Dictionary < Hash
|
|
181
167
|
|
182
168
|
# Keep dictionary sorted by value.
|
183
169
|
#
|
184
|
-
# d = Dictionary.
|
170
|
+
# d = Dictionary.new.order_by_value
|
185
171
|
# d["z"] = 1
|
186
172
|
# d["y"] = 2
|
187
173
|
# d["x"] = 3
|
@@ -191,7 +177,7 @@ class Dictionary < Hash
|
|
191
177
|
#
|
192
178
|
# Dictionary.new.order_by { |key,value| value }
|
193
179
|
|
194
|
-
def
|
180
|
+
def order_by_value
|
195
181
|
@order_by = lambda { |k,v| v }
|
196
182
|
order
|
197
183
|
self
|
@@ -201,31 +187,32 @@ class Dictionary < Hash
|
|
201
187
|
|
202
188
|
def reorder
|
203
189
|
if @order_by
|
204
|
-
assoc = @order.collect{ |k| [k
|
190
|
+
assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by( &@order_by )
|
205
191
|
@order = assoc.collect{ |k,v| k }
|
206
192
|
end
|
207
193
|
@order
|
208
194
|
end
|
209
195
|
|
210
|
-
#def
|
211
|
-
#
|
196
|
+
#def ==( hsh2 )
|
197
|
+
# return false if @order != hsh2.order
|
198
|
+
# super hsh2
|
212
199
|
#end
|
213
|
-
#alias_method :store_only, :store
|
214
|
-
|
215
|
-
alias_method :orig_store, :store
|
216
|
-
protected :orig_store
|
217
200
|
|
218
|
-
def
|
219
|
-
|
220
|
-
|
201
|
+
def ==( hsh2 )
|
202
|
+
if hsh2.is_a?( Dictionary )
|
203
|
+
@order == hsh2.order &&
|
204
|
+
@hash == hsh2.instance_variable_get("@hash")
|
205
|
+
else
|
206
|
+
false
|
207
|
+
end
|
221
208
|
end
|
222
209
|
|
223
|
-
|
224
|
-
|
210
|
+
def [] k
|
211
|
+
@hash[ k ]
|
212
|
+
end
|
225
213
|
|
226
|
-
def
|
227
|
-
@
|
228
|
-
super( a,b )
|
214
|
+
def fetch( k )
|
215
|
+
@hash.fetch( k )
|
229
216
|
end
|
230
217
|
|
231
218
|
# Store operator.
|
@@ -244,21 +231,24 @@ class Dictionary < Hash
|
|
244
231
|
end
|
245
232
|
end
|
246
233
|
|
247
|
-
|
234
|
+
def insert( i,k,v )
|
235
|
+
@order.insert( i,k )
|
236
|
+
@hash.store( k,v )
|
237
|
+
end
|
248
238
|
|
249
|
-
def
|
250
|
-
|
251
|
-
|
239
|
+
def store( a,b )
|
240
|
+
@order.push( a ) unless @hash.has_key?( a )
|
241
|
+
@hash.store( a,b )
|
252
242
|
end
|
253
243
|
|
254
244
|
def clear
|
255
245
|
@order = []
|
256
|
-
|
246
|
+
@hash.clear
|
257
247
|
end
|
258
248
|
|
259
249
|
def delete( key )
|
260
|
-
@order.delete key
|
261
|
-
|
250
|
+
@order.delete( key )
|
251
|
+
@hash.delete( key )
|
262
252
|
end
|
263
253
|
|
264
254
|
def each_key
|
@@ -267,14 +257,12 @@ class Dictionary < Hash
|
|
267
257
|
end
|
268
258
|
|
269
259
|
def each_value
|
270
|
-
order.each { |k| yield(
|
260
|
+
order.each { |k| yield( @hash[k] ) }
|
271
261
|
self
|
272
262
|
end
|
273
263
|
|
274
|
-
#alias_method :unordered_each, :each
|
275
|
-
|
276
264
|
def each
|
277
|
-
order.each { |k| yield( k
|
265
|
+
order.each { |k| yield( k,@hash[k] ) }
|
278
266
|
self
|
279
267
|
end
|
280
268
|
alias each_pair each
|
@@ -286,7 +274,7 @@ class Dictionary < Hash
|
|
286
274
|
|
287
275
|
def values
|
288
276
|
ary = []
|
289
|
-
order.each { |k| ary.push
|
277
|
+
order.each { |k| ary.push @hash[k] }
|
290
278
|
ary
|
291
279
|
end
|
292
280
|
|
@@ -296,7 +284,7 @@ class Dictionary < Hash
|
|
296
284
|
|
297
285
|
def invert
|
298
286
|
hsh2 = self.class.new
|
299
|
-
order.each { |k| hsh2[
|
287
|
+
order.each { |k| hsh2[@hash[k]] = k }
|
300
288
|
hsh2
|
301
289
|
end
|
302
290
|
|
@@ -310,8 +298,8 @@ class Dictionary < Hash
|
|
310
298
|
end
|
311
299
|
|
312
300
|
def replace( hsh2 )
|
313
|
-
@order = hsh2.
|
314
|
-
|
301
|
+
@order = hsh2.order
|
302
|
+
@hash = hsh2.hash
|
315
303
|
end
|
316
304
|
|
317
305
|
def shift
|
@@ -320,9 +308,9 @@ class Dictionary < Hash
|
|
320
308
|
end
|
321
309
|
|
322
310
|
def unshift( k,v )
|
323
|
-
unless
|
324
|
-
@order.unshift k
|
325
|
-
|
311
|
+
unless @hash.include?( k )
|
312
|
+
@order.unshift( k )
|
313
|
+
@hash.store( k,v )
|
326
314
|
true
|
327
315
|
else
|
328
316
|
false
|
@@ -334,9 +322,9 @@ class Dictionary < Hash
|
|
334
322
|
end
|
335
323
|
|
336
324
|
def push( k,v )
|
337
|
-
unless
|
338
|
-
@order.push k
|
339
|
-
|
325
|
+
unless @hash.include?( k )
|
326
|
+
@order.push( k )
|
327
|
+
@hash.store( k,v )
|
340
328
|
true
|
341
329
|
else
|
342
330
|
false
|
@@ -386,16 +374,22 @@ class Dictionary < Hash
|
|
386
374
|
end
|
387
375
|
|
388
376
|
def first
|
389
|
-
|
377
|
+
@hash[order.first]
|
390
378
|
end
|
391
379
|
|
392
380
|
def last
|
393
|
-
|
381
|
+
@hash[order.last]
|
394
382
|
end
|
395
383
|
|
384
|
+
def length
|
385
|
+
@order.length
|
386
|
+
end
|
387
|
+
alias :size :length
|
388
|
+
|
396
389
|
end
|
397
390
|
|
398
391
|
|
392
|
+
|
399
393
|
# _____ _
|
400
394
|
# |_ _|__ ___| |_
|
401
395
|
# | |/ _ \/ __| __|
|
@@ -33,12 +33,12 @@
|
|
33
33
|
# License:: Ruby License
|
34
34
|
|
35
35
|
require 'facets/core/kernel/bool.rb'
|
36
|
-
require 'facets/more/
|
36
|
+
require 'facets/more/openobject.rb'
|
37
37
|
#require 'facets/more/nullclass'
|
38
38
|
|
39
39
|
# = OpenCascade
|
40
40
|
#
|
41
|
-
# OpenCascade is subclass of
|
41
|
+
# OpenCascade is subclass of OpenObject. It differs in a few
|
42
42
|
# significant ways.
|
43
43
|
#
|
44
44
|
# The main reason this class is labeled "cascade", every internal
|
@@ -65,7 +65,7 @@ require 'facets/more/openhash.rb'
|
|
65
65
|
# So be sure to take that into account.
|
66
66
|
#++
|
67
67
|
|
68
|
-
class OpenCascade <
|
68
|
+
class OpenCascade < OpenObject
|
69
69
|
|
70
70
|
def method_missing( sym, arg=nil )
|
71
71
|
type = sym.to_s[-1,1]
|
@@ -1,13 +1,200 @@
|
|
1
|
-
#
|
1
|
+
# = openobject.rb
|
2
|
+
#
|
3
|
+
# == Copyright (c) 2005,2006 Thomas Sawyer
|
4
|
+
#
|
5
|
+
# Ruby License
|
6
|
+
#
|
7
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
8
|
+
# software under the same terms as Ruby.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
12
|
+
# FOR A PARTICULAR PURPOSE.
|
13
|
+
#
|
14
|
+
# == Authors and Contributors
|
15
|
+
#
|
16
|
+
# * Thomas Sawyer
|
17
|
+
# * George Moschovitis
|
2
18
|
|
3
|
-
|
19
|
+
# Author:: Thomas Sawyer
|
20
|
+
# Copyright:: Copyright (c) 2005 Thomas Sawyer
|
21
|
+
# License:: Ruby License
|
4
22
|
|
5
|
-
|
23
|
+
require 'facets/core/hash/to_h'
|
24
|
+
require 'facets/core/hash/to_proc'
|
25
|
+
require 'facets/core/kernel/object_class'
|
26
|
+
require 'facets/core/kernel/object_hexid'
|
27
|
+
|
28
|
+
# = OpenObject
|
29
|
+
#
|
30
|
+
# OpenObject is similar to OpenStruct, but differs in a couple ways.
|
31
|
+
#
|
32
|
+
# OpenObject is a subclass of Hash and can do just about everything
|
33
|
+
# a Hash can do, except that most public methods have been made
|
34
|
+
# protected and thus only available internally or via #send.
|
35
|
+
# A small number, like #each are still exposed publically though
|
36
|
+
# b/c of their importance.
|
37
|
+
#
|
38
|
+
# OpenObject will also clobber any method for which a slot is defined.
|
39
|
+
# Even generally very important methods can be clobbered, like
|
40
|
+
# instance_eval. So be careful. OpenObject should be used in highly
|
41
|
+
# controlled scenarios. If you want to pass one off to an "unknown"
|
42
|
+
# rountine, it is best to convert it to a Hash first and convert it
|
43
|
+
# back to an OpenObject when finished. To facilitate this the method
|
44
|
+
# #as_hash! is provided.
|
45
|
+
#
|
46
|
+
# o = OpenObject.new(:a=>1,:b=>2)
|
47
|
+
# o.as_hash!{ |h| h.update(:a=>6) }
|
48
|
+
# o #=> #<OpenObject {:a=>6,:b=>2}>
|
49
|
+
#
|
50
|
+
# Finally, unlike a regular Hash, all OpenObject's keys are symbols and
|
51
|
+
# all keys are converted to such using #to_sym on the fly.
|
52
|
+
|
53
|
+
class OpenObject < Hash
|
54
|
+
|
55
|
+
PUBLIC_METHODS = /(^__|^instance_|^object_|^\W|^as$|^send$|^class$|\?$)/
|
56
|
+
|
57
|
+
protected *public_instance_methods.select{ |m| m !~ PUBLIC_METHODS }
|
58
|
+
|
59
|
+
def self.[](hash=nil)
|
60
|
+
new(hash)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Inititalizer for OpenObject is slightly differnt than that of Hash.
|
64
|
+
# It does not take a default parameter, but an initial priming Hash
|
65
|
+
# as with OpenStruct. The initializer can still take a default block
|
66
|
+
# however. To set the degault value use ++#default!(value)++.
|
67
|
+
#
|
68
|
+
# OpenObject(:a=>1).default!(0)
|
69
|
+
|
70
|
+
def initialize( hash=nil, &yld )
|
71
|
+
super( &yld )
|
72
|
+
hash.each { |k,v| define_slot(k,v) } if hash
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize_copy( orig )
|
76
|
+
orig.each { |k,v| define_slot(k,v) }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Object inspection. (Careful, this can be clobbered!)
|
80
|
+
|
81
|
+
def inspect
|
82
|
+
"#<#{object_class}:#{object_hexid} #{super}>"
|
83
|
+
end
|
84
|
+
|
85
|
+
# Conversion methods. (Careful, these can be clobbered!)
|
86
|
+
|
87
|
+
def to_a() super end
|
88
|
+
|
89
|
+
def to_h() {}.update(self) end
|
90
|
+
def to_hash() {}.update(self) end
|
91
|
+
|
92
|
+
def to_proc() super end
|
93
|
+
|
94
|
+
def to_openobject() self end
|
95
|
+
|
96
|
+
# Iterate over each key-value pair. (Careful, this can be clobbered!)
|
97
|
+
|
98
|
+
def each(&yld) super(&yld) end
|
99
|
+
|
100
|
+
# Merge one OpenObject with another creating a new OpenObject.
|
101
|
+
|
102
|
+
def merge( other )
|
103
|
+
d = dup
|
104
|
+
d.send(:update, other)
|
105
|
+
d
|
106
|
+
end
|
107
|
+
|
108
|
+
# Update this OpenObject with another.
|
109
|
+
|
110
|
+
def update( other )
|
111
|
+
begin
|
112
|
+
other.each { |k,v| define_slot(k,v) }
|
113
|
+
rescue
|
114
|
+
other = other.to_h
|
115
|
+
retry
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
|
121
|
+
def delete(key)
|
122
|
+
super(key.to_sym)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Set the default value.
|
126
|
+
|
127
|
+
def default!(default)
|
128
|
+
self.default = default
|
129
|
+
end
|
130
|
+
|
131
|
+
# Preform inplace action on OpenObject as if it were a regular Hash.
|
132
|
+
#--
|
133
|
+
# TODO Not so sure about #as_hash!. For starters if it doesn't return a hash it will fail.
|
134
|
+
# TODO Replace by using #as(Hash). Perhaps as_hash and as_object shortcuts? Why?
|
135
|
+
#++
|
136
|
+
|
137
|
+
def as_hash!(&yld)
|
138
|
+
replace(yld.call(to_hash))
|
139
|
+
end
|
140
|
+
|
141
|
+
# Check equality. (Should equal be true for Hash too?)
|
142
|
+
|
143
|
+
def ==( other )
|
144
|
+
return false unless OpenObject === other
|
145
|
+
super(other) #(other.send(:table))
|
146
|
+
end
|
147
|
+
|
148
|
+
def []=(k,v)
|
149
|
+
protect_slot(k)
|
150
|
+
super(k.to_sym,v)
|
151
|
+
end
|
152
|
+
|
153
|
+
def [](k)
|
154
|
+
super(k.to_sym)
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
|
159
|
+
def store(k,v)
|
160
|
+
super(k.to_sym,v)
|
161
|
+
define_slot(k)
|
162
|
+
end
|
163
|
+
|
164
|
+
def fetch(k,*d,&b)
|
165
|
+
super(k.to_sym,*d,&b)
|
166
|
+
end
|
167
|
+
|
168
|
+
def define_slot( key, value=nil )
|
169
|
+
protect_slot( key )
|
170
|
+
self[key.to_sym] = value
|
171
|
+
end
|
172
|
+
|
173
|
+
def protect_slot( key )
|
174
|
+
(class << self; self; end).class_eval {
|
175
|
+
protected key rescue nil
|
176
|
+
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def method_missing( sym, arg=nil, &blk)
|
180
|
+
type = sym.to_s[-1,1]
|
181
|
+
key = sym.to_s.sub(/[=?!]$/,'').to_sym
|
182
|
+
if type == '='
|
183
|
+
define_slot(key,arg)
|
184
|
+
elsif type == '!'
|
185
|
+
define_slot(key,arg)
|
186
|
+
self
|
187
|
+
else
|
188
|
+
self[key]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
6
193
|
|
7
194
|
# Core Extensions
|
8
195
|
|
9
196
|
class NilClass
|
10
|
-
# Nil converts to an empty
|
197
|
+
# Nil converts to an empty OpenObject.
|
11
198
|
|
12
199
|
def to_openobject
|
13
200
|
OpenObject.new
|
@@ -15,7 +202,7 @@ class NilClass
|
|
15
202
|
end
|
16
203
|
|
17
204
|
class Hash
|
18
|
-
# Convert a Hash into an
|
205
|
+
# Convert a Hash into an OpenObject.
|
19
206
|
|
20
207
|
def to_openobject
|
21
208
|
OpenObject[self]
|
@@ -23,23 +210,145 @@ class Hash
|
|
23
210
|
end
|
24
211
|
|
25
212
|
class Proc
|
26
|
-
# Translates a Proc into an
|
213
|
+
# Translates a Proc into an OpenObject. By droping an OpenObject into
|
27
214
|
# the Proc, the resulting assignments incured as the procedure is
|
28
|
-
# evaluated produce the
|
215
|
+
# evaluated produce the OpenObject. This technique is simlar to that
|
29
216
|
# of MethodProbe.
|
30
217
|
#
|
31
218
|
# p = lambda { |x|
|
32
219
|
# x.word = "Hello"
|
33
220
|
# }
|
34
|
-
# o = p.
|
221
|
+
# o = p.to_openobject
|
35
222
|
# o.word #=> "Hello"
|
36
223
|
#
|
37
224
|
# NOTE The Proc must have an arity of one --no more and no less.
|
38
225
|
|
39
226
|
def to_openobject
|
40
|
-
raise ArgumentError, 'bad arity for converting Proc to
|
227
|
+
raise ArgumentError, 'bad arity for converting Proc to openobject' if arity != 1
|
41
228
|
o = OpenObject.new
|
42
229
|
self.call( o )
|
43
230
|
o
|
44
231
|
end
|
45
232
|
end
|
233
|
+
|
234
|
+
|
235
|
+
# _____ _
|
236
|
+
# |_ _|__ ___| |_
|
237
|
+
# | |/ _ \/ __| __|
|
238
|
+
# | | __/\__ \ |_
|
239
|
+
# |_|\___||___/\__|
|
240
|
+
#
|
241
|
+
|
242
|
+
=begin testing
|
243
|
+
|
244
|
+
require 'test/unit'
|
245
|
+
|
246
|
+
class TestOpenObject1 < Test::Unit::TestCase
|
247
|
+
|
248
|
+
def test_1_01
|
249
|
+
o = OpenObject.new
|
250
|
+
assert( o.respond_to?(:key?) )
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_1_02
|
254
|
+
assert_instance_of( OpenObject, OpenObject[{}] )
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_1_03
|
258
|
+
f0 = OpenObject.new
|
259
|
+
f0[:a] = 1
|
260
|
+
#assert_equal( [1], f0.to_a )
|
261
|
+
assert_equal( {:a=>1}, f0.to_h )
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_1_04
|
265
|
+
f0 = OpenObject[:a=>1]
|
266
|
+
f0[:b] = 2
|
267
|
+
assert_equal( {:a=>1,:b=>2}, f0.to_h )
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_1_05
|
271
|
+
f0 = OpenObject[:class=>1]
|
272
|
+
assert_equal( 1, f0.class )
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
class TestOpenObject2 < Test::Unit::TestCase
|
277
|
+
|
278
|
+
def test_2_01
|
279
|
+
f0 = OpenObject[:f0=>"f0"]
|
280
|
+
h0 = { :h0=>"h0" }
|
281
|
+
assert_equal( OpenObject[:f0=>"f0", :h0=>"h0"], f0.send(:merge,h0) )
|
282
|
+
assert_equal( {:f0=>"f0", :h0=>"h0"}, h0.merge( f0 ) )
|
283
|
+
end
|
284
|
+
|
285
|
+
def test_2_02
|
286
|
+
f1 = OpenObject[:f1=>"f1"]
|
287
|
+
h1 = { :h1=>"h1" }
|
288
|
+
f1.send(:update,h1)
|
289
|
+
h1.update( f1 )
|
290
|
+
assert_equal( OpenObject[:f1=>"f1", :h1=>"h1"], f1 )
|
291
|
+
assert_equal( {:f1=>"f1", :h1=>"h1"}, h1 )
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_2_03
|
295
|
+
o = OpenObject[:a=>1,:b=>{:x=>9}]
|
296
|
+
assert_equal( 9, o[:b][:x] )
|
297
|
+
assert_equal( 9, o.b[:x] )
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_2_04
|
301
|
+
o = OpenObject["a"=>1,"b"=>{:x=>9}]
|
302
|
+
assert_equal( 1, o["a"] )
|
303
|
+
assert_equal( 1, o[:a] )
|
304
|
+
assert_equal( {:x=>9}, o["b"] )
|
305
|
+
assert_equal( {:x=>9}, o[:b] )
|
306
|
+
assert_equal( 9, o["b"][:x] )
|
307
|
+
assert_equal( nil, o[:b]["x"] )
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
class TestOpenObject3 < Test::Unit::TestCase
|
313
|
+
def test_3_01
|
314
|
+
fo = OpenObject.new
|
315
|
+
9.times{ |i| fo.send( "n#{i}=", 1 ) }
|
316
|
+
9.times{ |i|
|
317
|
+
assert_equal( 1, fo.send( "n#{i}" ) )
|
318
|
+
}
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
class TestOpenObject4 < Test::Unit::TestCase
|
323
|
+
|
324
|
+
def test_4_01
|
325
|
+
ho = {}
|
326
|
+
fo = OpenObject.new
|
327
|
+
5.times{ |i| ho["n#{i}".to_sym]=1 }
|
328
|
+
5.times{ |i| fo.send( "n#{i}=", 1 ) }
|
329
|
+
assert_equal(ho, fo.to_h)
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
class TestOpenObject5 < Test::Unit::TestCase
|
335
|
+
|
336
|
+
def test_5_01
|
337
|
+
p = lambda { |x|
|
338
|
+
x.word = "Hello"
|
339
|
+
}
|
340
|
+
o = p.to_openobjrct
|
341
|
+
assert_equal( "Hello", o.word )
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_5_02
|
345
|
+
p = lambda { |x|
|
346
|
+
x.word = "Hello"
|
347
|
+
}
|
348
|
+
o = OpenObject[:a=>1,:b=>2]
|
349
|
+
assert_instance_of( Proc, o.to_proc )
|
350
|
+
end
|
351
|
+
|
352
|
+
end
|
353
|
+
|
354
|
+
=end
|