Skip to content

Instantly share code, notes, and snippets.

@tcrayford
tcrayford / sketch.rb
Created June 29, 2012 16:03 — forked from mattwynne/sketch.rb
sketch for Matt Wynne
class RubbishController
protected
def redirect_to(path)
puts "redirecting_to #{path}"
end
def render(renderable)
puts "rendering #{renderable}"
end
def current_user
class FuckYouPrivate
def initialize(thing)
@thing = thing
end
def method_missing(message, *args, &block)
@thing.send(message, *args, &block)
end
end
A Controlled Explosion
Well designed Rails controller methods follow very similar execution paths. Raptor is an experimental web framework designed to explode the Rails controller, reconstructing it inside the router.
This talk is a dive into Raptor's design, eventual goals and a small demonstration of what Raptor looks like today.
#logback.classic pattern: %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
#logback.classic pattern: %-5p [%d{ISO8601,Europe/London}] %c: %m
%ex
#logback.classic pattern: %-5p [%d{ISO8601,UTC}] %c: %m
%ex
DEBUG [2012-05-25 23:57:42,351] org.eclipse.jetty.util.log: Logging to Logger[org.eclipse.jetty.util.log] via org.eclipse.jetty.util.log.Slf4jLog
DEBUG [2012-05-25 23:57:42,381] org.hibernate.validator.engine.resolver.DefaultTraversableResolver: Cannot find javax.persistence.Persistence on classpath. Assuming non JPA 2 environment. All properties will per default be traversable.
DEBUG [2012-05-25 23:57:42,382] org.hibernate.validator.xml.ValidationXmlParser: Trying to load META-INF/validation.xml for XML based Validator configuration.
DEBUG [2012-05-25 23:57:42,382] org.hibernate.validator.xml.ValidationXmlParser: No META-INF/validation.xml found. Using annotation based configuration only
WARN [2012-05-25 23:57:42,446] com.yammer.dropwizard.config.ServerFactory:
specify "the first time rspec has made me sad" do
class CustomError < RuntimeError; end
expect do
raise CustomError.new('what')
end.to raise_error(CustomError.new('what'))
end
specify "the first time rspec has made me sad" do
class CustomError < RuntimeError; end
expect do
raise CustomError.new('what')
end.to raise(CustomError.new('what'))
end
1.9.3p125 :001 > class Foo < RuntimeError; def to_str; "other_string"; end; end
=> nil
1.9.3p125 :002 > begin raise Foo.new; rescue Foo => e; end
RuntimeError: other_string
from (irb):2
from /Users/tcrayford/.rvm/rubies/ruby-1.9.3-p125/bin/irb:16:in `<main>'
Note, the "don't stub external APIs" is a rule, but like all design/testing rules it *should* be broken with good judgement. Furthermore, like all design/testing rules, the best way to learn when to break it is to follow it rigorously until it leads you to a bad place.
Problems
--------
- Stubbing external APIs gives you no design feedback: you cannot change the third party API (unless you monkey patch, but seriously, Fuck That Shit. Since stubbing/mocking are primarily a design tool (for me), having to stub/mock something I cannot/will not change seems pointless.
- Stubbing a third party API relies on you having intimate understanding of the docs, including error conditions, timeouts etc. I'm not confident in my ability to successfully stub a third party API on each conditions.
The Solution
------------
# with dependency injection, and slightly different route syntax:
module WebCrawler
Routes = Raptor::App.new(self) do
queue = #... some sort of persistent queue initialized here
crawler = WebCrawler.new(queue)
path "to-be-crawled" do
create crawler, :enqueue!, :require => :logged_in
end
end
module Kernel
def an(value)
Thingy.new(value)
end
def none
Nothing.new
end
end