Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   Net::FTP puttextfile question (http://www.velocityreviews.com/forums/t839601-net-ftp-puttextfile-question.html)

Jeff 04-04-2007 01:26 AM

Net::FTP puttextfile question
 
I'm trying to use the Net::FTP class to send a text file to my FTP
server, but I don't have an actual text file to send. Instead I want
to send it a multi-line string as my "file". (I'm using Builder to
generate an XML file and I don't want to have to physically save it to
a file before sending it.)

The Net::FTP class has a method called puttextfile that seems to be
defined like this:

def puttextfile(localfile, remotefile = File.basename(localfile),
&block)

but I don't have a local filename to provide. Is there anything I can
use that would substitute for one?

I tried to use a StringIO object, hoping to use that as my
"localfile":

s = StringIO.new(xml_data)

but when I try to send it like this:

Net::FTP.open("domain.com", "username", "secret") do |ftp|
ftp.puttextfile(s, '\data\file.xml"')
end

I get this error:

TypeError: can't convert StringIO into String
from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `open'
from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `puttextfile'
from (irb):33
from c:/ruby/lib/ruby/1.8/net/ftp.rb:115:in `open'
from (irb):32

Obviously it wants a filename, and I'm giving it the actual IO object
instead. .NET had the concept of IO streams, and I was hoping to use
something like that here, but I can't figure out how.

Any ideas?

Thanks!
Jeff



Jeff 04-04-2007 02:57 AM

Re: Net::FTP puttextfile question
 
On Apr 3, 8:26 pm, "Jeff" <cohen.j...@gmail.com> wrote:
> I'm trying to use the Net::FTP class to send a text file to my FTP
> server, but I don't have an actual text file to send. Instead I want
> to send it a multi-line string as my "file". (I'm using Builder to
> generate an XML file and I don't want to have to physically save it to
> a file before sending it.)
>
> The Net::FTP class has a method called puttextfile that seems to be
> defined like this:
>
> def puttextfile(localfile, remotefile = File.basename(localfile),
> &block)
>
> but I don't have a local filename to provide. Is there anything I can
> use that would substitute for one?


I ended up subclassing and providing the functionality myself.

In case it helps anyone, here's what I came up with: two methods,
get_text_lines and send_text_lines. See below for complete source
(it's not too long). Suggestions for making the code more elegant are
definitely welcome.
Jeff

require 'net/ftp'

class JeffFTP < Net::FTP

# Sends a collection of lines to be saved in a file on the server
# lines can be an array, or anything responding to #each
def send_text_lines(lines, remotefile, &block) # :yield: line
storlines_from_array("STOR " + remotefile, lines, &block)
end

# Gets a file from the server as a collection of text lines.
# If you don't provide a block, it will return an array of lines.
# If you provide a block, each line will be passed to the block,
# and the return value will be an empty array.
# Large files should use the block form.
def get_text_lines(remotefile, &block) # :yield: line
lines = []
retrlines("RETR " + remotefile) do |line|
if block
yield(line)
else
lines << line
end
end
lines
end

private

def storlines_from_array(cmd, lines, &block) # :yield: line
synchronize do
voidcmd("TYPE A")
conn = transfercmd(cmd)
lines.each do |line|
conn.write(line)
yield(line) if block
end
conn.close
voidresp
end
end

end



Rick DeNatale 04-06-2007 01:31 PM

Re: Net::FTP puttextfile question
 
On 4/3/07, Jeff <cohen.jeff@gmail.com> wrote:
> I'm trying to use the Net::FTP class to send a text file to my FTP
> server, but I don't have an actual text file to send. Instead I want
> to send it a multi-line string as my "file". (I'm using Builder to
> generate an XML file and I don't want to have to physically save it to
> a file before sending it.)
>
> The Net::FTP class has a method called puttextfile that seems to be
> defined like this:
>
> def puttextfile(localfile, remotefile = File.basename(localfile),
> &block)
>
> but I don't have a local filename to provide. Is there anything I can
> use that would substitute for one?
>
> I tried to use a StringIO object, hoping to use that as my
> "localfile":
>
> s = StringIO.new(xml_data)
>
> but when I try to send it like this:
>
> Net::FTP.open("domain.com", "username", "secret") do |ftp|
> ftp.puttextfile(s, '\data\file.xml"')
> end
>
> I get this error:
>
> TypeError: can't convert StringIO into String
> from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `open'
> from c:/ruby/lib/ruby/1.8/net/ftp.rb:571:in `puttextfile'
> from (irb):33
> from c:/ruby/lib/ruby/1.8/net/ftp.rb:115:in `open'
> from (irb):32
>
> Obviously it wants a filename, and I'm giving it the actual IO object
> instead. .NET had the concept of IO streams, and I was hoping to use
> something like that here, but I can't figure out how.
>
> Any ideas?


Try turning the problem around and look at using open-uri instead of
Net::FTP? This extends Kernel::open so that it accepts ftp and http
urls as well as file names. This makes the ftp server look like a
local file.

So you'd do something like this (untested):

require 'open-uri'

open("ftp://user:secret@domain.com/data/file.xml",'w') do | f |
# write your data to the IO object f here
end
--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/



All times are GMT. The time now is 07:05 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.