Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Middleware: A General Purpose Abstraction

Middleware: A General Purpose Abstraction

Mitchell Hashimoto

June 02, 2012
Tweet

More Decks by Mitchell Hashimoto

Other Decks in Programming

Transcript

  1. 1 module Authlogic 2 module Session # :nodoc: 3 #

    This is the base class Authlogic, where all modules are included. 4 # 5 class Base 6 include Foundation 7 include Callbacks 8 9 # Included first so that the session resets itself to nil 10 include Timeout 11 12 # Included in a specific order so they are tried in this order when persisting 13 include Params 14 include Cookies 15 include Session 16 include HttpAuth 17 18 # Included in a specific order so magic states gets ran after a record is found 19 include Password 20 include UnauthorizedRecord 21 include MagicStates 22 23 include Activation 24 include ActiveRecordTrickery 25 include BruteForceProtection 26 include Existence 27 include Klass 28 include MagicColumns 29 include PerishableToken 30 include Persistence 31 include Scopes 32 include Id 33 include Validation 34 include PriorityRecord 35 end 36 end 37 end
  2. 1 def f(value) 2 value + 1 3 end 4

    5 def g(value) 6 value * 2 7 end
  3. 1 f(g(1)) # => 3 2 3 g(f(1)) # =>

    4 Clear Dependencies
  4. 1 f(g(1)) # => 3 2 3 g(f(1)) # =>

    4 True Separation of Logic
  5. 1 app = Rack::Builder.new do 2 use Middleware::Example 3 use

    Rack::CommonLogger 4 use Rack::ShowExceptions 5 end
  6. 1 app = Rack::Builder.new do 2 use Middleware::Example 3 use

    Rack::CommonLogger 4 use Rack::ShowExceptions 5 end
  7. 1 app = Rack::Builder.new do 2 use Middleware::Example 3 use

    Rack::CommonLogger 4 use Rack::ShowExceptions 5 end
  8. 1 module Middleware 2 class Example 3 def initialize(app) 4

    @app = app 5 end 6 7 def call(env) 8 # do something before the next middleware 9 # possibly modify the environment 10 11 # run the next middleware in the stack 12 @app.call(env) 13 14 # do something after the next middleware 15 end 16 end 17 end
  9. 1 module Middleware 2 class Example 3 def initialize(app) 4

    @app = app 5 end 6 7 def call(env) 8 # do something before the next middleware 9 # possibly modify the environment 10 11 # run the next middleware in the stack 12 @app.call(env) 13 14 # do something after the next middleware 15 end 16 end 17 end
  10. 1 module Middleware 2 class Example 3 def initialize(app) 4

    @app = app 5 end 6 7 def call(env) 8 # do something before the next middleware 9 # possibly modify the environment 10 11 # run the next middleware in the stack 12 @app.call(env) 13 14 # do something after the next middleware 15 end 16 end 17 end
  11. 1 module Middleware 2 class Example 3 def initialize(app) 4

    @app = app 5 end 6 7 def call(env) 8 # do something before the next middleware 9 # possibly modify the environment 10 11 # run the next middleware in the stack 12 @app.call(env) 13 14 # do something after the next middleware 15 end 16 end 17 end
  12. 1 app = Rack::Builder.new do 2 use Middleware::Example 3 use

    Rack::CommonLogger 4 use Rack::ShowExceptions 5 end
  13. 1 app = Rack::Builder.new do 2 use Middleware::Example 3 use

    Rack::CommonLogger 4 use Rack::ShowExceptions 5 end
  14. 1 module Middleware 2 class Example 3 # ... 4

    5 def call(env) 6 if env["path"] == "/foo" 7 env["path"] = "/bar" 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  15. 1 module Middleware 2 class Example 3 # ... 4

    5 def call(env) 6 if env["path"] == "/foo" 7 env["path"] = "/bar" 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  16. 1 module Middleware 2 class Example 3 # ... 4

    5 def call(env) 6 if env["path"] == "/foo" 7 env["path"] = "/bar" 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  17. 1 state = { "path" => "/foo" } 2 m

    = Middleware::Example.new 3 m.call(state) 4 assert state["path"] == "/bar"
  18. 1 Builder.new do 2 use General::CheckVirtualbox 3 use General::Validate 4

    use VM::CheckAccessible 5 use VM::Suspend 6 end
  19. 1 Builder.new do 2 use General::CheckVirtualbox 3 use General::Validate 4

    use VM::CheckAccessible 5 use VM::Suspend 6 end
  20. 1 Builder.new do 2 use General::CheckVirtualbox 3 use General::Validate 4

    use VM::CheckAccessible 5 use VM::Suspend 6 end
  21. 1 module Vagrant::Action::General 2 class Validate 3 # ... 4

    5 def call(env) 6 if env[:validate] 7 env[:vm].config.validate!(env[:vm].env) 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  22. 1 module Vagrant::Action::General 2 class Validate 3 # ... 4

    5 def call(env) 6 if env[:validate] 7 env[:vm].config.validate!(env[:vm].env) 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  23. 1 module Vagrant::Action::General 2 class Validate 3 # ... 4

    5 def call(env) 6 if env[:validate] 7 env[:vm].config.validate!(env[:vm].env) 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  24. 1 module Vagrant::Action::General 2 class Validate 3 # ... 4

    5 def call(env) 6 if env[:validate] 7 env[:vm].config.validate!(env[:vm].env) 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  25. 1 Builder.new do 2 use General::CheckVirtualbox 3 use General::Validate 4

    use VM::CheckAccessible 5 use VM::Suspend 6 end
  26. 1 module Vagrant::Action::VM 2 class Suspend 3 # ... 4

    5 def call(env) 6 if env[:vm].state == :running 7 env[:vm].driver.suspend 8 end 9 10 @app.call(env) 11 end 12 end 13 end
  27. 1 Builder.new do 2 use General::CheckVirtualbox 3 use General::Validate 4

    use VM::CheckAccessible 5 use VM::CheckBox 6 use VM::Import 7 use VM::CheckGuestAdditions 8 use VM::DefaultName 9 use VM::MatchMACAddress 10 use VM::CleanMachineFolder 11 use VM::ClearForwardedPorts 12 use VM::CheckPortCollisions 13 use VM::ForwardPorts 14 use VM::Provision 15 use VM::PruneNFSExports 16 use VM::NFS 17 use VM::ClearSharedFolders 18 use VM::ShareFolders 19 use VM::HostName 20 use VM::ClearNetworkInterfaces 21 use VM::Network 22 use VM::Customize 23 use VM::Boot 24 end
  28. 1 Builder.new do 2 use General::CheckVirtualbox 3 use General::Validate 4

    use VM::CheckAccessible 5 use VM::CheckBox 6 use VM::Import 7 use VM::CheckGuestAdditions 8 use VM::DefaultName 9 use VM::MatchMACAddress 10 use VM::CleanMachineFolder 11 use VM::ClearForwardedPorts 12 use VM::CheckPortCollisions 13 use VM::ForwardPorts 14 use VM::Provision 15 use VM::PruneNFSExports 16 use VM::NFS 17 use VM::ClearSharedFolders 18 use VM::ShareFolders 19 use VM::HostName 20 use VM::ClearNetworkInterfaces 21 use VM::Network 22 use VM::Customize 23 use VM::Boot 24 end
  29. 1 def accept_invitation!(opts = {}) 2 if self.invited? 3 self.setup(opts)

    4 self.invitation_token = nil 5 self.password = opts[:password] 6 self.password_confirmation = opts[:password_confirmation] 7 8 self.save 9 return unless self.errors.empty? 10 11 # moved old Invitation#share_with! logic into here, 12 # but i don't think we want to destroy the invitation 13 # anymore. we may want to just call self.share_with 14 invitations_to_me.each do |invitation| 15 if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) 16 invitation.destroy 17 end 18 end 19 20 self 21 end 22 end
  30. 1 def accept_invitation!(opts = {}) 2 if self.invited? 3 self.setup(opts)

    4 self.invitation_token = nil 5 self.password = opts[:password] 6 self.password_confirmation = opts[:password_confirmation] 7 8 self.save 9 return unless self.errors.empty? 10 11 # moved old Invitation#share_with! logic into here, 12 # but i don't think we want to destroy the invitation 13 # anymore. we may want to just call self.share_with 14 invitations_to_me.each do |invitation| 15 if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) 16 invitation.destroy 17 end 18 end 19 20 self 21 end 22 end
  31. 1 def accept_invitation!(opts = {}) 2 if self.invited? 3 self.setup(opts)

    4 self.invitation_token = nil 5 self.password = opts[:password] 6 self.password_confirmation = opts[:password_confirmation] 7 8 self.save 9 return unless self.errors.empty? 10 11 # moved old Invitation#share_with! logic into here, 12 # but i don't think we want to destroy the invitation 13 # anymore. we may want to just call self.share_with 14 invitations_to_me.each do |invitation| 15 if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) 16 invitation.destroy 17 end 18 end 19 20 self 21 end 22 end
  32. 1 def accept_invitation!(opts = {}) 2 if self.invited? 3 self.setup(opts)

    4 self.invitation_token = nil 5 self.password = opts[:password] 6 self.password_confirmation = opts[:password_confirmation] 7 8 self.save 9 return unless self.errors.empty? 10 11 # moved old Invitation#share_with! logic into here, 12 # but i don't think we want to destroy the invitation 13 # anymore. we may want to just call self.share_with 14 invitations_to_me.each do |invitation| 15 if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) 16 invitation.destroy 17 end 18 end 19 20 self 21 end 22 end
  33. 1 def accept_invitation!(opts = {}) 2 if self.invited? 3 self.setup(opts)

    4 self.invitation_token = nil 5 self.password = opts[:password] 6 self.password_confirmation = opts[:password_confirmation] 7 8 self.save 9 return unless self.errors.empty? 10 11 # moved old Invitation#share_with! logic into here, 12 # but i don't think we want to destroy the invitation 13 # anymore. we may want to just call self.share_with 14 invitations_to_me.each do |invitation| 15 if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) 16 invitation.destroy 17 end 18 end 19 20 self 21 end 22 end
  34. 1 def accept_invitation!(opts = {}) 2 if self.invited? 3 self.setup(opts)

    4 self.invitation_token = nil 5 self.password = opts[:password] 6 self.password_confirmation = opts[:password_confirmation] 7 8 self.save 9 return unless self.errors.empty? 10 11 # moved old Invitation#share_with! logic into here, 12 # but i don't think we want to destroy the invitation 13 # anymore. we may want to just call self.share_with 14 invitations_to_me.each do |invitation| 15 if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) 16 invitation.destroy 17 end 18 end 19 20 self 21 end 22 end
  35. 1 def setup(opts) 2 self.username = opts[:username] 3 self.email =

    opts[:email] 4 self.language = opts[:language] 5 self.language ||= I18n.locale.to_s 6 self.valid? 7 errors = self.errors 8 errors.delete :person 9 return if errors.size > 0 10 self.set_person(Person.new(opts[:person] || {} )) 11 self.generate_keys 12 self 13 end
  36. 1 class SetupUser 2 def call(env) 3 user = env[:user]

    4 5 user.username = env[:username] 6 user.email = env[:email] 7 user.language = env[:language] 8 user.language ||= I18n.locale.to_s 9 user.valid? 10 errors = user.errors 11 errors.delete :person 12 raise ErrorsHappened if errors.size > 0 13 user.set_person(Person.new(env[:person] || {} )) 14 user.generate_keys 15 end 16 end
  37. 1 class SetupUser 2 def call(env) 3 user = env[:user]

    4 5 user.username = env[:username] 6 user.email = env[:email] 7 user.language = env[:language] 8 user.language ||= I18n.locale.to_s 9 user.valid? 10 errors = user.errors 11 errors.delete :person 12 raise ErrorsHappened if errors.size > 0 13 user.set_person(Person.new(env[:person] || {} )) 14 user.generate_keys 15 @app.call(env) 16 end 17 end
  38. 1 class SetupUser 2 def call(env) 3 user = env[:user]

    4 5 user.username = env[:username] 6 user.email = env[:email] 7 user.language = env[:language] 8 user.language ||= I18n.locale.to_s 9 user.valid? 10 errors = user.errors 11 errors.delete :person 12 raise ErrorsHappened if errors.size > 0 13 user.set_person(Person.new(env[:person] || {} )) 14 user.generate_keys 15 @app.call(env) 16 end 17 end
  39. 1 Builder.new do 2 use HaltIfInvited 3 use SetupUser 4

    use SetPassword 5 use ClearInvitations 6 end
  40. 1 Builder.new do 2 use SetupUser 3 use AcceptInvite 4

    use ConfirmationEmail 5 end 6 7 Builder.new do 8 use SetupUser 9 use Signup 10 end
  41. 1 Builder.new do 2 use SetupUser 3 use AcceptInvite 4

    use ConfirmationEmail 5 end 6 7 Builder.new do 8 use SetupUser 9 use Signup 10 end
  42. 1 def do_something! 2 foo(1) 3 bar(2) 4 baz(3) 5

    end 6 7 Builder.new do 8 use Foo, 1 9 use Bar, 2 10 use Baz, 3 11 end
  43. 1 def do_something! 2 foo(bar(baz(1))) 3 end 4 5 Builder.new

    { 6 use Baz 7 use Bar 8 use Foo 9 }.call(1)