Hacker News new | past | comments | ask | show | jobs | submit login

Another cool way you could do this: Ruby methods can ask for their caller_locations. They work like this:

    # Source

    $ cat example_for_hn.rb
    def foo
      bar
    end

    def bar
      baz
    end

    def baz
      (c1, c2) = caller_locations.first(2)
      puts "Parent caller:      '#{c1.label}' in '#{c1.path}'"
      puts "Grandparent caller: '#{c2.label}' in '#{c2.path}'"
    end

    foo

    # Demo

    $ ruby example_for_hn.rb
    Parent caller:      'bar' in 'example_for_hn.rb'
    Grandparent caller: 'foo' in 'example_for_hn.rb'
So, you could define a method decorating class method like so:

    module Shitlist
      def shitlist(method_name, whitelist)
        original_method = instance_method(method_name)
        undef_method(method_name)

        define_method(method_name) do |*args, &block|
          call = caller_locations.first
          passes_whitelist = whitelist.any? do |label, file_pattern|
            call.label == label && call.absolute_path.end_with?(file_pattern)
          end

          unless passes_whitelist
            fail "Shitlisted method! Permitted callers: #{whitelist}"
          end

          original_method.bind(self).call(*args, &block)
        end
      end
    end
and then extend classes with it to use the decorator:

    class Example
      extend Shitlist

      def not_on_shitlist
        qux
      end

      def baz
        qux
      end

      def qux
        puts 'Only some methods can call me :)'
      end
      shitlist :qux, 'baz' => 'shitlist.rb'
    end
If I run this example (full source: https://git.io/JLOdV), the non-whitelisted caller throws an error:

    $ ruby shitlist.rb
    Only some methods can call me :)
    Traceback (most recent call last):
      2: from shitlist.rb:44:in `<main>'
      1: from shitlist.rb:25:in `not_on_shitlist'
    shitlist.rb:13:in `block in shitlist': Shitlisted method! Permitted callers: {"baz"=>"shitlist.rb"} (RuntimeError)

---

Of course, you might not want this hijacked method with tracing inside something performance critical. You could always configure the implementation to be a no-op in production.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: