decode 0.6.0 → 0.7.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: 59ccb94aeeb9afb9e56f473a90991bfb2955ce6bdc2a681b1c8ecf7ee72974f9
4
- data.tar.gz: d092f82acb7134df72dfbf2042617f656b94749c8f5b89ec7830e002ff781e8e
3
+ metadata.gz: d37f874bcef0dadaa82d665ae4f27ed182a0d45c55403a280c443dede81d1b97
4
+ data.tar.gz: a3394961b5285524ab07be9931aeb436cd78aa94286d6c65c81993389b162a28
5
5
  SHA512:
6
- metadata.gz: 4df6fd92d34b379631cf7a0358e3d41c7470824daadd0ce9274def8b40cd5579ddb9d81eaed6cfdd8bf44a09b735525332a35b75fb0cb95068063d5e67431c52
7
- data.tar.gz: fc5a74af220d01473013e7943d778017fd7f141086103fb350713e935893c2616495d1ce61a5b8421a940dfe44ca3b8eb3658dab0190ef3f4232fa2d9765892f
6
+ metadata.gz: 7df83797d9844a6eb0e4f52f275527327ce7d81564865edcc70d5bce99a2be89b002fbe42cd1440bf666b4197c6dbb85775b4b4097675e525c1100aaf242571a
7
+ data.tar.gz: b2303685a56fa40ae3195a21a7a2cf613f5301f6c4520e4e6d8853e218b44363d33d704cd487710af40728f1926832b7bfc8bbd2a90db3555f6ed22c74ec7c45
data/docs/config.ru ADDED
@@ -0,0 +1,6 @@
1
+
2
+ require 'utopia/setup'
3
+ UTOPIA ||= Utopia.setup
4
+
5
+ require 'utopia/project'
6
+ Utopia::Project.call(self)
data/docs/gems.locked ADDED
@@ -0,0 +1,137 @@
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
data/docs/gems.rb ADDED
@@ -0,0 +1,7 @@
1
+
2
+ source "https://rubygems.org"
3
+
4
+ group :preload do
5
+ gem "utopia-project", path: "../../../socketry/utopia-project"
6
+ gem "decode", path: "../"
7
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
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
+ require_relative '../../lib/decode/index'
6
+
7
+ # Firstly, construct the index:
8
+ index = Decode::Index.new
9
+
10
+ # Then, update the index by loading paths from the file system:
11
+ paths = Dir.glob(File.expand_path("../../lib/**/*.rb", __dir__))
12
+ index.update(paths)
13
+
14
+ # Finally, you can print out the loaded symbols:
15
+ index.symbols.each do |name, symbol|
16
+ puts symbol.long_form
17
+ end
18
+
19
+ # Lookup a specific symbol:
20
+ absolute_reference = Decode::Language::Ruby.reference("Decode::Index:lookup")
21
+ lookup_symbol = index.lookup(absolute_reference).first
22
+ puts lookup_symbol.long_form
23
+
24
+ # Lookup a method relative to that symbol:
25
+ relative_reference = Decode::Language::Ruby.reference("trie")
26
+ trie_attribute = index.lookup(relative_reference, relative_to: lookup_symbol).first
27
+ puts trie_attribute.long_form
data/lib/decode/index.rb CHANGED
@@ -41,10 +41,10 @@ module Decode
41
41
  source = Source.new(path)
42
42
  @sources[path] = Source.new(path)
43
43
 
44
- source.parse do |definition|
45
- @symbols[definition.qualified_name] = definition
44
+ source.symbols do |symbol|
45
+ @symbols[symbol.qualified_name] = symbol
46
46
 
47
- @trie.insert(definition.lexical_path, definition)
47
+ @trie.insert(symbol.lexical_path, symbol)
48
48
  end
49
49
  end
50
50
  end
@@ -27,6 +27,8 @@ require_relative 'function'
27
27
  require_relative 'method'
28
28
  require_relative 'module'
29
29
 
30
+ require_relative 'segment'
31
+
30
32
  module Decode
31
33
  module Language
32
34
  module Ruby
@@ -35,14 +37,14 @@ module Decode
35
37
  @parser = parser
36
38
  end
37
39
 
38
- def parse(input, &block)
40
+ def symbols_for(input, &block)
39
41
  buffer = ::Parser::Source::Buffer.new('(input)')
40
42
  buffer.source = input.read
41
43
 
42
44
  top, comments = @parser.parse_with_comments(buffer)
43
45
 
44
46
  if top
45
- walk(top, comments, &block)
47
+ walk_symbols(top, comments, &block)
46
48
  end
47
49
  end
48
50
 
@@ -72,11 +74,11 @@ module Decode
72
74
  end
73
75
 
74
76
  # Walk over the syntax tree and extract relevant definitions with their associated comments.
75
- def walk(node, comments, parent = nil, &block)
77
+ def walk_symbols(node, comments, parent = nil, &block)
76
78
  case node.type
77
79
  when :begin
78
80
  node.children.each do |child|
79
- walk(child, comments, parent, &block)
81
+ walk_symbols(child, comments, parent, &block)
80
82
  end
81
83
  when :module
82
84
  definition = Module.new(
@@ -88,7 +90,7 @@ module Decode
88
90
  yield definition
89
91
 
90
92
  if children = node.children[1]
91
- walk(children, comments, definition, &block)
93
+ walk_symbols(children, comments, definition, &block)
92
94
  end
93
95
  when :class
94
96
  definition = Class.new(
@@ -100,7 +102,7 @@ module Decode
100
102
  yield definition
101
103
 
102
104
  if children = node.children[2]
103
- walk(children, comments, definition, &block)
105
+ walk_symbols(children, comments, definition, &block)
104
106
  end
105
107
  when :sclass
106
108
  definition = Singleton.new(
@@ -112,7 +114,7 @@ module Decode
112
114
  yield definition
113
115
 
114
116
  if children = node.children[1]
115
- walk(children, comments, definition, &block)
117
+ walk_symbols(children, comments, definition, &block)
116
118
  end
117
119
  when :def
118
120
  definition = Method.new(
@@ -159,6 +161,51 @@ module Decode
159
161
  return node.children[0]
160
162
  end
161
163
  end
164
+
165
+ def segments_for(input, &block)
166
+ buffer = ::Parser::Source::Buffer.new('(input)')
167
+ buffer.source = input.read
168
+
169
+ top, comments = @parser.parse_with_comments(buffer)
170
+
171
+ # We delete any leading comments:
172
+ line = 0
173
+
174
+ while comment = comments.first
175
+ if comment.location.line == line
176
+ comments.pop
177
+ line += 1
178
+ else
179
+ break
180
+ end
181
+ end
182
+
183
+ # Now we iterate over the syntax tree and generate segments:
184
+ walk_segments(top, comments, &block)
185
+ end
186
+
187
+ def walk_segments(node, comments, &block)
188
+ case node.type
189
+ when :begin
190
+ segment = nil
191
+
192
+ node.children.each do |child|
193
+ if segment.nil?
194
+ segment = Segment.new(
195
+ extract_comments_for(child, comments),
196
+ child
197
+ )
198
+ elsif next_comments = extract_comments_for(child, comments)
199
+ yield segment if segment
200
+ segment = Segment.new(next_comments, child)
201
+ else
202
+ segment.expand(child)
203
+ end
204
+ end
205
+
206
+ yield segment if segment
207
+ end
208
+ end
162
209
  end
163
210
  end
164
211
  end
@@ -0,0 +1,46 @@
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 '../../segment'
22
+
23
+ module Decode
24
+ module Language
25
+ module Ruby
26
+ class Segment < Decode::Segment
27
+ def initialize(comments, node, **options)
28
+ super(comments, **options)
29
+
30
+ @node = node
31
+ @expression = node.location.expression
32
+ end
33
+
34
+ attr :node
35
+
36
+ def expand(node)
37
+ @expression = @expression.join(node.location.expression)
38
+ end
39
+
40
+ def code
41
+ @expression.source
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -24,8 +24,8 @@ require_relative 'ruby/parser'
24
24
  module Decode
25
25
  module Language
26
26
  module Ruby
27
- def self.parse(input, &block)
28
- Parser.new.parse(input, &block)
27
+ def self.name
28
+ "ruby"
29
29
  end
30
30
 
31
31
  # The symbol which is used to separate the specified definition from the parent scope.
@@ -56,6 +56,18 @@ module Decode
56
56
  def self.reference(value)
57
57
  Reference.new(value)
58
58
  end
59
+
60
+ # Parse the input yielding symbols.
61
+ # @yield [Definition]
62
+ def self.symbols_for(input, &block)
63
+ Parser.new.symbols_for(input, &block)
64
+ end
65
+
66
+ # Parse the input yielding interleaved comments and code segments.
67
+ # @yield [Segment]
68
+ def self.segments_for(input, &block)
69
+ Parser.new.segments_for(input, &block)
70
+ end
59
71
  end
60
72
  end
61
73
  end
@@ -0,0 +1,44 @@
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
+ class Segment
25
+ def initialize(comments)
26
+ @comments = comments
27
+ end
28
+
29
+ attr :comments
30
+
31
+ # An interface for accsssing the documentation of the definition.
32
+ # @return [Documentation | nil] A `Documentation` if this definition has comments.
33
+ def documentation
34
+ if @comments&.any?
35
+ @documentation ||= Documentation.new(@comments)
36
+ end
37
+ end
38
+
39
+ # The source code trailing the comments.
40
+ # @return [String | nil]
41
+ def code
42
+ end
43
+ end
44
+ end
data/lib/decode/source.rb CHANGED
@@ -27,16 +27,24 @@ module Decode
27
27
  @language = language || Language.detect(path)
28
28
  end
29
29
 
30
- def parse(&block)
31
- return to_enum(:parse) unless block_given?
30
+ def open(&block)
31
+ File.open(@path, &block)
32
+ end
33
+
34
+ def symbols(&block)
35
+ return to_enum(:symbols) unless block_given?
32
36
 
33
37
  self.open do |file|
34
- @language.parse(file, &block)
38
+ @language.symbols_for(file, &block)
35
39
  end
36
40
  end
37
41
 
38
- def open(&block)
39
- File.open(@path, &block)
42
+ def segments(&block)
43
+ return to_enum(:segments) unless block_given?
44
+
45
+ self.open do |file|
46
+ @language.segments_for(file, &block)
47
+ end
40
48
  end
41
49
  end
42
50
  end
data/lib/decode/symbol.rb CHANGED
@@ -23,6 +23,7 @@ require_relative 'documentation'
23
23
  module Decode
24
24
  Key = Struct.new(:kind, :name)
25
25
 
26
+ # A named element which represents some significant element of some kind in a computer program.
26
27
  class Symbol
27
28
  def initialize(kind, name, parent: nil, language: parent.language)
28
29
  @kind = kind
@@ -34,6 +35,8 @@ module Decode
34
35
  @qualified_name = nil
35
36
  end
36
37
 
38
+ # A symbol-specific key which represents the lexical scope.
39
+ # @return [Key]
37
40
  def key
38
41
  Key.new(@kind, @name)
39
42
  end
@@ -42,15 +45,25 @@ module Decode
42
45
  "\#<#{self.class} #{@kind} #{qualified_name}>"
43
46
  end
44
47
 
48
+ # The kind of symbol, e.g. `:module`.
45
49
  attr :kind
50
+
51
+ # The symbol name, e.g. `:Decode`.
46
52
  attr :name
53
+
54
+ # The parent symbol, defining lexical scope.
47
55
  attr :parent
56
+
57
+ # The language the symbol is defined within.
48
58
  attr :language
49
59
 
60
+ # The qualified name is an absolute name which includes any and all namespacing.
50
61
  def qualified_name
51
62
  @qualified_name ||= @language.join(self.path).freeze
52
63
  end
53
64
 
65
+ # The lexical scope as defined by the {key}.
66
+ # @return [Array]
54
67
  def path
55
68
  if @path
56
69
  @path
@@ -61,6 +74,7 @@ module Decode
61
74
  end
62
75
  end
63
76
 
77
+ # The lexical path, only taking into account the symbol names.
64
78
  def lexical_path
65
79
  self.path.map(&:name)
66
80
  end
data/lib/decode/trie.rb CHANGED
@@ -42,13 +42,11 @@ module Decode
42
42
  end
43
43
 
44
44
  def traverse(path = [], &block)
45
- catch(:skip) do
46
- yield(path, self)
47
-
45
+ yield(path, self, ->{
48
46
  @children.each do |name, node|
49
47
  node.traverse([*path, name], &block)
50
48
  end
51
- end
49
+ })
52
50
  end
53
51
  end
54
52
 
@@ -71,7 +69,7 @@ module Decode
71
69
  end
72
70
 
73
71
  def lookup(path)
74
- @root.lookup(path).values
72
+ @root.lookup(path)
75
73
  end
76
74
 
77
75
  # Given a base path, enumerate all paths under that.
@@ -82,6 +80,12 @@ module Decode
82
80
  end
83
81
  end
84
82
 
83
+ def traverse(path = [], &block)
84
+ if node = @root.lookup(path)
85
+ node.traverse(&block)
86
+ end
87
+ end
88
+
85
89
  def match(path, &block)
86
90
  @root.lookup(path)
87
91
  end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Decode
22
- VERSION = "0.6.0"
22
+ VERSION = "0.7.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.6.0
4
+ version: 0.7.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-02 00:00:00.000000000 Z
11
+ date: 2020-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -120,6 +120,10 @@ files:
120
120
  - ".rspec"
121
121
  - README.md
122
122
  - decode.gemspec
123
+ - docs/config.ru
124
+ - docs/gems.locked
125
+ - docs/gems.rb
126
+ - examples/index/extract.rb
123
127
  - gems.rb
124
128
  - lib/decode.rb
125
129
  - lib/decode/definition.rb
@@ -136,6 +140,8 @@ files:
136
140
  - lib/decode/language/ruby/module.rb
137
141
  - lib/decode/language/ruby/parser.rb
138
142
  - lib/decode/language/ruby/reference.rb
143
+ - lib/decode/language/ruby/segment.rb
144
+ - lib/decode/segment.rb
139
145
  - lib/decode/source.rb
140
146
  - lib/decode/symbol.rb
141
147
  - lib/decode/trie.rb