decode 0.14.1 → 0.15.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: b10527900f968f995dfb80150dbe8773f92857f190fe5ae3981af28363473530
4
- data.tar.gz: c58a678e66c1416ebc3c7a19dae19789644c937e990343ec4ea3bc565ee991a7
3
+ metadata.gz: 46819e1068182148b9179638359c81fe75b3276f3ae07285f962fbeda31f3a48
4
+ data.tar.gz: 24e0acf13ec561c1bb28be8700302302c2027c314d5c951613e3734260b1e995
5
5
  SHA512:
6
- metadata.gz: 2a5110378a537c6ee3ddb571a9d376af274e45ddf9835b347ac538a858eea5f140610e3cd04fa2e14c9c4c2e46a75f32adc7dbd10c39ac7de438ae2955336e7c
7
- data.tar.gz: fd1b0e0bbc3912cd3eedfab8bf0b0e8c2bdcda930783f08305a7de9e92f2629e0b500f727dfd92a52958b283e429636ca8a3b83f1345de98bf59257bd17fc415
6
+ metadata.gz: 8b07a7bb594c53d26e81903b54cf640b766318eba6365a90a6b443fa2036ab4b4b5ac2145aadf44aca5fff8b4f373ff4379f7301c1658ffc25bce693ab49a268
7
+ data.tar.gz: a23772085b48311f6f4596f1215dd3b2a0e1974a5ca3d78c4bd207118c3c6b048beb342fd3dd04accdd39ed531ebcd29d8b73e9733bcff532f90b8203ba7f746
@@ -77,6 +77,8 @@ module Decode
77
77
  "::#{@name}"
78
78
  end
79
79
 
80
+ # Does the definition name match the specified prefix?
81
+ # @returns [Boolean]
80
82
  def start_with?(prefix)
81
83
  self.nested_name.start_with?(prefix)
82
84
  end
@@ -24,11 +24,11 @@ module Decode
24
24
  class Reference
25
25
  # Initialize the reference.
26
26
  # @parameter identifier [String] The identifier part of the reference.
27
- def initialize(identifier, language)
27
+ def initialize(identifier, language, lexical_path = nil)
28
28
  @identifier = identifier
29
29
  @language = language
30
30
 
31
- @lexical_path = nil
31
+ @lexical_path = lexical_path
32
32
  @path = nil
33
33
  end
34
34
 
@@ -67,14 +67,35 @@ module Decode
67
67
  @lexical_path ||= self.split(@identifier)
68
68
  end
69
69
 
70
+ def priority(definition, prefix)
71
+ if prefix.nil?
72
+ return 1
73
+ elsif definition.start_with?(prefix)
74
+ return 0
75
+ else
76
+ return 2
77
+ end
78
+ end
79
+
70
80
  def best(definitions)
71
81
  prefix, name = lexical_path.last
72
82
 
73
- definitions.select do |definition|
74
- definition.language == @language && (
75
- prefix.nil? || definition.start_with?(prefix)
76
- )
83
+ first = nil
84
+ without_prefix = nil
85
+
86
+ definitions.each do |definition|
87
+ first ||= definition
88
+
89
+ next unless definition.language == @language
90
+
91
+ if prefix.nil?
92
+ without_prefix ||= definition
93
+ elsif definition.start_with?(prefix)
94
+ return definition
95
+ end
77
96
  end
97
+
98
+ return without_prefix || first
78
99
  end
79
100
 
80
101
  # The lexical path of the reference.
@@ -20,6 +20,7 @@
20
20
 
21
21
  require_relative 'ruby/reference'
22
22
  require_relative 'ruby/parser'
23
+ require_relative 'ruby/code'
23
24
 
24
25
  require_relative '../comment/tags'
25
26
  require_relative '../comment/parameter'
@@ -86,6 +87,10 @@ module Decode
86
87
  def self.segments_for(input, &block)
87
88
  Parser.new.segments_for(input, &block)
88
89
  end
90
+
91
+ def self.code_for(text, index, relative_to: nil)
92
+ Code.new(text, index, relative_to: relative_to, language: self)
93
+ end
89
94
  end
90
95
  end
91
96
  end
@@ -0,0 +1,85 @@
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
+ require_relative '../../syntax/link'
23
+
24
+ require 'parser/current'
25
+
26
+ module Decode
27
+ module Language
28
+ module Ruby
29
+ # A Ruby-specific block of code.
30
+ class Code
31
+ def initialize(text, index, relative_to: nil, language: relative_to&.language)
32
+ @text = text
33
+ @root = ::Parser::CurrentRuby.parse(text)
34
+ @index = index
35
+ @relative_to = relative_to
36
+ @language = language
37
+ end
38
+
39
+ attr :text
40
+
41
+ attr :language
42
+
43
+ def extract(into = [])
44
+ if @index
45
+ self.traverse(@root, into)
46
+ end
47
+
48
+ return into
49
+ end
50
+
51
+ private
52
+
53
+ def traverse(node, into)
54
+ case node&.type
55
+ when :send
56
+ if reference = Reference.from_const(node, @language)
57
+ if definition = @index.lookup(reference, relative_to: @relative_to)
58
+ expression = node.location.selector
59
+ range = expression.begin_pos...expression.end_pos
60
+ into << Syntax::Link.new(range, definition)
61
+ end
62
+ end
63
+
64
+ # Extract constants from arguments:
65
+ children = node.children[2..].each do |node|
66
+ traverse(node, into)
67
+ end
68
+ when :const
69
+ if reference = Reference.from_const(node, @language)
70
+ if definition = @index.lookup(reference, relative_to: @relative_to)
71
+ expression = node.location.name
72
+ range = expression.begin_pos...expression.end_pos
73
+ into << Syntax::Link.new(range, definition)
74
+ end
75
+ end
76
+ when :begin
77
+ node.children.each do |child|
78
+ traverse(child, into)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -40,7 +40,7 @@ module Decode
40
40
  class Parser
41
41
  # Extract definitions from the given input file.
42
42
  def definitions_for(input, &block)
43
- top, comments = ::Parser::CurrentRuby.parse_with_comments(input.read)
43
+ top, comments = ::Parser::CurrentRuby.parse_with_comments(input)
44
44
 
45
45
  if top
46
46
  walk_definitions(top, comments, &block)
@@ -241,7 +241,7 @@ module Decode
241
241
 
242
242
  # Extract segments from the given input file.
243
243
  def segments_for(input, &block)
244
- top, comments = ::Parser::CurrentRuby.parse_with_comments(input.read)
244
+ top, comments = ::Parser::CurrentRuby.parse_with_comments(input)
245
245
 
246
246
  # We delete any leading comments:
247
247
  line = 0
@@ -25,6 +25,37 @@ module Decode
25
25
  module Ruby
26
26
  # An Ruby-specific reference which can be resolved to zero or more definitions.
27
27
  class Reference < Language::Reference
28
+ def self.from_const(node, language)
29
+ lexical_path = append_const(node)
30
+
31
+ return self.new(node.location.expression.source, language, lexical_path)
32
+ end
33
+
34
+ def self.append_const(node, path = [])
35
+ parent, name = node.children
36
+
37
+ if parent and parent.type != :cbase
38
+ append_const(parent, path)
39
+ end
40
+
41
+ case node.type
42
+ when :const
43
+ if parent && parent.type != :cbase
44
+ path << ['::', name]
45
+ else
46
+ path << [nil, name]
47
+ end
48
+ when :send
49
+ path << ['#', name]
50
+ when :cbase
51
+ # Ignore.
52
+ else
53
+ raise ArgumentError, "Could not determine reference for #{node}!"
54
+ end
55
+
56
+ return path
57
+ end
58
+
28
59
  def split(text)
29
60
  text.scan(/(::|\.|#|:)?([^:.#]+)/)
30
61
  end
data/lib/decode/source.rb CHANGED
@@ -25,6 +25,7 @@ module Decode
25
25
  class Source
26
26
  def initialize(path, language)
27
27
  @path = path
28
+ @buffer = nil
28
29
  @language = language
29
30
  end
30
31
 
@@ -36,11 +37,10 @@ module Decode
36
37
  # @attribute [Language::Generic]
37
38
  attr :language
38
39
 
39
- # Open the source file for reading.
40
- # @yields {|file| ...} The opened {File} instance.
41
- # @parameter file [File]
42
- def open(&block)
43
- File.open(@path, &block)
40
+ # Read the source file into an internal buffer/cache.
41
+ # @returns [String]
42
+ def read
43
+ @buffer ||= File.read(@path).freeze
44
44
  end
45
45
 
46
46
  # Open the source file and read all definitions.
@@ -50,9 +50,7 @@ module Decode
50
50
  def definitions(&block)
51
51
  return to_enum(:definitions) unless block_given?
52
52
 
53
- self.open do |file|
54
- @language.definitions_for(file, &block)
55
- end
53
+ @language.definitions_for(self.read, &block)
56
54
  end
57
55
 
58
56
  # Open the source file and read all segments.
@@ -62,9 +60,11 @@ module Decode
62
60
  def segments(&block)
63
61
  return to_enum(:segments) unless block_given?
64
62
 
65
- self.open do |file|
66
- @language.segments_for(file, &block)
67
- end
63
+ @language.segments_for(self.read, &block)
64
+ end
65
+
66
+ def code(index = nil, relative_to: nil)
67
+ @language.code_for(self.read, index, relative_to: relative_to)
68
68
  end
69
69
  end
70
70
  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 'match'
22
+
23
+ module Decode
24
+ module Syntax
25
+ class Link < Match
26
+ def initialize(range, definition)
27
+ @definition = definition
28
+
29
+ super(range)
30
+ end
31
+
32
+ attr :definition
33
+
34
+ def apply(output, rewriter)
35
+ output << rewriter.link_to(
36
+ @definition,
37
+ rewriter.text_for(@range)
38
+ )
39
+
40
+ return self.size
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
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
+ module Decode
22
+ module Syntax
23
+ class Match
24
+ def initialize(range)
25
+ @range = range
26
+ end
27
+
28
+ attr :range
29
+
30
+ def apply(source)
31
+ return source[range]
32
+ end
33
+
34
+ def <=> other
35
+ @range.min <=> other.range.min
36
+ end
37
+
38
+ def offset
39
+ @range.min
40
+ end
41
+
42
+ def size
43
+ @range.size
44
+ end
45
+
46
+ def apply(output, rewriter)
47
+ output << rewriter.text_for(@range)
48
+
49
+ return self.size
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,70 @@
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
+ module Decode
22
+ module Syntax
23
+ class Rewriter
24
+ def initialize(text)
25
+ @text = text
26
+ @matches = []
27
+ end
28
+
29
+ attr :text
30
+
31
+ attr :matches
32
+
33
+ def << match
34
+ @matches << match
35
+ end
36
+
37
+ # Returns a chunk of raw text with no formatting.
38
+ def text_for(range)
39
+ @text[range]
40
+ end
41
+
42
+ def apply(output = [])
43
+ offset = 0
44
+
45
+ @matches.sort.each do |match|
46
+ if match.offset > offset
47
+ output << text_for(offset...match.offset)
48
+
49
+ offset = match.offset
50
+ elsif match.offset < offset
51
+ # Match intersects last output buffer.
52
+ next
53
+ end
54
+
55
+ offset += match.apply(output, self)
56
+ end
57
+
58
+ if offset < @text.size
59
+ output << text_for(offset...@text.size)
60
+ end
61
+
62
+ return output
63
+ end
64
+
65
+ def link_to(definition, text)
66
+ "[#{text}]"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Decode
22
- VERSION = "0.14.1"
22
+ VERSION = "0.15.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.14.1
4
+ version: 0.15.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-10 00:00:00.000000000 Z
11
+ date: 2020-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -139,6 +139,7 @@ files:
139
139
  - lib/decode/language/ruby/block.rb
140
140
  - lib/decode/language/ruby/call.rb
141
141
  - lib/decode/language/ruby/class.rb
142
+ - lib/decode/language/ruby/code.rb
142
143
  - lib/decode/language/ruby/constant.rb
143
144
  - lib/decode/language/ruby/definition.rb
144
145
  - lib/decode/language/ruby/function.rb
@@ -151,6 +152,9 @@ files:
151
152
  - lib/decode/scope.rb
152
153
  - lib/decode/segment.rb
153
154
  - lib/decode/source.rb
155
+ - lib/decode/syntax/link.rb
156
+ - lib/decode/syntax/match.rb
157
+ - lib/decode/syntax/rewriter.rb
154
158
  - lib/decode/trie.rb
155
159
  - lib/decode/version.rb
156
160
  homepage: https://github.com/ioquatix/decode