contraction 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/contract.rb +9 -4
- data/lib/contraction.rb +59 -12
- data/lib/parser.rb +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d949e8e0f90ac9a867b0bc500c174af356f714e2
|
4
|
+
data.tar.gz: 7946c533f8690b04dfb4a6f41f0e50e12b8b6f89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 178ca20aa78e13a2bcb22906f40e93667fcffd29ddf0e13e362a894f38c0d2769269f5e8e203aceda27567148f08abe1c8f8d53efbbe687df2fa96e4b5dcba4f
|
7
|
+
data.tar.gz: c2fb6d2cba4457341109c9b6d96c244ceee9316f19137398a8ca645ef3f2fac218a35ef6214389dae97c4957a9beb8628e8a66ceda451a902605e17115b78d3b
|
data/lib/contract.rb
CHANGED
@@ -4,13 +4,13 @@ module Contraction
|
|
4
4
|
|
5
5
|
# @params [Array<TypedLine>] rules The individual lines that define the
|
6
6
|
# contract.
|
7
|
-
def initialize(rules, mod, method_name)
|
7
|
+
def initialize(rules, mod, method_name, type)
|
8
8
|
@rules = rules
|
9
9
|
@mod = mod
|
10
10
|
@method_name = method_name
|
11
11
|
|
12
12
|
update_rule_values
|
13
|
-
get_method_definition
|
13
|
+
get_method_definition(type)
|
14
14
|
end
|
15
15
|
|
16
16
|
# Test weather the arguments to a method are of the correct type, and meet
|
@@ -57,8 +57,13 @@ module Contraction
|
|
57
57
|
@param_rules ||= @rules.select { |r| r.is_a?(Contraction::Parser::ParamLine) }
|
58
58
|
end
|
59
59
|
|
60
|
-
def get_method_definition
|
61
|
-
@params =
|
60
|
+
def get_method_definition(type)
|
61
|
+
@params = []
|
62
|
+
if type == :class
|
63
|
+
@params = mod.method(method_name.to_sym).parameters.map(&:last)
|
64
|
+
else
|
65
|
+
@params = mod.instance_method(method_name.to_sym).parameters.map(&:last)
|
66
|
+
end
|
62
67
|
end
|
63
68
|
|
64
69
|
def update_rule_values
|
data/lib/contraction.rb
CHANGED
@@ -9,14 +9,14 @@ module Contraction
|
|
9
9
|
# @param [Class] mod The module or class to update contracts for.
|
10
10
|
def self.update_contracts(mod)
|
11
11
|
instance = mod.allocate
|
12
|
-
instance_methods = (mod.instance_methods - Object.instance_methods - Contraction.instance_methods)
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
methods_for(mod).each do |(type, methods)|
|
14
|
+
methods.each do |method_name|
|
15
|
+
file_contents, line_no = read_file_for_method(instance, method_name, type)
|
17
16
|
|
18
|
-
|
19
|
-
|
17
|
+
contract = Contraction::Parser.parse(file_contents[0..line_no-2].reverse, mod, method_name, type)
|
18
|
+
define_wrapped_method(mod, method_name, contract, type)
|
19
|
+
end
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -25,10 +25,44 @@ module Contraction
|
|
25
25
|
update_contracts(mod)
|
26
26
|
end
|
27
27
|
|
28
|
+
# Get all the public instance methods for a given class, that are unique to
|
29
|
+
# class (ie, not built-ins)
|
30
|
+
# @param [Class] klass The class to get the methods from
|
31
|
+
# @return [Array<Symbol>] The method names
|
28
32
|
def self.instance_methods_for(klass)
|
29
33
|
klass.public_instance_methods - Object.public_instance_methods - Module.public_instance_methods
|
30
34
|
end
|
31
35
|
|
36
|
+
# Get all the public class methods for a given class that are unique to the
|
37
|
+
# class (ie, not built-ins). NOTE: doing something like the following _doesn't_
|
38
|
+
# make a class method private:
|
39
|
+
# class Foo
|
40
|
+
# private
|
41
|
+
# def self.foobar
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# That's because defining a method on an object, even `self`, re-opens the
|
46
|
+
# object to define the method on it. It's the same as saying `def
|
47
|
+
# some_object.foobar`, only in this case `some_object` is the handy-dandy
|
48
|
+
# `self`. To make that really private, you can do:
|
49
|
+
# class Foo
|
50
|
+
# private
|
51
|
+
# def self.foobar
|
52
|
+
# end
|
53
|
+
# private_class_method :foobar
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# ... or ...
|
57
|
+
# class Foo
|
58
|
+
# private
|
59
|
+
# class << self
|
60
|
+
# def self.foobar
|
61
|
+
# end
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# @param [Class] klass The class to get the methods from
|
65
|
+
# @return [Array<Symbol>] The method names
|
32
66
|
def self.class_methods_for(klass)
|
33
67
|
klass.public_methods - Object.public_methods - Module.public_methods
|
34
68
|
end
|
@@ -39,21 +73,34 @@ module Contraction
|
|
39
73
|
|
40
74
|
private
|
41
75
|
|
42
|
-
def self.read_file_for_method(instance, method_name)
|
43
|
-
file, line =
|
76
|
+
def self.read_file_for_method(instance, method_name, type)
|
77
|
+
file, line = nil, nil
|
78
|
+
if type == :class
|
79
|
+
file, line = instance.class.method(method_name).source_location
|
80
|
+
elsif type == :instance
|
81
|
+
file, line = instance.method(method_name).source_location
|
82
|
+
else
|
83
|
+
raise ArgumentError.new("Unknown method type, #{type.inspect}")
|
84
|
+
end
|
44
85
|
filename = File.expand_path(file)
|
45
86
|
file_contents = File.read(filename).split("\n")
|
46
87
|
return [file_contents, line]
|
47
88
|
end
|
48
89
|
|
49
|
-
def self.define_wrapped_method(mod, method_name, contract)
|
50
|
-
old_method = mod.instance_method(method_name)
|
90
|
+
def self.define_wrapped_method(mod, method_name, contract, type)
|
91
|
+
old_method = type == :instance ? mod.instance_method(method_name) : mod.method(method_name)
|
51
92
|
|
52
93
|
arg_checks = []
|
53
94
|
result_check = nil
|
54
|
-
|
95
|
+
type = type == :class ? :define_singleton_method : :define_method
|
96
|
+
mod.send(type, method_name) do |*method_args|
|
55
97
|
contract.valid_args?(*method_args)
|
56
|
-
result =
|
98
|
+
result = nil
|
99
|
+
if old_method.respond_to?(:bind)
|
100
|
+
result = old_method.bind(self).call(*method_args)
|
101
|
+
else
|
102
|
+
result = old_method.call(*method_args)
|
103
|
+
end
|
57
104
|
contract.valid_return?(*method_args, result)
|
58
105
|
result
|
59
106
|
end
|
data/lib/parser.rb
CHANGED
@@ -17,7 +17,7 @@ module Contraction
|
|
17
17
|
# contracts/docs apply to
|
18
18
|
# @return [Contract] A Contract object that can be used to evaluate
|
19
19
|
# correctness at run-time.
|
20
|
-
def self.parse(text, mod, method_name)
|
20
|
+
def self.parse(text, mod, method_name, type)
|
21
21
|
lines = text.is_a?(String) ? text.split(/$/) : text
|
22
22
|
results = []
|
23
23
|
lines.each do |line|
|
@@ -28,7 +28,7 @@ module Contraction
|
|
28
28
|
end
|
29
29
|
results.compact!
|
30
30
|
|
31
|
-
Contract.new(results, mod, method_name)
|
31
|
+
Contract.new(results, mod, method_name, type)
|
32
32
|
end
|
33
33
|
|
34
34
|
# Parse a single line of text for @param and @return statements.
|