Skip to content

Conversation

@Shamaoke
Copy link

Sometimes when exploring or debugging code it's necessary to know where
some method was defined. For this purpose Method#source_location is
used. It reports a filename and a line in the file with a method
definition. However, when using Module#class_eval and
Module#module_eval to dynamically define methods,
the output of Method#source_location is uninformative.

For this reason it's better to add __FILE__ and __LINE__ constants
as the second and third arguments to the aforementioned methods. This
allows Method#source_location to properly locate methods which was
defined dynamically.

Here's some examples:

require 'origin'

class Band
  extend Origin::Forwardable

  select_with :queryable

  def self.queryable
    Object.new.extend Origin::Queryable
  end
end

Band.method(:where).source_location
  # without __FILE__, __LINE__
  #=> ["(eval)", 1]

  # with __FILE__, __LINE__
  #=> ["<...>/lib/origin/forwardable.rb", 53]

require 'origin'

module Finders
  extend Origin::Forwardable

  select_with :queryable

  def queryable
    Object.new.extend Origin::Queryable
  end
end

class Band
  extend Finders
end

Band.method(:where).source_location
  # without __FILE__, __LINE__
  #=> ["(eval)", 1]

  # with __FILE__, __LINE__
  #=> ["<...>/lib/origin/forwardable.rb", 47]

Sometimes when exploring or debugging code it's necessary to know where
some method was defined. For this purpose `Method#source_location` is
used. It reports a filename and a line in the file with a method
definition. However, when using `Module#class_eval` and
`Module#module_eval` to dynamically define methods,
the output of `Method#source_location` is uninformative.

For this reason it's better to add `__FILE__` and `__LINE__` constants
as the second and third arguments to the aforementioned methods. This
allows `Method#source_location` to properly locate methods which was
defined dynamically.

Here's some examples:

    require 'origin'

    class Band
      extend Origin::Forwardable

      select_with :queryable

      def self.queryable
        Object.new.extend Origin::Queryable
      end
    end

    Band.method(:where).source_location
      # without __FILE__, __LINE__
      #=> ["(eval)", 1]

      # with __FILE__, __LINE__
      #=> ["<...>/lib/origin/forwardable.rb", 53]

    require 'origin'

    module Finders
      extend Origin::Forwardable

      select_with :queryable

      def queryable
        Object.new.extend Origin::Queryable
      end
    end

    class Band
      extend Finders
    end

    Band.method(:where).source_location
      # without __FILE__, __LINE__
      #=> ["(eval)", 1]

      # with __FILE__, __LINE__
      #=> ["<...>/lib/origin/forwardable.rb", 47]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be __LINE__ + 1

The actual location of a method which was defined through
`Module#class-/module_eval` with a heredoc as the first argument is one
line below the one reported by `Method#source_location`. For that reason
it needs to increase the __LINE__ value by one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants