This article was originally posted on the globaldev blog, they have kindly allowed me to repost it here. If you’re looking for a Ruby job in London you should check out their jobs page.
A preview version of the next major release of Ruby was announced at RubyConf by Matz this week, with some great new language features. This post covers a few of the highlights.
If you create a namespaced refinement:
module NumberQuery
refine String do
def number?
match(/^[1-9][0-9]+$/) ? true : false
end
end
end
It’s not available outside that namespace
begin
"123".number?
rescue => e
p e #=> #<NoMethodError: undefined method `number?' for "123":String>
end
But it is inside!
module NumberQuery
p "123".number? #=> true
end
You can add it to another namespace like so:
module MyApp
using NumberQuery
p "123".number? #=> true
p "foo".number? #=> false
end
def wrap(string, before: "<", after: ">")
"#{before}#{string}#{after}" # no need to retrieve options from a hash
end
# optional
p wrap("foo") #=> "<foo>"
# one or the other
p wrap("foo", before: "#<") #=> "#<foo>"
p wrap("foo", after: "]") #=> "<foo]"
# order not important
p wrap("foo", after: "]", before: "[") #=> "[foo]"
# double splat to capture all keyword arguments, or use as hash as keyword
# arguments
def capture(**opts)
opts
end
p capture(foo: "bar") #=> {:foo=>"bar"}
# keys must be symbols
opts = {:before => "(", :after => ")"}
p wrap("foo", **opts) #=> "(foo)"
# the old hash style syantax is still accepted for keyword arguments
p wrap("foo", :before => "{", :after => "}") #=> "{foo}"
Enumerator#lazy
Making an enumerable lazy makes it possible to enumerate infinite collections
require "timeout"
begin
timeout(1) {[1,2,3].cycle.map {|x| x * 10}}
rescue => e
p e #=> #<Timeout::Error: execution expired>
end
p [1,2,3].lazy.cycle.map {|x| x * 10}.take(5).to_a #=> [10, 20, 30, 10, 20]
A lazy enumerable will evaluate the entire chain for each element at a time,
rather than all elements at each stage of the chain, so the following will
output at 1 second intervals. Without #lazy
all output would come after 3
seconds
class Foo
include Enumerable
def each
sleep 1
yield 1
sleep 1
yield 2
sleep 1
yield 3
end
end
Foo.new.lazy.map {|x| x * 10}.each {|x| p x}
You would think that as the collection is only iterated once #lazy
might
speed things up, unfortunatly this generally isn’t the case
Module#prepend
module A
def foo
"A"
end
end
In a regular module include, the method in the class overrides the module
(module method is available as super
)
class B
include A
def foo
"B"
end
end
p B.new.foo #=> "B"
With prepend
the module method overides that in the class
(in the case the method in the class is available as super
)
class C
prepend A
def foo
"B"
end
end
p C.new.foo #=> "A"
#to_h
p({:foo => 1}.to_h) #=> {:foo=>1}
Baz = Struct.new(:foo)
baz = Baz.new(1)
p baz.to_h #=> {:foo=>1}
So instead of writing something overly strict like:
def foo(opts)
raise ArgumentError, "opts must be a Hash" unless opts.is_a?(Hash)
# do stuff with opts
end
We can go with the more versatile:
def foo(options)
if options.respond_to?(:to_h)
opts = options.to_h
else
raise TypeError, "can't convert #{options.inspect} into Hash"
end
# do stuff with opts
end
%i
: a literal for symbol arrayp %i{hurray huzzah whoop} #=> [:hurray, :huzzah, :whoop]
This is a fork of the Oniguruma regexp engine used by 1.9, with a few more features. More details here. The new features seem Perl-inspired, with a good reference available here
(?(cond)yes|no)
If cond
is matched, then match against yes
, if cond
is false match against
no
. cond
references a match either by group number or name, or is a
look-ahead/behind.
This example only matches a trailing capital if there is a leading capital:
regexp = /^([A-Z])?[a-z]+(?(1)[A-Z]|[a-z])$/
regexp =~ "foo" #=> 0
regexp =~ "foO" #=> nil
regexp =~ "FoO" #=> 0