[#43299] Ruby implementation Q's — justinj@... (Justin Johnson)

Apologies in advance for this meaty posting:

30 messages 2002/07/01

[#43358] (0..3) == (0...4) returning false? — Massimiliano Mirra <list@...>

Is there a reason for two ranges holding the same extension but

41 messages 2002/07/02

[#43416] Segmentation Fault - Ruby Garbage Collection — James Eric Birmingham <avenger@...>

During load testing of our Ruby program, we have been getting

22 messages 2002/07/02

[#43570] self_parent — Tom Sawyer <transami@...>

i was wondering what others thought of the idea of having a built in

47 messages 2002/07/04
[#43571] Re: self_parent — David Alan Black <dblack@...> 2002/07/04

Hello --

[#43584] Re: self_parent — Tom Sawyer <transami@...> 2002/07/04

all my real examples are pretty large, mostly to do with using the REXML

[#43628] Re: self_parent — Massimiliano Mirra <list@...> 2002/07/05

On Fri, Jul 05, 2002 at 07:49:09AM +0900, Tom Sawyer wrote:

[#43662] Re: self_parent — Tom Sawyer <transami@...> 2002/07/05

On Fri, 2002-07-05 at 05:31, Massimiliano Mirra wrote:

[#43705] Re: self_parent — Austin Ziegler <austin@...> 2002/07/05

On Sat, 6 Jul 2002 03:32:11 +0900, Tom Sawyer wrote:

[#43713] Re: self_parent — Michael Campbell <michael_s_campbell@...> 2002/07/05

> In ten years of professional software development, a good chunk of

[#43602] is there a better string.each? — Tyler Spivey <tspivey8@...>

well, i have a bit of a problem:

98 messages 2002/07/05
[#43606] Re: is there a better string.each? — Tom Sawyer <transami@...> 2002/07/05

a = "canada"

[#43644] Re: is there a better string.each? — Sean Russell <ser@...> 2002/07/05

Tom Sawyer wrote:

[#43645] Re: is there a better string.each? — Michael Campbell <michael_s_campbell@...> 2002/07/05

> > thought it was strange myself. personally i'd like it if String

[#43707] Re: is there a better string.each? — Sean Russell <ser@...> 2002/07/05

Hal E. Fulton wrote:

[#43714] Re: is there a better string.each? — Michael Campbell <michael_s_campbell@...> 2002/07/05

[#43774] Re: is there a better string.each? — Sean Russell <ser@...> 2002/07/06

Michael Campbell wrote:

[#43805] Re: is there a better string.each? — Michael Campbell <michael_s_campbell@...> 2002/07/07

[#43848] Re: is there a better string.each? — "Hal E. Fulton" <hal9000@...> 2002/07/07

----- Original Message -----

[#43611] Powered by Ruby (logo) — Davey <davey@...>

Hey,

23 messages 2002/07/05

[#43780] passing to objects at the bottom — Tom Sawyer <transami@...>

i have a chain of objects such that one object contains another which

17 messages 2002/07/06

[#43795] Pre-RCR... nil.empty? — Dave Thomas <Dave@...>

34 messages 2002/07/07
[#43799] Re: Pre-RCR... nil.empty? — David Alan Black <dblack@...> 2002/07/07

Hi --

[#43807] unshifting a directory onto ENV['PATH'] — Bil Kleb <W.L.Kleb@...>

Is there a more elegant (compact?) method than

16 messages 2002/07/07

[#43916] How to determine EOF with sysread? — Jim Freeze <jim@...>

Hi:

13 messages 2002/07/08

[#43943] SV: SV: [ANN] Archive 0.2 — Thomas Søndergaard <tsondergaard@...>

DQo+IFRoYW5rcy4gOi0pIEknbSBub3QgdGVycmlibHkgaW4gaHVycnkgdG8gYWRkIFppcCBzdXBw

13 messages 2002/07/08

[#43944] Re: is there a better string.each? — George Ogata <g_ogata@...>

Hi,

45 messages 2002/07/08
[#43959] Re: is there a better string.each? — Austin Ziegler <austin@...> 2002/07/08

On Mon, 8 Jul 2002 20:43:57 +0900, George Ogata wrote:

[#43949] for ... else ... end — "Kontra, Gergely" <kgergely@...>

Hi!

45 messages 2002/07/08
[#44103] Re: for ... else ... end — Sean Russell <ser@...> 2002/07/09

Yukihiro Matsumoto wrote:

[#44107] Re: for ... else ... end — "Kontra, Gergely" <kgergely@...> 2002/07/09

For the keyword war: (silly, dummy example)

[#43957] Redirecting standard error — Gilles Filippini <gilles.filippini@...>

Hi,

13 messages 2002/07/08

[#44019] String#split converts string args to regexes -- ? — David Alan Black <dblack@...>

Hello --

41 messages 2002/07/08
[#44104] Re: String#split converts string args to regexes -- ? — kasal@... (Stepan Kasal) 2002/07/09

Hallo,

[#44137] Re: String#split converts string args to regexes -- ? — matz@... (Yukihiro Matsumoto) 2002/07/09

Hi,

[#44209] Re: String#split converts string args to regexes -- ? — kasal@... (Stepan Kasal) 2002/07/10

Hallo,

[#44212] Re: String#split converts string args to regexes -- ? — David Alan Black <dblack@...> 2002/07/10

Hi --

[#44265] spliter of for...each: looping — Tom Sawyer <transami@...>

when looping, using each, i find i am often wonton of a few nice

24 messages 2002/07/10
[#44266] Re: spliter of for...each: looping — David Alan Black <dblack@...> 2002/07/10

Hello --

[#44268] Re: spliter of for...each: looping — Tom Sawyer <transami@...> 2002/07/10

hmmm...

[#44270] Re: spliter of for...each: looping — David Alan Black <dblack@...> 2002/07/10

Hi --

[#44272] Re: spliter of for...each: looping — Tom Sawyer <transami@...> 2002/07/10

david,

[#44275] Re: spliter of for...each: looping — David Alan Black <dblack@...> 2002/07/10

Hi --

[#44282] Re: spliter of for...each: looping — Tom Sawyer <transami@...> 2002/07/11

each_with_nindex, rocking! i'll throw that in my library, for sure.

[#44289] Re: spliter of for...each: looping — David Alan Black <dblack@...> 2002/07/11

Hi --

[#44296] RE: Commercial Support for Ruby — "Berger, Daniel" <djberge@...>

> Hi Everyone,

18 messages 2002/07/11

[#44312] opengl — Tom Sawyer <transami@...>

can any one give me some help installing the opengl interface library? i

22 messages 2002/07/11
[#44316] Re: opengl — Dossy <dossy@...> 2002/07/11

On 2002.07.12, Tom Sawyer <transami@transami.net> wrote:

[#44320] Re: opengl — Tom Sawyer <transami@...> 2002/07/11

just did apt-get mesag-dev. still the same thing:

[#44387] Dynamic Methods — "John" <nojgoalbyspam@...>

Hi all,

29 messages 2002/07/12
[#44402] Re: Dynamic Methods — "John" <nojgoalbyspam@...> 2002/07/12

Wow! Thanks Dave!

[#44408] Re: Dynamic Methods — Michael Campbell <michael_s_campbell@...> 2002/07/12

[#44415] Re: Dynamic Methods — "John" <nojgoalbyspam@...> 2002/07/13

> (What do you propose if more than one possibility matches, by the

[#44425] hey! where's #count? — Tom Sawyer <transami@...>

i went to count the number of equal objects in an array and discoverd

24 messages 2002/07/13
[#44515] Re: hey! where's #count? — "Christoph" <chr_news@...> 2002/07/14

"Tom Sawyer" wrote

[#44516] Re: hey! where's #count? — Philipp Meier <meier@...> 2002/07/14

On Sun, Jul 14, 2002 at 11:41:55PM +0900, Christoph wrote:

[#44517] RE: hey! where's #count? — "Christoph" <crippel@...> 2002/07/14

[#44482] instance_eval — "John" <nojgoalbyspam@...>

Hi all,

14 messages 2002/07/13

[#44618] RE: TkText no -textvariable workaround? — "J.Hawkesworth" <J.Hawkesworth@...>

I think what Tom is after is a neat way to have the widget's display

41 messages 2002/07/16
[#44621] RE: TkText no -textvariable workaround? — Tom Sawyer <transami@...> 2002/07/16

On Tue, 2002-07-16 at 09:08, J.Hawkesworth wrote:

[#44622] Re: TkText no -textvariable workaround? — Dossy <dossy@...> 2002/07/16

On 2002.07.17, Tom Sawyer <transami@transami.net> wrote:

[#44626] Re: TkText no -textvariable workaround? — Tom Sawyer <transami@...> 2002/07/16

actually, Dossy, your post was a bit helpful. what i'm after also sort

[#44628] Re: TkText no -textvariable workaround? — Dossy <dossy@...> 2002/07/16

On 2002.07.17, Tom Sawyer <transami@transami.net> wrote:

[#44734] Syntax "surprise" — "David Douthitt" <DDouthitt@...>

I don't know if this qualifies as a real "surprise", but it was to me. I h=

39 messages 2002/07/17

[#44788] Selling ruby to my boss — Francis Hwang <sera@...>

So I've just started working as the sole programmer at a non-profit

22 messages 2002/07/18

[#44829] Q: "print usage_msg, exit 1 if error_flag" does not work — kwatch@... (kwatch)

Hi,

15 messages 2002/07/18
[#44831] Re: Q: "print usage_msg, exit 1 if error_flag" does not work — ts <decoux@...> 2002/07/18

>>>>> "k" == kwatch <kwatch@lycos.jp> writes:

[#44832] Re: Q: "print usage_msg, exit 1 if error_flag" does not work — Hugh Sasse Staff Elec Eng <hgs@...> 2002/07/18

On Thu, 18 Jul 2002, ts wrote:

[#44833] Re: Q: "print usage_msg, exit 1 if error_flag" does not work — ts <decoux@...> 2002/07/18

>>>>> "H" == Hugh Sasse Staff Elec Eng <hgs@dmu.ac.uk> writes:

[#44855] Ruby in MacOSX 10.2 (Jaguar) — Luc Heinrich <lucsky@...>

It now seems to be "official" that Ruby will come by default with the next iteration of MacOSX.

12 messages 2002/07/18

[#44893] amrita 0.8.1 — Taku Nakajima <tnakajima@...>

Amrita is a a html/xhtml template library for Ruby.

22 messages 2002/07/19

[#44920] Objective C backend for Ruby? — "James F.Hranicky" <jfh@...>

While people are kicking around ideas for new backends for Ruby,

24 messages 2002/07/19

[#44985] GUI's and the Rouge, Part II — Tom Sawyer <transami@...>

in part one of this message i mention the problem of non-POLS and

72 messages 2002/07/20
[#45161] Re: GUI's and the Rouge, Part II — patrick-may@... (Patrick May) 2002/07/23

Ned Konz <ned@bike-nomad.com> wrote in message news:<200207201125.13528@ned.bike-nomad.com>...

[#45241] Re: GUI's and the Rouge, Part III (yes, finally) 1/2 — Tom Sawyer <transami@...> 2002/07/23

a bit of an intro: my original thought on the matter of making a

[#45246] Re: GUI's and the Rouge, Part III (yes, finally) 1/2 — Albert Wagner <alwagner@...> 2002/07/24

Still looks like plain old Model-View-Controller to me. You've split the

[#45282] RE: GUI's and the Rouge, Part III (yes, finally) 1/2 — "Curt Hibbs" <curt@...> 2002/07/24

Tom Sawyer wrote:

[#45287] RE: GUI's and the Rouge, Part III (yes, finally) 1/2 — Steve Tuckner <STUCKNER@...> 2002/07/24

What about WX-Windows. There is no ruby bindings for it, but would that fit

[#45300] RE: GUI's and the Rouge, Part III (yes, finally) 1/2 — Tom Sawyer <transami@...> 2002/07/24

On Wed, 2002-07-24 at 08:39, Steve Tuckner wrote:

[#45314] Re: GUI's and the Rouge, Part III (yes, finally) 1/2 — Wayne Vucenic <wvucenic@...> 2002/07/24

Hi Tom,

[#45364] RE: GUI's and the Rouge, Part III (yes, finally) 1/2 — "Curt Hibbs" <curt@...> 2002/07/25

Wayne Vucenic wrote:

[#45416] wxWindows for ruby — "repeater" <repeater@...> 2002/07/25

> Wayne Vucenic wrote:

[#44994] Learning Japanese — "John" <nojgoalbyspam@...>

Inspired to learn to read Japanese due to a lot of information on Ruby being

12 messages 2002/07/20

[#45044] Install troubles — Jim Freeze <jfreeze@...>

Hi:

13 messages 2002/07/21
[#45051] Re: Install troubles — Chris Gehlker <gehlker@...> 2002/07/21

On 7/21/02 12:13 PM, "Jim Freeze" <jfreeze@freebsdportal.com> wrote:

[#45085] ruby-dev summary 17696-17713 — Minero Aoki <aamine@...>

Hi all,

28 messages 2002/07/22
[#45090] rdtool and rdoc — Dave Thomas <Dave@...> 2002/07/22

Minero Aoki <aamine@mx.edit.ne.jp> writes:

[#45118] Re: rdtool and rdoc — "David Douthitt" <DDouthitt@...>

I took a look at your comparison page. I've not used either, but some thin=

16 messages 2002/07/22

[#45136] Strings and member-operators — the Bare <grrr@...>

Hi:

22 messages 2002/07/22
[#45140] Re: Strings and member-operators — Dossy <dossy@...> 2002/07/23

On 2002.07.23, the Bare <grrr@wild.net> wrote:

[#45148] Re: Strings and member-operators — David Alan Black <dblack@...> 2002/07/23

Hi --

[#45173] Re: Strings and member-operators — Dossy <dossy@...> 2002/07/23

On 2002.07.23, David Alan Black <dblack@candle.superlink.net> wrote:

[#45175] Re: Strings and member-operators — David Alan Black <dblack@...> 2002/07/23

Hi --

[#45198] Re: Strings and member-operators — George Ogata <g_ogata@...> 2002/07/23

Hello,

[#45201] Re: Strings and member-operators — David Alan Black <dblack@...> 2002/07/23

Hi --

[#45206] Re: Strings and member-operators — Tom Sawyer <transami@...> 2002/07/23

let me get this straight? is the original question how to strip a string

[#45257] Re: GUI's and the Rouge, Part III (yes, finally) 1/2 — Benjamin Peterson <bjsp123@...>

>you have this super application you wrote --the

11 messages 2002/07/24

[#45269] Can I get data back from a fork? — Jim Freeze <jfreeze@...>

Hi:

15 messages 2002/07/24

[#45286] Re: GUI's and the Rouge, Part III (yes, finally) 1/2 — Benjamin Peterson <bjsp123@...>

>its really just SOC on aanother level.

10 messages 2002/07/24

[#45368] Re: [OT] Re: GUI's and the Rouge, Part III (yes, finally) 1/2 — Benjamin Peterson <bjsp123@...>

>The functionality of a spreadsheet had been around

39 messages 2002/07/25
[#45476] Re: curses dev kit, was Re: [OT] Re: GUI's and the Rouge — Thomas Dickey <dickey@...> 2002/07/26

clemens fischer <ino-waiting@gmx.net> wrote:

[#45480] Re: curses dev kit, was Re: [OT] Re: GUI's and the Rouge — Massimiliano Mirra <list@...> 2002/07/26

On Fri, Jul 26, 2002 at 07:51:25PM +0900, Thomas Dickey wrote:

[#45422] Singleton Classes & thread safety — David King Landrith <dave@...>

I'm a bit new to Ruby, so please excuse me if this is a simplistic=20

24 messages 2002/07/25
[#45425] Re: Singleton Classes & thread safety — Ned Konz <ned@...> 2002/07/25

On Thursday 25 July 2002 02:06 pm, David King Landrith wrote:

[#45427] Re: Singleton Classes & thread safety — David King Landrith <dave@...> 2002/07/25

On Thursday, July 25, 2002, at 05:26 PM, Ned Konz wrote:

[#45430] Re: Singleton Classes & thread safety — Ned Konz <ned@...> 2002/07/25

On Thursday 25 July 2002 02:44 pm, David King Landrith wrote:

[#45431] How do you think of... — Michael Campbell <michael_s_campbell@...> 2002/07/25

This is going to sound like an odd question, and there's no "right"

[#45429] Opinion on Ruby maturity, the missing things — "Paul E.C. Melis" <paul@...>

Hello all,

18 messages 2002/07/25
[#45440] Re: Opinion on Ruby maturity, the missing things — John Carter <john.carter@...> 2002/07/25

On Fri, 26 Jul 2002, Paul E.C. Melis wrote:

[#45465] Ruby-Talk Index — Tom Sawyer <transami@...>

here's a one nighter coding challange for some one feeling the need to

17 messages 2002/07/26
[#45466] Re: Ruby-Talk Index — matz@... (Yukihiro Matsumoto) 2002/07/26

Hi,

[#45467] Re: Ruby-Talk Index — Tom Sawyer <transami@...> 2002/07/26

On Thu, 2002-07-25 at 23:50, Yukihiro Matsumoto wrote:

[#45621] Seattle.rb meeting tomorrow (7/30) — Pat Eyler <pate@...>

Just a quick reminder that we'll be meeting tomorrow night at 7:00 PM at

11 messages 2002/07/29

[#45644] FormatR 1.06 — Paul Rubel <rubel@...>

A new release of FormatR is out, 1.06. FormatR provides perl-like

37 messages 2002/07/30

[#45688] Ruby Language Q's — "Justin Johnson" <justinj@...>

76 messages 2002/07/30
[#45689] Re: Ruby Language Q's — Dave Thomas <Dave@...> 2002/07/30

"Justin Johnson" <justinj@mobiusent.com> writes:

[#45690] Re: Ruby Language Q's — ts <decoux@...> 2002/07/30

>>>>> "D" == Dave Thomas <Dave@PragmaticProgrammer.com> writes:

[#45723] Syntax proposal — Massimiliano Mirra <list@...>

I often write things like this:

12 messages 2002/07/30

[#45737] ActiveRubyScript and RubyAEOSA — Chris Gehlker <gehlker@...>

I just discovered ActiveRubyScript (sometimes written as two words) by

14 messages 2002/07/30
[#45742] Re: ActiveRubyScript and RubyAEOSA — "Hal E. Fulton" <hal9000@...> 2002/07/30

----- Original Message -----

[#45768] RE: A very basic tail -f implementation — "Berger, Daniel" <djberge@...>

> From: Paul Brannan [mailto:pbrannan@atdesk.com]

12 messages 2002/07/30

[#45799] Question about GetoptLong — Patrick Bennett <patrick.bennett@...>

I'm trying to recreate a Perl script in Ruby and have run into a problem.

22 messages 2002/07/31

[#45829] Unicode in Ruby now? — Tobias Peters <tpeters@...>

I've read the thread "Unicode in Ruby's Future?" [ruby-talk: 40016]. It

52 messages 2002/07/31
[#45840] Re: Unicode in Ruby now? — matz@... (Yukihiro Matsumoto) 2002/07/31

Hi,

[#45954] Re: Unicode in Ruby now? — Tobias Peters <tpeters@...> 2002/08/01

On Wed, 31 Jul 2002, Yukihiro Matsumoto wrote:

[#45960] Re: Unicode in Ruby now? — Curt Sampson <cjs@...> 2002/08/01

On Thu, 1 Aug 2002, Tobias Peters wrote:

[#45969] Re: Unicode in Ruby now? — Alexander Bokovoy <a.bokovoy@...> 2002/08/01

On Thu, Aug 01, 2002 at 07:53:07PM +0900, Curt Sampson wrote:

[#45973] Re: Unicode in Ruby now? — Curt Sampson <cjs@...> 2002/08/01

On Thu, 1 Aug 2002, Alexander Bokovoy wrote:

[#45979] Re: Unicode in Ruby now? — Alexander Bokovoy <a.bokovoy@...> 2002/08/01

On Thu, Aug 01, 2002 at 09:55:48PM +0900, Curt Sampson wrote:

[#45982] Re: Unicode in Ruby now? — Curt Sampson <cjs@...> 2002/08/01

On Thu, 1 Aug 2002, Alexander Bokovoy wrote:

[#45993] Re: Unicode in Ruby now? — Alexander Bokovoy <a.bokovoy@...> 2002/08/01

On Thu, Aug 01, 2002 at 11:23:38PM +0900, Curt Sampson wrote:

[#46042] Re: Unicode in Ruby now? — Curt Sampson <cjs@...> 2002/08/02

On Fri, 2 Aug 2002, Alexander Bokovoy wrote:

[#46260] Re: Unicode in Ruby now? — Clifford Heath <cjh_nospam@...> 2002/08/04

Curt Sampson wrote:

[#46266] Re: Unicode in Ruby now? — Curt Sampson <cjs@...> 2002/08/05

On Mon, 5 Aug 2002, Clifford Heath wrote:

[#46281] Re: Unicode in Ruby now? — Clifford Heath <cjh_nospam@...> 2002/08/05

Curt Sampson wrote:

[#45922] Re: Unicode in Ruby now? — Clifford Heath <cjh_nospam@...> 2002/08/01

Matz,

[#45931] Re: Unicode in Ruby now? — Curt Sampson <cjs@...> 2002/08/01

On Thu, 1 Aug 2002, Clifford Heath wrote:

[#45859] matrix challange — Daniel Bretoi <lists@...>

15 messages 2002/07/31

[#45876] Emacs is dead, long live whatever comes after that as long as it is made with Ruby — Jani Alanko <jani.alanko@...>

Subject is not exactly right but I was too lazy to invent something that

13 messages 2002/07/31

(long) need advice to improve code

From: "Mike Wilson" <wmwilson01@...>
Date: 2002-07-29 18:21:45 UTC
List: ruby-talk #45635
Full code follows at the bottom.


I've recently started hacking around on this again, and I'm stuck on a few 
things.  Firstly, this little work is a real memory hog, but I'm not skilled 
enough to be able to figure out why (anyone?).  Secondly, I have some minor 
issues that I'd like to solve, but I'm not sure how.  First, a little 
background of what this does.  This program basically logs you into any 
number of systems, using telnet and the same username and password for all 
of them.  Then you can run the same command on all of them by only typing it 
once.  So, I can say ./stelnet.rb host1 .. host20, log in just one time and 
then look at the root filesystems on all of them by running "ls /" one time 
and scrolling through the output.  So, on to my questions.  I'm having a 
hard time figuring out how to run some interactive commands which don't 
return any type of prompt (i.e. ex).  If I try to start an ex session (to 
edit a file) my program times out waiting for a prompt to return.  How can I 
get around this?  Also, how could I pass a CTRL-c through to ex instead of 
having my program die over it?  I guess the basic question is, how do I get 
this to act more like a real telnet session (i.e. more solid)?

Thanks

Code follows

#!/usr/gnu/bin/ruby

#  %W%        %G%
#
#  Program Name:        stelnet.rb
#  Date Created:        02/06/01
#  Creator:             Mike Wilson
#
#  SYNOPSIS
#       stelnet.rb host1..hostn
#
#  DESCRIPTION
#       stelnet will log you in to multiple systems, using telnet, and run
#       the specified commands.
#
require 'net/telnet'

module Net
    class Telnet
        # Allow us to get the hostname by printing the connection
        def to_s
            @options['Host']
        end
    end
end

module SuperTelnet
    class User
        # I'll add some stuff to this class at some point.
        attr_accessor :username, :passwd

        def initialize(user, pass)
            @username = user
            @passwd = pass
        end
    end

    class Connection
        # Keep track of all the open connections
        @@uservars = {}

        # This will be used when we only want to execute something once
        # i.e. help should only be displayed 1 time -- not 1 time per
        # connection.
        @@flag = 0

        def initialize(aHash, userObj)
            raise ArgumentError if not userObj.instance_of? 
SuperTelnet::User

            @conOptions = aHash
            @thisUser = userObj

            # Each user gets an array which will hold his connections
            # Hopefully, we'll be able to handle multiple users at some 
point.
            @@uservars[@thisUser] ||= []

            # Set some defaults so that you really only need to provide
            # the hostname to connect to within the conOptions hash.
            @conOptions['Prompt'] ||= Regexp.new('[#$%>] *\z', false, 'n')
            @conOptions['Timeout'] ||= 10
            @conOptions['Port'] ||= 23

            begin
	        @thisConnection = Net::Telnet.new(@conOptions)
            rescue SocketError
                yield "SocketError on #{@conOptions['Host']}, bad host?" if
                    block_given?
            rescue TimeoutError
                yield "TimeoutError on #{@conOptions['Host']}, host down?" 
if
                    block_given?
            rescue Errno::ECONNREFUSED
                yield "Connection refused on #{@conOptions['Host']}" if
                    block_given?
            else
                @@uservars[@thisUser] << self
            end

            @conOptions['Timeout'] = 30
        end

        # If the user enters something that looks like a meta command, but
        # isn't, method_missing will catch it and send it to the executeCmd
        # method to be issued on the command line.
        def method_missing(methodId)
            executeCmd(methodId.id2name) do |c|
                yield c if block_given?
            end
        end

        def to_s
            @thisConnection.to_s
        end

        def Connection.uservars
            @@uservars
        end

        # Always call this after looping through all of the hosts within
        # your implementation of this module.
        def Connection.flagReset
            @@flag = 0
        end

        # Feel free to redefine this as you add commands
        def Connection.help
            "\nAvaiable commands:\n" +
            "  !login(host [hostn])             -> autologin to hosts\n" +
            "  !logoff(host [hostn])            -> logoff hosts\n" +
            "  !su(host [hostn])                -> change user on hosts\n" +
            "  !su                              -> to su on all hosts\n" +
            "  !on(host [hostn]) somecommand    -> run only on these 
hosts\n" +
            "  !off(host [hostn]) somecommand   -> don't run on these\n" +
            "  !set key=value                   -> set user variable\n" +
            "                                      (reference via @key)\n" +
            "  !unset key                       -> unset user variable\n" +
            "  !quit(host [hostn])              -> logoff hosts\n" +
            "  !help                            -> this screen\n\n"
        end

        # Call this for each connection that's been created for thisUser.
        def loginOnConnection
            return if @thisConnection.nil?
            begin
                @thisConnection.login(@thisUser.username, @thisUser.passwd)
            rescue TimeoutError
                yield "TimeoutError on #{@thisConnection}, bad login?" if
                    block_given?
                logoffConnection
            end
        end

        # Call this when you're all done with the connection.  I use this
        # within the loginOnConnection method to remove the connection if
        # the login fails (i.e. bad login).
        def logoffConnection
            @@uservars[@thisUser].delete(self)
            @thisConnection.close
        end

        ####
        # Commands:  So far, you have 2 types of commands -- those that look
        # like !this and those that look like ?this.  !this being a regular
        # command, and ?this being more like a query. (i.e. ?threads #=> on)
        #
        # To add a new command, simply add the corresponding method.  Either
        # Bang_commandName(args, extras) or Qmark_commandName(args, extras)
        # depending on whether it's query or not.  Use the flag if
        # you only want it to execute once.  Other than that, you're done.
        ####

        # !help will print the help message.  Another reason to call
        # Connection.flagReset when you're done
        def Bang_help(args, extras)
            if @@flag == 0
                @@flag = 1
                Connection.help
            end
        end

        # This command equates to !su and !su(host1 host2) and !su host1 
host2
        # Here, we're allowing a method to perform su's so that you can
        # implement a way to hide the password.
        def Bang_su(args, extras)
            user, pass, *hosts = args
            if hosts.size.zero? or hosts.detect do |c|
                    c =~ @thisConnection.to_s
                end
                tmpHash = @conOptions

                # I'm assuming that you want the environment (i.e. the '-')
                tmpHash['String'] = "su - #{user}"
                tmpHash['Match'] = /[pP]assword:/

                @thisConnection.cmd(tmpHash) do |c| yield c if block_given? 
end

                tmpHash['String'] = pass
                tmpHash['Match'] = @conOptions['Prompt']
                @thisConnection.cmd(tmpHash) do |c| yield c if block_given? 
end
            end
        end

        # This command equates to !login(host1 host2) and !login host1 host2
        # Here, you'll be logged into the new hosts without having to 
provide
        # login info -- it'll just use your initial info.
        #
        # This also shows a case where you'd need to call 
Connection.flagReset
        def Bang_login(args, extras)
            if @@flag == 0
                @@flag = 1
                args.each do |arg|
                    Connection.new({'Host' => arg}, @thisUser) do |c|
                        puts c
                    end.loginOnConnection do |c|
                        puts c
                    end
                end
            end
            return
        end

        # This command is !logoff and !logoff(host1 host2) and !logoff host1
        # self-explanatory.
        def Bang_logoff(args, extras)
            raise EOFError if args.size.zero?
            if args.detect do |c|
                    c == @thisConnection.to_s
                end
                logoffConnection
            end
        end

        # Pretty much like the Unix env command at a basic level.  !env
        def Bang_env(args, extras)
            output = []
            if @@flag == 0
                @@flag = 1
                @@uservars.each do |k, v|
                    v = v.join(' ') if v.type == Array
                    output << "#{k}=#{v}\n"
                end
                output
            end
        end

        # This command equates to "!on(host1 host2) do some command"
        def Bang_on(args, extras)
            output = []
            args.each do |arg|
                arg == @thisConnection.to_s and
                    output << runCmdOnConnection(extras)
            end
            output
        end

        # Opposite of above, don't run on these hosts. "!off(host1 host2) 
..."
        def Bang_off(args, extras)
            output = []
            args.each do |arg|
                arg != @thisConnection.to_s and
                    output << runCmdOnConnection(extras)
            end
            output
        end

        # Set user variable.  Use the variable like @this.
        # So, !set foo=bar  can be used as @foo
        def Bang_set(args, extras)
            if @@flag == 0
                @@flag = 1
                k, v = args.join(' ').to_s.split('=')
                @@uservars[k] = v
            end
        end

        # Unset user variable.  !unset foo
        def Bang_unset(args, extras)
            if @@flag == 0
                @@flag = 1
                args.each do |arg|
                    @@uservars.delete(arg)
                end
            end
        end

        # Everything typed by the user (all commands, whether they're to
        # be processed internally or sent to the shell on each box) should
        # pass through this method.  So, really this should probably be 
called
        # proxyCmd or something.
        def executeCmd(cmd)
            # Substitute user variables out before anything else
            @@uservars.each do |k, v|
                cmd.sub!('@' + k.to_s, v.to_s)
            end

            output = case cmd
                when /^([!?=].*)/
                    # It might be an internal command.  Try to process it as
                    # such and if it fails, pass it to the shell
                    begin
                        executeMetaCmd($1)
                    rescue ArgumentError
                        runCmdOnConnection($1)
                    end
                else
                    # Didn't look like anything we're supposed to deal with.
                    # Send it to the shell.
                    runCmdOnConnection(cmd)
            end
            if output and not output.empty? and block_given?
                # Use yields rather than prints so that we can throw a GUI
                # frontend on this someday.
                yield "#{output}\n\n"
            end
            output
        end

        # This is kind of like a proxy for our internal commands.
        def executeMetaCmd(cmd)
            # extras is necessary for commands like:
            # ?on(host1 host2) ls -ltr /var
            # extras would equal "ls -ltr /var" here.
            extras = cmd.sub(/[!\?]\w+\s*\(.*\)\s*(.*)$/, '\1')

            # This is the command (i.e. login) and the hosts (generally)
            metaCmd, *args = cmd.sub(/([!\?]\w+)\s*\((.*)\).*$/, '\1 
\2').split

            case metaCmd
                when /!(\w+)/
                    # If the command was: !login foo bar
                    # call Bang_login(['foo', 'bar'], "")
                    meth = 'Bang_' + $1
                when /\?(\w+)/
                    # If the command was: ?on(oscar) ls -ltr /var
                    # call Qmark_on(['oscar'], "ls -ltr /var")
                    meth = 'Qmark_' + $1
            end
            send(meth, args, extras)
        end

        # This will send the command to the shell for this connection.
        def runCmdOnConnection(cmd)
            output = ["\n#{@thisConnection}:\n"]

            @thisConnection.cmd({
                'String'  => cmd,
                'Match'   => @conOptions['Prompt'],
                'Timeout' => false
            }) do |c|
                if c and c.chomp != cmd
                    output << c
                end
            end
            output
        end

        alias_method :Bang_quit, :Bang_logoff
        alias_method :Bang_exit, :Bang_logoff
    end
end

if __FILE__ == $0
    # We need to add a command "!threads(on|off)" so that we can have
    # sequential or threaded access.  We add all of the support methods, 
along
    # with redefining Connection.help to account for the new command, and
    # finally we add the actual command method Bang_threads.
    module SuperTelnet
        class Connection
            @@threading = 'on'

            def Connection.threading=(toggle)
                toggle = @@threading if toggle != 'on' and toggle != 'off'
                @@threading = toggle
                return
            end

            def Connection.threading
                @@threading
            end

            def Connection.help
                "\nAvaiable commands:\n" +
                "  !login(host [hostn])             -> autologin to hosts\n" 
+
                "  !logoff(host [hostn])            -> logoff hosts\n" +
                "  !su(host [hostn])                -> change user on 
hosts\n" +
                "  !su                              -> to su on all hosts\n" 
+
                "  !on(host [hostn]) somecommand    -> run only on these 
hosts\n" +
                "  !off(host [hostn]) somecommand   -> don't run on these\n" 
+
                "  !set key=value                   -> set user variable\n" 
+
                "                                      (reference via 
@key)\n" +
                "  !unset key                       -> unset user 
variable\n" +
                "  !threads <on|off>                -> set threaded or 
sequential\n" +
                "  ?threads                         -> return thread 
status\n" +
                "  !quit(host [hostn])              -> logoff hosts\n" +
                "  !help                            -> this screen\n\n"
            end

            def Bang_threads(args, extras)
                Connection.threading = args.to_s
            end

            def Qmark_threads(args, extras)
                Connection.threading
            end
        end
    end

    include SuperTelnet

    progname = File.basename $0

    def getUser
        print 'Username: '
        $stdin.gets.chomp
    end

    def getPwd
        print 'Password: '
        begin
            system 'stty -echo'
            $stdin.gets.chomp
        ensure
            puts
            system 'stty echo'
        end
    end

    def usage(progname)
        print "Usage: " + progname
        puts " host1..hostn"
        print Connection.help
        exit
    end

    usage(progname) if ARGV.size.zero? or ARGV[0] =~ /^-[?h]/
    user = User.new(getUser, getPwd)

    ARGV.each do |aHost|
        Connection.new({'Host'=>aHost}, user) do |c| puts c end
    end

    loginThreads = []
    Connection.uservars[user].each do |aCon|
        loginThreads << Thread.new(aCon) do |con|
            con.loginOnConnection do |c| puts c end
        end
    end
    loginThreads.each do |aThread| aThread.join end

    cmdThreads = []
    # Set threading on
    Connection.threading = 'on'
    begin
        while true
            exit if Connection.uservars[user].size.zero?

            print "#{progname}> "
            cmd = $stdin.readline.chomp

            # Within our module, the Bang_su method is called as
            # Bang_su(['username', 'password', 'host1', 'host2'], "")
            # Obviously, we don't want you to type it in on the commandline
            # like that (you'll expose your password), so we proxy instead.
            # You enter !su(host1 host2) and we call getUser and getPwd to
            # prompt you for you info.
            if cmd =~ /!su\s*\(?(.*)+\)?$/
                cmd = "!su(#{getUser} #{getPwd} #{$1})"
            end

            if Connection.threading == 'on'
                Connection.uservars[user].each do |aCon|
                    cmdThreads << Thread.new(aCon) do |con|
                        begin
                            con.executeCmd(cmd) do |c| puts c end
                        rescue Errno::ECONNRESET, Errno::EPIPE
                            puts "#{con}: Connection reset by peer - 
autologoff"
                            con.logoffConnection
                        end
                    end
                end
                cmdThreads.each do |aThread| aThread.join end
            else
                Connection.uservars[user].each do |con|
                    begin
                        con.executeCmd(cmd) do |c| puts c end
                    rescue Errno::ECONNRESET, Errno::EPIPE
                        puts "#{con}: Connection reset by peer - autologoff"
                        con.logoffConnection
                    end
                end
            end
            # Always do this when you've completed processing each command.
            Connection.flagReset
        end
    rescue Interrupt, EOFError
        Connection.uservars[user].each do |con|
            con.logoffConnection
        end
    rescue SocketError
        retry
    end
end




_________________________________________________________________
Chat with friends online, try MSN Messenger: http://messenger.msn.com

In This Thread

Prev Next