Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

inject things into views #55

Closed
wants to merge 2 commits into from

2 participants

Tom Crayford Gary Bernhardt
Tom Crayford
Collaborator

This enables users to write things like

<% if inject :user %>
Logout
<% end %>

in their views (assuming user is an injectable that returns nil when no user is available).

Gary Bernhardt

Mixing the inject into the access strikes me as a weird mixing of concerns. What about either declaring (<% inject :user %> makes user available, but doesn't return it), or a method_missing hack?

This makes me pine for a view/template distinction, but I don't think pursing that desire would lead to happiness... ;)

Tom Crayford
Collaborator

I like the first of those. Will put in a pull req in a bit.

Tom Crayford
Collaborator

So I thought about this a bit more (finally). The thing I dislike about the first approach (making things available) is that it forces mutable state into raptor.

I guess method_missing is kinda better than that (assuming you mean the template just calls user, and the context brings that out of the injector). Kinda makes the injector feel even more magic though.

Gary Bernhardt

It definitely does make it feel more magical. Are you happy enough to add it and try it out? If so, rebase onto master and I'll merge?

Tom Crayford
Collaborator

Thinking about fallbacks for when the injectable isn't available here. What about the method_missing hack taking a block, and only calling the block if the user is available:

<% current_user do |current_user| %>
  <a href="/logout">Logout</a>
<% end %>

This has a downside of not being able to display other text when the user isn't available.

Other options:

  • Pass a fallback to method_missing: current_user(:or => NilUser.new)

  • Pass a fallback to the inject method that makes the user available: inject :current_user, NilUser.new.

Tom Crayford tcrayford closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 28, 2012
  1. Tom Crayford

    inject things into views

    tcrayford authored
Commits on May 17, 2012
  1. Tom Crayford

    inject using method_missing

    tcrayford authored
This page is out of date. Refresh to see the latest.
7 lib/raptor/injector.rb
View
@@ -29,10 +29,13 @@ def args(method)
end.reject do |type, name|
type == :opt && sources[name].nil?
end.map do |type, name|
- source_proc = sources[name] or raise UnknownInjectable.new(name)
- source_proc.call
+ inject_name(name)
end
end
+ def inject_name(name)
+ source_proc = sources[name] or raise UnknownInjectable.new(name)
+ source_proc.call
+ end
def parameters(method)
method.parameters
3  lib/raptor/responders.rb
View
@@ -65,7 +65,8 @@ def self.action_template(app, presenter_name, parent_path, template_name)
def respond(route, subject, injector)
presenter = create_presenter(subject, injector)
- Rack::Response.new(render(presenter))
+ context = Raptor::ViewContext.new(presenter, injector)
+ Rack::Response.new(render(context))
end
def render(presenter)
17 lib/raptor/templates.rb
View
@@ -17,8 +17,8 @@ def self.find(path)
end
class NullLayout
- def self.render(inner, presenter)
- inner.render(presenter)
+ def self.render(inner, context)
+ inner.render(context)
end
end
@@ -37,17 +37,17 @@ def ==(other)
other.tilt == tilt
end
- def render(inner, presenter)
- context = ViewContext.new(presenter)
+ def render(inner, context)
rendered = inner.render(context)
@tilt.render(context) { rendered }
end
end
class ViewContext < BasicObject
- def initialize(presenter)
+ def initialize(presenter, injector)
@presenter = presenter
@areas = {}
+ @injector = injector
end
def content_for(name, &block)
@@ -60,7 +60,12 @@ def content_for(name, &block)
end
def method_missing(name, *args, &block)
- @presenter.send(name, *args, &block)
+ begin
+ @presenter.send(name, *args, &block)
+ rescue ::NoMethodError => e
+ ::Raptor.log("Injecting #{name.inspect} into view")
+ @injector.inject_name(name)
+ end
end
end
6 spec/injector_spec.rb
View
@@ -97,6 +97,12 @@ def takes_watermelon(watermelon); watermelon; end
injector.call(method(:takes_watermelon)).should == "fruity"
end
end
+
+ it "can be asked for an injection by name" do
+ shins = stub
+ injector = Raptor::Injector.new([Raptor::Injectables::Fixed.new(:shins, shins)])
+ injector.inject_name(:shins).should == shins
+ end
end
class ObjectWithInitializerTakingId
19 spec/template_spec.rb
View
@@ -1,6 +1,6 @@
require "rack"
require_relative "spec_helper"
-require_relative "../lib/raptor/templates"
+require_relative "../lib/raptor"
describe Raptor::Template do
let(:presenter) { stub("presenter") }
@@ -26,6 +26,7 @@
describe Raptor::Layout do
let(:presenter) { stub }
+ let(:injector) { Raptor::Injector.new([]) }
it "renders a yielded template" do
inner = stub(:render => 'inner')
@@ -37,28 +38,36 @@
it "integrates content_for" do
inner = Raptor::Template.from_path("../spec/fixtures/provides_content_for.html.erb")
layout = Raptor::Layout.from_path('spec/fixtures/layout_with_content_for.html.erb')
- rendered = layout.render(inner, presenter)
+ rendered = layout.render(inner, Raptor::ViewContext.new(presenter, injector))
rendered.strip.should include("<script></script")
end
end
describe Raptor::ViewContext do
+ let(:injector) { Raptor::Injector.new([]) }
it "delegates to the presenter" do
- Raptor::ViewContext.new(stub(:cheese => 'walrus')).cheese.should == 'walrus'
+ Raptor::ViewContext.new(stub(:cheese => 'walrus'), injector).cheese.should == 'walrus'
end
it "stores content_for" do
- context = Raptor::ViewContext.new(stub)
+ context = Raptor::ViewContext.new(stub, injector)
context.content_for(:head) { 'what' }
context.content_for(:head).should == 'what'
end
it "appends multiple content_for blocks" do
- context = Raptor::ViewContext.new(stub)
+ context = Raptor::ViewContext.new(stub, injector)
context.content_for(:head) { 'what' }
context.content_for(:head) { 'what' }
context.content_for(:head).should == 'whatwhat'
end
+
+ it "injects from the injector" do
+ current_user = stub
+ injector = Raptor::Injector.new([Raptor::Injectables::Fixed.new(:current_user, current_user)])
+ context = Raptor::ViewContext.new(Object.new, injector)
+ context.current_user.should == current_user
+ end
end
describe Raptor::FindsLayouts do
Something went wrong with that request. Please try again.