0
All I Really Need to Know*
I Learned by Writing My
Own Web Framework
Ben Scofield               7 November 2008
          ...
DSLs
                  DSL




                        Intimidate
                            and
                        ...
Rails
Rails




        your custom
         framework
Starter Projects
Hello World
main() {
    printf(quot;hello, worldnquot;);
}


-module(hello).

-export([hello/0]).

hello() ->
   io:format(quot;Hello...
main = putStrLn quot;Hello Worldquot;

Imports System.Console

Class HelloWorld

    Public Shared Sub Main()
        Writ...
Applications
To-do lists
DIY Blog
Frameworks?
PHP Framework   (based on Rails)
NOT FOR PRODUCTION!
well, maybe for production
but really:

NOT FOR PRODUCTION!
Frameworks
ActionMailer
   ActionPack
  ActiveRecord
Ruby on Rails
ActiveResource
 ActiveSupport
    Railties
request => response
Sequel
   ActiveRecord
persistence layer
    DataMapper
        Og
ERB
     Liquid
    Amrita2
templating layer
     Erubis
    Markaby
      HAML
Ramaze
       Waves
   ActionPack
the middle layer
    Merb Core
     Sinatra
     Camping
ActionMailer
 Merb Helpers
   utilities
ActiveSupport
   Railties
Tools
Rack
Mack
   CGI
            Coset
  SCGI
          Camping
  LSWS
          Halcyon
Mongrel
          Maveric
WEBrick
        ...
mod_rack
Rack::Lint
    Rack::URLMap
   Rack::Deflater
 Rack::CommonLogger
   middlewares
Rack::ShowExceptions
   Rack::Reloader
  ...
Rack::Request
     utility
Rack::Response
Other Layers
Sequel
   ActiveRecord
persistence layer
    DataMapper
        Og
ERB
     Liquid
    Amrita2
templating layer
     Erubis
    Markaby
      HAML
Start at the End
Vision
REST and Resources
fully-formed web applications
       built on resources
fully-formed        web applications
     built on resources
Birth of Athena
Dionysus
ask me after if you don’t get the joke
Project
Extraction   flickr: 95579828@N00
class Habit < Athena::Resource
  def get
    @habit = Habit.find(@id)
  end

  # ...
end


RouteMap = {
  :get => {
     /...
Results
puts quot;Starting Athena applicationquot;

require 'active_record'
require File.expand_path(File.join('./vendor/athena/li...
module Athena
  class Application
    def self.root
      File.join(File.dirname(__FILE__), '..', '..', '..', '..')
    en...
module Athena
  class Resource
    extend Athena::Persistence
    attr_accessor :template

    def self.inherited(f)
     ...
class Habit < Athena::Resource
  persist(ActiveRecord::Base) do
    validates_presence_of :name
  end

  def get
    @habi...
class Habits < Athena::SingletonResource
  default_resource

  def get
    @habits = Habit.all
  end

  def post
    @resu...
module Athena
  module Persistence
    def self.included(base)
      base.class_eval do
        @@persistence_class = nil
...
Lessons About the Web
HTTP status codes   http://thoughtpad.net/alan-dean/http-headers-status.gif
207
Multi-Status
207
sucks
 Multi-Status
rack::cache
http://tomayko.com/src/rack-cache/
Lessons About Ruby
module Athena
    class Application
      # ...

      def process_params(params)
        nested_pattern = /^(.+?)[(.*])/
...
module Athena
     module Persistence
       def self.included(base)
         base.class_eval do
           @@persistence_...
Tangled classes   flickr: randomurl
module Athena
     module Persistence
       # ...

       def method_missing(name, *args)
         return self.persistenc...
this session has been a LIE
More to learn   flickr: glynnis
... always   flickr: mointrigue
http://github.com/bscofield/athena
           (under construction)
Thank you!
    Questions?

 Ben Scofield
 Development Director, Viget Labs

 http://www.viget.com/extend | http://www.cula...
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
Upcoming SlideShare
Loading in...5
×

All I Need to Know I Learned by Writing My Own Web Framework

3,850

Published on

Slides from session at Rubyconf 2008

Published in: Technology
0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,850
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
106
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide

Transcript of "All I Need to Know I Learned by Writing My Own Web Framework"

  1. 1. All I Really Need to Know* I Learned by Writing My Own Web Framework Ben Scofield 7 November 2008 Rubyconf * about Ruby and the web
  2. 2. DSLs DSL Intimidate and Frighten flickr: cwsteeds
  3. 3. Rails
  4. 4. Rails your custom framework
  5. 5. Starter Projects
  6. 6. Hello World
  7. 7. main() { printf(quot;hello, worldnquot;); } -module(hello). -export([hello/0]). hello() -> io:format(quot;Hello World!~nquot;, []). PROGRAM HELLO PRINT*, 'Hello World!' END
  8. 8. main = putStrLn quot;Hello Worldquot; Imports System.Console Class HelloWorld Public Shared Sub Main() WriteLine(quot;Hello, world!quot;) End Sub End Class !greeting. +!greeting : true <- .print(quot;Hello Worldquot;).
  9. 9. Applications
  10. 10. To-do lists
  11. 11. DIY Blog
  12. 12. Frameworks?
  13. 13. PHP Framework (based on Rails)
  14. 14. NOT FOR PRODUCTION!
  15. 15. well, maybe for production
  16. 16. but really: NOT FOR PRODUCTION!
  17. 17. Frameworks
  18. 18. ActionMailer ActionPack ActiveRecord Ruby on Rails ActiveResource ActiveSupport Railties
  19. 19. request => response
  20. 20. Sequel ActiveRecord persistence layer DataMapper Og
  21. 21. ERB Liquid Amrita2 templating layer Erubis Markaby HAML
  22. 22. Ramaze Waves ActionPack the middle layer Merb Core Sinatra Camping
  23. 23. ActionMailer Merb Helpers utilities ActiveSupport Railties
  24. 24. Tools
  25. 25. Rack
  26. 26. Mack CGI Coset SCGI Camping LSWS Halcyon Mongrel Maveric WEBrick Sinatra FastCGI Vintage Fuzed Ramaze Thin Waves Ebb Merb
  27. 27. mod_rack
  28. 28. Rack::Lint Rack::URLMap Rack::Deflater Rack::CommonLogger middlewares Rack::ShowExceptions Rack::Reloader Rack::Static Rack::Cache
  29. 29. Rack::Request utility Rack::Response
  30. 30. Other Layers
  31. 31. Sequel ActiveRecord persistence layer DataMapper Og
  32. 32. ERB Liquid Amrita2 templating layer Erubis Markaby HAML
  33. 33. Start at the End
  34. 34. Vision
  35. 35. REST and Resources
  36. 36. fully-formed web applications built on resources
  37. 37. fully-formed web applications built on resources
  38. 38. Birth of Athena
  39. 39. Dionysus ask me after if you don’t get the joke
  40. 40. Project
  41. 41. Extraction flickr: 95579828@N00
  42. 42. class Habit < Athena::Resource def get @habit = Habit.find(@id) end # ... end RouteMap = { :get => { //habit/new/ => {:resource => :habit, :template => :new}, //habit/(d+)/ => {:resource => :habit}, //habit/(d+)/edit/ => {:resource => :habit, :template => :edit} }, :put => { //habit/(d+)/ => {:resource => :habit} }, :delete => { //habit/(d+)/ => {:resource => :habit} }, :post => { //habit// => {:resource => :habit} } }
  43. 43. Results
  44. 44. puts quot;Starting Athena applicationquot; require 'active_record' require File.expand_path(File.join('./vendor/athena/lib/athena')) puts quot;... Framework loadedquot; Athena.require_all_libs_relative_to('resources') puts quot;... Resources loadedquot; use Rack::Static, :urls => ['/images', '/stylesheets'], :root => 'public' run Athena::Application.new puts quot;... Application startednnquot; puts quot;^C to stop the applicationquot;
  45. 45. module Athena class Application def self.root File.join(File.dirname(__FILE__), '..', '..', '..', '..') end def self.route_map @route_map ||= { :get => {}, :post => {}, :put => {}, :delete => {} } @route_map end def call(environment) request = Rack::Request.new(environment) request_method = request.params['_method'] ? # ... matching_route = Athena::Application.route_map # ... if matching_route resource = matching_route.last[:class].new(request, request_method) resource.template = matching_route.last[:template] return resource.output else raise Athena::BadRequest end end end end
  46. 46. module Athena class Resource extend Athena::Persistence attr_accessor :template def self.inherited(f) unless f == Athena::SingletonResource url_name = f.name.downcase routing = url_name + id_pattern url_pattern = /^/#{routing}$/ Athena::Application.route_map[:get][/^/#{routing}/edit$/] = # ... Athena::Application.route_map[:post][/^/#{url_name}$/] = # ... # ... end end def self.default_resource Athena::Application.route_map[:get][/^/$/] = {:class => # ... end def self.id_pattern '/(d+)' end def get; raise Athena::MethodNotAllowed; end def put; raise Athena::MethodNotAllowed; end def post; raise Athena::MethodNotAllowed; end def delete; raise Athena::MethodNotAllowed; end # ... end end
  47. 47. class Habit < Athena::Resource persist(ActiveRecord::Base) do validates_presence_of :name end def get @habit = Habit.find_by_id(@id) || Habit.new_record end def post @habit = Habit.new_record(@params['habit']) @habit.save! end def put @habit = Habit.find(@id) @habit.update_attributes!(@params['habit']) end def delete Habit.find(@id).destroy end end
  48. 48. class Habits < Athena::SingletonResource default_resource def get @habits = Habit.all end def post @results = @params['habits'].map do |hash| Habit.new_record(hash).save end end def put @results = @params['habits'].map do |id, hash| Habit.find(id).update_attributes(hash) end end def delete Habit.find(:all, :conditions => ['id IN (?)', @params['habit_ids']] ).map(&:destroy) end end
  49. 49. module Athena module Persistence def self.included(base) base.class_eval do @@persistence_class = nil end end def persist(klass, &block) pklass = Class.new(klass) pklass.class_eval(&block) pklass.class_eval quot;set_table_name '#{self.name}'.tableizequot; eval quot;Persistent#{self.name} = pklassquot; @@persistence_class = pklass @@persistence_class.establish_connection( YAML::load(IO.read(File.join(Athena::Application.root, # ... ) end def new_record(*args) self.persistence_class.new(*args) end def persistence_class @@persistence_class end # ...
  50. 50. Lessons About the Web
  51. 51. HTTP status codes http://thoughtpad.net/alan-dean/http-headers-status.gif
  52. 52. 207 Multi-Status
  53. 53. 207 sucks Multi-Status
  54. 54. rack::cache http://tomayko.com/src/rack-cache/
  55. 55. Lessons About Ruby
  56. 56. module Athena class Application # ... def process_params(params) nested_pattern = /^(.+?)[(.*])/ processed = {} params.each do |k, v| if k =~ nested_pattern scanned = k.scan(nested_pattern).flatten first = scanned.first last = scanned.last.sub(/]/, '') if last == '' processed[first] ||= [] processed[first] << v else processed[first] ||= {} processed[first][last] = v processed[first] = process_params(processed[first]) end else processed[k] = v end end processed.delete('_method') processed end # ... end Form Parameters end
  57. 57. module Athena module Persistence def self.included(base) base.class_eval do @@persistence_class = nil end end def persist(klass, &block) pklass = Class.new(klass) pklass.class_eval(&block) pklass.class_eval quot;set_table_name '#{self.name}'.tableizequot; eval quot;Persistent#{self.name} = pklassquot; @@persistence_class = pklass @@persistence_class.establish_connection( YAML::load(IO.read(File.join(Athena::Application.root, # ... ) end def new_record(*args) self.persistence_class.new(*args) end def persistence_class @@persistence_class end # ... Dynamic class creation
  58. 58. Tangled classes flickr: randomurl
  59. 59. module Athena module Persistence # ... def method_missing(name, *args) return self.persistence_class.send(name, *args) rescue ActiveRecord::ActiveRecordError => e raise e rescue super end end end Exception Propagation
  60. 60. this session has been a LIE
  61. 61. More to learn flickr: glynnis
  62. 62. ... always flickr: mointrigue
  63. 63. http://github.com/bscofield/athena (under construction)
  64. 64. Thank you! Questions? Ben Scofield Development Director, Viget Labs http://www.viget.com/extend | http://www.culann.com ben.scofield@viget.com | bscofield@gmail.com
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×