A Foolish Manifesto

fREWdiculous!

Archive for the ‘Ruby’ Category

Ruby 1.9 is out!

Exciting! It was apparently put up yesterday, on Christmas. What a cool gift right? I looked through the changed maintained my Mauricio and here are /my/ favorites.

New literal hash syntax [Ruby2]

{a: "foo"}    # => {:a=>"foo"}

.() and calling Procs without #call/#[] [EXPERIMENTAL]

You can now do:

a = lambda{|*b| b} a.(1,2) # => [1, 2]

Multiple splats allowed

1.9 allows multiple splat operators when calling a method:

def foo(*a)
     a
   end

   foo(1, *[2,3], 4, *[5,6])                        # => [1, 2, 3, 4, 5, 6]

Mandatory arguments after optional arguments allowed

def m(a, b=nil, *c, d)
     [a,b,c,d]
   end
   m(1,2)                                         # => [1, nil, [], 2]

Object#tap

Passes the object to the block and returns it (meant to be used for call chaining).

"F".tap{|x| x.upcase!}[0] # => "F" # Note that "F".upcase![0] would fail since upcase! would return nil in this # case.

Module#attr is an alias of attr_reader

Use

attr :foo=

to create a read/write accessor. (RCR#331)

Enumerable#cycle

Calls the given block for each element of the enumerable in a never-ending cycle:

a = ["a", "b", "c"]
a.cycle {|x| puts x }  # print, a, b, c, a, b, c,.. forever.

Enumerable#group_by

Groups the values in the enumerable according to the value returned by the block:

(1..10).group_by{|x| x % 3} # => {0=>[3, 6, 9], 1=>[1, 4, 7, 10], 2=>[2, 5, 8]}

Enumerable#drop

Without a block, returns an array with all but the first n elements from the enumeration. Otherwise drops elements while the block returns true (and returns all the elements after it returns a false value):

a = [1, 2, 3, 4, 5] a.drop(3) # => [4, 5]
a.drop {|i| i < 3 } # => [3, 4, 5]

Enumerable#inject (#reduce) without a block

If no block is given, the first argument to #inject is the name of a two-argument method that will be called; the optional second argument is the initial value:

[RUBY_VERSION, RUBY_RELEASE_DATE] # => ["1.9.0", "2007-08-03"] (1..10).reduce(:+) # => 55

Enumerable#count

It could be defined in Ruby as

def count(*a) inject(0) do |c, e| if a.size == 1 # suspect, but this is how it works (a[0] == e) ? c + 1 : c else yield(e) ? c + 1 : c end end end

Therefore

["bar", 1, "foo", 2].count(1) # => 1 ["bar", 1, "foo", 2].count{|x| x.to_i != 0} # => 2

Array#nitems

It is equivalent to selecting the elements that satisfy a condition and obtaining the size of the resulting array:

%w[1 2 3 4 5 6].nitems{|x| x.to_i > 3}    # => 3

Block argument to Array#index, Array#rindex [Ruby2]

They can now take a block to make them work like #select.

['a','b','c'].index{|e| e == 'b'} # => 1 ['a','b','c'].index{|e| e == 'c'} # => 2 ['a','a','a'].rindex{|e| e == 'a'} # => 2 ['a','a','a'].index{|e| e == 'b'} # => nil

Array#combination

ary.combination(n){|c| ...}

yields all the combinations of length n of the elements in the array to the given block. If no block is passed, it returns an enumerator instead. The order of the combinations is unspecified.

a = [1, 2, 3, 4] a.combination(1).to_a #=> [[1],[2],[3],[4]] a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]] a.combination(4).to_a #=> [[1,2,3,4]] a.combination(0).to_a #=> [[]]: one combination of length 0 a.combination(5).to_a #=> [] : no combinations of length 5

Array#permutation

Operates like #combination, but with permutations of length n.
<code lang="ruby">a = [1, 2, 3] a.permutation(1).to_a #=> [[1],[2],[3]] a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] a.permutation(0).to_a #=> [[]]: one permutation of length 0 a.permutation(4).to_a #=> [] : no permutations of length 4

Array#pop, Array#shift

They can take an argument to specify how many objects to return:

%w[a b c d].pop(2) # => ["c", "d"]

Hash preserves order!

RUBY_VERSION                    # => "1.9.0"
h={:a=>1, :b=>2, :c=>3, :d=>4}  # => {:a=>1, :b=>2, :c=>3, :d=>4}
h[:e]=5
h                                           # => {:a=>1, :b=>2, :c=>3, :d=>4, :e=>5}

h.keys                                      # => [:a, :b, :c, :d, :e]
h.values                                    # => [1, 2, 3, 4, 5]
h.to_a                                      # => [[:a, 1], [:b, 2], [:c, 3], [:d, 4], [:e, 5]]

vs.

RUBY_VERSION                    # => "1.8.6"
h={:a=>1, :b=>2, :c=>3, :d=>4}  # => {:a=>1, :b=>2, :c=>3, :d=>4}
h[:e]=5
h                                           # => {:e=>5, :a=>1, :b=>2, :c=>3, :d=>4}
h.keys                                      # => [:e, :a, :b, :c, :d]
h.values                                    # => [5, 1, 2, 3, 4]
h.to_a                                      # => [[:e, 5], [:a, 1], [:b, 2], [:c, 3], [:d, 4]]

Numeric#upto, #downto, #times, #step

These methods return an enumerator if no block is given:

a = 10.times a.inject{|s,x| s+x } # => 45 a = [] b = 10.downto(5) b.each{|x| a << x} a # => [10, 9, 8, 7, 6, 5]

Range#cover?

range.cover?(value)

compares value to the begin and end values of the range, returning true if it is comprised between them, honoring #exclude_end?.

("a".."z").cover?("c")                            # => true
("a".."z").cover?("5")                            # => false

Limit input in IO#gets, IO#readline, IO#readlines, IO#each_line, IO#lines, IO.foreach, IO.readlines, StringIO#gets, StringIO#readline, StringIO#each, StringIO#readlines

These methods accept an optional integer argument to specify the maximum amount of data to be read. The limit is specified either as the (optional) second argument, or by passing a single integer argument (i.e. the first argument is interpreted as the limit if it’s an integer, as a line separator otherwise).

IO#ungetc, StringIO#ungetc

Allows to push back an arbitrarily large character.

Seven predicate methods where added for the weekdays:

Time.now        # => Thu Nov 03 18:58:25 CET 2005
Time.now.sunday?        # => false
  • 2 Comments
  • Filed under: Ruby
  • Friday Tips and Tricks

    Time saving tips and tricks!

    This first tip is something that I use almost daily. Do you ever want to change a filename to something that is similar to the original name? For instance, maybe you just want to change/add/remove the extension? Well, if you are using a reasonable shell you can do the following:

    # Add .txt to the filename
    cp textfiel{,.txt}
    # change el to le
    cp textfi{el,le}.txt
    # remove extension
    cp textfile{.txt,}

    Or how about this; fairly often I will be programming and I will be adding a predefined string to the end of another string a bunch of times, except for the last time. The idea is to put the predefined string between some other things. This is pretty regular if you are generating HTML or SQL. Well, instead of doing the following:

    output = ""
    some_array.each_with_index do |item,index|
    output += item
    output += " AND " unless index = some_array.length - 1
    end

    you can do:

    output = some_array.join(" AND ")

    Another thing that I find myself doing often is the following:

    output=""
    some_array.each_with_index do |item,index|
    output += "?"
    output += "," unless index=some_array.length-1
    end

    That will generate the question marks for an SQL statement. Again, that’s a little messy and there is a cleaner way to do it.

    output = some_array.map{"?"}.join(",")

    Much better! It’s much shorter and should be easier to understand for other Ruby programmers.

    It’s good to put things like this into practice, because it will make your code more readable and easier to maintain. Generally, in my manifesto, fewer lines of code (comments and whitespace don’t count) are better. Of course, in a language like Ruby this can create performance problems; it’s a balance between what works for you as the programmer and what works for the user. If the speed is really an issue, change the code. Otherwise, save your skull!

    If you have any tips for regular things like this, let me know. I need to know stuff like this just as much as anyone else.

  • 0 Comments
  • Filed under: Unix, Ruby, Shell