Ron 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +28 -2
- data/Makefile +19 -8
- data/lib/ron.rb +87 -49
- data/lib/ron/column_order.rb +1 -1
- data/lib/ron/float_accurate_to_s.rb +168 -0
- data/lib/ron/graphedge.rb +86 -16
- data/lib/ron/version.rb +1 -1
- data/ron.gemspec +13 -12
- data/test/test_all.rb +110 -37
- data/test/test_graphcopy.rb +42 -0
- metadata +4 -5
- data/Manifest.txt +0 -9
- data/Rakefile +0 -37
data/History.txt
CHANGED
@@ -1,4 +1,30 @@
|
|
1
|
-
=== 0.1.
|
1
|
+
=== 0.1.2 / 21dec2009
|
2
|
+
* 5 Major Bugfixes:
|
3
|
+
* preserve modules an object was extended by
|
4
|
+
* (but not Recursive, which is an artifact of using ron)
|
5
|
+
* single quote and backslash now handled right in String
|
6
|
+
* all significant digits now preserved in Float (really)
|
7
|
+
* many small improvements to object graph copying (see below)
|
8
|
+
* ported to MRI 1.9
|
9
|
+
|
10
|
+
* 2 Minor Bugfixes:
|
11
|
+
* preserve classes of descendants Regexp, Range, Array and Hash
|
12
|
+
* many changes to tests to improve coverage and correctness
|
13
|
+
* also, tests now work around bugs in yaml
|
14
|
+
|
15
|
+
* 1 Minor Enhancement:
|
16
|
+
* reworked build/gem scripts
|
17
|
+
|
18
|
+
* Improvements to object graph copying:
|
19
|
+
* depth-first copying is now available
|
20
|
+
* call may pass in a hash of objects to replace
|
21
|
+
* replacements when parent is nil or false are now an error
|
22
|
+
* protect against changes to hash, set, or array during traversal
|
23
|
+
* avoid inf-loop if replacing item with many items
|
24
|
+
* now possible to replace an object with another that contains the first
|
25
|
+
* in depth_graphcopy, delay all changes til right before the end
|
26
|
+
|
27
|
+
=== 0.1.1 / 5aug2009
|
2
28
|
* 1 Major Enhancement:
|
3
29
|
* significant improvements and bugfixes in graphcopy
|
4
30
|
|
@@ -7,7 +33,7 @@
|
|
7
33
|
* ported to ruby 1.9
|
8
34
|
* rewrote Class#- to be more compatible with Reg
|
9
35
|
|
10
|
-
=== 0.1.0 /
|
36
|
+
=== 0.1.0 / 7oct2006
|
11
37
|
|
12
38
|
* 1 major enhancement
|
13
39
|
* Birthday!
|
data/Makefile
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
name=Ron
|
2
|
+
lname=ron
|
3
|
+
gemname=Ron
|
4
|
+
|
5
|
+
#everything after this line is generic
|
6
|
+
|
7
|
+
version=$(shell ruby -r ./lib/$(lname)/version.rb -e "puts $(name)::VERSION")
|
8
|
+
filelist=$(shell git ls-files)
|
9
|
+
|
1
10
|
.PHONY: all test docs gem tar pkg email
|
2
11
|
all: test
|
3
12
|
|
@@ -10,23 +19,25 @@ docs:
|
|
10
19
|
pkg: gem tar
|
11
20
|
|
12
21
|
gem:
|
13
|
-
gem build
|
22
|
+
gem build $(lname).gemspec
|
14
23
|
|
15
24
|
tar:
|
16
|
-
tar
|
25
|
+
tar cf - $(filelist) | ( mkdir $(gemname)-$(version); cd $(gemname)-$(version); tar xf - )
|
26
|
+
tar czf $(gemname)-$(version).tar.gz $(gemname)-$(version)
|
27
|
+
rm -rf $(gemname)-$(version)
|
17
28
|
|
18
29
|
email: README.txt History.txt
|
19
30
|
ruby -e ' \
|
20
31
|
require "rubygems"; \
|
21
|
-
load "
|
22
|
-
spec= Gem::Specification.list.find{|x| x.name=="
|
32
|
+
load "./$(lname).gemspec"; \
|
33
|
+
spec= Gem::Specification.list.find{|x| x.name=="$(gemname)"}; \
|
23
34
|
puts "\
|
24
|
-
Subject: [ANN]
|
25
|
-
\n\
|
35
|
+
Subject: [ANN] $(name) #{spec.version} Released \
|
36
|
+
\n\n$(name) version #{spec.version} has been released! \n\n\
|
26
37
|
#{Array(spec.homepage).map{|url| " * #{url}\n" }} \
|
27
38
|
\n\
|
28
|
-
#{
|
39
|
+
#{$(name)::Description} \
|
29
40
|
\n\nChanges:\n\n \
|
30
|
-
#{
|
41
|
+
#{$(name)::Latest_changes} \
|
31
42
|
"\
|
32
43
|
'
|
data/lib/ron.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#require 'warning'
|
5
5
|
require 'ron/graphedge'
|
6
6
|
require 'continuation' unless defined? Continuation
|
7
|
+
require 'ron/float_accurate_to_s'
|
7
8
|
|
8
9
|
#to_ron
|
9
10
|
|
@@ -41,8 +42,15 @@ module Ron
|
|
41
42
|
def self.load str
|
42
43
|
eval str
|
43
44
|
end
|
45
|
+
|
46
|
+
def self.extension_modules_of(obj)
|
47
|
+
ancs=class<<obj; ancestors end
|
48
|
+
ancs=ancs[0...ancs.index(obj.class)]
|
49
|
+
return ancs
|
50
|
+
rescue TypeError
|
51
|
+
return []
|
52
|
+
end
|
44
53
|
|
45
|
-
CaptureCtx=[]
|
46
54
|
=begin
|
47
55
|
def self.recurse_safe_objects_equal?(o1,o2,session={})
|
48
56
|
pair=[o1.__id__,o2.__id__]
|
@@ -51,13 +59,13 @@ module Ron
|
|
51
59
|
|
52
60
|
o1.class==o2.class and
|
53
61
|
case o1
|
54
|
-
when Array
|
62
|
+
when Array
|
55
63
|
o1.size==o2.size and
|
56
64
|
o1.each_with_index{|i1,idx|
|
57
65
|
recurse_safe_objects_equal?(i1,o2[idx],session) or return
|
58
66
|
}
|
59
67
|
|
60
|
-
when Hash
|
68
|
+
when Hash
|
61
69
|
#oops, this depends on #== and #hash working right for recursive structures, which they don't.
|
62
70
|
o1.size==o2.size or return
|
63
71
|
recurse_safe_objects_equal? o1.default,o2.default,session or return
|
@@ -65,28 +73,28 @@ module Ron
|
|
65
73
|
return unless (o2.key? idx and recurse_safe_objects_equal? i1, o2[idx],session)
|
66
74
|
}
|
67
75
|
|
68
|
-
when Range
|
76
|
+
when Range
|
69
77
|
o1.exclude_end?()==o2.exclude_end?() and
|
70
78
|
recurse_safe_objects_equal? o1.begin, o2.begin,session and
|
71
79
|
recurse_safe_objects_equal? o1.end, o2.end,session
|
72
80
|
|
73
|
-
when Struct
|
81
|
+
when Struct
|
74
82
|
(mems=o1.members).size==o2.members.size and
|
75
83
|
mems.each{|i|
|
76
84
|
recurse_safe_objects_equal? o1[i], (o2[i] rescue return),session or return
|
77
85
|
}
|
78
|
-
when Binding
|
86
|
+
when Binding
|
79
87
|
recurse_safe_objects_equal? o1.to_h, o2.to_h, session
|
80
|
-
when Proc,Integer,Float,String
|
88
|
+
when Proc,Integer,Float,String
|
81
89
|
o1==o2
|
82
90
|
when Thread,ThreadGroup,Process,IO,Symbol,
|
83
|
-
Continuation,Class,Module
|
91
|
+
Continuation,Class,Module
|
84
92
|
return o1.equal?(o2)
|
85
|
-
when Exception
|
93
|
+
when Exception
|
86
94
|
o1.message==o2.message
|
87
|
-
when MatchData
|
95
|
+
when MatchData
|
88
96
|
o1.to_a==o2.to_a
|
89
|
-
when Time
|
97
|
+
when Time
|
90
98
|
o1.eql? o2
|
91
99
|
else true
|
92
100
|
end and
|
@@ -142,40 +150,65 @@ end
|
|
142
150
|
[Fixnum,NilClass,FalseClass,TrueClass,Symbol].each{|k|
|
143
151
|
k.class_eval{ alias to_ron inspect; undef to_ron_list }
|
144
152
|
}
|
145
|
-
|
146
|
-
|
147
|
-
|
153
|
+
|
154
|
+
class Bignum
|
155
|
+
def to_ron_list(session) [inspect] end
|
156
|
+
end
|
157
|
+
|
158
|
+
class Float
|
159
|
+
def to_ron_list(session)
|
160
|
+
[accurate_to_s]
|
161
|
+
end
|
162
|
+
end
|
148
163
|
|
149
164
|
class String
|
150
165
|
def to_ron_list session
|
151
|
-
|
152
|
-
|
166
|
+
result= [ "'", gsub(/['\\]/){ '\\'+$&}, "'" ]
|
167
|
+
if self.class!=String
|
168
|
+
result=[self.class.name, ".new(", result, ")"]
|
169
|
+
end
|
170
|
+
result
|
153
171
|
end
|
154
172
|
end
|
155
173
|
|
156
174
|
class Regexp
|
157
175
|
def to_ron_list session
|
158
|
-
|
159
|
-
|
176
|
+
if self.class==Regexp
|
177
|
+
[ inspect ]
|
178
|
+
else
|
179
|
+
[self.class.name, ".new(", self.source.inspect, ")"]
|
180
|
+
end
|
160
181
|
end
|
161
182
|
end
|
162
183
|
|
163
184
|
class Array
|
164
185
|
def to_ron_list session
|
165
|
-
["["] +
|
186
|
+
result=["["] +
|
166
187
|
map{|i|
|
167
188
|
i.to_ron_list2(session)<<', '
|
168
189
|
}.flatten<<
|
169
190
|
"]"
|
191
|
+
result.unshift self.class.name unless self.class==Array
|
192
|
+
result
|
170
193
|
end
|
171
194
|
end
|
172
195
|
|
173
196
|
class Hash
|
174
197
|
def to_ron_list session
|
175
|
-
|
176
|
-
|
198
|
+
if self.class==Hash
|
199
|
+
leader="{"
|
200
|
+
trailer="}"
|
201
|
+
sep="=>"
|
202
|
+
else
|
203
|
+
leader=self.class.name+"["
|
204
|
+
trailer="]"
|
205
|
+
sep=","
|
206
|
+
end
|
207
|
+
|
208
|
+
[leader]+map{|k,v|
|
209
|
+
Array(k.to_ron_list2(session)).push sep,
|
177
210
|
v.to_ron_list2(session)<<', '
|
178
|
-
}.flatten<<
|
211
|
+
}.flatten<<trailer
|
179
212
|
end
|
180
213
|
end
|
181
214
|
|
@@ -185,7 +218,7 @@ class Object
|
|
185
218
|
#warning "additional modules not handled"
|
186
219
|
#warning "prettified output not supported"
|
187
220
|
|
188
|
-
to_ron_list2.
|
221
|
+
to_ron_list2.join
|
189
222
|
end
|
190
223
|
|
191
224
|
def to_ron_list session
|
@@ -225,13 +258,21 @@ class Object
|
|
225
258
|
result=to_ron_list(session).unshift str
|
226
259
|
if result.last=="}#end object literal"
|
227
260
|
result.last.replace "}"
|
261
|
+
was_obj_syntax=true
|
228
262
|
else
|
229
263
|
#append instance_eval
|
230
|
-
ivars=instance_variables
|
264
|
+
ivars=instance_variables
|
265
|
+
ivars.map!{|iv| iv.to_s } if Symbol===ivars.first
|
266
|
+
ivars-=::Ron::IGNORED_INSTANCE_VARIABLES[self.class.name]
|
231
267
|
ivars.empty? or result.push ".with_ivars(", *ivars.map{|iv|
|
232
268
|
[":",iv.to_s,"=>",instance_variable_get(iv).to_ron_list2(session),', ']
|
233
269
|
}.flatten[0...-1]<<")"
|
234
270
|
end
|
271
|
+
extensions=Ron::extension_modules_of(self)
|
272
|
+
unless extensions.empty?
|
273
|
+
result=["(",result,")"] if was_obj_syntax
|
274
|
+
result.push ".extend(",extensions,")"
|
275
|
+
end
|
235
276
|
result.push ")" if str[/^Recursive\(/]
|
236
277
|
session.objects_seen[__id__]=[session.objects_in_progress.pop[1]]
|
237
278
|
result
|
@@ -268,7 +309,7 @@ Ron::IGNORED_INSTANCE_VARIABLES["Sequence::WeakRefSet"]=%w[@ids]
|
|
268
309
|
class Range
|
269
310
|
def to_ron_list session
|
270
311
|
# result=
|
271
|
-
["
|
312
|
+
[self.class.name, ".new(",first.to_ron_list2(session), ", ",
|
272
313
|
last.to_ron_list2(session),
|
273
314
|
(", true" if exclude_end?),
|
274
315
|
")"
|
@@ -301,7 +342,7 @@ class Binding
|
|
301
342
|
l<<"self"
|
302
343
|
h={}
|
303
344
|
l.each{|i| h[i.to_sym]=Kernel::eval i, self }
|
304
|
-
h[:yield]=Kernel::eval "block_given? and proc{|*
|
345
|
+
h[:yield]=Kernel::eval "block_given? and proc{|*a__| #,&b__\n yield(*a__) #,&b__\n}", self
|
305
346
|
h
|
306
347
|
end
|
307
348
|
|
@@ -316,17 +357,17 @@ class Binding
|
|
316
357
|
keys.empty? or
|
317
358
|
code=keys.map{|k|
|
318
359
|
k.to_s
|
319
|
-
}.join(',')+'
|
360
|
+
}.join(',')+',=*Thread.current[:$__Ron__CaptureCtx]'
|
320
361
|
mname="Ron__capture_binding#{Thread.current.object_id}" #unlikely method name
|
321
|
-
newmname=result=nil
|
362
|
+
oldmname=newmname=result=nil
|
322
363
|
|
323
364
|
eval "
|
324
|
-
Thread.critical=true
|
325
365
|
newmname=class<<the_self;
|
326
366
|
mname=oldmname='#{mname}'
|
327
|
-
im=instance_methods
|
367
|
+
im=instance_methods
|
368
|
+
im.map!{|sym| sym.to_s} if Symbol===im.first
|
328
369
|
mname+='-' while im.include? mname
|
329
|
-
alias_method mname, oldmname
|
370
|
+
alias_method mname, oldmname if im.include? oldmname
|
330
371
|
def #{mname}
|
331
372
|
#{code}
|
332
373
|
binding
|
@@ -334,9 +375,9 @@ class Binding
|
|
334
375
|
mname
|
335
376
|
end
|
336
377
|
"
|
337
|
-
|
378
|
+
Thread.current[:$__Ron__CaptureCtx]= h.values
|
338
379
|
result=the_self.send mname, &the_block
|
339
|
-
|
380
|
+
Thread.current[:$__Ron__CaptureCtx]=nil
|
340
381
|
class<<the_self;
|
341
382
|
self
|
342
383
|
end.send(*if newmname==mname
|
@@ -344,7 +385,6 @@ class Binding
|
|
344
385
|
else
|
345
386
|
[:alias_method, mname, oldmname]
|
346
387
|
end)
|
347
|
-
Thread.critical=false
|
348
388
|
result
|
349
389
|
end
|
350
390
|
alias from_h -
|
@@ -378,22 +418,20 @@ UnboundMethod,
|
|
378
418
|
|
379
419
|
|
380
420
|
#not sure about these:
|
381
|
-
[
|
382
|
-
Continuation,
|
383
|
-
:Thread,
|
384
|
-
:ThreadGroup,
|
385
|
-
|
386
|
-
:Mutex, #??
|
387
421
|
#and other interthead communication mechanisms, like
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
422
|
+
eval("["+%w[
|
423
|
+
Continuation
|
424
|
+
Thread
|
425
|
+
ThreadGroup
|
426
|
+
Mutex
|
427
|
+
Queue
|
428
|
+
SizedQueue
|
429
|
+
RingBuffer
|
430
|
+
ConditionVariable
|
431
|
+
Semaphore
|
432
|
+
CountingSemaphore
|
433
|
+
Multiwait
|
434
|
+
].map{|x| "(#{x} if defined? #{x}), "}.join+"]").compact.each{|k|
|
397
435
|
k.class_eval do
|
398
436
|
def to_ron(x=nil); raise Ron:: NotYetMaybeNeverSerializeableError end
|
399
437
|
alias to_ron_list to_ron
|
data/lib/ron/column_order.rb
CHANGED
@@ -86,7 +86,7 @@ module ForModule
|
|
86
86
|
#column_order defaults to attribute order if not given
|
87
87
|
cols=(@COLUMN_ORDER if defined? @COLUMN_ORDER) || @REG_ATTRIBUTE_ORDER
|
88
88
|
|
89
|
-
meths=instance_methods(false)
|
89
|
+
meths=instance_methods(false).map{|im| im.to_s}
|
90
90
|
|
91
91
|
module_eval <<-"END"
|
92
92
|
private #utility methods
|
@@ -0,0 +1,168 @@
|
|
1
|
+
begin #redparse/float_accurate_to_s overrides this one, if present
|
2
|
+
require 'redparse/float_accurate_to_s'
|
3
|
+
overridden=true
|
4
|
+
rescue Exception #and ignore
|
5
|
+
end
|
6
|
+
|
7
|
+
class Float
|
8
|
+
SIZE=[1.1].pack("d").size
|
9
|
+
BITSIZE=SIZE*8
|
10
|
+
BASE10_DIGITS=(2**BITSIZE-1).to_s.size
|
11
|
+
def accurate_to_s
|
12
|
+
return "#{'-' if self<0}Infinity" if infinite?
|
13
|
+
return "NaN" if nan?
|
14
|
+
return "0.0e0" if zero?
|
15
|
+
|
16
|
+
as_str=sprintf("%.#{BASE10_DIGITS+2}e",self)
|
17
|
+
|
18
|
+
#decompose self into sign, mantissa, and exponent (in string form)
|
19
|
+
all,sign,first,digits,exp=*as_str.match(/^([+-]?)(\d)\.(\d+)e(.*)$/)
|
20
|
+
digits=first<<digits
|
21
|
+
exp=exp.to_i+1
|
22
|
+
lead=sign<<"0."
|
23
|
+
return digits=digits if as_str.to_f.zero? #hopeless
|
24
|
+
|
25
|
+
#recompose back to a float
|
26
|
+
result=[lead,digits,"e",exp].join
|
27
|
+
result_f=result.to_f
|
28
|
+
delta=result_f - self
|
29
|
+
return digits=digits if delta.zero? #if representation is exact, return here
|
30
|
+
|
31
|
+
#figure out which direction to go to get toward the right answer
|
32
|
+
if delta<0
|
33
|
+
incr=1
|
34
|
+
else #delta>0
|
35
|
+
incr=-1
|
36
|
+
end
|
37
|
+
|
38
|
+
#keep adding increasing increments to mantissa
|
39
|
+
#until we get to a value on the other side of the correct answer
|
40
|
+
while true
|
41
|
+
while true
|
42
|
+
try_digits=digits.to_i.+(incr).to_s
|
43
|
+
if try_digits.size>digits.size
|
44
|
+
exp+=1
|
45
|
+
digits="0"+digits
|
46
|
+
end
|
47
|
+
fail if try_digits[0]==?- #can't happen... I think?
|
48
|
+
trying=[lead,try_digits,"e",exp].join
|
49
|
+
trying_f=trying.to_f
|
50
|
+
break unless trying_f.zero?
|
51
|
+
digits[-1,1]='' #workaround 1.8 bug
|
52
|
+
end
|
53
|
+
return digits=try_digits if trying_f==self
|
54
|
+
break if self.between?(*[trying_f,result_f].sort) #(trying_f-self)*delta<0
|
55
|
+
incr*=2
|
56
|
+
end
|
57
|
+
|
58
|
+
#we now have lower and upper bounds on the correct answer
|
59
|
+
lower,upper=*[digits.to_i, digits.to_i.+(incr)].sort
|
60
|
+
|
61
|
+
#maybe one of the bounds is already the correct answer?
|
62
|
+
result=[lead,lower,"e",exp].join
|
63
|
+
return digits=lower if result.to_f==self
|
64
|
+
result=[lead,upper,"e",exp].join
|
65
|
+
return digits=upper if result.to_f==self
|
66
|
+
|
67
|
+
#binary search between lower and upper bounds til we find a correct answer
|
68
|
+
digits=nil
|
69
|
+
while true
|
70
|
+
return as_str if upper-lower <= 1 #hopeless
|
71
|
+
mid=(lower+upper)/2
|
72
|
+
mid_s=[lead,mid,"e",exp].join
|
73
|
+
mid_f=mid_s.to_f
|
74
|
+
return digits=mid if mid_f==self
|
75
|
+
if mid_f<self
|
76
|
+
lower=mid
|
77
|
+
else #mid_f>self
|
78
|
+
upper=mid
|
79
|
+
end
|
80
|
+
end
|
81
|
+
ensure
|
82
|
+
|
83
|
+
#try to drop unneeded trailing digits
|
84
|
+
if digits
|
85
|
+
digits=digits.to_s
|
86
|
+
begin
|
87
|
+
last=digits.slice! -1
|
88
|
+
result=[lead,digits,"e",exp].join.to_f
|
89
|
+
end while result==self or result.zero? && digits.size.nonzero?
|
90
|
+
roundup=(digits.to_i+1).to_s
|
91
|
+
if roundup.size>digits.size
|
92
|
+
exp+=1
|
93
|
+
digits="0"+digits
|
94
|
+
end
|
95
|
+
roundup.slice! /0+\Z/
|
96
|
+
roundup=[lead,roundup,"e",exp].join
|
97
|
+
return roundup if roundup.to_f==self
|
98
|
+
return [lead,digits<<last,"e",exp].join
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end unless overridden
|
102
|
+
|
103
|
+
=begin not quite accurate, tho
|
104
|
+
class String
|
105
|
+
def accurate_to_f
|
106
|
+
all,sign,int,frac,exp=*self.match(/\A([+-])?([0-9_]+)(?:\.([0-9_]+))?(?:[eE]([+-]?[0-9_]+))?/)
|
107
|
+
exp=exp.to_i||0
|
108
|
+
exp-=frac.size
|
109
|
+
mantissa=sign<<int<<frac
|
110
|
+
mantissa=mantissa.to_f
|
111
|
+
scale=10.0**exp
|
112
|
+
return mantissa*scale
|
113
|
+
end
|
114
|
+
end unless overridden
|
115
|
+
=end
|
116
|
+
|
117
|
+
eval DATA.read if __FILE__==$0
|
118
|
+
__END__
|
119
|
+
|
120
|
+
require 'test/unit'
|
121
|
+
|
122
|
+
class FloatRoundTripTest<Test::Unit::TestCase
|
123
|
+
def float_round_trip f
|
124
|
+
str=f.accurate_to_s
|
125
|
+
if str=="Infinity"
|
126
|
+
return 1.0/0
|
127
|
+
elsif str=="-Infinity"
|
128
|
+
return -1.0/0
|
129
|
+
elsif str=="NaN"
|
130
|
+
return 0.0/0.0
|
131
|
+
else
|
132
|
+
str.to_f
|
133
|
+
end
|
134
|
+
end
|
135
|
+
alias frt float_round_trip
|
136
|
+
|
137
|
+
def rand_float
|
138
|
+
base=rand
|
139
|
+
range=Float::MIN_10_EXP..Float::MAX_10_EXP
|
140
|
+
extent=range.last-range.first
|
141
|
+
offset=rand(extent+1)
|
142
|
+
exp=range.first+offset
|
143
|
+
base*=10**exp
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_frt
|
147
|
+
data=[0.399891415240566, 0.198188037200931, 0.90302699802093,
|
148
|
+
7.48121345153454520016e-01, 4.11408313999083175005e-02,
|
149
|
+
2.68070684698467065488e-02, 3.85029229764812574999e-01,
|
150
|
+
"\327\237vY\343n\342?".unpack("d")[0],
|
151
|
+
1.0/0, -1.0/0, 0.0/0.0,
|
152
|
+
"\333\211>4\253Atu".unpack("d")[0],
|
153
|
+
"\2461\220\253\214\267e\021".unpack("d")[0],
|
154
|
+
"\r\032N\f'\336\243\003".unpack("d")[0],
|
155
|
+
"B[\226\001\2175f\021".unpack("d")[0],
|
156
|
+
"%\217\336\362\326\272\026\001".unpack("d")[0],
|
157
|
+
"\312\342\344\206\237\024\"\003".unpack("d")[0],
|
158
|
+
]
|
159
|
+
1_000_000.times{|i|
|
160
|
+
f=data.shift||rand_float
|
161
|
+
p sprintf("%.#{Float::BASE10_DIGITS}e",f)
|
162
|
+
p [f].pack"d"
|
163
|
+
p f.accurate_to_s
|
164
|
+
f2=frt f
|
165
|
+
warn "failed with i=#{i} f=#{f}, #{[f].pack("d").inspect}; f2=#{f2}, #{[f2].pack("d").inspect}" unless [f].pack("d")==[f2].pack("d")
|
166
|
+
}
|
167
|
+
end
|
168
|
+
end
|
data/lib/ron/graphedge.rb
CHANGED
@@ -38,23 +38,69 @@ module Ron
|
|
38
38
|
end
|
39
39
|
|
40
40
|
#--------------------------------
|
41
|
-
|
42
|
-
|
41
|
+
#
|
42
|
+
#NOTE: breadth_graphcopy has a problem; since graphwalk is not depth-first,
|
43
|
+
# if a node is replaced, the subnodes of the new node will not be walked.
|
44
|
+
# Instead, the old nodes will be walked.
|
45
|
+
# If this causes problems, use depth_graphcopy instead
|
46
|
+
def breadth_graphcopy(obj,old2new={})
|
43
47
|
root=nil
|
44
|
-
|
48
|
+
breadth_graphwalk(obj){|cntr,o,i,ty|
|
45
49
|
newo= block_given? && (yield cntr,o,i,ty,useit=[false])
|
46
|
-
useit.first
|
50
|
+
if useit.first
|
51
|
+
#fail unless newo
|
52
|
+
old2new[o.__id__]=newo
|
53
|
+
else
|
54
|
+
#fail unless o
|
55
|
+
newo= old2new[o.__id__] ||= (o.clone rescue o)
|
56
|
+
end
|
47
57
|
#IO objects really shouldn't be dup'd here
|
48
58
|
if Ron::GraphEdge::TopLevel==ty
|
49
59
|
root=newo
|
50
60
|
else
|
61
|
+
#fail unless old2new.has_key? cntr.__id__
|
51
62
|
ty.new(old2new[cntr.__id__],i,1){newo}.replace
|
52
63
|
end
|
53
64
|
}
|
54
65
|
return root
|
55
66
|
end
|
67
|
+
|
68
|
+
#--------------------------------
|
69
|
+
def depth_graphcopy(obj,old2new={})
|
70
|
+
root=nil
|
71
|
+
changes=[]
|
72
|
+
depth_graphwalk(obj){|cntr,o,i,ty|
|
73
|
+
newo=yield cntr,o,i,ty,useit=[false] if block_given?
|
74
|
+
if useit.first
|
75
|
+
#p [cntr.id,cntr,o,:>>,newo,newo.last.__id__]
|
76
|
+
old2new[o.__id__]=o #bad, bad... shouldn't be refs to old tree in old2new
|
77
|
+
else
|
78
|
+
begin
|
79
|
+
newo=o.clone
|
80
|
+
rescue Exception
|
81
|
+
newo=o
|
82
|
+
else
|
83
|
+
old2new[o.__id__]=newo
|
84
|
+
end
|
85
|
+
end
|
86
|
+
#IO objects really shouldn't be dup'd here
|
87
|
+
if Ron::GraphEdge::TopLevel==ty
|
88
|
+
root=newo
|
89
|
+
else
|
90
|
+
changes.push ty,cntr.__id__,i,newo
|
91
|
+
end
|
92
|
+
}
|
93
|
+
until changes.empty?
|
94
|
+
ty,cntr_id,i,newo=*changes.slice!(-4,4)
|
95
|
+
new_cntr=old2new[cntr_id]
|
96
|
+
ty.new(new_cntr,i,1){newo}.replace if old2new.has_key? cntr_id
|
97
|
+
end
|
98
|
+
return root
|
99
|
+
end
|
100
|
+
alias graphcopy depth_graphcopy
|
56
101
|
|
57
102
|
#--------------------------------
|
103
|
+
#breadth-first walk of an object graph
|
58
104
|
def graphwalk(obj)
|
59
105
|
yield nil,obj,nil,GraphEdge::TopLevel
|
60
106
|
todolist=[obj]
|
@@ -69,7 +115,18 @@ module Ron
|
|
69
115
|
}
|
70
116
|
}
|
71
117
|
end
|
72
|
-
|
118
|
+
alias breadth_graphwalk graphwalk
|
119
|
+
|
120
|
+
#--------------------------------
|
121
|
+
#depth-first walk of an object graph
|
122
|
+
def depth_graphwalk(obj,container=nil,index=nil,type=GraphEdge::TopLevel,seen=Set[],&block)
|
123
|
+
seen<<[container.__id__,type,index]
|
124
|
+
traverse(obj){|cntr,o,i,ty|
|
125
|
+
depth_graphwalk(o,cntr,i,ty,seen,&block) unless seen.include? [cntr.__id__,ty,i]
|
126
|
+
}
|
127
|
+
block[ container,obj,index,type ]
|
128
|
+
end
|
129
|
+
|
73
130
|
#--------------------------------
|
74
131
|
def abortable_graphwalk(obj)
|
75
132
|
return unless yield nil,obj,nil,GraphEdge::TopLevel
|
@@ -93,7 +150,7 @@ module Ron
|
|
93
150
|
case obj
|
94
151
|
when nil; #do nothing
|
95
152
|
when (Set if defined? Set)
|
96
|
-
obj.each{|elem|
|
153
|
+
obj.dup.each{|elem|
|
97
154
|
yield(obj,elem, elem, GraphEdge::SetMember)
|
98
155
|
}
|
99
156
|
when Struct;
|
@@ -101,12 +158,12 @@ module Ron
|
|
101
158
|
yield(obj,obj[mem],mem, GraphEdge::BracketsValue)
|
102
159
|
}
|
103
160
|
when Hash;
|
104
|
-
obj.each{|
|
161
|
+
obj.keys.each{|i| elem=obj[i]
|
105
162
|
yield(obj,elem,i, GraphEdge::HashValue)
|
106
163
|
yield(obj,i,i, GraphEdge::HashKey)
|
107
164
|
}
|
108
165
|
when Array;
|
109
|
-
obj.
|
166
|
+
(obj.size-1).downto(0){|i| elem=obj[i]
|
110
167
|
yield(obj,elem,i, GraphEdge::Array)
|
111
168
|
}
|
112
169
|
when Range;
|
@@ -120,7 +177,7 @@ module Ron
|
|
120
177
|
end
|
121
178
|
#traverse instance vars in any case
|
122
179
|
obj.instance_variables.each{|var|
|
123
|
-
yield obj, (obj.instance_variable_get var), var, GraphEdge::ObjectIvarValue
|
180
|
+
yield obj, (obj.instance_variable_get var), var.to_s, GraphEdge::ObjectIvarValue
|
124
181
|
}
|
125
182
|
end
|
126
183
|
|
@@ -158,7 +215,7 @@ module Ron
|
|
158
215
|
def initialize(context,index,len=1,&newval_code)
|
159
216
|
len>=0 or raise ArgumentError
|
160
217
|
@context,@index,@len,@newval_code=context,index,len,newval_code
|
161
|
-
|
218
|
+
fail unless @context
|
162
219
|
end
|
163
220
|
attr_reader :index,:len,:context
|
164
221
|
|
@@ -167,9 +224,9 @@ module Ron
|
|
167
224
|
|
168
225
|
def call; replace; end
|
169
226
|
|
170
|
-
def context_died
|
171
|
-
@context=nil
|
172
|
-
end
|
227
|
+
# def context_died
|
228
|
+
# @context=nil
|
229
|
+
# end
|
173
230
|
|
174
231
|
def new_value
|
175
232
|
@newval_code[self]
|
@@ -191,9 +248,22 @@ module Ron
|
|
191
248
|
context[@index]
|
192
249
|
end
|
193
250
|
|
194
|
-
|
195
|
-
|
196
|
-
|
251
|
+
|
252
|
+
a=[]
|
253
|
+
a[0]=*[1]
|
254
|
+
if a==[1]
|
255
|
+
def replace(*newvals)
|
256
|
+
newvals.empty? and newvals=[new_value]
|
257
|
+
context[@index]=*newvals
|
258
|
+
end
|
259
|
+
elsif a==[[1]] #goddamn 1.9 array multiple assignment semantics!
|
260
|
+
def replace(*newvals)
|
261
|
+
if newvals.empty? then newvals=new_value
|
262
|
+
elsif newvals.size==1 then newvals=newvals[0]
|
263
|
+
end
|
264
|
+
context[@index]=newvals
|
265
|
+
end
|
266
|
+
else fail
|
197
267
|
end
|
198
268
|
end
|
199
269
|
|
data/lib/ron/version.rb
CHANGED
data/ron.gemspec
CHANGED
@@ -1,28 +1,29 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
require
|
3
|
+
require "#{File.dirname(__FILE__)}/lib/ron/version"
|
4
4
|
Ron::Description=open("README.txt"){|f| f.read[/^==+ ?description[^\n]*?\n *\n?(.*?\n *\n.*?)\n *\n/im,1] }
|
5
5
|
Ron::Latest_changes="###"+open("History.txt"){|f| f.read[/\A===(.*?)(?====)/m,1] }
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "Ron"
|
9
9
|
s.version = Ron::VERSION
|
10
|
-
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
-
s.authors = ["Caleb Clausen"]
|
13
10
|
s.date = Time.now.strftime("%Y-%m-%d")
|
11
|
+
s.authors = ["Caleb Clausen"]
|
14
12
|
s.email = %q{caleb (at) inforadical (dot) net}
|
15
|
-
s.
|
16
|
-
s.
|
17
|
-
s.has_rdoc = true
|
13
|
+
s.summary = "Ruby Object Notation (Ron) is a ruby-based textual format for representing Ruby data."
|
14
|
+
s.description = Ron::Description
|
18
15
|
s.homepage = %{http://github.com/coatl/ron}
|
19
|
-
s.rdoc_options = %w[--inline-source --main README.txt]
|
20
|
-
s.require_paths = ["lib"]
|
21
16
|
s.rubyforge_project = %q{ron}
|
22
|
-
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split
|
23
19
|
s.test_files = %w[test/test_all.rb]
|
24
|
-
s.
|
25
|
-
s.
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.extra_rdoc_files = ["README.txt", "COPYING", "GPL"]
|
22
|
+
s.has_rdoc = true
|
23
|
+
s.rdoc_options = %w[--main README.txt]
|
24
|
+
|
25
|
+
s.rubygems_version = %q{1.3.0}
|
26
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
26
27
|
|
27
28
|
=begin
|
28
29
|
if s.respond_to? :specification_version then
|
data/test/test_all.rb
CHANGED
@@ -18,6 +18,8 @@ try_require 'rubygems'
|
|
18
18
|
try_require("sequence/weakrefset")
|
19
19
|
try_require 'facets/more/superstruct'
|
20
20
|
|
21
|
+
require "test/test_graphcopy"
|
22
|
+
|
21
23
|
$Verbose=true
|
22
24
|
|
23
25
|
=begin
|
@@ -67,10 +69,33 @@ def == bm
|
|
67
69
|
end
|
68
70
|
end
|
69
71
|
|
72
|
+
class MyString<String
|
73
|
+
attr_accessor :ivar
|
74
|
+
end
|
75
|
+
|
76
|
+
class MyRegexp<Regexp
|
77
|
+
attr_accessor :ivar
|
78
|
+
end
|
79
|
+
|
80
|
+
class MyArray<Array
|
81
|
+
attr_accessor :ivar
|
82
|
+
end
|
83
|
+
|
84
|
+
class MyHash<Hash
|
85
|
+
attr_accessor :ivar
|
86
|
+
end
|
87
|
+
|
88
|
+
class MyRange<Range
|
89
|
+
attr_accessor :ivar
|
90
|
+
end
|
91
|
+
|
92
|
+
module M
|
93
|
+
end
|
94
|
+
|
95
|
+
|
70
96
|
class RonTest<Test::Unit::TestCase
|
71
97
|
|
72
98
|
def test_ron
|
73
|
-
|
74
99
|
s1=1.0
|
75
100
|
s2=2.0
|
76
101
|
range=s1..s2
|
@@ -83,13 +108,16 @@ s2.instance_variable_set(:@n, ss)
|
|
83
108
|
s1=1.0
|
84
109
|
s2=2.0
|
85
110
|
sss=SortedSet[s1,s2]
|
86
|
-
s1.instance_variable_set(:@
|
87
|
-
s2.instance_variable_set(:@
|
111
|
+
s1.instance_variable_set(:@o, sss)
|
112
|
+
s2.instance_variable_set(:@o, sss)
|
88
113
|
|
89
114
|
sss.inspect #disable this and tests fail... why?!?!?
|
115
|
+
strongrefs=%w[a b c]
|
90
116
|
data=[
|
91
|
-
|
117
|
+
34565.23458888888*0.5,
|
118
|
+
45245.765735422567*0.5,
|
92
119
|
3.14159,
|
120
|
+
1.2345678901234567,
|
93
121
|
2**2000,
|
94
122
|
|
95
123
|
"string",
|
@@ -111,7 +139,7 @@ data=[
|
|
111
139
|
[1,2,3],
|
112
140
|
{1=>2,3=>4},
|
113
141
|
Set[1,2,3],
|
114
|
-
(Sequence::WeakRefSet[
|
142
|
+
(Sequence::WeakRefSet[*strongrefs] rescue warn 'weakrefset test disabled'),
|
115
143
|
A_Class.new,
|
116
144
|
2,
|
117
145
|
:symbol,
|
@@ -119,10 +147,18 @@ data=[
|
|
119
147
|
true,
|
120
148
|
false,
|
121
149
|
|
122
|
-
|
150
|
+
MyString.new,
|
151
|
+
MyRegexp.new(//),
|
152
|
+
MyArray.new,
|
153
|
+
MyHash.new,
|
154
|
+
MyRange.new(1,2),
|
155
|
+
|
156
|
+
"\\",
|
157
|
+
"'",
|
123
158
|
]
|
124
159
|
data.each{|datum|
|
125
|
-
|
160
|
+
GC.disable
|
161
|
+
#p datum
|
126
162
|
assert_equal datum, datum
|
127
163
|
assert_equal datum, ( dup=eval datum.to_ron )
|
128
164
|
assert_equal internal_state(datum), internal_state(dup)
|
@@ -138,17 +174,30 @@ data.each{|datum|
|
|
138
174
|
datum.instance_eval{@c=self}
|
139
175
|
assert_equal datum, ( dup=eval datum.to_ron )
|
140
176
|
assert_equal internal_state(datum), internal_state(dup)
|
177
|
+
|
178
|
+
datum.extend(M)
|
179
|
+
assert_equal datum, ( dup=eval datum.to_ron )
|
180
|
+
assert_equal internal_state(datum), internal_state(dup)
|
181
|
+
assert M===dup
|
141
182
|
end
|
183
|
+
GC.enable
|
142
184
|
}
|
143
185
|
data.each{|datum|
|
186
|
+
GC.disable
|
144
187
|
if case datum
|
145
188
|
when Fixnum,Symbol,true,false,nil; false
|
146
189
|
else true
|
147
190
|
end
|
148
191
|
datum.instance_eval{@d=data}
|
149
|
-
|
150
|
-
|
192
|
+
assert_equal datum, ( dup=eval datum.to_ron )
|
193
|
+
assert_equal internal_state(datum), internal_state(dup)
|
194
|
+
|
195
|
+
datum.extend(M)
|
196
|
+
assert_equal datum, ( dup=eval datum.to_ron )
|
197
|
+
assert_equal internal_state(datum), internal_state(dup)
|
198
|
+
assert M===dup
|
151
199
|
end
|
200
|
+
GC.enable
|
152
201
|
}
|
153
202
|
|
154
203
|
data2=[
|
@@ -160,35 +209,57 @@ data2=[
|
|
160
209
|
(h={};h[h]=0;h),
|
161
210
|
(h={};h[h]=h;h),
|
162
211
|
(s=Set[];s<<s;s),
|
212
|
+
(o=MyString.new; o.ivar=o; o),
|
213
|
+
(o=MyArray.new; o.ivar=o; o),
|
214
|
+
(o=MyHash.new; o.ivar=o; o),
|
215
|
+
(o=MyArray.new; o<<o),
|
216
|
+
(o=MyHash.new; o[1]=o; o),
|
217
|
+
(o=MyRange.new(1,2); o.ivar=o; o),
|
163
218
|
]
|
164
|
-
data2.each{|datum|
|
165
|
-
|
219
|
+
data2.each{|datum|
|
220
|
+
GC.disable
|
221
|
+
#p datum
|
166
222
|
assert_equal datum.to_yaml, datum.to_yaml
|
167
|
-
|
168
|
-
|
223
|
+
dup=eval datum.to_ron
|
224
|
+
dup.inspect #shouldn't be needed
|
225
|
+
assert_equal datum.to_yaml, dup.to_yaml
|
226
|
+
assert_equal internal_state(datum)[0...2], internal_state(dup)[0...2]
|
227
|
+
assert_equal internal_state(datum)[2..-1].to_yaml, internal_state(dup)[2..-1].to_yaml
|
169
228
|
|
170
229
|
if case datum
|
171
230
|
when Fixnum,Symbol,true,false,nil; false
|
172
231
|
else true
|
173
232
|
end
|
174
233
|
datum.instance_eval{@a,@b=1,2}
|
175
|
-
|
176
|
-
|
234
|
+
dup=eval datum.to_ron
|
235
|
+
dup.inspect #shouldn't be needed
|
236
|
+
assert_equal datum.to_yaml, dup.to_yaml
|
237
|
+
assert_equal internal_state(datum)[0...2], internal_state(dup)[0...2]
|
238
|
+
assert_equal internal_state(datum)[2..-1].to_yaml, internal_state(dup)[2..-1].to_yaml
|
177
239
|
|
178
240
|
datum.instance_eval{@c=self}
|
179
|
-
|
180
|
-
|
241
|
+
dup=eval datum.to_ron
|
242
|
+
dup.inspect #shouldn't be needed
|
243
|
+
assert_equal datum.to_yaml, dup.to_yaml
|
244
|
+
assert_equal internal_state(datum)[0...2], internal_state(dup)[0...2]
|
245
|
+
assert_equal internal_state(datum)[2..-1].to_yaml, internal_state(dup)[2..-1].to_yaml
|
246
|
+
|
247
|
+
datum.extend(M)
|
248
|
+
dup=eval datum.to_ron
|
249
|
+
dup.inspect #shouldn't be needed
|
250
|
+
assert_equal datum.to_yaml, dup.to_yaml
|
251
|
+
assert_equal internal_state(datum)[0...2], internal_state(dup)[0...2]
|
252
|
+
assert_equal internal_state(datum)[2..-1].to_yaml, internal_state(dup)[2..-1].to_yaml
|
253
|
+
assert M===dup
|
181
254
|
end
|
182
|
-
|
183
|
-
|
255
|
+
GC.enable
|
256
|
+
}
|
257
|
+
GC.disable
|
258
|
+
datum= ((w=Sequence::WeakRefSet[];w<<w;w) rescue warn 'weakrefset test disabled')
|
184
259
|
assert_equal datum.inspect, datum.inspect
|
185
260
|
assert_equal datum.inspect, ( dup=eval datum.to_ron ).inspect
|
186
261
|
assert_equal internal_state(datum).inspect, internal_state(dup).inspect
|
187
262
|
|
188
|
-
if case datum
|
189
|
-
when Fixnum,Symbol,true,false,nil; false
|
190
|
-
else true
|
191
|
-
end
|
192
263
|
datum.instance_eval{@a,@b=1,2}
|
193
264
|
assert_equal datum.inspect, ( dup=eval datum.to_ron ).inspect
|
194
265
|
assert_equal internal_state(datum).inspect, internal_state(dup).inspect
|
@@ -196,24 +267,26 @@ datum= ((w=Sequence::WeakRefSet[];w<<w;w) rescue warn 'weakrefset test disabled'
|
|
196
267
|
datum.instance_eval{@c=self}
|
197
268
|
assert_equal datum.inspect, ( dup=eval datum.to_ron ).inspect
|
198
269
|
assert_equal internal_state(datum).inspect, internal_state(dup).inspect
|
199
|
-
end
|
200
270
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
datum.
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
271
|
+
datum= (o=MyRegexp.new(//); o.ivar=o; o)
|
272
|
+
ron=datum.to_ron
|
273
|
+
assert_match %r"Recursive\(v\d+_=\{\}, MyRegexp\.new\(\"\"\)\.with_ivars\(:@ivar=>v\d+_\)\)", ron
|
274
|
+
assert_equal datum,eval(ron)
|
275
|
+
datum.extend M
|
276
|
+
ron=datum.to_ron
|
277
|
+
assert M===eval(ron)
|
278
|
+
GC.enable
|
279
|
+
end
|
280
|
+
|
281
|
+
def nonrecursive_ancestors_of x
|
282
|
+
class<<x;ancestors end-[Recursive]
|
283
|
+
rescue TypeError
|
284
|
+
[]
|
212
285
|
end
|
213
286
|
|
214
287
|
def internal_state x
|
215
|
-
list=(x.instance_variables-::Ron::IGNORED_INSTANCE_VARIABLES[x.class.name]).sort
|
216
|
-
[list]+list.map{|iv| x.instance_variable_get(iv)}
|
288
|
+
list=(x.instance_variables.map!{|iv| iv.to_s}-::Ron::IGNORED_INSTANCE_VARIABLES[x.class.name]).sort
|
289
|
+
[x.class,nonrecursive_ancestors_of(x),list]+list.map{|iv| x.instance_variable_get(iv)}
|
217
290
|
end
|
218
291
|
|
219
292
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'ron'
|
3
|
+
require 'ron/graphedge'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
class TestGraphCopy<Test::Unit::TestCase
|
7
|
+
inner=["foo",nil]
|
8
|
+
TESTDATA=[
|
9
|
+
{:one=>inner, :two=>inner, :three=>nil}
|
10
|
+
]
|
11
|
+
|
12
|
+
def test_depth
|
13
|
+
TESTDATA.each{|td|
|
14
|
+
copy=Ron::GraphWalk::depth_graphcopy(td){|cntr,o,i,ty,useit|
|
15
|
+
if :one==i and Ron::GraphEdge::HashValue==ty
|
16
|
+
useit[0]=true
|
17
|
+
["bar"]
|
18
|
+
elsif "foo"==o
|
19
|
+
useit[0]=true
|
20
|
+
"baz"
|
21
|
+
end
|
22
|
+
}
|
23
|
+
assert_equal({:three=>nil, :one=>["bar"], :two=>["baz", nil]}, copy)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_breadth
|
28
|
+
TESTDATA.each{|td|
|
29
|
+
copy=Ron::GraphWalk::breadth_graphcopy(td){|cntr,o,i,ty,useit|
|
30
|
+
if :one==i and Ron::GraphEdge::HashValue==ty
|
31
|
+
useit[0]=true
|
32
|
+
["bar"]
|
33
|
+
elsif "foo"==o
|
34
|
+
useit[0]=true
|
35
|
+
"baz"
|
36
|
+
end
|
37
|
+
}
|
38
|
+
assert_equal({:three=>nil, :one=>["baz", nil], :two=>["baz", nil]}, copy)
|
39
|
+
#?? is that really the right output ??
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Ron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Caleb Clausen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-03 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -28,20 +28,19 @@ files:
|
|
28
28
|
- GPL
|
29
29
|
- History.txt
|
30
30
|
- Makefile
|
31
|
-
- Manifest.txt
|
32
31
|
- README.txt
|
33
|
-
- Rakefile
|
34
32
|
- lib/ron.rb
|
35
33
|
- lib/ron/column_order.rb
|
34
|
+
- lib/ron/float_accurate_to_s.rb
|
36
35
|
- lib/ron/graphedge.rb
|
37
36
|
- lib/ron/version.rb
|
38
37
|
- ron.gemspec
|
39
38
|
- test/test_all.rb
|
39
|
+
- test/test_graphcopy.rb
|
40
40
|
has_rdoc: true
|
41
41
|
homepage: http://github.com/coatl/ron
|
42
42
|
post_install_message:
|
43
43
|
rdoc_options:
|
44
|
-
- --inline-source
|
45
44
|
- --main
|
46
45
|
- README.txt
|
47
46
|
require_paths:
|
data/Manifest.txt
DELETED
data/Rakefile
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# Copyright (C) 2006 Caleb Clausen
|
2
|
-
# Distributed under the terms of Ruby's license.
|
3
|
-
require 'rubygems'
|
4
|
-
require 'hoe'
|
5
|
-
require 'lib/ron/version.rb'
|
6
|
-
|
7
|
-
if $*==["test"]
|
8
|
-
#hack to get 'rake test' to stay in one process
|
9
|
-
#which keeps netbeans happy
|
10
|
-
$:<<"lib"
|
11
|
-
# require 'ron.rb'
|
12
|
-
# require "test/unit"
|
13
|
-
require "test/test_all.rb"
|
14
|
-
Test::Unit::AutoRunner.run
|
15
|
-
exit
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
Hoe.new("Ron", Ron::VERSION) do |_|
|
21
|
-
|
22
|
-
_.author = "Caleb Clausen"
|
23
|
-
_.email = "ron-owner @at@ inforadical .dot. net"
|
24
|
-
_.url = "http://rubyforge.org/projects/ron"
|
25
|
-
_.summary = "Ron is a ruby-based serialization format for representing any ruby
|
26
|
-
object graph."
|
27
|
-
|
28
|
-
_.description = <<'END'
|
29
|
-
Ron is very much like JSON, but based around Ruby instead of JavaScript.
|
30
|
-
Stardard Ruby literal notation is extended to include an object literal
|
31
|
-
and a way to create self-referencing data structures.
|
32
|
-
END
|
33
|
-
_.changes='' #1st version, no changes
|
34
|
-
end
|
35
|
-
|
36
|
-
# add other tasks here
|
37
|
-
|