Notes posted to Ruby
RSS feedArgument Accepted
Accepts a single argument sep_string
Includes descendants
May be helpful to know that this returns true if A is any descendant of B, not just a direct one. As an example:
class Foo; end class Bar < Foo; end class Baz < Bar; end Bar < Foo #=> true Baz < Foo #=> true
If you want direct descendance try Class#superclass:
Bar.superclass == Foo #=> true Baz.superclass == Foo #=> false
Replacing with "\" and match — a simple solution
A somewhat different approach to the same problem:
v.gsub(/(?=\W)/, '\\') #=> Foo\ Bar\!
But from what you are trying to achieve I suspect you might be interested in Regexp.escape method :)
Replacing with "\" and match
If you’re trying to place a “" in front of your matches, you’ll quickly see that it is a pain in the ass to add the quoting in the replacement string.
Here’s an example:
v = "Foo Bar!" # Target: Foo\ Bar\! # Resulting strings will not be quoted to decrease # the amount of backslashes. Compare \\! to "\\\\!" v.gsub(/\W/, '\0') #=> Foo Bar! # \\ escapes to a literal \, which next to the 0 becomes \0 v.gsub(/\W/, '\\0') #=> Foo Bar! # \\\0, means "\ \0", or "escaped \0" v.gsub(/\W/, '\\\0') #=> Foo\0Bar\0 # Same mechanism as before. \\ → \ v.gsub(/\W/, '\\\\0') #=> Foo\0Bar\0 # Finally! We have now an escaped \ before \0 and # we get the results we want. v.gsub(/\W/, '\\\\\0') #=> Foo\ Bar\! # It's very tempting to just write it like this now, right? v.gsub(/\W/) { |m| "\\#{m}" } #=> Foo\ Bar\! # It might not be shorter, but anyone can understand it.
Surely, there must be an easier way to do this. I haven’t found it, though. Hopefully, this makes it easier for you to understand why it behaves the way it does. :-)
Testing Regular Expressions?
Writing regular expressions is never easy. You may use http://rubular.com to test and optimize your regular expressions.
Example
code:
class Klass def set(string) var_name = "@#{string}" # the '@' is required self.instance_variable_set(var_name, 'bar') end def puts_foo puts @foo end end k = Klass.new k.puts_foo # nil k.set('foo') k.puts_foo # 'bar'
lower case am/pm
With DateTime#strftime you can also use %P to get a lowercase am/pm. Not so with Time#strftime though!
overwrite
Replacing old value with new one
>> Module.const_set('MY_CONSTANT', 'value') => "value" >> Module::MY_CONSTANT => "value" >> Module.const_set('MY_CONSTANT', 'new value') (irb):3: warning: already initialized constant MY_CONSTANT => "new value" >> Module::MY_CONSTANT => "new value"
or
>> Kernel.const_set('MY_CONSTANT', 'value') => "value" >> MY_CONSTANT => "value" >> Kernel.const_set('MY_CONSTANT', 'new value') (irb):3: warning: already initialized constant MY_CONSTANT => "new value" >> MY_CONSTANT => "new value"
define_method with parameters
Just to be clear, you can do this:
define_method(:my_method) do |foo, bar| # or even |*args| # do something end
This means same as:
def my_method(foo, bar) # do something end
If you want to define method with parameters that have default values, you need to get a bit more creative and do something like this:
define_method(:my_method) do |foo, bar| bar ||= {} # do something end
Don't forget to require 'tmpdir'
If you simply say Dir.tmpdir you might get a nice surprise:
irb> Dir.tmpdir NoMethodError: undefined method `tmpdir' for Dir:Class
from (irb):1
Strangely, this method seems to be stored in a file that Ruby doesn’t require by default. Just require 'tmpdir' and all should be well.
irb> require 'tmpdir' => true irb> Dir.tmpdir => "/var/folders/An/AnwlXPZFH2aRLCERERQDKE+++TI/-Tmp-"
Map-like Manipulation of Hash Values
Let’s say you want to multiply all values of the following hash by 2:
hash = { :a => 1, :b => 2, :c => 3 }
You can’t use map to do so:
hash.map {|k, v| v*2 } # => [6, 2, 4]
However, with merge you can:
hash.merge(hash) {|k,v| v*2 } => {:c=>6, :a=>2, :b=>4}
(The above is Ruby 1.8, in Ruby 1.9 the order is preserved.)
See Dir#glob
See glob for more usage information and comments.
Getting relative path from absolute globbing
Say you want to scan for files in directory base_dir and you want to use the relative path from this base dir, you could do it like this:
base_dir = '/path/to/dir' files = Dir[File.join(base_dir, '**', '*.yml')] # files now contain absolute paths: files.first # => "/path/to/dir/foo/bar.yml" # let's make them relative base_pathname = Pathname.new(base_dir) files = files.collect do |file| Pathname.new(file).relative_path_from(base_pathname) end files.first # => "foo/bar.yml"
Of course, a more common use-case could be the following:
def scan_for_documents! base_path = Pathname.new(self.base_path) self.contained_files = [] Dir[File.join(self.base_path, '**', '*.pdf')].each do |full_path| path = Pathname.new(full_path).relative_path_from(base_path) self.contained_files << path end end
Get all inner texts
Extend REXML::Element so that it can get the first text and following inner texts (child texts included) of the current element as array and as string:
class REXML::Element def inner_texts REXML::XPath.match(self,'.//text()') end def inner_text REXML::XPath.match(self,'.//text()').join end end
Receiving data over UDP
It’s perfectly normal to receive ‘X’ strings with Ruby’s UDP sockets before the actual content.
Consider the following example:
require 'socket' PORT = 5500 socket = UDPSocket.new socket.bind('', PORT) for i in 1..10 IO.select([socket]) p socket.recvfrom_nonblock(4096) end
Now, sending data with netcat:
echo "Hello APIdock" | nc -vv -u 127.0.0.1 5500
The application would output:
["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]] ["Hello APIdock\n", ["AF_INET", 61755, "localhost", "127.0.0.1"]]
Case-insensitive comparison
For a case-insensitive comparison, use String#casecmp
Using argument version in ruby < 1.8.7
The argument to this method was added in Ruby 1.8.7. If you want to use this form in an earlier version, you must instead use the slice! method.
It is mentioned up in the docs, but here it is again for reference:
# Ruby >= 1.8.7 p = list.pop(n) # Ruby < 1.8.7 p = list.slice!(-n, n)
collect/map
If you’d like to use this method for something like Enumerable#collect, you are looking at the wrong place. This method will return the initial integer, not the values from the block.
a = 20.times { |n| n * 2 } #=> 20
Instead, use Range#collect:
a = (0...20).collect { n * 2 }
Shortcut with %
@tordans for multiple args wrap the args in an array
Shortcut with %
Thanks iamcata, that works :). And I finally found the right place to put this comment: http://apidock.com/ruby/String/%25#726-Use-it-with-HAML
Use it with HAML
Like Henrik pointed out <a href=“http://henrik.nyh.se/2008/01/surround-helper-alternative-in-haml”>in his blogpost, this method is particulary useful when using HAML (http://haml-lang.com/) in Rails.
Instead of usind the HAML-Helper ‘surround’ (etc) you can just write
= "(%s)" % link_to("Edit", ...)
Or with two Arguments:
= "(%s, %s)" % ["Edit", "Delete"]
Thanks very much, Henrik!
Shortcut
According to http://henrik.nyh.se/2008/01/surround-helper-alternative-in-haml there is a short version for sprintf:
“(%s)” % “foo” is the same as sprintf(“(%s)”, “foo”)
Can someone who knows write more about this here? How do I work with multiple strings? Is this even possible? “(%s %t)” % “foo”, “bar” does not work.
extend adds class methods too
Because classes are objects. So for example:
module Ispeak def says "greetings aliens!" end end module Ieat def eats "spinach" end end module Inhabitant def says "I'm strong to the finish" end end class Human extend Ispeak # add class methods from Ispeak include Inhabitant # add instance methods from Inhabitant end Human.extend Ieat # add class methods from Ieat puts Human.says # -> greetings aliens! puts Human.eats # -> spinach popeye = Human.new puts popeye.says # -> I'm strong to the finish