low_type 0.8.6 → 0.8.8

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: ef26c686d314eec78cc49419d8f13d502d0a167f5b059961805754d38fd79a78
4
- data.tar.gz: df781758ab9e3bb9a5d9a7c2119cd6dd3d080ec2cc123cf78aa9a90b75b660fd
3
+ metadata.gz: b542b5e282a1c49db5ff50843ca16eae7ad0a6f50c143dd2568b4eed77b951ce
4
+ data.tar.gz: deeb4c06c3e78041eefd69ddb0ab16c5317c2b4ec28306092cbd0a608d6b862b
5
5
  SHA512:
6
- metadata.gz: 941cd854ce780919c11335896b727eb8e4084e42d4c75ca2c4e563507d1ba7c2a580c19e8056e2cb45c093b76387921df1eeba71f82e4a176e57478d73c492e2
7
- data.tar.gz: d47aa4998fd2154703359e382564321ad4dcd1cf6107990d5a7ec5b18634e8b1440d77fab5e0b165bfd6640ac114a771ed5e9a7dadcac284cc6941a43aaf0de4
6
+ metadata.gz: 7518519f80e3ba2edc2cd114a6fef9676e3866ac6c5032f983867cd8ab70a62de7e20113ed076c223e027c517654bd3538187eebd88a11964f46d8bdced623f0
7
+ data.tar.gz: d6fee3d4fd5a7135e91eeafe090ed844fbde9bfb5b495e1022352910544f76d0c5074d2c7cb04657d18d421b50977b0194cd7a6f546bb4dbec37c8483023c849
@@ -1,8 +1,8 @@
1
1
  require 'prism'
2
2
 
3
- require_relative 'sinatra_return_proxy'
4
3
  require_relative '../interfaces/adapter_interface'
5
4
  require_relative '../proxies/file_proxy'
5
+ require_relative '../proxies/return_proxy'
6
6
  require_relative '../error_types'
7
7
 
8
8
  module LowType
@@ -17,7 +17,7 @@ module LowType
17
17
  @file_path = file_path
18
18
  end
19
19
 
20
- def redefine_methods
20
+ def process
21
21
  method_calls = @parser.method_calls(method_names: [:get, :post, :patch, :put, :delete, :options, :query])
22
22
 
23
23
  # Type check return values.
@@ -35,57 +35,35 @@ module LowType
35
35
 
36
36
  route = "#{method_call.name.upcase} #{pattern}"
37
37
  @klass.low_methods[route] = MethodProxy.new(name: method_call.name, params:, return_proxy:)
38
+ end
39
+ end
38
40
 
39
- # We're in Sinatra now. Objects request/response are from Sinatra.
40
- @klass.after pattern do
41
- if (method_proxy = self.class.low_methods["#{request.request_method} #{pattern}"])
42
- proxy = method_proxy.return_proxy
41
+ def redefine
42
+ Module.new do
43
+ def invoke(&block)
44
+ res = catch(:halt, &block)
43
45
 
44
- # Inclusive rather than exclusive validation. If one type/value is valid then there's no need to error.
45
- valid_type = proxy.type_expression.types.any? do |type|
46
- proxy.type_expression.validate(value: SinatraAdapter.reconstruct_return_value(type:, response:), proxy:)
47
- end
46
+ raise AllowedTypeError, 'Did you mean "Response.finish"?' if res.to_s == 'Response'
48
47
 
49
- # No valid types so let's return a server error to the client.
50
- unless valid_type
51
- proxy.type_expression.types.each do |type|
52
- value = SinatraAdapter.reconstruct_return_value(type:, response:)
53
- unless proxy.type_expression.validate(value:, proxy:)
54
- status(500)
55
- body(proxy.error_message(value: value.inspect))
56
- break
57
- end
58
- end
48
+ route = "#{request.request_method} #{request.path}"
49
+ if (res && (method_proxy = self.class.low_methods[route]) && (proxy = method_proxy.return_proxy))
50
+ proxy.type_expression.types.each do |type|
51
+ proxy.type_expression.validate!(value: res, proxy:)
59
52
  end
60
53
  end
61
- end
62
- end
63
- end
64
54
 
65
- # The route's String/Array/Enumerable return value populates a Rack::Response object.
66
- # This response also contains values added via Sinatra DSL's header()/body() methods.
67
- # So reconstruct the return value from the response object, based on the return type.
68
- def self.reconstruct_return_value(type:, response:)
69
- valid_types = {
70
- Integer => -> (response) { response.status },
71
- String => -> (response) { response.body.first },
72
- HTML => -> (response) { response.body.first },
73
- JSON => -> (response) { response.body.first },
74
-
75
- # TODO: Should these be Enumerable[T] instead? How would we match a Module of a class in a hash key?
76
- # NOTE: These keys represent types, not type expressions.
77
- # A type lives inside a type expression and is actually an instance representing that type.
78
- [String] => -> (response) { response.body },
79
- [Integer, String] => -> (response) { [response.status, *response.body] },
80
- [Integer, Hash, String] => -> (response) { [response.status, response.headers, *response.body] },
81
- }
82
-
83
- raise AllowedTypeError, 'Did you mean "Response.finish"?' if type.to_s == 'Response'
84
-
85
- if (reconstructed_value = valid_types[type])
86
- return reconstructed_value.call(response)
87
- else
88
- raise AllowedTypeError, "Valid Sinatra return types: #{valid_types.keys.map(&:to_s).join(' | ')}"
55
+ res = [res] if (Integer === res) || (String === res)
56
+ if (Array === res) && (Integer === res.first)
57
+ res = res.dup
58
+ status(res.shift)
59
+ body(res.pop)
60
+ headers(*res)
61
+ elsif res.respond_to? :each
62
+ body res
63
+ end
64
+
65
+ nil # avoid double setting the same response tuple twice
66
+ end
89
67
  end
90
68
  end
91
69
 
@@ -98,7 +76,7 @@ module LowType
98
76
  expression = eval(return_type.slice).call
99
77
  expression = TypeExpression.new(type: expression) unless TypeExpression === expression
100
78
 
101
- SinatraReturnProxy.new(type_expression: expression, name: "#{method_node.name.upcase} #{pattern}", file:)
79
+ ReturnProxy.new(type_expression: expression, name: "#{method_node.name.upcase} #{pattern}", file:)
102
80
  end
103
81
  end
104
82
  end
data/lib/basic_types.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module LowType
2
2
  class Boolean; end # TrueClass or FalseClass
3
+
3
4
  class HTML < String; end
4
5
  class JSON < String; end
6
+ class XML < String; end
5
7
  end
@@ -1,6 +1,6 @@
1
1
  module LowType
2
2
  class AdapterInterface
3
- def redefine_methods
3
+ def process
4
4
  raise NotImplementedError
5
5
  end
6
6
  end
data/lib/low_type.rb CHANGED
@@ -43,8 +43,10 @@ module LowType
43
43
  klass.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.instance_methods, klass:, private_start_line:, file_path:)
44
44
  klass.singleton_class.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.class_methods, klass:, private_start_line:, file_path:)
45
45
 
46
- adapter = AdapterLoader.load(klass:, parser:, file_path:)
47
- adapter.redefine_methods if adapter
46
+ if (adapter = AdapterLoader.load(klass:, parser:, file_path:))
47
+ adapter.process
48
+ klass.prepend adapter.redefine
49
+ end
48
50
  ensure
49
51
  Array.define_singleton_method('[]', array_class_method)
50
52
  Hash.define_singleton_method('[]', hash_class_method)
@@ -7,6 +7,7 @@ module LowType
7
7
  attr_reader :types, :default_value
8
8
 
9
9
  def initialize(type: nil, default_value: :LOW_TYPE_UNDEFINED)
10
+ # Types can be instance representations of a structure.
10
11
  @types = []
11
12
  @types << type unless type.nil?
12
13
  @default_value = default_value
@@ -83,7 +84,7 @@ module LowType
83
84
  # [T, T, T]
84
85
  if types.length > 1
85
86
  types.each_with_index do |type, index|
86
- return false unless type === values[index]
87
+ return false unless type <= values[index].class # Example: HTML is a subclass of String and should pass as a String.
87
88
  end
88
89
  # [T]
89
90
  elsif types.length == 1
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LowType
4
- VERSION = '0.8.6'
4
+ VERSION = '0.8.8'
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.8.6
4
+ version: 0.8.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi
@@ -19,7 +19,6 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - lib/adapters/adapter_loader.rb
21
21
  - lib/adapters/sinatra_adapter.rb
22
- - lib/adapters/sinatra_return_proxy.rb
23
22
  - lib/basic_types.rb
24
23
  - lib/error_types.rb
25
24
  - lib/interfaces/adapter_interface.rb
@@ -1,18 +0,0 @@
1
- require_relative '../proxies/return_proxy'
2
-
3
- module LowType
4
- class SinatraReturnProxy < ReturnProxy
5
- attr_reader :type_expression, :name
6
-
7
- def initialize(type_expression:, name:, file:)
8
- @type_expression = type_expression
9
- @name = name
10
- @file = file
11
- end
12
-
13
- def error_message(value:)
14
- value = value[0...20] if value
15
- "Invalid return value '#{value}' for method '#{@name}'. Valid types: '#{@type_expression.valid_types}'"
16
- end
17
- end
18
- end