funtools 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/funtools.rb +1 -1
- data/lib/funtools/types.rb +56 -39
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85c1455381faf2166f294f26ce8b18012c1865e3
|
4
|
+
data.tar.gz: 1a36bf917be530c0081faff2d9c5dfa3890bf985
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dcb8af919e949195458d5481baa423b03434d05f12d05eb6ef6585066a680db4c7ce7f7bfc28e0bad684f9287ab920cf0959c7be9a9d7277ccff62361845719c
|
7
|
+
data.tar.gz: 0b7c58ed9c8e6f69e995dfaf9bf0d4120cdc4d64ab0f27506b9bf75af5b85ef7907f156cd7bebb0a97dd6b829ac7479aca995f26f5be090fe75dec4c5cfb794f
|
data/lib/funtools.rb
CHANGED
data/lib/funtools/types.rb
CHANGED
@@ -1,15 +1,63 @@
|
|
1
1
|
class Object
|
2
|
-
#
|
3
|
-
#
|
2
|
+
# Internal: Check a value to make sure it conforms to a given type.
|
3
|
+
#
|
4
|
+
# value - Value to be checked against types.
|
5
|
+
# type - Type definition to be used for type checking.
|
6
|
+
#
|
7
|
+
# Raises TypeError if the value does not match the expected type.
|
8
|
+
# Returns value.
|
9
|
+
check_type = ->(value, type) do
|
10
|
+
case type
|
11
|
+
when Class, Module
|
12
|
+
unless value.is_a?(type)
|
13
|
+
raise(TypeError, "Expected #{type}; got #{value.class}")
|
14
|
+
end
|
15
|
+
when Enumerable
|
16
|
+
unless type.map { |kind| value.is_a?(kind) }.any?
|
17
|
+
raise(TypeError, "Expected one of: #{type.join(', ')}; got #{value.class}")
|
18
|
+
end
|
19
|
+
else
|
20
|
+
raise(TypeError, "Unable to test type against #{type.class}")
|
21
|
+
end
|
22
|
+
value
|
23
|
+
end
|
24
|
+
|
25
|
+
# Internal: Align a set of expected types with the arguments given in a
|
26
|
+
# method call.
|
27
|
+
#
|
28
|
+
# typedefs - Array of types against which arguments should be checked.
|
29
|
+
# a - Array of arguments passed to a given method.
|
30
|
+
#
|
31
|
+
# Returns a 2-dimensional Array containing [Typedef, Value].
|
32
|
+
align_types = ->(typedefs, a) do
|
33
|
+
pivot = typedefs.index(typedefs.select { |k,n| k == :rest }.flatten)
|
34
|
+
|
35
|
+
if pivot
|
36
|
+
types_min = pivot + 1
|
37
|
+
args_num = a.length - types_min
|
38
|
+
rest_min = a.length - (args_num + 1)
|
39
|
+
|
40
|
+
typedefs[0...pivot].to_a.zip(a[0...pivot].to_a) +
|
41
|
+
a[pivot, args_num].to_a.zip([typedefs[pivot]].cycle).map(&:reverse) +
|
42
|
+
typedefs[types_min..-1].to_a.zip(a[rest_min..-1].to_a)
|
43
|
+
else
|
44
|
+
typedefs.zip(a)
|
45
|
+
end.reject { |t, v| v.nil? && t.first == :opt }.map { |t, v| [v, t.last] }
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Define a method in the current scope which wraps an already-defined
|
49
|
+
# method, enforcing a type check on all arguments and the return value.
|
4
50
|
#
|
5
51
|
# sym - Symbol defining the name of the method to be created.
|
6
|
-
#
|
52
|
+
# args - Zero or more types specified to correspond to arguments expected to
|
53
|
+
# be passed to the method in question.
|
54
|
+
# ret - Type the method in question is expected to return.
|
7
55
|
#
|
8
56
|
# Returns nothing.
|
9
|
-
|
57
|
+
define_method(:settype) do |sym, *args, ret|
|
10
58
|
message = :define_method if respond_to?(:define_method, true)
|
11
59
|
message ||= :define_singleton_method
|
12
|
-
old_method =
|
60
|
+
old_method = begin method(sym) rescue instance_method(sym) end
|
13
61
|
params = old_method.parameters
|
14
62
|
|
15
63
|
typedefs = old_method.parameters.select do |kind,_|
|
@@ -18,41 +66,10 @@ class Object
|
|
18
66
|
[req.first, args[index]]
|
19
67
|
end
|
20
68
|
|
21
|
-
check_type = ->(value, type) do
|
22
|
-
case type
|
23
|
-
when Class, Module
|
24
|
-
unless value.is_a?(type)
|
25
|
-
raise(TypeError, "Expected #{type}; got #{value.class}")
|
26
|
-
end
|
27
|
-
when Enumerable
|
28
|
-
unless type.map { |kind| value.is_a?(kind) }.any?
|
29
|
-
raise(TypeError, "Expected one of: #{type.join(', ')}; got #{value.class}")
|
30
|
-
end
|
31
|
-
else
|
32
|
-
raise(TypeError, "Unable to test type against #{type.class}")
|
33
|
-
end
|
34
|
-
value
|
35
|
-
end
|
36
|
-
|
37
|
-
align_types = ->(a) do
|
38
|
-
pivot = typedefs.index(typedefs.select { |k,n| k == :rest }.flatten)
|
39
|
-
|
40
|
-
if pivot
|
41
|
-
types_min = pivot + 1
|
42
|
-
args_num = a.length - types_min
|
43
|
-
rest_min = a.length - (args_num + 1)
|
44
|
-
|
45
|
-
typedefs[0...pivot].to_a.zip(a[0...pivot].to_a) +
|
46
|
-
a[pivot, args_num].to_a.zip([typedefs[pivot]].cycle).map(&:reverse) +
|
47
|
-
typedefs[types_min..-1].to_a.zip(a[rest_min..-1].to_a)
|
48
|
-
else
|
49
|
-
typedefs.zip(a)
|
50
|
-
end.reject { |t, v| v.nil? && t.first == :opt }.map { |t, v| [v, t.last] }
|
51
|
-
end
|
52
|
-
|
53
69
|
self.send(message, sym) do |*n, &b|
|
54
|
-
|
55
|
-
|
70
|
+
method = old_method.is_a?(Method) ? old_method : old_method.bind(self)
|
71
|
+
align_types.(typedefs, n).each { |pair| check_type.(*pair) }
|
72
|
+
check_type.(method.(*n, &b), ret)
|
56
73
|
end
|
57
74
|
end
|
58
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: funtools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tina Wuest
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Tools to assist in programming in a more functional style
|
14
14
|
email: tina@wuest.me
|