dhall 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -38,16 +38,10 @@ module Dhall
38
38
  req["Origin"] = parent_origin
39
39
  req["Access-Control-Request-Method"] = "GET"
40
40
  req["Access-Control-Request-Headers"] =
41
- source.headers.map { |h| h.fetch("header").to_s }.join(",")
42
- r = Net::HTTP.start(
43
- uri.hostname,
44
- uri.port,
45
- use_ssl: uri.scheme == "https",
46
- open_timeout: timeout,
47
- ssl_timeout: timeout,
48
- read_timeout: timeout,
49
- write_timeout: timeout
50
- ) { |http| http.request(req) }
41
+ source.headers.to_a.map { |h|
42
+ (h.fetch("header") { h.fetch("mapKey") }).to_s
43
+ }.join(",")
44
+ r = Util.net_http_req_with_timeout(uri, req, timeout: timeout)
51
45
 
52
46
  raise ImportFailedException, source if r.code != "200"
53
47
  unless r["Access-Control-Allow-Origin"] == parent_origin ||
@@ -63,19 +57,17 @@ module Dhall
63
57
  PreflightCORS.call(source, parent_origin)
64
58
  timeout = source.deadline.timeout
65
59
  uri = source.uri
66
- req = Net::HTTP::Get.new(uri)
67
- source.headers.each do |header|
68
- req[header.fetch("header").to_s] = header.fetch("value").to_s
60
+ r = loop do
61
+ req = Net::HTTP::Get.new(uri)
62
+ source.headers.each do |header|
63
+ req[(header.fetch("header") { header.fetch("mapKey") }).to_s] =
64
+ (header.fetch("value") { header.fetch("mapValue") }).to_s
65
+ end
66
+ r = Util.net_http_req_with_timeout(uri, req, timeout: timeout)
67
+
68
+ break r unless ["301", "302", "303", "307", "308"].include?(r.code)
69
+ uri = URI(r["Location"])
69
70
  end
70
- r = Net::HTTP.start(
71
- uri.hostname,
72
- uri.port,
73
- use_ssl: uri.scheme == "https",
74
- open_timeout: timeout,
75
- ssl_timeout: timeout,
76
- read_timeout: timeout,
77
- write_timeout: timeout
78
- ) { |http| http.request(req) }
79
71
 
80
72
  raise ImportFailedException, source if r.code != "200"
81
73
  r.body
@@ -86,7 +78,7 @@ module Dhall
86
78
  StandardReadHttpSources = lambda do |sources, parent_origin|
87
79
  ReadHttpSources.call(sources, parent_origin).map do |source_promise|
88
80
  source_promise.then do |s|
89
- s = s.force_encoding("UTF-8")
81
+ s = s.dup.force_encoding("UTF-8")
90
82
  unless s.valid_encoding?
91
83
  raise ImportFailedException, "#{s.inspect} is not valid UTF-8"
92
84
  end
@@ -106,7 +98,7 @@ module Dhall
106
98
  path_reader: ReadPathSources,
107
99
  http_reader: ReadHttpSources,
108
100
  https_reader: http_reader,
109
- public_gateway: "cloudflare-ipfs.com"
101
+ public_gateway: URI("https://cloudflare-ipfs.com")
110
102
  )
111
103
  @path_reader = path_reader
112
104
  @http_reader = http_reader
@@ -139,7 +131,7 @@ module Dhall
139
131
  def gateway_fallback(source, promise)
140
132
  promise.catch {
141
133
  @http_reader.call([
142
- source.to_uri(Import::Http, "localhost:8000")
134
+ source.to_uri(Import::Http, URI("http://localhost:8000"))
143
135
  ], "localhost").first
144
136
  }.catch do
145
137
  @https_reader.call([
@@ -182,11 +174,11 @@ module Dhall
182
174
 
183
175
  def fetch(key, &block)
184
176
  if key.is_a?(String) && key.start_with?("sha256:")
185
- file = @dir + key.sub(/^sha256:/, "")
177
+ file = @dir + key.sub(/^sha256:/, "1220")
186
178
  return Dhall.from_binary(file.binread) if file.exist?
187
179
 
188
180
  Promise.resolve(nil).then(&block).then do |result|
189
- file.open("wb") { |fh| fh.write(result.to_binary) }
181
+ file.open("wb") { |fh| fh.write(result.to_cbor) }
190
182
  result
191
183
  end
192
184
  else
@@ -359,7 +351,7 @@ module Dhall
359
351
  http_reader: ReadHttpSources,
360
352
  https_reader: http_reader,
361
353
  environment_reader: ReadEnvironmentSources,
362
- ipfs_public_gateway: "cloudflare-ipfs.com",
354
+ ipfs_public_gateway: URI("https://cloudflare-ipfs.com"),
363
355
  cache: RamCache.new,
364
356
  max_depth: 50
365
357
  )
@@ -427,9 +419,25 @@ module Dhall
427
419
  ).then { |h| @expr.with(h) }
428
420
  end
429
421
 
422
+ class ImportAsLocationResolver < ExpressionResolver
423
+ def resolve(resolver:, relative_to:)
424
+ Promise.resolve(nil).then do
425
+ @expr.real_path(relative_to).location
426
+ end
427
+ end
428
+ end
429
+
430
430
  class ImportResolver < ExpressionResolver
431
431
  register_for Import
432
432
 
433
+ def self.new(expr)
434
+ if expr.import_type == Import::AsLocation
435
+ ImportAsLocationResolver.new(expr)
436
+ else
437
+ super
438
+ end
439
+ end
440
+
433
441
  def resolve(resolver:, relative_to:)
434
442
  Promise.resolve(nil).then do
435
443
  resolver.cache_fetch(@expr.cache_key(relative_to)) do
@@ -12,7 +12,7 @@ module Dhall
12
12
 
13
13
  def self.assert_type(expr, assertion, message, context:)
14
14
  aexpr = self.for(expr).annotate(context)
15
- type = aexpr.type
15
+ type = aexpr.type.normalize
16
16
  raise TypeError, "#{message}: #{type}" unless assertion === type
17
17
  aexpr
18
18
  end
@@ -40,9 +40,13 @@ module Dhall
40
40
  @typecheckers[node_type] ||= [typechecker, extras]
41
41
  end
42
42
 
43
- def self.type_of(expr)
43
+ def self.annotate(expr)
44
44
  return if expr.nil?
45
- TypeChecker.for(expr).annotate(TypeChecker::Context.new).type
45
+ TypeChecker.for(expr).annotate(TypeChecker::Context.new)
46
+ end
47
+
48
+ def self.type_of(expr)
49
+ annotate(expr)&.type
46
50
  end
47
51
 
48
52
  class Context
@@ -358,10 +362,16 @@ module Dhall
358
362
  TypeChecker.register self, Dhall::EmptyList
359
363
 
360
364
  def initialize(expr)
361
- @expr = expr
365
+ @expr = expr.with(type: expr.type.normalize)
362
366
  end
363
367
 
364
368
  def annotate(context)
369
+ TypeChecker.assert @expr.type, Dhall::Application,
370
+ "EmptyList unknown type #{@expr.type.inspect}"
371
+
372
+ TypeChecker.assert @expr.type.function, Builtins[:List],
373
+ "EmptyList unknown type #{@expr.type.inspect}"
374
+
365
375
  TypeChecker.assert_type @expr.element_type, Builtins[:Type],
366
376
  "EmptyList element type not of type Type",
367
377
  context: context
@@ -383,7 +393,7 @@ module Dhall
383
393
  end
384
394
 
385
395
  def annotation
386
- list = @alist.with(element_type: element_type)
396
+ list = @alist.with(type: Builtins[:List].call(element_type))
387
397
  Dhall::TypeAnnotation.new(type: list.type, value: list)
388
398
  end
389
399
 
@@ -537,12 +547,13 @@ module Dhall
537
547
 
538
548
  class Selector
539
549
  def self.for(annotated_record)
540
- if annotated_record.type == Builtins[:Type]
550
+ typ = annotated_record.type.normalize
551
+ if KINDS.include?(typ)
541
552
  TypeSelector.new(annotated_record.value)
542
- elsif annotated_record.type.class == Dhall::RecordType
543
- new(annotated_record.type)
553
+ elsif typ.class == Dhall::RecordType
554
+ new(typ)
544
555
  else
545
- raise TypeError, "RecordSelection on #{annotated_record.type}"
556
+ raise TypeError, "RecordSelection on #{typ}"
546
557
  end
547
558
  end
548
559
 
@@ -604,6 +615,33 @@ module Dhall
604
615
  end
605
616
  end
606
617
 
618
+ class RecordProjectionByExpression
619
+ TypeChecker.register self, Dhall::RecordProjectionByExpression
620
+
621
+ def initialize(projection)
622
+ @selector = projection.selector.normalize
623
+ @project_by_expression = projection
624
+ @project_by_keys = Dhall::RecordProjection.for(
625
+ @project_by_expression.record,
626
+ @selector.keys
627
+ )
628
+ end
629
+
630
+ def annotate(context)
631
+ TypeChecker.assert @selector, Dhall::RecordType,
632
+ "RecordProjectionByExpression on #{@selector.class}"
633
+
634
+ TypeChecker.assert_type @project_by_keys, @selector,
635
+ "Type doesn't match #{@selector}",
636
+ context: context
637
+
638
+ Dhall::TypeAnnotation.new(
639
+ value: @project_by_expression,
640
+ type: @selector
641
+ )
642
+ end
643
+ end
644
+
607
645
  class Enum
608
646
  TypeChecker.register self, Dhall::Enum
609
647
 
@@ -648,6 +686,39 @@ module Dhall
648
686
  end
649
687
  end
650
688
 
689
+ class ToMap
690
+ TypeChecker.register self, Dhall::ToMap
691
+
692
+ def initialize(tomap)
693
+ @tomap = tomap
694
+ @record = TypeChecker.for(tomap.record)
695
+ end
696
+
697
+ def check_annotation(record_type)
698
+ if record_type.is_a?(Dhall::EmptyRecordType)
699
+ TypeChecker.assert @tomap.type, Dhall::Expression,
700
+ "toMap {=} has no annotation"
701
+ else
702
+ t = Types::MAP(v: record_type.record.values.first)
703
+
704
+ TypeChecker.assert t, (@tomap.type || t),
705
+ "toMap does not match annotation"
706
+ end
707
+ end
708
+
709
+ def annotate(context)
710
+ record_type = @record.annotate(context).type
711
+ TypeChecker.assert record_type, Dhall::RecordType,
712
+ "toMap on a non-record: #{record_type.inspect}"
713
+
714
+ TypeChecker.assert record_type.record.values, Util::ArrayAllTheSame,
715
+ "toMap heterogenous: #{record_type.inspect}"
716
+
717
+ type = check_annotation(record_type)
718
+ Dhall::TypeAnnotation.new(value: @tomap, type: type)
719
+ end
720
+ end
721
+
651
722
  class Merge
652
723
  TypeChecker.register self, Dhall::Merge
653
724
 
@@ -1209,12 +1280,13 @@ module Dhall
1209
1280
  TypeChecker.register self, Dhall::Builtin
1210
1281
 
1211
1282
  def self.for(builtin)
1212
- unfilled = builtin.unfill
1213
- if unfilled != builtin
1214
- TypeChecker.for(unfilled)
1215
- else
1216
- new(builtin)
1283
+ if builtin.is_a?(Dhall::BuiltinFunction)
1284
+ if (unfilled = builtin.unfill) != builtin
1285
+ return TypeChecker.for(unfilled)
1286
+ end
1217
1287
  end
1288
+
1289
+ new(builtin)
1218
1290
  end
1219
1291
 
1220
1292
  def initialize(builtin)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dhall/builtins"
4
+
5
+ module Dhall
6
+ module Types
7
+ def self.MAP_ENTRY(k: Builtins[:Text], v: Builtins[:Text])
8
+ RecordType.new(
9
+ record: {
10
+ "mapKey" => k, "mapValue" => v
11
+ }
12
+ )
13
+ end
14
+
15
+ def self.MAP(k: Builtins[:Text], v: Builtins[:Text])
16
+ Builtins[:List].call(MAP_ENTRY(k: k, v: v))
17
+ end
18
+ end
19
+ end
@@ -181,5 +181,36 @@ module Dhall
181
181
  def self.longest_common_prefix(a, b)
182
182
  a.zip(b).take_while { |(x, y)| x == y }.map(&:first)
183
183
  end
184
+
185
+ def self.indent_size(str)
186
+ if str.end_with?("\n")
187
+ 0
188
+ else
189
+ str
190
+ .scan(/^[ \t]*(?=[^ \t\n]|\Z)/)
191
+ .map(&:chars)
192
+ .reduce(&method(:longest_common_prefix))&.length.to_i
193
+ end
194
+ end
195
+
196
+ def self.path_components_to_uri(*components)
197
+ URI("/#{components.map(&method(:uri_escape)).join("/")}")
198
+ end
199
+
200
+ def self.uri_escape(s)
201
+ ::URI.encode_www_form_component(s).gsub("+", "%20")
202
+ end
203
+
204
+ def self.net_http_req_with_timeout(uri, req, timeout:)
205
+ Net::HTTP.start(
206
+ uri.hostname,
207
+ uri.port,
208
+ use_ssl: uri.scheme == "https",
209
+ open_timeout: timeout,
210
+ ssl_timeout: timeout,
211
+ read_timeout: timeout,
212
+ write_timeout: timeout
213
+ ) { |http| http.request(req) }
214
+ end
184
215
  end
185
216
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dhall
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Paul Weber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-13 00:00:00.000000000 Z
11
+ date: 2019-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base32
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.2
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: cbor
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,34 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: lazy_object
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: multihashes
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.3
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: promise.rb
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -137,6 +179,7 @@ files:
137
179
  - lib/dhall/parser.rb
138
180
  - lib/dhall/resolve.rb
139
181
  - lib/dhall/typecheck.rb
182
+ - lib/dhall/types.rb
140
183
  - lib/dhall/util.rb
141
184
  - lib/dhall/visitor.rb
142
185
  homepage: https://git.sr.ht/~singpolyma/dhall-ruby