State Machine DSL revamp

I min forrige blogpost gikk jeg gjennom hvordan jeg laget en enkel tilstandsmaskin i Ruby. Jeg har tenkt litt mer på den, og her kommer en liten forbedring..

Orginalt la jeg til rette for to ulike måter å konfigurere tilstandsmaskinen på. Først lagde jeg en enkel add_transition metode som jeg kunne kalle slik som dette:

   9         @state_machine.add_transition(:locked, :coin, :unlocked) { @unlock_called = true }

Ulempen med denne er at den ikke kommuniserer så godt – god kode skrevet for mennesker bør kommunisere mer enn det der. Jeg lagde derfor et flytende grensesnitt, ala det jeg tidligere hadde laget i C#.

   72         @state_machine.configure do |sm|

   73             sm.given(:locked).when(:coin).then_set_state(:unlocked).and_run { @unlock_called = true }

   74             sm.given(:locked).when(:pass).then_set_state(:locked).and_run { @alarm_called = true }

   75             sm.given(:unlocked).when(:coin).then_set_state(:unlocked).and_run { @thank_you_called = true }

   76             sm.given(:unlocked).when(:pass).then_set_state(:locked).and_run { @lock_action_called = true }

   77         end

Etter å ha tenkt meg litt om har jeg kommet opp med et grensesnitt jeg liker bedre. Det ligner mer på andre ting jeg har sett i Ruby, og er på en form som Rubyister gjerne refererer til som DSL-metoder. Ved å bruke en Hash (dotnet’ere kan kalle dette Dictionary) som parameter kommuniserer koden enda bedre. Det blir litt mer tekst å skrive, men på den andre siden er det også mere fleksibelt (om man f.eks. vil legge til flere parametre). Det nye grensesnittet brukes på denne måten:

   137         @state_machine.transition :if_state_is => :locked,  

   138             :when_event => :coin, :then_set_state => :unlocked do

   139             @unlock_called = true

   140         end

   141         @state_machine.transition :if_state_is => :locked,  

   142             :when_event => :pass, :then_set_state => :locked do

   143             @alarm_called = true

   144         end

   145         @state_machine.transition :if_state_is => :unlocked,  

   146             :when_event => :coin, :then_set_state => :unlocked do

   147             @thank_you_called = true

   148         end

   149         @state_machine.transition :if_state_is => :unlocked,  

   150             :when_event => :pass, :then_set_state => :locked do

   151             @lock_action_called = true

   152         end

Mellom ‘do’ og ‘end’ putter man selvsagt all koden som skal trigges av tilstandsendringen – på samme måte som man kunne gjøre mellom { og } i de foregående eksemplene (dette er to ulike måter å gjøre det samme på i Ruby, hvor klammene normalt brukes når kodeblokken er på samme linje som metodekallet, og bare inneholder én statement.

Selve transition-metoden er enkel å implementere. Den plukker ut verdiene fra Hash’en og sender dem til den tidligere definerte add_transition-metoden.

   185 class GenericStateMachine #open class definition to add another dsl method

   186     def transition args, &and_run

   187         add_transition args[:if_state_is], args[:when_event], args[:then_set_state], &and_run

   188     end

   189 end

Kategorier: Ruby.
RSS feed for kommentarene. Tilbaketråkk.

Skriv en kommentar

Torbjørn Marø

Torbjørn er systemutvikler og et aktivt medlem av .NET-miljøet i Bergen. Dette er hans blog.

Mulig relaterte linker

Siste kommentarer


Torbjørn: Kan alltid stole på at Ameth kommer med en fungerende løsn...

Ameth: Enumerable.Range(1, 11).Select(i => (Math.Pow(1+Math.Sqrt...

Torbjørn: Ja, Linq og lambda i C# har mange bruksområder, og gir komp...

Kenneth: Innså til slutt at å produsere fibonacci-følgen med en sl...

Kenneth: Dette er ikke relatert til verken mønstergjenkjenning eller...

Torbjørn: Note to self: I Clojure heter denne funksjonen mapcat...

Torbjørn: Nei, vi bruker ikke Clojure, og inntil videre lærer jeg meg...

 Hold deg oppdatert

Søk i bloggen

  • Follow me on Spotify

    Kategorier

  • .net ninja (26)
  • Bøker (10)
  • Diverse prosjekter (22)
  • Erlang (7)
  • F# (2)
  • Hardware (1)
  • Jobb (64)
  • kjempekjekt.com (16)
  • LISP/Clojure (11)
  • NNUG / community (39)
  • O/RM & databaser (9)
  • Off topic (111)
  • OO-design/clean code (19)
  • Podcasts (10)
  • Polyglot (23)
  • Ruby (18)
  • Silverlight / RIA (3)
  • Software/verktøy (16)
  • Softwareutvikling (14)
  • Testing / TDD (25)
  • the contiki strip (13)
  • User experience (3)
  • WCF (3)
  • Webutvikling (20)
  • WPF (9)
  • WTF (4)
  • Abonner via epost

    Om du vil kan du få alle nye blogposter tilsendt til din epost. Abonner nå, det er kjempeenkelt!

    Mine bokmerker

    Meta