Hi,
I’m trying to build a little internal DSL to create mini Sinatra
applications for little fakers to test stuff. I want the DSL to be
something like this:
post ‘/example’ do
content_type application/json
status 200
body transaction_status: billed, subscriber_id: asdfasdfasdf,
status: ack, trid: 123412341234
end
Things of note:
1.- I want to be able to pass a Hash as body, and to have it
transparently formatted for the appropriate content type. The default
content type will be application/www-form-urlencoded.
2.- I’d rather not have to put quotes around all strings, so I’ve
tried some method missing magic. The above example works, so, as you
can see, things like application/json, billed, etc don’t need quotes.
I even got this working:
body o-something => other.thing
but there are some things I can’t manage. For example the ‘/example’,
or things like
body o-something: otherthing
I also support passing any valid object to body to be returned (like a
string or any valid Sinatra return value). I only format Hashes.
I’m pasting here my current implementation to see if something can be
improved, or you have any advice on how to better approach this:
require ‘sinatra/base’
require ‘json’
FORMATTERS = {
“application/www-form-urlencoded” => lambda {|b| b.each.map {|k,v|
“#{CGI.escape(k)}=#{CGI.escape(v)}” }.join("&")},
“application/json” => lambda {|b| b.to_json}
}
class Stringy
def initialize o
@o = o
end
# this looks like black magic, and I wonder if in 6 months I'll be
able to understand this
def method_missing meth, *args, &blk
prefix = args.empty? ? “.” : “”
Stringy.new("#{@o.to_s}#{prefix}#{meth}#{args.first.to_s}")
end
def to_s
@o.to_s
end
end
class MyApp < Sinatra::Base
def method_missing meth, *args, &blk
Stringy.new(meth)
end
def stringifyKeysAndValues h
Hash[*h.map{|k,v| [k.to_s, v.to_s]}.flatten]
end
before do
content_type "application/www-form-urlencoded" # default, can
be overriden in the routes
end
after do
if Hash === body
body
FORMATTERS[response.content_type][stringifyKeysAndValues body]
end
end
end
MyApp.instance_eval(File.read(ARGV[0]))
MyApp.run!
Any comment is appreciated.
Jesus.