Storage of variables without initializing an object? Ruby Gem 'Mail' - ruby

Working with the Ruby Gem 'Mail', I am confused as to how variables are able to be stored without initializing an object? For example:
Mail.defaults do
retriever_method :pop3, :address => "pop.gmail.com",
:port => 995,
:user_name => '<username>',
:password => '<password>',
:enable_ssl => true
end
After which you are able to call methods such as Mail.first and have it return the first message in the mailbox with the configured defaults.
I realize everything in Ruby is an object, even a class, so when require 'mail' is called, does an object containing the the class Mail actually get created and mad available to the program? What exactly is happening here?

The contents of mail.rb are loaded into the file that has the require 'mail' statement.
After having a look in the gem, mail.rb contains the Mail module, which in turn contains many other require statements.
mail.rb
module Mail
## skipped for brevity
# Finally... require all the Mail.methods
require 'mail/mail'
end
mail/mail.rb
module Mail
## skipped for brevity
# Receive the first email(s) from the default retriever
# See Mail::Retriever for a complete documentation.
def self.first(*args, &block)
retriever_method.first(*args, &block)
end
end
So then the methods are made available to your program.

Related

Run controller as Ruby script?

In my application I setup a news controller to handle news feeds using Nokogiri:
class NewsController < InheritedResources::Base
def new
require 'nokogiri'
require 'open-uri'
doc = Nokogiri::XML(open("http://www.themusicvoid.com/feed"))
#info = doc.xpath('//item').take(5).map do |i|
News.create(:title => i.xpath('title').inner_text,
:description => i.xpath('description').inner_text,
:link => i.xpath('link').inner_text,
:image => i.xpath('image').inner_text)
end
end
end
This functions by running <%= debug #info %> in the new.html.erb file. It searches the RSS feed and automatically saves to my database.
The problem is that it would do this whenever ANYBODY loaded new.html.erb (although I could add that file to my robots.txt so at least bots wouldn't trigger it.)
What I actually want is some sort of a Ruby script or Rake task that would do the exact same thing without loading a page. If I just run the code above as a script, it works, it would output the data if I wanted to echo it, but it does not save the information to the database. Any ideas on how I might do that?
You can create a rake task under lib/tasks directory:
rss_fetcher.rake
require 'nokogiri'
require 'open-uri'
namespace :rss do
desc "Fetch rss feed"
task :fetch => :environment do
doc = Nokogiri::XML(open("http://www.themusicvoid.com/feed"))
#info = doc.xpath('//item').take(5).map do |i|
News.create(:title => i.xpath('title').inner_text, :description => i.xpath('description').inner_text, :link => i.xpath('link').inner_text, :image => i.xpath('image').inner_text)
end
end
end
then somewhere call rake 'rss:fetch'
I highly recommend the whenever gem to do that kind of job
gem install whenever
config/schedule.rb
every 2.hours do
rake "rss:fetch"
end

EM::Synchrony.defer with fiber aware database call causes FiberError exception

I'm trying to use EM-Synchrony for concurrency in an application and have come across an issue with my use of deferred code and Fibers.
Any calls to the database within either EM.defer or EM::Synchrony.defer results in the application crashing with the error can't yield from root fiber
Below is a very trimmed down runnable example of what I'm trying to accomplish. The first print works and displays [:first, 1] but the second is where I crash with the error mentioned above.
require 'mysql2'
require 'em-synchrony/activerecord'
ActiveRecord::Base.establish_connection(
:adapter => 'em_mysql2',
:username => 'user',
:password => 'pass',
:host => 'localhost',
:database => 'app_dev',
:pool => 60
)
class User < ActiveRecord::Base; end
EM.synchrony do
p [:first, User.all.count]
EM::Synchrony.defer do
p [:second, User.all.count]
end
end
My first thought was perhaps the Fiber.current and Fiber.yield within EM::Synchrony.defer meant I could fix the problem with an extra Fiber.new call
EM::Synchrony.defer do
Fiber.new do
p [:second, User.all.count]
end.resume
end
This fails to run as well but this time I get the error fiber called across threads.

sending file with pony by sinatra app - missing file

I want to send a email from my sinatra application.
Here is the code:
require 'pony'
class Cms < Application
get "/mail" do
Pony.mail :to => 'to#gmail.com',
:from => "from#gmail.com",
:subject => "Thanks for signing my guestbook!",
:via => :sendmail,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:user_name => 'user#gmail.com',
:pass => 'pass',
:enable_starttls_auto => false
},
:body => erb(:"cms/mail")
redirect '/'
end
end`
Thin is starting application with no errors, but When i request myapp.local/mail i've got an error:
LoadError - no such file to load -- mail/network/delivery_methods/smtp:
/var/lib/gems/1.8/gems/mail-2.4.4/lib/mail/configuration.rb:31:in lookup_delivery_method'
/var/lib/gems/1.8/gems/mail-2.4.4/lib/mail/configuration.rb:25:in delivery_method'
/var/lib/gems/1.8/gems/mail-2.4.4/lib/mail/mail.rb:111:in delivery_method'
/var/lib/gems/1.8/gems/mail-2.4.4/lib/mail/message.rb:116:in initialize'
/var/lib/gems/1.8/gems/mail-2.4.4/lib/mail/mail.rb:50:in new'
/var/lib/gems/1.8/gems/mail-2.4.4/lib/mail/mail.rb:50:in new'
/var/lib/gems/1.8/gems/pony-1.4/lib/pony.rb:174:in build_mail'
/var/lib/gems/1.8/gems/pony-1.4/lib/pony.rb:138:in mail'
./app/controllers/cms.rb:8:in GET /mail'
File /var/lib/gems/1.8/gems/mail-2.4.4/lib/mail/network/delivery_methods/smtp.rb exists.
I was getting this same error when I was using the inline configuration of the Mail gem:
mail.delivery_method :sendmail
mail.deliver!
Removing that first line, and moving the configuration to immediately following the loading of the mail gem fixed it.
Wherever in your app you require 'mail' just configure it immediately:
require 'mail'
Mail.defaults do
delivery_method :sendmail
end
Update: This worked for awhile... But then for some reason I began seeing this error:
rbenv/versions/1.8.7-p374/lib/ruby/gems/1.8/gems/mail-2.5.4/lib/mail/fields/common/common_address.rb:9:in `parse': no such file to load -- mail/elements/address_list (LoadError)
Update2: The failures happen randomly it seems. Something about the way the autoload works in Ruby 1.8.7-p374 is causing it to not be able to find files that do in fact exist. Also, I am using slimgems not rubygems.
These are the hacks I've had to implement so far to use Mail with multi-part email and sendmail delivery method:
require 'mail'
require 'mail/network/delivery_methods/sendmail'
require 'mail/elements/address_list'
require 'mail/fields/common/common_address'
require 'mail/elements/content_type_element'
require 'mail/elements/address'
require 'mail/elements/content_transfer_encoding_element'
Mail.defaults do
delivery_method :sendmail
end

In Ruby/Sinatra, Datamapper's .all works but .get doesn't?

I am trying to take data from a path in Sinatra, and use it to look up a particular record using Datamapper. The Datamapper docs seem to indicate that.
get "/test/:test_path" do
test_get = Intake.get( params[:test_path] )
# Do stuff
erb :blah_blah_blah
end
should find any records associated with the symbol :test_path
This does not work. test_get gets nil.
Meanwhile, what does work is
get "/test/:test_path" do
test_all = Intake.all(:test_path => params[:test_path] )
# Do stuff
erb :blah_blah
end
My two questions are:
What am I doing wrong with the .get() call in Datamapper?
Is the .all(:name => value) method slower than .get(), or does it not matter which I use?
Here's a Sinatra script pared down to demonstrate the behavior.
#!/usr/bin/env ruby
require 'rubygems'
require 'sinatra'
require 'dm-core'
require 'dm-timestamps'
DataMapper.setup(:default, {:adapter => 'yaml', :path => 'db'})
class Intake
include DataMapper::Resource
property :id, Serial
property :created_at, DateTime
property :test_path, String
end
get "/test/:test_path" do
test_all = Intake.all(:test_path => params[:test_path] )
puts 'test_all:' test_all.inspect
test_get = Intake.get( params[:test_path] )
puts 'test_get:' test_get.inspect
"Hello World!"
end
#get only does a lookup based on primary key, with is the id. So
Intake.get(params[:test_path])
looks for something with id params[:test_path], which will fail. Use
Intake.first(test_path: params[:test_path])

Selenium Ruby Reporting

I'm trying to set the environment for testing using Selenium and selenium-client gem.
I prefer unit test style over RSpec style of tests.
Do I have to build my own system for reporting then?
How can I add exception handling without having begin-rescue-end in each test? Is there any way to do that using mixins?
I'm not sure I understand what your question means in terms of reporting but the selenium-client gem handles both BDD and UnitTesting.
Below is code copied from the rubyforge page:
require "test/unit"
require "rubygems"
gem "selenium-client", ">=1.2.16"
require "selenium/client"
class ExampleTest < Test::Unit::TestCase
attr_reader :browser
def setup
#browser = Selenium::Client::Driver.new \
:host => "localhost",
:port => 4444,
:browser => "*firefox",
:url => "http://www.google.com",
:timeout_in_second => 60
browser.start_new_browser_session
end
def teardown
browser.close_current_browser_session
end
def test_page_search
browser.open "/"
assert_equal "Google", browser.title
browser.type "q", "Selenium seleniumhq"
browser.click "btnG", :wait_for => :page
assert_equal "Selenium seleniumhq - Google Search", browser.title
assert_equal "Selenium seleniumhq", browser.field("q")
assert browser.text?("seleniumhq.org")
assert browser.element?("link=Cached")
end
end
As for exception handling, UnitTesting handles the exceptions with an Error message.
That being said, I may have misunderstood your question.
Initial build of Extent is available for Ruby. You can view the sample here. Latest source is available at github.
Sample code:
# main extent instance
extent = RelevantCodes::ExtentReports.new('extent_ruby.html')
# extent-test
extent_test = extent.start_test('First', 'description string')
# logs
extent_test.log(:pass, 'step', 'details')
extent.end_test(extent_test)
# flush to write everything to html file
extent.flush

Resources