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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/decode/index.rb +16 -9
  4. data/context/coverage.md +325 -0
  5. data/context/getting-started.md +242 -0
  6. data/context/ruby-documentation.md +363 -0
  7. data/lib/decode/comment/attribute.rb +9 -3
  8. data/lib/decode/comment/node.rb +4 -2
  9. data/lib/decode/comment/option.rb +1 -1
  10. data/lib/decode/comment/parameter.rb +12 -6
  11. data/lib/decode/comment/pragma.rb +12 -1
  12. data/lib/decode/comment/raises.rb +1 -1
  13. data/lib/decode/comment/returns.rb +3 -4
  14. data/lib/decode/comment/tag.rb +13 -3
  15. data/lib/decode/comment/tags.rb +17 -2
  16. data/lib/decode/comment/text.rb +4 -1
  17. data/lib/decode/comment/throws.rb +1 -1
  18. data/lib/decode/comment/yields.rb +7 -1
  19. data/lib/decode/definition.rb +54 -42
  20. data/lib/decode/documentation.rb +12 -14
  21. data/lib/decode/index.rb +29 -14
  22. data/lib/decode/language/generic.rb +30 -14
  23. data/lib/decode/language/reference.rb +13 -4
  24. data/lib/decode/language/ruby/alias.rb +41 -0
  25. data/lib/decode/language/ruby/attribute.rb +7 -6
  26. data/lib/decode/language/ruby/block.rb +4 -1
  27. data/lib/decode/language/ruby/call.rb +16 -6
  28. data/lib/decode/language/ruby/class.rb +19 -36
  29. data/lib/decode/language/ruby/code.rb +27 -15
  30. data/lib/decode/language/ruby/constant.rb +9 -8
  31. data/lib/decode/language/ruby/definition.rb +27 -19
  32. data/lib/decode/language/ruby/function.rb +2 -1
  33. data/lib/decode/language/ruby/generic.rb +17 -7
  34. data/lib/decode/language/ruby/method.rb +47 -12
  35. data/lib/decode/language/ruby/module.rb +4 -11
  36. data/lib/decode/language/ruby/parser.rb +358 -207
  37. data/lib/decode/language/ruby/reference.rb +26 -17
  38. data/lib/decode/language/ruby/segment.rb +11 -4
  39. data/lib/decode/language/ruby.rb +4 -2
  40. data/lib/decode/language.rb +2 -2
  41. data/lib/decode/languages.rb +25 -6
  42. data/lib/decode/location.rb +2 -0
  43. data/lib/decode/scope.rb +1 -1
  44. data/lib/decode/segment.rb +6 -5
  45. data/lib/decode/source.rb +12 -4
  46. data/lib/decode/syntax/link.rb +9 -1
  47. data/lib/decode/syntax/match.rb +12 -0
  48. data/lib/decode/syntax/rewriter.rb +10 -0
  49. data/lib/decode/trie.rb +27 -22
  50. data/lib/decode/version.rb +1 -1
  51. data.tar.gz.sig +0 -0
  52. metadata +9 -10
  53. 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 'definition'
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 #{path_name.last}"
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 << #{@name}"
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('::').map(&:to_sym)
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 'definition'
7
- require_relative '../../syntax/link'
6
+ require_relative "definition"
7
+ require_relative "../../syntax/link"
8
8
 
9
- require 'parser/current'
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 = ::Parser::CurrentRuby.parse(text)
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 :send
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
- expression = node.location.selector
44
- range = expression.begin_pos...expression.end_pos
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
- children = node.children[2..-1].each do |node|
51
- traverse(node, into)
60
+ if node.arguments
61
+ node.arguments.arguments.each do |arg_node|
62
+ traverse(arg_node, into)
63
+ end
52
64
  end
53
- when :const
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.name
57
- range = expression.begin_pos...expression.end_pos
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 :begin
62
- node.children.each do |child|
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 'definition'
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.location.name.source
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.line == @node.location.last_line
27
- @node.location.expression.source
28
- elsif @node.children[2].type == :array
29
- "#{@name} = [...]"
30
- elsif @node.children[2].type == :hash
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 '../../definition'
6
+ require_relative "../../definition"
7
7
 
8
8
  module Decode
9
9
  module Language
10
10
  module Ruby
11
- # A Ruby-specific definition.
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
- def initialize(node, *arguments, visibility: nil, **options)
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
- def nested_name
22
- "\##{@name}"
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
- # @attribute [Symbol] The visibility of the definition.
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.line != @node.location.last_line
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.expression
43
- lines = expression.source.lines
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.source_line[/\A\s+/]
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
- expression = @node.location.expression
58
-
59
- Location.new(expression.source_buffer.name, expression.line)
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 'method'
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 'reference'
7
- require_relative 'parser'
8
- require_relative 'code'
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
- # The Ruby language.
15
+ # Represents the Ruby language implementation for parsing and analysis.
14
16
  class Generic < Language::Generic
15
- EXTENSIONS = ['.rb', '.ru']
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 'definition'
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
- @node.location.keyword.join(@node.location.name).source
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
- if node = @node.children[1]
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
- @node.location.keyword.join(
33
- arguments_node.location.expression
34
- ).source
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 'definition'
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 #{path_name.last}"
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 class.
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