rucoa 0.7.0 → 0.9.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +4 -1
- data/data/definitions_ruby_3_1 +0 -0
- data/lib/rucoa/configuration.rb +10 -0
- data/lib/rucoa/definition_store.rb +194 -27
- data/lib/rucoa/definitions/class_definition.rb +82 -0
- data/lib/rucoa/definitions/constant_definition.rb +7 -7
- data/lib/rucoa/definitions/method_definition.rb +18 -6
- data/lib/rucoa/definitions/module_definition.rb +8 -0
- data/lib/rucoa/definitions.rb +2 -0
- data/lib/rucoa/handlers/initialize_handler.rb +1 -0
- data/lib/rucoa/handlers/initialized_handler.rb +33 -5
- data/lib/rucoa/handlers/text_document_completion_handler.rb +2 -2
- data/lib/rucoa/handlers/text_document_definition_handler.rb +155 -0
- data/lib/rucoa/handlers/text_document_did_open_handler.rb +1 -4
- data/lib/rucoa/handlers/text_document_hover_handler.rb +3 -4
- data/lib/rucoa/handlers.rb +1 -0
- data/lib/rucoa/node_concerns/{name_full_qualifiable.rb → name_fully_qualifiable.rb} +2 -2
- data/lib/rucoa/node_concerns.rb +1 -1
- data/lib/rucoa/node_inspector.rb +56 -34
- data/lib/rucoa/nodes/base.rb +32 -7
- data/lib/rucoa/nodes/casgn_node.rb +1 -1
- data/lib/rucoa/nodes/cbase_node.rb +8 -0
- data/lib/rucoa/nodes/class_node.rb +62 -1
- data/lib/rucoa/nodes/const_node.rb +72 -0
- data/lib/rucoa/nodes/def_node.rb +11 -9
- data/lib/rucoa/nodes/defs_node.rb +21 -0
- data/lib/rucoa/nodes/lvar_node.rb +2 -1
- data/lib/rucoa/nodes/module_node.rb +1 -1
- data/lib/rucoa/nodes/send_node.rb +14 -10
- data/lib/rucoa/nodes.rb +1 -0
- data/lib/rucoa/parse_result.rb +29 -0
- data/lib/rucoa/parser.rb +40 -8
- data/lib/rucoa/parser_builder.rb +1 -0
- data/lib/rucoa/position.rb +1 -1
- data/lib/rucoa/rbs/class_definition_mapper.rb +46 -0
- data/lib/rucoa/rbs/constant_definition_mapper.rb +2 -2
- data/lib/rucoa/rbs/module_definition_mapper.rb +40 -0
- data/lib/rucoa/rbs/ruby_definitions_loader.rb +11 -7
- data/lib/rucoa/rbs.rb +2 -0
- data/lib/rucoa/rubocop/autocorrector.rb +12 -1
- data/lib/rucoa/rubocop/investigator.rb +10 -1
- data/lib/rucoa/server.rb +2 -1
- data/lib/rucoa/source.rb +47 -24
- data/lib/rucoa/source_store.rb +0 -13
- data/lib/rucoa/version.rb +1 -1
- data/lib/rucoa/yard/definitions_loader.rb +320 -48
- data/lib/rucoa/yard/type.rb +46 -0
- data/lib/rucoa/yard.rb +1 -1
- data/lib/rucoa.rb +1 -0
- metadata +11 -4
- data/lib/rucoa/yard/definition_mapper.rb +0 -217
@@ -6,10 +6,11 @@ module Rucoa
|
|
6
6
|
# @return [String]
|
7
7
|
# @example returns local variable name
|
8
8
|
# node = Rucoa::Source.new(
|
9
|
-
# content: <<~RUBY
|
9
|
+
# content: <<~RUBY,
|
10
10
|
# foo = 1
|
11
11
|
# foo
|
12
12
|
# RUBY
|
13
|
+
# uri: 'file:///path/to/example.rb'
|
13
14
|
# ).node_at(
|
14
15
|
# Rucoa::Position.new(
|
15
16
|
# column: 2,
|
@@ -5,11 +5,12 @@ module Rucoa
|
|
5
5
|
class SendNode < Base
|
6
6
|
# @return [Array<Rucoa::Nodes::Base>]
|
7
7
|
# @example returns arguments
|
8
|
-
# node = Rucoa::
|
9
|
-
# <<~RUBY
|
8
|
+
# node = Rucoa::Source.new(
|
9
|
+
# content: <<~RUBY,
|
10
10
|
# foo(bar, baz)
|
11
11
|
# RUBY
|
12
|
-
#
|
12
|
+
# uri: 'file:///path/to/example.rb'
|
13
|
+
# ).root_node
|
13
14
|
# expect(node.arguments.map(&:name)).to eq(
|
14
15
|
# %w[
|
15
16
|
# bar
|
@@ -22,11 +23,12 @@ module Rucoa
|
|
22
23
|
|
23
24
|
# @return [String]
|
24
25
|
# @example returns method name
|
25
|
-
# node = Rucoa::
|
26
|
-
# <<~RUBY
|
26
|
+
# node = Rucoa::Source.new(
|
27
|
+
# content: <<~RUBY,
|
27
28
|
# foo(bar, baz)
|
28
29
|
# RUBY
|
29
|
-
#
|
30
|
+
# uri: 'file:///path/to/example.rb'
|
31
|
+
# ).root_node
|
30
32
|
# expect(node.name).to eq('foo')
|
31
33
|
def name
|
32
34
|
children[1].to_s
|
@@ -34,17 +36,19 @@ module Rucoa
|
|
34
36
|
|
35
37
|
# @return [Rucoa::Nodes::Base, nil]
|
36
38
|
# @example returns nil for receiver-less method call
|
37
|
-
# node = Rucoa::
|
38
|
-
# <<~RUBY
|
39
|
+
# node = Rucoa::Source.new(
|
40
|
+
# content: <<~RUBY,
|
39
41
|
# foo(bar, baz)
|
40
42
|
# RUBY
|
41
|
-
#
|
43
|
+
# uri: 'file:///path/to/example.rb'
|
44
|
+
# ).root_node
|
42
45
|
# expect(node.receiver).to be_nil
|
43
46
|
# @example returns receiver
|
44
47
|
# node = Rucoa::Source.new(
|
45
|
-
# content: <<~RUBY
|
48
|
+
# content: <<~RUBY,
|
46
49
|
# foo.bar
|
47
50
|
# RUBY
|
51
|
+
# uri: 'file:///path/to/example.rb'
|
48
52
|
# ).node_at(
|
49
53
|
# Rucoa::Position.new(
|
50
54
|
# column: 4,
|
data/lib/rucoa/nodes.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rucoa
|
4
|
+
class ParseResult
|
5
|
+
# @return [Array<Parser::Source::Comment>, nil]
|
6
|
+
attr_reader :associations
|
7
|
+
|
8
|
+
# @return [Rucoa::Nodes::Base, nil]
|
9
|
+
attr_reader :root_node
|
10
|
+
|
11
|
+
# @param associations [Array<Parser::Source::Comment>, nil]
|
12
|
+
# @param failed [Boolean]
|
13
|
+
# @param root_node [Rucoa::Nodes::Base, nil]
|
14
|
+
def initialize(
|
15
|
+
associations: nil,
|
16
|
+
failed: false,
|
17
|
+
root_node: nil
|
18
|
+
)
|
19
|
+
@associations = associations
|
20
|
+
@failed = failed
|
21
|
+
@root_node = root_node
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Boolean]
|
25
|
+
def failed?
|
26
|
+
@failed
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/rucoa/parser.rb
CHANGED
@@ -3,29 +3,61 @@
|
|
3
3
|
require 'parser/current'
|
4
4
|
|
5
5
|
module Rucoa
|
6
|
-
# Parses Ruby text code.
|
7
6
|
class Parser
|
8
7
|
class << self
|
8
|
+
# @param path [String]
|
9
9
|
# @param text [String]
|
10
|
-
# @return [Rucoa::
|
11
|
-
|
12
|
-
|
10
|
+
# @return [Rucoa::ParseResult]
|
11
|
+
# @example returns non-failed parse result for valid Ruby source
|
12
|
+
# result = Rucoa::Parser.call(
|
13
|
+
# path: '/path/to/foo.rb',
|
14
|
+
# text: 'foo'
|
15
|
+
# )
|
16
|
+
# expect(result).not_to be_failed
|
17
|
+
# @example returns failed parse result for invalid Ruby source
|
18
|
+
# result = Rucoa::Parser.call(
|
19
|
+
# path: '/path/to/foo.rb',
|
20
|
+
# text: 'foo('
|
21
|
+
# )
|
22
|
+
# expect(result).to be_failed
|
23
|
+
def call(
|
24
|
+
path:,
|
25
|
+
text:
|
26
|
+
)
|
27
|
+
new(
|
28
|
+
path: path,
|
29
|
+
text: text
|
30
|
+
).call
|
13
31
|
end
|
14
32
|
end
|
15
33
|
|
34
|
+
# @param path [String]
|
16
35
|
# @param text [String]
|
17
|
-
def initialize(
|
36
|
+
def initialize(
|
37
|
+
path:,
|
38
|
+
text:
|
39
|
+
)
|
40
|
+
@path = path
|
18
41
|
@text = text
|
19
42
|
end
|
20
43
|
|
21
|
-
# @return [Rucoa::
|
44
|
+
# @return [Rucoa::ParseResult]
|
22
45
|
def call
|
23
|
-
parser.
|
46
|
+
root_node, comments = parser.parse_with_comments(
|
24
47
|
::Parser::Source::Buffer.new(
|
25
|
-
|
48
|
+
@path,
|
26
49
|
source: @text
|
27
50
|
)
|
28
51
|
)
|
52
|
+
ParseResult.new(
|
53
|
+
associations: ::Parser::Source::Comment.associate_locations(
|
54
|
+
root_node,
|
55
|
+
comments
|
56
|
+
),
|
57
|
+
root_node: root_node
|
58
|
+
)
|
59
|
+
rescue ::Parser::SyntaxError
|
60
|
+
ParseResult.new(failed: true)
|
29
61
|
end
|
30
62
|
|
31
63
|
private
|
data/lib/rucoa/parser_builder.rb
CHANGED
data/lib/rucoa/position.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rucoa
|
4
|
+
module Rbs
|
5
|
+
class ClassDefinitionMapper
|
6
|
+
class << self
|
7
|
+
# @param declaration [RBS::AST::Declarations::Class]
|
8
|
+
# @return [Rucoa::Definitions::ClassDefinition]
|
9
|
+
def call(declaration:)
|
10
|
+
new(declaration: declaration).call
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param declaration [RBS::AST::Declarations::Class]
|
15
|
+
def initialize(declaration:)
|
16
|
+
@declaration = declaration
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Rucoa::Definitions::ClassDefinition]
|
20
|
+
def call
|
21
|
+
Definitions::ClassDefinition.new(
|
22
|
+
fully_qualified_name: fully_qualified_name,
|
23
|
+
source_path: source_path,
|
24
|
+
super_class_fully_qualified_name: super_class_fully_qualified_name
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# @return [String]
|
31
|
+
def fully_qualified_name
|
32
|
+
@declaration.name.to_s.delete_prefix('::')
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [String]
|
36
|
+
def source_path
|
37
|
+
@declaration.location.name
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [String, nil]
|
41
|
+
def super_class_fully_qualified_name
|
42
|
+
@declaration.super_class&.name&.to_s&.delete_prefix('::')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -19,7 +19,7 @@ module Rucoa
|
|
19
19
|
# @return [Rucoa::Definitions::ConstantDefinition]
|
20
20
|
def call
|
21
21
|
Definitions::ConstantDefinition.new(
|
22
|
-
|
22
|
+
fully_qualified_name: fully_qualified_name,
|
23
23
|
source_path: source_path
|
24
24
|
)
|
25
25
|
end
|
@@ -27,7 +27,7 @@ module Rucoa
|
|
27
27
|
private
|
28
28
|
|
29
29
|
# @return [String]
|
30
|
-
def
|
30
|
+
def fully_qualified_name
|
31
31
|
@declaration.name.to_s.delete_prefix('::')
|
32
32
|
end
|
33
33
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rucoa
|
4
|
+
module Rbs
|
5
|
+
class ModuleDefinitionMapper
|
6
|
+
class << self
|
7
|
+
# @param declaration [RBS::AST::Declarations::Module]
|
8
|
+
# @return [Rucoa::Definitions::ModuleDefinition]
|
9
|
+
def call(declaration:)
|
10
|
+
new(declaration: declaration).call
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param declaration [RBS::AST::Declarations::Module]
|
15
|
+
def initialize(declaration:)
|
16
|
+
@declaration = declaration
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Rucoa::Definitions::ModuleDefinition]
|
20
|
+
def call
|
21
|
+
Definitions::ModuleDefinition.new(
|
22
|
+
fully_qualified_name: fully_qualified_name,
|
23
|
+
source_path: source_path
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# @return [String]
|
30
|
+
def fully_qualified_name
|
31
|
+
@declaration.name.to_s.delete_prefix('::')
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
def source_path
|
36
|
+
@declaration.location.name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -18,13 +18,17 @@ module Rucoa
|
|
18
18
|
declarations.flat_map do |declaration|
|
19
19
|
case declaration
|
20
20
|
when ::RBS::AST::Declarations::Constant
|
21
|
-
[
|
22
|
-
|
23
|
-
]
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
[ConstantDefinitionMapper.call(declaration: declaration)]
|
22
|
+
when ::RBS::AST::Declarations::Class
|
23
|
+
[ClassDefinitionMapper.call(declaration: declaration)] +
|
24
|
+
declaration.members.grep(::RBS::AST::Members::MethodDefinition).map do |method_definition|
|
25
|
+
MethodDefinitionMapper.call(
|
26
|
+
declaration: declaration,
|
27
|
+
method_definition: method_definition
|
28
|
+
)
|
29
|
+
end
|
30
|
+
when ::RBS::AST::Declarations::Module
|
31
|
+
[ModuleDefinitionMapper.call(declaration: declaration)] +
|
28
32
|
declaration.members.grep(::RBS::AST::Members::MethodDefinition).map do |method_definition|
|
29
33
|
MethodDefinitionMapper.call(
|
30
34
|
declaration: declaration,
|
data/lib/rucoa/rbs.rb
CHANGED
@@ -2,8 +2,10 @@
|
|
2
2
|
|
3
3
|
module Rucoa
|
4
4
|
module Rbs
|
5
|
+
autoload :ClassDefinitionMapper, 'rucoa/rbs/class_definition_mapper'
|
5
6
|
autoload :ConstantDefinitionMapper, 'rucoa/rbs/constant_definition_mapper'
|
6
7
|
autoload :MethodDefinitionMapper, 'rucoa/rbs/method_definition_mapper'
|
8
|
+
autoload :ModuleDefinitionMapper, 'rucoa/rbs/module_definition_mapper'
|
7
9
|
autoload :RubyDefinitionsLoader, 'rucoa/rbs/ruby_definitions_loader'
|
8
10
|
end
|
9
11
|
end
|
@@ -32,9 +32,20 @@ module Rucoa
|
|
32
32
|
# @return [String]
|
33
33
|
def call
|
34
34
|
@options[:stdin] = @source.content
|
35
|
-
run([
|
35
|
+
run([path])
|
36
36
|
@options[:stdin]
|
37
37
|
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @return [String]
|
42
|
+
def path
|
43
|
+
if @source.untitled?
|
44
|
+
'untitled'
|
45
|
+
else
|
46
|
+
@source.name
|
47
|
+
end
|
48
|
+
end
|
38
49
|
end
|
39
50
|
end
|
40
51
|
end
|
@@ -32,7 +32,7 @@ module Rucoa
|
|
32
32
|
# @return [Array<RuboCop::Cop::Offense>]
|
33
33
|
def call
|
34
34
|
@options[:stdin] = @source.content
|
35
|
-
run([
|
35
|
+
run([path])
|
36
36
|
@offenses
|
37
37
|
end
|
38
38
|
|
@@ -45,6 +45,15 @@ module Rucoa
|
|
45
45
|
@offenses = offenses
|
46
46
|
super
|
47
47
|
end
|
48
|
+
|
49
|
+
# @return [String]
|
50
|
+
def path
|
51
|
+
if @source.untitled?
|
52
|
+
'untitled'
|
53
|
+
else
|
54
|
+
@source.name
|
55
|
+
end
|
56
|
+
end
|
48
57
|
end
|
49
58
|
end
|
50
59
|
end
|
data/lib/rucoa/server.rb
CHANGED
@@ -13,6 +13,7 @@ module Rucoa
|
|
13
13
|
'shutdown' => Handlers::ShutdownHandler,
|
14
14
|
'textDocument/codeAction' => Handlers::TextDocumentCodeActionHandler,
|
15
15
|
'textDocument/completion' => Handlers::TextDocumentCompletionHandler,
|
16
|
+
'textDocument/definition' => Handlers::TextDocumentDefinitionHandler,
|
16
17
|
'textDocument/didChange' => Handlers::TextDocumentDidChangeHandler,
|
17
18
|
'textDocument/didClose' => Handlers::TextDocumentDidCloseHandler,
|
18
19
|
'textDocument/didOpen' => Handlers::TextDocumentDidOpenHandler,
|
@@ -58,7 +59,7 @@ module Rucoa
|
|
58
59
|
@source_store = SourceStore.new
|
59
60
|
|
60
61
|
@definition_store = DefinitionStore.new
|
61
|
-
@definition_store.
|
62
|
+
@definition_store.bulk_add(DefinitionArchiver.load)
|
62
63
|
end
|
63
64
|
|
64
65
|
# @return [void]
|
data/lib/rucoa/source.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'uri'
|
4
|
+
|
3
5
|
module Rucoa
|
4
6
|
class Source
|
5
7
|
# @return [String]
|
@@ -9,8 +11,8 @@ module Rucoa
|
|
9
11
|
attr_reader :uri
|
10
12
|
|
11
13
|
# @param content [String]
|
12
|
-
# @param uri [String
|
13
|
-
def initialize(content:, uri:
|
14
|
+
# @param uri [String]
|
15
|
+
def initialize(content:, uri:)
|
14
16
|
@content = content
|
15
17
|
@uri = uri
|
16
18
|
end
|
@@ -29,36 +31,41 @@ module Rucoa
|
|
29
31
|
# )
|
30
32
|
# expect(source.definitions).to match(
|
31
33
|
# [
|
34
|
+
# a_kind_of(Rucoa::Definitions::ClassDefinition),
|
32
35
|
# a_kind_of(Rucoa::Definitions::MethodDefinition)
|
33
36
|
# ]
|
34
37
|
# )
|
35
38
|
def definitions
|
36
|
-
@definitions ||=
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
@definitions ||=
|
40
|
+
if parse_result.failed?
|
41
|
+
[]
|
42
|
+
else
|
43
|
+
Yard::DefinitionsLoader.call(
|
44
|
+
associations: parse_result.associations,
|
45
|
+
root_node: parse_result.root_node
|
46
|
+
)
|
47
|
+
end
|
40
48
|
end
|
41
49
|
|
42
50
|
# @return [String, nil]
|
43
|
-
# @example returns path
|
51
|
+
# @example returns path for file URI
|
44
52
|
# source = Rucoa::Source.new(
|
45
53
|
# content: '',
|
46
54
|
# uri: 'file:///path/to/foo.rb'
|
47
55
|
# )
|
48
|
-
# expect(source.
|
49
|
-
# @example returns
|
56
|
+
# expect(source.name).to eq('/path/to/foo.rb')
|
57
|
+
# @example returns opaque for untitled URI
|
50
58
|
# source = Rucoa::Source.new(
|
51
59
|
# content: '',
|
52
60
|
# uri: 'untitled:Untitled-1'
|
53
61
|
# )
|
54
|
-
# expect(source.
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
::CGI.unescape(path)
|
62
|
+
# expect(source.name).to eq('Untitled-1')
|
63
|
+
def name
|
64
|
+
if untitled?
|
65
|
+
uri_object.opaque
|
66
|
+
else
|
67
|
+
uri_object.path
|
68
|
+
end
|
62
69
|
end
|
63
70
|
|
64
71
|
# @param position [Rucoa::Position]
|
@@ -67,29 +74,45 @@ module Rucoa
|
|
67
74
|
root_and_descendant_nodes.reverse.find do |node|
|
68
75
|
node.include_position?(position)
|
69
76
|
end
|
70
|
-
rescue ::Parser::SyntaxError
|
71
|
-
nil
|
72
77
|
end
|
73
78
|
|
74
79
|
# @return [Rucoa::Nodes::Base, nil]
|
75
80
|
def root_node
|
76
|
-
|
77
|
-
|
78
|
-
|
81
|
+
parse_result.root_node
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Boolean]
|
85
|
+
def failed_to_parse?
|
86
|
+
parse_result.failed?
|
79
87
|
end
|
80
88
|
|
81
89
|
# @return [Boolean]
|
82
|
-
def
|
83
|
-
|
90
|
+
def untitled?
|
91
|
+
uri_object.scheme == 'untitled'
|
84
92
|
end
|
85
93
|
|
86
94
|
private
|
87
95
|
|
96
|
+
# @return [Rucoa::ParseResult]
|
97
|
+
def parse_result
|
98
|
+
return @parse_result if instance_variable_defined?(:@parse_result)
|
99
|
+
|
100
|
+
@parse_result = Parser.call(
|
101
|
+
path: name,
|
102
|
+
text: @content
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
88
106
|
# @return [Array<Rucoa::Nodes::Base>]
|
89
107
|
def root_and_descendant_nodes
|
90
108
|
return [] unless root_node
|
91
109
|
|
92
110
|
[root_node, *root_node.descendants]
|
93
111
|
end
|
112
|
+
|
113
|
+
# @return [URI]
|
114
|
+
def uri_object
|
115
|
+
@uri_object ||= ::URI.parse(@uri)
|
116
|
+
end
|
94
117
|
end
|
95
118
|
end
|
data/lib/rucoa/source_store.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'cgi'
|
4
|
-
require 'uri'
|
5
|
-
|
6
3
|
module Rucoa
|
7
4
|
class SourceStore
|
8
5
|
def initialize
|
@@ -26,15 +23,5 @@ module Rucoa
|
|
26
23
|
def each_uri(&block)
|
27
24
|
@data.each_key(&block)
|
28
25
|
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
# @param uri [String]
|
33
|
-
# @return [String]
|
34
|
-
def path_from_uri(uri)
|
35
|
-
::CGI.unescape(
|
36
|
-
::URI.parse(uri).path || 'untitled'
|
37
|
-
)
|
38
|
-
end
|
39
26
|
end
|
40
27
|
end
|
data/lib/rucoa/version.rb
CHANGED