referral 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +32 -0
- data/.gitignore +8 -0
- data/.standard.yml +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +20 -0
- data/README.md +249 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/referral +7 -0
- data/lib/referral/cli.rb +18 -0
- data/lib/referral/error.rb +3 -0
- data/lib/referral/expands_directories.rb +13 -0
- data/lib/referral/file_store.rb +13 -0
- data/lib/referral/filters_tokens.rb +51 -0
- data/lib/referral/git_store.rb +42 -0
- data/lib/referral/matches_token_names.rb +22 -0
- data/lib/referral/parses_options.rb +64 -0
- data/lib/referral/prints_results.rb +67 -0
- data/lib/referral/runner.rb +20 -0
- data/lib/referral/scans_tokens.rb +41 -0
- data/lib/referral/sorts_tokens.rb +46 -0
- data/lib/referral/token_types.rb +186 -0
- data/lib/referral/tokenizes_identifiers.rb +32 -0
- data/lib/referral/translates_node_to_token.rb +29 -0
- data/lib/referral/value/node_type.rb +15 -0
- data/lib/referral/value/options.rb +38 -0
- data/lib/referral/value/result.rb +6 -0
- data/lib/referral/value/token.rb +68 -0
- data/lib/referral/version.rb +3 -0
- data/lib/referral.rb +11 -0
- data/referral.gemspec +29 -0
- metadata +135 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require "time"
|
2
|
+
require "referral/file_store"
|
3
|
+
require "referral/git_store"
|
4
|
+
|
5
|
+
module Referral
|
6
|
+
COLUMN_FUNCTIONS = {
|
7
|
+
id: ->(token) {
|
8
|
+
token.id
|
9
|
+
},
|
10
|
+
location: ->(token) {
|
11
|
+
"#{token.file}:#{token.line}:#{token.column}:"
|
12
|
+
},
|
13
|
+
file: ->(token) {
|
14
|
+
token.file
|
15
|
+
},
|
16
|
+
line: ->(token) {
|
17
|
+
token.line
|
18
|
+
},
|
19
|
+
column: ->(token) {
|
20
|
+
token.column
|
21
|
+
},
|
22
|
+
type: ->(token) {
|
23
|
+
token.type_name
|
24
|
+
},
|
25
|
+
scope: ->(token) {
|
26
|
+
token.scope
|
27
|
+
},
|
28
|
+
name: ->(token) {
|
29
|
+
token.literal_name
|
30
|
+
},
|
31
|
+
full_name: ->(token) {
|
32
|
+
token.full_name
|
33
|
+
},
|
34
|
+
source: ->(token) {
|
35
|
+
FileStore.read_line(token.file, token.line)
|
36
|
+
},
|
37
|
+
git_sha: ->(token) {
|
38
|
+
GitStore.sha(token.file, token.line)
|
39
|
+
},
|
40
|
+
git_author: ->(token) {
|
41
|
+
GitStore.author(token.file, token.line)
|
42
|
+
},
|
43
|
+
git_commit_at: ->(token) {
|
44
|
+
GitStore.time(token.file, token.line)&.utc&.iso8601
|
45
|
+
},
|
46
|
+
|
47
|
+
}
|
48
|
+
|
49
|
+
class PrintsResults
|
50
|
+
def call(result, options)
|
51
|
+
if options[:print_headers]
|
52
|
+
puts options[:columns].join(options[:delimiter])
|
53
|
+
end
|
54
|
+
|
55
|
+
result.tokens.each do |token|
|
56
|
+
cells = options[:columns].map { |column_name|
|
57
|
+
if (column = COLUMN_FUNCTIONS[column_name.to_sym])
|
58
|
+
column.call(token)
|
59
|
+
else
|
60
|
+
raise Referral::Error.new("Column '#{column_name}' not found in Referral::COLUMN_FUNCTIONS")
|
61
|
+
end
|
62
|
+
}
|
63
|
+
puts cells.join(options[:delimiter])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "referral/filters_tokens"
|
2
|
+
require "referral/sorts_tokens"
|
3
|
+
require "referral/scans_tokens"
|
4
|
+
require "referral/value/result"
|
5
|
+
|
6
|
+
module Referral
|
7
|
+
class Runner
|
8
|
+
def call(options)
|
9
|
+
Value::Result.new(
|
10
|
+
tokens: SortsTokens.new.call(
|
11
|
+
FiltersTokens.new.call(
|
12
|
+
ScansTokens.new.call(files: options.files),
|
13
|
+
options
|
14
|
+
),
|
15
|
+
options
|
16
|
+
)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "referral/translates_node_to_token"
|
2
|
+
require "referral/expands_directories"
|
3
|
+
require "referral/tokenizes_identifiers"
|
4
|
+
|
5
|
+
module Referral
|
6
|
+
class ScansTokens
|
7
|
+
def initialize
|
8
|
+
@expands_directories = ExpandsDirectories.new
|
9
|
+
@translates_node_to_token = TranslatesNodeToToken.new
|
10
|
+
@tokenizes_identifiers = TokenizesIdentifiers.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(files:, &blk)
|
14
|
+
@expands_directories.call(files).flat_map { |file|
|
15
|
+
begin
|
16
|
+
root = RubyVM::AbstractSyntaxTree.parse_file(file)
|
17
|
+
find_tokens([root], nil, file)
|
18
|
+
rescue SyntaxError => e
|
19
|
+
warn "ERROR: Failed to parse \"#{file}\": #{e.message} (#{e.class})"
|
20
|
+
rescue SystemCallError => e
|
21
|
+
warn "ERROR: Failed to read \"#{file}\": #{e.message} (#{e.class})"
|
22
|
+
end
|
23
|
+
}.compact
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def find_tokens(nodes, parent, file)
|
29
|
+
nodes.flat_map { |node|
|
30
|
+
next unless node.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
31
|
+
|
32
|
+
if (token = @translates_node_to_token.call(node, parent, file))
|
33
|
+
@tokenizes_identifiers.call(node, token)
|
34
|
+
[token, *find_tokens(node.children[1..-1], token, file)]
|
35
|
+
else
|
36
|
+
find_tokens(node.children, parent, file)
|
37
|
+
end
|
38
|
+
}.compact
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "referral/git_store"
|
2
|
+
|
3
|
+
module Referral
|
4
|
+
SORT_FUNCTIONS = {
|
5
|
+
file: ->(tokens) {
|
6
|
+
tokens.sort_by { |token|
|
7
|
+
[token.file, token.line, token.column, token.id]
|
8
|
+
}
|
9
|
+
},
|
10
|
+
scope: ->(tokens) {
|
11
|
+
max_length = tokens.map { |t| t.fully_qualified.size }.max
|
12
|
+
tokens.sort_by { |token|
|
13
|
+
names = token.fully_qualified.map { |fq| fq.name.to_s }
|
14
|
+
[
|
15
|
+
*names.fill("", names.size...max_length),
|
16
|
+
token.file, token.line, token.column, token.id,
|
17
|
+
]
|
18
|
+
}
|
19
|
+
},
|
20
|
+
least_recent_commit: ->(tokens) {
|
21
|
+
tokens.sort_by do |token|
|
22
|
+
[
|
23
|
+
GitStore.time(token.file, token.line).to_i,
|
24
|
+
token.file, token.line, token.column, token.id,
|
25
|
+
]
|
26
|
+
end
|
27
|
+
},
|
28
|
+
most_recent_commit: ->(tokens) {
|
29
|
+
tokens.sort_by { |token|
|
30
|
+
[
|
31
|
+
-1 * GitStore.time(token.file, token.line).to_i,
|
32
|
+
token.file, token.line, token.column, token.id,
|
33
|
+
]
|
34
|
+
}
|
35
|
+
},
|
36
|
+
}
|
37
|
+
class SortsTokens
|
38
|
+
def call(tokens, options)
|
39
|
+
if (sort_func = SORT_FUNCTIONS[options[:sort].to_sym])
|
40
|
+
sort_func.call(tokens)
|
41
|
+
else
|
42
|
+
raise Referral::Error.new("Sort '#{options[:sort]} not found in Referral::SORT_FUNCTIONS")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require "referral/value/node_type"
|
2
|
+
|
3
|
+
module Referral
|
4
|
+
JOIN_SEPARATORS = {
|
5
|
+
double_colon: "::",
|
6
|
+
dot: ".",
|
7
|
+
hash: "#",
|
8
|
+
tilde: "~",
|
9
|
+
}
|
10
|
+
TOKEN_TYPES = {
|
11
|
+
module: Value::NodeType.new(
|
12
|
+
name: :module,
|
13
|
+
ast_type: :MODULE,
|
14
|
+
join_separator: JOIN_SEPARATORS[:double_colon],
|
15
|
+
token_type: :definition,
|
16
|
+
reverse_identifiers: false,
|
17
|
+
good_parent: true,
|
18
|
+
name_finder: ->(node) { nil }
|
19
|
+
),
|
20
|
+
class: Value::NodeType.new(
|
21
|
+
name: :class,
|
22
|
+
ast_type: :CLASS,
|
23
|
+
join_separator: JOIN_SEPARATORS[:double_colon],
|
24
|
+
token_type: :definition,
|
25
|
+
reverse_identifiers: false,
|
26
|
+
good_parent: true,
|
27
|
+
name_finder: ->(node) { nil }
|
28
|
+
),
|
29
|
+
constant_def: Value::NodeType.new(
|
30
|
+
name: :constant_declaration,
|
31
|
+
ast_type: :CDECL,
|
32
|
+
join_separator: JOIN_SEPARATORS[:double_colon],
|
33
|
+
token_type: :definition,
|
34
|
+
reverse_identifiers: false,
|
35
|
+
good_parent: true,
|
36
|
+
name_finder: ->(node) {
|
37
|
+
possible_name = node.children[0]
|
38
|
+
possible_name.is_a?(Symbol) ? possible_name : nil
|
39
|
+
}
|
40
|
+
),
|
41
|
+
class_method: Value::NodeType.new(
|
42
|
+
name: :class_method,
|
43
|
+
ast_type: :DEFS,
|
44
|
+
join_separator: JOIN_SEPARATORS[:dot],
|
45
|
+
token_type: :definition,
|
46
|
+
reverse_identifiers: false,
|
47
|
+
good_parent: true,
|
48
|
+
name_finder: ->(node) { node.children[1] }
|
49
|
+
),
|
50
|
+
instance_method: Value::NodeType.new(
|
51
|
+
name: :instance_method,
|
52
|
+
ast_type: :DEFN,
|
53
|
+
join_separator: JOIN_SEPARATORS[:hash],
|
54
|
+
token_type: :definition,
|
55
|
+
reverse_identifiers: false,
|
56
|
+
good_parent: true,
|
57
|
+
name_finder: ->(node) { node.children[0] }
|
58
|
+
),
|
59
|
+
local_var_assign: Value::NodeType.new(
|
60
|
+
name: :local_var_assign,
|
61
|
+
ast_type: :LASGN,
|
62
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
63
|
+
token_type: :definition,
|
64
|
+
reverse_identifiers: false,
|
65
|
+
good_parent: false,
|
66
|
+
name_finder: ->(node) { node.children[0] }
|
67
|
+
),
|
68
|
+
instance_var_assign: Value::NodeType.new(
|
69
|
+
name: :instance_var_assign,
|
70
|
+
ast_type: :IASGN,
|
71
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
72
|
+
token_type: :definition,
|
73
|
+
reverse_identifiers: false,
|
74
|
+
good_parent: false,
|
75
|
+
name_finder: ->(node) { node.children[0] }
|
76
|
+
),
|
77
|
+
class_var_assign: Value::NodeType.new(
|
78
|
+
name: :class_var_assign,
|
79
|
+
ast_type: :CVASGN,
|
80
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
81
|
+
token_type: :definition,
|
82
|
+
reverse_identifiers: false,
|
83
|
+
good_parent: false,
|
84
|
+
name_finder: ->(node) { node.children[0] }
|
85
|
+
),
|
86
|
+
global_var_assign: Value::NodeType.new(
|
87
|
+
name: :global_var_assign,
|
88
|
+
ast_type: :GASGN,
|
89
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
90
|
+
token_type: :definition,
|
91
|
+
reverse_identifiers: false,
|
92
|
+
good_parent: false,
|
93
|
+
name_finder: ->(node) { node.children[0] }
|
94
|
+
),
|
95
|
+
attr_assign: Value::NodeType.new(
|
96
|
+
name: :attr_assign,
|
97
|
+
ast_type: :ATTRASGN,
|
98
|
+
join_separator: JOIN_SEPARATORS[:dot],
|
99
|
+
token_type: :definition,
|
100
|
+
reverse_identifiers: false,
|
101
|
+
good_parent: false,
|
102
|
+
name_finder: ->(node) { node.children[1] }
|
103
|
+
),
|
104
|
+
call: Value::NodeType.new(
|
105
|
+
name: :call,
|
106
|
+
ast_type: :CALL,
|
107
|
+
join_separator: JOIN_SEPARATORS[:dot],
|
108
|
+
token_type: :reference,
|
109
|
+
reverse_identifiers: true,
|
110
|
+
good_parent: true,
|
111
|
+
name_finder: ->(node) { node.children[1] }
|
112
|
+
),
|
113
|
+
function_call: Value::NodeType.new(
|
114
|
+
name: :function_call,
|
115
|
+
ast_type: :FCALL,
|
116
|
+
join_separator: JOIN_SEPARATORS[:dot],
|
117
|
+
token_type: :reference,
|
118
|
+
reverse_identifiers: true,
|
119
|
+
good_parent: false,
|
120
|
+
name_finder: ->(node) { node.children[0] }
|
121
|
+
),
|
122
|
+
local_var: Value::NodeType.new(
|
123
|
+
name: :local_var,
|
124
|
+
ast_type: :LVAR,
|
125
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
126
|
+
token_type: :reference,
|
127
|
+
reverse_identifiers: true,
|
128
|
+
good_parent: false,
|
129
|
+
name_finder: ->(node) { node.children[0] }
|
130
|
+
),
|
131
|
+
instance_var: Value::NodeType.new(
|
132
|
+
name: :instance_var,
|
133
|
+
ast_type: :IVAR,
|
134
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
135
|
+
token_type: :reference,
|
136
|
+
reverse_identifiers: true,
|
137
|
+
good_parent: false,
|
138
|
+
name_finder: ->(node) { node.children[0] }
|
139
|
+
),
|
140
|
+
class_var: Value::NodeType.new(
|
141
|
+
name: :class_var,
|
142
|
+
ast_type: :CVAR,
|
143
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
144
|
+
token_type: :reference,
|
145
|
+
reverse_identifiers: true,
|
146
|
+
good_parent: false,
|
147
|
+
name_finder: ->(node) { node.children[0] }
|
148
|
+
),
|
149
|
+
global_var: Value::NodeType.new(
|
150
|
+
name: :global_var,
|
151
|
+
ast_type: :GVAR,
|
152
|
+
join_separator: JOIN_SEPARATORS[:tilde],
|
153
|
+
token_type: :reference,
|
154
|
+
reverse_identifiers: true,
|
155
|
+
good_parent: false,
|
156
|
+
name_finder: ->(node) { node.children[0] }
|
157
|
+
),
|
158
|
+
constant_ref: Value::NodeType.new(
|
159
|
+
name: :constant,
|
160
|
+
ast_type: :CONST,
|
161
|
+
join_separator: JOIN_SEPARATORS[:double_colon],
|
162
|
+
token_type: :reference,
|
163
|
+
reverse_identifiers: true,
|
164
|
+
good_parent: false,
|
165
|
+
name_finder: ->(node) { node.children[0] }
|
166
|
+
),
|
167
|
+
double_colon: Value::NodeType.new(
|
168
|
+
name: :constant,
|
169
|
+
ast_type: :COLON2,
|
170
|
+
join_separator: JOIN_SEPARATORS[:double_colon],
|
171
|
+
token_type: :reference,
|
172
|
+
reverse_identifiers: true,
|
173
|
+
good_parent: false,
|
174
|
+
name_finder: ->(node) { node.children[1] }
|
175
|
+
),
|
176
|
+
triple_colon: Value::NodeType.new(
|
177
|
+
name: :constant,
|
178
|
+
ast_type: :COLON3,
|
179
|
+
join_separator: JOIN_SEPARATORS[:double_colon],
|
180
|
+
token_type: :reference,
|
181
|
+
reverse_identifiers: true,
|
182
|
+
good_parent: false,
|
183
|
+
name_finder: ->(node) { node.children[0] }
|
184
|
+
),
|
185
|
+
}
|
186
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "referral/translates_node_to_token"
|
2
|
+
|
3
|
+
module Referral
|
4
|
+
class TokenizesIdentifiers
|
5
|
+
def initialize
|
6
|
+
@translates_node_to_token = TranslatesNodeToToken.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(root_node, root_token)
|
10
|
+
find_names(root_node, root_token)
|
11
|
+
.reject { |identifier_token| identifier_token.name.nil? }
|
12
|
+
.tap do |identifiers|
|
13
|
+
root_token.identifiers = identifiers
|
14
|
+
|
15
|
+
if identifiers.any? { |id| id.node_type == TOKEN_TYPES[:triple_colon] }
|
16
|
+
root_token.parent = nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def find_names(node, parent)
|
24
|
+
return [] unless node.is_a?(RubyVM::AbstractSyntaxTree::Node)
|
25
|
+
|
26
|
+
[
|
27
|
+
*find_names(node.children.first, parent),
|
28
|
+
@translates_node_to_token.call(node, parent, parent.file),
|
29
|
+
].compact
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "referral/token_types"
|
2
|
+
require "referral/value/token"
|
3
|
+
|
4
|
+
module Referral
|
5
|
+
class TranslatesNodeToToken
|
6
|
+
def call(node, parent, file)
|
7
|
+
return unless (type = TOKEN_TYPES.values.find { |d| node.type == d.ast_type })
|
8
|
+
|
9
|
+
Value::Token.new(
|
10
|
+
name: type.name_finder.call(node),
|
11
|
+
node_type: type,
|
12
|
+
parent: parent_unless_bad_parent(parent, type),
|
13
|
+
file: file,
|
14
|
+
line: node.first_lineno,
|
15
|
+
column: node.first_column
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def parent_unless_bad_parent(parent_token, type)
|
22
|
+
return parent_token if parent_token&.node_type&.good_parent
|
23
|
+
|
24
|
+
# puts "should a #{parent_token.node_type.name} parent a #{type.name}?"
|
25
|
+
# return if parent_token.node_type.name == :local_var_assign
|
26
|
+
# parent_token
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Referral
|
2
|
+
module Value
|
3
|
+
class Options < Struct.new(
|
4
|
+
:files,
|
5
|
+
# Filtering
|
6
|
+
:name,
|
7
|
+
:exact_name,
|
8
|
+
:full_name,
|
9
|
+
:pattern,
|
10
|
+
:type,
|
11
|
+
:include_unnamed,
|
12
|
+
# Sorting
|
13
|
+
:sort,
|
14
|
+
# Printing
|
15
|
+
:print_headers,
|
16
|
+
:columns,
|
17
|
+
:delimiter,
|
18
|
+
keyword_init: true
|
19
|
+
)
|
20
|
+
|
21
|
+
def self.default(overrides = {})
|
22
|
+
DEFAULT.merge({files: Dir["**/*.rb"]}.merge(overrides))
|
23
|
+
end
|
24
|
+
|
25
|
+
DEFAULT = new(
|
26
|
+
columns: ["location", "type", "scope", "name"],
|
27
|
+
delimiter: " ",
|
28
|
+
include_unnamed: false,
|
29
|
+
sort: "file",
|
30
|
+
print_headers: false,
|
31
|
+
).freeze
|
32
|
+
|
33
|
+
def merge(new_opts)
|
34
|
+
self.class.new(to_h.merge(new_opts))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
|
3
|
+
module Referral
|
4
|
+
module Value
|
5
|
+
class Token < Struct.new(
|
6
|
+
:name, :identifiers, :node_type, :parent, :file, :line, :column,
|
7
|
+
keyword_init: true
|
8
|
+
)
|
9
|
+
|
10
|
+
def fully_qualified
|
11
|
+
[
|
12
|
+
*parent&.fully_qualified,
|
13
|
+
*identity_components,
|
14
|
+
].compact
|
15
|
+
end
|
16
|
+
|
17
|
+
def full_name
|
18
|
+
join_names(fully_qualified)
|
19
|
+
end
|
20
|
+
|
21
|
+
def scope
|
22
|
+
return "" unless parent
|
23
|
+
parent.full_name
|
24
|
+
end
|
25
|
+
|
26
|
+
def literal_name
|
27
|
+
if identifiers.empty?
|
28
|
+
name.to_s
|
29
|
+
else
|
30
|
+
join_names(identifiers)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def type_name
|
35
|
+
node_type.name.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def id
|
39
|
+
Digest::SHA1.hexdigest(to_h.merge(
|
40
|
+
parent: nil,
|
41
|
+
identifiers: identifiers&.map(&:id),
|
42
|
+
node_type: node_type.name
|
43
|
+
).inspect)[0..6]
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def join_names(tokens)
|
49
|
+
tokens.reduce("") { |s, token|
|
50
|
+
next s unless token.name
|
51
|
+
if s.empty?
|
52
|
+
token.name.to_s
|
53
|
+
else
|
54
|
+
"#{s}#{token.node_type.join_separator}#{token.name}"
|
55
|
+
end
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def identity_components
|
60
|
+
if identifiers && !identifiers.empty?
|
61
|
+
identifiers
|
62
|
+
else
|
63
|
+
[self]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/referral.rb
ADDED
data/referral.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "referral/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "referral"
|
7
|
+
spec.version = Referral::VERSION
|
8
|
+
spec.authors = ["Justin Searls"]
|
9
|
+
spec.email = ["searls@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Scan for definitions and references in your Ruby code."
|
12
|
+
spec.homepage = "https://github.com/testdouble/referral"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
16
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
17
|
+
|
18
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
end
|
21
|
+
spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.17.3"
|
26
|
+
spec.add_development_dependency "rake", "~> 12.3"
|
27
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
28
|
+
spec.add_development_dependency "standard"
|
29
|
+
end
|