decode 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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