Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion decode.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = ">= 3.2"

spec.add_dependency "parser"
spec.add_dependency "prism"
end
72 changes: 41 additions & 31 deletions lib/decode/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ module Decode
# A symbol with attached documentation.
class Definition
# Initialize the symbol.
# @parameter name [Symbol] The name of the definition.
# @parameter path [Symbol | Array(Symbol)] The path of the definition relatve to the parent.
# @parameter parent [Symbol] The parent lexical scope.
# @parameter language [Language] The language in which the symbol is defined in.
# @parameter comments [Array(String)] The comments associated with the definition.
def initialize(name, parent: nil, language: parent.language, comments: nil)
@name = name
# @parameter source [Source] The source file containing this definition.
def initialize(path, parent: nil, language: parent&.language, comments: nil, visibility: :public, source: parent&.source)
@path = Array(path).map(&:to_sym)

@parent = parent
@language = language
@source = source

@comments = comments
@visibility = visibility

@path = nil
@full_path = nil
@qualified_name = nil
@nested_name = nil
end

def inspect
Expand All @@ -34,7 +38,27 @@ def inspect
# The symbol name.
# e.g. `:Decode`.
# @attribute [Symbol]
attr :name
def name
@path.last
end

# The path to the definition, relative to the parent.
# @attribute [Array(Symbol)]
attr :path

# The full path to the definition.
def full_path
@full_path ||= begin
if @parent
@parent.full_path + @path
else
@path
end
end
end

# @deprecated Use {#path} instead.
alias lexical_path path

# The parent definition, defining lexical scope.
# @attribute [Definition | Nil]
Expand All @@ -44,6 +68,10 @@ def inspect
# @attribute [Language::Generic]
attr :language

# The source file containing this definition.
# @attribute [Source | Nil]
attr :source

# The comment lines which directly preceeded the definition.
# @attribute [Array(String)]
attr :comments
Expand All @@ -62,17 +90,17 @@ def public?
def qualified_name
@qualified_name ||= begin
if @parent
@parent.qualified_name + self.nested_name
[@parent.qualified_name, self.nested_name].join("::")
else
@name.to_s
self.nested_name
end
end
end

# The name of this definition plus the nesting prefix.
# The name relative to the parent.
# @returns [String]
def nested_name
"::#{@name}"
@nested_name ||= "#{@path.join("::")}"
end

# Does the definition name match the specified prefix?
Expand All @@ -86,28 +114,6 @@ def convert(kind)
raise ArgumentError, "Unable to convert #{self} into #{kind}!"
end

# The lexical scope as an array of names.
# e.g. `[:Decode, :Definition]`
# @returns [Array]
def path
if @path
# Cached version:
@path
elsif @parent
# Merge with parent:
@path = [*@parent.path, *path_name].freeze
else
# At top:
@path = path_name.freeze
end
end

def path_name
[@name]
end

alias lexical_path path

# A short form of the definition.
# e.g. `def short_form`.
#
Expand Down Expand Up @@ -173,5 +179,9 @@ def documentation
def location
nil
end

# The visibility of the definition.
# @attribute [Symbol] :public, :private, :protected
attr_accessor :visibility
end
end
4 changes: 2 additions & 2 deletions lib/decode/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def update(paths)
# $stderr.puts "Adding #{symbol.qualified_name} to #{symbol.lexical_path.join(' -> ')}"

@definitions[symbol.qualified_name] = symbol
@trie.insert(symbol.path, symbol)
@trie.insert(symbol.full_path, symbol)
end
end
end
Expand All @@ -71,7 +71,7 @@ def lookup(reference, relative_to: nil)
if reference.absolute? || relative_to.nil?
lexical_path = []
else
lexical_path = relative_to.path.dup
lexical_path = relative_to.full_path.dup
end

path = reference.path
Expand Down
34 changes: 34 additions & 0 deletions lib/decode/language/ruby/alias.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2020-2024, by Samuel Williams.

require_relative "definition"

module Decode
module Language
module Ruby
# Represents an alias statement, e.g., `alias new_name old_name` or `alias_method :new_name, :old_name`
class Alias < Definition
def initialize(new_name, old_name, **options)
super(new_name, **options)
@old_name = old_name
end

attr :old_name

def short_form
"alias #{self.name} #{@old_name}"
end

def long_form
"alias #{self.name} #{@old_name}"
end

def to_s
"#{self.class.name} #{self.name} -> #{@old_name}"
end
end
end
end
end
10 changes: 5 additions & 5 deletions lib/decode/language/ruby/attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ class Attribute < Definition
# The short form of the attribute.
# e.g. `attr :value`.
def short_form
case @node.type
when :block
case @node&.type
when :block_node
"#{@name} { ... }"
else
@node.location.expression.source
@node&.location&.slice || @name
end
end

def long_form
if @node.location.line == @node.location.last_line
@node.location.expression.source
if @node&.location&.start_line == @node&.location&.end_line
@node.location.slice
else
short_form
end
Expand Down
20 changes: 15 additions & 5 deletions lib/decode/language/ruby/call.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,32 @@ module Ruby
class Call < Definition
# A block can sometimes be a container for other definitions.
def container?
false
@node&.block && @node.block.opening == "do"
end

# The short form of the class.
# e.g. `foo`.
def short_form
@name.to_s
if @node&.block && @node.block.opening == "{"
"#{name} { ... }"
else
name.to_s
end
end

# The long form of the class.
# e.g. `foo(:bar)`.
def long_form
if @node.location.line == @node.location.last_line
@node.location.expression.source
if @node.location.start_line == @node.location.end_line
@node.location.slice
else
self.short_form
# For multiline calls, use the actual call name with arguments
if @node.arguments && @node.arguments.arguments.any?
arg_text = @node.arguments.arguments.map { |arg| arg.location.slice }.join(", ")
"#{@node.name}(#{arg_text})"
else
@node.name.to_s
end
end
end

Expand Down
46 changes: 12 additions & 34 deletions lib/decode/language/ruby/class.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,23 @@ module Language
module Ruby
# A Ruby-specific class.
class Class < Definition
def initialize(*arguments, super_class: nil, **options)
super(*arguments, **options)

@super_class = super_class
end

attr :super_class

# A class is a container for other definitions.
def container?
true
end

def nested_name
"::#{name}"
end

# The short form of the class.
# e.g. `class Animal`.
def short_form
"class #{path_name.last}"
"class #{self.name}"
end

# The long form of the class.
Expand All @@ -35,21 +39,11 @@ def long_form
end
end

def super_class
if super_node = @node.children[1]
super_node.location.expression.source
end
end

# The fully qualified name of the class.
# e.g. `class ::Barnyard::Dog`.
def qualified_form
"class #{self.qualified_name}"
end

def path_name
@name.to_s.split("::").map(&:to_sym)
end
end

# A Ruby-specific singleton class.
Expand All @@ -73,30 +67,14 @@ def nested?
# The short form of the class.
# e.g. `class << self`.
def short_form
"class << #{@name}"
"class << #{self.name}"
end

# The long form is the same as the short form.
alias long_form short_form

def path_name
[:class]
end

# The lexical scope as an array of names.
# e.g. `[:Decode, :Definition]`
# @returns [Array]
def path
if @path
# Cached version:
@path
else
@path = [*self.absolute_path, *self.path_name]
end
end


private

def absolute_path
if @parent
@parent.path
Expand Down
Loading
Loading