Sinatra Trick for Single File, Databaseless State Across EventContexts
Okay, caveat time. This might not be a trick. In fact, it might be dangerous or stupid. I am not talented enough to know. However, under the assumption that “taking some time and effort to do something sneaky” could translate into re-usable knowledge, I’ll stick my reputation on the line that this could help another human being (or bad ass Turing machine).
Background: I’m using Sinatra to build a REST API for a project on which I am working. There are actually a few loosely-coupled servers that perform different functions. One server manages Trades between users of the system. There is no database behind the trades because a trade only exists in the running context and affects only the holdings of each user IF they actually complete a trade within the context. So, I wanted my trade server, which is a Sinatra application, to include the trading classes which effectively maintain a hash in memory for pending trades until they are completed.
Here’s the Sinatra app (abbreviated):
set :port, 5555
set :trades, Trades.create
### API ###
get '/list/:key' do
puts Sinatra.application.options.trades.find(@key).to_json
end
Dirty, sneaky and fun. We’re using Sinatra’s options to store a newly created instance of the class that manages the trades hash. For some reason (told you I wasn’t a brilliant hacker), you cannot instantiate the Trades class using the new operator in the option setting method. So, how do we get around that?
class Trades
private_class_method :new
@@trades = {}
public
def Trades.create
@@trades
end
def find(key)
@@trades[key]
end
def add(trade)
@@trades.store(trade.key, trade)
end
def remove(key)
@@trades.delete(key)
end
end
You guessed it. Or read it above. Or both. That’s a hand-rolled Singleton. And Blake would be happy that it all works in one file. And I’d be happy if you know any tricks to make this even more terse.