it_only: running a single example in RSpec
Sometimes you want to focus on just one example in your RSpec file. I had to do this quite often in the last 3 days and I got tired of commenting out stuff back and forth. So, I give you “it_only” example.
module Spec
module DSL
module BehaviourEval
module ModuleMethods
def it(description = :__generate_description, opts = {}, &block)
return if @it_only_found
examples << Example.new(description, opts, &block)
end
# Same as +it+ only blocks all other examples making this the
# only example that would run.
def it_only(description = :__generate_description, opts = {}, &block)
@it_only_found = true
@examples = [Example.new(description, opts, &block)]
end
end
end
end
end
Drop this into your spec_helper.rb and now if you want to focus on a single example, just make it “it_only” instead of “it“.
Installing Ruby Gems with native extensions in Ubuntu
I’ve recently started experimenting with using Ubuntu for my Ruby development. Some of the Gems like JSON and HPricot have extension compilation step which doesn’t work on a default Ubuntu installation.
Here are a few steps that you need to get it to work.
- Open up Synaptic Package Manager from System > Preferences
- Search for “ruby1.8-dev”, right click and check “Mark for installation”
- Search for “build-essential” and mark it for installation as well
- Click “Apply” in the toolbar
After the update is finished, you should be able to install Gems which require native extensions compilation.
Performance where not expected or gsub vs sub string
If I were to be asked what is faster, regular sub string operation or a regular expression, I would without hesitation answer that sub string is.
This was the assumption that I approached a simple task with – stripping slashes from beginning and end of a string. Here’s the code:
path = path[1..-1] if path[0, 1] == '/' path = path[0..-2] if path[-1, 1] == '/'
I would naturally assume that the block above would be faster than path.gsub!(/^\/|\/$/, ''). But just in case, lets benchmark to be sure.
require 'benchmark'
original = '/hello/somewhat/long/path/here/'
max = 1_000_000
puts Benchmark.measure {
1.upto(max) do
path = original
path = path[1..-1] if path[0, 1] == '/'
path = path[0..-2] if path[-1, 1] == '/'
end
}
puts Benchmark.measure {
1.upto(max) do
path = original
path.gsub!(/^/|/$/, '')
end
}
# prints out
4.212000 0.000000 4.212000 ( 4.270000)
2.418000 0.000000 2.418000 ( 2.435000)
I don’t understand why, but gsub is 57% faster. I find it hard to believe that a few extra Ruby statements introduce so much overhead that it becomes slower than entire regular expressions engine. Anyone has any explanation for this?
Ruby: get full history (all parents) of a hash node
Nested hashes could be used to represent tree structures. Here’s a code to to find a node by key and get all of its parents:
def hash_history(hash, desired_key, &block)
return false unless Hash === hash
hash.each_pair do |key, value|
if key == desired_key or hash_history(value, desired_key, &block)
yield(key, value)
return true
end
end
return false
end
hash = {
:level_1 => {
:level_2 => {
:level_3 => {
:search => 'test'
}
}
}
}
hash_history(hash, :search) { |key, value| puts key }
# prints out...
# search
# level_3
# level_2
# level_1
RDoc bug: visiblity of attributes is always public
It would appear that RDoc Ruby parser in Ruby 1.8.6 has a bug which leads to attributes always being public.
Here’s the fix in parser_rb.rb:
...
def parse_attr(context, single, tk, comment)
args = parse_symbol_arg(1)
if args.size > 0
name = args[0]
rw = "R"
skip_tkspace(false)
tk = get_tk
if tk.kind_of? TkCOMMA
rw = "RW" if get_bool
else
unget_tk tk
end
att = Attr.new(get_tkread, name, rw, comment)
att.top_level = @top_level
att.visibility = context.visibility ######### NEW LINE ##########
read_documentation_modifiers(att, ATTR_MODIFIERS)
if att.document_self
context.add_attribute(att)
end
else
warn("'attr' ignored - looks like a variable")
end
end
...
def parse_attr_accessor(context, single, tk, comment)
args = parse_symbol_arg
read = get_tkread
rw = "?"
# If nodoc is given, don't document any of them
tmp = CodeObject.new
read_documentation_modifiers(tmp, ATTR_MODIFIERS)
return unless tmp.document_self
case tk.name
when "attr_reader" then rw = "R"
when "attr_writer" then rw = "W"
when "attr_accessor" then rw = "RW"
else
rw = @options.extra_accessor_flags[tk.name]
end
for name in args
att = Attr.new(get_tkread, name, rw, comment)
att.top_level = @top_level
att.visibility = context.visibility ######### NEW LINE ##########
context.add_attribute(att)
end
end