code_web 0.0.4
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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +85 -0
- data/Rakefile +6 -0
- data/code_web.gemspec +26 -0
- data/exe/code_web +6 -0
- data/lib/code_web/cli.rb +101 -0
- data/lib/code_web/code_parser.rb +229 -0
- data/lib/code_web/html_report.rb +157 -0
- data/lib/code_web/method_cache.rb +29 -0
- data/lib/code_web/method_call.rb +116 -0
- data/lib/code_web/method_list.rb +60 -0
- data/lib/code_web/text_report.rb +41 -0
- data/lib/code_web/version.rb +3 -0
- data/lib/code_web.rb +11 -0
- data/spec/code_parser_spec.rb +252 -0
- data/spec/method_cache_spec.rb +29 -0
- data/spec/method_call_spec.rb +69 -0
- data/spec/method_list_spec.rb +32 -0
- data/spec/spec_helper.rb +7 -0
- metadata +129 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module CodeWeb
|
2
|
+
class MethodCache
|
3
|
+
# Map<String,Array<MethodCall>>
|
4
|
+
attr_accessor :method_calls
|
5
|
+
|
6
|
+
# only store the information on these methods
|
7
|
+
attr_accessor :method_regex
|
8
|
+
attr_accessor :arg_regex
|
9
|
+
|
10
|
+
def initialize(method_regex = nil)
|
11
|
+
@method_calls=[]
|
12
|
+
@method_regex = method_regex
|
13
|
+
end
|
14
|
+
|
15
|
+
def <<(mc)
|
16
|
+
@method_calls << mc if detect?(mc)
|
17
|
+
end
|
18
|
+
|
19
|
+
def detect?(mc)
|
20
|
+
(method_regex.nil? || mc.full_method_name =~ method_regex) &&
|
21
|
+
(
|
22
|
+
arg_regex.nil? || (
|
23
|
+
mc.hash_args? &&
|
24
|
+
mc.arg_keys.detect {|key| key =~ arg_regex }
|
25
|
+
)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module CodeWeb
|
2
|
+
# method call reference
|
3
|
+
class MethodCall
|
4
|
+
# file that has this method call
|
5
|
+
attr_accessor :filename
|
6
|
+
# line number that has this method
|
7
|
+
attr_accessor :line
|
8
|
+
# method name
|
9
|
+
attr_accessor :name
|
10
|
+
# what arguments are passed in
|
11
|
+
attr_accessor :args
|
12
|
+
alias :arguments :args
|
13
|
+
# is this calling a yield block
|
14
|
+
attr_accessor :is_yielding
|
15
|
+
|
16
|
+
def initialize(filename, line, name=nil, args=[], is_yielding=false)
|
17
|
+
@filename = filename
|
18
|
+
@line = line
|
19
|
+
@name = name
|
20
|
+
@args = sorted_hash(args)
|
21
|
+
@is_yielding = !! is_yielding
|
22
|
+
end
|
23
|
+
|
24
|
+
def args?
|
25
|
+
args && !args.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def yields?
|
29
|
+
is_yielding
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_types
|
33
|
+
args.map { |arg| arg_type(arg) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def small_signature
|
37
|
+
[arg_type(args.first), args.size]
|
38
|
+
end
|
39
|
+
|
40
|
+
def signature
|
41
|
+
"#{full_method_name}(#{sorted_args.to_s})#{" yields" if is_yielding}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def short_method_name
|
45
|
+
Array(name).last
|
46
|
+
end
|
47
|
+
|
48
|
+
def full_method_name
|
49
|
+
Array(name).compact.join(".")
|
50
|
+
end
|
51
|
+
|
52
|
+
def short_filename
|
53
|
+
filename.split("/").last if filename
|
54
|
+
end
|
55
|
+
|
56
|
+
def sorted_args(hash=@args)
|
57
|
+
hash.map {|arg| sorted_hash(arg) }.join(", ")
|
58
|
+
end
|
59
|
+
|
60
|
+
def sorted_hash(args)
|
61
|
+
case args
|
62
|
+
when Hash
|
63
|
+
args.each_pair.sort_by {|n,v| n }.inject({}) {|h, (n,v)| h[n]=sorted_hash(v); h}
|
64
|
+
when Array
|
65
|
+
args
|
66
|
+
else
|
67
|
+
args
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def hash_args?
|
72
|
+
args.first.class == Hash
|
73
|
+
end
|
74
|
+
|
75
|
+
def args_size
|
76
|
+
args.size
|
77
|
+
end
|
78
|
+
|
79
|
+
def hash_arg
|
80
|
+
args.first
|
81
|
+
end
|
82
|
+
|
83
|
+
def arg_keys
|
84
|
+
args.first.keys
|
85
|
+
end
|
86
|
+
|
87
|
+
def ==(other)
|
88
|
+
other &&
|
89
|
+
other.name == @name &&
|
90
|
+
other.args == @args &&
|
91
|
+
other.is_yielding == @is_yielding
|
92
|
+
end
|
93
|
+
|
94
|
+
# used by debugging (not sure if this should be signature)
|
95
|
+
def to_s(spaces = '')
|
96
|
+
"#{spaces}#{full_method_name}(#{args.map{|arg|arg.inspect}.join(", ")})#{" do" if is_yielding}"
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def arg_type(arg)
|
102
|
+
case arg
|
103
|
+
when Array
|
104
|
+
'[]'
|
105
|
+
when Hash
|
106
|
+
'{}'
|
107
|
+
when nil
|
108
|
+
"nil"
|
109
|
+
when Symbol
|
110
|
+
':'
|
111
|
+
else
|
112
|
+
'str'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
#collection of similar method calls
|
3
|
+
module CodeWeb
|
4
|
+
class MethodList
|
5
|
+
extend Forwardable
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
# what was used in the group by
|
9
|
+
attr_accessor :name
|
10
|
+
# the collection (actually [[k,[v1,v2]],[k2,[v1,v2]]])
|
11
|
+
attr_accessor :collection
|
12
|
+
|
13
|
+
def initialize(name, collection)
|
14
|
+
@name = name
|
15
|
+
@collection = collection
|
16
|
+
end
|
17
|
+
|
18
|
+
def group_by(name, arg_regex=nil, sort_by = nil, &block)
|
19
|
+
if block.nil?
|
20
|
+
if arg_regex.nil?
|
21
|
+
block = Proc.new { |m| m.send(name).to_s }
|
22
|
+
else
|
23
|
+
block = Proc.new {|m|
|
24
|
+
if m.hash_args?
|
25
|
+
m.hash_arg.collect {|n,v| v if n =~ arg_regex}.compact.join(" ")
|
26
|
+
else
|
27
|
+
m.signature
|
28
|
+
end
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
MethodList.new(name, collection.group_by(&block).sort_by {|n, ms| sort_by ? ms.first.send(sort_by) : n })
|
33
|
+
end
|
34
|
+
|
35
|
+
def f
|
36
|
+
collection.first
|
37
|
+
end
|
38
|
+
|
39
|
+
delegate [:detect, :each_with_index, :count] => :collection
|
40
|
+
delegate [:args_size, :hash_arg, :hash_args?] => :f
|
41
|
+
|
42
|
+
def detect(&block)
|
43
|
+
collection.detect(&block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def each(&block)
|
47
|
+
collection.each do |n, c|
|
48
|
+
yield MethodList.new(n,c)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def arg_keys
|
53
|
+
@arg_keys ||= collection.inject(Set.new) {|acc, m| m.arg_keys.each {|k| acc << k} ; acc}.sort_by {|n| n}
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.group_by(collection, name)
|
57
|
+
MethodList.new(nil, collection).group_by(name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module CodeWeb
|
2
|
+
class TextReport
|
3
|
+
# @!attribute :method_calls [r]
|
4
|
+
# list of all the method_Calls
|
5
|
+
# @return [Array<MethodCall>]
|
6
|
+
attr_accessor :method_calls
|
7
|
+
attr_accessor :arg_regex
|
8
|
+
def arg_regex? ; ! arg_regex.nil? ; end
|
9
|
+
|
10
|
+
def initialize(method_calls, class_map=nil, arg_regex=nil, out=STDOUT)
|
11
|
+
@method_calls = method_calls
|
12
|
+
@arg_regex = arg_regex
|
13
|
+
@out = out
|
14
|
+
end
|
15
|
+
|
16
|
+
def report
|
17
|
+
methods_by_name.each do |methods|
|
18
|
+
@out.puts "---- #{methods.name} ----"
|
19
|
+
methods.group_by(:signature, arg_regex).each do |methods_with_signature|
|
20
|
+
if arg_regex?
|
21
|
+
@out.puts " --> #{arg_regex.inspect}=#{methods_with_signature.name}"
|
22
|
+
else
|
23
|
+
@out.puts " --> #{methods_with_signature.name}"
|
24
|
+
end
|
25
|
+
methods_with_signature.each_with_index do |method, i|
|
26
|
+
@out.puts
|
27
|
+
@out.puts method.signature
|
28
|
+
@out.puts "#{method.filename}:#{method.line}"
|
29
|
+
end
|
30
|
+
@out.puts
|
31
|
+
@out.puts
|
32
|
+
end
|
33
|
+
@out.puts
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def methods_by_name
|
38
|
+
MethodList.group_by(method_calls, :short_method_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/code_web.rb
ADDED
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
#$debug=true
|
4
|
+
#$verbose=true
|
5
|
+
describe CodeWeb::CodeParser do
|
6
|
+
|
7
|
+
context "method call" do
|
8
|
+
it 'should add a method' do
|
9
|
+
subject << CodeWeb::MethodCall.new(nil, "puts", ['"x"'], false )
|
10
|
+
expect(method_calls('puts')).to eq([
|
11
|
+
meth('puts',['"x"'])
|
12
|
+
])
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should support basic method call' do
|
16
|
+
parse %{puts}
|
17
|
+
expect(method_calls('puts')).to eq([
|
18
|
+
meth('puts',[])
|
19
|
+
])
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should support method call with arguments' do
|
23
|
+
parse %{puts "x", :y, true, false}
|
24
|
+
expect(method_calls('puts')).to eq([
|
25
|
+
meth('puts',['"x"', :y, :true, :false])
|
26
|
+
])
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should support method calls with hash arguments' do
|
30
|
+
parse %{puts(a:5, "b" => 3)}
|
31
|
+
expect(method_calls('puts')).to eq([
|
32
|
+
meth('puts',{:a => 5, "b" => 3})
|
33
|
+
])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should support method call ob objects' do
|
37
|
+
parse %{y.puts "x"}
|
38
|
+
expect(method_calls('y.puts')).to eq([
|
39
|
+
meth('y.puts',['"x"'])
|
40
|
+
])
|
41
|
+
end
|
42
|
+
|
43
|
+
#NOTE the chaining isn't perfect
|
44
|
+
it "should support method chaining" do
|
45
|
+
parse "x(a:5).y().z(5)"
|
46
|
+
expect(method_calls('x')).to eq([
|
47
|
+
meth('x', [{a:5}])
|
48
|
+
])
|
49
|
+
|
50
|
+
expect(method_calls('x(...).y')).to eq([
|
51
|
+
meth('x(...).y')
|
52
|
+
])
|
53
|
+
|
54
|
+
expect(method_calls('x(...).y.z')).to eq([
|
55
|
+
meth('x(...).y.z',[5])
|
56
|
+
])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should support method calls with method calls' do
|
60
|
+
parse "a(b(5))"
|
61
|
+
expect(method_calls('b')).to eq([
|
62
|
+
meth('b',[5])
|
63
|
+
])
|
64
|
+
expect(method_calls('a')).to eq([
|
65
|
+
meth('a','b(...)')
|
66
|
+
])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'blocks' do
|
71
|
+
it 'should support if blocks' do
|
72
|
+
parse "if a(5) ; b(5) ; else c(5) ; end"
|
73
|
+
expect(method_calls('a')).to eq([
|
74
|
+
meth('a',[5])
|
75
|
+
])
|
76
|
+
expect(method_calls('b')).to eq([
|
77
|
+
meth('b',[5])
|
78
|
+
])
|
79
|
+
expect(method_calls('c')).to eq([
|
80
|
+
meth('c',[5])
|
81
|
+
])
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should support yield blocks' do
|
85
|
+
parse "a(5) { |x| b(x) }"
|
86
|
+
expect(method_calls('a')).to eq([
|
87
|
+
meth('a',[5], true)
|
88
|
+
])
|
89
|
+
expect(method_calls('b')).to eq([
|
90
|
+
meth('b',[:x], false)
|
91
|
+
])
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should support rescue blocks' do
|
95
|
+
parse %{
|
96
|
+
begin
|
97
|
+
a(5)
|
98
|
+
rescue => e
|
99
|
+
b(5)
|
100
|
+
ensure
|
101
|
+
c()
|
102
|
+
end
|
103
|
+
}
|
104
|
+
expect(method_calls('a')).to eq([
|
105
|
+
meth('a',[5])
|
106
|
+
])
|
107
|
+
expect(method_calls('b')).to eq([
|
108
|
+
meth('b',[5])
|
109
|
+
])
|
110
|
+
expect(method_calls('c')).to eq([
|
111
|
+
meth('c')
|
112
|
+
])
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should support rescue blocks' do
|
116
|
+
parse "begin ; a(5) ; rescue ; b(5) ; end"
|
117
|
+
expect(method_calls('a')).to eq([
|
118
|
+
meth('a',[5])
|
119
|
+
])
|
120
|
+
expect(method_calls('b')).to eq([
|
121
|
+
meth('b',[5])
|
122
|
+
])
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should support rescue inline' do
|
126
|
+
parse "a(5) rescue b(5)"
|
127
|
+
expect(method_calls('a')).to eq([
|
128
|
+
meth('a',[5])
|
129
|
+
])
|
130
|
+
expect(method_calls('b')).to eq([
|
131
|
+
meth('b',[5])
|
132
|
+
])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'variables' do
|
137
|
+
it "should support global variables" do
|
138
|
+
parse %{$x=puts}
|
139
|
+
expect(method_calls('puts')).to eq([
|
140
|
+
meth('puts')
|
141
|
+
])
|
142
|
+
end
|
143
|
+
it "should support global variable fetch" do
|
144
|
+
parse %{$x = puts}
|
145
|
+
expect(method_calls('puts')).to eq([
|
146
|
+
meth('puts')
|
147
|
+
])
|
148
|
+
end
|
149
|
+
it "should support constants" do
|
150
|
+
parse %{
|
151
|
+
ABC=puts
|
152
|
+
Class::ABC.runx
|
153
|
+
}
|
154
|
+
expect(method_calls('puts')).to eq([
|
155
|
+
meth('puts')
|
156
|
+
])
|
157
|
+
expect(method_calls('Class.ABC.runx')).to eq([
|
158
|
+
meth('Class.ABC.runx')
|
159
|
+
])
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should parse modules' do
|
164
|
+
parse %{
|
165
|
+
module X
|
166
|
+
ABC=abc()
|
167
|
+
def method1
|
168
|
+
@module_var=mod1()
|
169
|
+
end
|
170
|
+
def method2
|
171
|
+
@@module_var=mod2()
|
172
|
+
end
|
173
|
+
def method3
|
174
|
+
return mod3()
|
175
|
+
end
|
176
|
+
end
|
177
|
+
}
|
178
|
+
expect(method_calls('abc')).to eq([
|
179
|
+
meth('abc')
|
180
|
+
])
|
181
|
+
expect(method_calls('mod1')).to eq([
|
182
|
+
meth('mod1')
|
183
|
+
])
|
184
|
+
expect(method_calls('mod2')).to eq([
|
185
|
+
meth('mod2')
|
186
|
+
])
|
187
|
+
expect(method_calls('mod3')).to eq([
|
188
|
+
meth('mod3')
|
189
|
+
])
|
190
|
+
|
191
|
+
end
|
192
|
+
it 'should support class' do
|
193
|
+
parse %{
|
194
|
+
module X
|
195
|
+
attr_accessor :var
|
196
|
+
class Class1
|
197
|
+
def method1
|
198
|
+
@var=m1(5)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
class Class2 < Class1
|
202
|
+
def method2
|
203
|
+
var=m2()
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
}
|
208
|
+
expect(method_calls('m1')).to eq([
|
209
|
+
meth('m1',[5])
|
210
|
+
])
|
211
|
+
expect(method_calls('m2')).to eq([
|
212
|
+
meth('m2')
|
213
|
+
])
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should interpolate strings" do
|
217
|
+
parse 'puts "abc#{subf()}"'
|
218
|
+
expect(method_calls('subf')).to eq([
|
219
|
+
meth('subf')
|
220
|
+
])
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should support logic" do
|
224
|
+
parse 'a() && b() || c() and d() or e()'
|
225
|
+
%w(a b c d e).each do |method_name|
|
226
|
+
expect(method_calls(method_name)).to eq([
|
227
|
+
meth(method_name)
|
228
|
+
])
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
private
|
233
|
+
|
234
|
+
def method_calls(method_name=nil)
|
235
|
+
if method_name
|
236
|
+
subject.method_calls.select { |mc| mc.full_method_name =~ /#{method_name}/ }
|
237
|
+
else
|
238
|
+
subject.method_calls
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def parse(body, require_string=nil)
|
243
|
+
test_method_name = caller[0].split(':').first #[0..1].join(':')
|
244
|
+
subject.parse(test_method_name, body, require_string)
|
245
|
+
end
|
246
|
+
|
247
|
+
def meth(name, args=[], is_yield=false, source = __FILE__)
|
248
|
+
name = [name.to_sym] if name.is_a?(String)
|
249
|
+
args = [args] unless args.is_a?(Array)
|
250
|
+
CodeWeb::MethodCall.new(source, 1, name, args, is_yield)
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CodeWeb::MethodCache do
|
4
|
+
describe "#<<" do
|
5
|
+
context "with default regex" do
|
6
|
+
it { expect(subject.method_calls).to be_empty }
|
7
|
+
context "with method" do
|
8
|
+
before { subject << methodcall }
|
9
|
+
it { expect(subject.method_calls.size).to eq(1) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with regex" do
|
14
|
+
subject { described_class.new(/good/)}
|
15
|
+
context "with matching regex" do
|
16
|
+
before { subject << methodcall("goodone") }
|
17
|
+
it { expect(subject.method_calls.size).to eq(1) }
|
18
|
+
end
|
19
|
+
context "with non-matching regex" do
|
20
|
+
before { subject << methodcall("badone") }
|
21
|
+
it { expect(subject.method_calls.size).to eq(0) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def methodcall(name = "method", args = [])
|
27
|
+
CodeWeb::MethodCall.new("file.rb", 5, name, args)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CodeWeb::MethodCall do
|
4
|
+
subject { described_class }
|
5
|
+
it "should compare" do
|
6
|
+
expect(meth('puts', ['a', 'b'])).to eq(meth('puts',['a','b'], false, ['sample.rb']))
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#args?" do
|
10
|
+
it { expect(meth("method", nil)).not_to be_args}
|
11
|
+
it { expect(meth("method", [])).not_to be_args}
|
12
|
+
it { expect(meth("method", [:a])).to be_args}
|
13
|
+
it { expect(meth("method", [:a => 'a'])).to be_args}
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#yields?" do
|
17
|
+
it { expect(meth("method", [], false)).not_to be_yield }
|
18
|
+
it { expect(meth("method", [], true)).to be_yield }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#method_types" do
|
22
|
+
it { expect(meth("method", [%w(a b), {'a' => 'b'}, nil, :a, 'b']).method_types).to eq(%w([] {} nil : str)) }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#small_signature" do
|
26
|
+
it { expect(meth("method", [%w(a b)]).small_signature).to eq(["[]", 1]) }
|
27
|
+
it { expect(meth("method", [[], [], []]).small_signature).to eq(["[]", 3]) }
|
28
|
+
it { expect(meth("method", [{}, []]).small_signature).to eq(["{}", 2]) }
|
29
|
+
it { expect(meth("method", []).small_signature).to eq(["nil", 0]) }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#signature" do
|
33
|
+
it { expect(meth("method", [%w(a b)]).signature).to eq("method(a, b)") }
|
34
|
+
#it { expect(meth("method", [[], [], []]).signature).to eq("method([],[],[])")}
|
35
|
+
# it { expect(meth("method", [{}, []]).signature).to eq("method({})") }
|
36
|
+
# it { expect(meth("method", []).signature).to eq("method(nil)") }
|
37
|
+
# it { expect(meth("method", [%w(a b), :other, :a => b]).signature).to eq("method(a, b)") }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "sorted_args" do
|
41
|
+
it "should not tack on [] to base args" do
|
42
|
+
expect(meth('name',['a','b']).sorted_args.to_s).to eq('a, b')
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should handle sub arrays" do
|
46
|
+
expect(meth.sorted_hash(['b']).to_s).to eq('["b"]')
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should handle hash" do
|
50
|
+
expect(meth.sorted_hash(b:5, a:3).to_s).to eq('{:a=>3, :b=>5}')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "method_type" do
|
55
|
+
# a string, a constant - same thing
|
56
|
+
it "should handle strings" do
|
57
|
+
expect(meth('name',['a']).method_types).to eq(['str'])
|
58
|
+
end
|
59
|
+
it "should handle arrays and hashes" do
|
60
|
+
expect(meth('name',[['a','b'], {'a' => 5}, 'x']).method_types).to eq(['[]','{}','str'])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def meth(name = "method", args=[], is_yield=false, source = "file1", line = 5)
|
67
|
+
CodeWeb::MethodCall.new(source, line, name, args, is_yield)
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CodeWeb::MethodList do
|
4
|
+
let(:four) { described_class.new(nil, [meth("a",%w(a b c)), meth("a",%w(a b)), meth("b",%w(a b)), meth("b",%w(a))]) }
|
5
|
+
|
6
|
+
describe "#group_by" do
|
7
|
+
subject { four.group_by(:name) }
|
8
|
+
it { expect(four.group_by(:name).count).to eq(2) }
|
9
|
+
it { expect(four.group_by(:name).map { |m| m.f.name }).to eq(%w(a b)) }
|
10
|
+
it { expect(four.group_by(:args_size).map { |m| m.args_size }).to eq([1, 2, 3]) }
|
11
|
+
end
|
12
|
+
|
13
|
+
# "#group_by"
|
14
|
+
#detect
|
15
|
+
#each
|
16
|
+
describe "#count" do
|
17
|
+
it { expect(ml([meth("a"), meth("b")]).count).to eq(2) }
|
18
|
+
end
|
19
|
+
describe "#arg_keys" do
|
20
|
+
it { expect(ml([meth("method", [{a:5, b:5, c:5}]), meth("method", [{d:5}])]).arg_keys).to eq([:a, :b, :c, :d]) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def ml(methods, name=nil)
|
26
|
+
described_class.new(name, methods)
|
27
|
+
end
|
28
|
+
|
29
|
+
def meth(name = "method", args=[], is_yield=false, source = "file1", line = 5)
|
30
|
+
CodeWeb::MethodCall.new(source, line, name, args, is_yield)
|
31
|
+
end
|
32
|
+
end
|