decode 0.9.0 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 813979836080a611db0650430359874b554250326fc391d453405b01a6137fc5
4
- data.tar.gz: a0335e5e13a888f0b19a06f3010063bf840be1cf399134e37d112dcdba98dd9b
3
+ metadata.gz: fd42fdf97af9b39dd08a24eb01bf8e165f5f5b5af934024789d14e68d007d68b
4
+ data.tar.gz: dd47038eaacad07b6a00a28cd7942ccf397fbee3f86245277658bbc8988e3189
5
5
  SHA512:
6
- metadata.gz: f155904d306e546b857cca49e8ef25590de20253febff28f82a390ee6dd09e5bd412a5966578f4cf419848bc7282a34c64d1b8c98ce9ce28f6a92a821c46b298
7
- data.tar.gz: 3e65b213a410b83b48dc30e1a89f49f5a013b0eeb414bd41d91510d9069921b95f7bfb74195b011ab42c1c7dc6c8ddb53935f40bdf97d068e2c3d8a79b07f5b1
6
+ metadata.gz: 39d1157dab86e1200394f89e19b8996f974ce62fee7843cebe1b9a4f9637cdf68629d91d431f2be7af77697443fefed8ad80b60b9297e284ca4ad65c42355990
7
+ data.tar.gz: 1385928ab0ec53208ddaffb9acceb2c2da1bd976ecea650291564e30b0d7191aded0f2d2b6946815a16f48534602f3ac365ed0c143e831bdb052704907bc2eb1
@@ -18,22 +18,87 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require_relative 'symbol'
22
-
23
21
  module Decode
24
22
  # A symbol with attached documentation.
25
- class Definition < Symbol
26
- def initialize(kind, name, comments, **options)
27
- super(kind, name, **options)
23
+ class Definition
24
+ # Initialize the symbol.
25
+ # @param name [Symbol] The name of the definition.
26
+ # @param parent [Symbol] The parent lexical scope.
27
+ # @param language [Language] The language in which the symbol is defined in.
28
+ # @param comments [Array(String)] The comments associated with the definition.
29
+ def initialize(name, parent: nil, language: parent.language, comments: nil)
30
+ @name = name
28
31
 
29
32
  @comments = comments
33
+ @language = language
34
+ @parent = parent
35
+
36
+ @path = nil
37
+ @qualified_name = nil
30
38
  @documentation = nil
31
39
  end
32
40
 
41
+ def to_s
42
+ "\#<#{self.class} #{qualified_name}>"
43
+ end
44
+
45
+ # The symbol name.
46
+ # e.g. `:Decode`.
47
+ attr :name
48
+
49
+ # The parent symbol, defining lexical scope.
50
+ attr :parent
51
+
52
+ # The language the symbol is defined within.
53
+ attr :language
54
+
33
55
  # The comment lines which directly preceeded the definition.
34
56
  # @attr [Array(String)]
35
57
  attr :comments
36
58
 
59
+ # The qualified name is an absolute name which includes any and all namespacing.
60
+ # @return [String]
61
+ def qualified_name
62
+ @qualified_name ||= begin
63
+ if @parent
64
+ @parent.qualified_name + self.nested_name
65
+ else
66
+ @name.to_s
67
+ end
68
+ end
69
+ end
70
+
71
+ # The name of this definition plus the nesting prefix.
72
+ # @return [String]
73
+ def nested_name
74
+ "::#{@name}"
75
+ end
76
+
77
+ def start_with?(prefix)
78
+ self.nested_name.start_with?(prefix)
79
+ end
80
+
81
+ def convert(kind)
82
+ raise ArgumentError, "Unable to convert #{self} into #{kind}!"
83
+ end
84
+
85
+ # The lexical scope which is an array of lexical {Key} instances as generated by {key}.
86
+ # @return [Array]
87
+ def path
88
+ if @path
89
+ # Cached version:
90
+ @path
91
+ elsif @parent
92
+ # Merge with parent:
93
+ @path = [*@parent.path, @name]
94
+ else
95
+ # At top:
96
+ @path = [@name]
97
+ end
98
+ end
99
+
100
+ alias lexical_path path
101
+
37
102
  # A short form of the definition.
38
103
  # e.g. `def short_form`.
39
104
  #
data/lib/decode/index.rb CHANGED
@@ -22,12 +22,12 @@ 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
+ # A list of definitions organised for quick lookup and lexical enumeration.
26
26
  class Index
27
27
  # Initialize an empty index.
28
28
  def initialize
29
29
  @sources = {}
30
- @symbols = {}
30
+ @definitions = {}
31
31
 
32
32
  # This is essentially a prefix tree:
33
33
  @trie = Trie.new
@@ -37,17 +37,17 @@ module Decode
37
37
  # @attr [Array(Source)]
38
38
  attr :sources
39
39
 
40
- # All symbols which have been parsed.
40
+ # All definitions which have been parsed.
41
41
  # @attr [Array(Symbol)]
42
- attr :symbols
42
+ attr :definitions
43
43
 
44
- # A (prefix) trie of lexically scoped symbols.
44
+ # A (prefix) trie of lexically scoped definitions.
45
45
  # @attr [Trie]
46
46
 
47
47
  attr :trie
48
48
 
49
49
  # Updates the index by parsing the specified files.
50
- # All extracted symbols are merged into the existing index.
50
+ # All extracted definitions are merged into the existing index.
51
51
  #
52
52
  # @param paths [Array(String)] The source file paths.
53
53
  def update(paths)
@@ -55,23 +55,24 @@ module Decode
55
55
  source = Source.new(path)
56
56
  @sources[path] = Source.new(path)
57
57
 
58
- source.symbols do |symbol|
59
- @symbols[symbol.qualified_name] = symbol
58
+ source.definitions do |symbol|
59
+ # $stderr.puts "Adding #{symbol.qualified_name} to #{symbol.lexical_path.join(' -> ')}"
60
60
 
61
- @trie.insert(symbol.lexical_path, symbol)
61
+ @definitions[symbol.qualified_name] = symbol
62
+ @trie.insert(symbol.path, symbol)
62
63
  end
63
64
  end
64
65
  end
65
66
 
66
- # Lookup the specified reference and return matching symbols.
67
+ # Lookup the specified reference and return matching definitions.
67
68
  #
68
69
  # @param reference [Reference] The reference to match.
69
- # @param relative_to [Symbol] Lookup the reference relative to the scope of this symbol.
70
+ # @param relative_to [Definition] Lookup the reference relative to the scope of this definition.
70
71
  def lookup(reference, relative_to: nil)
71
72
  if reference.absolute? || relative_to.nil?
72
73
  lexical_path = []
73
74
  else
74
- lexical_path = relative_to.lexical_path
75
+ lexical_path = relative_to.path
75
76
  end
76
77
 
77
78
  path = reference.path
@@ -81,11 +82,7 @@ module Decode
81
82
 
82
83
  if node.children[path.first]
83
84
  if target = node.lookup(path)
84
- if reference.kind
85
- return target.values.select{|symbol| symbol.kind == reference.kind}
86
- else
87
- return target.values
88
- end
85
+ return reference.best(target.values)
89
86
  else
90
87
  return nil
91
88
  end
@@ -25,16 +25,23 @@ module Decode
25
25
  module Ruby
26
26
  # A Ruby-specific attribute.
27
27
  class Attribute < Definition
28
- # The keyword that defined the attribute.
29
- # @return [String]
30
- def keyword
31
- @node.children[1]
32
- end
33
-
34
28
  # The short form of the attribute.
35
29
  # e.g. `attr :value`.
36
30
  def short_form
37
- "#{self.keyword} #{@name.inspect}"
31
+ case @node.type
32
+ when :block
33
+ "#{@name} { ... }"
34
+ else
35
+ @node.location.expression.source
36
+ end
37
+ end
38
+
39
+ def long_form
40
+ if @node.location.line == @node.location.last_line
41
+ @node.location.expression.source
42
+ else
43
+ short_form
44
+ end
38
45
  end
39
46
  end
40
47
  end
@@ -0,0 +1,72 @@
1
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'definition'
22
+
23
+ module Decode
24
+ module Language
25
+ module Ruby
26
+ # A Ruby-specific block which might carry other definitions.
27
+ class Block < Definition
28
+ # A block can sometimes be a container for other definitions.
29
+ def container?
30
+ true
31
+ end
32
+
33
+ def nested_name
34
+ ".#{name}"
35
+ end
36
+
37
+ # The short form of the block.
38
+ # e.g. `foo`.
39
+ def short_form
40
+ @name.to_s
41
+ end
42
+
43
+ # The long form of the block.
44
+ # e.g. `foo(:bar)`.
45
+ def long_form
46
+ if @node.location.line == @node.location.last_line
47
+ @node.location.expression.source
48
+ else
49
+ @node.children[0].location.expression.source
50
+ end
51
+ end
52
+
53
+ # The fully qualified name of the block.
54
+ # e.g. `::Barnyard::foo`.
55
+ def qualified_form
56
+ self.qualified_name
57
+ end
58
+
59
+ def convert(kind)
60
+ case kind
61
+ when :attr
62
+ Attribute.new(@node, @name,
63
+ comments: @comments, parent: @parent, language: @language
64
+ )
65
+ else
66
+ super
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'definition'
22
+
23
+ module Decode
24
+ module Language
25
+ module Ruby
26
+ # A Ruby-specific block which might carry other definitions.
27
+ class Call < Definition
28
+ # A block can sometimes be a container for other definitions.
29
+ def container?
30
+ false
31
+ end
32
+
33
+ # The short form of the class.
34
+ # e.g. `foo`.
35
+ def short_form
36
+ @name.to_s
37
+ end
38
+
39
+ # The long form of the class.
40
+ # e.g. `foo(:bar)`.
41
+ def long_form
42
+ if @node.location.line == @node.location.last_line
43
+ @node.location.expression.source
44
+ else
45
+ self.short_form
46
+ end
47
+ end
48
+
49
+ # The fully qualified name of the block.
50
+ # e.g. `class ::Barnyard::Dog`.
51
+ def qualified_form
52
+ self.qualified_name
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -30,6 +30,10 @@ module Decode
30
30
  true
31
31
  end
32
32
 
33
+ def nested_name
34
+ "::#{name}"
35
+ end
36
+
33
37
  # The short form of the class.
34
38
  # e.g. `class Animal`.
35
39
  def short_form
@@ -31,6 +31,10 @@ module Decode
31
31
  @node.location.name.source
32
32
  end
33
33
 
34
+ def nested_name
35
+ "::#{@name}"
36
+ end
37
+
34
38
  # The long form of the constant.
35
39
  # e.g. `NAME = "Alice"`.
36
40
  def long_form
@@ -26,12 +26,16 @@ module Decode
26
26
  # A Ruby-specific definition.
27
27
  class Definition < Decode::Definition
28
28
  # Initialize the definition from the syntax tree node.
29
- def initialize(kind, name, comments, node, **options)
30
- super(kind, name, comments, **options)
29
+ def initialize(node, *arguments, **options)
30
+ super(*arguments, **options)
31
31
 
32
32
  @node = node
33
33
  end
34
34
 
35
+ def nested_name
36
+ "\##{@name}"
37
+ end
38
+
35
39
  # The parser syntax tree node.
36
40
  attr :node
37
41
 
@@ -25,6 +25,10 @@ module Decode
25
25
  module Ruby
26
26
  # A Ruby-specific function.
27
27
  class Function < Method
28
+ def nested_name
29
+ ".#{@name}"
30
+ end
31
+
28
32
  # The node which contains the function arguments.
29
33
  def arguments_node
30
34
  if node = @node.children[2]
@@ -51,6 +51,17 @@ module Decode
51
51
  self.short_form
52
52
  end
53
53
  end
54
+
55
+ def convert(kind)
56
+ case kind
57
+ when :attr
58
+ Attribute.new(@node, @name,
59
+ comments: @comments, parent: @parent, language: @language
60
+ )
61
+ else
62
+ super
63
+ end
64
+ end
54
65
  end
55
66
  end
56
67
  end
@@ -30,6 +30,10 @@ module Decode
30
30
  true
31
31
  end
32
32
 
33
+ def nested_name
34
+ "::#{name}"
35
+ end
36
+
33
37
  # The short form of the module.
34
38
  # e.g. `module Barnyard`.
35
39
  def short_form
@@ -20,7 +20,11 @@
20
20
 
21
21
  require 'parser/current'
22
22
 
23
+ require_relative '../../scope'
24
+
23
25
  require_relative 'attribute'
26
+ require_relative 'block'
27
+ require_relative 'call'
24
28
  require_relative 'class'
25
29
  require_relative 'constant'
26
30
  require_relative 'function'
@@ -34,12 +38,12 @@ module Decode
34
38
  module Ruby
35
39
  # The Ruby source code parser.
36
40
  class Parser
37
- # Extract symbols from the given input file.
38
- def symbols_for(input, &block)
41
+ # Extract definitions from the given input file.
42
+ def definitions_for(input, &block)
39
43
  top, comments = ::Parser::CurrentRuby.parse_with_comments(input.read)
40
44
 
41
45
  if top
42
- walk_symbols(top, comments, &block)
46
+ walk_definitions(top, comments, &block)
43
47
  end
44
48
  end
45
49
 
@@ -69,68 +73,69 @@ module Decode
69
73
  end
70
74
 
71
75
  # Walk over the syntax tree and extract relevant definitions with their associated comments.
72
- def walk_symbols(node, comments, parent = nil, &block)
76
+ def walk_definitions(node, comments, parent = nil, &block)
73
77
  case node.type
74
78
  when :begin
75
79
  node.children.each do |child|
76
- walk_symbols(child, comments, parent, &block)
80
+ walk_definitions(child, comments, parent, &block)
77
81
  end
78
82
  when :module
79
83
  definition = Module.new(
80
- :module, node.children[0].children[1],
81
- extract_comments_for(node, comments), node,
82
- parent: parent, language: Ruby
84
+ node, node.children[0].children[1],
85
+ comments: extract_comments_for(node, comments),
86
+ parent: parent,
87
+ language: Ruby
83
88
  )
84
89
 
85
90
  yield definition
86
91
 
87
92
  if children = node.children[1]
88
- walk_symbols(children, comments, definition, &block)
93
+ walk_definitions(children, comments, definition, &block)
89
94
  end
90
95
  when :class
91
96
  definition = Class.new(
92
- :class, node.children[0].children[1],
93
- extract_comments_for(node, comments), node,
97
+ node, node.children[0].children[1],
98
+ comments: extract_comments_for(node, comments),
94
99
  parent: parent, language: Ruby
95
100
  )
96
101
 
97
102
  yield definition
98
103
 
99
104
  if children = node.children[2]
100
- walk_symbols(children, comments, definition, &block)
105
+ walk_definitions(children, comments, definition, &block)
101
106
  end
102
107
  when :sclass
103
108
  definition = Singleton.new(
104
- :class, node.children[0],
105
- extract_comments_for(node, comments), node,
109
+ node, node.children[0],
110
+ comments: extract_comments_for(node, comments),
106
111
  parent: parent, language: Ruby
107
112
  )
108
113
 
109
114
  yield definition
110
115
 
111
116
  if children = node.children[1]
112
- walk_symbols(children, comments, definition, &block)
117
+ walk_definitions(children, comments, definition, &block)
113
118
  end
114
119
  when :def
115
120
  definition = Method.new(
116
- :def, node.children[0],
117
- extract_comments_for(node, comments), node,
121
+ node, node.children[0],
122
+ comments: extract_comments_for(node, comments),
118
123
  parent: parent, language: Ruby
119
124
  )
120
125
 
121
126
  yield definition
122
127
  when :defs
123
128
  definition = Function.new(
124
- :defs, node.children[1],
125
- extract_comments_for(node, comments), node,
129
+ node, node.children[1],
130
+ comments: extract_comments_for(node, comments),
126
131
  parent: parent, language: Ruby
127
132
  )
128
133
 
129
134
  yield definition
130
135
  when :casgn
131
136
  definition = Constant.new(
132
- :constant, node.children[1],
133
- extract_comments_for(node, comments), node,
137
+ node, node.children[1],
138
+ comments: extract_comments_for(node, comments),
134
139
  parent: parent, language: Ruby
135
140
  )
136
141
 
@@ -140,21 +145,98 @@ module Decode
140
145
  case name
141
146
  when :attr, :attr_reader, :attr_writer, :attr_accessor
142
147
  definition = Attribute.new(
143
- :def, name_for(node.children[2]),
144
- extract_comments_for(node, comments), node,
148
+ node, name_for(node.children[2]),
149
+ comments: extract_comments_for(node, comments),
145
150
  parent: parent, language: Ruby
146
151
  )
147
152
 
148
153
  yield definition
154
+ else
155
+ extracted_comments = extract_comments_for(node, comments)
156
+ if kind = kind_for(node, extracted_comments)
157
+ definition = Call.new(
158
+ node, name_for(node, extracted_comments),
159
+ comments: extracted_comments,
160
+ parent: parent, language: Ruby
161
+ )
162
+
163
+ yield definition
164
+ end
165
+ end
166
+ when :block
167
+ extracted_comments = extract_comments_for(node, comments)
168
+
169
+ if name = name_for(node, extracted_comments)
170
+ definition = Block.new(
171
+ node, name,
172
+ comments: extracted_comments,
173
+ parent: scope_for(extracted_comments, parent, &block),
174
+ language: Ruby
175
+ )
176
+
177
+ if kind = kind_for(node, extracted_comments)
178
+ definition = definition.convert(kind)
179
+ end
180
+
181
+ yield definition
182
+
183
+ if children = node.children[2]
184
+ walk_definitions(children, comments, definition, &block)
185
+ end
149
186
  end
150
187
  end
151
188
  end
152
189
 
153
- def name_for(node)
190
+ NAME_ATTRIBUTE = /\A@name\s+(?<value>.*?)\Z/
191
+
192
+ def name_for(node, comments = nil)
193
+ comments&.each do |comment|
194
+ if match = comment.match(NAME_ATTRIBUTE)
195
+ return match[:value].to_sym
196
+ end
197
+ end
198
+
154
199
  case node.type
155
200
  when :sym
156
201
  return node.children[0]
202
+ when :send
203
+ return node.children[1]
204
+ when :block
205
+ return node.children[0].children[1]
206
+ end
207
+ end
208
+
209
+ KIND_ATTRIBUTE = /\A
210
+ (@(?<kind>attr)\s+(?<value>.*?))|
211
+ (@define\s+(?<kind>)\s+(?<value>.*?))
212
+ \Z/x
213
+
214
+ def kind_for(node, comments = nil)
215
+ comments&.each do |comment|
216
+ if match = comment.match(KIND_ATTRIBUTE)
217
+ return match[:kind].to_sym
218
+ end
157
219
  end
220
+
221
+ return nil
222
+ end
223
+
224
+ SCOPE_ATTRIBUTE = /\A
225
+ (@scope\s+(?<names>.*?))
226
+ \Z/x
227
+
228
+ def scope_for(comments, parent = nil, &block)
229
+ comments&.each do |comment|
230
+ if match = comment.match(SCOPE_ATTRIBUTE)
231
+ return match[:names].split(/\s+/).map(&:to_sym).inject(nil) do |memo, name|
232
+ scope = Scope.new(name, parent: memo, language: Ruby)
233
+ yield scope
234
+ scope
235
+ end
236
+ end
237
+ end
238
+
239
+ return parent
158
240
  end
159
241
 
160
242
  # Extract segments from the given input file.
@@ -21,20 +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
+ # An Ruby-specific reference which can be resolved to zero or more definitions.
25
25
  class Reference
26
- KIND = {
27
- ':' => :def,
28
- '.' => :defs,
29
- }.freeze
30
-
31
26
  # Initialize the reference.
32
27
  # @param value [String] The string value of the reference.
33
28
  def initialize(value)
34
29
  @value = value
35
30
 
31
+ @lexical_path = nil
36
32
  @path = nil
37
- @kind = nil
38
33
  end
39
34
 
40
35
  # Whether the reference starts at the base of the lexical tree.
@@ -42,40 +37,22 @@ module Decode
42
37
  @value.start_with?('::')
43
38
  end
44
39
 
45
- METHOD = /\A(?<scope>.*?)?(?<kind>:|\.)(?<name>.+?)\z/
40
+ def lexical_path
41
+ @lexical_path ||= @value.scan(/(::|\.|#|:)?([^:.#]+)/)
42
+ end
46
43
 
47
- # The lexical path of the reference.
48
- # @return [Array(String)]
49
- def path
50
- if @path.nil?
51
- @path = @value.split(/::/)
52
-
53
- if last = @path.pop
54
- if match = last.match(METHOD)
55
- @kind = KIND[match[:kind]]
56
-
57
- if scope = match[:scope]
58
- @path << scope
59
- end
60
-
61
- @path << match[:name]
62
- else
63
- @path << last
64
- end
65
- end
66
-
67
- @path = @path.map(&:to_sym)
68
- @path.freeze
69
- end
44
+ def best(definitions)
45
+ prefix, name = lexical_path.last
70
46
 
71
- return @path
47
+ definitions.select do |definition|
48
+ prefix.nil? || definition.start_with?(prefix)
49
+ end
72
50
  end
73
51
 
74
- # The kind of symbol to match.
75
- def kind
76
- self.path
77
-
78
- return @kind
52
+ # The lexical path of the reference.
53
+ # @return [Array(String)]
54
+ def path
55
+ @path ||= self.lexical_path.map{|_, name| name.to_sym}
79
56
  end
80
57
  end
81
58
  end
@@ -31,42 +31,16 @@ module Decode
31
31
  "ruby"
32
32
  end
33
33
 
34
- # The symbol which is used to separate the specified definition from the parent scope.
35
- PREFIX = {
36
- class: '::',
37
- module: '::',
38
- def: ':',
39
- constant: '::',
40
- defs: '.',
41
- }.freeze
42
-
43
- # Generate a language-specific fully qualified name.
44
- def self.join(symbols, absolute = true)
45
- buffer = String.new
46
-
47
- symbols.each do |symbol|
48
- if absolute == false
49
- absolute = true
50
- else
51
- buffer << PREFIX[symbol.kind]
52
- end
53
-
54
- buffer << symbol.name.to_s
55
- end
56
-
57
- return buffer
58
- end
59
-
60
34
  # Generate a language-specific reference.
61
35
  def self.reference(value)
62
36
  Reference.new(value)
63
37
  end
64
38
 
65
- # Parse the input yielding symbols.
39
+ # Parse the input yielding definitions.
66
40
  # @block `{|definition| ...}`
67
41
  # @yield definition [Definition]
68
- def self.symbols_for(input, &block)
69
- Parser.new.symbols_for(input, &block)
42
+ def self.definitions_for(input, &block)
43
+ Parser.new.definitions_for(input, &block)
70
44
  end
71
45
 
72
46
  # Parse the input yielding interleaved comments and code segments.
@@ -21,7 +21,7 @@
21
21
  require_relative 'language/ruby'
22
22
 
23
23
  module Decode
24
- # Language specific parsers and symbols.
24
+ # Language specific parsers and definitions.
25
25
  module Language
26
26
  def self.detect(path)
27
27
  case File.extname(path)
@@ -0,0 +1,34 @@
1
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'definition'
22
+
23
+ module Decode
24
+ # An abstract namespace for nesting definitions.
25
+ class Scope < Definition
26
+ def short_form
27
+ @name
28
+ end
29
+
30
+ def container?
31
+ true
32
+ end
33
+ end
34
+ end
data/lib/decode/source.rb CHANGED
@@ -41,11 +41,11 @@ module Decode
41
41
  File.open(@path, &block)
42
42
  end
43
43
 
44
- def symbols(&block)
45
- return to_enum(:symbols) unless block_given?
44
+ def definitions(&block)
45
+ return to_enum(:definitions) unless block_given?
46
46
 
47
47
  self.open do |file|
48
- @language.symbols_for(file, &block)
48
+ @language.definitions_for(file, &block)
49
49
  end
50
50
  end
51
51
 
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Decode
22
- VERSION = "0.9.0"
22
+ VERSION = "0.10.0"
23
23
  end
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.9.0
4
+ version: 0.10.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-05 00:00:00.000000000 Z
11
+ date: 2020-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -129,6 +129,8 @@ files:
129
129
  - lib/decode/language.rb
130
130
  - lib/decode/language/ruby.rb
131
131
  - lib/decode/language/ruby/attribute.rb
132
+ - lib/decode/language/ruby/block.rb
133
+ - lib/decode/language/ruby/call.rb
132
134
  - lib/decode/language/ruby/class.rb
133
135
  - lib/decode/language/ruby/constant.rb
134
136
  - lib/decode/language/ruby/definition.rb
@@ -138,9 +140,9 @@ files:
138
140
  - lib/decode/language/ruby/parser.rb
139
141
  - lib/decode/language/ruby/reference.rb
140
142
  - lib/decode/language/ruby/segment.rb
143
+ - lib/decode/scope.rb
141
144
  - lib/decode/segment.rb
142
145
  - lib/decode/source.rb
143
- - lib/decode/symbol.rb
144
146
  - lib/decode/trie.rb
145
147
  - lib/decode/version.rb
146
148
  homepage: https://github.com/ioquatix/decode
data/lib/decode/symbol.rb DELETED
@@ -1,90 +0,0 @@
1
- # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require_relative 'documentation'
22
-
23
- module Decode
24
- # A language agnostic lexical scope.
25
- Key = Struct.new(:kind, :name)
26
-
27
- # A named element which represents some significant element of some kind in a computer program.
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.
34
- def initialize(kind, name, parent: nil, language: parent.language)
35
- @kind = kind
36
- @name = name
37
- @parent = parent
38
- @language = language
39
-
40
- @path = nil
41
- @qualified_name = nil
42
- end
43
-
44
- # A symbol-specific key which represents the lexical scope.
45
- # @return [Key]
46
- def key
47
- Key.new(@kind, @name)
48
- end
49
-
50
- def inspect
51
- "\#<#{self.class} #{@kind} #{qualified_name}>"
52
- end
53
-
54
- # The kind of symbol.
55
- # e.g. `:module`.
56
- attr :kind
57
-
58
- # The symbol name.
59
- # e.g. `:Decode`.
60
- attr :name
61
-
62
- # The parent symbol, defining lexical scope.
63
- attr :parent
64
-
65
- # The language the symbol is defined within.
66
- attr :language
67
-
68
- # The qualified name is an absolute name which includes any and all namespacing.
69
- def qualified_name
70
- @qualified_name ||= @language.join(self.path).freeze
71
- end
72
-
73
- # The lexical scope which is an array of lexical {Key} instances as generated by {key}.
74
- # @return [Array]
75
- def path
76
- if @path
77
- @path
78
- elsif @parent
79
- @path = [*@parent.path, self.key]
80
- else
81
- @path = [self.key]
82
- end
83
- end
84
-
85
- # The lexical path, only taking into account the symbol names.
86
- def lexical_path
87
- self.path.map(&:name)
88
- end
89
- end
90
- end