Ruby: how to parse e-mail mime from the stdin - ruby

Anyone know how I can parse the E-mail MIME from Ruby when the input is from STDIN? I have found a gem called "mail" which looks really nice but so far as I can see it's able to read a mail only from the file:
require 'mail'
mail = Mail.read('/path/to/message.eml')
This is how I'm testing it:
# First one is from stdin:
require 'mail'
mail = Mail.new($stdin.readlines)
p mail.from
p mail.to
returns:
nil
nil
# This one is from the file:
mail2 = Mail.new("my_email.txt")
p mail2.from
p mail2.to
returns:
nil
nil
# The same file but I'm using Mail.read:
mail3 = Mail.read("my_email.txt")
p mail3.from
p mail3.to
returns:
["test#gmail.com"]
["test2#gmail.com"]
STDIN I'm testing like:
# cat my_email.txt | ruby code.rb
So the method Mail.read works fine with my e-mail, but when I want to put my stdin to the Mail.read I have:
mail/mail.rb:176:in `initialize': no implicit conversion of Array into String (TypeError)
I know that I can save that file from stdin to the temp folder and then open it by Mail.read but I don't want to do this in that way since it will be slow.
The full url to the gem is: https://github.com/mikel/mail

readlines returns an array... of lines! You might want to try read on ARGF which is the input provided by $stdin instead.
mail = Mail.new ARGF.read
See the relevant documentation.

IO#readlines produces an array. You want a string there:
# readmail.rb
require 'mail'
mail = Mail.new(STDIN.read)
p mail.from
p mail.to
# mail.eml
From: bob#test.lindsaar.net
To: mikel#test.lindsaar.net
Subject: This is an email
This is the body
# command line
$ ruby readmail.rb < mail.eml
# => ["bob#test.lindsaar.net"]
# => ["mikel#test.lindsaar.net"]

Related

How do I log a URL encode if it's a private method?

Using Ruby 1.9.1 or 1.9.3, I have a problem inserting the % symbol into a database.
The exception is:
/app/vendor/ruby-1.9.3/lib/ruby/1.9.1/uri/common.rb:898:in `decode_www_form_component'
I was told to use p to output str.
This is ruby/lib/1.9.1/util/common.rb:
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
require 'logger'
# Keep data for the current month only
$LOG = Logger.new('this_month.log', 'monthly')
$LOG.debug("#{str.p}")
raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
end
I got this error:
Internal Server Error
cannot parse Cookie header: private method `p' called for "innate.sid":String
How do I p str to find out what's inside it and maybe what encoding it is?
You don't need the p method if you're using logger. p and puts output to stdout.
# this is equavalent to `puts str`
$LOG.debug(str)
# for more "raw" data
# `p str` or `puts str.inspect`
$LOG.debug(str.inspect)

Ruby how to write to Tempfile?

I am trying to create a Tempfile and write some text into it. But I get this strange behavior in console
t = Tempfile.new("test_temp") # => #<File:/tmp/test_temp20130805-28300-1u5g9dv-0>
t << "Test data" # => #<File:/tmp/test_temp20130805-28300-1u5g9dv-0>
t.write("test data") # => 9
IO.read t.path # => ""
I also tried cat /tmp/test_temp20130805-28300-1u5g9dv-0 but the file is empty.
Am I missing anything? Or what's the proper way to write to Tempfile?
FYI I'm using ruby 1.8.7
You're going to want to close the temp file after writing to it. Just add a t.close to the end. I bet the file has buffered output.
Try this
run t.rewind before read
require 'tempfile'
t = Tempfile.new("test_temp")
t << "Test data"
t.write("test data") # => 9
IO.read t.path # => ""
t.rewind
IO.read t.path # => "Test datatest data"
close or rewind will actually write out content to file. And you may want to delete it after using:
file = Tempfile.new('test_temp')
begin
file.write <<~FILE
Test data
test data
FILE
file.close
puts IO.read(file.path) #=> Test data\ntestdata\n
ensure
file.delete
end
It's worth mentioning, calling .rewind is a must otherwise any subsequent .read call will just return empty value

Sinatra outputs correctly to console, but no output to browser

I want to output RSS via Sinatra. I wrote below code, but it outputs nothing. Strangly, when I wrote puts before rss, it output rss correctly to console! Why I cannot output to browser?
#encoding: utf-8
require 'sinatra'
require 'rss'
...
get '/' do
...
rss = RSS::Maker.make("2.0") do |rss|
rss.channel.about = 'http://hoge/rss.xml'
rss.channel.title = "hoge"
...
end
content_type = 'application/xml'
# puts rss # => output correctly to console
rss # => output nothing
end
whole code: https://github.com/weed/p120905-rss-process-test/blob/master/app.rb
Thanks for your kindness.
Sinatra doesn't seem to know what to do with the RSS object.
How about changing the last line in the get block to
rss.to_s

understanding Ruby code?

I was wondering if anyone can help me understanding the Ruby code below? I'm pretty new to Ruby programming and having trouble understanding the meaning of each functions.
When I run this with my twitter username and password as parameter, I get a stream of twitter feed samples. What do I need to do with this code to only display the hashtags?
I'm trying to gather the hashtags every 30 seconds, then sort from least to most occurrences of the hashtags.
Not looking for solutions, but for ideas. Thanks!
require 'eventmachine'
require 'em-http'
require 'json'
usage = "#{$0} <user> <password>"
abort usage unless user = ARGV.shift
abort usage unless password = ARGV.shift
url = 'https://stream.twitter.com/1/statuses/sample.json'
def handle_tweet(tweet)
return unless tweet['text']
puts "#{tweet['user']['screen_name']}: #{tweet['text']}"
end
EventMachine.run do
http = EventMachine::HttpRequest.new(url).get :head => { 'Authorization' => [ user, password ] }
buffer = ""
http.stream do |chunk|
buffer += chunk
while line = buffer.slice!(/.+\r?\n/)
handle_tweet JSON.parse(line)
end
end
end
puts "#{tweet['user']['screen_name']}: #{tweet['text']}"
That line shows you a user name followed by the content of the tweet.
Let's take a step back for a sec.
Hash tags appear inside the tweet's content--this means they're inside tweet['text']. A hash tag always takes the form of a # followed by a bunch of non-space characters. That's really easy to grab with a regex. Ruby's core API facilitates that via String#scan. Example:
"twitter is short #foo yawn #bar".scan(/\#\w+/) # => ["#foo", "#bar"]
What you want is something like this:
def handle_tweet(tweet)
return unless tweet['text']
# puts "#{tweet['user']['screen_name']}: #{tweet['text']}" # OLD
puts tweet['text'].scan(/\#\w+/).to_s
end
tweet['text'].scan(/#\w+/) is an array of strings. You can do whatever you want with that array. Supposing you're new to Ruby and want to print the hash tags to the console, here's a brief note about printing arrays with puts:
puts array # => "#foo\n#bar"
puts array.to_s # => '["#foo", "#bar"]'
#Load Libraries
require 'eventmachine'
require 'em-http'
require 'json'
# Looks like this section assumes you're calling this from commandline.
usage = "#{$0} <user> <password>" # $0 returns the name of the program
abort usage unless user = ARGV.shift # Return first argument passed when program called
abort usage unless password = ARGV.shift
# The URL
url = 'https://stream.twitter.com/1/statuses/sample.json'
# method which, when called later, prints out the tweets
def handle_tweet(tweet)
return unless tweet['text'] # Ensures tweet object has 'text' property
puts "#{tweet['user']['screen_name']}: #{tweet['text']}" # write the result
end
# Create an HTTP request obj to URL above with user authorization
EventMachine.run do
http = EventMachine::HttpRequest.new(url).get :head => { 'Authorization' => [ user, password ] }
# Initiate an empty string for the buffer
buffer = ""
# Read the stream by line
http.stream do |chunk|
buffer += chunk
while line = buffer.slice!(/.+\r?\n/) # cut each line at newline
handle_tweet JSON.parse(line) # send each tweet object to handle_tweet method
end
end
end
Here's a commented version of what the source is doing. If you just want the hashtag, you'll want to rewrite handle_tweet to something like this:
handle_tweet(tweet)
tweet.scan(/#\w/) do |tag|
puts tag
end
end

Having trouble saving to file in Ruby

Hi I have a simple form that allows a user to input a name, their gender and a password. I use Digest::MD5.hexdigest to encrypt the input. Once I have the encrypted input eg, d1c261ede46c1c66b7e873564291ebdc, I want to be able to append this to a file I have already created. However every thing I have tried just isn't working. Can anyone please help and thank you in advance. Here is what I have:
input = STDIN.read( ENV["CONTENT_LENGHT"] )
puts "Content-type: text/html \n\n"
require 'digest/md5'
digest = Digest::MD5.hexdigest(input)
f = File.open("register.txt", "a")
f.write(digest)
f.close
I have also tried this with no luck:
File.open("register.txt", "a") do |f|
f.puts(digest)
end
If the code is verbatim then I think you have a typo in the first line: did you mean CONTENT_LENGHT or is it a typo? ENV[] will return a string if the variable is set, which will upset STDIN#read. I get TypeError: can't convert String into Integer. Assuming the typo, then ENV[] returns nil, which tells STDIN#read to read until EOF, which from the console means, I think, Control-Z. That might be causing a problem.
I suggest you investigate by modifying your script thus:
read_length = ENV["CONTENT_LENGTH"].to_i # assumed typo fixed, convert to integer
puts "read length = #{read_length}"
input = STDIN.read( read_length )
puts "input = #{input}"
puts "Content-type: text/html \n\n" # this seems to serve no purpose
require 'digest/md5'
digest = Digest::MD5.hexdigest(input)
puts "digest = #{digest}"
# prefer this version: it's more idiomatically "Rubyish"
File.open("register.txt", "a") do |f|
puts "file opened"
f.puts(digest)
end
file_content = File.read("register.txt")
puts "done, file content = #{file_content}"
This works on my machine, with the following output (when CONTENT_LENGTH set to 12):
read length = 12
abcdefghijkl
input = abcdefghijkl
Content-type: text/html
digest = 9fc9d606912030dca86582ed62595cf7
file opened
done, file content = 6cfbc6ae37c91b4faf7310fbc2b7d5e8
e271dc47fa80ddc9e6590042ad9ed2b7
b0fb8772912c4ac0f13525409c2b224e
9fc9d606912030dca86582ed62595cf7

Resources