Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Net::Netrc request for comments

Reply
Thread Tools

Net::Netrc request for comments

 
 
Bob Showalter
Guest
Posts: n/a
 
      09-22-2005
Hi,

I'm a Perl-er learning ruby. I'm creating a ruby port of Perl's Net::Netrc
module for accessing ftp(1)'s .netrc file. I couldn't find an existing ruby
version anywhere.

My current code is below. I've essentially ported the Perl module's usage
semantics, although my internal implementation is quite different. I'd sure
appreciate any feedback, especially related to doing things the "ruby way",
with a view toward submitting this code to the appropriate archive site(s)
at some point.

Example usage:

require 'net/netrc'

n = Net::Netrc.locate('example.com')
if (n.nil?)
puts "No entry found"
else
puts "login = #{n.login}, password = #{n.password}"
end

Questions:

1. Should I use locate() instead of new()? locate() is how the Perl
module works.

2. Should I return nil if no entry is found, or should I return an
object with the accessors all nil?

3. Should I be returning a Net::Netrc object at all, or just a simple
Hash? Or should Net::Netrc sublcass Hash?

4. Is rasing a SecurityError appropriate? Should I create a specific
exception class instead?

------- BEGIN CODE --------

module Net

class Netrc

attr_accessor :machine, :login, assword, :account

# returns name of .netrc file
def Netrc.rcname
# TODO: cross platform? getpwuid() for home dir?
home = ENV['HOME']
home ||= ENV['HOMEDRIVE'] + (ENV['HOMEPATH'] || '') if
ENV['HOMEDRIVE']
File.join(home, '.netrc')
end

# opens .netrc file, returning File object if successful.
# returns nil if .netrc not found.
# raises SecurityError if .netrc is not owned by the current.
# user or if it is readable or writable by other than the
# current user.
def Netrc.open
name = rcname
return nil unless File.exist?(name)
# TODO: this stat code not applicable to Win32 (and others?)
s = File.stat(name)
raise SecurityError, "Not owner: #{name}" unless s.owned?
raise SecurityError, "Bad permissions: #{name}" if s.mode & 077 != 0
File.open(name, 'r')
end

# given a machine name, returns a Net::Netrc object containing
# the matching entry for that name, or the default entry. If
# no match is found an no default entry exists, nil is returned.
def Netrc.locate(mach)
f = open or return nil
entry = nil
key = nil
inmacdef = false
while line = f.gets
if inmacdef
inmacdef = false if line.strip.empty?
next
end
toks = line.scan(/"((?:\\.|[^"])*)"|((?:\\.|\S)+)/).flatten.compact
toks.each { |t| t.gsub!(/\\(.)/, '\1') }
while toks.length > 0
tok = toks.shift
if key
entry = new if key == 'machine' && tok == mach
entry.send "#{key}=", tok if entry
key = nil
end
case tok
when 'default'
return entry if entry
entry = new
when 'machine'
return entry if entry
key = 'machine'
when 'login', 'password', 'account'
key = tok
end
end
end
entry
end

end

end

------- END CODE --------

TIA for any feedback,

Bob


 
Reply With Quote
 
 
 
 
nobu.nokada@softhome.net
Guest
Posts: n/a
 
      09-22-2005
Hi,

At Fri, 23 Sep 2005 00:54:51 +0900,
Bob Showalter wrote in [ruby-talk:157128]:
> I'm a Perl-er learning ruby. I'm creating a ruby port of Perl's Net::Netrc
> module for accessing ftp(1)'s .netrc file. I couldn't find an existing ruby
> version anywhere.


I'm using <http://www.rubyist.net/~nobu/ruby/netrc.rb>.

--
Nobu Nakada


 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      09-22-2005
Bob Showalter <(E-Mail Removed)> wrote:
> Hi,
>
> I'm a Perl-er learning ruby. I'm creating a ruby port of Perl's
> Net::Netrc module for accessing ftp(1)'s .netrc file. I couldn't find
> an existing ruby version anywhere.
>
> My current code is below. I've essentially ported the Perl module's
> usage semantics, although my internal implementation is quite
> different. I'd sure appreciate any feedback, especially related to
> doing things the "ruby way", with a view toward submitting this code
> to the appropriate archive site(s) at some point.
>
> Example usage:
>
> require 'net/netrc'
>
> n = Net::Netrc.locate('example.com')
> if (n.nil?)
> puts "No entry found"
> else
> puts "login = #{n.login}, password = #{n.password}"
> end
>
> Questions:
>
> 1. Should I use locate() instead of new()? locate() is how the Perl
> module works.


I'd use locate only and probably make new private. Reason is that locate
will not always return a valid object.

> 2. Should I return nil if no entry is found, or should I return an
> object with the accessors all nil?


Return nil

> 3. Should I be returning a Net::Netrc object at all, or just a simple
> Hash? Or should Net::Netrc sublcass Hash?


Definitely not the latter. I'd probably use an instance of Net::Netrc and
add some methods (who says the Ruby version must not be better than the Perl
version)? For example, I'd add a method that opens a connection with the
info you have:

class Netrc
def open(do_init = true)
conn = Ftp.open machine
begin
conn.login login, password
# add code that executes all default actions if defined, maybe
argument flag controlled
rescue Net::FTPPermError
conn.close
raise
end

if block_given?
begin
yield conn
ensure
conn.close
end

nil
else
conn
end
end
end

Then you can do

n = Net::Netrc.locate('example.com')

if n
n.open do |ftp|
files = ftp.chdir('pub/lang/ruby/contrib')
files = ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
end
else
puts "not found"
end

You could even make this more convenient by adding a class method open that
does this

class Netrc
def self.open(machine, do_init = true, &b)
n = locate machine
raise "error" unless n
n.open(do_init, &b)
end
end

Then you can do

Net::Netrc.open('ftp.foo.bar') do |ftp|
...
end

Uh, just detected a name clash. I'd rename your open as this seems to be a
rather internal method.

> 4. Is rasing a SecurityError appropriate? Should I create a specific
> exception class instead?


I think it's appropriate. However, it seems to me that if you want to mimic
FTP's behavior then you should raise the exception only if you find a
password:
http://www.die.net/doc/linux/man/man5/netrc.5.html

> ------- BEGIN CODE --------
>
> module Net
>
> class Netrc
>
> attr_accessor :machine, :login, assword, :account
>
> # returns name of .netrc file
> def Netrc.rcname
> # TODO: cross platform? getpwuid() for home dir?
> home = ENV['HOME']
> home ||= ENV['HOMEDRIVE'] + (ENV['HOMEPATH'] || '') if
> ENV['HOMEDRIVE']
> File.join(home, '.netrc')
> end
>
> # opens .netrc file, returning File object if successful.
> # returns nil if .netrc not found.
> # raises SecurityError if .netrc is not owned by the current.
> # user or if it is readable or writable by other than the
> # current user.
> def Netrc.open
> name = rcname
> return nil unless File.exist?(name)
> # TODO: this stat code not applicable to Win32 (and others?)
> s = File.stat(name)
> raise SecurityError, "Not owner: #{name}" unless s.owned?
> raise SecurityError, "Bad permissions: #{name}" if s.mode & 077
> != 0 File.open(name, 'r')
> end
>
> # given a machine name, returns a Net::Netrc object containing
> # the matching entry for that name, or the default entry. If
> # no match is found an no default entry exists, nil is returned.
> def Netrc.locate(mach)
> f = open or return nil
> entry = nil
> key = nil
> inmacdef = false
> while line = f.gets
> if inmacdef
> inmacdef = false if line.strip.empty?
> next
> end
> toks =
> line.scan(/"((?:\\.|[^"])*)"|((?:\\.|\S)+)/).flatten.compact
> toks.each { |t| t.gsub!(/\\(.)/, '\1') } while toks.length > 0


# what do you need that "while toks.length > 0" for? Seems completely
superfluous to me. Or is this an indentation problem and the "while" should
have been on the next line? Hmm, probably...

I'd probably do the parsing a bit different: I would have to think about
this a bit more but I'd keep a set of settings for default and a set for the
machine and directly return if I found the machine. Just a rough idea...

> tok = toks.shift
> if key
> entry = new if key == 'machine' && tok == mach
> entry.send "#{key}=", tok if entry
> key = nil
> end
> case tok
> when 'default'
> return entry if entry
> entry = new
> when 'machine'
> return entry if entry
> key = 'machine'
> when 'login', 'password', 'account'
> key = tok
> end
> end
> end
> entry
> end
>
> end
>
> end
>
> ------- END CODE --------
>
> TIA for any feedback,
>
> Bob


You're welcome!

Kind regards

robert

 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      09-22-2005
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> Hi,
>
> At Fri, 23 Sep 2005 00:54:51 +0900,
> Bob Showalter wrote in [ruby-talk:157128]:
>> I'm a Perl-er learning ruby. I'm creating a ruby port of Perl's
>> Net::Netrc module for accessing ftp(1)'s .netrc file. I couldn't
>> find an existing ruby version anywhere.

>
> I'm using <http://www.rubyist.net/~nobu/ruby/netrc.rb>.


"Internal Server Error" - Hm...

robert
 
Reply With Quote
 
nobu.nokada@softhome.net
Guest
Posts: n/a
 
      09-23-2005
Hi,

At Fri, 23 Sep 2005 01:46:40 +0900,
Robert Klemme wrote in [ruby-talk:157135]:
> > I'm using <http://www.rubyist.net/~nobu/ruby/netrc.rb>.

>
> "Internal Server Error" - Hm...


Hmmm, I can't stop it from seeing .rb as CGI. Try
<http://www.rubyist.net/~nobu/ruby/netrc_rb.txt>

--
Nobu Nakada


 
Reply With Quote
 
Bob Showalter
Guest
Posts: n/a
 
      09-23-2005
(E-Mail Removed) wrote:
> Hi,
>
> At Fri, 23 Sep 2005 01:46:40 +0900,
> Robert Klemme wrote in [ruby-talk:157135]:
>>> I'm using <http://www.rubyist.net/~nobu/ruby/netrc.rb>.

>>
>> "Internal Server Error" - Hm...

>
> Hmmm, I can't stop it from seeing .rb as CGI. Try
> http://www.rubyist.net/~nobu/ruby/netrc_rb.txt


Thanks, I can see it now. Looks like you subclassed Hash. I will study your
code more. Your parsing logic seems much more complex than mine; perhaps I'm
missing something.

I note that your technique is similar to the Perl module in that you load
the entire file into a hash. But this conflicts with the documentation in
that once a matching "machine" entry is found or the "default" entry is
found, parsing stops when the next "machine" or "default" entry (or eof) is
found.

So if I have:

machine foo ...
default ...
machine bar ...

ftp(1) will not see the "bar" entry (but instead would return the default
login), while your code (and the Perl code) will return the "bar" entry.



 
Reply With Quote
 
nobuyoshi nakada
Guest
Posts: n/a
 
      09-26-2005
Hi,

At Fri, 23 Sep 2005 09:52:06 +0900,
Bob Showalter wrote in [ruby-talk:157201]:
> I note that your technique is similar to the Perl module in that you load
> the entire file into a hash. But this conflicts with the documentation in
> that once a matching "machine" entry is found or the "default" entry is
> found, parsing stops when the next "machine" or "default" entry (or eof) is
> found.


Thank you, I haven't noticed it. But is that behaviors better?

--
Nobu Nakada


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
A program to replace all JS comments with JSP comments in jsp files tungchau81@yahoo.com Javascript 4 06-03-2006 02:00 PM
A program to replace all JS comments with JSP comments in jsp files tungchau81@yahoo.com Java 0 06-02-2006 06:35 AM
Comments format: comments extending over multi-line Monk C Programming 10 04-20-2005 05:09 PM
[pfoto] request for comments Bartek Wi¶niewski Digital Photography 4 05-09-2004 01:16 AM
Re: Accessing Request.InputStream / Request.BinaryRead *as the request is occuring*: How??? Brian Birtle ASP .Net 2 10-16-2003 02:11 PM



Advertisments