Ruby als lijm

Geplaatst door Michiel de Mare do, 01 jun 2006 08:12:00 GMT

Ruby is natuurlijk een prachtige object-georienteerde taal waar je de mooiste domain-specific languages mee kunt maken. Maar soms heb je gewoon een scriptingtaal nodig, en daar dient Ruby ook prima voor.

Een collega vroeg of iemand een tooltje kende om een serialVersionUID toe te voegen aan alle java-classes in een project die er nog niet een hebben. Java gebruikt deze ids om te kijken of een geserializeerd object dezelfde versie heeft als de class. Mijn collega dacht aan een Eclipse-plugin – ik dacht aan Ruby.

Het zou eenvoudig zijn om een programmaatje helemaal in Ruby te schrijven die dit voor je doet – maar dat zou toch nog teveel werk zijn. Beter is het om de unix-shell voor je te laten werken.

Eerst heb je alle filenamen nodig van java-files binnen een directory-boom die geen serialVersionUID bevatten. Daar komt grep van pas.

grep print standaard alle regels uit die matchen met de zoekstring. Met de -l parameter print het alleen de filenaam uit van een match – met de -L parameter alleen de filenamen die niet matchen. Verder zoeken we recursief (met de -R parameter), dus moeten we een file-pattern opgeven.

In Ruby voer je een shell-commando uit door er backquotes omheen te zetten. Het resultaat is de output van het commando, als string.
fnames = `grep -LR --include=*.java serialVersionUID *`

Vervolgens hebben we een commando nodig dat een regel met de uid genereert.

uid_maker = proc do
  "private static long serialVersionUID = #{rand(2**63)};" 
end

Verder moeten we de files editen. Daar gebruiken we een editor voor, en wel eentje die we vanuit de command-line kunnen aansturen: Vim! We geven (met de -c parameter) drie commando’s mee aan Vim. Eerst zoeken we naar de regel waar “public class” in voorkomt, dan naar de regel (inclusief de huidige) waar de accolade staat.

In het tweede Vim-commando switchen we naar de normal mode. Dan voegen we een nieuwe lege regel toe (met o) onder de huidige regel, en voegen we de tekst toe.

In het derde Vim-commando schrijven we de file weg, en sluiten we Vim.

cmd = proc do |filename|
  `vim -c "/public class/-1;/{" -c "normal o #{uid_maker.call}" -c wq #{filename}`
end

Tenslotte maken we van elke regel in de string met filenamen een array-element, en voeren we ons commando uit op elke gevonden file.

fnames.split.each &cmd

Met slechts kennis van vier hulpmiddelen(Ruby, unix, Vim, en reguliere expressies) hebben we in acht regels een nuttig tooltje geschreven dat onze Java-collega’s een hoop werk kan besparen. En hoe handiger je bent met deze vier gereedschappen, hoe meer mogelijkheden je zult zien om je collega’s (en jezelf!) nog meer werk te besparen.

Geplaatst in  | 4 reacties

Reacties

  1. Matthijs Langenberg zei ongeveer 1 uur later:

    Leuk dat je hier Ruby voor gebruikt heb Michiel, ik zou het zelf bij bash gehouden hebben, en pas bij complexere structuren Ruby gebruikt hebben.

  2. Danny zei ongeveer 2 uur later:

    Voor zoiets zou ik zelf een macro in jEdit schrijven. Ook wel handig als je niet onder Unix werkt.

  3. Danny zei ongeveer 3 uur later:

    Maar het zit natuurlijk gewoon al standaard ingebakken in Eclipse (Eclipse rocks!). Kijk in de Problems view; daar zie je als het goed is warnings met de tekst “The serializable class XYZ does not declare a static final serialVersionUID field of type long”. Rechterklik op een van die warnings en kies Quick Fix. Kies vervolgens in het Quick Fix window ‘Add generated serial version ID’ en klik op de button ‘Add Matching Problems’ en daarna op ‘Select All’ en dan op OK.

  4. Erik van Oosten zei 15 dagen later:

    Naast dat ik vind dat je alleen serialVersionUID moet toevoegen aan classes die je wilt serializeren, heeft het ook weinig zin een serialVersionUID aan classes toe te voegen die helemaal niet serializeerbaar zijn. En dat laatste doet je voorstel niet. Het is ook vrij lastig omdat een class best een interface kan implementeren die Serializable uitbreid.

    Maar goed, te veel Java voor een Ruby blog :)

(Laat url/e-mail achter »)

   Voorvertoning