protocol 0.8.2 → 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.
- 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:
|