nitro 0.3.0 → 0.4.1

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 (148) hide show
  1. data/ChangeLog +284 -0
  2. data/{LICENCE → LICENSE} +1 -1
  3. data/README +13 -17
  4. data/RELEASES +13 -1
  5. data/Rakefile +1 -9
  6. data/bin/cluster.rb +5 -5
  7. data/examples/blog/README +45 -0
  8. data/examples/blog/apache.conf +0 -0
  9. data/examples/blog/app.rb +21 -0
  10. data/examples/blog/config.rb +88 -0
  11. data/examples/blog/lib/blog.rb +104 -0
  12. data/examples/blog/log/app.log +117 -0
  13. data/examples/blog/root/comments.xhtml +38 -0
  14. data/examples/blog/root/entry_form.xhtml +18 -0
  15. data/examples/blog/root/index.xhtml +43 -0
  16. data/examples/blog/root/login.xhtml +24 -0
  17. data/examples/blog/root/m/bubbles.gif +0 -0
  18. data/examples/blog/root/m/comments_curve.gif +0 -0
  19. data/examples/blog/root/m/down.gif +0 -0
  20. data/examples/blog/root/m/footer_bg.gif +0 -0
  21. data/examples/blog/root/m/garrow.gif +0 -0
  22. data/examples/blog/root/m/gbull.gif +0 -0
  23. data/examples/blog/root/m/grbull.gif +0 -0
  24. data/examples/blog/root/m/h1_bg.gif +0 -0
  25. data/examples/blog/root/m/header_bg.gif +0 -0
  26. data/examples/blog/root/m/obull.gif +0 -0
  27. data/examples/blog/root/m/page_bg.gif +0 -0
  28. data/examples/blog/root/m/side_title_bg.gif +0 -0
  29. data/examples/blog/root/m/sidebar_bg.gif +0 -0
  30. data/examples/blog/root/recent_posts.xhtml +14 -0
  31. data/examples/blog/root/style.css +201 -0
  32. data/examples/blog/root/style.xsl +118 -0
  33. data/examples/blog/root/view_entry.xhtml +29 -0
  34. data/examples/og/run.rb +27 -29
  35. data/examples/tiny/README +3 -4
  36. data/examples/tiny/app.rb +6 -16
  37. data/examples/tiny/config.rb +30 -0
  38. data/examples/tiny/log/app.log +23 -0
  39. data/examples/tiny/root/{index.sx → index.xhtml} +3 -6
  40. data/lib/{n/std.rb → nitro.rb} +9 -4
  41. data/lib/{n → nitro}/application.rb +13 -7
  42. data/lib/{n → nitro}/config.rb +38 -8
  43. data/lib/{n → nitro}/events.rb +1 -1
  44. data/lib/{n → nitro}/l10n.rb +1 -1
  45. data/lib/{n → nitro}/logger.rb +8 -8
  46. data/lib/{n → nitro}/macros.rb +3 -3
  47. data/lib/{n → nitro}/mixins.rb +1 -1
  48. data/lib/nitro/properties.rb +301 -0
  49. data/lib/{n → nitro}/server.rb +2 -2
  50. data/lib/{n → nitro}/server/appserver.rb +14 -5
  51. data/lib/{n → nitro}/server/cluster.rb +5 -5
  52. data/lib/{n → nitro}/server/cookie.rb +1 -1
  53. data/lib/nitro/server/dispatcher.rb +66 -0
  54. data/lib/{n → nitro}/server/filters.rb +7 -7
  55. data/lib/{n → nitro}/server/filters/autologin.rb +3 -3
  56. data/lib/{n → nitro}/server/fragment.rb +3 -3
  57. data/lib/{n → nitro}/server/handlers.rb +3 -3
  58. data/lib/nitro/server/render.rb +200 -0
  59. data/lib/{n → nitro}/server/request.rb +6 -6
  60. data/lib/{n → nitro}/server/requestpart.rb +5 -5
  61. data/lib/{n → nitro}/server/script.rb +3 -3
  62. data/lib/{n → nitro}/server/server.rb +4 -4
  63. data/lib/{n → nitro}/server/session.rb +3 -3
  64. data/lib/nitro/server/shaders.rb +165 -0
  65. data/lib/{n → nitro}/server/user.rb +1 -1
  66. data/lib/nitro/server/webrick.rb +175 -0
  67. data/lib/nitro/service.rb +25 -0
  68. data/lib/{n → nitro}/sitemap.rb +2 -2
  69. data/lib/{n → nitro}/ui/date-select.rb +0 -0
  70. data/lib/{n → nitro}/ui/pager.rb +1 -1
  71. data/lib/{n → nitro}/ui/popup.rb +1 -1
  72. data/lib/{n → nitro}/ui/select.rb +1 -1
  73. data/lib/{n → nitro}/ui/tabs.rb +1 -1
  74. data/lib/{n → nitro}/utils/array.rb +1 -1
  75. data/lib/{n → nitro}/utils/cache.rb +1 -1
  76. data/lib/{n → nitro}/utils/gfx.rb +1 -1
  77. data/lib/{n → nitro}/utils/hash.rb +1 -1
  78. data/lib/{n → nitro}/utils/html.rb +1 -1
  79. data/lib/{n → nitro}/utils/http.rb +1 -1
  80. data/lib/{n → nitro}/utils/mail.rb +1 -1
  81. data/lib/{n → nitro}/utils/number.rb +1 -1
  82. data/lib/{n → nitro}/utils/pool.rb +1 -1
  83. data/lib/{n → nitro}/utils/string.rb +19 -95
  84. data/lib/{n → nitro}/utils/template.rb +0 -0
  85. data/lib/{n → nitro}/utils/time.rb +1 -1
  86. data/lib/{n → nitro}/utils/uri.rb +3 -3
  87. data/lib/nitro/version.rb +11 -0
  88. data/lib/{n/og.rb → og.rb} +61 -31
  89. data/lib/{n/og → og}/backend.rb +13 -7
  90. data/lib/{n/og → og}/backends/mysql.rb +43 -39
  91. data/lib/{n/og → og}/backends/psql.rb +42 -38
  92. data/lib/{n/og → og}/connection.rb +21 -9
  93. data/lib/{n/og → og}/meta.rb +18 -12
  94. data/lib/xsl/base.xsl +11 -88
  95. data/test/n/server/tc_cookie.rb +1 -1
  96. data/test/n/server/tc_filters.rb +1 -1
  97. data/test/n/server/tc_request.rb +3 -3
  98. data/test/n/server/tc_requestpart.rb +2 -2
  99. data/test/n/server/tc_session.rb +1 -1
  100. data/test/n/tc_events.rb +1 -1
  101. data/test/n/tc_og.rb +16 -18
  102. data/test/n/tc_properties.rb +22 -18
  103. data/test/n/tc_sitemap.rb +2 -2
  104. data/test/n/ui/tc_pager.rb +4 -4
  105. data/test/n/utils/tc_cache.rb +1 -1
  106. data/test/n/utils/tc_hash.rb +1 -1
  107. data/test/n/utils/tc_html.rb +1 -1
  108. data/test/n/utils/tc_http.rb +1 -1
  109. data/test/n/utils/tc_number.rb +1 -1
  110. data/test/n/utils/tc_strings.rb +1 -46
  111. data/test/n/utils/tc_uri.rb +1 -1
  112. metadata +101 -108
  113. data/examples/simple/README +0 -42
  114. data/examples/simple/app.rb +0 -31
  115. data/examples/simple/conf/apache.conf +0 -100
  116. data/examples/simple/conf/config.rb +0 -72
  117. data/examples/simple/conf/debug-config.rb +0 -26
  118. data/examples/simple/conf/live-config.rb +0 -26
  119. data/examples/simple/conf/requires.rb +0 -43
  120. data/examples/simple/ctl +0 -32
  121. data/examples/simple/env.rb +0 -32
  122. data/examples/simple/install.rb +0 -12
  123. data/examples/simple/lib/articles/entities.rb +0 -37
  124. data/examples/simple/lib/articles/lc-en.rb +0 -36
  125. data/examples/simple/lib/articles/methods.rb +0 -55
  126. data/examples/simple/lib/articles/part.rb +0 -57
  127. data/examples/simple/root/add-article.sx +0 -15
  128. data/examples/simple/root/article-form.ss +0 -20
  129. data/examples/simple/root/comments-form.ss +0 -16
  130. data/examples/simple/root/comments.si +0 -30
  131. data/examples/simple/root/index.sx +0 -44
  132. data/examples/simple/root/shader/shader.xsl +0 -100
  133. data/examples/simple/root/shader/style.css +0 -9
  134. data/examples/simple/root/view-article.sx +0 -29
  135. data/examples/tiny/conf/config.rb +0 -62
  136. data/examples/tiny/conf/requires.rb +0 -33
  137. data/examples/tiny/ctl +0 -16
  138. data/lib/n/parts.rb +0 -157
  139. data/lib/n/properties.rb +0 -199
  140. data/lib/n/server/dispatcher.rb +0 -55
  141. data/lib/n/server/handlers/code-handler.rb +0 -182
  142. data/lib/n/server/handlers/page-handler.rb +0 -612
  143. data/lib/n/server/webrick.rb +0 -283
  144. data/lib/n/shaders.rb +0 -166
  145. data/lib/n/sync/clc.rb +0 -110
  146. data/lib/n/sync/handler.rb +0 -229
  147. data/lib/n/sync/server.rb +0 -176
  148. data/lib/p/README +0 -1
@@ -1,283 +0,0 @@
1
- # code:
2
- # * George Moschovitis <gm@navel.gr>
3
- # * Elias Athanasopoulos <elathan@navel.gr>
4
- #
5
- # (c) 2004 Navel, all rights reserved.
6
- # $Id: webrick.rb 118 2004-11-01 10:13:42Z gmosx $
7
-
8
- require "drb"
9
- require "cgi"
10
- require "singleton"
11
- require "webrick"
12
-
13
- require "n/logger"
14
- require "n/application"
15
- require "n/utils/cache"
16
- require "n/server/request"
17
- require "n/server/request"
18
- require "n/server/handlers"
19
- require "n/server/session"
20
- require "n/server/appserver"
21
-
22
- # Override WEBrick to suit our needs.
23
- #
24
- module WEBrick
25
- class HTTPRequest
26
- alias_method :old_parse_uri, :parse_uri
27
- def parse_uri(str, scheme="http")
28
- old_parse_uri(__rewrite(str.dup), scheme)
29
- end
30
-
31
- # gmosx, FIXME: temp hack!
32
- #
33
- def __rewrite(uri)
34
- # FIXME: scan for first ONLY.
35
- realm = uri.scan(/^\/(.*?)\//)
36
- realm = realm[0][0] unless realm.empty?
37
-
38
- if rules = $rewrites[realm]
39
- for rule in rules
40
- return uri if uri.gsub!(rule[0], rule[1])
41
- end
42
- end
43
-
44
- return uri
45
- end
46
- end
47
-
48
- # Expose some response variables.
49
- #
50
- class HTTPResponse
51
- attr_writer :header
52
- attr_writer :cookies
53
- end
54
- end
55
-
56
- module N
57
-
58
- # = Webrick AppServer
59
- #
60
- # The Application Server. Handles dynamic requests in a web application.
61
- # Dont keepalive (or use a VERY SMALL keepalive). Typically this server
62
- # is used along with a standard http server that handles other resources.
63
- #
64
- # Used temporarily unitl we build our own app server.
65
- #
66
- class Webrick < N::AppServer
67
- include WEBrick
68
-
69
- # the integrated webrock server.
70
- attr_accessor :webrick
71
-
72
- def initialize(name = "WebrickServer")
73
- super
74
- end
75
-
76
- # Start the application server.
77
- #
78
- def start
79
- accesslog = WEBrick::BasicLog::new("/dev/null")
80
- referer = WEBrick::BasicLog::new("/dev/null")
81
-
82
- @webrick = HTTPServer.new(
83
- :BindAddress => $appsrv_address,
84
- :Port => $appsrv_port,
85
- :DocumentRoot => $root_dir,
86
- # gmosx, FIXME: this shit still logs!!
87
- :Logger => Log.new(nil, WEBrick::Log::WARN),
88
- # elathan: amateur...
89
- :AccessLog => [
90
- [accesslog, AccessLog::COMMON_LOG_FORMAT],
91
- [referer, AccessLog::REFERER_LOG_FORMAT]
92
- ]
93
- )
94
-
95
- @webrick.mount("/", N::WebrickServlet)
96
-
97
- trap("INT") {
98
- @webrick.shutdown()
99
- }
100
-
101
- @webrick.start()
102
- end
103
-
104
- # Stop the application server.
105
- #
106
- def stop
107
- @webrick.stop
108
- end
109
-
110
- end
111
-
112
- # = WebrickServlet
113
- #
114
- # A webrick servlet that implements the Nitro Engine.
115
- #
116
- # TODO: Lots of stuff should be factored out!
117
- #
118
- class WebrickServlet < WEBrick::HTTPServlet::AbstractServlet
119
- include WEBrick
120
-
121
- # Handle a HTTP GET request.
122
- #
123
- def do_GET(wreq, wres)
124
- request = create_request(wreq)
125
- request.session = create_session(request)
126
-
127
- extension = N::StringUtils.extension_from_path(request.path)
128
- if handler = $srv_extension_map[extension]
129
- handler = handler[1]
130
- else
131
- $log.error "Cannot handle '#{request.path}'"
132
- return nil
133
- end
134
-
135
- begin
136
- $og.get_connection if $og
137
- fragment, script = handler.process(request)
138
-
139
- if fragment
140
- request.out["Content-Type"] = "text/html" unless request.out["Content-Type"]
141
- request.out_buffer = fragment.body
142
- end
143
-
144
- unless request.expires?
145
- request.expires!(Time.now())
146
- end
147
-
148
- rescue Exception, StandardError => e
149
- $log.error "error while handling the request #{request.uri}"
150
- $log.error pp_exception(e)
151
-
152
- if $error_page_url
153
- # internal redirect to error page.
154
- # gmosx: reset handler for .rx pages.
155
- handler = $srv_extension_map["sx"][1]
156
- request.path = $error_page_url
157
- retry
158
- else
159
- # no custom error page defined. Presen a simple yet
160
- # useful error screen.
161
- request.out["Content-Type"] = "text/html"
162
- body = %{
163
- <h1>ERROR</h1>
164
- <p>Click <a href="#{request.referer}">here</a> to return
165
- to the previous page.</p>
166
- }
167
- if request.error_log
168
- body << %{
169
- <h3>Request error log</h3>
170
- <pre>#{request.error_log.join("\n")}</pre>
171
- }
172
- end
173
- body << %{
174
- <h3>Exception</h3>
175
- <pre>#{pp_exception(e)}</pre>
176
- }
177
- request.out_buffer = body
178
- end
179
- ensure
180
- $og.put_connection if $og
181
- end
182
-
183
- # gmosx: optimize me, do something more clever!!!
184
- request.session.synchronize!
185
-
186
- wres.status = request.status
187
- wres.header = request.out
188
- wres.cookies = request.out_cookies.values()
189
- wres.body = request.out_buffer
190
- end
191
-
192
- alias :do_POST :do_GET
193
-
194
- #-------------------------------------------------------------------------------
195
-
196
- private
197
-
198
- # Convert a webrick request to an engine request
199
- # FIXME: this is UNOPTIMIZED code!
200
- #
201
- def create_request(wreq)
202
- # FIXME: use a resource pool!
203
- request = N::Request.new
204
-
205
- request.uri = wreq.unparsed_uri
206
- request.translated_uri = wreq.path_info
207
- request.path = wreq.path
208
- # enforce filename if missing, FIXME: improve this.
209
- request.path << $index_filename if request.path[-1] == ?/
210
- # request.path_info = wreq.path_info
211
- request.query_string = wreq.query_string
212
- request.method = wreq.request_method
213
- # gmosx: X-FORWARDED-FOR is used in a proxy configuration.
214
- request.remote_addr = wreq["X-FORWARDED-FOR"] || wreq["REMOTE_ADDR"]
215
-
216
- # gmosx: remove this ??
217
- request.in = {}
218
- wreq.header.each { |k, v|
219
- # gmosx: upcase to make compatible with n2 codebase.
220
- request.in[k.upcase] = v[0]
221
- }
222
-
223
- request.parts = {}
224
- request.parameters = {}
225
-
226
- wreq.query.each { |k, v|
227
- if v.filename
228
- request.parts[k] = N::RequestPart.new(v.filename, v)
229
- else
230
- request.parameters[k] = v
231
- end
232
- }
233
-
234
- request.in_cookies = {}
235
- wreq.cookies.each { |c|
236
- request.in_cookies[c.name] = c
237
- }
238
-
239
- # gmosx: is this STILL needed??
240
- #
241
- # INVESTIGATE, FIXME: this is a hack!
242
- # apache prepends $srv_url and fucks up msie.
243
- # FIXME: add unit test for this!
244
- if ref = request.in["REFERER"]
245
- split_re = Regexp.new($srv_url) unless split_re
246
- xref = ref.split(split_re).last
247
- if N::StringUtils.valid?(xref)
248
- request.in["REFERER"] = xref
249
- end
250
- end
251
-
252
- return request
253
- end
254
-
255
- # Create session
256
- #
257
- def create_session(request)
258
- session = nil
259
- session_id = nil
260
-
261
- # gmosx: i have to fix the get_cookie method to return a
262
- # full cookie object.
263
-
264
- if session_id = request.get_cookie(N::Session::COOKIE_NAME)
265
- session = $sessions[session_id]
266
- $log.debug "Stale session cookie: #{session_id}" unless session
267
- # FIXME: remove cookie if stale!
268
- else
269
- session_id = N::Session.calculate_id()
270
- cookie = N::Cookie.new(N::Session::COOKIE_NAME, session_id)
271
- request.out_cookies[N::Session::COOKIE_NAME] = cookie
272
- end
273
-
274
- # session not found and must be created
275
- unless session
276
- session = N::Session.new(session_id)
277
- end
278
-
279
- return session
280
- end
281
- end
282
-
283
- end # module
@@ -1,166 +0,0 @@
1
- # code:
2
- # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: shaders.rb 109 2004-10-27 09:12:45Z gmosx $
6
-
7
- module N;
8
-
9
- # = Shader
10
- #
11
- # The equivalent of a 3d engine shader. Converts the page representation
12
- # to the html output. Actually converts it to a dynamic page ready for
13
- # evaluation.
14
- #
15
- # === Design:
16
- #
17
- # We follow the xp methodology: the shader as simple as possible.
18
- # In the future we may add mulitple xsls (xsl pipeline) but
19
- # we done need them now, so we wont code them!
20
- #
21
- # - when compiling get the default shader and keep it in the
22
- # script structure.
23
- #
24
- # noo better push them in a request stack!
25
- #
26
- # - when rendering:
27
- # if there is an override shader use it! (example: inject shader)
28
- # if there is a parent shader use it!
29
- # if there is a script shader use it!
30
- # if there is a user shader use it!
31
- # if there is an app shader use it!
32
- # no shading!
33
- #
34
- # === Think:
35
- #
36
- # - are inject override shaders possible ? (no they are
37
- # dynamic)
38
- #
39
- # === TODO:
40
- #
41
- # - add monitoring support for xsl's.
42
- #
43
- # One shader can utilize several xsls to render different pages.
44
- # the shader selection may be time consuming but is performed once
45
- # when transforming the script, so its essentially for free (and
46
- # anyway the xsl transoformation is orders of magnitude slower)
47
- #
48
- # There is no need to keep post xsl. I can reuse the same xsl
49
- # by calling transform again.
50
- #
51
- class Shader
52
- attr_accessor :name
53
- attr_accessor :xsl_filename
54
- # the xslt transoformer.
55
- attr_accessor :xslt
56
- attr_accessor :mtime
57
-
58
- def initialize(name, xsl_filename)
59
- # leave this require here. only inlcude the xslt
60
- # library if the project needs it.
61
- require "xml/xslt"
62
-
63
- @name = name
64
- @xsl_filename = xsl_filename
65
- @xslt = XML::XSLT.new
66
- parse_xsl!
67
- end
68
-
69
- # transform the given document
70
- #
71
- def xsl_transform(document)
72
- @xslt.xml = document
73
- return @xslt.serve()
74
- end
75
- alias_method :transform, :xsl_transform
76
-
77
- def xsl
78
- parse_xsl! if $reload_xsl
79
- return @xsl
80
- end
81
-
82
- def to_s
83
- @name
84
- end
85
-
86
- private
87
-
88
- # Parse the xsl.
89
- #
90
- def parse_xsl!
91
- $log.debug "Parsing xsl '#{@xsl_filename}'" if $DBG
92
- @mtime = File.stat(@xsl_filename).mtime
93
- @xslt.xsl = File.read(@xsl_filename)
94
- end
95
-
96
- end
97
-
98
- # = NilShader
99
- #
100
- # A shader that does absolutely nothing. Typically
101
- # used when you want to avoid XSLT in simple
102
- # applications.
103
- #
104
- class NilShader < Shader
105
- def initialize
106
- # gmosx: to get better display.
107
- @name = nil
108
- @mtime = Time.at(0)
109
- end
110
-
111
- # No transform, just convert to a String.
112
- def transform(document)
113
- return document.to_s
114
- end
115
- end
116
-
117
- # = ShaderManager
118
- #
119
- # Manages the shaders for the webapp.
120
- #
121
- # TODO: integrate with sitemap.
122
- #
123
- # === Design:
124
- #
125
- # - the shader selection may be time consuming but is performed once
126
- # when transforming the script, so its essentially for free (and
127
- # anyway the xsl transoformation is orders of magnitude slower)
128
- #
129
- class ShaderManager
130
- # corresponding arrays
131
- attr_accessor :regex, :shaders
132
- attr_accessor :default_shader
133
-
134
- def initialize
135
- @regex = []
136
- @shaders = []
137
- end
138
-
139
- def set_default(shader)
140
- @default_shader = shader
141
- end
142
-
143
- def add(regex, shader)
144
- @regex << regex
145
- @shaders << shader
146
- end
147
-
148
- def shader_for_path(path)
149
- @regex.each_with_index { |rx, idx|
150
- if path =~ rx
151
- return @shaders[idx]
152
- end
153
- }
154
- return @default_shader
155
- end
156
-
157
- def delete(regex)
158
- if idx = @regex.index(regex)
159
- @regex.delete_at(idx)
160
- @shaders.delete_at(idx)
161
- end
162
- end
163
-
164
- end
165
-
166
- end # module;
@@ -1,110 +0,0 @@
1
- #!/usr/local/bin/ruby -w
2
-
3
- # = A Command Line Client (clc) for the Sync Server
4
- #
5
- # code:
6
- # * Anastasios Koutoumanos <ak@navel.gr>
7
- # * George Moschovitis <gm@navel.gr>
8
- #
9
- # (c) 2004 Navel, all rights reserved.
10
- # $Id: clc.rb 101 2004-10-22 12:35:39Z gmosx $
11
-
12
- require "logger"
13
- require "socket"
14
- require "thread"
15
- require "timeout"
16
- require "getoptlong"
17
-
18
- @opts = GetoptLong.new(
19
- [ "--server", "-s", GetoptLong::REQUIRED_ARGUMENT ],
20
- [ "--port", "-p", GetoptLong::REQUIRED_ARGUMENT ],
21
- [ "--file", "-f", "-l", GetoptLong::REQUIRED_ARGUMENT ]
22
- )
23
-
24
- def prompt
25
- printf(Time.now.strftime("%H:%M:%S> "))
26
- end
27
-
28
- def connect(srv, port)
29
- begin
30
- @socket = TCPSocket.new(srv, port)
31
- rescue
32
- $log.error "Cannot connect to server, is it online?"
33
- exit(0)
34
- end
35
- $log.info "Connected to #{@socket.addr[3]}:#{@socket.addr[1]}"
36
- end
37
-
38
- def send(str)
39
- $log.info "write: #{str}"
40
- @socket.send("#{str}\000", 0)
41
- end
42
-
43
- def read()
44
- begin
45
- loop do
46
- timeout(0.7) do
47
- while @socket.readline("\000")
48
- $log.info "read: #{$_}"
49
- end
50
- end
51
- end
52
- rescue TimeoutError
53
- #drink it
54
- end
55
- end
56
-
57
- def write(cmd)
58
- if cmd = cmd.strip() and not cmd.empty?
59
- send(cmd)
60
- else
61
- $log.error "Syntax error"
62
- end
63
- end
64
-
65
- if __FILE__ == $0
66
-
67
- $log = Logger.new(STDERR)
68
-
69
- @opts.each { |opt, arg|
70
- case opt
71
- when "--file"
72
- @file = File.new(arg)
73
- when "--server"
74
- @server = arg
75
- when "--port"
76
- port = port.to_i
77
- end
78
- }
79
-
80
- @server ||= "localhost"
81
- @port ||= 2121
82
-
83
- connect(@server, @port)
84
-
85
- reader = Thread.new {
86
- loop do
87
- read()
88
- end
89
- }
90
-
91
- writer = Thread.new {
92
- # replay input file
93
- if @file
94
- @file.each_line { |cmd|
95
- write(cmd)
96
- }
97
- end
98
-
99
- # normal rep loop
100
- loop do
101
- prompt()
102
- cmd = gets()
103
- write(cmd)
104
- end
105
- }
106
-
107
- reader.join()
108
- writer.join()
109
-
110
- end