ParseTree 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +13 -0
- data/Rakefile +1 -1
- data/lib/parse_tree.rb +101 -97
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
=== 2.0.2 / 2007-09-20
|
2
|
+
|
3
|
+
* 2 minor enhancements:
|
4
|
+
|
5
|
+
* Deactivated gcc-specific compiler flags unless ENV['ANAL'] or on my domain.
|
6
|
+
* Minor code cleanup - happier with -pedantic and the like.
|
7
|
+
|
8
|
+
* 1 bug fix:
|
9
|
+
|
10
|
+
* FINALLY conquered the splat args bug on certain platforms/versions.
|
11
|
+
Special Thanks to Jonas Pfenniger for debugging this and providing
|
12
|
+
a patch.
|
13
|
+
|
1
14
|
=== 2.0.1 / 2007-08-21
|
2
15
|
|
3
16
|
* 1 major enhancement:
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ Hoe.new("ParseTree", ParseTree::VERSION) do |p|
|
|
11
11
|
p.summary = "Extract and enumerate ruby parse trees."
|
12
12
|
p.summary = p.paragraphs_of("README.txt", 2).join("\n\n")
|
13
13
|
p.description = p.paragraphs_of("README.txt", 2..6, 8).join("\n\n")
|
14
|
-
p.changes = p.paragraphs_of("History.txt", 1..6).join("\n\n")
|
14
|
+
p.changes = p.paragraphs_of("History.txt", 1..6).join("\n\n").gsub(/\s*===.*\Z/ms, '')
|
15
15
|
p.clean_globs << File.expand_path("~/.ruby_inline")
|
16
16
|
p.extra_deps << ['RubyInline', '>= 3.6.0']
|
17
17
|
p.spec_extras[:require_paths] = proc { |paths| paths << 'test' }
|
data/lib/parse_tree.rb
CHANGED
@@ -41,7 +41,7 @@ end
|
|
41
41
|
|
42
42
|
class ParseTree
|
43
43
|
|
44
|
-
VERSION = '2.0.
|
44
|
+
VERSION = '2.0.2'
|
45
45
|
|
46
46
|
##
|
47
47
|
# Front end translation method.
|
@@ -79,7 +79,7 @@ class ParseTree
|
|
79
79
|
|
80
80
|
def initialize(include_newlines=$DEBUG)
|
81
81
|
if include_newlines then
|
82
|
-
warn "
|
82
|
+
warn "WAR\NING: include_newlines=true from #{caller[0..9].join(', ')}"
|
83
83
|
end
|
84
84
|
@include_newlines = include_newlines
|
85
85
|
end
|
@@ -100,8 +100,6 @@ class ParseTree
|
|
100
100
|
def parse_tree(*klasses)
|
101
101
|
result = []
|
102
102
|
klasses.each do |klass|
|
103
|
-
# TODO: remove this on v 1.1
|
104
|
-
raise "You should call parse_tree_for_method(#{klasses.first}, #{klass}) instead of parse_tree" if Symbol === klass or String === klass
|
105
103
|
klassname = klass.name rescue '' # HACK klass.name should never be nil
|
106
104
|
# Tempfile's DelegateClass(File) seems to
|
107
105
|
# cause this
|
@@ -123,14 +121,12 @@ class ParseTree
|
|
123
121
|
|
124
122
|
method_names.sort.each do |m|
|
125
123
|
r = parse_tree_for_method(klass, m.to_sym)
|
126
|
-
p m => r if r == [nil]
|
127
124
|
code << r
|
128
125
|
end
|
129
126
|
|
130
127
|
klass.modules.each do |mod| # TODO: add a test for this damnit
|
131
128
|
mod.instance_methods.each do |m|
|
132
129
|
r = parse_tree_for_method(mod, m.to_sym)
|
133
|
-
p m => r if r == [nil]
|
134
130
|
code << r
|
135
131
|
end
|
136
132
|
end
|
@@ -254,13 +250,27 @@ p m => r if r == [nil]
|
|
254
250
|
builder.include '"node.h"'
|
255
251
|
builder.include '"st.h"'
|
256
252
|
builder.include '"env.h"'
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
253
|
+
|
254
|
+
if ENV['ANAL'] or ENV['DOMAIN'] =~ /zenspider/ then
|
255
|
+
builder.add_compile_flags "-Wall"
|
256
|
+
builder.add_compile_flags "-W"
|
257
|
+
builder.add_compile_flags "-Wpointer-arith"
|
258
|
+
builder.add_compile_flags "-Wcast-qual"
|
259
|
+
builder.add_compile_flags "-Wcast-align"
|
260
|
+
builder.add_compile_flags "-Wwrite-strings"
|
261
|
+
builder.add_compile_flags "-Wmissing-noreturn"
|
262
|
+
builder.add_compile_flags "-Wno-long-long"
|
263
|
+
|
264
|
+
# NOTE: this flag doesn't work w/ gcc 2.95.x - the FreeBSD default
|
265
|
+
# builder.add_compile_flags "-Wno-strict-aliasing"
|
266
|
+
# ruby.h screws these up hardcore:
|
267
|
+
# builder.add_compile_flags "-Wundef"
|
268
|
+
# builder.add_compile_flags "-Wconversion"
|
269
|
+
# builder.add_compile_flags "-Wstrict-prototypes"
|
270
|
+
# builder.add_compile_flags "-Wmissing-prototypes"
|
271
|
+
# builder.add_compile_flags "-Wsign-compare"
|
272
|
+
end
|
273
|
+
|
264
274
|
# NOTE: If you get weird compiler errors like:
|
265
275
|
# dereferencing type-punned pointer will break strict-aliasing rules
|
266
276
|
# PLEASE do one of the following:
|
@@ -268,18 +278,6 @@ p m => r if r == [nil]
|
|
268
278
|
# 2) Fix it and send me the patch
|
269
279
|
# 3) (quick, but dirty and bad), comment out the following line:
|
270
280
|
builder.add_compile_flags "-Werror"
|
271
|
-
# NOTE: this flag doesn't work w/ gcc 2.95.x - the FreeBSD default
|
272
|
-
# builder.add_compile_flags "-Wno-strict-aliasing"
|
273
|
-
# ruby.h screws these up hardcore:
|
274
|
-
# builder.add_compile_flags "-Wundef"
|
275
|
-
# builder.add_compile_flags "-Wconversion"
|
276
|
-
# builder.add_compile_flags "-Wstrict-prototypes"
|
277
|
-
# builder.add_compile_flags "-Wmissing-prototypes"
|
278
|
-
# builder.add_compile_flags "-Wsign-compare"
|
279
|
-
|
280
|
-
def self.if_version(test, version, str)
|
281
|
-
RUBY_VERSION.send(test, version) ? str : ""
|
282
|
-
end
|
283
281
|
|
284
282
|
builder.prefix %{
|
285
283
|
#define nd_3rd u3.node
|
@@ -300,7 +298,9 @@ p m => r if r == [nil]
|
|
300
298
|
VALUE klass, rklass;
|
301
299
|
VALUE recv;
|
302
300
|
ID id, oid;
|
303
|
-
#
|
301
|
+
#if RUBY_VERSION_CODE > 182
|
302
|
+
int safe_level;
|
303
|
+
#endif
|
304
304
|
NODE *body;
|
305
305
|
};
|
306
306
|
|
@@ -376,7 +376,7 @@ again_no_block:
|
|
376
376
|
}
|
377
377
|
contnode = node->nd_next;
|
378
378
|
|
379
|
-
|
379
|
+
/* FIX: this will break the moment there is a block w/in a block */
|
380
380
|
old_ary = ary;
|
381
381
|
ary = current;
|
382
382
|
node = node->nd_head;
|
@@ -501,10 +501,12 @@ again_no_block:
|
|
501
501
|
add_to_parse_tree(current, node->nd_3rd, newlines, locals);
|
502
502
|
break;
|
503
503
|
|
504
|
+
/*
|
504
505
|
// rescue body:
|
505
506
|
// begin stmt rescue exception => var; stmt; [rescue e2 => v2; s2;]* end
|
506
507
|
// stmt rescue stmt
|
507
508
|
// a = b rescue c
|
509
|
+
*/
|
508
510
|
|
509
511
|
case NODE_RESBODY:
|
510
512
|
if (node->nd_3rd) {
|
@@ -576,7 +578,7 @@ again_no_block:
|
|
576
578
|
}
|
577
579
|
break;
|
578
580
|
|
579
|
-
#
|
581
|
+
#if RUBY_VERSION_CODE < 190
|
580
582
|
case NODE_DMETHOD:
|
581
583
|
{
|
582
584
|
struct METHOD *data;
|
@@ -585,10 +587,9 @@ again_no_block:
|
|
585
587
|
add_to_parse_tree(current, data->body, newlines, locals);
|
586
588
|
break;
|
587
589
|
}
|
588
|
-
#
|
590
|
+
#endif
|
589
591
|
|
590
592
|
case NODE_METHOD:
|
591
|
-
fprintf(stderr, "u1 = %p u2 = %p u3 = %p\\n", node->nd_1st, node->nd_2nd, node->nd_3rd);
|
592
593
|
add_to_parse_tree(current, node->nd_3rd, newlines, locals);
|
593
594
|
break;
|
594
595
|
|
@@ -598,10 +599,9 @@ again_no_block:
|
|
598
599
|
|
599
600
|
case NODE_OP_ASGN1:
|
600
601
|
add_to_parse_tree(current, node->nd_recv, newlines, locals);
|
601
|
-
#
|
602
|
-
#{if_version :<=, "1.8.4", "#if 1"}
|
602
|
+
#if RUBY_VERSION_CODE < 185
|
603
603
|
add_to_parse_tree(current, node->nd_args->nd_next, newlines, locals);
|
604
|
-
rb_ary_pop(rb_ary_entry(current, -1));
|
604
|
+
rb_ary_pop(rb_ary_entry(current, -1)); /* no idea why I need this */
|
605
605
|
#else
|
606
606
|
add_to_parse_tree(current, node->nd_args->nd_2nd, newlines, locals);
|
607
607
|
#endif
|
@@ -664,9 +664,8 @@ again_no_block:
|
|
664
664
|
add_to_parse_tree(current, node->nd_value, newlines, locals);
|
665
665
|
break;
|
666
666
|
|
667
|
-
case NODE_VALIAS:
|
668
|
-
#
|
669
|
-
#{if_version :<=, "1.8.4", "#if 1"}
|
667
|
+
case NODE_VALIAS: /* u1 u2 (alias $global $global2) */
|
668
|
+
#if RUBY_VERSION_CODE < 185
|
670
669
|
rb_ary_push(current, ID2SYM(node->u2.id));
|
671
670
|
rb_ary_push(current, ID2SYM(node->u1.id));
|
672
671
|
#else
|
@@ -674,9 +673,8 @@ again_no_block:
|
|
674
673
|
rb_ary_push(current, ID2SYM(node->u2.id));
|
675
674
|
#endif
|
676
675
|
break;
|
677
|
-
case NODE_ALIAS:
|
678
|
-
#
|
679
|
-
#{if_version :<=, "1.8.4", "#if 1"}
|
676
|
+
case NODE_ALIAS: /* u1 u2 (alias :blah :blah2) */
|
677
|
+
#if RUBY_VERSION_CODE < 185
|
680
678
|
rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u2.id)));
|
681
679
|
rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u1.id)));
|
682
680
|
#else
|
@@ -685,16 +683,15 @@ again_no_block:
|
|
685
683
|
#endif
|
686
684
|
break;
|
687
685
|
|
688
|
-
case NODE_UNDEF:
|
689
|
-
#
|
690
|
-
#{if_version :<=, "1.8.4", "#if 1"}
|
686
|
+
case NODE_UNDEF: /* u2 (undef name, ...) */
|
687
|
+
#if RUBY_VERSION_CODE < 185
|
691
688
|
rb_ary_push(current, wrap_into_node("lit", ID2SYM(node->u2.id)));
|
692
689
|
#else
|
693
690
|
add_to_parse_tree(current, node->nd_value, newlines, locals);
|
694
691
|
#endif
|
695
692
|
break;
|
696
693
|
|
697
|
-
case NODE_COLON3:
|
694
|
+
case NODE_COLON3: /* u2 (::OUTER_CONST) */
|
698
695
|
rb_ary_push(current, ID2SYM(node->u2.id));
|
699
696
|
break;
|
700
697
|
|
@@ -777,28 +774,37 @@ again_no_block:
|
|
777
774
|
break;
|
778
775
|
|
779
776
|
case NODE_ARGS: {
|
780
|
-
|
781
|
-
|
782
|
-
int i;
|
783
|
-
int max_args;
|
784
|
-
NODE *optnode;
|
785
|
-
|
786
|
-
max_args = node->nd_cnt;
|
787
|
-
for (i = 0; i < max_args; i++) {
|
788
|
-
// regular arg names
|
789
|
-
rb_ary_push(current, ID2SYM(locals[i + 3]));
|
790
|
-
}
|
777
|
+
NODE *optnode;
|
778
|
+
int i = 0, max_args = node->nd_cnt;
|
791
779
|
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
780
|
+
/* push regular argument names */
|
781
|
+
for (; i < max_args; i++) {
|
782
|
+
rb_ary_push(current, ID2SYM(locals[i + 3]));
|
783
|
+
}
|
784
|
+
|
785
|
+
/* look for optional arguments */
|
786
|
+
optnode = node->nd_opt;
|
787
|
+
while (optnode) {
|
788
|
+
rb_ary_push(current, ID2SYM(locals[i + 3]));
|
789
|
+
i++;
|
790
|
+
optnode = optnode->nd_next;
|
791
|
+
}
|
799
792
|
|
793
|
+
/* look for vargs */
|
794
|
+
#if RUBY_VERSION_CODE > 184
|
795
|
+
if (node->nd_rest) {
|
796
|
+
VALUE sym = rb_str_new2("*");
|
797
|
+
if (locals[i + 3]) {
|
798
|
+
rb_str_concat(sym, rb_str_new2(rb_id2name(locals[i + 3])));
|
799
|
+
}
|
800
|
+
sym = rb_str_intern(sym);
|
801
|
+
rb_ary_push(current, sym);
|
802
|
+
}
|
803
|
+
#else
|
804
|
+
{
|
805
|
+
long arg_count = (long)node->nd_rest;
|
800
806
|
if (arg_count > 0) {
|
801
|
-
|
807
|
+
/* *arg name */
|
802
808
|
VALUE sym = rb_str_new2("*");
|
803
809
|
if (locals[i + 3]) {
|
804
810
|
rb_str_concat(sym, rb_str_new2(rb_id2name(locals[i + 3])));
|
@@ -806,24 +812,22 @@ again_no_block:
|
|
806
812
|
sym = rb_str_intern(sym);
|
807
813
|
rb_ary_push(current, sym);
|
808
814
|
} else if (arg_count == 0) {
|
809
|
-
|
815
|
+
/* nothing to do in this case, empty list */
|
810
816
|
} else if (arg_count == -1) {
|
811
|
-
|
817
|
+
/* nothing to do in this case, handled above */
|
812
818
|
} else if (arg_count == -2) {
|
813
|
-
|
814
|
-
#if RUBY_VERSION_CODE < 185
|
819
|
+
/* nothing to do in this case, no name == no use */
|
815
820
|
rb_ary_push(current, rb_str_intern(rb_str_new2("*")));
|
816
|
-
#endif
|
817
821
|
} else {
|
818
822
|
rb_raise(rb_eArgError,
|
819
823
|
"not a clue what this arg value is: %ld", arg_count);
|
820
824
|
}
|
825
|
+
}
|
826
|
+
#endif
|
821
827
|
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
add_to_parse_tree(current, node->nd_opt, newlines, locals);
|
826
|
-
}
|
828
|
+
optnode = node->nd_opt;
|
829
|
+
if (optnode) {
|
830
|
+
add_to_parse_tree(current, node->nd_opt, newlines, locals);
|
827
831
|
}
|
828
832
|
} break;
|
829
833
|
|
@@ -837,13 +841,13 @@ again_no_block:
|
|
837
841
|
rb_ary_push(current, ID2SYM(node->nd_vid));
|
838
842
|
break;
|
839
843
|
|
840
|
-
case NODE_XSTR:
|
841
|
-
case NODE_STR:
|
844
|
+
case NODE_XSTR: /* u1 (%x{ls}) */
|
845
|
+
case NODE_STR: /* u1 */
|
842
846
|
case NODE_LIT:
|
843
847
|
rb_ary_push(current, node->nd_lit);
|
844
848
|
break;
|
845
849
|
|
846
|
-
case NODE_MATCH:
|
850
|
+
case NODE_MATCH: /* u1 -> [:lit, u1] */
|
847
851
|
{
|
848
852
|
rb_ary_push(current, wrap_into_node("lit", node->nd_lit));
|
849
853
|
}
|
@@ -853,28 +857,28 @@ again_no_block:
|
|
853
857
|
rb_ary_push(current, INT2FIX(nd_line(node)));
|
854
858
|
rb_ary_push(current, rb_str_new2(node->nd_file));
|
855
859
|
|
856
|
-
if (! RTEST(newlines)) rb_ary_pop(ary);
|
860
|
+
if (! RTEST(newlines)) rb_ary_pop(ary); /* nuke it */
|
857
861
|
|
858
862
|
node = node->nd_next;
|
859
863
|
goto again;
|
860
864
|
break;
|
861
865
|
|
862
|
-
case NODE_NTH_REF:
|
866
|
+
case NODE_NTH_REF: /* u2 u3 ($1) - u3 is local_cnt('~') ignorable? */
|
863
867
|
rb_ary_push(current, INT2FIX(node->nd_nth));
|
864
868
|
break;
|
865
869
|
|
866
|
-
case NODE_BACK_REF:
|
870
|
+
case NODE_BACK_REF: /* u2 u3 ($& etc) */
|
867
871
|
{
|
868
872
|
char c = node->nd_nth;
|
869
873
|
rb_ary_push(current, rb_str_intern(rb_str_new(&c, 1)));
|
870
874
|
}
|
871
875
|
break;
|
872
876
|
|
873
|
-
case NODE_BLOCK_ARG:
|
877
|
+
case NODE_BLOCK_ARG: /* u1 u3 (def x(&b) */
|
874
878
|
rb_ary_push(current, ID2SYM(node->u1.id));
|
875
879
|
break;
|
876
880
|
|
877
|
-
|
881
|
+
/* these nodes are empty and do not require extra work: */
|
878
882
|
case NODE_RETRY:
|
879
883
|
case NODE_FALSE:
|
880
884
|
case NODE_NIL:
|
@@ -887,12 +891,12 @@ again_no_block:
|
|
887
891
|
|
888
892
|
case NODE_SPLAT:
|
889
893
|
case NODE_TO_ARY:
|
890
|
-
case NODE_SVALUE:
|
894
|
+
case NODE_SVALUE: /* a = b, c */
|
891
895
|
add_to_parse_tree(current, node->nd_head, newlines, locals);
|
892
896
|
break;
|
893
897
|
|
894
|
-
case NODE_ATTRASGN:
|
895
|
-
|
898
|
+
case NODE_ATTRASGN: /* literal.meth = y u1 u2 u3 */
|
899
|
+
/* node id node */
|
896
900
|
if (node->nd_1st == RNODE(1)) {
|
897
901
|
add_to_parse_tree(current, NEW_SELF(), newlines, locals);
|
898
902
|
} else {
|
@@ -906,8 +910,8 @@ again_no_block:
|
|
906
910
|
add_to_parse_tree(current, node->nd_2nd, newlines, locals);
|
907
911
|
break;
|
908
912
|
|
909
|
-
case NODE_POSTEXE:
|
910
|
-
|
913
|
+
case NODE_POSTEXE: /* END { ... } */
|
914
|
+
/* Nothing to do here... we are in an iter block */
|
911
915
|
break;
|
912
916
|
|
913
917
|
case NODE_CFUNC:
|
@@ -916,28 +920,28 @@ again_no_block:
|
|
916
920
|
rb_ary_push(current, INT2NUM(node->nd_argc));
|
917
921
|
break;
|
918
922
|
|
919
|
-
#
|
923
|
+
#if RUBY_VERSION_CODE >= 190
|
920
924
|
case NODE_ERRINFO:
|
921
925
|
case NODE_VALUES:
|
922
926
|
case NODE_PRELUDE:
|
923
927
|
case NODE_LAMBDA:
|
924
928
|
puts("no worky in 1.9 yet");
|
925
929
|
break;
|
926
|
-
#
|
930
|
+
#endif
|
927
931
|
|
928
|
-
|
929
|
-
|
930
|
-
case NODE_MEMO:
|
932
|
+
/* Nodes we found but have yet to decypher */
|
933
|
+
/* I think these are all runtime only... not positive but... */
|
934
|
+
case NODE_MEMO: /* enum.c zip */
|
931
935
|
case NODE_CREF:
|
932
|
-
|
933
|
-
|
934
|
-
|
936
|
+
/* #defines: */
|
937
|
+
/* case NODE_LMASK: */
|
938
|
+
/* case NODE_LSHIFT: */
|
935
939
|
default:
|
936
940
|
rb_warn("Unhandled node #%d type '%s'", nd_type(node), rb_id2name(SYM2ID(rb_ary_entry(node_names, nd_type(node)))));
|
937
941
|
if (RNODE(node)->u1.node != NULL) rb_warning("unhandled u1 value");
|
938
942
|
if (RNODE(node)->u2.node != NULL) rb_warning("unhandled u2 value");
|
939
943
|
if (RNODE(node)->u3.node != NULL) rb_warning("unhandled u3 value");
|
940
|
-
if (RTEST(ruby_debug)) fprintf(stderr, "u1 = %p u2 = %p u3 = %p\\n", node->nd_1st, node->nd_2nd, node->nd_3rd);
|
944
|
+
if (RTEST(ruby_debug)) fprintf(stderr, "u1 = %p u2 = %p u3 = %p\\n", (void*)node->nd_1st, (void*)node->nd_2nd, (void*)node->nd_3rd);
|
941
945
|
rb_ary_push(current, INT2FIX(-99));
|
942
946
|
rb_ary_push(current, INT2FIX(nd_type(node)));
|
943
947
|
break;
|
@@ -963,14 +967,14 @@ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE newlines, VALU
|
|
963
967
|
VALUE result = rb_ary_new();
|
964
968
|
VALUE version = rb_const_get_at(rb_cObject,rb_intern("RUBY_VERSION"));
|
965
969
|
|
966
|
-
(void) self;
|
970
|
+
(void) self; /* quell warnings */
|
967
971
|
|
968
972
|
if (strcmp(StringValuePtr(version), #{RUBY_VERSION.inspect})) {
|
969
973
|
rb_fatal("bad version, %s != #{RUBY_VERSION}\\n", StringValuePtr(version));
|
970
974
|
}
|
971
975
|
|
972
976
|
id = rb_to_id(method);
|
973
|
-
if (RTEST(is_cls_meth)) {
|
977
|
+
if (RTEST(is_cls_meth)) { /* singleton method */
|
974
978
|
klass = CLASS_OF(klass);
|
975
979
|
}
|
976
980
|
if (st_lookup(RCLASS(klass)->m_tbl, id, &n)) {
|
@@ -1000,7 +1004,7 @@ static VALUE parse_tree_for_str(VALUE source, VALUE filename, VALUE line,
|
|
1000
1004
|
NODE *node = NULL;
|
1001
1005
|
int critical;
|
1002
1006
|
|
1003
|
-
(void) self;
|
1007
|
+
(void) self; /* quell warnings */
|
1004
1008
|
|
1005
1009
|
tmp = rb_check_string_type(filename);
|
1006
1010
|
if (NIL_P(tmp)) {
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ParseTree
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 2.0.
|
7
|
-
date: 2007-
|
6
|
+
version: 2.0.2
|
7
|
+
date: 2007-09-20 00:00:00 -07:00
|
8
8
|
summary: ParseTree is a C extension (using RubyInline) that extracts the parse tree for an entire class or a specific method and returns it as a s-expression (aka sexp) using ruby's arrays, strings, symbols, and integers.
|
9
9
|
require_paths:
|
10
10
|
- lib
|