inlay 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4c4e3fe710798287aba2920de80b5a321c2d89543256b9b6079eba08d93dc9e3
4
+ data.tar.gz: 1f3f0803affda38c5dc7c8c821f2cfdbe7d18846a184e317712a0477a3f2a9e7
5
+ SHA512:
6
+ metadata.gz: 926cf085ff8b9dcad417763adf7da3d8de669a134df5e5c218dacf42c4a242091a54693e81672dd33e38ef598c31fdffd679e45711c5c92e9341a094a8cab3fa
7
+ data.tar.gz: 8272ef2ad9566553b4562107c74617d09d22680d6c672897168d7521dd6779387a425cb1b051986fa63ddd961e4dd0137a589db2a067291b6eeb7a66abdae7c8
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-09-25
4
+
5
+ Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Yudai Takada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # Inlay
2
+
3
+ Render Ruby graphics where you inspect them. Inlay shows Tessel images, RBGL surfaces, and chart output in terminals, IRB, and Pry.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ gem install inlay
9
+ ```
10
+
11
+ Add `inlay` to your Gemfile. Inlay uses [Tessel](https://github.com/rbgfx/tessel) for images and [Termvas](https://github.com/rbgfx/termvas) for terminal output.
12
+
13
+ ## Use in IRB
14
+
15
+ Add this to `~/.irbrc`:
16
+
17
+ ```ruby
18
+ require "inlay/irb"
19
+ ```
20
+
21
+ Now returning an image from a prompt displays it inline and leaves a short summary as the result:
22
+
23
+ ```ruby
24
+ image = Tessel.read("brick.png").scale_nearest(64, 64)
25
+ image
26
+ ```
27
+
28
+ Pry uses the same integration style:
29
+
30
+ ```ruby
31
+ require "inlay/pry"
32
+ ```
33
+
34
+ Inlay uses the terminal protocol selected by Termvas: Kitty, iTerm2, Sixel, or true-color half blocks. Piped output, `TERM=dumb`, `INLAY=off`, and `NO_COLOR` with half blocks show only the summary.
35
+
36
+ ## Use in a script
37
+
38
+ ```ruby
39
+ require "inlay"
40
+
41
+ image = Tessel.read("brick.png")
42
+ Inlay.show(image, width: 40)
43
+ Inlay.config.max_rows = 30
44
+ ```
45
+
46
+ To install the short `inlay(value)` helper, require `inlay/kernel`. Explicit calls accept image paths; ordinary returned strings are never treated as paths.
47
+
48
+ Objects can implement `to_inlay` and return a `Tessel::Image`, `{ png: bytes }`, `{ svg: markup, png: -> { bytes } }`, or `{ frames: images, fps: number }`. Custom object types can also be registered:
49
+
50
+ ```ruby
51
+ Inlay.register(MySurface) { |surface| surface.to_tessel_image }
52
+ ```
53
+
54
+ ## Configuration
55
+
56
+ `Inlay.config.enabled` toggles terminal rendering. `max_rows` caps terminal height and `max_pixels` limits decoded and displayed input size. Small images (up to 32×32) are enlarged with nearest-neighbor scaling; larger images are reduced with alpha-aware area averaging. Set `INLAY=off` to disable terminal output for a process.
57
+
58
+ ## Development
59
+
60
+ ```sh
61
+ bundle install
62
+ bundle exec rake verify
63
+ ```
64
+
65
+ ## License
66
+
67
+ MIT
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task verify: :spec
9
+ task default: :verify
data/docs/spikes.md ADDED
@@ -0,0 +1,8 @@
1
+ # Integration spikes
2
+
3
+ - IRB 1.18's `IRB::Inspector` supports a streaming inspector that writes into IRB's result buffer. Inlay writes terminal escapes to `$stdout` separately and leaves a short summary in the buffer. IRB paging and assignment truncation therefore only see the summary. The supported minimum is IRB 1.13, the first version with the supported inspector API.
4
+ - `.irbrc` runs before the first prompt, so environment-based terminal detection can be cached at install time without competing with Reline input. Inlay does not issue device queries.
5
+ - Rails console uses IRB's configured inspector when initialized after `.irbrc`; re-running `Inlay.irb_install!` wraps a subsequently selected inspector. Rails itself is not part of the test dependency set.
6
+ - Pry's configured printer receives `(output, value, pry_instance)`; the adapter retains that printer and passes it the summary.
7
+ - IRuby's public display registry supports predicate matchers and dynamic MIME pairs. SVG is preferred; PNG and GIF-in-HTML are selected from the normalized return value.
8
+ - `@ruby/3.4-wasm-wasi` 2.10.1 / Ruby 3.4.1 with Larb and JS host bindings completed 3,600 simulated 60 fps callbacks in 61.95 seconds. With one stable JS trampoline and Ruby/JS GC every 600 frames, WASM memory changed from 71,499,776 to 71,565,312 bytes; JS heap grew 4,261,280 bytes. This validates the callback strategy under Node, not a browser or GPU workload.
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inlay
4
+ module Adapters
5
+ @adapters = {}
6
+
7
+ module_function
8
+
9
+ def register(klass, adapter)
10
+ raise TypeError, "adapter key must be a Class or Module" unless klass.is_a?(Module)
11
+
12
+ @adapters[klass] = adapter
13
+ end
14
+
15
+ def convert(object)
16
+ pair = @adapters.find { |klass, _| object.is_a?(klass) }
17
+ return pair.last.call(object) if pair
18
+
19
+ return object if defined?(Tessel::Image) && object.is_a?(Tessel::Image)
20
+
21
+ if defined?(RBGL::Engine::Framebuffer) && object.is_a?(RBGL::Engine::Framebuffer)
22
+ return Tessel::Image.from_rgba(object.width, object.height, object.to_rgba_bytes)
23
+ end
24
+
25
+ if defined?(RBGL::Engine::Texture) && object.is_a?(RBGL::Engine::Texture)
26
+ bytes = object.data.flat_map { |color| [color.r, color.g, color.b, color.a] }.pack("C*")
27
+ return Tessel::Image.from_rgba(object.width, object.height, bytes)
28
+ end
29
+
30
+ if defined?(Inkplot::Chart) && object.is_a?(Inkplot::Chart)
31
+ return object.to_inlay
32
+ end
33
+
34
+ nil
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inlay
4
+ class Config
5
+ attr_accessor :enabled
6
+ attr_reader :max_rows, :max_pixels
7
+
8
+ def initialize
9
+ @enabled = true
10
+ @max_rows = 24
11
+ @max_pixels = 1_048_576
12
+ end
13
+
14
+ def max_rows=(value)
15
+ @max_rows = positive_integer(value, :max_rows)
16
+ end
17
+
18
+ def max_pixels=(value)
19
+ @max_pixels = positive_integer(value, :max_pixels)
20
+ end
21
+
22
+ private
23
+
24
+ def positive_integer(value, name)
25
+ number = Integer(value)
26
+ raise ArgumentError, "#{name} must be positive" unless number.positive?
27
+
28
+ number
29
+ rescue ArgumentError, TypeError
30
+ raise ArgumentError, "#{name} must be a positive integer"
31
+ end
32
+ end
33
+ end
data/lib/inlay/irb.rb ADDED
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "inlay"
4
+ require "irb"
5
+ require "irb/inspector"
6
+
7
+ module Inlay
8
+ module IRBIntegration
9
+ class << self
10
+ attr_reader :original, :wrapper
11
+
12
+ def install
13
+ mode = IRB.conf[:INSPECT_MODE]
14
+ selected = mode.is_a?(IRB::Inspector) ? mode : IRB::Inspector::INSPECTORS[mode] || IRB::Inspector::INSPECTORS[mode.to_s] || IRB::Inspector::INSPECTORS[:p]
15
+ return false unless selected
16
+
17
+ @original = selected unless mode.equal?(@wrapper)
18
+ @protocol = TerminalOutput.protocol
19
+ @wrapper = IRB::Inspector.new(proc do |value, output, colorize: true|
20
+ begin
21
+ if Inlay.displayable?(value)
22
+ output << Inlay.show(value, protocol: @protocol)
23
+ else
24
+ @original.inspect_value(value, output, colorize: colorize)
25
+ end
26
+ rescue StandardError
27
+ @original.inspect_value(value, output, colorize: colorize)
28
+ end
29
+ end)
30
+ IRB.conf[:INSPECT_MODE] = @wrapper
31
+ context = IRB.CurrentContext if IRB.respond_to?(:CurrentContext)
32
+ context.inspect_mode = @wrapper if context&.respond_to?(:inspect_mode=)
33
+ true
34
+ end
35
+
36
+ def uninstall
37
+ return false unless @wrapper && IRB.conf[:INSPECT_MODE].equal?(@wrapper)
38
+
39
+ IRB.conf[:INSPECT_MODE] = @original
40
+ context = IRB.CurrentContext if IRB.respond_to?(:CurrentContext)
41
+ context.inspect_mode = @original if context&.respond_to?(:inspect_mode=)
42
+ @wrapper = @original = @protocol = nil
43
+ true
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ Inlay::IRBIntegration.install
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "inlay"
4
+
5
+ module Kernel
6
+ private
7
+
8
+ def inlay(object, **options)
9
+ Inlay.show(object, **options)
10
+ end
11
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inlay
4
+ Normalized = Struct.new(:image, :svg, :png, :frames, :fps, keyword_init: true)
5
+
6
+ module Normalizer
7
+ module_function
8
+
9
+ def call(object, allow_path: false, seen: {})
10
+ raise Error, "recursive to_inlay result" if seen[object.object_id]
11
+
12
+ converted = Adapters.convert(object)
13
+ return Normalized.new(image: converted) if converted.is_a?(Tessel::Image)
14
+ return from_value(converted, allow_path: allow_path, seen: seen) unless converted.nil?
15
+
16
+ return from_value(object.to_inlay, allow_path: allow_path, seen: seen.merge(object.object_id => true)) if object.respond_to?(:to_inlay)
17
+ return from_value(object, allow_path: allow_path, seen: seen) if object.is_a?(Hash)
18
+ return from_path(object) if allow_path && path_value?(object)
19
+
20
+ Normalized.new
21
+ end
22
+
23
+ def terminal_image(normalized)
24
+ return normalized.image if normalized.image
25
+ return Tessel.decode(normalized.png, max_pixels: Inlay.config.max_pixels) if normalized.png.is_a?(String)
26
+ if normalized.png.respond_to?(:call)
27
+ value = normalized.png.call
28
+ return value if value.is_a?(Tessel::Image)
29
+ return Tessel.decode(value, max_pixels: Inlay.config.max_pixels) if value.is_a?(String)
30
+ return call(value).image
31
+ end
32
+ return call(normalized.frames.first).image if normalized.frames&.any?
33
+
34
+ nil
35
+ end
36
+
37
+ def from_value(value, allow_path:, seen:)
38
+ raise Error, "recursive to_inlay result" if seen[value.object_id]
39
+ return Normalized.new(image: value) if value.is_a?(Tessel::Image)
40
+ return from_path(value) if allow_path && path_value?(value)
41
+ return Normalized.new unless value.is_a?(Hash)
42
+
43
+ data = value.each_with_object({}) { |(key, item), result| result[key.to_sym] = item if key.respond_to?(:to_sym) }
44
+ if data[:frames]
45
+ frames = Array(data[:frames])
46
+ raise ArgumentError, "frames must not be empty" if frames.empty?
47
+ raise TypeError, "frames must contain Tessel::Image values" unless frames.all? { |frame| frame.is_a?(Tessel::Image) }
48
+ raise TypeError, "fps must be a positive number" unless data[:fps].is_a?(Numeric) && data[:fps].positive?
49
+
50
+ return Normalized.new(frames: frames, fps: data[:fps])
51
+ end
52
+ raise TypeError, "png must be bytes or a callable" if data[:png] && !data[:png].is_a?(String) && !data[:png].respond_to?(:call)
53
+ raise TypeError, "svg must be a String" if data[:svg] && !data[:svg].is_a?(String)
54
+
55
+ Normalized.new(svg: data[:svg], png: data[:png])
56
+ end
57
+ private_class_method :from_value
58
+
59
+ def from_path(value)
60
+ bytes = value.is_a?(Pathname) ? File.binread(value) : String(value)
61
+ Normalized.new(image: Tessel.decode(bytes, max_pixels: Inlay.config.max_pixels))
62
+ end
63
+ private_class_method :from_path
64
+
65
+ def path_value?(value)
66
+ value.is_a?(Pathname) || (value.is_a?(String) && IMAGE_EXTENSIONS.include?(File.extname(value).downcase) && File.file?(value))
67
+ end
68
+ IMAGE_EXTENSIONS = %w[.png .ppm .pnm .bmp].freeze
69
+ private_class_method :path_value?
70
+ end
71
+ end
data/lib/inlay/pry.rb ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "inlay"
4
+ require "pry"
5
+
6
+ module Inlay
7
+ module PryIntegration
8
+ class << self
9
+ attr_reader :original, :wrapper
10
+
11
+ def install
12
+ return true if Pry.config.print.equal?(@wrapper)
13
+
14
+ @original = Pry.config.print
15
+ @wrapper = proc do |output, value, pry_instance|
16
+ begin
17
+ value = Inlay.show(value) if Inlay.displayable?(value)
18
+ rescue StandardError
19
+ # Preserve Pry's configured printer if image rendering fails.
20
+ end
21
+ @original.call(output, value, pry_instance)
22
+ end
23
+ Pry.config.print = @wrapper
24
+ true
25
+ end
26
+
27
+ def uninstall
28
+ return false unless @wrapper && Pry.config.print.equal?(@wrapper)
29
+
30
+ Pry.config.print = @original
31
+ @wrapper = @original = nil
32
+ true
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ Inlay::PryIntegration.install
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inlay
4
+ module Sizer
5
+ module_function
6
+
7
+ def fit(image, width: nil, height: nil, scale: :auto, columns: nil, rows: nil)
8
+ raise TypeError, "expected a Tessel::Image" unless image.is_a?(Tessel::Image)
9
+ raise ArgumentError, "unknown scale mode: #{scale}" unless %i[auto fit pixel none].include?(scale)
10
+ return image if image.width.zero? || image.height.zero?
11
+
12
+ columns ||= width || Termvas::Terminal.new(alt_screen: false).size[0]
13
+ width = [Integer(width || columns), Integer(columns)].min
14
+ height = [Integer(height || Inlay.config.max_rows * 2), Inlay.config.max_rows * 2].min
15
+ raise ArgumentError, "display dimensions must be positive" unless width.positive? && height.positive?
16
+ pixel_scale = scale == :pixel || (scale == :auto && image.width <= 32 && image.height <= 32)
17
+ max_factor = [width / [image.width, 1].max, height / [image.height, 1].max].min
18
+ if pixel_scale && max_factor > 1
19
+ return image.scale_nearest(image.width * max_factor, image.height * max_factor)
20
+ end
21
+ return image if image.width <= width && image.height <= height
22
+
23
+ factor = [width.to_f / image.width, height.to_f / image.height, 1.0].min
24
+ resize_area(image, [(image.width * factor).floor, 1].max, [(image.height * factor).floor, 1].max)
25
+ end
26
+
27
+ def resize_area(image, width, height)
28
+ bytes = image.bytes
29
+ output = String.new(capacity: width * height * 4, encoding: Encoding::BINARY)
30
+ height.times do |y|
31
+ top = y * image.height.to_f / height
32
+ bottom = (y + 1) * image.height.to_f / height
33
+ width.times do |x|
34
+ left = x * image.width.to_f / width
35
+ right = (x + 1) * image.width.to_f / width
36
+ alpha = red = green = blue = area = 0.0
37
+ (top.floor...bottom.ceil).each do |source_y|
38
+ weight_y = [bottom, source_y + 1].min - [top, source_y].max
39
+ (left.floor...right.ceil).each do |source_x|
40
+ weight = weight_y * ([right, source_x + 1].min - [left, source_x].max)
41
+ offset = (source_y * image.width + source_x) * 4
42
+ a = bytes.getbyte(offset + 3)
43
+ area += weight
44
+ alpha += a * weight
45
+ red += bytes.getbyte(offset) * a * weight
46
+ green += bytes.getbyte(offset + 1) * a * weight
47
+ blue += bytes.getbyte(offset + 2) * a * weight
48
+ end
49
+ end
50
+ output << (alpha.zero? ? 0 : (red / alpha).round)
51
+ output << (alpha.zero? ? 0 : (green / alpha).round)
52
+ output << (alpha.zero? ? 0 : (blue / alpha).round)
53
+ output << (alpha / area).round
54
+ end
55
+ end
56
+ Tessel::Image.from_rgba(width, height, output)
57
+ end
58
+ private_class_method :resize_area
59
+ end
60
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inlay
4
+ module Summary
5
+ module_function
6
+
7
+ def call(object, normalized)
8
+ image = normalized.image || (normalized.frames&.first if normalized.frames)
9
+ dimensions = image ? " #{image.width}x#{image.height}" : ""
10
+ name = case object
11
+ when Tessel::Image then "Tessel::Image"
12
+ else object.class.name || object.class.to_s
13
+ end
14
+ frames = normalized.frames ? " frames=#{normalized.frames.length}" : ""
15
+ "#<#{name}#{dimensions}#{frames}>"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inlay
4
+ module TerminalOutput
5
+ module_function
6
+
7
+ def protocol(output: $stdout, env: ENV)
8
+ return :none unless Inlay.config.enabled
9
+ return :none unless output.tty?
10
+ return :none unless env["INLAY"] != "off"
11
+ return :none if env["TERM"] == "dumb"
12
+
13
+ selected = Termvas::Detector.protocol(env)
14
+ return :none if selected == :blocks && env.key?("NO_COLOR")
15
+
16
+ selected
17
+ end
18
+
19
+ def write(image, width: nil, height: nil, scale: :auto, protocol: nil, output: $stdout, env: ENV)
20
+ selected = (protocol || self.protocol(output: output, env: env)).to_sym
21
+ return false unless Inlay.config.enabled && output.tty? && selected != :none
22
+ return false if selected == :blocks && env.key?("NO_COLOR")
23
+ return false if image.width * image.height > Inlay.config.max_pixels
24
+
25
+ image = Sizer.fit(image, width: width, height: height, scale: scale)
26
+ bytes = image.bytes
27
+ encoded = case selected.to_sym
28
+ when :blocks then Termvas::Encoders::Blocks.encode(bytes, image.width, image.height)
29
+ when :kitty then Termvas::Encoders::Kitty.encode(bytes, image.width, image.height, id: next_kitty_id)
30
+ when :iterm2
31
+ png = Tessel::PNG.encode(image)
32
+ Termvas::Encoders::ITerm2.encode(png, width: image.width, height: image.height)
33
+ when :sixel then Termvas::Encoders::Sixel.encode(bytes, image.width, image.height)
34
+ else return false
35
+ end
36
+ output.write(encoded)
37
+ output.write("\n")
38
+ true
39
+ end
40
+
41
+ def next_kitty_id
42
+ @kitty_id_lock ||= Mutex.new
43
+ @kitty_id_lock.synchronize { @kitty_id = (@kitty_id.to_i % 2_147_483_647) + 1 }
44
+ end
45
+ private_class_method :next_kitty_id
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Inlay
4
+ VERSION = "0.1.0"
5
+ end
data/lib/inlay.rb ADDED
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tessel"
4
+ require "termvas"
5
+ require "pathname"
6
+ require_relative "inlay/version"
7
+ require_relative "inlay/config"
8
+ require_relative "inlay/adapters"
9
+ require_relative "inlay/normalizer"
10
+ require_relative "inlay/sizer"
11
+ require_relative "inlay/summary"
12
+ require_relative "inlay/terminal_output"
13
+
14
+ module Inlay
15
+ class Error < StandardError; end
16
+
17
+ class << self
18
+ def config
19
+ @config ||= Config.new
20
+ end
21
+
22
+ def register(klass, &adapter)
23
+ raise ArgumentError, "an adapter block is required" unless adapter
24
+
25
+ Adapters.register(klass, adapter)
26
+ end
27
+
28
+ def normalize(object, allow_path: false)
29
+ Normalizer.call(object, allow_path: allow_path)
30
+ end
31
+
32
+ def displayable?(object)
33
+ normalized = normalize(object)
34
+ !!(normalized.image || normalized.svg || normalized.png || normalized.frames)
35
+ rescue StandardError
36
+ false
37
+ end
38
+
39
+ def protocol
40
+ TerminalOutput.protocol
41
+ end
42
+
43
+ def irb_install!
44
+ require_relative "inlay/irb"
45
+ IRBIntegration.install
46
+ end
47
+
48
+ def irb_uninstall!
49
+ IRBIntegration.uninstall if defined?(IRBIntegration)
50
+ end
51
+
52
+ def show(object, width: nil, height: nil, scale: :auto, protocol: nil)
53
+ normalized = normalize(object, allow_path: true)
54
+ image = Normalizer.terminal_image(normalized)
55
+ normalized.image ||= image
56
+ summary = Summary.call(object, normalized)
57
+ return summary unless image && TerminalOutput.write(image, width: width, height: height, scale: scale, protocol: protocol)
58
+
59
+ summary
60
+ end
61
+ end
62
+ end
data/sig/inlay.rbs ADDED
@@ -0,0 +1,32 @@
1
+ module Inlay
2
+ class Error < StandardError
3
+ end
4
+
5
+ class Config
6
+ attr_accessor enabled: bool
7
+ attr_accessor max_rows: Integer
8
+ attr_accessor max_pixels: Integer
9
+ end
10
+
11
+ class Normalized
12
+ attr_accessor image: untyped
13
+ attr_accessor svg: String?
14
+ attr_accessor png: untyped
15
+ attr_accessor frames: Array[untyped]?
16
+ attr_accessor fps: Numeric?
17
+ end
18
+
19
+ def self.config: () -> Config
20
+ def self.register: (Module klass) { (untyped object) -> untyped } -> Module
21
+ def self.normalize: (untyped object, ?allow_path: bool) -> Normalized
22
+ def self.displayable?: (untyped object) -> bool
23
+ def self.protocol: () -> Symbol
24
+ def self.show: (untyped object, ?width: Integer?, ?height: Integer?, ?scale: Symbol, ?protocol: Symbol?) -> String
25
+ def self.irb_install!: () -> bool
26
+ def self.irb_uninstall!: () -> (bool | nil)
27
+ end
28
+
29
+ module Kernel
30
+ private
31
+ def inlay: (untyped object, **untyped options) -> String
32
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inlay
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yudai Takada
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: tessel
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 0.2.0
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: 0.2.0
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '1'
32
+ - !ruby/object:Gem::Dependency
33
+ name: termvas
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: 0.2.0
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '1'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 0.2.0
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '1'
52
+ - !ruby/object:Gem::Dependency
53
+ name: base64
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ type: :runtime
60
+ prerelease: false
61
+ version_requirements: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ - !ruby/object:Gem::Dependency
67
+ name: irb
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '1.13'
73
+ type: :development
74
+ prerelease: false
75
+ version_requirements: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '1.13'
80
+ - !ruby/object:Gem::Dependency
81
+ name: pry
82
+ requirement: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '3.0'
101
+ type: :development
102
+ prerelease: false
103
+ version_requirements: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - "~>"
106
+ - !ruby/object:Gem::Version
107
+ version: '3.0'
108
+ description: Render Tessel images and graphics buffers in terminals, IRB, and Pry.
109
+ email:
110
+ - t.yudai92@gmail.com
111
+ executables: []
112
+ extensions: []
113
+ extra_rdoc_files: []
114
+ files:
115
+ - CHANGELOG.md
116
+ - LICENSE.txt
117
+ - README.md
118
+ - Rakefile
119
+ - docs/spikes.md
120
+ - lib/inlay.rb
121
+ - lib/inlay/adapters.rb
122
+ - lib/inlay/config.rb
123
+ - lib/inlay/irb.rb
124
+ - lib/inlay/kernel.rb
125
+ - lib/inlay/normalizer.rb
126
+ - lib/inlay/pry.rb
127
+ - lib/inlay/sizer.rb
128
+ - lib/inlay/summary.rb
129
+ - lib/inlay/terminal_output.rb
130
+ - lib/inlay/version.rb
131
+ - sig/inlay.rbs
132
+ homepage: https://github.com/rbgfx/inlay
133
+ licenses:
134
+ - MIT
135
+ metadata:
136
+ homepage_uri: https://github.com/rbgfx/inlay
137
+ source_code_uri: https://github.com/rbgfx/inlay/tree/main
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 3.2.0
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubygems_version: 4.0.16
153
+ specification_version: 4
154
+ summary: Display Ruby graphics in terminals and REPLs
155
+ test_files: []