Unindent HEREDOCs in Ruby 2.3
In Ruby 2.3 you can use <<~
instead of <<-
to automatically remove indentation from a HEREDOCs:
str = <<~MESSAGE
Hello Universe!
This is me.
Bye!
MESSAGE
str
will now be:
Hello Universe!
This is me.
Bye!
Make Nokogiri use system libxml2
The nokogiri gem provides different packages for several platforms. Each platform-specific variant ships pre-built binaries of libxml2
, e.g. x86_64-linux
includes binaries for 64bit Linux on Intel/AMD. This significantly speeds up installation of the gem, as Nokogiri no longer needs to compile libxml2
.
However, this also means that for each security issue with libxml2
, Nokogiri maintainers have to update their pre-built binaries and release a new version of the gem. Then, you need to update and ...
How to encode or decode quoted-printable strings
E-mails are usually encoded using Quoted Printable. Here is how to decode or encode such strings.
You probably know Quoted Printable from e-mail bodies appearing in Rails logs, where =
s become =3D
s in URLs, or where long lines are split up and trailed by =
after each split.
Decode Quoted Printable
Decoding such strings is actually quite simple using plain Ruby:
"foo=3Dbar".unpack('M')[0]
# => "foo=bar"
Note that unpack
will return an array. Our result is the 1st item.
...
Stop using bundle exec
Install this gem and stop using bundle exec
or even Geordi's handy b
. Yay!
Sidekiq: Problems and Troubleshooting
When using Sidekiq in your application, you must write thread-safe code.
This wiki page also lists gems that are known to be unsafe on threaded applications.
When adding a gem that will also be used by a Sidekiq worker, make sure to confirm it's thread-safe.
Beware ruby's var1 = var2 = "value" multiple assignment
This looks like it is safe to use:
2.2.1 :001 > a = b = "hello world"
"hello world"
2.2.1 :002 > a
"hello world"
2.2.1 :003 > b
"hello world"
2.2.1 :004 > b = " goodbye!"
" goodbye!"
2.2.1 :005 > a
"hello world"
2.2.1 :006 > b
" goodbye!"
But it isn't!
2.2.1 :010 > a = b = "hello world"
"hello world"
2.2.1 :011 > a
"hello world"
2.2.1 :012 > b
"hello world"
2.2.1 :013 > b << " goodbye!"
"hello world goodbye!"
2.2.1 :014 > a
"hello world goodbye!"
2.2.1 :015 > b
"hello world goodbye!"
What is happening when we do `a = b = ...
Upgrade from Ruby 1.8.7 to 2.1.5 – an incomplete guide
I recommend to go straight to 2.1.5+
without intermediate steps. Otherwhise you burden yourself with unnecessary work of encoding problems.
Issues you may encounter:
- Set the ruby version within your
.ruby-version
file to2.1.5
- Remove gem
ruby-debug
and use e.g.byebug
- Remove gem
oniguruma
- Remove gem
fastercsv
- Replace gem
mysql
withmysql2
- Update gem capistrano
2.12.0
to~>2.12
when bound forRuby 1.8.7
and remove obsolete explicite Gemfile entries fornet-scp
andnet-ssh
if present. - Update gem `and...
Override Cucumber steps without an ambiguity error
Cucumber raises a Cucumber::Ambiguous
if more than one step definitions match a step.
Our new cucumber_priority gem provides a way to mark step definitions as overridable, meaning that they can always be overshadowed by a more specific version without raising an error.
This gem is currently used by spreewald and cucumber_factory.
Marking step definiti...
Defining and calling lambdas or procs (Ruby)
Ruby has the class Proc
which encapsulates a "block of code". There are 2 "flavors" of Procs
:
- Those with "block semantics", called
blocks
or confusingly sometimes alsoprocs
- Those with "method semantics", called
lambdas
lambdas
They behave like Ruby method definitions:
- They are strict about their arguments.
-
return
means "exit thelambda
"
How to define a lambda
-
With the
lambda
keywordtest = lambda do |arg| puts arg end
-
With the lambda literal
->
(since Ruby 1.9.1)
...
Class: RubyVM::InstructionSequence (Ruby 2.0.0)
This class contains nerdcore things such as disassembling a piece of Ruby into VM calls or enabling tail-call optimization.
Also see this article about enabling TCO on a per-method basis.
Git: Issues with Gemfile.lock
When there's a Gemfile.lock
in your working directory that you cannot remove by either checkout
, reset [--hard]
, stash
, probably Rails' Spring is the culprit and not Bundler itself.
Fix
spring stop
The author of the linked Stackoverflow post supposes Spring re-writes the Gemfile.lock
on change to ensure all Spring processes are using the same gem versions. Meh.
How to run a small web server (one-liner)
Sometimes you just want to have a small web server that serves files to test something.
Serve the current directory
On Ruby 1.9.2+ you can do the following (".
" for current directory). You might need to gem install webrick
on modern Rubies.
ruby -run -ehttpd . -p8000
Python 2.x offers a similar way.
python -m SimpleHTTPServer 8000 .
This is the same way with Python 3.x
python -m http.server
In both cases your web server is single-threaded and will block when large files are being downloaded from you.
WEBrick ...
Gemspecs must not list the same gem as both runtime and development dependency
When you're developing a gem, never list the same dependency as both runtime and development dependency in your .gemspec
.
So don't do this:
spec.add_dependency 'activesupport'
spec.add_development_dependency 'activesupport', '~> 2.3'
If you do this, your gemspec will not validate and modern versions of Bundler will silently ignore it. This leads to errors like:
Could not find your-gem-0.1.2 in any of the sources
What to do instead
If you want to freeze a different version of a dependency for your t...
Ruby: How to update all values of a Hash
There are many solutions, but a very concise one is this:
hash.merge!(hash) do |key, old_value, new_value|
# Return something
end
The block of merge!
will be called whenever a key in the argument hash already exists in the base hash. Since hash
is updated with itself, each key will conflict and thus allow you to modify the value of each key to whatever you like (by returning old_value
you'd get the behavior of Rails' reverse_merge!
, by re...
Count number of existing objects in Ruby
Sometimes you want to know exactly how many objects exist within your running Ruby process. Here is how:
stats = {}
ObjectSpace.each_object {|o| stats[o.class].nil? ? stats[o.class] = 0 : stats[o.class] += 1 }; stats
=> {String=>192038, Array=>67690, Time=>2667, Gem::Specification=>2665, Regexp=>491, Gem::Requirement=>16323, Gem::StubSpecification=>2665, ...}
Maybe you want to sort it like this:
stats.sort_by {|k,v| v }
Ruby will get a safe navigation operator: '.?'
This is basically Ruby-native syntax for andand
.
About Ruby's conversion method pairs
Ruby has a set of methods to convert an object to another representation. Most of them come in explicit and implicit flavor.
explicit | implicit |
---|---|
to_a |
to_ary |
to_h |
to_hash |
to_s |
to_str |
to_i |
to_int |
There may be even more.
Don't name your methods like the implicit version (most prominently to_hash
) but the like the explicit one.
Explicit conversion
Explicit conversion happens when requesting it, e.g. with the splat opera...
Sending TCP keepalives in Ruby
When you make a simple TCP connection to a remote server (like telnet
), your client won't normally notice when the connection is unexpectly severed on the remote side. E.g. if someone would disconnect a network cable from the server you're connected to, no client would notice. It would simply look like nothing is being sent.
You can detect remote connection loss by configuring your client socket to send TCP keepalive signals after some period of inactivity. If those signals are not acknowledged by the other side, your client will terminat...
Test downstream bandwidth of Internet connection
You want to test your 1GE or 10GE internet uplink? We needed to ensure we have full 10GE to the backbone for a customer project.
Using netcat
To test whether we can achieve the bandwidth internally, you can use netcat and dd like this:
On your first server: nc -v -l 55333 > /dev/null
On your second server: dd if=/dev/zero bs=1024K count=5000 | nc -v $remote_ip 55333
You should see some output like this:
user@xxx:~ % dd if=/dev/zero bs=1024K count=5000 | nc -v removed 55333
Connection to 91.250.95.249 55333 port [...
Ruby: How to make an object that works with multiple assignment
Ruby allows multiple assignment:
a, b, c = o
In order to prove multiple values from a single object, Ruby calls #to_a
on the object:
o = String.new('O')
def o.to_a
[1,2,3]
end
a, b, c = o # Implicit call to #to_a here
a # => 1
b # => 2
c # => 3
Hence, if you want your class to support multiple assignment, make sure to define a #to_a
method.
Heads up: Ruby implicitly converts a hash to keyword arguments
When a method has keyword arguments, Ruby offers implicit conversion of a Hash
argument into keyword arguments. This conversion is performed by calling to_hash
on the last argument to that method, before assigning optional arguments. If to_hash
returns an instance of Hash
, the hash is taken as keyword arguments to that method.
Iss...
Ruby: Do not mix optional and keyword arguments
Writing ruby methods that accept both optional and keyword arguments is dangerous and should be avoided. This confusing behavior will be deprecated in Ruby 2.7 and removed in Ruby 3, but right now you need to know about the following caveats.
Consider the following method
# DO NOT DO THIS
def colored_p(object = nil, color: 'red')
switch_color_to(color)
puts object.inspect
end
colored_p(['an array']) # ['an array'] (in red)
colored_p({ a: 'hash' }, color: 'blue') # {:a=>'hash'} (in blue)
colored_p({ a: 'ha...
ExceptionNotification gem will only show application backtrace starting on Rails 4
Starting with Rails 4.0, when you get an exception reported via the ExceptionNotification
gem, you will only see a very short backtrace with all backtrace lines from gems or ruby libraries missing.
This happens, because the ExceptionNotification
gem uses Rails' default backtrace cleaner. To get a full backtrace in exception emails, you can remove the comment from this line in config/initializers/backtrace_silencers.rb
:
Rails.backtrace_cleaner.remove_silencers!
Note that this will break the "Application Trace" functionality o...
Enumerators in Ruby
Starting with Ruby 1.9, most #each
methods can be called without a block, and will return an enumerator. This is what allows you to do things like
['foo', 'bar', 'baz'].each.with_index.collect { |name, index| name * index }
# -> ["", "bar", "bazbaz"]
If you write your own each
method, it is useful to follow the same practice, i.e. write a method that
- calls a given block for all entries
- returns an enumerator, if no block is given
How to write a canonical each
method
To write a m...