funtools 0.6.0 → 0.6.1
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/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
|