decode 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/decode.gemspec +1 -1
- data/examples/{index → decode-index}/extract.rb +0 -1
- data/gems.rb +2 -0
- data/lib/decode/definition.rb +18 -5
- data/lib/decode/documentation.rb +24 -1
- data/lib/decode/index.rb +19 -1
- data/lib/decode/language.rb +2 -3
- data/lib/decode/language/ruby.rb +9 -2
- data/lib/decode/language/ruby/attribute.rb +5 -0
- data/lib/decode/language/ruby/class.rb +16 -0
- data/lib/decode/language/ruby/constant.rb +5 -0
- data/lib/decode/language/ruby/definition.rb +5 -0
- data/lib/decode/language/ruby/function.rb +2 -0
- data/lib/decode/language/ruby/method.rb +6 -0
- data/lib/decode/language/ruby/module.rb +5 -0
- data/lib/decode/language/ruby/parser.rb +7 -14
- data/lib/decode/language/ruby/reference.rb +7 -0
- data/lib/decode/language/ruby/segment.rb +6 -2
- data/lib/decode/segment.rb +16 -2
- data/lib/decode/source.rb +10 -0
- data/lib/decode/symbol.rb +11 -3
- data/lib/decode/trie.rb +42 -9
- data/lib/decode/version.rb +1 -1
- metadata +3 -6
- data/docs/config.ru +0 -6
- data/docs/gems.locked +0 -137
- data/docs/gems.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1ca1745dcb76b54a61777388aba926d1262967dc51ca7ad633debc369f67d9f
|
4
|
+
data.tar.gz: 4164ca61971b6573b8604767cfdf35766605893f8d63cba44a516d705c0d5093
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b247bcd2d6b0eaacf1bbaa444cd98df314251bca958914793ad455521c9f379233f737e6afeeb31197b76f0ce9876de1887304203eb5487fda113fa4b8eea11
|
7
|
+
data.tar.gz: 72b714cf3ad9b0f7969e23be899ca10186994661d6dbc0bb91bd27a200a6ce4ee18815bca5a7cc355316ea5f53b6ed2d818073b28f61a41caca0dbbf52196623
|
data/README.md
CHANGED
@@ -4,10 +4,12 @@ A Ruby code analysis tool and documentation generator.
|
|
4
4
|
|
5
5
|
## Usage
|
6
6
|
|
7
|
-
Please see the documentation
|
7
|
+
Please see the <a href="https://ioquatix.github.io/decode">project documentation</a> or run it locally using `bake utopia:project:serve`.
|
8
8
|
|
9
9
|
## Contributing
|
10
10
|
|
11
|
+
We welcome contributions to this project.
|
12
|
+
|
11
13
|
1. Fork it
|
12
14
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
13
15
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
data/decode.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
# Specify which files should be added to the gem when it is released.
|
17
17
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
18
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
19
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(docs|test|spec|features)/}) }
|
20
20
|
end
|
21
21
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
# This example demonstrates how to extract symbols using the index. An instance of {Decode::Index} is used for loading symbols from source code files. These symbols are available as a flat list and as a trie structure. You can look up specific symbols using a reference using {Decode::Index:lookup}.
|
4
|
-
|
5
4
|
require_relative '../../lib/decode/index'
|
6
5
|
|
7
6
|
# Firstly, construct the index:
|
data/gems.rb
CHANGED
data/lib/decode/definition.rb
CHANGED
@@ -21,6 +21,7 @@
|
|
21
21
|
require_relative 'symbol'
|
22
22
|
|
23
23
|
module Decode
|
24
|
+
# A symbol with attached documentation.
|
24
25
|
class Definition < Symbol
|
25
26
|
def initialize(kind, name, comments, **options)
|
26
27
|
super(kind, name, **options)
|
@@ -29,44 +30,56 @@ module Decode
|
|
29
30
|
@documentation = nil
|
30
31
|
end
|
31
32
|
|
33
|
+
# The comment lines which directly preceeded the definition.
|
34
|
+
# @attr [Array(String)]
|
32
35
|
attr :comments
|
33
36
|
|
34
|
-
# A short form of the definition
|
37
|
+
# A short form of the definition.
|
38
|
+
# e.g. `def short_form`.
|
39
|
+
#
|
35
40
|
# @return [String | nil]
|
36
41
|
def short_form
|
37
42
|
end
|
38
43
|
|
39
|
-
# A long form of the definition
|
44
|
+
# A long form of the definition.
|
45
|
+
# e.g. `def initialize(kind, name, comments, **options)`.
|
46
|
+
#
|
40
47
|
# @return [String | nil]
|
41
48
|
def long_form
|
42
49
|
self.short_form
|
43
50
|
end
|
44
51
|
|
45
|
-
# A long form which uses the qualified name if possible.
|
52
|
+
# A long form which uses the qualified name if possible.
|
53
|
+
# Defaults to {long_form}.
|
54
|
+
#
|
46
55
|
# @return [String | nil]
|
47
56
|
def qualified_form
|
48
57
|
self.long_form
|
49
58
|
end
|
50
59
|
|
51
60
|
# The full text of the definition.
|
61
|
+
#
|
52
62
|
# @return [String | nil]
|
53
63
|
def text
|
54
64
|
end
|
55
65
|
|
56
66
|
# Whether this definition can contain nested definitions.
|
67
|
+
#
|
57
68
|
# @return [Boolean]
|
58
69
|
def container?
|
59
70
|
false
|
60
71
|
end
|
61
72
|
|
62
73
|
# Whether this represents a single entity to be documented (along with it's contents).
|
74
|
+
#
|
63
75
|
# @return [Boolean]
|
64
76
|
def nested?
|
65
77
|
container?
|
66
78
|
end
|
67
79
|
|
68
|
-
#
|
69
|
-
#
|
80
|
+
# Structured access to the definitions comments.
|
81
|
+
#
|
82
|
+
# @return [Documentation | Nil] A `Documentation` if this definition has comments.
|
70
83
|
def documentation
|
71
84
|
if @comments&.any?
|
72
85
|
@documentation ||= Documentation.new(@comments)
|
data/lib/decode/documentation.rb
CHANGED
@@ -19,13 +19,26 @@
|
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
21
|
module Decode
|
22
|
+
# Structured access to a set of comment lines.
|
22
23
|
class Documentation
|
23
|
-
|
24
|
+
# Initialize the documenation with an array of comments, within a specific language.
|
25
|
+
#
|
26
|
+
# @param comments [Array(String)] An array of comment lines.
|
27
|
+
# @param language [Language] The language in which the comments were extracted.
|
28
|
+
def initialize(comments, language = nil)
|
24
29
|
@comments = comments
|
30
|
+
@language = language
|
25
31
|
end
|
26
32
|
|
33
|
+
# The language in which the documentation was extracted from.
|
34
|
+
attr :language
|
35
|
+
|
27
36
|
DESCRIPTION = /\A\s*([^@\s].*)?\z/
|
28
37
|
|
38
|
+
# The text-only lines of the comment block.
|
39
|
+
#
|
40
|
+
# @yield [String]
|
41
|
+
# @return [Enumerable]
|
29
42
|
def description
|
30
43
|
return to_enum(:description) unless block_given?
|
31
44
|
|
@@ -52,6 +65,11 @@ module Decode
|
|
52
65
|
|
53
66
|
ATTRIBUTE = /\A\s*@(?<name>.*?)\s+(?<value>.*?)\z/
|
54
67
|
|
68
|
+
# The attribute lines of the comment block.
|
69
|
+
# e.g. `@return [String]`.
|
70
|
+
#
|
71
|
+
# @yield [String]
|
72
|
+
# @return [Enumerable]
|
55
73
|
def attributes
|
56
74
|
return to_enum(:attributes) unless block_given?
|
57
75
|
|
@@ -64,6 +82,11 @@ module Decode
|
|
64
82
|
|
65
83
|
PARAMETER = /\A\s*@param\s+(?<name>.*?)\s+\[(?<type>.*?)\]\s+(?<details>.*?)\z/
|
66
84
|
|
85
|
+
# The parameter lines of the comment block.
|
86
|
+
# e.g. `@param value [String] The value.`
|
87
|
+
#
|
88
|
+
# @yield [String]
|
89
|
+
# @return [Enumerable]
|
67
90
|
def parameters
|
68
91
|
return to_enum(:parameters) unless block_given?
|
69
92
|
|
data/lib/decode/index.rb
CHANGED
@@ -22,7 +22,9 @@ require_relative 'source'
|
|
22
22
|
require_relative 'trie'
|
23
23
|
|
24
24
|
module Decode
|
25
|
+
# A list of symbols organised for quick lookup and lexical enumeration.
|
25
26
|
class Index
|
27
|
+
# Initialize an empty index.
|
26
28
|
def initialize
|
27
29
|
@sources = {}
|
28
30
|
@symbols = {}
|
@@ -31,11 +33,23 @@ module Decode
|
|
31
33
|
@trie = Trie.new
|
32
34
|
end
|
33
35
|
|
36
|
+
# All source files that have been parsed.
|
37
|
+
# @attr [Array(Source)]
|
34
38
|
attr :sources
|
39
|
+
|
40
|
+
# All symbols which have been parsed.
|
41
|
+
# @attr [Array(Symbol)]
|
35
42
|
attr :symbols
|
36
43
|
|
44
|
+
# A (prefix) trie of lexically scoped symbols.
|
45
|
+
# @attr [Trie]
|
46
|
+
|
37
47
|
attr :trie
|
38
48
|
|
49
|
+
# Updates the index by parsing the specified files.
|
50
|
+
# All extracted symbols are merged into the existing index.
|
51
|
+
#
|
52
|
+
# @param paths [Array(String)] The source file paths.
|
39
53
|
def update(paths)
|
40
54
|
paths.each do |path|
|
41
55
|
source = Source.new(path)
|
@@ -49,6 +63,10 @@ module Decode
|
|
49
63
|
end
|
50
64
|
end
|
51
65
|
|
66
|
+
# Lookup the specified reference and return matching symbols.
|
67
|
+
#
|
68
|
+
# @param reference [Reference] The reference to match.
|
69
|
+
# @param relative_to [Symbol] Lookup the reference relative to the scope of this symbol.
|
52
70
|
def lookup(reference, relative_to: nil)
|
53
71
|
if reference.absolute? || relative_to.nil?
|
54
72
|
lexical_path = []
|
@@ -59,7 +77,7 @@ module Decode
|
|
59
77
|
path = reference.path
|
60
78
|
|
61
79
|
while true
|
62
|
-
node = @trie.
|
80
|
+
node = @trie.lookup(lexical_path)
|
63
81
|
|
64
82
|
if node.children[path.first]
|
65
83
|
if target = node.lookup(path)
|
data/lib/decode/language.rb
CHANGED
@@ -21,13 +21,12 @@
|
|
21
21
|
require_relative 'language/ruby'
|
22
22
|
|
23
23
|
module Decode
|
24
|
+
# Language specific parsers and symbols.
|
24
25
|
module Language
|
25
26
|
def self.detect(path)
|
26
27
|
case File.extname(path)
|
27
|
-
when '.rb'
|
28
|
+
when '.rb', '.ru'
|
28
29
|
return Language::Ruby
|
29
|
-
else
|
30
|
-
raise ArgumentError, "Could not determine language for #{path}!"
|
31
30
|
end
|
32
31
|
end
|
33
32
|
end
|
data/lib/decode/language/ruby.rb
CHANGED
@@ -23,7 +23,10 @@ require_relative 'ruby/parser'
|
|
23
23
|
|
24
24
|
module Decode
|
25
25
|
module Language
|
26
|
+
# The Ruby language.
|
26
27
|
module Ruby
|
28
|
+
# The canoical name of the language for use in output formatting.
|
29
|
+
# e.g. source code highlighting.
|
27
30
|
def self.name
|
28
31
|
"ruby"
|
29
32
|
end
|
@@ -37,6 +40,7 @@ module Decode
|
|
37
40
|
defs: '.',
|
38
41
|
}.freeze
|
39
42
|
|
43
|
+
# Generate a language-specific fully qualified name.
|
40
44
|
def self.join(symbols, absolute = true)
|
41
45
|
buffer = String.new
|
42
46
|
|
@@ -53,18 +57,21 @@ module Decode
|
|
53
57
|
return buffer
|
54
58
|
end
|
55
59
|
|
60
|
+
# Generate a language-specific reference.
|
56
61
|
def self.reference(value)
|
57
62
|
Reference.new(value)
|
58
63
|
end
|
59
64
|
|
60
65
|
# Parse the input yielding symbols.
|
61
|
-
# @
|
66
|
+
# @block `{|definition| ...}`
|
67
|
+
# @yield definition [Definition]
|
62
68
|
def self.symbols_for(input, &block)
|
63
69
|
Parser.new.symbols_for(input, &block)
|
64
70
|
end
|
65
71
|
|
66
72
|
# Parse the input yielding interleaved comments and code segments.
|
67
|
-
# @
|
73
|
+
# @block `{|segment| ...}`
|
74
|
+
# @yield segment [Segment]
|
68
75
|
def self.segments_for(input, &block)
|
69
76
|
Parser.new.segments_for(input, &block)
|
70
77
|
end
|
@@ -23,11 +23,16 @@ require_relative 'definition'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby-specific attribute.
|
26
27
|
class Attribute < Definition
|
28
|
+
# The keyword that defined the attribute.
|
29
|
+
# @return [String]
|
27
30
|
def keyword
|
28
31
|
@node.children[1]
|
29
32
|
end
|
30
33
|
|
34
|
+
# The short form of the attribute.
|
35
|
+
# e.g. `attr :value`.
|
31
36
|
def short_form
|
32
37
|
"#{self.keyword} #{@name.inspect}"
|
33
38
|
end
|
@@ -23,15 +23,21 @@ require_relative 'definition'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby-specific class.
|
26
27
|
class Class < Definition
|
28
|
+
# A class is a container for other definitions.
|
27
29
|
def container?
|
28
30
|
true
|
29
31
|
end
|
30
32
|
|
33
|
+
# The short form of the class.
|
34
|
+
# e.g. `class Animal`.
|
31
35
|
def short_form
|
32
36
|
"class #{@name}"
|
33
37
|
end
|
34
38
|
|
39
|
+
# The long form of the class.
|
40
|
+
# e.g. `class Dog < Animal`.
|
35
41
|
def long_form
|
36
42
|
if super_node = @node.children[1]
|
37
43
|
@node.location.keyword.join(
|
@@ -42,24 +48,34 @@ module Decode
|
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
51
|
+
# The fully qualified name of the class.
|
52
|
+
# e.g. `class ::Barnyard::Dog`.
|
45
53
|
def qualified_form
|
46
54
|
"class #{self.qualified_name}"
|
47
55
|
end
|
48
56
|
end
|
49
57
|
|
58
|
+
# A Ruby-specific singleton class.
|
50
59
|
class Singleton < Definition
|
60
|
+
# A singleton class is a container for other definitions.
|
61
|
+
# @return [Boolean]
|
51
62
|
def container?
|
52
63
|
true
|
53
64
|
end
|
54
65
|
|
66
|
+
# Typically, a singleton class does not contain other definitions.
|
67
|
+
# @return [Boolean]
|
55
68
|
def nested?
|
56
69
|
false
|
57
70
|
end
|
58
71
|
|
72
|
+
# The short form of the class.
|
73
|
+
# e.g. `class << (self)`.
|
59
74
|
def short_form
|
60
75
|
"class << #{@name}"
|
61
76
|
end
|
62
77
|
|
78
|
+
# The long form is the same as the short form.
|
63
79
|
alias long_form short_form
|
64
80
|
end
|
65
81
|
end
|
@@ -23,11 +23,16 @@ require_relative 'definition'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby-specific constant.
|
26
27
|
class Constant < Definition
|
28
|
+
# The short form of the constant.
|
29
|
+
# e.g. `NAME`.
|
27
30
|
def short_form
|
28
31
|
@node.location.name.source
|
29
32
|
end
|
30
33
|
|
34
|
+
# The long form of the constant.
|
35
|
+
# e.g. `NAME = "Alice"`.
|
31
36
|
def long_form
|
32
37
|
if @node.location.line == @node.location.last_line
|
33
38
|
@node.location.expression.source
|
@@ -23,15 +23,20 @@ require_relative '../../definition'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby-specific definition.
|
26
27
|
class Definition < Decode::Definition
|
28
|
+
# Initialize the definition from the syntax tree node.
|
27
29
|
def initialize(kind, name, comments, node, **options)
|
28
30
|
super(kind, name, comments, **options)
|
29
31
|
|
30
32
|
@node = node
|
31
33
|
end
|
32
34
|
|
35
|
+
# The parser syntax tree node.
|
33
36
|
attr :node
|
34
37
|
|
38
|
+
# The source code associated with the definition.
|
39
|
+
# @return [String]
|
35
40
|
def text
|
36
41
|
@node.location.expression.source
|
37
42
|
end
|
@@ -23,7 +23,9 @@ require_relative 'method'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby-specific function.
|
26
27
|
class Function < Method
|
28
|
+
# The node which contains the function arguments.
|
27
29
|
def arguments_node
|
28
30
|
if node = @node.children[2]
|
29
31
|
if node.location.expression
|
@@ -23,11 +23,15 @@ require_relative 'definition'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby-specific method.
|
26
27
|
class Method < Definition
|
28
|
+
# The short form of the method.
|
29
|
+
# e.g. `def puts`.
|
27
30
|
def short_form
|
28
31
|
@node.location.keyword.join(@node.location.name).source
|
29
32
|
end
|
30
33
|
|
34
|
+
# The node which contains the function arguments.
|
31
35
|
def arguments_node
|
32
36
|
if node = @node.children[1]
|
33
37
|
if node.location.expression
|
@@ -36,6 +40,8 @@ module Decode
|
|
36
40
|
end
|
37
41
|
end
|
38
42
|
|
43
|
+
# The long form of the method.
|
44
|
+
# e.g. `def puts(*lines, separator: "\n")`.
|
39
45
|
def long_form
|
40
46
|
if arguments_node = self.arguments_node
|
41
47
|
@node.location.keyword.join(
|
@@ -23,15 +23,20 @@ require_relative 'definition'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby-specific module.
|
26
27
|
class Module < Definition
|
28
|
+
# A module is a container for other definitions.
|
27
29
|
def container?
|
28
30
|
true
|
29
31
|
end
|
30
32
|
|
33
|
+
# The short form of the module.
|
34
|
+
# e.g. `module Barnyard`.
|
31
35
|
def short_form
|
32
36
|
"module #{@name}"
|
33
37
|
end
|
34
38
|
|
39
|
+
# The long form is the same as the short form.
|
35
40
|
alias long_form short_form
|
36
41
|
end
|
37
42
|
end
|
@@ -32,16 +32,11 @@ require_relative 'segment'
|
|
32
32
|
module Decode
|
33
33
|
module Language
|
34
34
|
module Ruby
|
35
|
+
# The Ruby source code parser.
|
35
36
|
class Parser
|
36
|
-
|
37
|
-
@parser = parser
|
38
|
-
end
|
39
|
-
|
37
|
+
# Extract symbols from the given input file.
|
40
38
|
def symbols_for(input, &block)
|
41
|
-
|
42
|
-
buffer.source = input.read
|
43
|
-
|
44
|
-
top, comments = @parser.parse_with_comments(buffer)
|
39
|
+
top, comments = ::Parser::CurrentRuby.parse_with_comments(input.read)
|
45
40
|
|
46
41
|
if top
|
47
42
|
walk_symbols(top, comments, &block)
|
@@ -162,11 +157,9 @@ module Decode
|
|
162
157
|
end
|
163
158
|
end
|
164
159
|
|
160
|
+
# Extract segments from the given input file.
|
165
161
|
def segments_for(input, &block)
|
166
|
-
|
167
|
-
buffer.source = input.read
|
168
|
-
|
169
|
-
top, comments = @parser.parse_with_comments(buffer)
|
162
|
+
top, comments = ::Parser::CurrentRuby.parse_with_comments(input.read)
|
170
163
|
|
171
164
|
# We delete any leading comments:
|
172
165
|
line = 0
|
@@ -193,11 +186,11 @@ module Decode
|
|
193
186
|
if segment.nil?
|
194
187
|
segment = Segment.new(
|
195
188
|
extract_comments_for(child, comments),
|
196
|
-
child
|
189
|
+
Ruby, child
|
197
190
|
)
|
198
191
|
elsif next_comments = extract_comments_for(child, comments)
|
199
192
|
yield segment if segment
|
200
|
-
segment = Segment.new(next_comments, child)
|
193
|
+
segment = Segment.new(next_comments, Ruby, child)
|
201
194
|
else
|
202
195
|
segment.expand(child)
|
203
196
|
end
|
@@ -21,12 +21,15 @@
|
|
21
21
|
module Decode
|
22
22
|
module Language
|
23
23
|
module Ruby
|
24
|
+
# An Ruby-specific reference which can be resolved to zero or more symbols.
|
24
25
|
class Reference
|
25
26
|
KIND = {
|
26
27
|
':' => :def,
|
27
28
|
'.' => :defs,
|
28
29
|
}.freeze
|
29
30
|
|
31
|
+
# Initialize the reference.
|
32
|
+
# @param value [String] The string value of the reference.
|
30
33
|
def initialize(value)
|
31
34
|
@value = value
|
32
35
|
|
@@ -34,12 +37,15 @@ module Decode
|
|
34
37
|
@kind = nil
|
35
38
|
end
|
36
39
|
|
40
|
+
# Whether the reference starts at the base of the lexical tree.
|
37
41
|
def absolute?
|
38
42
|
@value.start_with?('::')
|
39
43
|
end
|
40
44
|
|
41
45
|
METHOD = /\A(?<scope>.*?)?(?<kind>:|\.)(?<name>.+?)\z/
|
42
46
|
|
47
|
+
# The lexical path of the reference.
|
48
|
+
# @return [Array(String)]
|
43
49
|
def path
|
44
50
|
if @path.nil?
|
45
51
|
@path = @value.split(/::/)
|
@@ -65,6 +71,7 @@ module Decode
|
|
65
71
|
return @path
|
66
72
|
end
|
67
73
|
|
74
|
+
# The kind of symbol to match.
|
68
75
|
def kind
|
69
76
|
self.path
|
70
77
|
|
@@ -23,20 +23,24 @@ require_relative '../../segment'
|
|
23
23
|
module Decode
|
24
24
|
module Language
|
25
25
|
module Ruby
|
26
|
+
# A Ruby specific code segment.
|
26
27
|
class Segment < Decode::Segment
|
27
|
-
def initialize(comments, node, **options)
|
28
|
-
super(comments, **options)
|
28
|
+
def initialize(comments, language, node, **options)
|
29
|
+
super(comments, language, **options)
|
29
30
|
|
30
31
|
@node = node
|
31
32
|
@expression = node.location.expression
|
32
33
|
end
|
33
34
|
|
35
|
+
# The parser syntax tree node.
|
34
36
|
attr :node
|
35
37
|
|
36
38
|
def expand(node)
|
37
39
|
@expression = @expression.join(node.location.expression)
|
38
40
|
end
|
39
41
|
|
42
|
+
# The source code trailing the comments.
|
43
|
+
# @return [String | nil]
|
40
44
|
def code
|
41
45
|
@expression.source
|
42
46
|
end
|
data/lib/decode/segment.rb
CHANGED
@@ -21,18 +21,32 @@
|
|
21
21
|
require_relative 'documentation'
|
22
22
|
|
23
23
|
module Decode
|
24
|
+
# A chunk of code with an optional preceeding comment block.
|
25
|
+
#
|
26
|
+
# ~~~ ruby
|
27
|
+
# # Get the first segment from a source file:
|
28
|
+
# segment = source.segments.first
|
29
|
+
# ~~~
|
30
|
+
#
|
24
31
|
class Segment
|
25
|
-
def initialize(comments)
|
32
|
+
def initialize(comments, language)
|
26
33
|
@comments = comments
|
34
|
+
@language = language
|
27
35
|
end
|
28
36
|
|
37
|
+
# The preceeding comments.
|
38
|
+
# @attr [Array(String)]
|
29
39
|
attr :comments
|
30
40
|
|
41
|
+
# The language of the code attached to this segment.
|
42
|
+
# @attr [Language]
|
43
|
+
attr :language
|
44
|
+
|
31
45
|
# An interface for accsssing the documentation of the definition.
|
32
46
|
# @return [Documentation | nil] A `Documentation` if this definition has comments.
|
33
47
|
def documentation
|
34
48
|
if @comments&.any?
|
35
|
-
@documentation ||= Documentation.new(@comments)
|
49
|
+
@documentation ||= Documentation.new(@comments, @language)
|
36
50
|
end
|
37
51
|
end
|
38
52
|
|
data/lib/decode/source.rb
CHANGED
@@ -22,11 +22,21 @@ require_relative 'language'
|
|
22
22
|
|
23
23
|
module Decode
|
24
24
|
class Source
|
25
|
+
def self.for?(path)
|
26
|
+
if language = Language.detect(path)
|
27
|
+
self.new(path, language)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
25
31
|
def initialize(path, language = nil)
|
26
32
|
@path = path
|
27
33
|
@language = language || Language.detect(path)
|
28
34
|
end
|
29
35
|
|
36
|
+
attr :path
|
37
|
+
|
38
|
+
attr :language
|
39
|
+
|
30
40
|
def open(&block)
|
31
41
|
File.open(@path, &block)
|
32
42
|
end
|
data/lib/decode/symbol.rb
CHANGED
@@ -21,10 +21,16 @@
|
|
21
21
|
require_relative 'documentation'
|
22
22
|
|
23
23
|
module Decode
|
24
|
+
# A language agnostic lexical scope.
|
24
25
|
Key = Struct.new(:kind, :name)
|
25
26
|
|
26
27
|
# A named element which represents some significant element of some kind in a computer program.
|
27
28
|
class Symbol
|
29
|
+
# Initialize the symbol.
|
30
|
+
# @param kind [Symbol] The kind of symbol.
|
31
|
+
# @param name [Symbol] The name of the symbol.
|
32
|
+
# @param parent [Symbol] The parent lexical scope.
|
33
|
+
# @param language [Language] The language in which the symbol is defined in.
|
28
34
|
def initialize(kind, name, parent: nil, language: parent.language)
|
29
35
|
@kind = kind
|
30
36
|
@name = name
|
@@ -45,10 +51,12 @@ module Decode
|
|
45
51
|
"\#<#{self.class} #{@kind} #{qualified_name}>"
|
46
52
|
end
|
47
53
|
|
48
|
-
# The kind of symbol
|
54
|
+
# The kind of symbol.
|
55
|
+
# e.g. `:module`.
|
49
56
|
attr :kind
|
50
57
|
|
51
|
-
# The symbol name
|
58
|
+
# The symbol name.
|
59
|
+
# e.g. `:Decode`.
|
52
60
|
attr :name
|
53
61
|
|
54
62
|
# The parent symbol, defining lexical scope.
|
@@ -62,7 +70,7 @@ module Decode
|
|
62
70
|
@qualified_name ||= @language.join(self.path).freeze
|
63
71
|
end
|
64
72
|
|
65
|
-
# The lexical scope as
|
73
|
+
# The lexical scope which is an array of lexical {Key} instances as generated by {key}.
|
66
74
|
# @return [Array]
|
67
75
|
def path
|
68
76
|
if @path
|
data/lib/decode/trie.rb
CHANGED
@@ -21,16 +21,27 @@
|
|
21
21
|
require_relative 'source'
|
22
22
|
|
23
23
|
module Decode
|
24
|
+
# A prefix-trie data structure for fast lexical lookups.
|
24
25
|
class Trie
|
26
|
+
# A single node in the trie.
|
25
27
|
class Node
|
26
28
|
def initialize
|
27
29
|
@values = nil
|
28
30
|
@children = Hash.new
|
29
31
|
end
|
30
32
|
|
33
|
+
# A mutable array of all values that terminate at this node.
|
34
|
+
# @attr [Array]
|
31
35
|
attr_accessor :values
|
36
|
+
|
37
|
+
# A hash table of all children nodes, indexed by name.
|
38
|
+
# @attr [Hash(String, Node)]
|
32
39
|
attr :children
|
33
40
|
|
41
|
+
# Look up a lexical path starting at this node.
|
42
|
+
#
|
43
|
+
# @param path [Array(String)] The path to resolve.
|
44
|
+
# @return [Node | Nil]
|
34
45
|
def lookup(path, index = 0)
|
35
46
|
if index < path.size
|
36
47
|
if child = @children[path[index]]
|
@@ -41,6 +52,15 @@ module Decode
|
|
41
52
|
end
|
42
53
|
end
|
43
54
|
|
55
|
+
# Traverse the trie from this node.
|
56
|
+
# Invoke `descend.call` to traverse the children of the current node.
|
57
|
+
#
|
58
|
+
# @param path [Array(String)] The current lexical path.
|
59
|
+
#
|
60
|
+
# @block `{|path, node, descend| descend.call}`
|
61
|
+
# @yield path [Array(String)] The current lexical path.
|
62
|
+
# @yield node [Node] The current node which is being traversed.
|
63
|
+
# @yield descend [Proc] The recursive method for traversing children.
|
44
64
|
def traverse(path = [], &block)
|
45
65
|
yield(path, self, ->{
|
46
66
|
@children.each do |name, node|
|
@@ -50,14 +70,18 @@ module Decode
|
|
50
70
|
end
|
51
71
|
end
|
52
72
|
|
53
|
-
|
54
|
-
|
73
|
+
# Initialize an empty trie.
|
55
74
|
def initialize
|
56
75
|
@root = Node.new
|
57
76
|
end
|
58
77
|
|
78
|
+
# The root of the trie.
|
79
|
+
# @attr [Node]
|
59
80
|
attr :root
|
60
81
|
|
82
|
+
# Insert the specified value at the given path into the trie.
|
83
|
+
# @param path [Array(String)] The lexical path where the value will be inserted.
|
84
|
+
# @param value [Object] The value to insert.
|
61
85
|
def insert(path, value)
|
62
86
|
node = @root
|
63
87
|
|
@@ -68,26 +92,35 @@ module Decode
|
|
68
92
|
(node.values ||= []) << value
|
69
93
|
end
|
70
94
|
|
95
|
+
# Lookup the values at the specified path.
|
96
|
+
#
|
97
|
+
# @param path [Array(String)] The lexical path which contains the values.
|
98
|
+
# @return [Array(Object) | Nil] The values that existed (or not) at the specified path.
|
71
99
|
def lookup(path)
|
72
100
|
@root.lookup(path)
|
73
101
|
end
|
74
102
|
|
75
|
-
#
|
76
|
-
#
|
103
|
+
# Enumerate all lexical scopes under the specified path.
|
104
|
+
#
|
105
|
+
# @block `{|path, values| ...}`
|
106
|
+
# @yield path [Array(String)] The lexical path.
|
107
|
+
# @yield values [Array(Object)] The values that exist at the given path.
|
77
108
|
def each(path = [], &block)
|
78
109
|
if node = @root.lookup(path)
|
79
|
-
node.traverse
|
110
|
+
node.traverse do |path, node, descend|
|
111
|
+
yield path, node.values
|
112
|
+
|
113
|
+
descend.call
|
114
|
+
end
|
80
115
|
end
|
81
116
|
end
|
82
117
|
|
118
|
+
# Traverse the trie.
|
119
|
+
# See {Node:traverse} for details.
|
83
120
|
def traverse(path = [], &block)
|
84
121
|
if node = @root.lookup(path)
|
85
122
|
node.traverse(&block)
|
86
123
|
end
|
87
124
|
end
|
88
|
-
|
89
|
-
def match(path, &block)
|
90
|
-
@root.lookup(path)
|
91
|
-
end
|
92
125
|
end
|
93
126
|
end
|
data/lib/decode/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: decode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -120,10 +120,7 @@ files:
|
|
120
120
|
- ".rspec"
|
121
121
|
- README.md
|
122
122
|
- decode.gemspec
|
123
|
-
-
|
124
|
-
- docs/gems.locked
|
125
|
-
- docs/gems.rb
|
126
|
-
- examples/index/extract.rb
|
123
|
+
- examples/decode-index/extract.rb
|
127
124
|
- gems.rb
|
128
125
|
- lib/decode.rb
|
129
126
|
- lib/decode/definition.rb
|
data/docs/config.ru
DELETED
data/docs/gems.locked
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: ../../../socketry/utopia-project
|
3
|
-
specs:
|
4
|
-
utopia-project (0.1.0)
|
5
|
-
decode
|
6
|
-
falcon
|
7
|
-
kramdown
|
8
|
-
kramdown-parser-gfm
|
9
|
-
rackula
|
10
|
-
thread-local
|
11
|
-
utopia (~> 2.14)
|
12
|
-
utopia-gallery
|
13
|
-
|
14
|
-
PATH
|
15
|
-
remote: ..
|
16
|
-
specs:
|
17
|
-
decode (0.6.0)
|
18
|
-
parser
|
19
|
-
|
20
|
-
GEM
|
21
|
-
remote: https://rubygems.org/
|
22
|
-
specs:
|
23
|
-
ast (2.4.0)
|
24
|
-
async (1.25.2)
|
25
|
-
console (~> 1.0)
|
26
|
-
nio4r (~> 2.3)
|
27
|
-
timers (~> 4.1)
|
28
|
-
async-container (0.16.4)
|
29
|
-
async (~> 1.0)
|
30
|
-
async-io (~> 1.26)
|
31
|
-
process-group
|
32
|
-
async-http (0.52.0)
|
33
|
-
async (~> 1.25)
|
34
|
-
async-io (~> 1.28)
|
35
|
-
async-pool (~> 0.2)
|
36
|
-
protocol-http (~> 0.18.0)
|
37
|
-
protocol-http1 (~> 0.12.0)
|
38
|
-
protocol-http2 (~> 0.14.0)
|
39
|
-
async-http-cache (0.2.0)
|
40
|
-
async-http (~> 0.51)
|
41
|
-
async-io (1.29.0)
|
42
|
-
async (~> 1.14)
|
43
|
-
async-pool (0.3.0)
|
44
|
-
async (~> 1.25)
|
45
|
-
build-environment (1.13.0)
|
46
|
-
concurrent-ruby (1.1.6)
|
47
|
-
console (1.8.2)
|
48
|
-
falcon (0.36.4)
|
49
|
-
async (~> 1.13)
|
50
|
-
async-container (~> 0.16.0)
|
51
|
-
async-http (~> 0.52.0)
|
52
|
-
async-http-cache (~> 0.2.0)
|
53
|
-
async-io (~> 1.22)
|
54
|
-
build-environment (~> 1.13)
|
55
|
-
localhost (~> 1.1)
|
56
|
-
process-metrics (~> 0.2.0)
|
57
|
-
rack (>= 1.0)
|
58
|
-
samovar (~> 2.1)
|
59
|
-
ffi (1.12.2)
|
60
|
-
http-accept (2.1.1)
|
61
|
-
kramdown (2.2.1)
|
62
|
-
rexml
|
63
|
-
kramdown-parser-gfm (1.1.0)
|
64
|
-
kramdown (~> 2.0)
|
65
|
-
localhost (1.1.6)
|
66
|
-
mail (2.7.1)
|
67
|
-
mini_mime (>= 0.1.1)
|
68
|
-
mapping (1.1.1)
|
69
|
-
mime-types (3.3.1)
|
70
|
-
mime-types-data (~> 3.2015)
|
71
|
-
mime-types-data (3.2020.0425)
|
72
|
-
mini_mime (1.0.2)
|
73
|
-
msgpack (1.3.3)
|
74
|
-
nio4r (2.5.2)
|
75
|
-
parser (2.7.1.2)
|
76
|
-
ast (~> 2.4.0)
|
77
|
-
process-group (1.2.1)
|
78
|
-
process-terminal (~> 0.2.0)
|
79
|
-
process-metrics (0.2.1)
|
80
|
-
console (~> 1.8)
|
81
|
-
samovar (~> 2.1)
|
82
|
-
process-terminal (0.2.0)
|
83
|
-
ffi
|
84
|
-
protocol-hpack (1.4.2)
|
85
|
-
protocol-http (0.18.0)
|
86
|
-
protocol-http1 (0.12.0)
|
87
|
-
protocol-http (~> 0.18)
|
88
|
-
protocol-http2 (0.14.0)
|
89
|
-
protocol-hpack (~> 1.4)
|
90
|
-
protocol-http (~> 0.18)
|
91
|
-
rack (2.2.2)
|
92
|
-
rackula (1.1.0)
|
93
|
-
falcon (~> 0.34)
|
94
|
-
samovar (~> 2.1)
|
95
|
-
variant
|
96
|
-
rake (13.0.1)
|
97
|
-
rake-compiler (1.1.0)
|
98
|
-
rake
|
99
|
-
rexml (3.2.4)
|
100
|
-
samovar (2.1.4)
|
101
|
-
console (~> 1.0)
|
102
|
-
mapping (~> 1.0)
|
103
|
-
thread-local (1.0.0)
|
104
|
-
timers (4.3.0)
|
105
|
-
trenni (3.9.0)
|
106
|
-
rake-compiler
|
107
|
-
utopia (2.15.1)
|
108
|
-
concurrent-ruby (~> 1.0)
|
109
|
-
console (~> 1.0)
|
110
|
-
http-accept (~> 2.1)
|
111
|
-
mail (~> 2.6)
|
112
|
-
mime-types (~> 3.0)
|
113
|
-
msgpack
|
114
|
-
rack (~> 2.2)
|
115
|
-
samovar (~> 2.1)
|
116
|
-
trenni (~> 3.0)
|
117
|
-
variant (~> 0.1)
|
118
|
-
utopia-gallery (2.5.0)
|
119
|
-
trenni (~> 3.9)
|
120
|
-
utopia (~> 2.0)
|
121
|
-
vips-thumbnail (~> 1.6)
|
122
|
-
variant (0.1.1)
|
123
|
-
thread-local
|
124
|
-
vips (8.9.1)
|
125
|
-
ffi (~> 1.9)
|
126
|
-
vips-thumbnail (1.6.0)
|
127
|
-
vips (~> 8.9)
|
128
|
-
|
129
|
-
PLATFORMS
|
130
|
-
ruby
|
131
|
-
|
132
|
-
DEPENDENCIES
|
133
|
-
decode!
|
134
|
-
utopia-project!
|
135
|
-
|
136
|
-
BUNDLED WITH
|
137
|
-
2.1.4
|