kenichi / angelo

Sinatra-like DSL for Reel that supports WebSockets and SSE
Other
303 stars 23 forks source link

Multiple before and after blocks #3

Closed samjohnduke closed 10 years ago

samjohnduke commented 10 years ago

Just want to say first that I love this little framework, I've used celluloid as library before and this just really makes sense.

I'm building a little messaging app and I have created a few components like sessions and authentication, the problem is when I extracted them into a library I had no way to set them up before and after each request.

Because there is no rack and therefore no middleware I couldn't think of a way to wrap a request apart from before and after. I had a look at adding filters like sinatra has but I couldn't get the context for running the filter blocks right.

Maybe there is another way?

kenichi commented 10 years ago

@samjohnduke thanks! i'm glad you like it :smiley_cat:

i've got a basic (very) start on more sinatra-like filters going on the 'filters' branch. please have a look:

https://github.com/kenichi/angelo/compare/filters

this is mostly a spike solution, but it does work... you can do something like this:

class FilterTest < Angelo::Base
  before '/secret_area' do
     # authenticate!
  end
  get '/' do
     erb :index
  end
  get '/secret_area' do
     erb :authed_user
  end
end

thoughts? also, i'm interested in your "components like sessions". can you provide some examples of that?

samjohnduke commented 10 years ago

Ah. That's a really cool way to program. Not seen anything like that in ruby before. It looks exactly like what I was after.

For context the components are similar to how you implemented the erb module. You include the module, it calls a registered method with the base context and then you add the necessary components onto the base.

module Session 
  def self.included? base
    registered base
  end

  def registered app
    app.before do
       init_session request
    end

    app.after do
      finalize_session
    end
  end

  def init_session request
    @session_key = fetch_session_key(request)
    @session = SessionStore.new  
  end

  ...

end

As far as I can tell it's basically the same as sinatra without Angelo::Base having the register function call. It is a little less clean this way but it works. (except that it doesn't if you want to declare another before or after block elsewhere)

I'll extract the whole session gem and push it to git hub so it's available, but the codes not the greatest.

samjohnduke commented 10 years ago

Here is the sessions gem I extracted - Angelo Sessions

kenichi commented 10 years ago

@samjohnduke thanks! i will be looking further over the weekend...

kenichi commented 10 years ago

@samjohnduke i added pattern matching in filters when using mustermann. from the branch, you can now do:

include Angelo::Mustermann

before '/user/:user_id/:relation' do
  # access params[:user_id] and params[:relation] here
end

get '/user/:id/things' do
  # params keys from before block are not accessible here
  # params[:user_id] will be nil, but params[:id] will not be
end

This is how Sinatra behaves and it seems legit to me.

Also, out of curiosity, what parts/code/style do you mean by:

Ah. That's a really cool way to program. Not seen anything like that in ruby before.

Lastly, thanks for your interest! I got your angelo-sessions code working with this branch! :smiley_cat:

samjohnduke commented 10 years ago

@kenichi Glad you got sessions working!

I think the blocks look good and will perform exactly as required. I will have a further look this weekend and see how it goes.

I was referring to binding a 'floating' instance method to the current caller before invoking it. I haven't done much meta programming in ruby and it's something I'm still trying to get my head around. But it looks really useful.