dhall 0.1.0 → 0.2.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.
data/lib/dhall/binary.rb CHANGED
@@ -227,7 +227,7 @@ module Dhall
227
227
  ::TrueClass => ->(e) { Bool.new(value: e) },
228
228
  ::FalseClass => ->(e) { Bool.new(value: e) },
229
229
  ::Float => ->(e) { Double.new(value: e) },
230
- ::String => ->(e) { Builtins::ALL[e]&.new || Variable.new(name: e) },
230
+ ::String => ->(e) { Builtins[e.to_sym] || (raise "Unknown builtin") },
231
231
  ::Integer => ->(e) { Variable.new(index: e) },
232
232
  ::Array => lambda { |e|
233
233
  if e.length == 2 && e.first.is_a?(::String)
@@ -64,8 +64,8 @@ module Dhall
64
64
 
65
65
  class Double_show < Builtin
66
66
  def call(arg)
67
- if arg.is_a?(Double)
68
- Text.new(value: arg.to_s)
67
+ if arg.is_a?(Dhall::Double)
68
+ Dhall::Text.new(value: arg.to_s)
69
69
  else
70
70
  super
71
71
  end
@@ -74,8 +74,8 @@ module Dhall
74
74
 
75
75
  class Integer_show < Builtin
76
76
  def call(arg)
77
- if arg.is_a?(Integer)
78
- Text.new(value: arg.to_s)
77
+ if arg.is_a?(Dhall::Integer)
78
+ Dhall::Text.new(value: arg.to_s)
79
79
  else
80
80
  super
81
81
  end
@@ -84,8 +84,8 @@ module Dhall
84
84
 
85
85
  class Integer_toDouble < Builtin
86
86
  def call(arg)
87
- if arg.is_a?(Integer)
88
- Double.new(value: arg.value.to_f)
87
+ if arg.is_a?(Dhall::Integer)
88
+ Dhall::Double.new(value: arg.value.to_f)
89
89
  else
90
90
  super
91
91
  end
@@ -105,20 +105,20 @@ module Dhall
105
105
 
106
106
  def call(arg)
107
107
  arg.call(
108
- Variable.new(name: "Natural"),
108
+ Natural.new,
109
109
  Function.of_arguments(
110
- Variable.new(name: "Natural"),
111
- body: Variable["_"] + Natural.new(value: 1)
110
+ Natural.new,
111
+ body: Variable["_"] + Dhall::Natural.new(value: 1)
112
112
  ),
113
- Natural.new(value: 0)
113
+ Dhall::Natural.new(value: 0)
114
114
  )
115
115
  end
116
116
  end
117
117
 
118
118
  class Natural_even < Builtin
119
119
  def call(nat)
120
- if nat.is_a?(Natural)
121
- Bool.new(value: nat.even?)
120
+ if nat.is_a?(Dhall::Natural)
121
+ Dhall::Bool.new(value: nat.even?)
122
122
  else
123
123
  super
124
124
  end
@@ -127,9 +127,9 @@ module Dhall
127
127
 
128
128
  class Natural_fold < Builtin
129
129
  include(ValueSemantics.for_attributes do
130
- nat Either(nil, Natural), default: nil
131
- type Either(nil, Expression), default: nil
132
- f Either(nil, Expression), default: nil
130
+ nat Either(nil, Dhall::Natural), default: nil
131
+ type Either(nil, Expression), default: nil
132
+ f Either(nil, Expression), default: nil
133
133
  end)
134
134
 
135
135
  def call(arg)
@@ -145,8 +145,8 @@ module Dhall
145
145
 
146
146
  class Natural_isZero < Builtin
147
147
  def call(nat)
148
- if nat.is_a?(Natural)
149
- Bool.new(value: nat.zero?)
148
+ if nat.is_a?(Dhall::Natural)
149
+ Dhall::Bool.new(value: nat.zero?)
150
150
  else
151
151
  super
152
152
  end
@@ -155,8 +155,8 @@ module Dhall
155
155
 
156
156
  class Natural_odd < Builtin
157
157
  def call(nat)
158
- if nat.is_a?(Natural)
159
- Bool.new(value: nat.odd?)
158
+ if nat.is_a?(Dhall::Natural)
159
+ Dhall::Bool.new(value: nat.odd?)
160
160
  else
161
161
  super
162
162
  end
@@ -165,8 +165,8 @@ module Dhall
165
165
 
166
166
  class Natural_show < Builtin
167
167
  def call(nat)
168
- if nat.is_a?(Natural)
169
- Text.new(value: nat.to_s)
168
+ if nat.is_a?(Dhall::Natural)
169
+ Dhall::Text.new(value: nat.to_s)
170
170
  else
171
171
  super
172
172
  end
@@ -175,8 +175,8 @@ module Dhall
175
175
 
176
176
  class Natural_toInteger < Builtin
177
177
  def call(nat)
178
- if nat.is_a?(Natural)
179
- Integer.new(value: nat.value)
178
+ if nat.is_a?(Dhall::Natural)
179
+ Dhall::Integer.new(value: nat.value)
180
180
  else
181
181
  super
182
182
  end
@@ -202,7 +202,7 @@ module Dhall
202
202
  def call(arg)
203
203
  fill_or_call(arg) do
204
204
  arg.call(
205
- Variable["List"].call(type),
205
+ List.new.call(type),
206
206
  cons,
207
207
  EmptyList.new(element_type: type)
208
208
  )
@@ -214,8 +214,8 @@ module Dhall
214
214
  def cons
215
215
  Function.of_arguments(
216
216
  type,
217
- Variable["List"].call(type.shift(1, "_", 0)),
218
- body: List.of(Variable["_", 1]).concat(Variable["_"])
217
+ List.new.call(type.shift(1, "_", 0)),
218
+ body: Dhall::List.of(Variable["_", 1]).concat(Variable["_"])
219
219
  )
220
220
  end
221
221
  end
@@ -242,7 +242,7 @@ module Dhall
242
242
 
243
243
  def call(arg)
244
244
  fill_or_call(arg) do
245
- if arg.is_a?(List)
245
+ if arg.is_a?(Dhall::List)
246
246
  arg.first
247
247
  else
248
248
  super
@@ -258,7 +258,7 @@ module Dhall
258
258
 
259
259
  def call(arg)
260
260
  fill_or_call(arg) do
261
- if arg.is_a?(List)
261
+ if arg.is_a?(Dhall::List)
262
262
  _call(arg)
263
263
  else
264
264
  super
@@ -272,7 +272,7 @@ module Dhall
272
272
  arg.map(type: indexed_type(type)) { |x, idx|
273
273
  Record.new(
274
274
  record: {
275
- "index" => Natural.new(value: idx),
275
+ "index" => Dhall::Natural.new(value: idx),
276
276
  "value" => x
277
277
  }
278
278
  )
@@ -282,7 +282,7 @@ module Dhall
282
282
  def indexed_type(value_type)
283
283
  RecordType.new(
284
284
  record: {
285
- "index" => Variable.new(name: "Natural"),
285
+ "index" => Natural.new,
286
286
  "value" => value_type
287
287
  }
288
288
  )
@@ -296,7 +296,7 @@ module Dhall
296
296
 
297
297
  def call(arg)
298
298
  fill_or_call(arg) do
299
- if arg.is_a?(List)
299
+ if arg.is_a?(Dhall::List)
300
300
  arg.last
301
301
  else
302
302
  super
@@ -312,8 +312,8 @@ module Dhall
312
312
 
313
313
  def call(arg)
314
314
  fill_or_call(arg) do
315
- if arg.is_a?(List)
316
- Natural.new(value: arg.length)
315
+ if arg.is_a?(Dhall::List)
316
+ Dhall::Natural.new(value: arg.length)
317
317
  else
318
318
  super
319
319
  end
@@ -328,7 +328,7 @@ module Dhall
328
328
 
329
329
  def call(arg)
330
330
  fill_or_call(arg) do
331
- if arg.is_a?(List)
331
+ if arg.is_a?(Dhall::List)
332
332
  arg.reverse
333
333
  else
334
334
  super
@@ -356,7 +356,7 @@ module Dhall
356
356
  def call(arg)
357
357
  fill_or_call(arg) do
358
358
  arg.call(
359
- Variable["Optional"].call(type),
359
+ Optional.new.call(type),
360
360
  some,
361
361
  OptionalNone.new(value_type: type)
362
362
  )
@@ -368,7 +368,7 @@ module Dhall
368
368
  def some
369
369
  Function.of_arguments(
370
370
  type,
371
- body: Optional.new(
371
+ body: Dhall::Optional.new(
372
372
  value: Variable["_"],
373
373
  value_type: type
374
374
  )
@@ -405,8 +405,8 @@ module Dhall
405
405
  )
406
406
 
407
407
  def call(arg)
408
- if arg.is_a?(Text)
409
- Text.new(
408
+ if arg.is_a?(Dhall::Text)
409
+ Dhall::Text.new(
410
410
  value: "\"#{arg.value.gsub(
411
411
  /["\$\\\b\f\n\r\t\u0000-\u001F]/,
412
412
  &ENCODE
@@ -418,8 +418,47 @@ module Dhall
418
418
  end
419
419
  end
420
420
 
421
+ class Bool < Builtin
422
+ end
423
+
424
+ class Optional < Builtin
425
+ end
426
+
427
+ class Natural < Builtin
428
+ end
429
+
430
+ class Integer < Builtin
431
+ end
432
+
433
+ class Double < Builtin
434
+ end
435
+
436
+ class Text < Builtin
437
+ end
438
+
439
+ class List < Builtin
440
+ end
441
+
442
+ class None < Builtin
443
+ def call(arg)
444
+ OptionalNone.new(value_type: arg)
445
+ end
446
+ end
447
+
448
+ class Type < Builtin
449
+ end
450
+
451
+ class Kind < Builtin
452
+ end
453
+
454
+ class Sort < Builtin
455
+ end
456
+
421
457
  # rubocop:enable Style/ClassAndModuleCamelCase
422
458
 
423
- ALL = Hash[constants.map { |c| [c.to_s.tr("_", "/"), const_get(c)] }]
459
+ def self.[](k)
460
+ const = constants.find { |c| c.to_s.tr("_", "/").to_sym == k }
461
+ const && const_get(const).new
462
+ end
424
463
  end
425
464
  end
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "psych"
4
+
5
+ module Dhall
6
+ class Coder
7
+ JSON_LIKE = [
8
+ ::Array, ::Hash,
9
+ ::TrueClass, ::FalseClass, ::NilClass,
10
+ ::Integer, ::Float, ::String
11
+ ].freeze
12
+
13
+ class Verifier
14
+ def initialize(*classes)
15
+ @classes = classes
16
+ @matcher = ValueSemantics::Either.new(classes)
17
+ end
18
+
19
+ def verify_class(klass, op)
20
+ if @classes.any? { |safe| klass <= safe }
21
+ klass
22
+ else
23
+ raise ArgumentError, "#{op} does not match "\
24
+ "#{@classes.inspect}: #{klass}"
25
+ end
26
+ end
27
+
28
+ def verify(obj, op)
29
+ if @matcher === obj
30
+ obj
31
+ else
32
+ raise ArgumentError, "#{op} does not match "\
33
+ "#{@classes.inspect}: #{obj.inspect}"
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.load(source, transform_keys: :to_s)
39
+ new.load(source, transform_keys: transform_keys)
40
+ end
41
+
42
+ def self.dump(obj)
43
+ new.dump(obj)
44
+ end
45
+
46
+ def initialize(default: nil, safe: JSON_LIKE)
47
+ @default = default
48
+ @verifier = Verifier.new(*Array(safe))
49
+ @verifier.verify(default, "default value")
50
+ end
51
+
52
+ def load_async(source, op="load_async", transform_keys: :to_s)
53
+ return Promise.resolve(@default) if source.nil?
54
+ return Promise.resolve(source) unless source.is_a?(String)
55
+
56
+ Dhall.load(source).then do |expr|
57
+ decode(expr, op, transform_keys: transform_keys)
58
+ end
59
+ end
60
+
61
+ def load(source, transform_keys: :to_s)
62
+ load_async(source, "load", transform_keys: transform_keys).sync
63
+ end
64
+
65
+ module ToRuby
66
+ refine Expression do
67
+ def to_ruby
68
+ self
69
+ end
70
+ end
71
+
72
+ refine Natural do
73
+ alias_method :to_ruby, :to_i
74
+ end
75
+
76
+ refine Integer do
77
+ alias_method :to_ruby, :to_i
78
+ end
79
+
80
+ refine Double do
81
+ alias_method :to_ruby, :to_f
82
+ end
83
+
84
+ refine Text do
85
+ alias_method :to_ruby, :to_s
86
+ end
87
+
88
+ refine Bool do
89
+ def to_ruby
90
+ self === true
91
+ end
92
+ end
93
+
94
+ refine Record do
95
+ def to_ruby(&decode)
96
+ Hash[to_h.map { |k, v| [k, decode[v]] }]
97
+ end
98
+ end
99
+
100
+ refine EmptyRecord do
101
+ def to_ruby
102
+ {}
103
+ end
104
+ end
105
+
106
+ refine List do
107
+ def to_ruby(&decode)
108
+ to_a.map(&decode)
109
+ end
110
+ end
111
+
112
+ refine Optional do
113
+ def to_ruby(&decode)
114
+ reduce(nil, &decode)
115
+ end
116
+ end
117
+
118
+ refine Function do
119
+ def to_ruby(&decode)
120
+ ->(*args) { decode[expr.call(*args)] }
121
+ end
122
+ end
123
+
124
+ refine Union do
125
+ def to_ruby
126
+ if !value.nil? && tag.match(/\A\p{Upper}/) &&
127
+ Object.const_defined?(tag)
128
+ yield extract, Object.const_get(tag)
129
+ elsif extract == :None
130
+ nil
131
+ else
132
+ yield extract
133
+ end
134
+ end
135
+ end
136
+
137
+ refine TypeAnnotation do
138
+ def to_ruby
139
+ yield value
140
+ end
141
+ end
142
+ end
143
+
144
+ using ToRuby
145
+
146
+ module InitWith
147
+ refine Object do
148
+ def init_with(coder)
149
+ coder.map.each do |k, v|
150
+ instance_variable_set(:"@#{k}", v)
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ using InitWith
157
+
158
+ def revive(klass, expr, op="revive", transform_keys: :to_s)
159
+ @verifier.verify_class(klass, op)
160
+ return klass.from_dhall(expr) if klass.respond_to?(:from_dhall)
161
+
162
+ klass.allocate.tap do |o|
163
+ o.init_with(Util.psych_coder_for(
164
+ klass.name,
165
+ decode(expr, op, transform_keys: transform_keys)
166
+ ))
167
+ end
168
+ end
169
+
170
+ def decode(expr, op="decode", klass: nil, transform_keys: :to_s)
171
+ return revive(klass, expr, op, transform_keys: transform_keys) if klass
172
+ @verifier.verify(
173
+ Util.transform_keys(
174
+ expr.to_ruby { |dexpr, dklass|
175
+ decode(dexpr, op, klass: dklass, transform_keys: transform_keys)
176
+ },
177
+ &transform_keys
178
+ ),
179
+ op
180
+ )
181
+ end
182
+
183
+ def dump(obj)
184
+ return if obj.nil?
185
+
186
+ Dhall.dump(@verifier.verify(obj, "dump"))
187
+ end
188
+ end
189
+ end