decode 0.6.0 → 0.7.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: 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