decode 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bake/decode/index.rb +16 -9
- data/context/coverage.md +325 -0
- data/context/getting-started.md +242 -0
- data/context/ruby-documentation.md +363 -0
- data/lib/decode/comment/attribute.rb +9 -3
- data/lib/decode/comment/node.rb +4 -2
- data/lib/decode/comment/option.rb +1 -1
- data/lib/decode/comment/parameter.rb +12 -6
- data/lib/decode/comment/pragma.rb +12 -1
- data/lib/decode/comment/raises.rb +1 -1
- data/lib/decode/comment/returns.rb +3 -4
- data/lib/decode/comment/tag.rb +13 -3
- data/lib/decode/comment/tags.rb +17 -2
- data/lib/decode/comment/text.rb +4 -1
- data/lib/decode/comment/throws.rb +1 -1
- data/lib/decode/comment/yields.rb +7 -1
- data/lib/decode/definition.rb +54 -42
- data/lib/decode/documentation.rb +12 -14
- data/lib/decode/index.rb +29 -14
- data/lib/decode/language/generic.rb +30 -14
- data/lib/decode/language/reference.rb +13 -4
- data/lib/decode/language/ruby/alias.rb +41 -0
- data/lib/decode/language/ruby/attribute.rb +7 -6
- data/lib/decode/language/ruby/block.rb +4 -1
- data/lib/decode/language/ruby/call.rb +16 -6
- data/lib/decode/language/ruby/class.rb +19 -36
- data/lib/decode/language/ruby/code.rb +27 -15
- data/lib/decode/language/ruby/constant.rb +9 -8
- data/lib/decode/language/ruby/definition.rb +27 -19
- data/lib/decode/language/ruby/function.rb +2 -1
- data/lib/decode/language/ruby/generic.rb +17 -7
- data/lib/decode/language/ruby/method.rb +47 -12
- data/lib/decode/language/ruby/module.rb +4 -11
- data/lib/decode/language/ruby/parser.rb +358 -207
- data/lib/decode/language/ruby/reference.rb +26 -17
- data/lib/decode/language/ruby/segment.rb +11 -4
- data/lib/decode/language/ruby.rb +4 -2
- data/lib/decode/language.rb +2 -2
- data/lib/decode/languages.rb +25 -6
- data/lib/decode/location.rb +2 -0
- data/lib/decode/scope.rb +1 -1
- data/lib/decode/segment.rb +6 -5
- data/lib/decode/source.rb +12 -4
- data/lib/decode/syntax/link.rb +9 -1
- data/lib/decode/syntax/match.rb +12 -0
- data/lib/decode/syntax/rewriter.rb +10 -0
- data/lib/decode/trie.rb +27 -22
- data/lib/decode/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +9 -10
- metadata.gz.sig +0 -0
@@ -3,26 +3,34 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "definition"
|
7
7
|
|
8
8
|
module Decode
|
9
9
|
module Language
|
10
10
|
module Ruby
|
11
11
|
# A Ruby-specific class.
|
12
12
|
class Class < Definition
|
13
|
+
# Initialize a new class definition.
|
14
|
+
# @parameter arguments [Array] The definition arguments.
|
15
|
+
# @parameter super_class [String] The super class name.
|
16
|
+
# @parameter options [Hash] Additional options.
|
17
|
+
def initialize(*arguments, super_class: nil, **options)
|
18
|
+
super(*arguments, **options)
|
19
|
+
|
20
|
+
@super_class = super_class
|
21
|
+
end
|
22
|
+
|
23
|
+
attr :super_class
|
24
|
+
|
13
25
|
# A class is a container for other definitions.
|
14
26
|
def container?
|
15
27
|
true
|
16
28
|
end
|
17
29
|
|
18
|
-
def nested_name
|
19
|
-
"::#{name}"
|
20
|
-
end
|
21
|
-
|
22
30
|
# The short form of the class.
|
23
31
|
# e.g. `class Animal`.
|
24
32
|
def short_form
|
25
|
-
"class #{
|
33
|
+
"class #{self.name}"
|
26
34
|
end
|
27
35
|
|
28
36
|
# The long form of the class.
|
@@ -35,25 +43,16 @@ module Decode
|
|
35
43
|
end
|
36
44
|
end
|
37
45
|
|
38
|
-
def super_class
|
39
|
-
if super_node = @node.children[1]
|
40
|
-
super_node.location.expression.source
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
46
|
# The fully qualified name of the class.
|
45
47
|
# e.g. `class ::Barnyard::Dog`.
|
46
48
|
def qualified_form
|
47
49
|
"class #{self.qualified_name}"
|
48
50
|
end
|
49
|
-
|
50
|
-
def path_name
|
51
|
-
@name.to_s.split('::').map(&:to_sym)
|
52
|
-
end
|
53
51
|
end
|
54
52
|
|
55
53
|
# A Ruby-specific singleton class.
|
56
54
|
class Singleton < Definition
|
55
|
+
# Generate a nested name for the singleton class.
|
57
56
|
def nested_name
|
58
57
|
"::class"
|
59
58
|
end
|
@@ -73,35 +72,19 @@ module Decode
|
|
73
72
|
# The short form of the class.
|
74
73
|
# e.g. `class << self`.
|
75
74
|
def short_form
|
76
|
-
"class << #{
|
75
|
+
"class << #{self.name}"
|
77
76
|
end
|
78
77
|
|
79
78
|
# The long form is the same as the short form.
|
80
79
|
alias long_form short_form
|
81
|
-
|
82
|
-
def path_name
|
83
|
-
[:class]
|
84
|
-
end
|
85
|
-
|
86
|
-
# The lexical scope as an array of names.
|
87
|
-
# e.g. `[:Decode, :Definition]`
|
88
|
-
# @returns [Array]
|
89
|
-
def path
|
90
|
-
if @path
|
91
|
-
# Cached version:
|
92
|
-
@path
|
93
|
-
else
|
94
|
-
@path = [*self.absolute_path, *self.path_name]
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
80
|
+
|
98
81
|
private
|
99
|
-
|
82
|
+
|
100
83
|
def absolute_path
|
101
84
|
if @parent
|
102
85
|
@parent.path
|
103
86
|
else
|
104
|
-
@name.to_s.split(
|
87
|
+
@name.to_s.split("::").map(&:to_sym)
|
105
88
|
end
|
106
89
|
end
|
107
90
|
end
|
@@ -3,19 +3,24 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "definition"
|
7
|
+
require_relative "../../syntax/link"
|
8
8
|
|
9
|
-
require
|
9
|
+
require "prism"
|
10
10
|
|
11
11
|
module Decode
|
12
12
|
module Language
|
13
13
|
module Ruby
|
14
14
|
# A Ruby-specific block of code.
|
15
15
|
class Code
|
16
|
+
# Initialize a new code block.
|
17
|
+
# @parameter text [String] The code text.
|
18
|
+
# @parameter index [Index] The index to use.
|
19
|
+
# @parameter relative_to [Definition] The definition this code is relative to.
|
20
|
+
# @parameter language [Language] The language of the code.
|
16
21
|
def initialize(text, index, relative_to: nil, language: relative_to&.language)
|
17
22
|
@text = text
|
18
|
-
@root = ::
|
23
|
+
@root = ::Prism.parse(text)
|
19
24
|
@index = index
|
20
25
|
@relative_to = relative_to
|
21
26
|
@language = language
|
@@ -25,9 +30,11 @@ module Decode
|
|
25
30
|
|
26
31
|
attr :language
|
27
32
|
|
33
|
+
# Extract definitions from the code.
|
34
|
+
# @parameter into [Array] The array to extract definitions into.
|
28
35
|
def extract(into = [])
|
29
36
|
if @index
|
30
|
-
traverse(@root, into)
|
37
|
+
traverse(@root.value, into)
|
31
38
|
end
|
32
39
|
|
33
40
|
return into
|
@@ -37,29 +44,34 @@ module Decode
|
|
37
44
|
|
38
45
|
def traverse(node, into)
|
39
46
|
case node&.type
|
40
|
-
when :
|
47
|
+
when :program_node
|
48
|
+
traverse(node.statements, into)
|
49
|
+
when :call_node
|
41
50
|
if reference = Reference.from_const(node, @language)
|
42
51
|
if definition = @index.lookup(reference, relative_to: @relative_to)
|
43
|
-
|
44
|
-
|
52
|
+
# Use message_loc for the method name, not the entire call
|
53
|
+
expression = node.message_loc
|
54
|
+
range = expression.start_offset...expression.end_offset
|
45
55
|
into << Syntax::Link.new(range, definition)
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
49
59
|
# Extract constants from arguments:
|
50
|
-
|
51
|
-
|
60
|
+
if node.arguments
|
61
|
+
node.arguments.arguments.each do |arg_node|
|
62
|
+
traverse(arg_node, into)
|
63
|
+
end
|
52
64
|
end
|
53
|
-
when :
|
65
|
+
when :constant_read_node
|
54
66
|
if reference = Reference.from_const(node, @language)
|
55
67
|
if definition = @index.lookup(reference, relative_to: @relative_to)
|
56
|
-
expression = node.location
|
57
|
-
range = expression.
|
68
|
+
expression = node.location
|
69
|
+
range = expression.start_offset...expression.end_offset
|
58
70
|
into << Syntax::Link.new(range, definition)
|
59
71
|
end
|
60
72
|
end
|
61
|
-
when :
|
62
|
-
node.
|
73
|
+
when :statements_node
|
74
|
+
node.body.each do |child|
|
63
75
|
traverse(child, into)
|
64
76
|
end
|
65
77
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "definition"
|
7
7
|
|
8
8
|
module Decode
|
9
9
|
module Language
|
@@ -13,9 +13,10 @@ module Decode
|
|
13
13
|
# The short form of the constant.
|
14
14
|
# e.g. `NAME`.
|
15
15
|
def short_form
|
16
|
-
@node.
|
16
|
+
@node.name.to_s
|
17
17
|
end
|
18
18
|
|
19
|
+
# Generate a nested name for the constant.
|
19
20
|
def nested_name
|
20
21
|
"::#{@name}"
|
21
22
|
end
|
@@ -23,12 +24,12 @@ module Decode
|
|
23
24
|
# The long form of the constant.
|
24
25
|
# e.g. `NAME = "Alice"`.
|
25
26
|
def long_form
|
26
|
-
if @node.location.
|
27
|
-
@node.location.
|
28
|
-
elsif @node.
|
29
|
-
"#{@name} = [...]"
|
30
|
-
elsif @node.
|
31
|
-
"#{@name} = {...}"
|
27
|
+
if @node.location.start_line == @node.location.end_line
|
28
|
+
@node.location.slice
|
29
|
+
elsif @node.value&.type == :array_node
|
30
|
+
"#{@node.name} = [...]"
|
31
|
+
elsif @node.value&.type == :hash_node
|
32
|
+
"#{@node.name} = {...}"
|
32
33
|
else
|
33
34
|
self.short_form
|
34
35
|
end
|
@@ -3,60 +3,68 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "../../definition"
|
7
7
|
|
8
8
|
module Decode
|
9
9
|
module Language
|
10
10
|
module Ruby
|
11
|
-
#
|
11
|
+
# Represents a Ruby-specific definition extracted from source code.
|
12
12
|
class Definition < Decode::Definition
|
13
13
|
# Initialize the definition from the syntax tree node.
|
14
|
-
|
14
|
+
# @parameter arguments [Array] Arguments passed to the parent class.
|
15
|
+
# @parameter visibility [Symbol] The visibility of the definition (:public, :private, :protected).
|
16
|
+
# @parameter node [Parser::AST::Node] The syntax tree node representing this definition.
|
17
|
+
# @parameter options [Hash] Additional options passed to the parent class.
|
18
|
+
def initialize(*arguments, visibility: nil, node: nil, **options)
|
15
19
|
super(*arguments, **options)
|
16
20
|
|
17
|
-
@node = node
|
18
21
|
@visibility = visibility
|
22
|
+
@node = node
|
19
23
|
end
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
# @attribute [Parser::AST::Node] The parser syntax tree node.
|
25
|
+
# The parser syntax tree node.
|
26
|
+
# @attribute [Parser::AST::Node] The AST node representing this definition.
|
26
27
|
attr :node
|
27
28
|
|
28
|
-
#
|
29
|
+
# The visibility of the definition.
|
30
|
+
# @attribute [Symbol] The visibility level (:public, :private, or :protected).
|
29
31
|
attr_accessor :visibility
|
30
32
|
|
33
|
+
# Check if this definition is public.
|
34
|
+
# @returns [Boolean] True if the definition is public.
|
31
35
|
def public?
|
32
36
|
@visibility == :public
|
33
37
|
end
|
34
38
|
|
39
|
+
# Check if this definition spans multiple lines.
|
40
|
+
# @returns [Boolean] True if the definition spans multiple lines.
|
35
41
|
def multiline?
|
36
|
-
@node.location.
|
42
|
+
@node.location.start_line != @node.location.end_line
|
37
43
|
end
|
38
44
|
|
39
45
|
# The source code associated with the definition.
|
40
|
-
# @returns [String]
|
46
|
+
# @returns [String] The source code text for this definition.
|
41
47
|
def text
|
42
|
-
expression = @node.location
|
43
|
-
lines = expression.
|
48
|
+
expression = @node.location
|
49
|
+
lines = expression.slice.lines
|
44
50
|
if lines.count == 1
|
45
51
|
return lines.first
|
46
52
|
else
|
47
|
-
if indentation = expression.
|
53
|
+
if indentation = expression.slice.lines.first[/\A\s+/]
|
48
54
|
# Remove all the indentation:
|
49
|
-
lines.each{|line| line.sub!(indentation,
|
55
|
+
lines.each{|line| line.sub!(indentation, "")}
|
50
56
|
end
|
51
57
|
|
52
58
|
return lines.join
|
53
59
|
end
|
54
60
|
end
|
55
61
|
|
62
|
+
# Get the location of this definition.
|
63
|
+
# @returns [Location | Nil] The location object if source is available.
|
56
64
|
def location
|
57
|
-
|
58
|
-
|
59
|
-
|
65
|
+
if @source
|
66
|
+
Location.new(@source.path, @node.location.start_line)
|
67
|
+
end
|
60
68
|
end
|
61
69
|
end
|
62
70
|
end
|
@@ -3,13 +3,14 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "method"
|
7
7
|
|
8
8
|
module Decode
|
9
9
|
module Language
|
10
10
|
module Ruby
|
11
11
|
# A Ruby-specific function.
|
12
12
|
class Function < Method
|
13
|
+
# Generate a nested name for the function.
|
13
14
|
def nested_name
|
14
15
|
".#{@name}"
|
15
16
|
end
|
@@ -3,27 +3,37 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2021-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
6
|
+
require_relative "reference"
|
7
|
+
require_relative "parser"
|
8
|
+
require_relative "code"
|
9
|
+
|
10
|
+
require_relative "../generic"
|
9
11
|
|
10
12
|
module Decode
|
11
13
|
module Language
|
12
14
|
module Ruby
|
13
|
-
#
|
15
|
+
# Represents the Ruby language implementation for parsing and analysis.
|
14
16
|
class Generic < Language::Generic
|
15
|
-
EXTENSIONS = [
|
17
|
+
EXTENSIONS = [".rb", ".ru"]
|
16
18
|
|
19
|
+
# Get the parser for Ruby source code.
|
20
|
+
# @returns [Parser] The Ruby parser instance.
|
17
21
|
def parser
|
18
22
|
@parser ||= Parser.new(self)
|
19
23
|
end
|
20
24
|
|
21
|
-
# Generate a language-specific reference.
|
22
|
-
# @parameter identifier [String] A valid identifier.
|
25
|
+
# Generate a language-specific reference for Ruby.
|
26
|
+
# @parameter identifier [String] A valid Ruby identifier.
|
27
|
+
# @returns [Reference] A Ruby-specific reference object.
|
23
28
|
def reference_for(identifier)
|
24
29
|
Reference.new(identifier, self)
|
25
30
|
end
|
26
31
|
|
32
|
+
# Generate a code representation with syntax highlighting and link resolution.
|
33
|
+
# @parameter text [String] The source code text to format.
|
34
|
+
# @parameter index [Index] The index for resolving references.
|
35
|
+
# @parameter relative_to [Definition] The definition to resolve relative references from.
|
36
|
+
# @returns [Code] A formatted code object with syntax highlighting.
|
27
37
|
def code_for(text, index, relative_to: nil)
|
28
38
|
Code.new(text, index, relative_to: relative_to, language: self)
|
29
39
|
end
|
@@ -3,35 +3,57 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "definition"
|
7
7
|
|
8
8
|
module Decode
|
9
9
|
module Language
|
10
10
|
module Ruby
|
11
11
|
# A Ruby-specific method.
|
12
12
|
class Method < Definition
|
13
|
+
# Initialize a new method definition.
|
14
|
+
# @parameter arguments [Array] The definition arguments.
|
15
|
+
# @parameter receiver [String] The method receiver (for class methods).
|
16
|
+
# @parameter options [Hash] Additional options.
|
17
|
+
def initialize(*arguments, receiver: nil, **options)
|
18
|
+
super(*arguments, **options)
|
19
|
+
@receiver = receiver
|
20
|
+
end
|
21
|
+
|
22
|
+
attr :receiver
|
23
|
+
|
24
|
+
# Generate a nested name for the method.
|
25
|
+
def nested_name
|
26
|
+
if @receiver
|
27
|
+
".#{self.name}"
|
28
|
+
else
|
29
|
+
"##{self.name}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
13
33
|
# The short form of the method.
|
14
|
-
# e.g. `def puts`.
|
34
|
+
# e.g. `def puts` or `def self.puts`.
|
15
35
|
def short_form
|
16
|
-
@
|
36
|
+
if @receiver
|
37
|
+
"def #{@receiver}.#{@node.name}"
|
38
|
+
else
|
39
|
+
"def #{@node.name}"
|
40
|
+
end
|
17
41
|
end
|
18
42
|
|
19
43
|
# The node which contains the function arguments.
|
20
44
|
def arguments_node
|
21
|
-
|
22
|
-
if node.location.expression
|
23
|
-
return node
|
24
|
-
end
|
25
|
-
end
|
45
|
+
@node.parameters
|
26
46
|
end
|
27
47
|
|
28
48
|
# The long form of the method.
|
29
|
-
# e.g. `def puts(*lines, separator: "\n")`.
|
49
|
+
# e.g. `def puts(*lines, separator: "\n")` or `def self.puts(*lines, separator: "\n")`.
|
30
50
|
def long_form
|
31
51
|
if arguments_node = self.arguments_node
|
32
|
-
@
|
33
|
-
arguments_node.location.
|
34
|
-
|
52
|
+
if @receiver
|
53
|
+
"def #{@receiver}.#{@node.name}(#{arguments_node.location.slice})"
|
54
|
+
else
|
55
|
+
"def #{@node.name}(#{arguments_node.location.slice})"
|
56
|
+
end
|
35
57
|
else
|
36
58
|
self.short_form
|
37
59
|
end
|
@@ -43,6 +65,19 @@ module Decode
|
|
43
65
|
self.qualified_name
|
44
66
|
end
|
45
67
|
|
68
|
+
# Override the qualified_name method to handle method name joining correctly
|
69
|
+
def qualified_name
|
70
|
+
@qualified_name ||= begin
|
71
|
+
if @parent
|
72
|
+
[@parent.qualified_name, self.nested_name].join("")
|
73
|
+
else
|
74
|
+
self.nested_name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Convert the method to a different kind of definition.
|
80
|
+
# @parameter kind [Symbol] The kind to convert to.
|
46
81
|
def convert(kind)
|
47
82
|
case kind
|
48
83
|
when :attribute
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "definition"
|
7
7
|
|
8
8
|
module Decode
|
9
9
|
module Language
|
@@ -15,29 +15,22 @@ module Decode
|
|
15
15
|
true
|
16
16
|
end
|
17
17
|
|
18
|
-
def nested_name
|
19
|
-
"::#{name}"
|
20
|
-
end
|
21
|
-
|
22
18
|
# The short form of the module.
|
23
19
|
# e.g. `module Barnyard`.
|
24
20
|
def short_form
|
25
|
-
"module #{
|
21
|
+
"module #{self.name}"
|
26
22
|
end
|
27
23
|
|
24
|
+
# Generate a long form representation of the module.
|
28
25
|
def long_form
|
29
26
|
qualified_form
|
30
27
|
end
|
31
28
|
|
32
|
-
# The fully qualified name of the
|
29
|
+
# The fully qualified name of the module.
|
33
30
|
# e.g. `module ::Barnyard::Dog`.
|
34
31
|
def qualified_form
|
35
32
|
"module #{self.qualified_name}"
|
36
33
|
end
|
37
|
-
|
38
|
-
def path_name
|
39
|
-
@name.to_s.split('::').map(&:to_sym)
|
40
|
-
end
|
41
34
|
end
|
42
35
|
end
|
43
36
|
end
|