kapusta 0.1.2 → 0.1.4

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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kapusta
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.4'
5
5
  end
data/lib/kapusta.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'kapusta/version'
4
+ require_relative 'kapusta/error'
4
5
  require_relative 'kapusta/support'
5
6
  require_relative 'kapusta/ast'
6
7
  require_relative 'kapusta/reader'
data/spec/cli_spec.rb CHANGED
@@ -26,17 +26,23 @@ ensure
26
26
  end
27
27
 
28
28
  RSpec.describe Kapusta::CLI do
29
- it 'compiles a .kap file to stdout with --compile' do
29
+ it 'compiles a .kap file to runnable Ruby with --compile' do
30
30
  path = File.expand_path('../examples/fizzbuzz.kap', __dir__)
31
31
 
32
- output = capture_stdout do
32
+ ruby = capture_stdout do
33
33
  described_class.start(['--compile', path])
34
34
  end
35
35
 
36
- expect(output).to include('__kap_print_values("FizzBuzz")')
37
- expect(output).not_to include('Kapusta::Compiler::Runtime')
38
- expect(output).not_to include('module Kapusta')
39
- expect(output).not_to include('def __kap_get_path')
36
+ Dir.mktmpdir do |dir|
37
+ output_path = File.join(dir, 'fizzbuzz.rb')
38
+ File.write(output_path, ruby)
39
+
40
+ stdout, stderr, status = Open3.capture3(RbConfig.ruby, output_path)
41
+
42
+ expected = "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\n"
43
+ expect(status.success?).to eq(true), stderr
44
+ expect(stdout).to eq(expected)
45
+ end
40
46
  end
41
47
 
42
48
  it 'rejects extra positional arguments in compile mode' do
@@ -50,21 +56,6 @@ RSpec.describe Kapusta::CLI do
50
56
  expect(error_output).to include('usage: kapusta')
51
57
  end
52
58
 
53
- it 'emits standalone Ruby that runs with plain ruby' do
54
- source_path = File.expand_path('../examples/fizzbuzz.kap', __dir__)
55
-
56
- Dir.mktmpdir do |dir|
57
- output_path = File.join(dir, 'fizzbuzz.rb')
58
- ruby = Kapusta.compile(File.read(source_path), path: source_path)
59
- File.write(output_path, ruby)
60
-
61
- stdout, stderr, status = Open3.capture3(RbConfig.ruby, output_path)
62
-
63
- expect(status.success?).to eq(true), stderr
64
- expect(stdout).to include("FizzBuzz\n")
65
- end
66
- end
67
-
68
59
  it 'passes remaining arguments through to the Kapusta program' do
69
60
  path = File.expand_path('../examples/greet.kap', __dir__)
70
61
 
@@ -31,6 +31,10 @@ RSpec.describe 'examples' do
31
31
  expect(run_example('anagram.kap')).to eq("true\ntrue\nfalse\n")
32
32
  end
33
33
 
34
+ it 'anonymous-greeter.kap' do
35
+ expect(run_example('anonymous-greeter.kap')).to eq("Hello, anonymous!\nHello, Ada!\n")
36
+ end
37
+
34
38
  it 'calc.kap' do
35
39
  expect(run_example('calc.kap')).to eq("14\n")
36
40
  end
@@ -39,6 +43,10 @@ RSpec.describe 'examples' do
39
43
  expect(run_example('binary-search.kap')).to eq("3\nnil\n")
40
44
  end
41
45
 
46
+ it 'binary-to-decimal.kap' do
47
+ expect(run_example('binary-to-decimal.kap')).to eq("11\n0\n42\n")
48
+ end
49
+
42
50
  it 'blocks-and-kwargs.kap' do
43
51
  path = File.expand_path('../tmp/blocks-and-kwargs.txt', EXAMPLES_DIR)
44
52
  FileUtils.rm_f(path)
@@ -55,6 +63,10 @@ RSpec.describe 'examples' do
55
63
  expect(run_example('counter.kap')).to eq("12\n")
56
64
  end
57
65
 
66
+ it 'contains-duplicate.kap' do
67
+ expect(run_example('contains-duplicate.kap')).to eq("true\nfalse\ntrue\n")
68
+ end
69
+
58
70
  it 'doto.kap' do
59
71
  expect(run_example('doto.kap')).to eq("1, 2, 3\n")
60
72
  end
@@ -169,6 +181,18 @@ RSpec.describe 'examples' do
169
181
  expect(run_example('match.kap')).to eq("Ada: 9\nLin: no score\nunknown\n")
170
182
  end
171
183
 
184
+ it 'packet-router.kap' do
185
+ expect(run_example('packet-router.kap')).to eq("score:9\nother\ncity:nil\n5\n0\nping:7\n")
186
+ end
187
+
188
+ it 'or-patterns.kap' do
189
+ expect(run_example('or-patterns.kap')).to eq("1:2\n2:1\nother\n")
190
+ end
191
+
192
+ it 'underscore-patterns.kap' do
193
+ expect(run_example('underscore-patterns.kap')).to eq("5\nnil\n5\nfallback\n")
194
+ end
195
+
172
196
  it 'scopes.kap' do
173
197
  expect(run_example('scopes.kap')).to eq("5\n9\n9\n9\n")
174
198
  end
@@ -224,6 +248,10 @@ RSpec.describe 'examples' do
224
248
  it 'threading.kap' do
225
249
  expect(run_example('threading.kap')).to eq("[Ada Lovelace]!\t<Ada!>\tnil\tATSUPAK\tnil\n")
226
250
  end
251
+
252
+ it 'tic-tac-toe.kap' do
253
+ expect(run_example('tic-tac-toe.kap')).to eq("X\nO\nX\ndraw\n")
254
+ end
227
255
  end
228
256
 
229
257
  RSpec.describe Kapusta do
@@ -278,6 +306,6 @@ end
278
306
  RSpec.describe 'errors' do
279
307
  it 'raises on unclosed list' do
280
308
  expect { Kapusta.eval('(fn hello [name] (.. "Hi " name "!")') }
281
- .to raise_error(/unclosed \(/)
309
+ .to raise_error(Kapusta::Reader::Error, /unclosed \(/)
282
310
  end
283
311
  end
@@ -272,6 +272,26 @@ RSpec.describe Kapusta::Formatter do
272
272
  end
273
273
  end
274
274
 
275
+ it 'preserves nil-valued let bindings before function bindings' do
276
+ Dir.mktmpdir do |dir|
277
+ path = File.join(dir, 'sample.kap')
278
+ File.write(path, <<~KAP)
279
+ (let [name nil get-input (fn [] "Dave")]
280
+ (print (get-input)))
281
+ KAP
282
+
283
+ output = capture_stdout do
284
+ expect(described_class.new([path]).run).to eq(0)
285
+ end
286
+
287
+ expect(output).to eq(<<~KAP)
288
+ (let [name nil
289
+ get-input (fn [] "Dave")]
290
+ (print (get-input)))
291
+ KAP
292
+ end
293
+ end
294
+
275
295
  example_idempotence_paths.each do |relative_path|
276
296
  it "keeps #{relative_path} unchanged" do
277
297
  path = File.expand_path("../#{relative_path}", __dir__)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kapusta
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgenii Morozov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-23 00:00:00.000000000 Z
11
+ date: 2026-04-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Kapusta is a Lisp for the Ruby runtime.
14
14
  email:
@@ -27,10 +27,13 @@ files:
27
27
  - examples/accumulator.kap
28
28
  - examples/ackermann.kap
29
29
  - examples/anagram.kap
30
+ - examples/anonymous-greeter.kap
30
31
  - examples/binary-search.kap
32
+ - examples/binary-to-decimal.kap
31
33
  - examples/block-sort.kap
32
34
  - examples/blocks-and-kwargs.kap
33
35
  - examples/calc.kap
36
+ - examples/contains-duplicate.kap
34
37
  - examples/counter.kap
35
38
  - examples/describe.kap
36
39
  - examples/destructure.kap
@@ -51,6 +54,8 @@ files:
51
54
  - examples/match.kap
52
55
  - examples/min-max.kap
53
56
  - examples/module-header.kap
57
+ - examples/or-patterns.kap
58
+ - examples/packet-router.kap
54
59
  - examples/palindrome.kap
55
60
  - examples/pangram.kap
56
61
  - examples/pcall.kap
@@ -68,11 +73,12 @@ files:
68
73
  - examples/stack.kap
69
74
  - examples/sum.kap
70
75
  - examples/threading.kap
76
+ - examples/tic-tac-toe.kap
71
77
  - examples/tset.kap
72
78
  - examples/two-sum.kap
79
+ - examples/underscore-patterns.kap
73
80
  - exe/kapfmt
74
81
  - exe/kapusta
75
- - kapfmt
76
82
  - kapusta.gemspec
77
83
  - lib/kapusta.rb
78
84
  - lib/kapusta/ast.rb
@@ -89,6 +95,7 @@ files:
89
95
  - lib/kapusta/compiler/normalizer.rb
90
96
  - lib/kapusta/compiler/runtime.rb
91
97
  - lib/kapusta/env.rb
98
+ - lib/kapusta/error.rb
92
99
  - lib/kapusta/formatter.rb
93
100
  - lib/kapusta/reader.rb
94
101
  - lib/kapusta/support.rb
data/kapfmt DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- load File.expand_path('exe/kapfmt', __dir__)