Search code examples
rubysinatraruby-1.9.3before-filter

implement a rails before_filter in ruby without rails


I am using g a logger in all of my classes. I want each msg to begin with class name and method name like so:

Class_name::Method_name

this is what i'm doing now :

class FOO

 def initialize
 end

 def bar
   msg_prefix = "#{self.class}::#{__method__}"
   ... some code ...
   @logeer = "#{msg_prefix} msg ..."
 end

 def bar2
   msg_prefix = "#{self.class}::#{__method__}"
   ... some code 2 ...
   @logeer = "#{msg_prefix} msg2 ..."
 end

end

i want to use a before_filter like in rails to prevent duplicity, I am using sinatra but the classes are plain old ruby 1.9.3 classes

ideas??


Solution

  • You can get a callback on any method being created with Module#method_added, alias the old method, then define a new method that calls the before_filter method first. Here's my (extremely) rough first concept:

    module Filter
      def before_filter name
        @@filter = name
      end
    
      def method_added name
        return if @filtering # Don't add filters to original_ methods
        return if @@filter == name # Don't filter filters
        return if name == :initialize
    
        @filtering = true
    
        alias_method :"original_#{name}", name
        define_method name do |*args|
          self.send @@filter, name
          self.send :"original_#{name}", *args
        end
        @filtering = false
      end
    end
    
    class FilterTest
      extend Filter
      before_filter :prepare_logs
    
      def baz
        puts "#{@msg_prefix} message goes here"
      end
    
      def prepare_logs name
        @msg_prefix = "#{self.class}::#{name}"
      end
    end
    
    ft = FilterTest.new
    ft.baz
    

    By using __method__ like you were in create_prefix, you'll get the name of the filter method, not the original method, so you have to pass the method name in. There might be other solutions to make that a bit cleaner.