low_type 0.2.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f39ec6a2c5d0986b75bd52a8bec8033b38bd5ba094515994fa655e253b47a669
4
- data.tar.gz: f7aa54e8ce075b121a8e8fed025ea5a60e13a151a6891cb6aaedbe63432f8769
3
+ metadata.gz: b01f96320aa0543e44d8b4b40430903af4966174fb9ae1533ddf7240c1919ec1
4
+ data.tar.gz: 87094ba39f9755fce4befa350b7ce33d7bd807a9774f1366340a0c9003788933
5
5
  SHA512:
6
- metadata.gz: 021eec0aae1a09604d45f5911647000f1620a0d1482cd743ee5066ae660b7e425af246a4806b7ef50763bc1dad3587631eeeea5e428abb7cc20308dec043d9f1
7
- data.tar.gz: a238797c74dbe741db04a104ebad2f081d197bd5cea38dde2ae4ee5cb4a6735de183d1722b08229691d063c14e2f8ffd2662957fb19573f840bb19bc01cc4626
6
+ metadata.gz: 2b4ff1cca9f7763084b3283a13b34955863a81074a6161703c3993aa6d0916180804f8b6058ee35779be159eec7000d9c2f676c656254a67039cb3548073f10d
7
+ data.tar.gz: 39aad0e4a488963333b31c8ec21fc6586e78e5d0ebf76a6546997183ada9ce6baacbd0107ecd0ed71ce5e5c9fa14d8597936b5db874edc48fdc6c082651ea72e
data/lib/low_type.rb CHANGED
@@ -6,6 +6,19 @@ require_relative 'type_expression'
6
6
  module LowType
7
7
  # We do as much as possible on class load rather than on instantiation to be thread-safe and efficient.
8
8
  def self.included(klass)
9
+
10
+ # Array[] class method returns a type expression only for the duration of this "included" hook.
11
+ array_class_method = Array.method('[]').unbind
12
+ Array.define_singleton_method('[]') do |expression|
13
+ TypeExpression.new(type: [(expression)])
14
+ end
15
+
16
+ # Hash[] class method returns a type expression only for the duration of this "included" hook.
17
+ hash_class_method = Hash.method('[]').unbind
18
+ Hash.define_singleton_method('[]') do |expression|
19
+ TypeExpression.new(type: expression)
20
+ end
21
+
9
22
  class << klass
10
23
  def low_params
11
24
  @low_params ||= {}
@@ -24,8 +37,12 @@ module LowType
24
37
 
25
38
  parser = Parser.new(file_path: LowType.file_path(klass:))
26
39
  private_start_line = parser.private_start_line
40
+
27
41
  klass.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.instance_methods, private_start_line:, klass:)
28
42
  klass.singleton_class.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.class_methods, private_start_line:, klass:)
43
+ ensure
44
+ Array.define_singleton_method('[]', array_class_method)
45
+ Hash.define_singleton_method('[]', hash_class_method)
29
46
  end
30
47
 
31
48
  class << self
@@ -44,6 +61,4 @@ module LowType
44
61
 
45
62
  class ValueExpression; end
46
63
  class Boolean; end # TrueClass or FalseClass
47
- class KeyValue; end # KeyValue[String => Hash]
48
- class MixedTypes; end # MixedTypes[String | Integer]
49
64
  end
data/lib/redefiner.rb CHANGED
@@ -8,12 +8,7 @@ module LowType
8
8
  def redefine_methods(method_nodes:, private_start_line:, klass:)
9
9
  Module.new do
10
10
  method_nodes.each do |method_node|
11
- args = method_node.parameters.slice
12
-
13
- proxy_method = eval("-> (#{args}) {}")
14
- required_args, required_kwargs = Redefiner.required_args(proxy_method)
15
-
16
- klass.low_params[method_node.name] = Redefiner.type_expressions_from_params(proxy_method, args, required_args, required_kwargs)
11
+ klass.low_params[method_node.name] = Redefiner.param_proxy_with_type_expressions(method_node)
17
12
  next if klass.low_params[method_node.name].empty?
18
13
 
19
14
  define_method(method_node.name) do |*args, **kwargs|
@@ -34,28 +29,14 @@ module LowType
34
29
  end
35
30
  end
36
31
 
37
- def required_args(proxy_method)
38
- required_args = []
39
- required_kwargs = {}
40
-
41
- proxy_method.parameters.each do |param|
42
- param_type, param_name = param
43
-
44
- case param_type
45
- when :req
46
- required_args << nil
47
- when :keyreq
48
- required_kwargs[param_name] = nil
49
- end
50
- end
51
-
52
- [required_args, required_kwargs]
53
- end
32
+ def param_proxy_with_type_expressions(method_node)
33
+ params = method_node.parameters.slice
34
+ proxy_method = eval("-> (#{params}) {}")
35
+ required_args, required_kwargs = Redefiner.required_args(proxy_method)
54
36
 
55
- def type_expressions_from_params(proxy_method, args, required_args, required_kwargs)
56
37
  typed_method = eval(
57
38
  <<~RUBY
58
- -> (#{args}) {
39
+ -> (#{params}) {
59
40
  param_proxies = []
60
41
 
61
42
  proxy_method.parameters.each_with_index do |param, position|
@@ -78,6 +59,28 @@ module LowType
78
59
 
79
60
  # Call method with only its required args to evaluate type expressions (which are stored as default values).
80
61
  typed_method.call(*required_args, **required_kwargs)
62
+
63
+ # TODO: Write spec for this.
64
+ rescue ArgumentError => e
65
+ raise ArgumentError, "Incorrect param syntax"
66
+ end
67
+
68
+ def required_args(proxy_method)
69
+ required_args = []
70
+ required_kwargs = {}
71
+
72
+ proxy_method.parameters.each do |param|
73
+ param_type, param_name = param
74
+
75
+ case param_type
76
+ when :req
77
+ required_args << nil
78
+ when :keyreq
79
+ required_kwargs[param_name] = nil
80
+ end
81
+ end
82
+
83
+ [required_args, required_kwargs]
81
84
  end
82
85
  end
83
86
  end
@@ -29,7 +29,16 @@ module LowType
29
29
  raise ArgumentError, "Missing required argument of type '#{@types.join(', ')}' for '#{name}'"
30
30
  end
31
31
 
32
- raise TypeError, "Invalid type '#{arg.class}' for '#{name}'" unless @types.include?(arg.class)
32
+ @types.each do |type|
33
+ return true if LowType.type?(type) && type == arg.class
34
+ # TODO: Shallow validation of enumerables could be made deeper with user config.
35
+ return true if type.class == Array && arg.class == Array && type.first == arg.first.class
36
+ if type.class == Hash && arg.class == Hash && type.keys[0] == arg.keys[0].class && type.values[0] == arg.values[0].class
37
+ return true
38
+ end
39
+ end
40
+
41
+ raise TypeError, "Invalid type '#{arg.class}' for '#{name}'"
33
42
  end
34
43
  end
35
44
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LowType
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: low_type
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi