tmm1 / ripper-tags

fast, accurate ctags generator for ruby source code using Ripper
MIT License
550 stars 43 forks source link

initialize is magic! #69

Closed kwerle closed 1 year ago

kwerle commented 6 years ago

I'm using ripper-tags for https://github.com/kwerle/ruby_language_server. THANKS! Though I may move away from it to get a little more control over how things work - mostly to get variable declarations included.

It makes me a little sad that the initialize method is reported as just a method, and not something magical like a constructor.

mislav commented 6 years ago

I'm sure you might be able to include variable definitions if you hack around the source code for a bit. We do operate on the entire parsed AST of the source code, which includes variable definitions among other things. But, we ignore them. You're welcome to share your solution if you manage to get them scanned as tags, but we probably wouldn't include that feature as part of default mode, since tags aren't usually generated for variables (otherwise the tags file would get too noisy).

Is there something you would want to see changed about how the initialize method is handled? Constructors in Ruby are literally called initialize. I'm not sure what you're proposing as an alternative. If there's no concrete proposal, I would close this one out. Thank you!

kwerle commented 6 years ago

I've got a solution for variables - essentially I'm running ripper on my own, stealing code from ripper-tags as needed. Eventually I'll probably remove ripper-tags as a resource/requirement.

But your work on this project has been a huge help to mine! Thank you!

I also have a workaround for the new->initialize thing. I catch the request to find the definition for "new" and change the request to "initialize". Works for me.

For ripper-tags I would recommend you catch the declaration of "initialize" and create a copy tag for "new". The same kind of thing you do for "has_one :attribute" handling. I suggest this not because it will be useful for my current project, but because this has frustrated me in the past when using tagging solutions and looking for ".new".

JoshCheek commented 6 years ago

In general, #initialize is probably equivalent to "constructor", so that's probably useful, but it is worth noting that some libs override .new (example).

Also, while I don't see people do things like this, there's nothing preventing them from making their own corollaries to new/initialize, eg:

# Example 1: new/initialize are convention rather than magic
class Class
  def new2(*args, &block)
    allocate.tap { |obj| obj.send :initialize2, *args, &block }
  end
end

class C
  attr_reader :a
  def initialize2(a)
    @a = a
  end
end

C.new2('custom constructor!').a  # => "custom constructor!"

# Example 2: some sort of fancy factory-style constructor
class Class
  def knew(keywords)
    allocate.tap do |obj|
      keywords.each { |k, v| obj.instance_variable_set "@#{k}", v }
    end
  end
end

Object.knew(keyword: 'constructor')
# => #<Object:0x00007fdae28b5f00 @keyword="constructor">
mislav commented 1 year ago

For ripper-tags I would recommend you catch the declaration of "initialize" and create a copy tag for "new".

Sorry for late reply. In Ruby, the semantics of initialize (an instance method) and new (a class method) are different, so I'd prefer to keep them named separately for now, instead of potentially causing confusion by aliasing these two method names.