nitro 0.10.0 → 0.11.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.
Files changed (99) hide show
  1. data/AUTHORS +4 -1
  2. data/ChangeLog +290 -7
  3. data/README +3 -3
  4. data/RELEASES +94 -0
  5. data/Rakefile +7 -7
  6. data/benchmark/og/bench.rb +11 -10
  7. data/{ChangeLog.1 → doc/ChangeLog.1} +0 -0
  8. data/doc/apache.txt +9 -0
  9. data/doc/architecture.txt +1 -27
  10. data/doc/bugs.txt +11 -4
  11. data/doc/config.txt +22 -0
  12. data/doc/og_config.txt +35 -0
  13. data/doc/og_tutorial.txt +595 -0
  14. data/doc/tutorial.txt +22 -0
  15. data/examples/blog/conf/apache.conf +30 -0
  16. data/examples/blog/conf/lhttpd.conf +2 -2
  17. data/examples/blog/lib/blog/controller.rb +11 -2
  18. data/examples/blog/log/apache.error_log +5528 -0
  19. data/examples/blog/root/fcgi.rb +1 -1
  20. data/examples/blog/run.rb +9 -3
  21. data/examples/flash/run.rb +2 -2
  22. data/examples/no_xsl_blog/conf/apache.conf +30 -0
  23. data/examples/no_xsl_blog/conf/lhttpd.conf +1 -1
  24. data/examples/no_xsl_blog/lib/blog/controller.rb +2 -2
  25. data/examples/no_xsl_blog/log/apache.error_log +68 -0
  26. data/examples/no_xsl_blog/root/fcgi.rb +2 -2
  27. data/examples/no_xsl_blog/run.rb +3 -3
  28. data/examples/og/run.rb +1 -1
  29. data/examples/tiny/conf/apache.conf +29 -4
  30. data/examples/tiny/conf/lhttpd.conf +1 -1
  31. data/examples/tiny/log/apache.error_log +30 -0
  32. data/examples/tiny/root/fcgi.rb +2 -2
  33. data/examples/tiny/root/index.xhtml +1 -1
  34. data/examples/tiny/run.rb +3 -2
  35. data/examples/wee_style/run.rb +7 -9
  36. data/examples/why_wiki/README +5 -0
  37. data/examples/why_wiki/run.rb +57 -0
  38. data/examples/why_wiki/wiki.yml +6 -0
  39. data/examples/wiki.yml +1 -0
  40. data/lib/glue/array.rb +14 -33
  41. data/lib/glue/hash.rb +32 -53
  42. data/lib/glue/pool.rb +9 -12
  43. data/lib/glue/property.rb +31 -9
  44. data/lib/nitro.rb +30 -8
  45. data/lib/nitro/adapters/cgi.rb +23 -3
  46. data/lib/nitro/adapters/webrick.rb +9 -3
  47. data/lib/nitro/builders/form.rb +21 -13
  48. data/lib/nitro/builders/rss.rb +20 -9
  49. data/lib/nitro/builders/table.rb +69 -10
  50. data/lib/nitro/builders/xhtml.rb +13 -4
  51. data/lib/nitro/component.rb +15 -0
  52. data/lib/nitro/conf.rb +4 -3
  53. data/lib/nitro/context.rb +22 -14
  54. data/lib/nitro/controller.rb +63 -5
  55. data/lib/nitro/dispatcher.rb +11 -6
  56. data/lib/nitro/output.rb +28 -0
  57. data/lib/nitro/render.rb +78 -59
  58. data/lib/nitro/request.rb +5 -1
  59. data/lib/nitro/runner.rb +20 -6
  60. data/lib/nitro/session.rb +89 -18
  61. data/lib/nitro/session/drb.rb +31 -0
  62. data/lib/nitro/session/drbserver.rb +71 -0
  63. data/lib/nitro/session/memory.rb +13 -0
  64. data/lib/nitro/simple.rb +7 -0
  65. data/lib/nitro/ui/date-select.rb +2 -5
  66. data/lib/nitro/ui/pager.rb +4 -4
  67. data/lib/nitro/ui/tabs.rb +2 -4
  68. data/lib/nitro/uri.rb +7 -4
  69. data/lib/og.rb +20 -12
  70. data/lib/og/adapter.rb +40 -13
  71. data/lib/og/adapters/filesys.rb +121 -0
  72. data/lib/og/adapters/mysql.rb +10 -5
  73. data/lib/og/adapters/oracle.rb +374 -0
  74. data/lib/og/adapters/psql.rb +10 -23
  75. data/lib/og/adapters/sqlite.rb +3 -3
  76. data/lib/og/backend.rb +2 -2
  77. data/lib/og/connection.rb +6 -6
  78. data/lib/og/database.rb +5 -5
  79. data/lib/og/enchant.rb +6 -2
  80. data/lib/og/meta.rb +56 -26
  81. data/lib/og/mock.rb +1 -1
  82. data/lib/og/typemacros.rb +23 -0
  83. data/lib/parts/content.rb +4 -10
  84. data/test/nitro/adapters/tc_cgi.rb +1 -1
  85. data/test/nitro/builders/tc_rss.rb +1 -1
  86. data/test/nitro/builders/tc_table.rb +30 -0
  87. data/test/nitro/tc_context.rb +4 -0
  88. data/test/nitro/tc_controller.rb +9 -2
  89. data/test/og/tc_filesys.rb +83 -0
  90. data/test/og/tc_meta.rb +55 -0
  91. data/test/tc_og.rb +115 -36
  92. data/vendor/README +11 -5
  93. data/vendor/breakpoint.rb +35 -38
  94. data/vendor/breakpoint_client.rb +119 -80
  95. data/vendor/composite_sexp_processor.rb +43 -0
  96. data/vendor/parse_tree.rb +745 -0
  97. data/vendor/sexp_processor.rb +453 -0
  98. metadata +34 -7
  99. data/examples/no_xsl_blog/conf/app.conf.rb +0 -47
@@ -2,16 +2,18 @@ require 'breakpoint'
2
2
  require 'optparse'
3
3
  require 'timeout'
4
4
 
5
- options = {
5
+ Options = {
6
6
  :ClientURI => nil,
7
7
  :ServerURI => "druby://localhost:42531",
8
- :RetryDelay => 10
8
+ :RetryDelay => 2,
9
+ :Permanent => true,
10
+ :Verbose => false
9
11
  }
10
12
 
11
13
  ARGV.options do |opts|
12
14
  script_name = File.basename($0)
13
15
  opts.banner = [
14
- "Usage: ruby #{script_name} [options] [server uri]",
16
+ "Usage: ruby #{script_name} [Options] [server uri]",
15
17
  "",
16
18
  "This tool lets you connect to a breakpoint service ",
17
19
  "which was started via Breakpoint.activate_drb.",
@@ -28,13 +30,13 @@ ARGV.options do |opts|
28
30
  "connections from the server.",
29
31
  "Default: Find a good URI automatically.",
30
32
  "Example: -c druby://localhost:12345"
31
- ) { |options[:ClientURI]| }
33
+ ) { |Options[:ClientURI]| }
32
34
 
33
35
  opts.on("-s", "--server-uri=uri",
34
36
  "Connect to the server specified at the",
35
37
  "specified uri.",
36
38
  "Default: druby://localhost:42531"
37
- ) { |options[:ServerURI]| }
39
+ ) { |Options[:ServerURI]| }
38
40
 
39
41
  opts.on("-R", "--retry-delay=delay", Integer,
40
42
  "Automatically try to reconnect to the",
@@ -43,112 +45,149 @@ ARGV.options do |opts|
43
45
  "A value of 0 disables automatical",
44
46
  "reconnecting completely.",
45
47
  "Default: 10"
46
- ) { |options[:RetryDelay]| }
48
+ ) { |Options[:RetryDelay]| }
49
+
50
+ opts.on("-P", "--[no-]permanent",
51
+ "Run the breakpoint client in permanent mode.",
52
+ "This means that the client will keep continue",
53
+ "running even after the server has closed the",
54
+ "connection. Useful for example in Rails."
55
+ ) { |Options[:Permanent]| }
56
+
57
+ opts.on("-V", "--[no-]verbose",
58
+ "Run the breakpoint client in verbose mode.",
59
+ "Will produce more messages, for example between",
60
+ "individual breakpoints. This might help in seeing",
61
+ "that the breakpoint client is still alive, but adds",
62
+ "quite a bit of clutter."
63
+ ) { |Options[:Verbose]| }
47
64
 
48
65
  opts.separator ""
49
66
 
50
67
  opts.on("-h", "--help",
51
68
  "Show this help message."
52
69
  ) { puts opts; exit }
70
+ opts.on("-v", "--version",
71
+ "Display the version information."
72
+ ) do
73
+ id = %q$Id: breakpoint_client.rb 91 2005-02-04 22:34:08Z flgr $
74
+ puts id.sub("Id: ", "")
75
+ puts "(Breakpoint::Version = #{Breakpoint::Version})"
76
+ exit
77
+ end
53
78
 
54
79
  opts.parse!
55
80
  end
56
81
 
57
- options[:ServerURI] = ARGV[0] if ARGV[0]
82
+ Options[:ServerURI] = ARGV[0] if ARGV[0]
58
83
 
59
- loop do
60
- DRb.start_service(options[:ClientURI])
84
+ module Handlers
85
+ extend self
61
86
 
62
- begin
63
- service = DRbObject.new(nil, options[:ServerURI])
87
+ def breakpoint_handler(workspace, message)
88
+ puts message
89
+ IRB.start(nil, nil, workspace)
64
90
 
65
- begin
66
- timeout(10) { service.ping }
67
- rescue Timeout::Error, DRb::DRbConnError
68
- puts "",
69
- " *** Breakpoint service didn't respond to ping request ***",
70
- " This likely happened because of a misconfigured ACL (see the",
71
- " documentation of Breakpoint.activate_drb, note that by default",
72
- " you can only connect to a remote Breakpoint service via a SSH",
73
- " tunnel), but might also be caused by an extremely slow connection.",
74
- ""
75
- raise
91
+ puts ""
92
+ if Options[:Verbose] then
93
+ puts "Resumed execution. Waiting for next breakpoint...", ""
76
94
  end
95
+ end
77
96
 
78
- begin
79
- service.register_eval_handler do |code|
80
- result = eval(code, TOPLEVEL_BINDING)
81
- if result
82
- DRbObject.new(result)
83
- else
84
- result
85
- end
86
- end
87
-
88
- service.register_collision_handler do
89
- msg = [
90
- " *** Breakpoint service collision ***",
91
- " Another Breakpoint service tried to use the",
92
- " port already occupied by this one. It will",
93
- " keep waiting until this Breakpoint service",
94
- " is shut down.",
95
- " ",
96
- " If you are using the Breakpoint library for",
97
- " debugging a Rails or other CGI application",
98
- " this likely means that this Breakpoint",
99
- " session belongs to an earlier, outdated",
100
- " request and should be shut down via 'exit'."
101
- ].join("\n")
102
-
103
- if RUBY_PLATFORM["win"] then
104
- # This sucks. Sorry, I'm not doing this because
105
- # I like funky message boxes -- I need to do this
106
- # because on Windows I have no way of displaying
107
- # my notification via puts() when gets() is still
108
- # being performed on STDIN. I have not found a
109
- # better solution.
110
- begin
111
- require 'tk'
112
- root = TkRoot.new { withdraw }
113
- Tk.messageBox('message' => msg, 'type' => 'ok')
114
- root.destroy
115
- rescue Exception
116
- puts "", msg, ""
117
- end
118
- else
119
- puts "", msg, ""
120
- end
121
- end
97
+ def eval_handler(code)
98
+ result = eval(code, TOPLEVEL_BINDING)
99
+ if result then
100
+ DRbObject.new(result)
101
+ else
102
+ result
103
+ end
104
+ end
122
105
 
123
- service.register_handler do |workspace, message|
124
- puts message
125
- IRB.start(nil, nil, workspace)
126
- puts "", "Resumed execution. Waiting for next breakpoint...", ""
106
+ def collision_handler()
107
+ msg = [
108
+ " *** Breakpoint service collision ***",
109
+ " Another Breakpoint service tried to use the",
110
+ " port already occupied by this one. It will",
111
+ " keep waiting until this Breakpoint service",
112
+ " is shut down.",
113
+ " ",
114
+ " If you are using the Breakpoint library for",
115
+ " debugging a Rails or other CGI application",
116
+ " this likely means that this Breakpoint",
117
+ " session belongs to an earlier, outdated",
118
+ " request and should be shut down via 'exit'."
119
+ ].join("\n")
120
+
121
+ if RUBY_PLATFORM["win"] then
122
+ # This sucks. Sorry, I'm not doing this because
123
+ # I like funky message boxes -- I need to do this
124
+ # because on Windows I have no way of displaying
125
+ # my notification via puts() when gets() is still
126
+ # being performed on STDIN. I have not found a
127
+ # better solution.
128
+ begin
129
+ require 'tk'
130
+ root = TkRoot.new { withdraw }
131
+ Tk.messageBox('message' => msg, 'type' => 'ok')
132
+ root.destroy
133
+ rescue Exception
134
+ puts "", msg, ""
127
135
  end
136
+ else
137
+ puts "", msg, ""
138
+ end
139
+ end
140
+ end
128
141
 
129
- puts "Connection established. Waiting for breakpoint...", ""
142
+ # Used for checking whether we are currently in the reconnecting loop.
143
+ reconnecting = false
144
+
145
+ loop do
146
+ DRb.start_service(Options[:ClientURI])
147
+
148
+ begin
149
+ service = DRbObject.new(nil, Options[:ServerURI])
150
+
151
+ begin
152
+ ehandler = Handlers.method(:eval_handler)
153
+ chandler = Handlers.method(:collision_handler)
154
+ handler = Handlers.method(:breakpoint_handler)
155
+ service.eval_handler = ehandler
156
+ service.collision_handler = chandler
157
+ service.handler = handler
158
+
159
+ reconnecting = false
160
+ if Options[:Verbose] then
161
+ puts "Connection established. Waiting for breakpoint...", ""
162
+ end
130
163
 
131
164
  loop do
132
165
  begin
133
166
  service.ping
134
167
  rescue DRb::DRbConnError => error
135
- puts "Server exited. Closing connection..."
168
+ puts "Server exited. Closing connection...", ""
169
+ exit! unless Options[:Permanent]
136
170
  break
137
171
  end
138
172
 
139
173
  sleep(0.5)
140
174
  end
141
175
  ensure
142
- service.unregister_handler
176
+ service.eval_handler = nil
177
+ service.collision_handler = nil
178
+ service.handler = nil
143
179
  end
144
180
  rescue Exception => error
145
- if options[:RetryDelay] > 0 then
146
- puts "No connection to breakpoint service at #{options[:ServerURI]}:",
147
- " (#{error.inspect})"
148
- puts error.backtrace if $DEBUG
149
- puts " Reconnecting in #{options[:RetryDelay]} seconds..."
150
-
151
- sleep options[:RetryDelay]
181
+ if Options[:RetryDelay] > 0 then
182
+ if not reconnecting then
183
+ reconnecting = true
184
+ puts "No connection to breakpoint service at #{Options[:ServerURI]} " +
185
+ "(#{error.class})"
186
+ puts error.backtrace if $DEBUG
187
+ puts "Tries to connect will be made every #{Options[:RetryDelay]} seconds..."
188
+ end
189
+
190
+ sleep Options[:RetryDelay]
152
191
  retry
153
192
  else
154
193
  raise
@@ -0,0 +1,43 @@
1
+ require 'sexp_processor'
2
+
3
+ ##
4
+ # Implements the Composite pattern on SexpProcessor. Need we say more?
5
+ #
6
+ # Yeah... probably. Implements a SexpProcessor of SexpProcessors so
7
+ # you can easily chain multiple to each other. At some stage we plan
8
+ # on having all of them run +process+ and but only ever output
9
+ # something when +generate+ is called, allowing for deferred final
10
+ # processing.
11
+
12
+ class CompositeSexpProcessor < SexpProcessor
13
+
14
+ ##
15
+ # The list o' processors to run.
16
+
17
+ attr_reader :processors
18
+
19
+ def initialize # :nodoc:
20
+ super
21
+ @processors = []
22
+ end
23
+
24
+ ##
25
+ # Add a +processor+ to the list of processors to run.
26
+
27
+ def <<(processor)
28
+ raise ArgumentError, "Can only add sexp processors" unless
29
+ SexpProcessor === processor
30
+ @processors << processor
31
+ end
32
+
33
+ ##
34
+ # Run +exp+ through all of the processors, returning the final
35
+ # result.
36
+
37
+ def process(exp)
38
+ @processors.each do |processor|
39
+ exp = processor.process(exp)
40
+ end
41
+ exp
42
+ end
43
+ end
@@ -0,0 +1,745 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ begin
4
+ require 'rubygems'
5
+ require_gem 'RubyInline'
6
+ rescue LoadError
7
+ require "inline"
8
+ end
9
+
10
+ ##
11
+ # ParseTree is a RubyInline-style extension that accesses and
12
+ # traverses the internal parse tree created by ruby.
13
+ #
14
+ # class Example
15
+ # def blah
16
+ # return 1 + 1
17
+ # end
18
+ # end
19
+ #
20
+ # ParseTree.new.parse_tree(Example)
21
+ # => [[:class, :Example, :Object,
22
+ # [:defn,
23
+ # "blah",
24
+ # [:scope,
25
+ # [:block,
26
+ # [:args],
27
+ # [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]]
28
+
29
+ class ParseTree
30
+
31
+ VERSION = '1.3.3'
32
+
33
+ ##
34
+ # Initializes a ParseTree instance. Includes newline nodes if
35
+ # +include_newlines+ which defaults to +$DEBUG+.
36
+
37
+ def initialize(include_newlines=$DEBUG)
38
+ @include_newlines = include_newlines
39
+ end
40
+
41
+ ##
42
+ # Main driver for ParseTree. Returns an array of arrays containing
43
+ # the parse tree for +klasses+.
44
+ #
45
+ # Structure:
46
+ #
47
+ # [[:class, classname, superclassname, [:defn :method1, ...], ...], ...]
48
+ #
49
+ # NOTE: v1.0 - v1.1 had the signature (klass, meth=nil). This wasn't
50
+ # used much at all and since parse_tree_for_method already existed,
51
+ # it was deemed more useful to expand this method to do multiple
52
+ # classes.
53
+
54
+ def parse_tree(*klasses)
55
+ result = []
56
+ klasses.each do |klass|
57
+ # TODO: remove this on v 1.1
58
+ raise "You should call parse_tree_for_method(#{klasses.first}, #{klass}) instead of parse_tree" if Symbol === klass or String === klass
59
+ klassname = klass.name || '' # HACK klass.name should never be nil
60
+ # Tempfile's DelegateClass(File) seems to
61
+ # cause this
62
+ klassname = "UnnamedClass_#{klass.object_id}" if klassname.empty?
63
+ klassname = klassname.to_sym
64
+
65
+ code = if Class === klass then
66
+ superclass = klass.superclass.name
67
+ superclass = "nil" if superclass.empty?
68
+ superclass = superclass.to_sym
69
+ [:class, klassname, superclass]
70
+ else
71
+ [:module, klassname]
72
+ end
73
+
74
+ klass.instance_methods(false).sort.each do |m|
75
+ $stderr.puts "parse_tree_for_method(#{klass}, #{m}):" if $DEBUG
76
+ code << parse_tree_for_method(klass, m.to_sym)
77
+ end
78
+ result << code
79
+ end
80
+ return result
81
+ end
82
+
83
+ ##
84
+ # Returns the parse tree for just one +method+ of a class +klass+.
85
+ #
86
+ # Format:
87
+ #
88
+ # [:defn, :name, :body]
89
+
90
+ def parse_tree_for_method(klass, method)
91
+ parse_tree_for_meth(klass, method.to_sym, @include_newlines)
92
+ end
93
+
94
+ ############################################################
95
+ # END of rdoc methods
96
+ ############################################################
97
+
98
+ inline do |builder|
99
+ builder.add_type_converter("VALUE", '', '')
100
+ builder.add_type_converter("ID *", '', '')
101
+ builder.add_type_converter("NODE *", '(NODE *)', '(VALUE)')
102
+ builder.include '"intern.h"'
103
+ builder.include '"node.h"'
104
+ builder.include '"st.h"'
105
+ builder.include '"env.h"'
106
+ builder.add_compile_flags "-Wall"
107
+ builder.add_compile_flags "-W"
108
+ builder.add_compile_flags "-Wpointer-arith"
109
+ builder.add_compile_flags "-Wcast-qual"
110
+ builder.add_compile_flags "-Wcast-align"
111
+ builder.add_compile_flags "-Wwrite-strings"
112
+ builder.add_compile_flags "-Wmissing-noreturn"
113
+ # NOTE: If you get weird compiler errors like:
114
+ # dereferencing type-punned pointer will break strict-aliasing rules
115
+ # PLEASE do one of the following:
116
+ # 1) Get me a login on your box so I can repro this and get it fixed.
117
+ # 2) Fix it and send me the patch
118
+ # 3) (quick, but dirty and bad), comment out the following line:
119
+ builder.add_compile_flags "-Werror"
120
+ # NOTE: this flag doesn't work w/ gcc 2.95.x - the FreeBSD default
121
+ # builder.add_compile_flags "-Wno-strict-aliasing"
122
+ # ruby.h screws these up hardcore:
123
+ # builder.add_compile_flags "-Wundef"
124
+ # builder.add_compile_flags "-Wconversion"
125
+ # builder.add_compile_flags "-Wstrict-prototypes"
126
+ # builder.add_compile_flags "-Wmissing-prototypes"
127
+ # builder.add_compile_flags "-Wsign-compare"
128
+
129
+ builder.prefix %q{
130
+ #define nd_3rd u3.node
131
+
132
+ struct METHOD {
133
+ VALUE klass, rklass;
134
+ VALUE recv;
135
+ ID id, oid;
136
+ NODE *body;
137
+ };
138
+
139
+ struct BLOCK {
140
+ NODE *var;
141
+ NODE *body;
142
+ VALUE self;
143
+ struct FRAME frame;
144
+ struct SCOPE *scope;
145
+ VALUE klass;
146
+ NODE *cref;
147
+ int iter;
148
+ int vmode;
149
+ int flags;
150
+ int uniq;
151
+ struct RVarmap *dyna_vars;
152
+ VALUE orig_thread;
153
+ VALUE wrapper;
154
+ VALUE block_obj;
155
+ struct BLOCK *outer;
156
+ struct BLOCK *prev;
157
+ };
158
+
159
+ static char node_type_string[][60] = {
160
+ // 00
161
+ "method", "fbody", "cfunc", "scope", "block",
162
+ "if", "case", "when", "opt_n", "while",
163
+ // 10
164
+ "until", "iter", "for", "break", "next",
165
+ "redo", "retry", "begin", "rescue", "resbody",
166
+ // 20
167
+ "ensure", "and", "or", "not", "masgn",
168
+ "lasgn", "dasgn", "dasgn_curr", "gasgn", "iasgn",
169
+ // 30
170
+ "cdecl", "cvasgn", "cvdecl", "op_asgn1", "op_asgn2",
171
+ "op_asgn_and", "op_asgn_or", "call", "fcall", "vcall",
172
+ // 40
173
+ "super", "zsuper", "array", "zarray", "hash",
174
+ "return", "yield", "lvar", "dvar", "gvar",
175
+ // 50
176
+ "ivar", "const", "cvar", "nth_ref", "back_ref",
177
+ "match", "match2", "match3", "lit", "str",
178
+ // 60
179
+ "dstr", "xstr", "dxstr", "evstr", "dregx",
180
+ "dregx_once", "args", "argscat", "argspush", "splat",
181
+ // 70
182
+ "to_ary", "svalue", "block_arg", "block_pass", "defn",
183
+ "defs", "alias", "valias", "undef", "class",
184
+ // 80
185
+ "module", "sclass", "colon2", "colon3", "cref",
186
+ "dot2", "dot3", "flip2", "flip3", "attrset",
187
+ // 90
188
+ "self", "nil", "true", "false", "defined",
189
+ // 95
190
+ "newline", "postexe",
191
+ #ifdef C_ALLOCA
192
+ "alloca",
193
+ #endif
194
+ "dmethod", "bmethod",
195
+ // 100 / 99
196
+ "memo", "ifunc", "dsym", "attrasgn",
197
+ // 104 / 103
198
+ "last"
199
+ };
200
+ }
201
+
202
+ builder.c_raw %q^
203
+ static void add_to_parse_tree(VALUE ary,
204
+ NODE * n,
205
+ VALUE newlines,
206
+ ID * locals) {
207
+ NODE * volatile node = n;
208
+ NODE * volatile contnode = NULL;
209
+ VALUE old_ary = Qnil;
210
+ VALUE current;
211
+ VALUE node_name;
212
+
213
+ if (!node) return;
214
+
215
+ again:
216
+
217
+ if (node) {
218
+ node_name = ID2SYM(rb_intern(node_type_string[nd_type(node)]));
219
+ if (RTEST(ruby_debug)) {
220
+ fprintf(stderr, "%15s: %s%s%s\n",
221
+ node_type_string[nd_type(node)],
222
+ (RNODE(node)->u1.node != NULL ? "u1 " : " "),
223
+ (RNODE(node)->u2.node != NULL ? "u2 " : " "),
224
+ (RNODE(node)->u3.node != NULL ? "u3 " : " "));
225
+ }
226
+ } else {
227
+ node_name = ID2SYM(rb_intern("ICKY"));
228
+ }
229
+
230
+ current = rb_ary_new();
231
+ rb_ary_push(ary, current);
232
+ rb_ary_push(current, node_name);
233
+
234
+ again_no_block:
235
+
236
+ switch (nd_type(node)) {
237
+
238
+ case NODE_BLOCK:
239
+ if (contnode) {
240
+ add_to_parse_tree(current, node, newlines, locals);
241
+ break;
242
+ }
243
+
244
+ contnode = node->nd_next;
245
+
246
+ // NOTE: this will break the moment there is a block w/in a block
247
+ old_ary = ary;
248
+ ary = current;
249
+ node = node->nd_head;
250
+ goto again;
251
+ break;
252
+
253
+ case NODE_FBODY:
254
+ case NODE_DEFINED:
255
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
256
+ break;
257
+
258
+ case NODE_COLON2:
259
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
260
+ rb_ary_push(current, ID2SYM(node->nd_mid));
261
+ break;
262
+
263
+ case NODE_MATCH2:
264
+ case NODE_MATCH3:
265
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
266
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
267
+ break;
268
+
269
+ case NODE_BEGIN:
270
+ case NODE_OPT_N:
271
+ case NODE_NOT:
272
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
273
+ break;
274
+
275
+ case NODE_IF:
276
+ add_to_parse_tree(current, node->nd_cond, newlines, locals);
277
+ if (node->nd_body) {
278
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
279
+ } else {
280
+ rb_ary_push(current, Qnil);
281
+ }
282
+ if (node->nd_else) {
283
+ add_to_parse_tree(current, node->nd_else, newlines, locals);
284
+ } else {
285
+ rb_ary_push(current, Qnil);
286
+ }
287
+ break;
288
+
289
+ case NODE_CASE:
290
+ add_to_parse_tree(current, node->nd_head, newlines, locals); /* expr */
291
+ node = node->nd_body;
292
+ while (node) {
293
+ add_to_parse_tree(current, node, newlines, locals);
294
+ if (nd_type(node) == NODE_WHEN) { /* when */
295
+ node = node->nd_next;
296
+ } else {
297
+ break; /* else */
298
+ }
299
+ if (! node) {
300
+ rb_ary_push(current, Qnil); /* no else */
301
+ }
302
+ }
303
+ break;
304
+
305
+ case NODE_WHEN:
306
+ add_to_parse_tree(current, node->nd_head, newlines, locals); /* args */
307
+ if (node->nd_body) {
308
+ add_to_parse_tree(current, node->nd_body, newlines, locals); /* body */
309
+ } else {
310
+ rb_ary_push(current, Qnil);
311
+ }
312
+ break;
313
+
314
+ case NODE_WHILE:
315
+ case NODE_UNTIL:
316
+ add_to_parse_tree(current, node->nd_cond, newlines, locals);
317
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
318
+ break;
319
+
320
+ case NODE_BLOCK_PASS:
321
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
322
+ add_to_parse_tree(current, node->nd_iter, newlines, locals);
323
+ break;
324
+
325
+ case NODE_ITER:
326
+ case NODE_FOR:
327
+ add_to_parse_tree(current, node->nd_iter, newlines, locals);
328
+ if (node->nd_var != (NODE *)1
329
+ && node->nd_var != (NODE *)2
330
+ && node->nd_var != NULL) {
331
+ add_to_parse_tree(current, node->nd_var, newlines, locals);
332
+ } else {
333
+ rb_ary_push(current, Qnil);
334
+ }
335
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
336
+ break;
337
+
338
+ case NODE_BREAK:
339
+ case NODE_NEXT:
340
+ case NODE_YIELD:
341
+ if (node->nd_stts)
342
+ add_to_parse_tree(current, node->nd_stts, newlines, locals);
343
+ break;
344
+
345
+ case NODE_RESCUE:
346
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
347
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
348
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
349
+ break;
350
+
351
+ // rescue body:
352
+ // begin stmt rescue exception => var; stmt; [rescue e2 => v2; s2;]* end
353
+ // stmt rescue stmt
354
+ // a = b rescue c
355
+
356
+ case NODE_RESBODY:
357
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
358
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
359
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
360
+ break;
361
+
362
+ case NODE_ENSURE:
363
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
364
+ if (node->nd_ensr) {
365
+ add_to_parse_tree(current, node->nd_ensr, newlines, locals);
366
+ }
367
+ break;
368
+
369
+ case NODE_AND:
370
+ case NODE_OR:
371
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
372
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
373
+ break;
374
+
375
+ case NODE_DOT2:
376
+ case NODE_DOT3:
377
+ case NODE_FLIP2:
378
+ case NODE_FLIP3:
379
+ add_to_parse_tree(current, node->nd_beg, newlines, locals);
380
+ add_to_parse_tree(current, node->nd_end, newlines, locals);
381
+ break;
382
+
383
+ case NODE_RETURN:
384
+ if (node->nd_stts)
385
+ add_to_parse_tree(current, node->nd_stts, newlines, locals);
386
+ break;
387
+
388
+ case NODE_ARGSCAT:
389
+ case NODE_ARGSPUSH:
390
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
391
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
392
+ break;
393
+
394
+ case NODE_CALL:
395
+ case NODE_FCALL:
396
+ case NODE_VCALL:
397
+ if (nd_type(node) != NODE_FCALL)
398
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
399
+ rb_ary_push(current, ID2SYM(node->nd_mid));
400
+ if (node->nd_args || nd_type(node) != NODE_FCALL)
401
+ add_to_parse_tree(current, node->nd_args, newlines, locals);
402
+ break;
403
+
404
+ case NODE_SUPER:
405
+ add_to_parse_tree(current, node->nd_args, newlines, locals);
406
+ break;
407
+
408
+ case NODE_BMETHOD:
409
+ {
410
+ struct BLOCK *data;
411
+ Data_Get_Struct(node->nd_cval, struct BLOCK, data);
412
+ add_to_parse_tree(current, data->var, newlines, locals);
413
+ add_to_parse_tree(current, data->body, newlines, locals);
414
+ break;
415
+ }
416
+ break;
417
+
418
+ case NODE_DMETHOD:
419
+ {
420
+ struct METHOD *data;
421
+ Data_Get_Struct(node->nd_cval, struct METHOD, data);
422
+ rb_ary_push(current, ID2SYM(data->id));
423
+ add_to_parse_tree(current, data->body, newlines, locals);
424
+ break;
425
+ }
426
+
427
+ case NODE_METHOD:
428
+ fprintf(stderr, "u1 = %p u2 = %p u3 = %p\n", node->nd_1st, node->nd_2nd, node->nd_3rd);
429
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
430
+ break;
431
+
432
+ case NODE_SCOPE:
433
+ add_to_parse_tree(current, node->nd_next, newlines, node->nd_tbl);
434
+ break;
435
+
436
+ case NODE_OP_ASGN1:
437
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
438
+ add_to_parse_tree(current, node->nd_args->nd_next, newlines, locals);
439
+ add_to_parse_tree(current, node->nd_args->nd_head, newlines, locals);
440
+ break;
441
+
442
+ case NODE_OP_ASGN2:
443
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
444
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
445
+ break;
446
+
447
+ case NODE_OP_ASGN_AND:
448
+ case NODE_OP_ASGN_OR:
449
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
450
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
451
+ break;
452
+
453
+ case NODE_MASGN:
454
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
455
+ if (node->nd_args) {
456
+ if (node->nd_args != (NODE *)-1) {
457
+ add_to_parse_tree(current, node->nd_args, newlines, locals);
458
+ }
459
+ }
460
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
461
+ break;
462
+
463
+ case NODE_LASGN:
464
+ case NODE_IASGN:
465
+ case NODE_DASGN:
466
+ case NODE_DASGN_CURR:
467
+ case NODE_CDECL:
468
+ case NODE_CVASGN:
469
+ case NODE_CVDECL:
470
+ case NODE_GASGN:
471
+ rb_ary_push(current, ID2SYM(node->nd_vid));
472
+ add_to_parse_tree(current, node->nd_value, newlines, locals);
473
+ break;
474
+
475
+ case NODE_ALIAS: // u1 u2 (alias :blah :blah2)
476
+ case NODE_VALIAS: // u1 u2 (alias $global $global2)
477
+ rb_ary_push(current, ID2SYM(node->u1.id));
478
+ rb_ary_push(current, ID2SYM(node->u2.id));
479
+ break;
480
+
481
+ case NODE_COLON3: // u2 (::OUTER_CONST)
482
+ case NODE_UNDEF: // u2 (undef instvar)
483
+ rb_ary_push(current, ID2SYM(node->u2.id));
484
+ break;
485
+
486
+ case NODE_HASH:
487
+ {
488
+ NODE *list;
489
+
490
+ list = node->nd_head;
491
+ while (list) {
492
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
493
+ list = list->nd_next;
494
+ if (list == 0)
495
+ rb_bug("odd number list for Hash");
496
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
497
+ list = list->nd_next;
498
+ }
499
+ }
500
+ break;
501
+
502
+ case NODE_ARRAY:
503
+ while (node) {
504
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
505
+ node = node->nd_next;
506
+ }
507
+ break;
508
+
509
+ case NODE_DSTR:
510
+ case NODE_DXSTR:
511
+ case NODE_DREGX:
512
+ case NODE_DREGX_ONCE:
513
+ {
514
+ NODE *list = node->nd_next;
515
+ if (nd_type(node) == NODE_DREGX || nd_type(node) == NODE_DREGX_ONCE) {
516
+ break;
517
+ }
518
+ rb_ary_push(current, rb_str_new3(node->nd_lit));
519
+ while (list) {
520
+ if (list->nd_head) {
521
+ switch (nd_type(list->nd_head)) {
522
+ case NODE_STR:
523
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
524
+ break;
525
+ case NODE_EVSTR:
526
+ add_to_parse_tree(current, list->nd_head->nd_body, newlines, locals);
527
+ break;
528
+ default:
529
+ add_to_parse_tree(current, list->nd_head, newlines, locals);
530
+ break;
531
+ }
532
+ }
533
+ list = list->nd_next;
534
+ }
535
+ }
536
+ break;
537
+
538
+ case NODE_DEFN:
539
+ case NODE_DEFS:
540
+ if (node->nd_defn) {
541
+ if (nd_type(node) == NODE_DEFS)
542
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
543
+ rb_ary_push(current, ID2SYM(node->nd_mid));
544
+ add_to_parse_tree(current, node->nd_defn, newlines, locals);
545
+ }
546
+ break;
547
+
548
+ case NODE_CLASS:
549
+ case NODE_MODULE:
550
+ rb_ary_push(current, ID2SYM((ID)node->nd_cpath->nd_mid));
551
+ if (node->nd_super && nd_type(node) == NODE_CLASS) {
552
+ add_to_parse_tree(current, node->nd_super, newlines, locals);
553
+ }
554
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
555
+ break;
556
+
557
+ case NODE_SCLASS:
558
+ add_to_parse_tree(current, node->nd_recv, newlines, locals);
559
+ add_to_parse_tree(current, node->nd_body, newlines, locals);
560
+ break;
561
+
562
+ case NODE_ARGS:
563
+ if (locals &&
564
+ (node->nd_cnt || node->nd_opt || node->nd_rest != -1)) {
565
+ int i;
566
+ NODE *optnode;
567
+ long arg_count;
568
+
569
+ for (i = 0; i < node->nd_cnt; i++) {
570
+ // regular arg names
571
+ rb_ary_push(current, ID2SYM(locals[i + 3]));
572
+ }
573
+
574
+ optnode = node->nd_opt;
575
+ while (optnode) {
576
+ // optional arg names
577
+ rb_ary_push(current, ID2SYM(locals[i + 3]));
578
+ i++;
579
+ optnode = optnode->nd_next;
580
+ }
581
+
582
+ arg_count = node->nd_rest;
583
+ if (arg_count > 0) {
584
+ // *arg name
585
+ rb_ary_push(current, ID2SYM(locals[node->nd_rest + 1]));
586
+ } else if (arg_count == -1) {
587
+ // nothing to do in this case, handled above
588
+ } else if (arg_count == -2) {
589
+ // nothing to do in this case, no name == no use
590
+ } else {
591
+ puts("not a clue what this arg value is");
592
+ exit(1);
593
+ }
594
+
595
+ optnode = node->nd_opt;
596
+ // block?
597
+ if (optnode) {
598
+ add_to_parse_tree(current, node->nd_opt, newlines, locals);
599
+ }
600
+ }
601
+ break;
602
+
603
+ case NODE_LVAR:
604
+ case NODE_DVAR:
605
+ case NODE_IVAR:
606
+ case NODE_CVAR:
607
+ case NODE_GVAR:
608
+ case NODE_CONST:
609
+ case NODE_ATTRSET:
610
+ rb_ary_push(current, ID2SYM(node->nd_vid));
611
+ break;
612
+
613
+ case NODE_XSTR: // u1 (%x{ls})
614
+ case NODE_STR: // u1
615
+ case NODE_LIT:
616
+ case NODE_MATCH:
617
+ rb_ary_push(current, node->nd_lit);
618
+ break;
619
+
620
+ case NODE_NEWLINE:
621
+ rb_ary_push(current, INT2FIX(nd_line(node)));
622
+ rb_ary_push(current, rb_str_new2(node->nd_file));
623
+
624
+ if (! RTEST(newlines)) rb_ary_pop(ary); // nuke it
625
+
626
+ node = node->nd_next;
627
+ goto again;
628
+ break;
629
+
630
+ case NODE_NTH_REF: // u2 u3 ($1) - u3 is local_cnt('~') ignorable?
631
+ rb_ary_push(current, INT2FIX(node->nd_nth));
632
+ break;
633
+
634
+ case NODE_BACK_REF: // u2 u3 ($& etc)
635
+ {
636
+ char c = node->nd_nth;
637
+ rb_ary_push(current, rb_str_intern(rb_str_new(&c, 1)));
638
+ }
639
+ break;
640
+
641
+ case NODE_BLOCK_ARG: // u1 u3 (def x(&b)
642
+ rb_ary_push(current, ID2SYM(node->u1.id));
643
+ break;
644
+
645
+ // these nodes are empty and do not require extra work:
646
+ case NODE_RETRY:
647
+ case NODE_FALSE:
648
+ case NODE_NIL:
649
+ case NODE_SELF:
650
+ case NODE_TRUE:
651
+ case NODE_ZARRAY:
652
+ case NODE_ZSUPER:
653
+ case NODE_REDO:
654
+ break;
655
+
656
+ case NODE_SPLAT:
657
+ case NODE_TO_ARY:
658
+ case NODE_SVALUE: // a = b, c
659
+ add_to_parse_tree(current, node->nd_head, newlines, locals);
660
+ break;
661
+
662
+ case NODE_ATTRASGN: // literal.meth = y u1 u2 u3
663
+ // node id node
664
+ if (node->nd_1st == RNODE(1)) {
665
+ add_to_parse_tree(current, NEW_SELF(), newlines, locals);
666
+ } else {
667
+ add_to_parse_tree(current, node->nd_1st, newlines, locals);
668
+ }
669
+ rb_ary_push(current, ID2SYM(node->u2.id));
670
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
671
+ break;
672
+
673
+ case NODE_DSYM: // :"#{foo}" u1 u2 u3
674
+ add_to_parse_tree(current, node->nd_3rd, newlines, locals);
675
+ break;
676
+
677
+ case NODE_EVSTR:
678
+ add_to_parse_tree(current, node->nd_2nd, newlines, locals);
679
+ break;
680
+
681
+ case NODE_POSTEXE: // END { ... }
682
+ // Nothing to do here... we are in an iter block
683
+ break;
684
+
685
+ case NODE_CFUNC:
686
+ rb_ary_push(current, INT2FIX(node->nd_cfnc));
687
+ rb_ary_push(current, INT2FIX(node->nd_argc));
688
+ break;
689
+
690
+ // Nodes we found but have yet to decypher
691
+ // I think these are all runtime only... not positive but...
692
+ case NODE_MEMO: // enum.c zip
693
+ case NODE_CREF:
694
+ case NODE_IFUNC:
695
+ // #defines:
696
+ // case NODE_LMASK:
697
+ // case NODE_LSHIFT:
698
+ default:
699
+ rb_warn("Unhandled node #%d type '%s'", nd_type(node), node_type_string[nd_type(node)]);
700
+ if (RNODE(node)->u1.node != NULL) rb_warning("unhandled u1 value");
701
+ if (RNODE(node)->u2.node != NULL) rb_warning("unhandled u2 value");
702
+ if (RNODE(node)->u3.node != NULL) rb_warning("unhandled u3 value");
703
+ if (RTEST(ruby_debug)) fprintf(stderr, "u1 = %p u2 = %p u3 = %p\n", node->nd_1st, node->nd_2nd, node->nd_3rd);
704
+ rb_ary_push(current, INT2FIX(-99));
705
+ rb_ary_push(current, INT2FIX(nd_type(node)));
706
+ break;
707
+ }
708
+
709
+ // finish:
710
+ if (contnode) {
711
+ node = contnode;
712
+ contnode = NULL;
713
+ current = ary;
714
+ ary = old_ary;
715
+ old_ary = Qnil;
716
+ goto again_no_block;
717
+ }
718
+ }
719
+ ^ # end of add_to_parse_tree block
720
+
721
+ builder.c %q{
722
+ static VALUE parse_tree_for_meth(VALUE klass, VALUE method, VALUE newlines) {
723
+ VALUE n;
724
+ NODE *node = NULL;
725
+ ID id;
726
+ VALUE result = rb_ary_new();
727
+
728
+ (void) self; // quell warnings
729
+ (void) argc; // quell warnings
730
+
731
+ id = rb_to_id(method);
732
+ if (st_lookup(RCLASS(klass)->m_tbl, id, &n)) {
733
+ node = (NODE*)n;
734
+ rb_ary_push(result, ID2SYM(rb_intern("defn")));
735
+ rb_ary_push(result, ID2SYM(id));
736
+ add_to_parse_tree(result, node->nd_body, newlines, NULL);
737
+ } else {
738
+ rb_ary_push(result, Qnil);
739
+ }
740
+
741
+ return result;
742
+ }
743
+ }
744
+ end # inline call
745
+ end # ParseTree class