protocol 0.8.2 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +2 -0
- data/Rakefile +2 -3
- data/VERSION +1 -1
- data/benchmarks/method_parser.rb +51 -0
- data/examples/comparing.rb +5 -4
- data/examples/enumerating.rb +16 -7
- data/examples/indexing.rb +2 -1
- data/examples/locking.rb +12 -12
- data/examples/queue.rb +54 -51
- data/examples/stack.rb +13 -13
- data/install.rb +6 -1
- data/lib/protocol/method_parser/parse_tree.rb +124 -0
- data/lib/protocol/method_parser/ruby_parser.rb +123 -0
- data/lib/protocol/version.rb +1 -1
- data/lib/protocol.rb +23 -98
- data/make_doc.rb +1 -2
- data/protocol.gemspec +3 -2
- data/tests/test_protocol.rb +10 -11
- data/tests/test_protocol_method_parser.rb +146 -0
- metadata +19 -2
data/CHANGES
CHANGED
data/Rakefile
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# vim: set et sw=2 ts=2:
|
2
|
-
|
3
1
|
begin
|
4
2
|
require 'rake/gempackagetask'
|
5
3
|
rescue LoadError
|
@@ -11,7 +9,7 @@ include Config
|
|
11
9
|
PKG_NAME = 'protocol'
|
12
10
|
PKG_VERSION = File.read('VERSION').chomp
|
13
11
|
PKG_FILES = FileList['**/*'].exclude(/(CVS|\.svn|pkg|coverage)/)
|
14
|
-
CLEAN.include 'coverage', 'doc'
|
12
|
+
CLEAN.include 'coverage', 'doc', Dir['benchmarks/data/*.*']
|
15
13
|
|
16
14
|
desc "Installing library"
|
17
15
|
task :install do
|
@@ -51,6 +49,7 @@ EOT
|
|
51
49
|
|
52
50
|
s.require_path = 'lib'
|
53
51
|
s.add_dependency 'ParseTree', '~> 3.0'
|
52
|
+
s.add_dependency 'ruby_parser', '~> 2.0'
|
54
53
|
|
55
54
|
s.has_rdoc = true
|
56
55
|
s.rdoc_options << '--main' << 'doc-main.txt'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bullshit'
|
4
|
+
require 'protocol'
|
5
|
+
|
6
|
+
class MethodParserBenchmark < Bullshit::RepeatCase
|
7
|
+
include Protocol
|
8
|
+
|
9
|
+
class Foo
|
10
|
+
def foo(a, b = nil, *c)
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
warmup yes
|
16
|
+
|
17
|
+
iterations 500
|
18
|
+
|
19
|
+
truncate_data do
|
20
|
+
alpha_level 0.05
|
21
|
+
window_size 10
|
22
|
+
slope_angle 0.003
|
23
|
+
end
|
24
|
+
|
25
|
+
output_dir File.join(File.dirname(__FILE__), 'data')
|
26
|
+
data_file yes
|
27
|
+
histogram yes
|
28
|
+
|
29
|
+
autocorrelation do
|
30
|
+
alpha_level 0.05
|
31
|
+
max_lags 50
|
32
|
+
file yes
|
33
|
+
end
|
34
|
+
|
35
|
+
def benchmark_standard
|
36
|
+
@mp = MethodParser.new(Foo, :foo)
|
37
|
+
end
|
38
|
+
|
39
|
+
def after_standard
|
40
|
+
@mp.args == [ :a, :b, :'*c', :'&block' ] or raise "wrong result"
|
41
|
+
end
|
42
|
+
|
43
|
+
def benchmark_nocache
|
44
|
+
@mp = MethodParser.new(Foo, :foo)
|
45
|
+
end
|
46
|
+
|
47
|
+
def after_nocache
|
48
|
+
@mp.args == [ :a, :b, :'*c', :'&block' ] or raise "wrong result"
|
49
|
+
MethodParser.flush_source_cache
|
50
|
+
end
|
51
|
+
end
|
data/examples/comparing.rb
CHANGED
@@ -18,9 +18,9 @@ goliath = Person.new 'Goliath', 2_60
|
|
18
18
|
david = Person.new 'David', 1_40
|
19
19
|
symbol = Person.new 'The artist formerly known as Prince', 1_40
|
20
20
|
|
21
|
-
david < goliath #
|
22
|
-
david >= goliath #
|
23
|
-
david == symbol #
|
21
|
+
puts "david < goliath = #{david < goliath} (true)"
|
22
|
+
puts "david >= goliath = #{david >= goliath} (false)"
|
23
|
+
puts "david == symbol = #{david == symbol} (true)"
|
24
24
|
|
25
25
|
begin
|
26
26
|
class NoPerson
|
@@ -32,6 +32,7 @@ begin
|
|
32
32
|
|
33
33
|
conform_to Comparing
|
34
34
|
end
|
35
|
+
puts "Should have thrown Protocol::CheckFailed!"
|
35
36
|
rescue Protocol::CheckFailed => e
|
36
|
-
e
|
37
|
+
p e
|
37
38
|
end
|
data/examples/enumerating.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
require 'protocol
|
1
|
+
require 'protocol'
|
2
|
+
|
3
|
+
Enumerating = Protocol do
|
4
|
+
# Iterate over each element of this Enumerating class and pass it to the
|
5
|
+
# _block_.
|
6
|
+
def each(&block) end
|
7
|
+
|
8
|
+
include Enumerable
|
9
|
+
end
|
2
10
|
|
3
11
|
begin
|
4
12
|
class FailAry
|
@@ -11,8 +19,9 @@ begin
|
|
11
19
|
|
12
20
|
conform_to Enumerating
|
13
21
|
end
|
22
|
+
puts "Should have thrown Protocol::CheckFailed!"
|
14
23
|
rescue Protocol::CheckFailed => e
|
15
|
-
e
|
24
|
+
p e # => "Enumerating#each(0&): expected a block argument for FailAry"
|
16
25
|
end
|
17
26
|
|
18
27
|
class Ary
|
@@ -27,9 +36,9 @@ class Ary
|
|
27
36
|
conform_to Enumerating
|
28
37
|
end
|
29
38
|
|
30
|
-
Ary.new.map { |x| x * x }
|
31
|
-
Ary.conform_to?(Enumerating)
|
32
|
-
Ary.new.conform_to?(Enumerating)
|
39
|
+
puts Ary.new.map { |x| x * x }.inspect + " ([1, 4, 9])"
|
40
|
+
puts Ary.conform_to?(Enumerating).to_s + " (true)"
|
41
|
+
puts Ary.new.conform_to?(Enumerating).to_s + " (true)"
|
33
42
|
|
34
43
|
Enumerating.check_failure :none
|
35
44
|
|
@@ -43,5 +52,5 @@ class FailAry2
|
|
43
52
|
conform_to Enumerating
|
44
53
|
end
|
45
54
|
|
46
|
-
FailAry2.conform_to?(Enumerating)
|
47
|
-
FailAry2.new.conform_to?(Enumerating)
|
55
|
+
puts FailAry2.conform_to?(Enumerating).to_s + " (false)"
|
56
|
+
puts FailAry2.new.conform_to?(Enumerating).to_s + " (false)"
|
data/examples/indexing.rb
CHANGED
data/examples/locking.rb
CHANGED
@@ -53,7 +53,7 @@ if $0 == __FILE__
|
|
53
53
|
# Locking '...'.
|
54
54
|
# Synchronized with '...'..
|
55
55
|
# Unlocking '...'.
|
56
|
-
mutex = FileMutex.new
|
56
|
+
p mutex = FileMutex.new
|
57
57
|
mutex.synchronize do
|
58
58
|
puts "Synchronized with '#{mutex.path}'."
|
59
59
|
end
|
@@ -74,13 +74,13 @@ if $0 == __FILE__
|
|
74
74
|
conform_to Locking # actually Mutex itself would conform as well ;)
|
75
75
|
end
|
76
76
|
|
77
|
-
mutex = MemoryMutex.new
|
77
|
+
p mutex = MemoryMutex.new
|
78
78
|
mutex.synchronize do
|
79
79
|
puts "Synchronized in memory."
|
80
80
|
end
|
81
81
|
|
82
|
-
MemoryMutex.conform_to?
|
83
|
-
MemoryMutex.new.conform_to?
|
82
|
+
puts MemoryMutex.conform_to?(Locking).to_s + ' (true)'
|
83
|
+
puts MemoryMutex.new.conform_to?(Locking).to_s + ' (true)'
|
84
84
|
|
85
85
|
class MyClass
|
86
86
|
def initialize
|
@@ -90,22 +90,22 @@ if $0 == __FILE__
|
|
90
90
|
attr_reader :mutex
|
91
91
|
|
92
92
|
def mutex=(mutex)
|
93
|
-
Locking
|
93
|
+
Locking =~ mutex
|
94
94
|
@mutex = mutex
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
98
|
obj = MyClass.new
|
99
|
-
obj.mutex # => #<FileMutex:0xb788f9ac @tempfile=#<File:/tmp/file-mutex.26553.2>>
|
99
|
+
p obj.mutex # => #<FileMutex:0xb788f9ac @tempfile=#<File:/tmp/file-mutex.26553.2>>
|
100
100
|
begin
|
101
101
|
obj.mutex = Object.new
|
102
|
+
puts "Should have thrown Protocol::CheckFailed!"
|
102
103
|
rescue Protocol::CheckFailed => e
|
103
|
-
e
|
104
|
+
p e
|
104
105
|
end
|
105
|
-
obj.mutex = MemoryMutex.new # => #<MemoryMutex:0xb788f038 @mutex=#<Mutex:0xb788eea8>>
|
106
|
+
p obj.mutex = MemoryMutex.new # => #<MemoryMutex:0xb788f038 @mutex=#<Mutex:0xb788eea8>>
|
106
107
|
# This works as well:
|
107
|
-
obj.mutex = Mutex.new
|
108
|
-
Locking.check
|
109
|
-
Mutex.conform_to?
|
108
|
+
obj.mutex = Mutex.new
|
109
|
+
puts Locking.check(Mutex).to_s + ' (true)'
|
110
|
+
puts Mutex.conform_to?(Locking).to_s + ' (true)'
|
110
111
|
end
|
111
|
-
# >> "Locking '/tmp/file-mutex.26553.1'.\nSynchronized with '/tmp/file-mutex.26553.1'.\nUnlocking '/tmp/file-mutex.26553.1'.\nSynchronized in memory.\n"
|
data/examples/queue.rb
CHANGED
@@ -100,55 +100,58 @@ class Q
|
|
100
100
|
conform_to QueueProtocol
|
101
101
|
end
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
103
|
+
def should_be(a1, a2)
|
104
|
+
puts "#{a1.inspect} (#{a2.inspect})"
|
105
|
+
end
|
106
|
+
|
107
|
+
q = Q.new
|
108
|
+
q.observer = O.new
|
109
|
+
should_be q.empty?, true
|
110
|
+
begin
|
111
|
+
q.deq
|
112
|
+
rescue Protocol::CheckError => e
|
113
|
+
p e
|
114
|
+
end
|
115
|
+
should_be q.empty?, true
|
116
|
+
should_be q.size, 0
|
117
|
+
should_be q.first, nil
|
118
|
+
q.enq 2
|
119
|
+
should_be q.empty?, false
|
120
|
+
should_be q.size, 1
|
121
|
+
should_be q.first, 2
|
122
|
+
q.enq 2
|
123
|
+
should_be q.size, 2
|
124
|
+
should_be q.deq, 2
|
125
|
+
should_be q.first, 2
|
126
|
+
should_be q.size, 1
|
127
|
+
|
128
|
+
q = Q.new
|
129
|
+
q.observer = O.new
|
130
|
+
should_be q.empty?, true
|
131
|
+
begin
|
132
|
+
q.deq
|
133
|
+
puts "Should have thrown Protocol::CheckFailed!"
|
134
|
+
rescue Protocol::CheckError => e
|
135
|
+
p e
|
136
|
+
end
|
137
|
+
should_be q.empty?, true
|
138
|
+
should_be q.size, 0
|
139
|
+
should_be q.first, nil
|
140
|
+
q.enq 2
|
141
|
+
should_be q.empty?, false
|
142
|
+
should_be q.size, 1
|
143
|
+
should_be q.first, 2
|
144
|
+
q.enq 2
|
145
|
+
should_be q.size, 2
|
146
|
+
should_be q.deq, 2
|
147
|
+
should_be q.first, 2
|
148
|
+
should_be q.size, 1
|
149
|
+
q.observer = SneakyO.new
|
150
|
+
should_be q.deq, 2
|
151
|
+
should_be q.empty?, true
|
152
|
+
begin
|
153
|
+
q.enq 7
|
154
|
+
puts "Should have thrown Protocol::CheckFailed!"
|
155
|
+
rescue Protocol::CheckError => e
|
156
|
+
p e
|
153
157
|
end
|
154
|
-
# >> "Enqueued.\nEnqueued.\nDequeued.\nEnqueued.\nEnqueued.\nDequeued.\nDequeued.\nEnqueued.\nDequeued.\n"
|
data/examples/stack.rb
CHANGED
@@ -53,23 +53,23 @@ end
|
|
53
53
|
|
54
54
|
if $0 == __FILE__
|
55
55
|
s = S.new
|
56
|
-
s.top
|
57
|
-
s.empty
|
58
|
-
s.size
|
56
|
+
puts s.top.inspect + " (nil)"
|
57
|
+
puts s.empty?.to_s + " (true)"
|
58
|
+
puts s.size.to_s + " (0)"
|
59
59
|
begin
|
60
60
|
s.pop
|
61
61
|
rescue Protocol::CheckError => e
|
62
|
-
e # => #<Protocol::PreconditionCheckError: StackProtocol#empty?(0): precondition failed for S>
|
62
|
+
p e # => #<Protocol::PreconditionCheckError: StackProtocol#empty?(0): precondition failed for S>
|
63
63
|
end
|
64
|
-
s.empty
|
64
|
+
puts s.empty?.to_s + " (true)"
|
65
65
|
s.push 2
|
66
|
-
s.empty
|
67
|
-
s.size
|
68
|
-
s.top
|
66
|
+
puts s.empty?.to_s + " (false)"
|
67
|
+
puts s.size.to_s + " (1)"
|
68
|
+
puts s.top.to_s + " (2)"
|
69
69
|
s.push 4
|
70
|
-
s.top
|
71
|
-
s.size
|
72
|
-
s.pop
|
73
|
-
s.top
|
74
|
-
s.size
|
70
|
+
puts s.top.to_s + " (4)"
|
71
|
+
puts s.size.to_s + " (2)"
|
72
|
+
puts s.pop.to_s + " (4)"
|
73
|
+
puts s.top.to_s + " (2)"
|
74
|
+
puts s.size.to_s + " (1)"
|
75
75
|
end
|
data/install.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# vim: set et sw=2 ts=2:
|
3
2
|
|
4
3
|
require 'rbconfig'
|
5
4
|
require 'fileutils'
|
@@ -16,3 +15,9 @@ mkdir_p dest
|
|
16
15
|
for file in Dir['lib/protocol/*.rb']
|
17
16
|
install(file, dest)
|
18
17
|
end
|
18
|
+
|
19
|
+
dest = File.join(CONFIG["sitelibdir"], 'protocol', 'method_parser')
|
20
|
+
mkdir_p dest
|
21
|
+
for file in Dir['lib/protocol/method_parser/*.rb']
|
22
|
+
install(file, dest)
|
23
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'parse_tree'
|
2
|
+
require 'sexp_processor'
|
3
|
+
|
4
|
+
module Protocol
|
5
|
+
# Parse protocol method definition to derive a Message specification.
|
6
|
+
class MethodParser < SexpProcessor
|
7
|
+
# Create a new MethodParser instance for method +methodname+ of module
|
8
|
+
# +modul+. For eigenmethods set +eigenclass+ to true, otherwise bad things
|
9
|
+
# will happen.
|
10
|
+
def initialize(modul, methodname, eigenclass = false)
|
11
|
+
super()
|
12
|
+
@method = Module === modul ?
|
13
|
+
modul.instance_method(methodname) :
|
14
|
+
modul.method(methodname)
|
15
|
+
self.strict = false
|
16
|
+
self.auto_shift_type = true
|
17
|
+
@complex = false
|
18
|
+
@first_defn = true
|
19
|
+
@first_block = true
|
20
|
+
@args = []
|
21
|
+
@arg_kinds = []
|
22
|
+
@arity = @method.arity
|
23
|
+
parsed = ParseTree.new.parse_tree_for_method(modul, methodname, eigenclass)
|
24
|
+
process parsed
|
25
|
+
end
|
26
|
+
|
27
|
+
# Process +exp+, but catch UnsupportedNodeError exceptions and ignore them.
|
28
|
+
def process(exp)
|
29
|
+
super
|
30
|
+
rescue UnsupportedNodeError => ignore
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the names of the arguments of the parsed method.
|
34
|
+
attr_reader :args
|
35
|
+
|
36
|
+
def arg(i)
|
37
|
+
@args[i]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the names of the arguments of the parsed method.
|
41
|
+
attr_reader :arg_kinds
|
42
|
+
|
43
|
+
def arg_kind(i)
|
44
|
+
@arg_kinds[i]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the arity of the parsed method.
|
48
|
+
attr_reader :arity
|
49
|
+
|
50
|
+
# Return true if this protocol method is a complex method, which ought to
|
51
|
+
# be called for checking conformance to the protocol.
|
52
|
+
def complex?
|
53
|
+
@complex
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return true if a block argument was detected.
|
57
|
+
def block_arg?
|
58
|
+
@arg_kinds.last == :block
|
59
|
+
end
|
60
|
+
|
61
|
+
# Only consider first the first defn, skip inner method definitions.
|
62
|
+
def process_defn(exp)
|
63
|
+
if @first_defn
|
64
|
+
@first_defn = false
|
65
|
+
_name, scope = exp
|
66
|
+
process scope
|
67
|
+
end
|
68
|
+
exp.clear
|
69
|
+
s :dummy
|
70
|
+
end
|
71
|
+
|
72
|
+
# Remember the argument names in +exp+ in the args attribute.
|
73
|
+
def process_args(exp)
|
74
|
+
@args.replace exp.select { |x| x.is_a? Symbol }
|
75
|
+
@arg_kinds = @args.map { |a| a.to_s[0] == ?* ? :rest : :req }
|
76
|
+
if block = exp.find { |x| x.is_a?(Array) and x.first == :block }
|
77
|
+
lasgns = block[1..-1].transpose[1]
|
78
|
+
i = args.size - 1
|
79
|
+
@args.reverse_each do |a|
|
80
|
+
exp.first
|
81
|
+
l = lasgns.last
|
82
|
+
if a == l
|
83
|
+
@arg_kinds[i] = :opt
|
84
|
+
lasgns.pop
|
85
|
+
end
|
86
|
+
i -= 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
exp.clear
|
90
|
+
s :dummy
|
91
|
+
end
|
92
|
+
|
93
|
+
# Remember if we encounter a block argument.
|
94
|
+
def process_block_arg(exp)
|
95
|
+
@args.push :"&#{exp.first}"
|
96
|
+
@arg_kinds.push :block
|
97
|
+
exp.clear
|
98
|
+
s :dummy
|
99
|
+
end
|
100
|
+
|
101
|
+
# Remember if we encounter a yield keyword.
|
102
|
+
def process_yield(exp)
|
103
|
+
if @arg_kinds.last != :block
|
104
|
+
@args.push :'&block'
|
105
|
+
@arg_kinds.push :block
|
106
|
+
end
|
107
|
+
exp.clear
|
108
|
+
s :dummy
|
109
|
+
end
|
110
|
+
|
111
|
+
# We only consider the first block in +exp+ (can there be more than one?),
|
112
|
+
# and then try to figure out, if this is a complex method or not. Continue
|
113
|
+
# processing the +exp+ tree after that.
|
114
|
+
def process_block(exp)
|
115
|
+
if @first_block
|
116
|
+
@first_block = false
|
117
|
+
@complex = exp.flatten.any? { |e| [ :call, :fcall, :vcall ].include?(e) }
|
118
|
+
exp.each { |e| process e }
|
119
|
+
end
|
120
|
+
exp.clear
|
121
|
+
s :dummy
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'ruby_parser'
|
2
|
+
|
3
|
+
module Protocol
|
4
|
+
# Parse protocol method definition to derive a Message specification.
|
5
|
+
class MethodParser
|
6
|
+
class << self
|
7
|
+
attr_accessor :__source_cache__
|
8
|
+
|
9
|
+
# Flushes the source cache.
|
10
|
+
def flush_source_cache
|
11
|
+
__source_cache__.clear
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
self.__source_cache__ = {}
|
16
|
+
|
17
|
+
# Create a new MethodParser instance for method +methodname+ of module
|
18
|
+
# +modul+. For eigenmethods set +eigenclass+ to true, otherwise bad things
|
19
|
+
# will happen.
|
20
|
+
def initialize(modul, methodname, eigenclass = false)
|
21
|
+
@method = Module === modul ?
|
22
|
+
modul.instance_method(methodname) :
|
23
|
+
modul.method(methodname)
|
24
|
+
compute_args
|
25
|
+
parse_method
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the names of the arguments of the parsed method.
|
29
|
+
attr_reader :args
|
30
|
+
|
31
|
+
# Returns the i-th argument (beginning with 0).
|
32
|
+
def arg(i)
|
33
|
+
@args[i]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the kinds of the arguments of the parsed method.
|
37
|
+
attr_reader :arg_kinds
|
38
|
+
|
39
|
+
# Returns the i-th kind of an argument (beginning with 0).
|
40
|
+
def arg_kind(i)
|
41
|
+
@arg_kinds[i]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the arity of the parsed method.
|
45
|
+
attr_reader :arity
|
46
|
+
|
47
|
+
# Return true if this protocol method is a complex method, which ought to
|
48
|
+
# be called for checking conformance to the protocol.
|
49
|
+
def complex?
|
50
|
+
@complex
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return true if a block argument was detected.
|
54
|
+
def block_arg?
|
55
|
+
@arg_kinds.last == :block
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def compute_args
|
61
|
+
@arity = @method.arity
|
62
|
+
if @method.respond_to?(:parameters)
|
63
|
+
parameters = @method.parameters
|
64
|
+
@args, @arg_kinds = parameters.map do |kind, name|
|
65
|
+
case kind
|
66
|
+
when :req
|
67
|
+
[ name, kind ]
|
68
|
+
when :opt
|
69
|
+
[ name, kind ]
|
70
|
+
when :rest
|
71
|
+
[ :"*#{name}", kind ]
|
72
|
+
when :block
|
73
|
+
[ :"&#{name}", kind ]
|
74
|
+
end
|
75
|
+
end.compact.transpose
|
76
|
+
else
|
77
|
+
raise NotImplementedError,
|
78
|
+
"#{@method.class}#parameters as in ruby version >=1.9.2 is required"
|
79
|
+
end
|
80
|
+
@args ||= []
|
81
|
+
@arg_kinds ||= []
|
82
|
+
end
|
83
|
+
|
84
|
+
def cached_source(filename)
|
85
|
+
cache = self.class.__source_cache__
|
86
|
+
unless source = cache[filename]
|
87
|
+
begin
|
88
|
+
source = IO.readlines(filename)
|
89
|
+
cache[filename] = source
|
90
|
+
rescue SystemCallError => e
|
91
|
+
$DEBUG and warn "Caught #{e.class}: #{e}"
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
source
|
96
|
+
end
|
97
|
+
|
98
|
+
def parse_method
|
99
|
+
@complex = false
|
100
|
+
filename, lineno = @method.source_location
|
101
|
+
if filename
|
102
|
+
source = cached_source(filename) or return
|
103
|
+
source = source[(lineno - 1)..-1].join
|
104
|
+
current = 0
|
105
|
+
tree = nil
|
106
|
+
while current = source.index('end', current)
|
107
|
+
current += 3
|
108
|
+
begin
|
109
|
+
tree = RubyParser.new.parse(source[0, current], filename)
|
110
|
+
break
|
111
|
+
rescue SyntaxError, Racc::ParseError
|
112
|
+
end
|
113
|
+
end
|
114
|
+
ary = tree.to_a.flatten
|
115
|
+
@complex = ary.flatten.any? { |node| [ :call, :fcall, :vcall ].include?(node) }
|
116
|
+
if ary.index(:yield) and @arg_kinds.last != :block
|
117
|
+
@args.push :'&block'
|
118
|
+
@arg_kinds.push :block
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/lib/protocol/version.rb
CHANGED
data/lib/protocol.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'protocol/version'
|
2
|
-
require 'parse_tree'
|
3
|
-
require 'sexp_processor'
|
4
2
|
|
5
3
|
module Protocol
|
4
|
+
if RUBY_VERSION[/\A1\.8\./]
|
5
|
+
require 'protocol/method_parser/parse_tree'
|
6
|
+
else
|
7
|
+
require 'protocol/method_parser/ruby_parser'
|
8
|
+
end
|
9
|
+
|
6
10
|
class ::Object
|
7
11
|
# Returns true if this object conforms to +protocol+, otherwise false.
|
8
12
|
#
|
@@ -144,7 +148,7 @@ module Protocol
|
|
144
148
|
# after the result of the wrapped method was determined.
|
145
149
|
class Postcondition
|
146
150
|
instance_methods.each do |m|
|
147
|
-
m =~ /\A(__|instance_eval\Z|inspect\Z)/ or undef_method m
|
151
|
+
m.to_s =~ /\A(__|object_id|instance_eval\Z|inspect\Z)/ or undef_method m
|
148
152
|
end
|
149
153
|
|
150
154
|
def initialize(object)
|
@@ -204,8 +208,9 @@ module Protocol
|
|
204
208
|
# Creates a Message instance named +name+, with the arity +arity+.
|
205
209
|
# If +arity+ is nil, the arity isn't checked during conformity tests.
|
206
210
|
def initialize(protocol, name, arity = nil, block_expected = false)
|
211
|
+
name = name.to_s
|
207
212
|
@protocol, @name, @arity, @block_expected =
|
208
|
-
protocol, name
|
213
|
+
protocol, name, arity, !!block_expected
|
209
214
|
end
|
210
215
|
|
211
216
|
# The protocol this message was defined in.
|
@@ -320,7 +325,7 @@ module Protocol
|
|
320
325
|
(1..arity).map { |i| "x#{i}," }
|
321
326
|
else
|
322
327
|
(1..~arity).map { |i| "x#{i}," } << '*rest,'
|
323
|
-
end
|
328
|
+
end.join
|
324
329
|
wrapped_call = %{
|
325
330
|
alias_method :'#{inner_name}', :'#{name}'
|
326
331
|
|
@@ -395,7 +400,7 @@ module Protocol
|
|
395
400
|
" in method '#{name}' (#{check_arity} for #{arity}) of #{object}")
|
396
401
|
end
|
397
402
|
if block_expected?
|
398
|
-
if object.singleton_methods(false).include?(name)
|
403
|
+
if object.singleton_methods(false).map { |m| m.to_s } .include?(name)
|
399
404
|
parser = MethodParser.new(object, name, true)
|
400
405
|
else
|
401
406
|
ancestors = object.class.ancestors
|
@@ -446,90 +451,6 @@ module Protocol
|
|
446
451
|
end
|
447
452
|
end
|
448
453
|
|
449
|
-
# Parse protocol method definition to derive a Message specification.
|
450
|
-
class MethodParser < SexpProcessor
|
451
|
-
# Create a new MethodParser instance for method +methodname+ of module
|
452
|
-
# +modul+. For eigenmethods set +eigenclass+ to true, otherwise bad things
|
453
|
-
# will happen.
|
454
|
-
def initialize(modul, methodname, eigenclass = false)
|
455
|
-
super()
|
456
|
-
self.strict = false
|
457
|
-
self.auto_shift_type = true
|
458
|
-
@complex = false
|
459
|
-
@block_arg = false
|
460
|
-
@first_defn = true
|
461
|
-
@first_block = true
|
462
|
-
@args = []
|
463
|
-
parsed = ParseTree.new.parse_tree_for_method(modul, methodname, eigenclass)
|
464
|
-
process parsed
|
465
|
-
end
|
466
|
-
|
467
|
-
# Process +exp+, but catch UnsupportedNodeError exceptions and ignore them.
|
468
|
-
def process(exp)
|
469
|
-
super
|
470
|
-
rescue UnsupportedNodeError => ignore
|
471
|
-
end
|
472
|
-
|
473
|
-
# Returns the names of the arguments of the parsed method.
|
474
|
-
attr_reader :args
|
475
|
-
|
476
|
-
# Returns the arity of the parsed method.
|
477
|
-
def arity
|
478
|
-
@args.size
|
479
|
-
end
|
480
|
-
|
481
|
-
# Return true if this protocol method is a complex method, which ought to
|
482
|
-
# be called for checking conformance to the protocol.
|
483
|
-
def complex?
|
484
|
-
@complex
|
485
|
-
end
|
486
|
-
|
487
|
-
# Return true if a block argument was detected.
|
488
|
-
def block_arg?
|
489
|
-
@block_arg
|
490
|
-
end
|
491
|
-
|
492
|
-
# Only consider first the first defn, skip inner method definitions.
|
493
|
-
def process_defn(exp)
|
494
|
-
if @first_defn
|
495
|
-
@first_defn = false
|
496
|
-
_name, scope = exp
|
497
|
-
process scope
|
498
|
-
end
|
499
|
-
exp.clear
|
500
|
-
s :dummy
|
501
|
-
end
|
502
|
-
|
503
|
-
# Remember the argument names in +exp+ in the args attribute.
|
504
|
-
def process_args(exp)
|
505
|
-
@args.replace exp
|
506
|
-
exp.clear
|
507
|
-
s :dummy
|
508
|
-
end
|
509
|
-
|
510
|
-
# Remember if we encounter a block argument or a yield keyword.
|
511
|
-
def process_block_arg(exp)
|
512
|
-
@block_arg = true
|
513
|
-
exp.clear
|
514
|
-
s :dummy
|
515
|
-
end
|
516
|
-
|
517
|
-
alias process_yield process_block_arg
|
518
|
-
|
519
|
-
# We only consider the first block in +exp+ (can there be more than one?),
|
520
|
-
# and then try to figure out, if this is a complex method or not. Continue
|
521
|
-
# processing the +exp+ tree after that.
|
522
|
-
def process_block(exp)
|
523
|
-
if @first_block
|
524
|
-
@first_block = false
|
525
|
-
@complex = exp[-1][0] != :nil rescue false
|
526
|
-
exp.each { |e| process e }
|
527
|
-
end
|
528
|
-
exp.clear
|
529
|
-
s :dummy
|
530
|
-
end
|
531
|
-
end
|
532
|
-
|
533
454
|
# A ProtocolModule object
|
534
455
|
class ProtocolModule < Module
|
535
456
|
# Creates an new ProtocolModule instance.
|
@@ -546,7 +467,7 @@ module Protocol
|
|
546
467
|
def descriptors
|
547
468
|
descriptors = []
|
548
469
|
protocols.each do |a|
|
549
|
-
descriptors << a.instance_variable_get(
|
470
|
+
descriptors << a.instance_variable_get(:@descriptor)
|
550
471
|
end
|
551
472
|
descriptors
|
552
473
|
end
|
@@ -578,8 +499,7 @@ module Protocol
|
|
578
499
|
# have to call #reset_messages, if you want to recompute the array in the
|
579
500
|
# next call to #messages.
|
580
501
|
def messages
|
581
|
-
|
582
|
-
@messages = []
|
502
|
+
result = []
|
583
503
|
seen = {}
|
584
504
|
descriptors.each do |d|
|
585
505
|
dm = d.messages
|
@@ -588,10 +508,9 @@ module Protocol
|
|
588
508
|
seen[m.name] = true
|
589
509
|
delete
|
590
510
|
end
|
591
|
-
|
511
|
+
result.concat dm
|
592
512
|
end
|
593
|
-
|
594
|
-
@messages
|
513
|
+
result.sort!
|
595
514
|
end
|
596
515
|
|
597
516
|
alias to_a messages
|
@@ -820,8 +739,14 @@ module Protocol
|
|
820
739
|
# This Method tries to find the first module that implements the method
|
821
740
|
# named +methodname+ in the array of +ancestors+. If this fails nil is
|
822
741
|
# returned.
|
823
|
-
def find_method_module(methodname, ancestors)
|
824
|
-
|
742
|
+
def find_method_module(methodname, ancestors)
|
743
|
+
methodname = methodname.to_s
|
744
|
+
ancestors.each do |a|
|
745
|
+
begin
|
746
|
+
a.instance_method(methodname)
|
747
|
+
return a
|
748
|
+
rescue NameError
|
749
|
+
end
|
825
750
|
end
|
826
751
|
nil
|
827
752
|
end
|
data/make_doc.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# vim: set et sw=2 ts=2:
|
3
2
|
|
4
3
|
$outdir = 'doc/'
|
5
4
|
puts "Creating documentation in '#$outdir'."
|
6
|
-
system "rdoc --main=doc-main.txt -o #$outdir doc-main.txt lib
|
5
|
+
system "rdoc --main=doc-main.txt -o #$outdir doc-main.txt #{Dir['lib/**/*.rb'] * ' '}"
|
data/protocol.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = 'protocol'
|
4
|
-
s.version = '0.
|
5
|
-
s.files = ["CHANGES", "COPYING", "Rakefile", "VERSION", "doc-main.txt", "examples", "examples/comparing.rb", "examples/enumerating.rb", "examples/game.rb", "examples/hello_world_patternitis.rb", "examples/indexing.rb", "examples/locking.rb", "examples/queue.rb", "examples/stack.rb", "install.rb", "lib", "lib/protocol", "lib/protocol.rb", "lib/protocol/core.rb", "lib/protocol/version.rb", "make_doc.rb", "protocol.gemspec", "tests", "tests/test_protocol.rb"]
|
4
|
+
s.version = '0.9.0'
|
5
|
+
s.files = ["CHANGES", "COPYING", "Rakefile", "VERSION", "benchmarks", "benchmarks/data", "benchmarks/method_parser.rb", "doc-main.txt", "examples", "examples/comparing.rb", "examples/enumerating.rb", "examples/game.rb", "examples/hello_world_patternitis.rb", "examples/indexing.rb", "examples/locking.rb", "examples/queue.rb", "examples/stack.rb", "install.rb", "lib", "lib/protocol", "lib/protocol.rb", "lib/protocol/core.rb", "lib/protocol/method_parser", "lib/protocol/method_parser/parse_tree.rb", "lib/protocol/method_parser/ruby_parser.rb", "lib/protocol/version.rb", "make_doc.rb", "protocol.gemspec", "tests", "tests/test_protocol.rb", "tests/test_protocol_method_parser.rb"]
|
6
6
|
s.summary = 'Method Protocols for Ruby Classes'
|
7
7
|
s.description = <<EOT
|
8
8
|
This library offers an implementation of protocols against which you can check
|
@@ -14,6 +14,7 @@ EOT
|
|
14
14
|
|
15
15
|
s.require_path = 'lib'
|
16
16
|
s.add_dependency 'ParseTree', '~> 3.0'
|
17
|
+
s.add_dependency 'ruby_parser', '~> 2.0'
|
17
18
|
|
18
19
|
s.has_rdoc = true
|
19
20
|
s.rdoc_options << '--main' << 'doc-main.txt'
|
data/tests/test_protocol.rb
CHANGED
@@ -19,25 +19,25 @@ class TestProtocol < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
TestProtocol_foo_bar_1 = Protocol do
|
22
|
-
include TestProtocol_foo
|
22
|
+
include TestProtocol::TestProtocol_foo
|
23
23
|
understand :bar
|
24
24
|
end
|
25
25
|
|
26
26
|
TestProtocol_foo_bar_1_fail = Protocol do
|
27
|
-
include TestProtocol_foo
|
27
|
+
include TestProtocol::TestProtocol_foo
|
28
28
|
understand :bar
|
29
29
|
end
|
30
30
|
|
31
31
|
TestProtocol_foo_bar_2 = Protocol do
|
32
|
-
include TestProtocol_foo
|
33
|
-
include TestProtocol_bar
|
32
|
+
include TestProtocol::TestProtocol_foo
|
33
|
+
include TestProtocol::TestProtocol_bar
|
34
34
|
end
|
35
35
|
|
36
36
|
TestProtocol_foo_bar_2_fail = Protocol do
|
37
37
|
check_failure :error
|
38
38
|
|
39
|
-
include TestProtocol_foo
|
40
|
-
include TestProtocol_bar
|
39
|
+
include TestProtocol::TestProtocol_foo
|
40
|
+
include TestProtocol::TestProtocol_bar
|
41
41
|
end
|
42
42
|
|
43
43
|
TestProtocolArgs = Protocol do
|
@@ -47,7 +47,7 @@ class TestProtocol < Test::Unit::TestCase
|
|
47
47
|
end
|
48
48
|
|
49
49
|
TestProtocolArgsOverwritten = Protocol do
|
50
|
-
include TestProtocolArgs
|
50
|
+
include TestProtocol::TestProtocolArgs
|
51
51
|
|
52
52
|
def bar(a, b, c)
|
53
53
|
end
|
@@ -101,8 +101,8 @@ class TestProtocol < Test::Unit::TestCase
|
|
101
101
|
|
102
102
|
TestProtocolWrapMethod = Protocol do
|
103
103
|
def foo_bar(foo, bar)
|
104
|
-
TestProtocolWrapMethodPassedFoo =~ foo
|
105
|
-
TestProtocolWrapMethodPassedBar =~ bar
|
104
|
+
::TestProtocol::TestProtocolWrapMethodPassedFoo =~ foo
|
105
|
+
::TestProtocol::TestProtocolWrapMethodPassedBar =~ bar
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -128,7 +128,7 @@ class TestProtocol < Test::Unit::TestCase
|
|
128
128
|
end
|
129
129
|
|
130
130
|
TestProtocolInheritance = Protocol do
|
131
|
-
inherit MyClass, :one_with_block
|
131
|
+
inherit TestProtocol::MyClass, :one_with_block
|
132
132
|
end
|
133
133
|
|
134
134
|
TestProtocolInheritanceC = Protocol do
|
@@ -617,4 +617,3 @@ class TestProtocol < Test::Unit::TestCase
|
|
617
617
|
end
|
618
618
|
end
|
619
619
|
end
|
620
|
-
# vim: set et sw=2 ts=2:
|
@@ -0,0 +1,146 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'protocol'
|
5
|
+
|
6
|
+
class TestProtocolMethodParser < Test::Unit::TestCase
|
7
|
+
include Protocol
|
8
|
+
|
9
|
+
class A
|
10
|
+
def empty
|
11
|
+
end
|
12
|
+
|
13
|
+
def none()
|
14
|
+
end
|
15
|
+
|
16
|
+
def one_req(a)
|
17
|
+
end
|
18
|
+
|
19
|
+
def two_req(a, b)
|
20
|
+
end
|
21
|
+
|
22
|
+
def one_req_one_opt(a, b = nil)
|
23
|
+
end
|
24
|
+
|
25
|
+
def one_opt(a = nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
def two_opt(a = nil, b = nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
def one_req_rest(a, *b)
|
32
|
+
end
|
33
|
+
|
34
|
+
def one_opt_rest(a = nil, *b)
|
35
|
+
end
|
36
|
+
|
37
|
+
def block(&b)
|
38
|
+
end
|
39
|
+
|
40
|
+
def one_req_block(a, &b)
|
41
|
+
end
|
42
|
+
|
43
|
+
def one_opt_block(a = nil, &b)
|
44
|
+
end
|
45
|
+
|
46
|
+
def yield
|
47
|
+
yield
|
48
|
+
end
|
49
|
+
|
50
|
+
def yield_block(&b)
|
51
|
+
yield
|
52
|
+
end
|
53
|
+
|
54
|
+
def complex_end
|
55
|
+
a = :end
|
56
|
+
foo { }
|
57
|
+
end
|
58
|
+
|
59
|
+
def complex
|
60
|
+
foo { }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_args
|
65
|
+
m = :empty; mp = MethodParser.new(A, m)
|
66
|
+
assert_equal 0, mp.arity, "arity failed for A##{m}"
|
67
|
+
assert_equal [ ], mp.args, "args failed for A##{m}"
|
68
|
+
assert_equal [ ], mp.arg_kinds, "args failed for A##{m}"
|
69
|
+
assert !mp.complex?
|
70
|
+
m = :none; mp = MethodParser.new(A, m)
|
71
|
+
assert_equal 0, mp.arity, "arity failed for A##{m}"
|
72
|
+
assert_equal [ ], mp.args, "args failed for A##{m}"
|
73
|
+
assert_equal [ ], mp.arg_kinds, "args failed for A##{m}"
|
74
|
+
assert !mp.complex?
|
75
|
+
m = :one_req; mp = MethodParser.new(A, m)
|
76
|
+
assert_equal 1, mp.arity, "arity failed for A##{m}"
|
77
|
+
assert_equal [ :a ], mp.args, "args failed for A##{m}"
|
78
|
+
assert_equal [ :req ], mp.arg_kinds, "args failed for A##{m}"
|
79
|
+
assert !mp.complex?
|
80
|
+
m = :two_req; mp = MethodParser.new(A, m)
|
81
|
+
assert_equal 2, mp.arity, "arity failed for A##{m}"
|
82
|
+
assert_equal [ :req, :req ], mp.arg_kinds, "args failed for A##{m}"
|
83
|
+
assert_equal [ :a, :b ], mp.args, "args failed for A##{m}"
|
84
|
+
assert !mp.complex?
|
85
|
+
m = :one_req_one_opt; mp = MethodParser.new(A, m)
|
86
|
+
assert_equal -2, mp.arity, "arity failed for A##{m}"
|
87
|
+
assert_equal [ :a, :b ], mp.args, "args failed for A##{m}"
|
88
|
+
assert_equal [ :req, :opt ], mp.arg_kinds, "args failed for A##{m}"
|
89
|
+
assert !mp.complex?
|
90
|
+
m = :one_opt; mp = MethodParser.new(A, m)
|
91
|
+
assert_equal -1, mp.arity, "arity failed for A##{m}"
|
92
|
+
assert_equal [ :a ], mp.args, "args failed for A##{m}"
|
93
|
+
assert_equal [ :opt ], mp.arg_kinds, "args failed for A##{m}"
|
94
|
+
assert !mp.complex?
|
95
|
+
m = :two_opt; mp = MethodParser.new(A, m)
|
96
|
+
assert_equal -1, mp.arity, "arity failed for A##{m}"
|
97
|
+
assert_equal [ :a, :b ], mp.args, "args failed for A##{m}"
|
98
|
+
assert_equal [ :opt, :opt ], mp.arg_kinds, "args failed for A##{m}"
|
99
|
+
assert !mp.complex?
|
100
|
+
m = :one_req_rest; mp = MethodParser.new(A, m)
|
101
|
+
assert_equal -2, mp.arity, "arity failed for A##{m}"
|
102
|
+
assert_equal [ :a, :'*b' ], mp.args, "args failed for A##{m}"
|
103
|
+
assert_equal [ :req, :rest ], mp.arg_kinds, "args failed for A##{m}"
|
104
|
+
assert !mp.complex?
|
105
|
+
m = :one_opt_rest; mp = MethodParser.new(A, m)
|
106
|
+
assert_equal -1, mp.arity, "arity failed for A##{m}"
|
107
|
+
assert_equal [ :a, :'*b' ], mp.args, "args failed for A##{m}"
|
108
|
+
assert_equal [ :opt, :rest ], mp.arg_kinds, "args failed for A##{m}"
|
109
|
+
assert !mp.complex?
|
110
|
+
m = :block; mp = MethodParser.new(A, m)
|
111
|
+
assert_equal 0, mp.arity, "arity failed for A##{m}"
|
112
|
+
assert_equal [ :'&b' ], mp.args, "args failed for A##{m}"
|
113
|
+
assert_equal [ :block ], mp.arg_kinds, "args failed for A##{m}"
|
114
|
+
assert !mp.complex?
|
115
|
+
m = :one_req_block; mp = MethodParser.new(A, m)
|
116
|
+
assert_equal 1, mp.arity, "arity failed for A##{m}"
|
117
|
+
assert_equal [ :a, :'&b' ], mp.args, "args failed for A##{m}"
|
118
|
+
assert_equal [ :req, :block ], mp.arg_kinds, "args failed for A##{m}"
|
119
|
+
assert !mp.complex?
|
120
|
+
m = :one_opt_block; mp = MethodParser.new(A, m)
|
121
|
+
assert_equal -1, mp.arity, "arity failed for A##{m}"
|
122
|
+
assert_equal [ :a, :'&b' ], mp.args, "args failed for A##{m}"
|
123
|
+
assert_equal [ :opt, :block ], mp.arg_kinds, "args failed for A##{m}"
|
124
|
+
assert !mp.complex?
|
125
|
+
m = :yield_block; mp = MethodParser.new(A, m)
|
126
|
+
assert_equal 0, mp.arity, "arity failed for A##{m}"
|
127
|
+
assert_equal [ :'&b' ], mp.args, "args failed for A##{m}"
|
128
|
+
assert_equal [ :block ], mp.arg_kinds, "args failed for A##{m}"
|
129
|
+
assert !mp.complex?
|
130
|
+
m = :yield; mp = MethodParser.new(A, m)
|
131
|
+
assert_equal 0, mp.arity, "arity failed for A##{m}"
|
132
|
+
assert_equal [ :'&block' ], mp.args, "args failed for A##{m}"
|
133
|
+
assert_equal [ :block ], mp.arg_kinds, "args failed for A##{m}"
|
134
|
+
assert !mp.complex?
|
135
|
+
m = :complex_end; mp = MethodParser.new(A, m)
|
136
|
+
assert_equal 0, mp.arity, "arity failed for A##{m}"
|
137
|
+
assert_equal [ ], mp.args, "args failed for A##{m}"
|
138
|
+
assert_equal [ ], mp.arg_kinds, "args failed for A##{m}"
|
139
|
+
assert mp.complex?
|
140
|
+
m = :complex; mp = MethodParser.new(A, m)
|
141
|
+
assert_equal 0, mp.arity, "arity failed for A##{m}"
|
142
|
+
assert_equal [ ], mp.args, "args failed for A##{m}"
|
143
|
+
assert_equal [ ], mp.arg_kinds, "args failed for A##{m}"
|
144
|
+
assert mp.complex?
|
145
|
+
end
|
146
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protocol
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Frank
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-08-11 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,6 +22,16 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "3.0"
|
24
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: ruby_parser
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "2.0"
|
34
|
+
version:
|
25
35
|
description: This library offers an implementation of protocols against which you can check the conformity of your classes or instances of your classes. They are a bit like Java Interfaces, but as mixin modules they can also contain already implemented methods. Additionaly you can define preconditions/postconditions for methods specified in a protocol.
|
26
36
|
email: flori@ping.de
|
27
37
|
executables: []
|
@@ -35,6 +45,9 @@ files:
|
|
35
45
|
- COPYING
|
36
46
|
- Rakefile
|
37
47
|
- VERSION
|
48
|
+
- benchmarks
|
49
|
+
- benchmarks/data
|
50
|
+
- benchmarks/method_parser.rb
|
38
51
|
- doc-main.txt
|
39
52
|
- examples
|
40
53
|
- examples/comparing.rb
|
@@ -50,11 +63,15 @@ files:
|
|
50
63
|
- lib/protocol
|
51
64
|
- lib/protocol.rb
|
52
65
|
- lib/protocol/core.rb
|
66
|
+
- lib/protocol/method_parser
|
67
|
+
- lib/protocol/method_parser/parse_tree.rb
|
68
|
+
- lib/protocol/method_parser/ruby_parser.rb
|
53
69
|
- lib/protocol/version.rb
|
54
70
|
- make_doc.rb
|
55
71
|
- protocol.gemspec
|
56
72
|
- tests
|
57
73
|
- tests/test_protocol.rb
|
74
|
+
- tests/test_protocol_method_parser.rb
|
58
75
|
has_rdoc: true
|
59
76
|
homepage: http://protocol.rubyforge.org
|
60
77
|
post_install_message:
|