cgen 0.16.0
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/.gitignore +5 -0
- data/History.txt +199 -0
- data/README.txt +34 -0
- data/examples/bench.rb +14 -0
- data/examples/complex.rb +63 -0
- data/examples/complex2.rb +48 -0
- data/examples/cshadow-example.rb +55 -0
- data/examples/cshadow-point.rb +58 -0
- data/examples/ctest.rb +34 -0
- data/examples/ctest2.rb +32 -0
- data/examples/ctest3.rb +179 -0
- data/examples/ctest4.rb +18 -0
- data/examples/ctest5.rb +27 -0
- data/examples/example-ruby-talk-30April2004.rb +65 -0
- data/examples/fixed-array.rb +221 -0
- data/examples/inherit-example.rb +26 -0
- data/examples/inherit-example.txt +80 -0
- data/examples/instance-eval.rb +66 -0
- data/examples/ivset.rb +55 -0
- data/examples/marshal-test.rb +19 -0
- data/examples/matrix.rb +91 -0
- data/examples/modular-def.rb +87 -0
- data/examples/objattr.rb +46 -0
- data/examples/opaque-struct-test.rb +36 -0
- data/examples/sample.rb +184 -0
- data/examples/struct.rb +103 -0
- data/examples/test.rb +24 -0
- data/examples/yaml.rb +56 -0
- data/install.rb +1015 -0
- data/lib/cgen/attribute.rb +414 -0
- data/lib/cgen/cgen.rb +2041 -0
- data/lib/cgen/cshadow.rb +1037 -0
- data/lib/cgen/inherit.rb +46 -0
- data/rakefile +42 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test-attribute.rb +430 -0
- data/test/test-cgen.rb +127 -0
- data/test/test-cshadow.rb +289 -0
- data/test/test.rb +17 -0
- metadata +123 -0
data/History.txt
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
cgen 0.16.0
|
2
|
+
|
3
|
+
- Moved to Mr. Bones, git, gems, rubyforge.
|
4
|
+
|
5
|
+
- API doc reformatted from rd2 to rdoc.
|
6
|
+
|
7
|
+
cgen 0.15
|
8
|
+
|
9
|
+
- Reinstated "extern" for extern prototypes.
|
10
|
+
|
11
|
+
- CShadow.shadow_attr returns list of handles to the r/w funcs
|
12
|
+
|
13
|
+
- CGen does 'make clean' if extconf.rb changes
|
14
|
+
|
15
|
+
- #extconf yields line array
|
16
|
+
|
17
|
+
- Attributes remember their owner_class.
|
18
|
+
|
19
|
+
cgen 0.14
|
20
|
+
|
21
|
+
- Fixed to work with the YAML changes in ruby 1.8.4.
|
22
|
+
|
23
|
+
cgen 0.13
|
24
|
+
|
25
|
+
- InitAccumulators were writing code to execute every time, rather
|
26
|
+
than just the first time. Fixed the bug.
|
27
|
+
|
28
|
+
- #declare_struct may be passed attributes, such as
|
29
|
+
"__attribute__((__packed__))"
|
30
|
+
|
31
|
+
- Fixed a bug caused by having more than one ruby interpreter installed.
|
32
|
+
|
33
|
+
- MSVC compatibility fixes.
|
34
|
+
|
35
|
+
cgen 0.12
|
36
|
+
|
37
|
+
- CShadow.define_c_function for convenience.
|
38
|
+
|
39
|
+
- Improved sorting of component classes to reduce nondeterminism in code
|
40
|
+
generation, and to thereby reduce time to rebuild.
|
41
|
+
|
42
|
+
- Reorgnized CShadow base classes so that methods are provided by
|
43
|
+
extending with a module, CShadowClassMethods, instead of being
|
44
|
+
defined individually in each base class. This means that they can be
|
45
|
+
overridden and called with super. It's also cleaner and probably
|
46
|
+
faster.
|
47
|
+
|
48
|
+
- Included examples/yaml.rb, which was mistakenly left out of 0.11
|
49
|
+
|
50
|
+
- CShadow#inspect added. Shows both shadow attrs and instance vars.
|
51
|
+
|
52
|
+
cgen 0.11
|
53
|
+
|
54
|
+
- CShadow classes are YAML friendly--see docs on cshadow and
|
55
|
+
examples/yaml.rb.
|
56
|
+
|
57
|
+
- Library#literal_symbol to streamline use of rb_hash_aref etc.
|
58
|
+
|
59
|
+
- Improved granularity for efficient separate compilation.
|
60
|
+
|
61
|
+
- Improved indentation in CFunctions.
|
62
|
+
|
63
|
+
- CShadow: added a new statement accumulators to _dump_data_method
|
64
|
+
and _load_data_method, called 'pre_code' and 'post_code',
|
65
|
+
replacing 'extra_code'.
|
66
|
+
|
67
|
+
- Library#extconf should now return a string or array of strings,
|
68
|
+
which will be used as the contents of extconf.rb.
|
69
|
+
|
70
|
+
cgen 0.10
|
71
|
+
|
72
|
+
- For versions of ruby 1.7.3 and 1.8 after 20Dec2002, we use
|
73
|
+
rb_define_alloc_func() instead of defining an "allocate" class method,
|
74
|
+
which would cause a warning.
|
75
|
+
|
76
|
+
- Tested with MinGW/MSYS on Windows.
|
77
|
+
|
78
|
+
- Deprecated methods (define_method and define_class_method) removed. See
|
79
|
+
notes for 0.9, below.
|
80
|
+
|
81
|
+
cgen 0.9 [Never released]
|
82
|
+
|
83
|
+
- Now uses standard install.rb.
|
84
|
+
|
85
|
+
- Updated to ruby-1.7.3, 2002-10-30. (CShadow no longer uses class vars,
|
86
|
+
since their semantics have changed. It uses class instance vars instead.)
|
87
|
+
|
88
|
+
- Tested with ruby-1.6.7 and ruby-1.7.3 (no patch needed for either).
|
89
|
+
Patch for marshal.c in ruby-1.6.6 is still included.
|
90
|
+
|
91
|
+
- Tests now use Test::Unit.
|
92
|
+
|
93
|
+
- [INTERFACE CHANGE] Library#define_method and the define_method class
|
94
|
+
methods in shadow classes are now deprecated. They work correctly but issue
|
95
|
+
a warning. They will be removed in future releases. Use #define_c_method
|
96
|
+
instead. This change is necessary because ruby-1.7 already has
|
97
|
+
Module.define_method. For consistency, this name change propagates to other
|
98
|
+
define methods:
|
99
|
+
|
100
|
+
define --> define_c_function
|
101
|
+
define_method --> define_c_method
|
102
|
+
define_module_function --> define_c_module_function
|
103
|
+
define_global_function --> define_c_global_function
|
104
|
+
define_singleton_method --> define_c_singleton_method
|
105
|
+
|
106
|
+
cgen 0.8
|
107
|
+
- Minor fix to install.rb for compatibility with ruby 1.7.
|
108
|
+
- CGenerator::Library's purge_source_dir attribute now applies to .o files
|
109
|
+
as well as .c and .h.
|
110
|
+
- Shadow attributes can now be nonpersistent, using the :nonpersistent flag
|
111
|
+
in shadow_attr_accessor declarations. This reduces library size as well
|
112
|
+
as the size of the persistant image.
|
113
|
+
- CShadow: added a new statement accumulator to _dump_data_method and
|
114
|
+
_load_data_method, called 'extra_code', which can be used to pre- (in
|
115
|
+
the case of dump) or post- (in the case of load) process the object. For
|
116
|
+
instance, additonal (nonpersistent) resources may need to be created or
|
117
|
+
initialized based on the loaded attr values.
|
118
|
+
- [Interface change] Removed the before_commit and after_commit methods from
|
119
|
+
CShadow and added more general methods to CGen::Library, to which CShadow
|
120
|
+
delegates. See the docs in cshadow.rb.
|
121
|
+
|
122
|
+
cgen 0.7
|
123
|
+
- Added makedepend step to compilation so that the resulting library
|
124
|
+
reflects changes in headers. Library#makedepend can be overridden.
|
125
|
+
- Added CommentAccumulator, and gave each CFile a CommentAccumulator
|
126
|
+
called 'preamble' that comes before the include accumulator.
|
127
|
+
- Factored Library#write into #write and #update_file to give finer grained
|
128
|
+
control over checking whether a file needs updating.
|
129
|
+
- Added the purge_source_dir attribute of a library to optionally delete
|
130
|
+
or rename any source files that are not part of the current generation.
|
131
|
+
- Added show_times method (controlled by @@show_times) to print timing
|
132
|
+
information for the steps of the commit process.
|
133
|
+
|
134
|
+
cgen 0.6
|
135
|
+
- Fixed a bug in CShadow which caused attr initializers not to be
|
136
|
+
inherited by the 'new' method of a subclass. Fixed similar bugs
|
137
|
+
with attr dump and load code. Added tests for these.
|
138
|
+
- Added optional subclass arg to define_method, define_singleton_method,
|
139
|
+
etc. The subclass arg allows the generated template to belong to a
|
140
|
+
subclass of the function template it would normally belong to.
|
141
|
+
- IntAttribute, LongAttribute: Use INT2NUM rather than INT2FIX to handle
|
142
|
+
numbers on the order of 2**30 (n<=2**29 was ok before, n>=2**31 is too
|
143
|
+
large for native longs, and raises an exception). Added tests for this.
|
144
|
+
|
145
|
+
cgen 0.5
|
146
|
+
- Added before_commit and after_commit hooks for CShadow classes.
|
147
|
+
- Added LongAttribute.
|
148
|
+
- The protected and private declarations work on shadow attrs (in
|
149
|
+
the command form "protected :x", but not in the block form
|
150
|
+
"protected; shadow_attr_reader :x ...").
|
151
|
+
- declare_struct now uses declare, rather than a separate accumulator,
|
152
|
+
so that the order of declarations in a file is preserved.
|
153
|
+
|
154
|
+
cgen 0.4
|
155
|
+
- With a patch to marshal.c in the ruby source, CShadow now handles
|
156
|
+
marshalling of shadow objects. See attribute.rb and marshal.patch.
|
157
|
+
- Tests added to attribute.rb for marshalling.
|
158
|
+
- CGenerator::Structure now allows recursive structs, so this works:
|
159
|
+
class Foo; include CShadow; shadow_attr_accessor :foo => [Foo]
|
160
|
+
(It always worked without the [], but that's another beast.)
|
161
|
+
|
162
|
+
cgen 0.3
|
163
|
+
- Shadow structures: C structs painlessly attached to Ruby objects.
|
164
|
+
- Extensible architecture for shadow attributes
|
165
|
+
- Basic attributes for int, double, char*, Ruby object, etc.
|
166
|
+
- Inheritance of attributes.
|
167
|
+
- See docs in cshadow.html and attribute.html.
|
168
|
+
- Structure "inheritance":
|
169
|
+
a_struct.inherit another_struct.declare!
|
170
|
+
- Libraries are now inspectible, with hierarchical display of nested
|
171
|
+
templates and accumulators.
|
172
|
+
- Optional type checking for c_array_args.
|
173
|
+
- It's now easy to send definitions to other .c files besides the
|
174
|
+
main one for the library. See documentation for "add_file" and the
|
175
|
+
example in cgen.rb. CShadow takes advantage of this feature.
|
176
|
+
- Finer granularity in cgen's make process: write, mkmf, and make are
|
177
|
+
separate; mkmf still calls Library#extconf. You can pass arguments
|
178
|
+
to #make that the make program understands, such as 'distclean'.
|
179
|
+
- Cgen has now improved from alpha to beta quality code. Testing is
|
180
|
+
fairly thorough, especially in cshadow.rb and attribute.rb, and
|
181
|
+
documentation covers all public methods and many internal methods.
|
182
|
+
- Updated to work with Ruby 1.6.6.
|
183
|
+
- Now installs all four library files into cgen/ dir (the location of
|
184
|
+
this dir is controllable with the -d arg to install.rb.)
|
185
|
+
|
186
|
+
cgen 0.2
|
187
|
+
- Nice syntax for required, optional, rest, and block arguments, using
|
188
|
+
rb_scan_args. Performs default initialization for optional arguments.
|
189
|
+
See new code in sample.rb.
|
190
|
+
- Methods and other RubyFunctions return nil by default.
|
191
|
+
- Runs mkmf.rb in a forked process, because:
|
192
|
+
1. mkmf uses global scope |:(
|
193
|
+
2. might need to run mkmf twice in one session
|
194
|
+
3. this puts the mkmf log file in the lib dir, not the main dir.
|
195
|
+
- The cwd when the extension is 'require'-d is now the same as the main dir.
|
196
|
+
- Fixed bug with #c_array_args in the RubyFunction classes.
|
197
|
+
|
198
|
+
cgen 0.1
|
199
|
+
- First public release. Alpha, but basic functionality seems to work.
|
data/README.txt
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
high level overview
|
3
|
+
|
4
|
+
purpose and history
|
5
|
+
|
6
|
+
getting started
|
7
|
+
|
8
|
+
- will need compiler
|
9
|
+
|
10
|
+
advanced
|
11
|
+
|
12
|
+
==Object attributes
|
13
|
+
|
14
|
+
===class CShadow::ObjectAttribute
|
15
|
+
|
16
|
+
===class CShadow::ShadowObjectAttribute
|
17
|
+
|
18
|
+
|
19
|
+
examples
|
20
|
+
|
21
|
+
more docs
|
22
|
+
|
23
|
+
|
24
|
+
==web site
|
25
|
+
|
26
|
+
==license
|
27
|
+
|
28
|
+
==author
|
29
|
+
Copyright 2001-2009
|
30
|
+
Joel VanderWerf,
|
31
|
+
mailto:vjoel@users.sourceforge.net
|
32
|
+
|
33
|
+
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/24443
|
34
|
+
|
data/examples/bench.rb
ADDED
data/examples/complex.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class MyComplex < Numeric
|
6
|
+
include CShadow
|
7
|
+
|
8
|
+
shadow_attr_accessor :re => "double re", :im => "double im"
|
9
|
+
|
10
|
+
def initialize re, im
|
11
|
+
self.re = re
|
12
|
+
self.im = im
|
13
|
+
end
|
14
|
+
|
15
|
+
define_c_method(:abs) {
|
16
|
+
include "<math.h>"
|
17
|
+
returns "rb_float_new(sqrt(pow(shadow->re, 2) + pow(shadow->im, 2)))"
|
18
|
+
}
|
19
|
+
|
20
|
+
define_c_method(:mul!) {
|
21
|
+
arguments :other
|
22
|
+
declare :other_shadow => "MyComplex_Shadow *other_shadow"
|
23
|
+
declare :new_re => "double new_re", :new_im => "double new_im"
|
24
|
+
body %{
|
25
|
+
switch (TYPE(other)) {
|
26
|
+
case T_FIXNUM: shadow->re *= FIX2INT(other);
|
27
|
+
shadow->im *= FIX2INT(other); break;
|
28
|
+
case T_FLOAT: shadow->re *= NUM2DBL(other);
|
29
|
+
shadow->im *= NUM2DBL(other); break;
|
30
|
+
default:
|
31
|
+
if (rb_obj_is_kind_of(other, #{declare_class MyComplex}) ==
|
32
|
+
Qtrue) {
|
33
|
+
Data_Get_Struct(other, MyComplex_Shadow, other_shadow);
|
34
|
+
new_re = shadow->re * other_shadow->re -
|
35
|
+
shadow->im * other_shadow->im;
|
36
|
+
new_im = shadow->re * other_shadow->im +
|
37
|
+
shadow->im * other_shadow->re;
|
38
|
+
shadow->re = new_re;
|
39
|
+
shadow->im = new_im;
|
40
|
+
}
|
41
|
+
else
|
42
|
+
rb_raise(#{declare_class ArgumentError},
|
43
|
+
"Argument to mul! is not numeric.");
|
44
|
+
}
|
45
|
+
}
|
46
|
+
returns "self"
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
require 'ftools'
|
51
|
+
dir = File.join("tmp", RUBY_VERSION)
|
52
|
+
File.mkpath dir
|
53
|
+
Dir.chdir dir
|
54
|
+
|
55
|
+
MyComplex.commit
|
56
|
+
|
57
|
+
z = MyComplex.new 5, 1.3
|
58
|
+
puts z.abs
|
59
|
+
z.mul! 10
|
60
|
+
p [z.re, z.im]
|
61
|
+
w = MyComplex.new 7.9, -1.2
|
62
|
+
z.mul! w
|
63
|
+
p [z.re, z.im]
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class MyComplex2 < Numeric
|
6
|
+
include CShadow
|
7
|
+
|
8
|
+
shadow_attr_accessor :re => "double re", :im => "double im"
|
9
|
+
|
10
|
+
def initialize re, im
|
11
|
+
self.re = re
|
12
|
+
self.im = im
|
13
|
+
end
|
14
|
+
|
15
|
+
define_c_method(:abs) {
|
16
|
+
include "<math.h>"
|
17
|
+
returns "rb_float_new(sqrt(pow(shadow->re, 2) + pow(shadow->im, 2)))"
|
18
|
+
}
|
19
|
+
|
20
|
+
define_c_method(:scale!) {
|
21
|
+
c_array_args {
|
22
|
+
optional :factor
|
23
|
+
default :factor => "INT2NUM(10)"
|
24
|
+
typecheck :factor => Numeric
|
25
|
+
}
|
26
|
+
body %{
|
27
|
+
shadow->re *= NUM2DBL(factor);
|
28
|
+
shadow->im *= NUM2DBL(factor);
|
29
|
+
}
|
30
|
+
returns "self"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'ftools'
|
35
|
+
dir = File.join("tmp", RUBY_VERSION)
|
36
|
+
File.mkpath dir
|
37
|
+
Dir.chdir dir do
|
38
|
+
MyComplex2.commit
|
39
|
+
end
|
40
|
+
|
41
|
+
z = MyComplex2.new 5, 1.3
|
42
|
+
puts z.abs # ==> 5.1662365412358
|
43
|
+
z.scale! 3.0 # float
|
44
|
+
p [z.re, z.im] # ==> [15.0, 3.9]
|
45
|
+
z.scale! 3 # int
|
46
|
+
p [z.re, z.im] # ==> [45.0, 11.7]
|
47
|
+
z.scale! # use default value
|
48
|
+
p [z.re, z.im] # ==> [450.0, 117]
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/env/bin ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class Test
|
6
|
+
include CShadow
|
7
|
+
shadow_attr_accessor\
|
8
|
+
:i => "int ii",
|
9
|
+
:d => "double d"
|
10
|
+
shadow_attr_reader :obj => Object
|
11
|
+
end
|
12
|
+
|
13
|
+
class SubTest < Test
|
14
|
+
shadow_attr :hidden_array => Array
|
15
|
+
shadow_attr_accessor\
|
16
|
+
:foo => "char *foo",
|
17
|
+
:bar => Symbol,
|
18
|
+
:test => [Test]
|
19
|
+
end
|
20
|
+
|
21
|
+
class OtherSubTest < Test
|
22
|
+
shadow_attr_accessor :j => "int j"
|
23
|
+
def initialize j_init
|
24
|
+
self.j = j_init
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class SubSubTest < SubTest
|
29
|
+
shadow_attr_accessor :z => Object
|
30
|
+
end
|
31
|
+
|
32
|
+
require 'ftools'
|
33
|
+
dir = File.join("tmp", RUBY_VERSION)
|
34
|
+
File.mkpath dir
|
35
|
+
Dir.chdir dir
|
36
|
+
|
37
|
+
SubTest.commit # same as Test.commit
|
38
|
+
|
39
|
+
x = SubTest.new
|
40
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
41
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
42
|
+
x.i = 7.5; x.d = 3; x.foo = "fred"; x.bar = :WILMA
|
43
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
44
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
45
|
+
|
46
|
+
y = OtherSubTest.new -123456789
|
47
|
+
puts y.j, y.d
|
48
|
+
|
49
|
+
# make sure ShadowAttribute works
|
50
|
+
puts "x.test = #{x.test || 'nil'}"
|
51
|
+
x.test = y
|
52
|
+
puts "x.test = #{x.test || 'nil'}"
|
53
|
+
puts x.test.j
|
54
|
+
|
55
|
+
SubSubTest.each_shadow_attr {|x| p x}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/env/bin ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class Point
|
6
|
+
include CShadow
|
7
|
+
|
8
|
+
###
|
9
|
+
|
10
|
+
shadow_attr_accessor\
|
11
|
+
:i => "int ii",
|
12
|
+
:d => "double d"
|
13
|
+
shadow_attr_reader :obj => Object
|
14
|
+
end
|
15
|
+
|
16
|
+
class SubTest < Test
|
17
|
+
shadow_attr :hidden_array => Array
|
18
|
+
shadow_attr_accessor\
|
19
|
+
:foo => "char *foo",
|
20
|
+
:bar => Symbol,
|
21
|
+
:test => [Test]
|
22
|
+
end
|
23
|
+
|
24
|
+
class OtherSubTest < Test
|
25
|
+
shadow_attr_accessor :j => "int j"
|
26
|
+
def initialize j_init
|
27
|
+
self.j = j_init
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class SubSubTest < SubTest
|
32
|
+
shadow_attr_accessor :z => Object
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'ftools'
|
36
|
+
dir = File.join("tmp", RUBY_VERSION)
|
37
|
+
File.mkpath dir
|
38
|
+
Dir.chdir dir
|
39
|
+
|
40
|
+
SubTest.commit # same as Test.commit
|
41
|
+
|
42
|
+
x = SubTest.new
|
43
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
44
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
45
|
+
x.i = 7.5; x.d = 3; x.foo = "fred"; x.bar = :WILMA
|
46
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
47
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
48
|
+
|
49
|
+
y = OtherSubTest.new -123456789
|
50
|
+
puts y.j, y.d
|
51
|
+
|
52
|
+
# make sure ShadowAttribute works
|
53
|
+
puts "x.test = #{x.test || 'nil'}"
|
54
|
+
x.test = y
|
55
|
+
puts "x.test = #{x.test || 'nil'}"
|
56
|
+
puts x.test.j
|
57
|
+
|
58
|
+
SubSubTest.each_shadow_attr {|x| p x}
|