nitro 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +8 -0
- data/ChangeLog +1546 -0
- data/LICENCE +32 -0
- data/README +278 -0
- data/RELEASES +7 -0
- data/Rakefile +79 -0
- data/bin/cluster.rb +219 -0
- data/doc/architecture.txt +28 -0
- data/doc/bugs.txt +7 -0
- data/doc/css.txt +20 -0
- data/doc/ideas.txt +120 -0
- data/doc/pg.txt +47 -0
- data/doc/svn.txt +82 -0
- data/doc/todo.txt +30 -0
- data/etc/new-project.rb +18 -0
- data/examples/simple/README +15 -0
- data/examples/simple/app.rb +31 -0
- data/examples/simple/conf/apache.conf +100 -0
- data/examples/simple/conf/config.rb +89 -0
- data/examples/simple/conf/debug-config.rb +53 -0
- data/examples/simple/conf/live-config.rb +48 -0
- data/examples/simple/conf/overrides.rb +9 -0
- data/examples/simple/conf/requires.rb +51 -0
- data/examples/simple/ctl +32 -0
- data/examples/simple/env.rb +33 -0
- data/examples/simple/install.rb +12 -0
- data/examples/simple/lib/articles/entities.rb +35 -0
- data/examples/simple/lib/articles/lc-en.rb +36 -0
- data/examples/simple/lib/articles/methods.rb +55 -0
- data/examples/simple/lib/articles/part.rb +58 -0
- data/examples/simple/logs/access_log +2 -0
- data/examples/simple/logs/apache.log +3 -0
- data/examples/simple/logs/app.log +1 -0
- data/examples/simple/logs/events.log +1 -0
- data/examples/simple/root/add-article.sx +15 -0
- data/examples/simple/root/article-form.ss +20 -0
- data/examples/simple/root/comments-form.ss +16 -0
- data/examples/simple/root/comments.si +30 -0
- data/examples/simple/root/index.sx +44 -0
- data/examples/simple/root/shader/shader.xsl +100 -0
- data/examples/simple/root/shader/style.css +9 -0
- data/examples/simple/root/view-article.sx +30 -0
- data/examples/tiny/app.rb +30 -0
- data/examples/tiny/conf/apache.conf +100 -0
- data/examples/tiny/conf/config.rb +67 -0
- data/examples/tiny/conf/requires.rb +40 -0
- data/examples/tiny/ctl +31 -0
- data/examples/tiny/logs/access_log +9 -0
- data/examples/tiny/logs/apache.log +9 -0
- data/examples/tiny/root/index.sx +35 -0
- data/lib/n/app/cluster.rb +219 -0
- data/lib/n/app/cookie.rb +86 -0
- data/lib/n/app/filters/autologin.rb +50 -0
- data/lib/n/app/fragment.rb +67 -0
- data/lib/n/app/handlers.rb +120 -0
- data/lib/n/app/handlers/code-handler.rb +184 -0
- data/lib/n/app/handlers/page-handler.rb +612 -0
- data/lib/n/app/request-part.rb +59 -0
- data/lib/n/app/request.rb +653 -0
- data/lib/n/app/script.rb +398 -0
- data/lib/n/app/server.rb +53 -0
- data/lib/n/app/session.rb +224 -0
- data/lib/n/app/user.rb +47 -0
- data/lib/n/app/webrick-servlet.rb +213 -0
- data/lib/n/app/webrick.rb +70 -0
- data/lib/n/application.rb +187 -0
- data/lib/n/config.rb +31 -0
- data/lib/n/db.rb +217 -0
- data/lib/n/db/README +232 -0
- data/lib/n/db/connection.rb +369 -0
- data/lib/n/db/make-release.sh +26 -0
- data/lib/n/db/managed.rb +235 -0
- data/lib/n/db/mixins.rb +282 -0
- data/lib/n/db/mysql.rb +342 -0
- data/lib/n/db/psql.rb +378 -0
- data/lib/n/db/tools.rb +110 -0
- data/lib/n/db/utils.rb +99 -0
- data/lib/n/events.rb +118 -0
- data/lib/n/l10n.rb +22 -0
- data/lib/n/logger.rb +33 -0
- data/lib/n/macros.rb +53 -0
- data/lib/n/mixins.rb +46 -0
- data/lib/n/parts.rb +154 -0
- data/lib/n/properties.rb +194 -0
- data/lib/n/server.rb +61 -0
- data/lib/n/server/PLAYBACK.txt +8 -0
- data/lib/n/server/RESEARCH.txt +13 -0
- data/lib/n/server/filter.rb +77 -0
- data/lib/n/shaders.rb +167 -0
- data/lib/n/sitemap.rb +188 -0
- data/lib/n/std.rb +69 -0
- data/lib/n/sync/clc.rb +108 -0
- data/lib/n/sync/handler.rb +221 -0
- data/lib/n/sync/server.rb +170 -0
- data/lib/n/tools/README +11 -0
- data/lib/n/ui/date-select.rb +74 -0
- data/lib/n/ui/pager.rb +187 -0
- data/lib/n/ui/popup.rb +45 -0
- data/lib/n/ui/select.rb +41 -0
- data/lib/n/ui/tabs.rb +34 -0
- data/lib/n/utils/array.rb +92 -0
- data/lib/n/utils/cache.rb +144 -0
- data/lib/n/utils/gfx.rb +108 -0
- data/lib/n/utils/hash.rb +148 -0
- data/lib/n/utils/html.rb +147 -0
- data/lib/n/utils/http.rb +98 -0
- data/lib/n/utils/mail.rb +28 -0
- data/lib/n/utils/number.rb +31 -0
- data/lib/n/utils/pool.rb +66 -0
- data/lib/n/utils/string.rb +297 -0
- data/lib/n/utils/template.rb +38 -0
- data/lib/n/utils/time.rb +91 -0
- data/lib/n/utils/uri.rb +193 -0
- data/lib/xsl/base.xsl +205 -0
- data/lib/xsl/ce.xsl +30 -0
- data/lib/xsl/localization.xsl +23 -0
- data/lib/xsl/xforms.xsl +26 -0
- data/test/run.rb +95 -0
- metadata +187 -0
data/lib/n/shaders.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# = Shader
|
2
|
+
#
|
3
|
+
# The equivalent of a 3d engine shader. Converts the page representation
|
4
|
+
# to the html output. Actually converts it to a dynamic page ready for
|
5
|
+
# evaluation.
|
6
|
+
#
|
7
|
+
# === Design:
|
8
|
+
#
|
9
|
+
# We follow the xp methodology: the shader as simple as possible.
|
10
|
+
# In the future we may add mulitple xsls (xsl pipeline) but
|
11
|
+
# we done need them now, so we wont code them!
|
12
|
+
#
|
13
|
+
# - when compiling get the default shader and keep it in the
|
14
|
+
# script structure.
|
15
|
+
#
|
16
|
+
# noo better push them in a request stack!
|
17
|
+
#
|
18
|
+
# - when rendering:
|
19
|
+
# if there is an override shader use it! (example: inject shader)
|
20
|
+
# if there is a parent shader use it!
|
21
|
+
# if there is a script shader use it!
|
22
|
+
# if there is a user shader use it!
|
23
|
+
# if there is an app shader use it!
|
24
|
+
# no shading!
|
25
|
+
#
|
26
|
+
# === Think:
|
27
|
+
#
|
28
|
+
# - are inject override shaders possible ? (no they are
|
29
|
+
# dynamic)
|
30
|
+
#
|
31
|
+
# === TODO:
|
32
|
+
#
|
33
|
+
# - add monitoring support for xsl's.
|
34
|
+
#
|
35
|
+
# code:
|
36
|
+
# George Moschovitis <gm@navel.gr>
|
37
|
+
#
|
38
|
+
# (c) 2004 Navel, all rights reserved.
|
39
|
+
# $Id: shaders.rb 89 2004-10-20 12:55:58Z gmosx $
|
40
|
+
|
41
|
+
module N;
|
42
|
+
|
43
|
+
# = Shader
|
44
|
+
#
|
45
|
+
# One shader can utilize several xsls to render different pages.
|
46
|
+
# the shader selection may be time consuming but is performed once
|
47
|
+
# when transforming the script, so its essentially for free (and
|
48
|
+
# anyway the xsl transoformation is orders of magnitude slower)
|
49
|
+
#
|
50
|
+
# There is no need to keep post xsl. I can reuse the same xsl
|
51
|
+
# by calling transform again.
|
52
|
+
#
|
53
|
+
class Shader
|
54
|
+
attr_accessor :name
|
55
|
+
attr_accessor :xsl_filename
|
56
|
+
# the xslt transoformer.
|
57
|
+
attr_accessor :xslt
|
58
|
+
attr_accessor :mtime
|
59
|
+
|
60
|
+
def initialize(name, xsl_filename)
|
61
|
+
# leave this require here. only inlcude the xslt
|
62
|
+
# library if the project needs it.
|
63
|
+
require "xml/xslt"
|
64
|
+
|
65
|
+
@name = name
|
66
|
+
@xsl_filename = xsl_filename
|
67
|
+
@xslt = XML::XSLT.new
|
68
|
+
parse_xsl!
|
69
|
+
end
|
70
|
+
|
71
|
+
# transform the given document
|
72
|
+
#
|
73
|
+
def xsl_transform(document)
|
74
|
+
@xslt.xml = document
|
75
|
+
return @xslt.serve()
|
76
|
+
end
|
77
|
+
alias_method :transform, :xsl_transform
|
78
|
+
|
79
|
+
def xsl
|
80
|
+
parse_xsl! if $reload_xsl
|
81
|
+
return @xsl
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_s
|
85
|
+
@name
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Parse the xsl.
|
91
|
+
#
|
92
|
+
def parse_xsl!
|
93
|
+
$log.debug "Parsing xsl '#{@xsl_filename}'" if $DBG
|
94
|
+
@mtime = File.stat(@xsl_filename).mtime
|
95
|
+
@xslt.xsl = File.read(@xsl_filename)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
# = NilShader
|
101
|
+
#
|
102
|
+
# A shader that does absolutely nothing.
|
103
|
+
#
|
104
|
+
# === WARNING: not tested.
|
105
|
+
#
|
106
|
+
class NilShader < Shader
|
107
|
+
def initialize
|
108
|
+
@name = "nil"
|
109
|
+
@mtime = Time.at(0)
|
110
|
+
end
|
111
|
+
|
112
|
+
# No transform, just convert to a String.
|
113
|
+
def transform(document)
|
114
|
+
return document.to_s
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# = ShaderManager
|
119
|
+
#
|
120
|
+
# Manages the shaders for the webapp.
|
121
|
+
#
|
122
|
+
# TODO: integrate with sitemap.
|
123
|
+
#
|
124
|
+
# === Design:
|
125
|
+
#
|
126
|
+
# - the shader selection may be time consuming but is performed once
|
127
|
+
# when transforming the script, so its essentially for free (and
|
128
|
+
# anyway the xsl transoformation is orders of magnitude slower)
|
129
|
+
#
|
130
|
+
class ShaderManager
|
131
|
+
# corresponding arrays
|
132
|
+
attr_accessor :regex, :shaders
|
133
|
+
attr_accessor :default_shader
|
134
|
+
|
135
|
+
def initialize
|
136
|
+
@regex = []
|
137
|
+
@shaders = []
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_default(shader)
|
141
|
+
@default_shader = shader
|
142
|
+
end
|
143
|
+
|
144
|
+
def add(regex, shader)
|
145
|
+
@regex << regex
|
146
|
+
@shaders << shader
|
147
|
+
end
|
148
|
+
|
149
|
+
def shader_for_path(path)
|
150
|
+
@regex.each_with_index { |rx, idx|
|
151
|
+
if path =~ rx
|
152
|
+
return @shaders[idx]
|
153
|
+
end
|
154
|
+
}
|
155
|
+
return @default_shader
|
156
|
+
end
|
157
|
+
|
158
|
+
def delete(regex)
|
159
|
+
if idx = @regex.index(regex)
|
160
|
+
@regex.delete_at(idx)
|
161
|
+
@shaders.delete_at(idx)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end # module;
|
data/lib/n/sitemap.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# = SiteMap
|
2
|
+
#
|
3
|
+
# Encapsulates the page structure and additional metadata.
|
4
|
+
#
|
5
|
+
# === TODO:
|
6
|
+
#
|
7
|
+
# move out of the UI namespace.
|
8
|
+
# include url remapping functionality.
|
9
|
+
#
|
10
|
+
# === Design
|
11
|
+
#
|
12
|
+
# Unlike the original version, this is presentation agnostic, and
|
13
|
+
# greatly simplified.
|
14
|
+
#
|
15
|
+
# === Todo:
|
16
|
+
#
|
17
|
+
# - support strings as titles.
|
18
|
+
# - add support to read the map from a config file.
|
19
|
+
# - rename to appmap ?
|
20
|
+
#
|
21
|
+
# code:
|
22
|
+
# George Moschovitis <gm@navel.gr>
|
23
|
+
#
|
24
|
+
# (c) 2004 Navel, all rights reserved.
|
25
|
+
# $Id: sitemap.rb 71 2004-10-18 10:50:22Z gmosx $
|
26
|
+
|
27
|
+
require "n/utils/hash"
|
28
|
+
|
29
|
+
module N
|
30
|
+
|
31
|
+
# = SitePage
|
32
|
+
#
|
33
|
+
class SitePage
|
34
|
+
# the uri for this page
|
35
|
+
attr_accessor :uri
|
36
|
+
# the real uri to this page calculated by the page overloader)
|
37
|
+
attr_accessor :real_uri
|
38
|
+
attr_accessor :realm
|
39
|
+
# the shader for this page, overrided the shader calculated
|
40
|
+
# by the engine
|
41
|
+
attr_accessor :shader
|
42
|
+
attr_accessor :level
|
43
|
+
# title of the page
|
44
|
+
attr_accessor :title
|
45
|
+
# description of the page
|
46
|
+
attr_accessor :description
|
47
|
+
attr_accessor :parent, :children
|
48
|
+
attr_accessor :flag
|
49
|
+
|
50
|
+
# the realm this page belongs to, typically the part name.
|
51
|
+
# put symbols in this variable
|
52
|
+
attr_accessor :realm
|
53
|
+
|
54
|
+
def initialize(uri, title = nil, parent = nil, realm = nil)
|
55
|
+
@uri, @title, @parent = uri, title, parent
|
56
|
+
|
57
|
+
# inherit realm from parent if exists
|
58
|
+
if parent and parent.realm
|
59
|
+
@realm = parent.realm
|
60
|
+
else
|
61
|
+
@realm = realm
|
62
|
+
end
|
63
|
+
|
64
|
+
@children = []
|
65
|
+
@parent.children << self if parent
|
66
|
+
|
67
|
+
# gmosx: is this good?
|
68
|
+
# automatically add to the sitemap.
|
69
|
+
$sitemap << self
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return string representation
|
73
|
+
#
|
74
|
+
def to_s
|
75
|
+
return @title
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# = SiteMap
|
80
|
+
#
|
81
|
+
# === TODO:
|
82
|
+
# Use a second class in the UI namespace for rendering
|
83
|
+
# related stuff?
|
84
|
+
#
|
85
|
+
class SiteMap < N::SafeHash
|
86
|
+
|
87
|
+
# The root page for this sitemap
|
88
|
+
attr_accessor :root
|
89
|
+
|
90
|
+
# The separator used when creating paths
|
91
|
+
attr_accessor :separator
|
92
|
+
|
93
|
+
def initialize(separator = " > ")
|
94
|
+
super
|
95
|
+
@separator = separator
|
96
|
+
end
|
97
|
+
|
98
|
+
def << (page)
|
99
|
+
self[page.uri] = page
|
100
|
+
unless page.parent
|
101
|
+
@root = page
|
102
|
+
page.realm = :root
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Path as array of pages
|
107
|
+
#
|
108
|
+
def path(uri)
|
109
|
+
return nil unless uri
|
110
|
+
|
111
|
+
if page = self[uri]
|
112
|
+
res = Array.new;
|
113
|
+
|
114
|
+
res << page
|
115
|
+
while page = page.parent
|
116
|
+
res.unshift(page)
|
117
|
+
end
|
118
|
+
|
119
|
+
return res
|
120
|
+
else
|
121
|
+
$log.warn "The uri #{uri} is not registered in the SiteMap!"
|
122
|
+
end
|
123
|
+
|
124
|
+
return nil
|
125
|
+
end
|
126
|
+
|
127
|
+
# Calculates the linked path to the given uri.
|
128
|
+
#
|
129
|
+
def linked_path(uri, lc = nil, args = nil)
|
130
|
+
if the_path = path(uri)
|
131
|
+
i = -1
|
132
|
+
j, s = 0, the_path.size()
|
133
|
+
return the_path.collect { |p|
|
134
|
+
j += 1
|
135
|
+
if p.title.is_a?(String)
|
136
|
+
j == s ? p.title : %|<a href="#{p.uri}">#{p.title}</a>|
|
137
|
+
elsif p.title.is_a?(Symbol)
|
138
|
+
j == s ? lc[p.title] : %|<a href="#{p.uri}">#{lc[p.title]}</a>|
|
139
|
+
else
|
140
|
+
i += 1
|
141
|
+
title, qs = p.title.call(args[i])
|
142
|
+
j == s ? title : %|<a href="#{p.uri}#{qs}">#{title}</a>|
|
143
|
+
end
|
144
|
+
}.join(@separator)
|
145
|
+
|
146
|
+
else
|
147
|
+
return nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Calculates the path to the given uri.
|
152
|
+
#
|
153
|
+
def str_path(uri, lc = nil, args = nil)
|
154
|
+
if the_path = path(uri)
|
155
|
+
i = -1
|
156
|
+
return the_path.collect { |p|
|
157
|
+
if p.title.is_a?(String)
|
158
|
+
p.title
|
159
|
+
elsif p.title.is_a?(Symbol)
|
160
|
+
lc[p.title]
|
161
|
+
else
|
162
|
+
i += 1
|
163
|
+
p.title.call(args[i])[0]
|
164
|
+
end
|
165
|
+
}.join(@separator)
|
166
|
+
else
|
167
|
+
return nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns a String representation of the Sitemap.
|
172
|
+
#
|
173
|
+
def to_s
|
174
|
+
str = "#{root}"
|
175
|
+
arr = []
|
176
|
+
self.each_pair { |page, title|
|
177
|
+
arr << "#{title}: #{page}"
|
178
|
+
}
|
179
|
+
return "#{str} {" + arr.join(",") + "}"
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end # module
|
185
|
+
|
186
|
+
# the default sitemap.
|
187
|
+
$sitemap = N::SiteMap.new
|
188
|
+
|
data/lib/n/std.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# = Navel Software Technology
|
2
|
+
#
|
3
|
+
# code: gmosx, drak, ekarak
|
4
|
+
#
|
5
|
+
# (c) 2001-2004 Navel, all rights reserved.
|
6
|
+
# $Id: std.rb 71 2004-10-18 10:50:22Z gmosx $
|
7
|
+
|
8
|
+
# we want readable code
|
9
|
+
|
10
|
+
require "English"
|
11
|
+
require "pp"
|
12
|
+
|
13
|
+
class NilClass
|
14
|
+
# to_i, to_s are handled by default.
|
15
|
+
|
16
|
+
def to_i
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_f
|
21
|
+
return 0.0
|
22
|
+
end
|
23
|
+
|
24
|
+
# quite usefull for error tolerant apps.
|
25
|
+
# a bit dangerous though.
|
26
|
+
#
|
27
|
+
def empty?
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
#
|
34
|
+
class Class
|
35
|
+
def to_i()
|
36
|
+
return self.hash()
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
#
|
42
|
+
module Kernel
|
43
|
+
# pretty prints an exception/error object
|
44
|
+
# usefull for helpfull debug messages
|
45
|
+
#
|
46
|
+
# Input:
|
47
|
+
# The Exception/StandardError object
|
48
|
+
#
|
49
|
+
# Output:
|
50
|
+
# the pretty printed string
|
51
|
+
#
|
52
|
+
def pp_exception(ex)
|
53
|
+
return %{#{ex.message}\n\tBACKTRACE:\n\t#{ex.backtrace.join("\n\t")}\n\tLOGGED FROM:\n\t#{caller[0]}}
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# predefine some comonly used objects
|
59
|
+
|
60
|
+
EMPTY_STRING = ""
|
61
|
+
|
62
|
+
# This the default 72 chars separator, copy paste to use it
|
63
|
+
# in your source file. Btw all lines in your source file should
|
64
|
+
# be less than 72 chars. So you can use this as a ruler if your
|
65
|
+
# editor does not support it.
|
66
|
+
|
67
|
+
#-----------------------------------------------------------------------
|
68
|
+
|
69
|
+
|
data/lib/n/sync/clc.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# = A Command Line Client (clc) for the Sync Server
|
4
|
+
#
|
5
|
+
# code: tml, drak
|
6
|
+
#
|
7
|
+
# (c) 2004 Navel, all rights reserved.
|
8
|
+
# $Id: clc.rb 71 2004-10-18 10:50:22Z gmosx $
|
9
|
+
|
10
|
+
require "logger"
|
11
|
+
require "socket"
|
12
|
+
require "thread"
|
13
|
+
require "timeout"
|
14
|
+
require "getoptlong"
|
15
|
+
|
16
|
+
@opts = GetoptLong.new(
|
17
|
+
[ "--server", "-s", GetoptLong::REQUIRED_ARGUMENT ],
|
18
|
+
[ "--port", "-p", GetoptLong::REQUIRED_ARGUMENT ],
|
19
|
+
[ "--file", "-f", "-l", GetoptLong::REQUIRED_ARGUMENT ]
|
20
|
+
)
|
21
|
+
|
22
|
+
def prompt
|
23
|
+
printf(Time.now.strftime("%H:%M:%S> "))
|
24
|
+
end
|
25
|
+
|
26
|
+
def connect(srv, port)
|
27
|
+
begin
|
28
|
+
@socket = TCPSocket.new(srv, port)
|
29
|
+
rescue
|
30
|
+
$log.error "Cannot connect to server, is it online?"
|
31
|
+
exit(0)
|
32
|
+
end
|
33
|
+
$log.info "Connected to #{@socket.addr[3]}:#{@socket.addr[1]}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def send(str)
|
37
|
+
$log.info "write: #{str}"
|
38
|
+
@socket.send("#{str}\000", 0)
|
39
|
+
end
|
40
|
+
|
41
|
+
def read()
|
42
|
+
begin
|
43
|
+
loop do
|
44
|
+
timeout(0.7) do
|
45
|
+
while @socket.readline("\000")
|
46
|
+
$log.info "read: #{$_}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
rescue TimeoutError
|
51
|
+
#drink it
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def write(cmd)
|
56
|
+
if cmd = cmd.strip() and not cmd.empty?
|
57
|
+
send(cmd)
|
58
|
+
else
|
59
|
+
$log.error "Syntax error"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if __FILE__ == $0
|
64
|
+
|
65
|
+
$log = Logger.new(STDERR)
|
66
|
+
|
67
|
+
@opts.each { |opt, arg|
|
68
|
+
case opt
|
69
|
+
when "--file"
|
70
|
+
@file = File.new(arg)
|
71
|
+
when "--server"
|
72
|
+
@server = arg
|
73
|
+
when "--port"
|
74
|
+
port = port.to_i
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
@server ||= "localhost"
|
79
|
+
@port ||= 2121
|
80
|
+
|
81
|
+
connect(@server, @port)
|
82
|
+
|
83
|
+
reader = Thread.new {
|
84
|
+
loop do
|
85
|
+
read()
|
86
|
+
end
|
87
|
+
}
|
88
|
+
|
89
|
+
writer = Thread.new {
|
90
|
+
# replay input file
|
91
|
+
if @file
|
92
|
+
@file.each_line { |cmd|
|
93
|
+
write(cmd)
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
# normal rep loop
|
98
|
+
loop do
|
99
|
+
prompt()
|
100
|
+
cmd = gets()
|
101
|
+
write(cmd)
|
102
|
+
end
|
103
|
+
}
|
104
|
+
|
105
|
+
reader.join()
|
106
|
+
writer.join()
|
107
|
+
|
108
|
+
end
|