25 februari: amsterdam.rb

Geplaatst door Michiel de Mare di, 19 feb 2008 14:38:50 GMT

De laatste maandag van de maand komt eraan, dus vindt op 25 februari de tweede bijeenkomst van amsterdam.rb plaats! De vorige keer was een groot succes met een flinke opkomst. We houden het deze keer weer op dezelfde lokatie: de Bekeerde Suster aan de Nieuwmarkt, vanaf een uur of acht.

Voor vragen (of om te zien wie er vorige keer gekomen zijn) is er een Google Group ter coördinatie: amsterdam-rb

Tot maandag!

Geplaatst in , ,  | geen reacties

Our Daily Method #11: Hash#inv_multi

Geplaatst door Michiel de Mare di, 19 feb 2008 08:00:00 GMT

Hash has an invert-method, but it often happens that you’re dealing with a hash with arrays as values. Naturally, you don’t want arrays as keys – you want every element in the array to turn into a key, with an array of all original keys with that element as the value.

Simple example


{1 => [3,4]}.inv_multi
# => {3=>[1], 4=>[1]}

Complex example


{1 => [3,4,5,6], 2 => [3,4], 4 => 11}.inv_multi
# => {5=>[1], 11=>[4], 6=>[1], 3=>[1, 2], 4=>[1, 2]}
The method itself:

class Hash
  def inv_multi
    # there's inject! again. daily method #5
    inject!({}) do |h,(k,v)|  # Is this obvious? If not, say so!
      # this lambda binds h and k.
      l = lambda {|x| (h[x] ||= []) << k}
      if Array === v
        v.each(&l)
      else # value doesn't have to be an array
        l[v]
      end
    end
  end
end

Geplaatst in , ,  | geen reacties

Onze dagmethode #11: Hash#inv_multi

Geplaatst door Michiel de Mare di, 19 feb 2008 08:00:00 GMT

Hash heeft een invert-methode, maar vaak heb je een hash die als values arrays heeft. Je wilt natuurlijk geen arrays als keys, maar juist dat elk element in de array een key wordt met als value een array met alle oorspronkelijke keys.

Simpel voorbeeld


{1 => [3,4]}.inv_multi
# => {3=>[1], 4=>[1]}

Complex voorbeeld


{1 => [3,4,5,6], 2 => [3,4], 4 => 11}.inv_multi
# => {5=>[1], 11=>[4], 6=>[1], 3=>[1, 2], 4=>[1, 2]}
De methode:

class Hash
  def inv_multi
    # there's inject! again. daily method #5
    inject!({}) do |h,(k,v)|  # Is this obvious? If not, say so!
      # this lambda binds h and k.
      l = lambda {|x| (h[x] ||= []) << k}
      # value doesn't have to be an array
      Array === v ? v.each(&l) : l[v]
    end
  end
end

Geplaatst in ,  | geen reacties

Onze dagmethode #10: Object#r[rs][ds]s

Geplaatst door Michiel de Mare ma, 18 feb 2008 08:00:00 GMT

Ruby 1.9 heeft Object#tap. Lang geleden introduceerde DannyObject#with. Dan is er nog Object#instance_eval.

Hebben deze methodes iets gemeen behalve hun raadselachtige namen?

Het blijkt van wel.Deze methoden vallen in de familie methoden die:
  1. Voor elk Object gedefinieerd zijn.
  2. Een block nemen en dat altijd éénmaal uitvoeren
  3. Niets anders doen

Misschien verbaast het je dat er maar liefst drie methoden in deze categorie zijn. En er is zelfs nog een vierde!

Want zelfs binnen deze strenge specificaties zijn er nog een paar openstaande punten:
  1. Wat retourneren we? Het object zelf? Of het resultaat van het block?
  2. Binnen het block, wat is self? Is het het object? Of is het onveranderd (waardoor we het object als argument moeten meegeven)?
Hoe zit dat voor de methoden die we net hebben genoemd?
  • tap: retourneert resultaat, zelfde self in block
  • with: retourneert self, zelfde self in block
  • instance_eval: retourneert resultaat, andere self in block.
En de ontbrekende methode:
  • switch: retourneert self, andere self in block.

Laten we deze methoden in actie zien!

Lees verder...

Geplaatst in ,  | geen reacties

Our Daily Method #10: Object#r[rs][ds]s

Geplaatst door Michiel de Mare ma, 18 feb 2008 08:00:00 GMT

Ruby 1.9 has Object#tap. Danny introduced Object#with a long time ago. Then there’s Object#instance_eval.

Do these methods have anything in common, except for the inscrutability of their names?

It turns out that they do. These methods fall in the family of methods that:
  1. Are defined for any Object
  2. Take a block and always execute it once
  3. Don’t do anything else

So it may seem amazing that there are as much as three methods in this category. Actually, there’s even a fourth!

You see, even within these strict specs there are two decisions that we have to take.
  1. What do we return? The object itself? Or the result of the block?
  2. Within the block, what is self? Is it the object? Or is it unchanged (so we need to pass on the object as an argument)?
How do the methods we referred to earlier stack up?
  • tap: returns result, same self in block
  • with: return self, same self in block
  • instance_eval: returns result, different self in block.
And the Missing Method:
  • switch: returns self, different self in block.

Let’s see these methods in action!

Lees verder...

Geplaatst in , ,  | geen reacties

Our Daily Method #9: String#+@

Geplaatst door Michiel de Mare vr, 15 feb 2008 08:00:00 GMT

It’s Friday so we’ll keep it short.


[String,Symbol].each{|c|c.class_eval {alias +@ to_sym}}

Is it a Symbol? Is it a String? Who gives a damn!


hash[+key]

Geplaatst in , ,  | geen reacties

Onze dagmethode #9: String#+@

Geplaatst door Michiel de Mare vr, 15 feb 2008 08:00:00 GMT

Het is vrijdag dus we houden het kort.


[String,Symbol].each{|c|c.class_eval {alias +@ to_sym}}

Is het een Symbol? Is het een String? Who gives a damn!


hash[+key]

Geplaatst in ,  | 2 reacties

Onze dagmethode #8: Object.alias_class_method

Geplaatst door Remco van 't Veer do, 14 feb 2008 08:00:00 GMT

In een eerdere dagmethode wordt een alias gemaakt voor een class methode. Dat is een beetje lastig omdat de Module#alias_method eigenlijk alleen opereert op instance methoden. Gelukkig is een class niet meer dan een instance van Class en kunnen we dus die instance gebruiken om alias_method op uit te voeren.

Een bekende methode om een object instance uit te breiden is met de class<< notatie. Hiermee kan je een object voorzien van een singleton/eigen/virtual/meta-class welke je kan voorzien van methoden voor die specifieke instancie. Omdat binnen een class definitie self verwijst naar de class instance van deze definitie kunnen we het volgende schrijven:


class Foo
  class << self
    alias_method :neu, :new
  end
end

Deze Foo class kunnen we nu instanceren met neu (merk op dat new gewoon een class methode is). Omdat de class<< notitie binnen een class een beetje een rommelige indruk wekt, gebruik ik liever de volgende uitbreiding op Object:


class Object
  def self.alias_class_method(new_name, old_name)
    meta = class << self; self; end
    meta.send :alias_method, new_name, old_name
  end
end

Hiermee kan je schrijven:


class Foo
  alias_class_method :neu, :new
end

Zie voor mee informatie over eigenclasses de discussie tussen Nutter en Lam op Ruby-core.

Geplaatst in ,  | geen reacties

Our Daily Method #8: Object.alias_class_method

Geplaatst door Remco van 't Veer do, 14 feb 2008 08:00:00 GMT

In an earlier daily method an alias is created for a class method. This is a bit tricky since the Module#alias_method method only operates in instance methodes. Fortunately a class is an instance of Class so we can use that instance as a context to use alias_method.

To extend an object instance we use the class<< notation. This adds a singleton/eigen/virtual/meta-class to the given instance which you can use to add methodes. Inside a class definition the self object points to the instance of the class begin defined. This allows us the do the following:


class Foo
  class << self
    alias_method :neu, :new
  end
end

This Foo class can now be instanciated using neu (note, new is just a class method). But this class<< stuff inside a class is a bit messy. I prefer using the following extension to Object:


class Object
  def self.alias_class_method(new_name, old_name)
    meta = class << self; self; end
    meta.send :alias_method, new_name, old_name
  end
end

Now we can write:


class Foo
  alias_class_method :neu, :new
end

For more information about eigenclasses see the discussion Nutter and Lam had on Ruby-core.

Geplaatst in , ,  | geen reacties

Onze dagmethode #7: Enumerable#mjoin

Geplaatst door Michiel de Mare wo, 13 feb 2008 08:00:00 GMT

Jullie kennen natuurlijk flatten. flatten neemt een array en walst hem plat. Na afloop bevat de array alleen nog niet-arrays. Maar soms heb je een array van arrays van arrays en wil je hem in een array van arrays omtoveren. Wat we nodig hebben is flatten-light: mjoin

module Enumerable
  def mjoin
    inject!([]) {|memo,x| a.each {|x| memo << x}}
  end
end
(lees meer over inject!).

Wanneer heb je dit nodig? Altijd als je map wilt gebruiken maar je wilt niet elke keer precies één waarde teruggeven. en daarnaast sommige waardes in de array zelf arrays zijn, waardoor flatten afvalt.

Klinkt dat uitermate zeldzaam? In feite is dit anders een doodnormale datastructuur. Een tabel is een array van arrays, en een join is een operatie die per row nul of meer resultaten teruggeeft. En vandaar ook de naam! (join is natuurlijk al bezet – mjoin was geïnspireerd door dit artikel).

Binnenkort meer over tabellen als datastructuur in Ruby.

Geplaatst in ,  | 1 reactie

Oudere artikelen: 1 2 3 4 5 6 ... 12