jweir / elmish

Ruby inspired by Elm

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

elmish

Ruby Inspired by Elm

Ruby lets you do the silliest of things.

This began solving a real problem – I needed a workflow which could handle several different branches, including retries. And I wanted code that was easy to comprehend. (@jessitron sums up Ruby as easy to write and hard to reason about. The solution was a long case statement method which took a message and a state and returned a new message and updated state. This was inspired by Elm's update pattern.

def run
  action, state = init

  loop do
     action, state = update(action, state)
     break if action == :exit
  end

  [action, state]
end

def update(msg, state)
  case msg
  when :start then
     state.download = fetch
     [:validate, state]
  when :validate then
     if waiting(state.download) 
        sleep 1.minute
        [:start, state]
     else
        [:write, state]
     end

What is nice is a process can be restarted at any point. It is easy to see the general sequence of events. Like Elm's update adding a new action is not too difficult.

What I didn't like about this was using symbols. What if constants could be used instead?

Elmish was born.

module Counter
  extend Elmish

  Actions %w|
    Noop
    Inc
    IncN/Fixnum  # this creates a union type that accepts Fixnums
    Dec
    DecN/Fixnum
  |

  def self.init
    [Noop, 0]
  end

  # msg is an Action
  # state is whatever state object you want
  def self.update(msg, state)
    case msg
    when Inc then
      [Noop, state + 1]
    when IncN then
      [Noop, state + msg.value]
    when Dec then
      [Noop, state - 1]
    when DecN then
      [Noop, state - msg.value]
    else
      raise "hell"
    end
  end
end

_, state = Counter.init
#=>  [Counter::Noop, 0]

_, state = Counter.update Workflow::Inc, state
#=>  [Counter::Noop, 1]

# Look a Union type with a value of 3
_, state = Counter.update (Workflow::IncN 3), state
#=>  [Counter::Noop, 4]

# runtime type checking is better than no type checking? Maybe? 
_, state = Counter.update (Workflow::IncN 'string?'), state
#=> Elmish::Union::TypeMismatch: [String, Fixnum]

This is terrible and unncessary. It probably creates more problems than it solves, but it was a fun excerise.

I'm not using this in production, but if I do, I will update this code with a gem or something.

About

Ruby inspired by Elm


Languages

Language:Ruby 100.0%