z, ? | toggle help (this) |
space, → | next slide |
shift-space, ← | previous slide |
d | toggle debug mode |
## <ret> | go to slide # |
c, t | table of contents (vi) |
f | toggle footer |
r | reload slides |
n | toggle notes |
p | run preshow |
johnbender.github.com/presentation-middleware
module Authlogic module Session # :nodoc: # This is the base class Authlogic, where all modules are included. # For information on functiionality see the various sub modules. class Base include Foundation include Callbacks # Included first so that the session resets itself to nil include Timeout # Included in a specific order so they are tried in this order when persisting include Params include Cookies include Session include HttpAuth # Included in a specific order so magic states gets ran after a record is found include Password include UnauthorizedRecord include MagicStates include Activation include ActiveRecordTrickery include BruteForceProtection include Existence include Klass include MagicColumns include PerishableToken include Persistence include Scopes include Id include Validation include PriorityRecord end end end
class Lamp def initialize(bulb_age) @bulb_age = bulb_age end def needs_maintenance? @bulb_age > 2 end end
class Lamp def initialize(bulb_age) @bulb_age = bulb_age end def needs_maintenance? @bulb_age > 2 end end
class Lamp def initialize(bulb) @bulb = bulb end def needs_maintenance? @bulb.needs_maintenance? end end
python.org/dev/peps/pep-0333/
app = Rack::Builder.new do use Middleware::Example use Rack::CommonLogger use Rack::ShowExceptions end
app = Rack::Builder.new do use Middleware::Example use Rack::CommonLogger use Rack::ShowExceptions end
↓
app = Rack::Builder.new do use Middleware::Example use Rack::CommonLogger use Rack::ShowExceptions end
↓
module Middleware class Example def initialize(app) @app = app end def call(env) # do something before the next middleware # possibly modify the environment # run the next middleware in the stack @app.call(env) # do something after the next middleware end end end
module Middleware class Example def initialize(app) @app = app end def call(env) # do something before the next middleware # possibly modify the environment # run the next middleware in the stack @app.call(env) # do something after the next middleware end end end
module Middleware class Example def initialize(app) @app = app end def call(env) # do something before the next middleware # possibly modify the environment # run the next middleware in the stack @app.call(env) # do something after the next middleware end end end
app = Rack::Builder.new do use Middleware::Example use Rack::CommonLogger use Rack::ShowExceptions end
Rack::Handler::Puma.run(app)
app = Rack::Builder.new do use Middleware::Example use Rack::CommonLogger use Rack::ShowExceptions end
↓
app = Rack::Builder.new do use Middleware::Example use Rack::CommonLogger use Rack::ShowExceptions end
↓
module Middleware class Example def initialize(app) @app = app end def call(env) # do something before the next middleware # possibly modify the environment # run the next middleware in the stack @app.call(env) # do something after the next middleware end end end
module Middleware class Example def initialize(app) @app = app end def call(env) # do something before the next middleware # possibly modify the environment # run the next middleware in the stack @app.call(env) # do something after the next middleware end end end
module Middleware class Example def initialize(app) @app = app end def call(env) # do something before the next middleware # possibly modify the environment # run the next middleware in the stack @app.call(env) # do something after the next middleware end end end
vagrantup.com
$ vagrant suspend
Builder.new do use General::Validate use VM::CheckAccessible use VM::Suspend end
Builder.new do use General::Validate use VM::CheckAccessible use VM::Suspend end
↓
Builder.new do use General::Validate use VM::CheckAccessible use VM::Suspend end
↓
module Vagrant::Action::General class Validate def initialize(app, env) @app, @env = app, env end def call(env) if !@env["validate"] @env[:vm].config.validate!(@env[:vm].env) end @app.call(@env) end end end
module Vagrant::Action::General class Validate def initialize(app, env) @app, @env = app, env end def call(env) if !@env["validate"] @env[:vm].config.validate!(@env[:vm].env) end @app.call(@env) end end end
module Vagrant::Action::General class Validate def initialize(app, env) @app, @env = app, env end def call(env) if !@env["validate"] @env[:vm].config.validate!(@env[:vm].env) end @app.call(@env) end end end
Builder.new do use General::Validate use VM::CheckAccessible use VM::Suspend end
↓
module Vagrant::Action::VM class CheckAccessible def initialize(app, env) @app = app end def call(env) if env[:vm].state == :inaccessible raise Errors::VMInaccessible end @app.call(env) end end end
module Vagrant::Action::VM class CheckAccessible def initialize(app, env) @app = app end def call(env) if env[:vm].state == :inaccessible raise Errors::VMInaccessible end @app.call(env) end end end
Builder.new do use General::Validate use VM::CheckAccessible use VM::Suspend end
↓
module Vagrant::Action::VM class Suspend def initialize(app, env) @app = app end def call(env) if env[:vm].state == :running env[:vm].driver.suspend end @app.call(env) end end end
module Vagrant::Action::VM class Suspend def initialize(app, env) @app = app end def call(env) if env[:vm].state == :running env[:vm].driver.suspend end @app.call(env) end end end
module Vagrant::Action::VM class Suspend def initialize(app, env) @app = app end def call(env) if env[:vm].state == :running env[:vm].driver.suspend end @app.call(env) end end end
$ vagrant up
Builder.new do use General::Validate use VM::CheckAccessible use VM::CheckBox use VM::Import use VM::CheckGuestAdditions use VM::MatchMACAddress use VM::CheckAccessible use VM::CleanMachineFolder use VM::ClearForwardedPorts use VM::CheckPortCollisions use VM::ForwardPorts use VM::Provision use VM::NFS use VM::ClearSharedFolders use VM::ShareFolders use VM::HostName use VM::ClearNetworkInterfaces use VM::Network use VM::Customize use VM::Boot end
Builder.new do use General::Validate use VM::CheckAccessible use VM::CheckBox use VM::Import use VM::CheckGuestAdditions use VM::MatchMACAddress use VM::CheckAccessible use VM::CleanMachineFolder use VM::ClearForwardedPorts use VM::CheckPortCollisions use VM::ForwardPorts use VM::Provision use VM::NFS use VM::ClearSharedFolders use VM::ShareFolders use VM::HostName use VM::ClearNetworkInterfaces use VM::Network use VM::Customize use VM::Boot end
Builder.new do use General::Validate use VM::CheckAccessible use VM::CheckBox use VM::Import use VM::CheckGuestAdditions use VM::MatchMACAddress use VM::CheckAccessible use VM::CleanMachineFolder use VM::ClearForwardedPorts use VM::CheckPortCollisions use VM::ForwardPorts use VM::Provision use VM::NFS use VM::ClearSharedFolders use VM::ShareFolders use VM::HostName use VM::ClearNetworkInterfaces use VM::Network use VM::Customize use VM::Boot end
class User < ActiveRecord::Base include Diaspora::UserModules include Encryptor::Private def self.all_sharing_with_person(person) User.joins(:contacts).where(:contacts => {:person_id => person.id}) end # @return [User] def self.find_by_invitation(invitation) service = invitation.service identifier = invitation.identifier if service == 'email' existing_user = User.where(:email => identifier).first else existing_user = User.joins(:services).where(:services => {:type => "Services::#{service.titleize}", :uid => identifier}).first end if existing_user.nil? i = Invitation.where(:service => service, :identifier => identifier).first existing_user = i.recipient if i end existing_user end # @return [User] def self.find_or_create_by_invitation(invitation) if existing_user = self.find_by_invitation(invitation) existing_user else self.create_from_invitation!(invitation) end end # ... to be continued ...
def self.create_from_invitation!(invitation) user = User.new user.generate_keys user.send(:generate_invitation_token) user.email = invitation.identifier if invitation.service == 'email' # we need to make a custom validator here to make this safer user.save(:validate => false) user end def send_reset_password_instructions generate_reset_password_token! if should_generate_token? Resque.enqueue(Jobs::ResetPassword, self.id) end def update_user_preferences(pref_hash) if self.disable_mail UserPreference::VALID_EMAIL_TYPES.each{|x| self.user_preferences.find_or_create_by_email_type(x)} self.disable_mail = false self.save end pref_hash.keys.each do |key| if pref_hash[key] == 'true' self.user_preferences.find_or_create_by_email_type(key) else block = self.user_preferences.where(:email_type => key).first if block block.destroy end end end end def strip_and_downcase_username if username.present? username.strip! username.downcase! end end # ... to be continued ...
def set_current_language self.language = I18n.locale.to_s if self.language.blank? end # This override allows a user to enter either their email address or their username into the username field. # @return [User] The user that matches the username/email condition. # @return [nil] if no user matches that condition. def self.find_for_database_authentication(conditions={}) conditions = conditions.dup conditions[:username] = conditions[:username].downcase if conditions[:username] =~ /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i # email regex conditions[:email] = conditions.delete(:username) end where(conditions).first end # @param [Person] person # @return [Boolean] whether this user can add person as a contact. def can_add?(person) return false if self.person == person return false if self.contact_for(person).present? true end def confirm_email(token) return false if token.blank? || token != confirm_email_token self.email = unconfirmed_email save end ######### Aspects ###################### def move_contact(person, to_aspect, from_aspect) return true if to_aspect == from_aspect contact = contact_for(person) add_contact_to_aspect(contact, to_aspect) membership = contact ? AspectMembership.where(:contact_id => contact.id, :aspect_id => from_aspect.id).first : nil return(membership && membership.destroy) end # ... to be continued ...
def add_contact_to_aspect(contact, aspect) return true if AspectMembership.exists?(:contact_id => contact.id, :aspect_id => aspect.id) contact.aspect_memberships.create!(:aspect => aspect) end ######## Posting ######## def build_post(class_name, opts = {}) opts[:author] = self.person opts[:diaspora_handle] = opts[:author].diaspora_handle model_class = class_name.to_s.camelize.constantize model_class.diaspora_initialize(opts) end def dispatch_post(post, opts = {}) additional_people = opts.delete(:additional_subscribers) mailman = Postzord::Dispatcher.build(self, post, :additional_subscribers => additional_people) mailman.post(opts) end def update_post(post, post_hash = {}) if self.owns? post post.update_attributes(post_hash) Postzord::Dispatcher.build(self, post).post end end def notify_if_mentioned(post) return unless self.contact_for(post.author) && post.respond_to?(:mentions?) post.notify_person(self.person) if post.mentions? self.person end def add_to_streams(post, aspects_to_insert) inserted_aspect_ids = aspects_to_insert.map{|x| x.id} aspects_to_insert.each do |aspect| aspect << post end end # ... to be continued ...
def aspects_from_ids(aspect_ids) if aspect_ids == "all" || aspect_ids == :all self.aspects else aspects.where(:id => aspect_ids) end end def salmon(post) Salmon::EncryptedSlap.create_by_user_and_activity(self, post.to_diaspora_xml) end def build_relayable(model, options = {}) r = model.new(options.merge(:author_id => self.person.id)) r.set_guid r.initialize_signatures r end ######## Commenting ######## def build_comment(options = {}) build_relayable(Comment, options) end ######## Liking ######## def build_like(options = {}) build_relayable(Like, options) end def liked?(target) if target.likes.loaded? if self.like_for(target) return true else return false end else Like.exists?(:author_id => self.person.id, :target_type => target.class.base_class.to_s, :target_id => target.id) end end # ... to be continued ...
# Get the user's like of a post, if there is one. # @param [Post] post # @return [Like] def like_for(target) if target.likes.loaded? return target.likes.detect{ |like| like.author_id == self.person.id } else return Like.where(:author_id => self.person.id, :target_type => target.class.base_class.to_s, :target_id => target.id).first end end ######### Mailer ####################### def mail(job, *args) pref = job.to_s.gsub('Jobs::Mail::', '').underscore if(self.disable_mail == false && !self.user_preferences.exists?(:email_type => pref)) Resque.enqueue(job, *args) end end def mail_confirm_email return false if unconfirmed_email.blank? Resque.enqueue(Jobs::Mail::ConfirmEmail, id) true end ######### Posts and Such ############### def retract(target, opts={}) # ... redacted ... mailman = Postzord::Dispatcher.build(self, retraction, opts) mailman.post retraction.perform(self) retraction end # ... aaaaand we're done here ...
# Get the user's like of a post, if there is one. # @param [Post] post # @return [Like] def like_for(target) if target.likes.loaded? return target.likes.detect{ |like| like.author_id == self.person.id } else return Like.where(:author_id => self.person.id, :target_type => target.class.base_class.to_s, :target_id => target.id).first end end ######### Mailer ####################### def mail(job, *args) pref = job.to_s.gsub('Jobs::Mail::', '').underscore if(self.disable_mail == false && !self.user_preferences.exists?(:email_type => pref)) Resque.enqueue(job, *args) end end def mail_confirm_email return false if unconfirmed_email.blank? Resque.enqueue(Jobs::Mail::ConfirmEmail, id) true end ######### Posts and Such ############### def retract(target, opts={}) # ... redacted ... mailman = Postzord::Dispatcher.build(self, retraction, opts) mailman.post retraction.perform(self) retraction end # ... aaaaand we're done here ...
accept_invitation!
def accept_invitation!(opts = {}) log_hash = { :event => :invitation_accepted, :username => opts[:username], :uid => self.id } if invitations_to_me.first && invitations_to_me.first.sender log_hash[:inviter] = invitations_to_me.first.sender.diaspora_handle end if self.invited? self.setup(opts) self.invitation_token = nil self.password = opts[:password] self.password_confirmation = opts[:password_confirmation] self.save return unless self.errors.empty? # moved old Invitation#share_with! logic into here, # but i don't think we want to destroy the invitation # anymore. we may want to just call self.share_with invitations_to_me.each do |invitation| if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) invitation.destroy end end log_hash[:status] = "success" Rails.logger.info(log_hash) self end end
def accept_invitation!(opts = {}) log_hash = { :event => :invitation_accepted, :username => opts[:username], :uid => self.id } if invitations_to_me.first && invitations_to_me.first.sender log_hash[:inviter] = invitations_to_me.first.sender.diaspora_handle end if self.invited? self.setup(opts) self.invitation_token = nil self.password = opts[:password] self.password_confirmation = opts[:password_confirmation] self.save return unless self.errors.empty? # moved old Invitation#share_with! logic into here, # but i don't think we want to destroy the invitation # anymore. we may want to just call self.share_with invitations_to_me.each do |invitation| if !invitation.admin? && invitation.sender.share_with(self.person, invitation.aspect) invitation.destroy end end log_hash[:status] = "success" Rails.logger.info(log_hash) self end end
def call(env) @user = env[:user] opts = env[:opts] log_hash = { :event => :invitation_accepted, :username => opts[:username], :uid => user.id } if user.invitations_to_me.first && user.invitations_to_me.first.sender log_hash[:inviter] = user.invitations_to_me.first.sender.diaspora_handle end if user.invited? user.setup(opts) user.invitation_token = nil user.password = opts[:password] user.password_confirmation = opts[:password_confirmation] user.save return unless user.errors.empty? user.invitations_to_me.each do |invitation| if !invitation.admin? && invitation.sender.share_with(user.person, invitation.aspect) invitation.destroy end end log_hash[:status] = "success" Rails.logger.info(log_hash) user end # call the next middleware @app.call end
def call(env) @user = env[:user] opts = env[:opts] log_hash = { :event => :invitation_accepted, :username => opts[:username], :uid => user.id } if user.invitations_to_me.first && user.invitations_to_me.first.sender log_hash[:inviter] = user.invitations_to_me.first.sender.diaspora_handle end if user.invited? user.setup(opts) user.invitation_token = nil user.password = opts[:password] user.password_confirmation = opts[:password_confirmation] user.save return unless user.errors.empty? user.invitations_to_me.each do |invitation| if !invitation.admin? && invitation.sender.share_with(user.person, invitation.aspect) invitation.destroy end end log_hash[:status] = "success" Rails.logger.info(log_hash) user end # call the next middleware @app.call end
def call(env) @user = env[:user] opts = env[:opts] log_hash = { :event => :invitation_accepted, :username => opts[:username], :uid => user.id } if user.invitations_to_me.first && user.invitations_to_me.first.sender log_hash[:inviter] = user.invitations_to_me.first.sender.diaspora_handle end if user.invited? user.setup(opts) user.invitation_token = nil user.password = opts[:password] user.password_confirmation = opts[:password_confirmation] user.save return unless user.errors.empty? user.invitations_to_me.each do |invitation| if !invitation.admin? && invitation.sender.share_with(user.person, invitation.aspect) invitation.destroy end end log_hash[:status] = "success" Rails.logger.info(log_hash) user end # call the next middleware @app.call end
def call(env) @user = env[:user] opts = env[:opts] log_hash = { :event => :invitation_accepted, :username => opts[:username], :uid => user.id } if user.invitations_to_me.first && user.invitations_to_me.first.sender log_hash[:inviter] = user.invitations_to_me.first.sender.diaspora_handle end if user.invited? user.setup(opts) user.invitation_token = nil user.password = opts[:password] user.password_confirmation = opts[:password_confirmation] user.save return unless user.errors.empty? user.invitations_to_me.each do |invitation| if !invitation.admin? && invitation.sender.share_with(user.person, invitation.aspect) invitation.destroy end end log_hash[:status] = "success" Rails.logger.info(log_hash) user end # call the next middleware @app.call end
def setup(opts) user.username = opts[:username] user.email = opts[:email] user.language = opts[:language] user.language || = I18n.locale.to_s user.valid? errors = user.errors errors.delete :person return if errors.size > 0 user.set_person(Person.new(opts[:person] || {} )) user.generate_keys end
def setup(opts) user.username = opts[:username] user.email = opts[:email] user.language = opts[:language] user.language || = I18n.locale.to_s user.valid? errors = user.errors errors.delete :person return if errors.size > 0 user.set_person(Person.new(opts[:person] || {} )) user.generate_keys end
class InvitationsController < Devise::InvitationsController def update # ... omitted ... user = User.find_by_invitation_token!(invitation_token) user.accept_invitation!(params[:user]) # ... omitted ... end end
class User < ActiveRecord::Base def accept_invitation!(opts = {}) accept = Middleware::AcceptInvitation.new(lambda {}) accept.call(opts.merge(:user => self)) # or run(:accept_invitation, opts.merge(:user => self)) end end
class User < ActiveRecord::Base def accept_invitation!(opts = {}) accept = Middleware::AcceptInvitation.new(lambda {}) accept.call(opts.merge(:user => self)) # or run(:accept_invitation, opts.merge(:user => self)) end end
it "should setup the user" do mock.expects(:setup) @middleware.call(:user => mock) end
noob_stack = Builder.new do use Actions::User::AcceptInvite use Actions::User::Noob end veteran_stack = Builder.new do use Actions::User::AcceptInvite use Actions::User::Veteran end
noob_stack = Builder.new do use Actions::User::AcceptInvite use Actions::User::Noob end veteran_stack = Builder.new do use Actions::User::AcceptInvite use Actions::User::Veteran end
Builder.new do use Bar use Baz use Bak end Builder.new do use Bar use Bang use Bok end
Builder.new do use Bar use Baz use Bak end Builder.new do use Bar use Bang use Bok end
def foo bar(1) baz(2) bak("fing") end
Builder.new do use Bar, 1 use Baz, 2 use Bak, "fing" end
@stack ||= Builder.new do use Bar use Baz use Bak end @stack.call(1, 2, "fing")
def foo bar(baz(bak("fing"))) end
Builder.new { use Bak use Baz use Bar }.call("fing")