funtools 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/funtools.rb +1 -1
  3. data/lib/funtools/types.rb +56 -39
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6162644033dfb0b9f74e9160309669f04c2515f
4
- data.tar.gz: 05e8411ba686b59b795d704d7137d8d5eaa70cf2
3
+ metadata.gz: 85c1455381faf2166f294f26ce8b18012c1865e3
4
+ data.tar.gz: 1a36bf917be530c0081faff2d9c5dfa3890bf985
5
5
  SHA512:
6
- metadata.gz: d8b8d0ae31a9584ac89608d90612fad08965d96e64a4bf94009d5d5658ff8e2b68581f3b14380c69e5e4e665792998e1be68448fb876fd2ae3485537c71d4660
7
- data.tar.gz: fabe23f7ac2a025750a415a2a4485f1aeb58c585f39acc5090f2e81062407505d45159117226c4750f7fbaeb2a499712a2b1ba26ea18fa7348b7d3d3f89c7dc4
6
+ metadata.gz: dcb8af919e949195458d5481baa423b03434d05f12d05eb6ef6585066a680db4c7ce7f7bfc28e0bad684f9287ab920cf0959c7be9a9d7277ccff62361845719c
7
+ data.tar.gz: 0b7c58ed9c8e6f69e995dfaf9bf0d4120cdc4d64ab0f27506b9bf75af5b85ef7907f156cd7bebb0a97dd6b829ac7479aca995f26f5be090fe75dec4c5cfb794f
@@ -5,5 +5,5 @@ require 'funtools/composition'
5
5
  require 'funtools/pattern-matching'
6
6
 
7
7
  module Funtools
8
- VERSION = '0.6.0'
8
+ VERSION = '0.6.1'
9
9
  end
@@ -1,15 +1,63 @@
1
1
  class Object
2
- # Public: Define a method in the current scope which will execute a given
3
- # block recursively until a fixpoint is reached.
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
- # block - Block containing the logic for the function to be created.
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
- def settype(sym, *args, ret)
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 = self.method(sym)
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
- align_types.(n).each { |pair| check_type.(*pair) }
55
- check_type.(old_method.(*n, &b), ret)
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.0
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-10-28 00:00:00.000000000 Z
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