Arc Forumnew | comments | leaders | submitlogin
10 points by emmett 6170 days ago | link | parent

Typically, you'd never write the program that way in Ruby. All the popular ruby web frameworks are not continuation or closure based. Instead, you'd keep the state in memory on the server, tied to the session. You'd also use three templates, one per page. In Rails:

  def said
    if request.method == :post
      session[:said] = params[:said]
      render :action => "clickhere"
    else
      render :action => "result" if session[:said]
    end
  end

  default template said.rhtml:
  <% form_tag do %><%= text_field_tag "said", "" %><%= submit_tag %><% end %>

  clickhere.rhtml:
  <%= link_to "click here", "" %>
  
  result.rhtml:
  You said <%= session[:said] %>

But now that you mention it, ruby has callcc...let me see what that implies...


9 points by brett 6170 days ago | link

you don't really need callcc as much as just storing proc closures

here's a ruby version a bit closer to the original. there's a bunch of support and then process roughly corresponds to said above

  #!/usr/bin/env ruby
  require 'rubygems'
  require 'mongrel'

  class FooHandler < Mongrel::HttpHandler
  
    def initialize
      @fnids = {}
      @c = 0
    end
  
    def new_fnid(proc)
      @c += 1
      @fnids[@c] = proc
      @c
    end
  
    def query_params(request)
      request.class.query_parse(request.params['QUERY_STRING'])
    end
  
    def pr(response, html)    
      response.start do |head,out|
        head["Content-Type"] = "text/html"
        out << html
      end
    end
  
    def w_link(response, link_text, &block)
      c = new_fnid(block)
      pr(response, "<a href='?fnid=#{c}'>#{link_text}</a>")
    end
  
    def aform(response, form_html, &block)
      c = new_fnid(block)
      pr(response, "<form><input type='hidden' name='fnid' value='#{c}'>#{form_html}</form>")
    end
  
    def process(request, response)
      if (fnid = query_params(request)['fnid'])
        @fnids[fnid.to_i].call(request, response)
      else
        aform(response, "<input name='foo'><input type='submit'>") do |req1, resp1|
          w_link(resp1, "click here") do |req2, resp2|
            pr(resp2, "you said: " + query_params(req1)['foo'])
          end
        end
      end
    end
  end

  Mongrel::Configurator.new :port => 8080 do
    listener {uri "/", :handler => FooHandler.new}
    trap("INT") {stop}
    run
  end.join

-----

3 points by s3graham 6170 days ago | link

Neat, thanks. (Not quite "right" since I can change &foo=myinput on page 2, but I'm guessing that could easily be fixed with an extra closure somewhere).

-----

3 points by lojic 6169 days ago | link

You can use request.post? instead of request.method == :post if you like.

-----

2 points by saharrison 6169 days ago | link

Ruby's callcc is not a true continuation -- you can't store the state of the continuation.

-----

1 point by pc 6166 days ago | link

Huh?

-----

1 point by simen 6163 days ago | link

Ruby's continuations can't be serialized. That does not make them any less true continuations, though.

-----