RailsConf: Bill Katz - Metaprogramming Writertopia
Posted by Nick Sieger Sat, 24 Jun 2006 17:27:00 GMT
Bill Katz took a code-focused approach to explaining metaprogramming and DSLs.
Resources
- http://www.writertopia.com/developers has an authorization plugin used in writertopia, which is the main focus of this talk.
- http://www.simbiome.org and https://wimtk.org/svn/simbiome contain code for physics based simulation resources.
Bill applies Paul Graham’s quote on bottom-up design and lisp as justification for using Ruby to program DSLs.
Authorization plugin
In search of a better authorization scheme, Bill wanted an elegant syntax using blocks to delineate sections of code that require specific permissions, and a more intuitive way of managing the data surrounding access controls.
current_user.has_role? "moderator"
current_user.has_role? "member", workshop
workshop.accepts_role? "member", user
current_user.is_moderator_of workshop
user.is_eligible_for? campbell_award
Implementing permit
class MeetingController < ApplicationController
permit "rubyists and wanna_be_rubyists", :except => :public_text
We need a class method. Where to put it? How does this work? (Insert pretty diagram of instance, singleton class and superclass here.) Metaclassees are “anonymous”, you don’t see them by looking at class ancestors.
ActionController::Base.send(:include, Authorization::Base)
ActionView::Base.send(:include, Authorization::Base::ControllerInstanceMethods)
Singleton methods from the point of view of the object are the same as
instance methods in the metaclass. See slides on “How do we permit?”
for details. Bill chose to tuck the DSL-related methods into modules
and used self.included
, class_eval
and other goodies to set
up the methods in the correct places. There is more than way to do
this but I suspect Bill chose to do it for purposes of cleanly
separating concerns along the lines of where in the class hierarchy
the methods live.
ActiveRecord::Base.send(:include,
Authorization::ObjectRolesTable::UserExtensions,
Authorization::ObjectRolesTable::ModelExtensions)
This loads an acts_as_authorizable
plugin which, when used in a
model, inserts an accepts_role
family of methods for querying and
setting user roles.
Bill blazed through a whole lot of pretty-looking code here for how to set up the DSL infrastructure. You’ll have to go over to the writertopia developer link to see it. Bill has said he’ll post his slides online as well.
Questions
- Use of
method_missing
-- does that clash withActiveRecord::Base
usage ofmethod_missing
? No, as long as you usesuper
to invoke the next method in the chain, you’re ok. Ruby module inclusion semantics handle this for you. - How to insert the class methods? A discussion started around
ActionController::Base.send(:include, ...)
and There is More Than One Way to Do It.
ActionController::Base.send(:include, Authorization::Base)
class ActionController::Base; include Authorization::Base; end
ActionController::Base.class_eval { include Authorization::Base }
- Question about the class inheritance chain. There are actually two inheritance chains, one for the classes and one for the metaclasses. Resolution at method invocation time travels first to the object’s metaclass, then to the object’s class, then to the superclass of the singleton class, then the class’s superclass, etc. Blech, that makes no sense. Instead, go read Seeing Metaclasses Early.