How can I profile `require` statements in Ruby? - ruby

I'm interested in seeing how long (in seconds) each require statement in my Ruby code takes to load. How can I temporarily override that method and print out some logging information for slow loads?

You can override Kernel.require like this:
module Kernel
# make an alias of the original require
alias_method :original_require, :require
# rewrite require
def require name
start = Time.now
# code to time
ret = original_require name
finish = Time.now
diff = finish - start
# TODO: This should really add up all of
# the require calls for a certain module
if diff > 0.1
puts "#{diff} #{name}"
end
ret
end
end

Related

Three Ruby classes, more than three problems?

I have three Ruby files in the same directory:
classthree.rb
otherclass.rb
samplecode.rb
Here are the contents of classthree.rb:
require './samplecode.rb'
require './otherclass.rb'
class ClassThree
def initialize()
puts "this class three here"
end
end
Here are the contents of samplecode.rb:
require './otherclass.rb'
require './classthree.rb'
class SampleCode
$smart = SampleCode.new
#sides = 3
##x = "333"
def ugly()
g = ClassThree.new
puts g
puts "monkey see"
end
def self.ugly()
s = SampleCode.new
s.ugly
puts s
puts $smart
puts "monkey see this self"
end
SampleCode.ugly
end
Here are the contents of otherclass.rb:
require './samplecode.rb'
require './classthree.rb'
END {
puts "ending"
}
BEGIN{
puts "beginning"
}
class OtherClass
def initialize()
s = SampleCode.new
s.ugly
end
end
My two questions are:
There has to be a better way than require './xyz.rb' for every class in the directory. Isn't there something like require './*.rb'?
When I run ruby otherclass.rb I get the following output:
Why do I get "beginning" and "ending" twice each??
At 1 - The best way to deal with it is to create another file. You can call it environment.rb or initialize.rb, and it would require all the needed files.
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'samplecode.rb'
require 'classthree.rb'
require 'classthree.rb'
Now you only need to require this file once on the start of the application.
At 2 - You started from file 'otherclass.rb'. It displays the first 'beginning' bit and then it loads samplecode.rb file. At this point, 'otherclass.rb' has not been loaded yet - it was not required by any other file. hence samplecode.rb is rerunning whole otherclass.rb, which is being required there. Rerunning doesn't reload 'samplecode.rb' as it was already required (require checks first whether file was or was not required). That's why you're seeing those messages twice.

Override rake test:units runner

I recently decided to write a simple test runtime profiler for our Rails 3.0 app's test suite. It's a very simple (read: hacky) script that adds each test's time to a global, and then outputs the result at the end of the run:
require 'test/unit/ui/console/testrunner'
module ProfilingHelper
def self.included mod
$test_times ||= []
mod.class_eval do
setup :setup_profiling
def setup_profiling
#test_start_time = Time.now
end
teardown :teardown_profiling
def teardown_profiling
#test_took_time = Time.now - #test_start_time
$test_times << [name, #test_took_time]
end
end
end
end
class ProfilingRunner < Test::Unit::UI::Console::TestRunner
def finished(elapsed_time)
super
tests = $test_times.sort{|x,y| y[1] <=> x[1]}.first(100)
output("Top 100 slowest tests:")
tests.each do |t|
output("#{t[1].round(2)}s: \t #{t[0]}")
end
end
end
Test::Unit::AutoRunner::RUNNERS[:profiling] = proc do |r|
ProfilingRunner
end
This allows me to run the suites like so rake test:xxx TESTOPTS="--runner=profiling" and get a list of Top 100 tests appended to the end of the default runner's output. It works great for test:functionals and test:integration, and even for test:units TEST='test/unit/an_example_test.rb'. But if I do not specify a test for test:units, the TESTOPTS appears to be ignored.
In classic SO style, I found the answer after articulating clearly to myself, so here it is:
When run without TEST=/test/unit/blah_test.rb, test:units TESTOPTS= needs a -- before its contents. So the solution in its entirety is simply:
rake test:units TESTOPTS='-- --runner=profiling'

Is it possible to globally increase Watir-Webdriver when_present wait time?

I am writing an automated testing program which will test some web programs that are sometimes slow to load certain AJAX calls. For instance the user will click 'Query' which will result in a HTML 'loading' overlay for anywhere from 15 to 90 seconds. When the search completes, it will then update a table on the same page with the results.
So obviously I can increase the waiting time individually like so:
browser.td(:id => 'someId').when_present.some_action #=> will wait 30 seconds
browser.td(:id => 'someId').when_present(90).some_action #=> will wait *90* seconds
But is there a way to modify (in my case increase) the time so Watir-Webdriver always waits 90 seconds on .when_present like so:
browser.some_default = 90
browser.td(:id => 'someId').when_present.some_action #=> will wait *90* seconds
A few words of warning: Client timeout will not affect when_present. Nor will implicit wait.
Update: This monkey patch has been merged into watir-webdriver and so will no longer be needed in watir-webdriver v0.6.5. You will be able to set the timeout using:
Watir.default_timeout = 90
The wait methods are defined similar to:
def when_present(timeout = 30)
message = "waiting for #{selector_string} to become present"
if block_given?
Watir::Wait.until(timeout, message) { present? }
yield self
else
WhenPresentDecorator.new(self, timeout, message)
end
end
As you can see, the default timeout of 30 seconds is hard-coded. Therefore, there is no easy way to change it everywhere.
However, you could monkey patch the wait methods to use a default time and set it to what you want. The following monkey patch will set the default timeout to 90 seconds.
require 'watir-webdriver'
module Watir
# Can be changed within a script with Watir.default_wait_time = 30
#default_wait_time = 90
class << self
attr_accessor :default_wait_time
end
module Wait
class << self
alias old_until until
def until(timeout = Watir.default_wait_time, message = nil, &block)
old_until(timeout, message, &block)
end
alias old_while while
def while(timeout = Watir.default_wait_time, message = nil, &block)
old_while(timeout, message, &block)
end
end # self
end # Wait
module EventuallyPresent
alias old_when_present when_present
def when_present(timeout = Watir.default_wait_time, &block)
old_when_present(timeout, &block)
end
alias old_wait_until_present wait_until_present
def wait_until_present(timeout = Watir.default_wait_time)
old_wait_until_present(timeout)
end
alias old_wait_while_present wait_while_present
def wait_while_present(timeout = Watir.default_wait_time)
old_wait_while_present(timeout)
end
end # EventuallyPresent
end # Watir
Include the patch after the watir webdriver code is loaded.

With Test::Unit, how can I run a bit of code before all tests (but not each test)?

In my test app, which uses test::unit, I need to start by pulling a bunch of data from various sources. I'd like to only do this once - the data is only read, not written, and doesn't change between tests, and the loading (and error checking for the loading), takes some time.
There are values that I DO want reset every time, and those are easy enough, but what if I want persistant accessible values? What's the best way to do this?
I'm especially interested in solutions that would let my push those assignments to some module that can be included in all my tests, since they all need access to this data.
Why do you need it inside the test? You could define it gloabl:
gem 'test-unit'#, '>= 2.1.1' #startup
require 'test/unit'
GLOBAL_DATA = 11
class My_Tests < Test::Unit::TestCase
def test_1()
puts "Testing startup 1"
assert_equal(11, GLOBAL_DATA)
end
end
GLOBAL_DATA could be a (singleton)-class (respective an instance).
If you have only one testclass, you may use TestCase.startup:
gem 'test-unit'#, '>= 2.1.1' #startup
require 'test/unit'
class My_Tests < Test::Unit::TestCase
def self.startup
puts "Define global_data "
##global_data = 11
end
def test_1()
puts "Testing 1"
assert_equal(11, ##global_data = 11)
end
def test_2()
puts "Testing 2"
assert_equal(11, ##global_data = 11)
end
end
You can just put them at the top of the class. They will get executed, and then your tests will get executed.
You could do this in the setup method:
def setup
if !defined?(##initial_data)
# Whatever you need to do to get your initial data
##initial_data = foo
end
#other_data = bar
end

In Sinatra(Ruby), how should I create global variables which are assigned values only once in the application lifetime?

In Sinatra, I'm unable to create global variables which are assigned values only once in the application lifetime. Am I missing something? My simplified code looks like this:
require 'rubygems' if RUBY_VERSION < "1.9"
require 'sinatra/base'
class WebApp < Sinatra::Base
#a = 1
before do
#b = 2
end
get '/' do
puts #a, #b
"#{#a}, #{#b}"
end
end
WebApp.run!
This results in
nil
2
in the terminal and ,2 in the browser.
If I try to put #a = 1 in the initialize method, I'm getting an error in the WebApp.run! line.
I feel I'm missing something because if I can't have global variables, then how can I load large data during application instantiation?
before do seems to get called every time there is a request from the client side.
class WebApp < Sinatra::Base
configure do
set :my_config_property, 'hello world'
end
get '/' do
"#{settings.my_config_property}"
end
end
Beware that if you use Shotgun, or some other Rack runner tool that reloads the code on each request the value will be recreated each time and it will look as if it's not assigned only once. Run in production mode to disable reloading and you will see that it's only assigned on the first request (you can do this with for example rackup --env production config.ru).
I ran into a similar issue, I was trying to initialize an instance variable #a using the initialize method but kept receiving an exception every time:
class MyApp < Sinatra::Application
def initialize
#a = 1
end
get '/' do
puts #a
'inside get'
end
end
I finally decided to look into the Sinatra code for initialize:
# File 'lib/sinatra/base.rb', line 877
def initialize(app = nil)
super()
#app = app
#template_cache = Tilt::Cache.new
yield self if block_given?
end
Looks like it does some necessary bootstrapping and I needed to call super().
def initialize
super()
#a = 1
end
This seemed to fix my issue and everything worked as expected.
Another option:
helpers do
def a
a ||= 1
end
end
Building on Theo's accepted solution, it is also possible to do:
class App < Sinatra::Application
set :blabla, ''
namespace '/b' do
get '/baby' do
# do something where bouh is assigned a value
settings.blabla = 'bouh'
end
end
namespace '/z'
get '/human' do
# settings.blabla is available here with newly assigned value
end
end
end
You could use OpenStruct.
require 'rubygems'
require 'sinatra'
require 'ostruct'
configure do
Struct = OpenStruct.new(
:foo => 'bar'
)
end
get '/' do
"#{Struct.foo}" # => bar
end
You can even use the Struct class in views and other loaded files.

Resources