gesso 0.2.1 → 0.2.2

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: 90c0643abc753048a4b7a6f6e053365f83e91245665d3e5005874421f16766fd
4
- data.tar.gz: 92d213ea481855e6ab3077a137c93a1674be5096ceb2c1b4fd891788b2ab1622
3
+ metadata.gz: 9d81b5d76a40f26f95761bf4d82b4d076022988982dcde7b10bd4d3e6e85e848
4
+ data.tar.gz: c05f94b79974fc4442cf47ff38fedbbac326670e1925bdf93bbed3d254e0ea50
5
5
  SHA512:
6
- metadata.gz: 982f5be756b4cd323db6c0d6c54768a58162abfac80da0a0445d88f172f2747ecb28ae89b887585300f736b644a78a86e08586f1adaf739f2c3c82cc933a483d
7
- data.tar.gz: bdda02c05630ba784127723db5f8657e3982ad16c2733e3cae779dd750ce3abd35eac55681d91680c3975ca4f6dd008be6e7a019063c113425bffab6bb24de76
6
+ metadata.gz: 978be319368cddce51892a03d1ccac2d1b7d8ebd78f34480941052862b50523f8be35961cb2449818ddb02a2e715d95d2bc09a6314c4245c222cdf7af2991178
7
+ data.tar.gz: dd0c2771359bdefbb72d520749c659e0f1e1ed8dfa323530e8fb3e2d3c39f944de09c256f22303956d898465e2f51df57b19a87d4e747d7de7fd3360f7cec1fa
data/.codespellignore ADDED
File without changes
data/.yamllint ADDED
@@ -0,0 +1,16 @@
1
+ extends: default
2
+ ignore: |
3
+ build/
4
+ node_modules/
5
+ runtime/build/
6
+ tmp/
7
+ **/*.dSYM/**
8
+
9
+ rules:
10
+ comments:
11
+ min-spaces-from-content: 1
12
+ document-start: disable
13
+ line-length:
14
+ max: 200
15
+ truthy:
16
+ check-keys: false
data/CHANGELOG.md CHANGED
@@ -1,10 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.2] - 2026-09-26
4
+
5
+ - Preserve existing GIF recordings when a sketch fails.
6
+ - Reject non-finite frame rates and color ranges.
7
+
3
8
  ## [0.2.1] - 2026-09-25
4
9
 
10
+ - Prevent Bundler from selecting unsupported major versions of runtime dependencies.
11
+
12
+ ## [0.2.0] - 2026-09-25
13
+
5
14
  - Run sketches in the browser with Webvas.
6
15
  - Record headless and window sketch frames as GIF with the optional Flipbook gem.
7
- - Constrain runtime dependencies to supported major versions.
8
16
 
9
17
  ## [0.1.0] - 2026-09-23
10
18
 
data/lib/gesso/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gesso
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.2"
5
5
  end
data/lib/gesso.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "tessel"
4
+ require "tempfile"
4
5
 
5
6
  require_relative "gesso/version"
6
7
 
@@ -122,7 +123,7 @@ module Gesso
122
123
  mode = mode.to_sym
123
124
  raise ArgumentError, "color mode must be :rgb or :hsb" unless %i[rgb hsb].include?(mode)
124
125
  ranges = [max1, max2, max3, max_alpha].map(&:to_f)
125
- raise ArgumentError, "color ranges must be positive" unless ranges.all?(&:positive?)
126
+ raise ArgumentError, "color ranges must be finite and positive" unless ranges.all? { |range| range.finite? && range.positive? }
126
127
  @color_mode = mode
127
128
  @color_ranges = ranges
128
129
  end
@@ -148,7 +149,7 @@ module Gesso
148
149
  def frame_rate(value = nil)
149
150
  return (@frame_rate || 60.0) unless value
150
151
  value = value.to_f
151
- raise ArgumentError, "frame rate must be positive" unless value.positive?
152
+ raise ArgumentError, "frame rate must be finite and positive" unless value.finite? && value.positive?
152
153
  @frame_rate = value
153
154
  end
154
155
  def millis = (@frame_count * 1000.0 / frame_rate).round
@@ -295,16 +296,32 @@ module Gesso
295
296
  rescue LoadError => error
296
297
  raise LoadError, "Gesso#save_gif requires the optional flipbook gem", cause: error
297
298
  end
298
- writer = Flipbook::GIF::Writer.open(path, width: @width, height: @height, loop:, palette: :per_frame)
299
- @gif_recorder = { writer:, remaining: frames, delay: Rational(1, rate.to_s) }
299
+ target = File.expand_path(path)
300
+ mode = File.exist?(target) ? File.stat(target).mode & 0o777 : 0o666 & ~File.umask
301
+ io = Tempfile.new(".gesso-", File.dirname(target))
302
+ io.binmode
303
+ writer = Flipbook::GIF::Writer.new(io, width: @width, height: @height, loop:, palette: :per_frame)
304
+ @gif_recorder = { writer:, io:, target:, mode:, remaining: frames, delay: Rational(1, rate.to_s) }
300
305
  path
306
+ rescue Exception
307
+ io&.close!
308
+ raise
301
309
  end
302
310
  def gif_frames_remaining = @gif_recorder&.fetch(:remaining)
303
311
 
304
- def close
312
+ def close(discard: false)
305
313
  recorder = @gif_recorder
306
314
  @gif_recorder = nil
307
- recorder&.fetch(:writer)&.close
315
+ return unless recorder
316
+ return recorder[:io].close! if discard
317
+
318
+ recorder[:writer].close
319
+ recorder[:io].close
320
+ File.chmod(recorder[:mode], recorder[:io].path)
321
+ File.rename(recorder[:io].path, recorder[:target])
322
+ rescue Exception
323
+ recorder&.fetch(:io)&.close!
324
+ raise
308
325
  end
309
326
  def get(x, y) = @canvas[x, y]
310
327
  def set(x, y, value) = @canvas[x, y] = value
@@ -489,9 +506,11 @@ module Gesso
489
506
  def self.run(sketch, frames: nil)
490
507
  sketch.prepare!
491
508
  frames ||= sketch.gif_frames_remaining || 1
492
- Array.new(frames) { sketch.frame.dup }
509
+ images = Array.new(frames) { sketch.frame.dup }
510
+ completed = true
511
+ images
493
512
  ensure
494
- sketch.close
513
+ sketch.close(discard: !completed)
495
514
  end
496
515
  end
497
516
 
@@ -508,9 +527,10 @@ module Gesso
508
527
  delay = 1.0 / sketch.frame_rate - (Process.clock_gettime(Process::CLOCK_MONOTONIC) - started)
509
528
  sleep(delay) if delay.positive? && backend.to_sym != :file
510
529
  end
530
+ completed = true
511
531
  ensure
512
532
  window&.close
513
- sketch.close
533
+ sketch.close(discard: !completed)
514
534
  end
515
535
  end
516
536
 
data/sig/gesso.rbs CHANGED
@@ -3,6 +3,6 @@ module Gesso
3
3
  class Sketch
4
4
  def save_gif: (String path, ?frames: Integer, ?fps: Numeric, ?loop: bool | Integer) -> String
5
5
  def gif_frames_remaining: () -> Integer?
6
- def close: () -> untyped
6
+ def close: (?discard: bool) -> untyped
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gesso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-25 00:00:00.000000000 Z
11
+ date: 2026-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tessel
@@ -118,6 +118,8 @@ executables:
118
118
  extensions: []
119
119
  extra_rdoc_files: []
120
120
  files:
121
+ - ".codespellignore"
122
+ - ".yamllint"
121
123
  - CHANGELOG.md
122
124
  - LICENSE.txt
123
125
  - README.md