safrano 0.6.5 → 0.6.7

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: b71032a7ee1e048867f3b54f57d920ba772a44f29a3419a598d2206d50e949c7
4
- data.tar.gz: d203df34eda2c7aad9385a84e866d273f1a1f37ba981ffdcc8956de9dad35633
3
+ metadata.gz: a93263d81a1f266029f7aac03d6b7226477f10d27d33255462e08133955ab759
4
+ data.tar.gz: 894a0bfab2eeeee57543bee7dd0c1ec93b5bc73e0afc6fe5f979c7b7e7067039
5
5
  SHA512:
6
- metadata.gz: d5cb1583e62f42f9007368204d24f101273049c05e75723dbcd7796732d83e1ac29a1515df0a876a2002c212b0da8204c498070104688fd4b493092072e13dee
7
- data.tar.gz: 96aa136d330148331b98943807c83b42e466aa7357c8b360b3f5a66843b9472df41015309b2bef19d993bdabf5f4d1d41e983e7082a1f06d34015370bc87a034
6
+ metadata.gz: f0900d4f692a9139226d4fb84703f8a0c47a071b97b0a46c8455016f6a7d0d09caf2b12f32e616c9880a10a0b50e09917ca22afc4af7fc0f4cddac690193b25c
7
+ data.tar.gz: 30a623f667830e0dc4342bcf240843d313173ef12c0e877dc1814e779fc7f53459e7ec7e958aedd22b4387c9390907844a0c2c84a639db8d98dc62805203a671
@@ -21,7 +21,7 @@ module Safrano
21
21
  class Static < Handler
22
22
  def initialize(root: nil, mediaklass:)
23
23
  @root = File.absolute_path(root || Dir.pwd)
24
- @file_server = ::Rack::File.new(@root)
24
+ @file_server = ::Rack::Files.new(@root)
25
25
  @media_class = mediaklass
26
26
  @media_dir_name = mediaklass.to_s
27
27
  register
@@ -81,9 +81,9 @@ module Safrano
81
81
  end
82
82
 
83
83
  # needed for ComplexType result
84
- def to_odata_json(_req)
84
+ def to_odata_json(req)
85
85
  t = self.class.klassmod.output_template
86
- innerh = _req.service.get_entity_odata_h(entity: @value, template: t)
86
+ innerh = req.service.get_entity_odata_h(entity: @value, template: t)
87
87
  innerj = innerh.to_json
88
88
 
89
89
  "#{DJ_OPEN}#{innerj}#{DJ_CLOSE}"
data/lib/odata/error.rb CHANGED
@@ -48,6 +48,13 @@ module Safrano
48
48
  end
49
49
  end
50
50
 
51
+ # used in function import error handling. cf. func import / do_execute_func
52
+ def self.with_error(result)
53
+ if result.respond_to?(:error) && (err = result.error)
54
+ yield err
55
+ end
56
+ end
57
+
51
58
  # base module for HTTP errors, when used as a Error Class
52
59
  module ErrorClass
53
60
  include ::Safrano::Contract::Invalid
@@ -94,10 +101,20 @@ module Safrano
94
101
  # generic http 500 server err
95
102
  class ServerError
96
103
  extend ErrorClass
104
+ include ErrorInstance
97
105
  HTTP_CODE = 500
98
106
  @msg = 'Server error'
99
107
  end
100
108
 
109
+ class ServiceOperationError
110
+ extend ErrorClass
111
+ include ErrorInstance
112
+ HTTP_CODE = 500
113
+ def initialize(msg:, sopname: nil)
114
+ @msg = "Error in service operation #{sopname}: #{msg}"
115
+ end
116
+ end
117
+
101
118
  # for outputing Sequel exceptions that we could not prevent
102
119
  class SequelExceptionError < ServerError
103
120
  include ErrorInstance
@@ -10,6 +10,21 @@ module Safrano
10
10
  end
11
11
 
12
12
  module FunctionImport
13
+ # error classes
14
+ class DefinitionMissing < StandardError
15
+ def initialize(fnam)
16
+ msg = "Function import #{fnam}: definition is missing. Provide definition either as a return code block or with .definition(lambda)"
17
+ super(msg)
18
+ end
19
+ end
20
+ class ProcRedefinition < StandardError
21
+ def initialize(fnam)
22
+ msg = "Function import #{fnam}: Block/lambda Redefinition . Provide definition either as a return code block or with .definition(lambda) but not both"
23
+ super(msg)
24
+ end
25
+ end
26
+
27
+ # Function import object
13
28
  class Function
14
29
  @allowed_transitions = [Safrano::TransitionEnd]
15
30
  attr_reader :name
@@ -53,8 +68,6 @@ module Safrano
53
68
  alias auto_query_params auto_query_parameters
54
69
 
55
70
  def return(klassmod, &proc)
56
- raise('Please provide a code block') unless block_given?
57
-
58
71
  @returning = if klassmod.respond_to? :return_as_instance_descriptor
59
72
  klassmod.return_as_instance_descriptor
60
73
  else
@@ -62,13 +75,35 @@ module Safrano
62
75
  # --> assume it is a Primitive
63
76
  ResultDefinition.asPrimitiveType(klassmod)
64
77
  end
65
- @proc = proc
78
+ # block is optional since 0.6.7
79
+ # the function definition can now also be made with .definition(lambda)
80
+ # consistency check that there is a single definition either as a
81
+ # return-block or a definition lambda is made on publish finalise
82
+
83
+ if block_given?
84
+ # proc already defined...
85
+ raise Redefinition.new(@name) if @proc
86
+
87
+ @proc = proc
88
+ end
89
+
66
90
  self
67
91
  end
68
92
 
69
- def return_collection(klassmod, &proc)
70
- raise('Please provide a code block') unless block_given?
93
+ def definition(lambda)
94
+ raise('Please provide a lambda') unless lambda
95
+ # proc already defined...
96
+ raise ProcRedefinition.new(@name) if @proc
97
+
98
+ @proc = lambda
99
+ end
100
+
101
+ # this is called from service.finalize_publishing
102
+ def check_definition
103
+ raise DefinitionMissing.new(@name) unless @proc
104
+ end
71
105
 
106
+ def return_collection(klassmod, lambda: nil, &proc)
72
107
  @returning = if klassmod.respond_to? :return_as_collection_descriptor
73
108
  klassmod.return_as_collection_descriptor
74
109
  else
@@ -77,7 +112,14 @@ module Safrano
77
112
  # ResultAsPrimitiveTypeColl.new(klassmod)
78
113
  ResultDefinition.asPrimitiveTypeColl(klassmod)
79
114
  end
80
- @proc = proc
115
+ # block is optional since 0.6.7
116
+ if block_given?
117
+ # proc already defined...
118
+ raise ProcRedefinition.new(@name) if @proc
119
+
120
+ @proc = proc
121
+ end
122
+
81
123
  self
82
124
  end
83
125
  # def initialize_params
@@ -151,14 +193,31 @@ module Safrano
151
193
  def with_transition_validated(req)
152
194
  # initialize_params
153
195
  @params = req.params
154
- return yield unless (@error = check_url_func_params)
155
-
196
+ unless (@error = check_url_func_params)
197
+ begin
198
+ return yield
199
+ rescue LocalJumpError => e
200
+ @error = Safrano::ServiceOperationReturnError.new
201
+ end
202
+ end
156
203
  [nil, :error, @error] if @error
157
204
  end
158
205
 
159
206
  def do_execute_func(req)
160
207
  with_transition_validated(req) do
161
208
  result = @proc.call(**@funcparams)
209
+
210
+ # (application-)error handling
211
+ # the result is an Error object or class
212
+
213
+ # Note: Sequel::Error exceptions are already
214
+ # handled on rack app level (cf. the call methode )
215
+ Safrano::with_error(result) do |error|
216
+ @error = error
217
+ return [nil, :error, @error] # this is return from do_execute_func !
218
+ end
219
+
220
+ # non error case
162
221
  [@returning.do_execute_func_result(result, req, @auto_query_params), :run]
163
222
  end
164
223
  end
@@ -753,7 +753,8 @@ module Safrano
753
753
  # json is default content type so we dont need to specify it here again
754
754
  # TODO quirks array mode !
755
755
  # [201, EMPTY_HASH, new_entity.to_odata_post_json(service: req.service)]
756
- [201, { 'Location' => new_entity.uri }, new_entity.to_odata_create_json(request: req)]
756
+ [201, { Safrano::LOCATION => new_entity.uri },
757
+ new_entity.to_odata_create_json(request: req)]
757
758
  else # TODO: other formats
758
759
  415
759
760
  end
@@ -1,9 +1,15 @@
1
1
  require 'json'
2
2
  require 'time'
3
-
3
+ require 'base64'
4
4
  # client parsing functionality to ease testing
5
5
 
6
6
  module Safrano
7
+ module RFC2047
8
+ def self.encode(str)
9
+ "=?utf-8?b?#{Base64.strict_encode64(str)}?="
10
+ end
11
+ end
12
+
7
13
  module OData
8
14
  # this is used to parse inbound json payload on POST / PUT & co
9
15
  # it does not do symbolize but proper (hopefully) type casting when needed
data/lib/safrano/core.rb CHANGED
@@ -13,10 +13,10 @@ module Safrano
13
13
 
14
14
  # some prominent constants... probably already defined elsewhere eg in Rack
15
15
  # but lets KISS
16
- CONTENT_TYPE = 'Content-Type'
17
- CONTENT_LENGTH = 'Content-Length'
18
- LOCATION = 'Location'
19
- CTT_TYPE_LC = 'content-type'
16
+ CONTENT_TYPE = 'content-type'
17
+ CONTENT_LENGTH = 'content-length'
18
+ LOCATION = 'location'
19
+
20
20
  TEXTPLAIN_UTF8 = 'text/plain;charset=utf-8'
21
21
  APPJSON = 'application/json'
22
22
  APPXML = 'application/xml'
@@ -142,12 +142,12 @@ module MIME
142
142
  @lines = inpstr.readlines(@sep)
143
143
  else
144
144
  # rack input wrapper only has gets but not readlines
145
- sepsave = $INPUT_RECORD_SEPARATOR
146
- $INPUT_RECORD_SEPARATOR = @sep
147
- while (line = inpstr.gets)
148
- @lines << line
149
- end
150
- $INPUT_RECORD_SEPARATOR = sepsave
145
+ # BUT the rack SPEC says it only supports gets without argument!
146
+ # --> finally we end up using read and split into lines...
147
+ # normally should be ok for $batch POST payloads
148
+
149
+ # inpstr.read should be a String
150
+ @lines = inpstr.read.lines(@sep)
151
151
 
152
152
  end
153
153
  # tmp hack for test-tools that convert CRLF in payload to LF :-(
@@ -375,7 +375,7 @@ module Safrano
375
375
  def finalize_publishing
376
376
  # build the cmap
377
377
  @cmap = {}
378
- @collections.each do |klass|
378
+ @collections&.each do |klass|
379
379
  @cmap[klass.entity_set_name] = klass
380
380
  # set namespace needed to have qualified type name
381
381
  copy_namespace_to(klass)
@@ -393,7 +393,7 @@ module Safrano
393
393
  set_uribase
394
394
 
395
395
  # finalize the uri's and include NoMappingBeforeOutput or MappingBeforeOutput as needed
396
- @collections.each do |klass|
396
+ @collections&.each do |klass|
397
397
  klass.finalize_publishing(self)
398
398
 
399
399
  klass.build_uri(@uribase)
@@ -448,9 +448,14 @@ module Safrano
448
448
  Safrano::Filter::DateTimeLit.include Safrano::Filter::DateTimeDefault
449
449
  Safrano::Filter::DateTimeOffsetLit.include Safrano::Filter::DateTimeDefault
450
450
  end
451
+
452
+ # check function import definition
453
+ function_imports.each_value { |func| func.check_definition }
451
454
  end
452
455
 
453
456
  def execute_deferred_iblocks
457
+ return unless @collections
458
+
454
459
  @collections.each do |k|
455
460
  k.instance_eval(&k.deferred_iblock) if k.deferred_iblock
456
461
  end
@@ -460,6 +465,8 @@ module Safrano
460
465
  ## evaluated after '@collections' is filled !
461
466
  # A regexp matching all allowed base entities (eg product|categories )
462
467
  def base_url_regexp
468
+ return unless @collections
469
+
463
470
  @collections.map(&:entity_set_name).join('|')
464
471
  end
465
472
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Safrano
4
- VERSION = '0.6.5'
4
+ VERSION = '0.6.7'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safrano
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - oz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-28 00:00:00.000000000 Z
11
+ date: 2023-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: '1.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: '1.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rfc2047
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '1.0'
117
+ version: '2.0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '1.0'
124
+ version: '2.0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rake
127
127
  requirement: !ruby/object:Gem::Requirement