Class: LittleGhost::Artifact

Inherits:
Object
  • Object
show all
Defined in:
lib/little_ghost/artifact.rb

Overview

Represents a file, image, or document produced by a Tool or supplied to a Run. LittleGhost sends supported media to the model once and may store the same bytes for filesystem Tools. Inline artifacts contain their bytes. Deferred artifacts contain an application-defined reference that the block passed to Configuration#artifacts may use to load the bytes.

image = LittleGhost::Artifact.new(
data: File.binread("chart.png"),
media_type: "image/png",
name: "chart.png"
)

download = LittleGhost::Artifact.deferred(
reference: {file_id: "file-481"},
media_type: "application/pdf",
name: "report.pdf"
)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data:, media_type:, name: nil, metadata: {}) ⇒ Artifact

Creates an inline artifact from binary data and a MIME media_type.



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/little_ghost/artifact.rb', line 23

def initialize(data:, media_type:, name: nil, metadata: {})
  data = String(data).b
  initialize_fields(
    data: data.freeze,
    reference: nil,
    media_type:,
    name:,
    bytes: data.bytesize,
    metadata:
  )
rescue TypeError
  raise ArgumentError, "artifact data must be a string"
end

Instance Attribute Details

#bytesObject (readonly)

Known byte count, otherwise nil for an unresolved artifact.



66
67
68
# File 'lib/little_ghost/artifact.rb', line 66

def bytes
  @bytes
end

#dataObject (readonly)

Binary content for an inline artifact, otherwise nil.



57
58
59
# File 'lib/little_ghost/artifact.rb', line 57

def data
  @data
end

#media_typeObject (readonly)

MIME media type used to present the artifact.



64
65
66
# File 'lib/little_ghost/artifact.rb', line 64

def media_type
  @media_type
end

#metadataObject (readonly)

Deeply frozen application metadata.



68
69
70
# File 'lib/little_ghost/artifact.rb', line 68

def 
  @metadata
end

#nameObject (readonly)

Optional display filename.



62
63
64
# File 'lib/little_ghost/artifact.rb', line 62

def name
  @name
end

#referenceObject (readonly)

Application-defined deferred reference, or generated Workspace reference after storage; otherwise nil.



60
61
62
# File 'lib/little_ghost/artifact.rb', line 60

def reference
  @reference
end

Class Method Details

.deferred(reference:, media_type:, name: nil, metadata: {}) ⇒ Object

Creates an artifact whose bytes may be loaded later by the block passed to Configuration#artifacts.

Raises:

  • (ArgumentError)


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/little_ghost/artifact.rb', line 39

def self.deferred(reference:, media_type:, name: nil, metadata: {})
  raise ArgumentError, "artifact reference is required" if reference.nil?
  reference = immutable_reference(reference)

  allocate.tap do |artifact|
    artifact.__send__(
      :initialize_fields,
      data: nil,
      reference:,
      media_type:,
      name:,
      bytes: nil,
      metadata:
    )
  end
end

.materialized(reference:, bytes:, media_type:, name: nil, metadata: {}) ⇒ Object

:nodoc:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/little_ghost/artifact.rb', line 101

def materialized(reference:, bytes:, media_type:, name: nil, metadata: {}) # :nodoc:
  reference = String(reference)
  bytes = Integer(bytes)
  raise ArgumentError, "artifact reference is required" if reference.empty?
  raise ArgumentError, "artifact bytes must not be negative" if bytes.negative?

  allocate.tap do |artifact|
    artifact.__send__(
      :initialize_fields,
      data: nil,
      reference: reference.freeze,
      media_type:,
      name:,
      bytes:,
      metadata:
    )
  end
rescue TypeError
  raise ArgumentError, "materialized artifact fields are invalid"
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Compares all immutable artifact fields.



77
78
79
80
81
# File 'lib/little_ghost/artifact.rb', line 77

def ==(other)
  other.instance_of?(self.class) &&
    [data, reference, name, media_type, bytes, ] ==
      [other.data, other.reference, other.name, other.media_type, other.bytes, other.]
end

#deferred?Boolean

Whether this artifact requires an application resolver.

Returns:

  • (Boolean)


74
# File 'lib/little_ghost/artifact.rb', line 74

def deferred? = !reference.nil? && bytes.nil?

#hashObject

Computes a Hash key from all immutable artifact fields.



86
# File 'lib/little_ghost/artifact.rb', line 86

def hash = [self.class, data, reference, name, media_type, bytes, ].hash

#inline?Boolean

Whether this artifact contains its bytes directly.

Returns:

  • (Boolean)


71
# File 'lib/little_ghost/artifact.rb', line 71

def inline? = !data.nil?

#inspectObject

Avoids placing bytes, names, metadata, or deferred references in diagnostics.



89
90
91
92
93
94
95
96
97
98
# File 'lib/little_ghost/artifact.rb', line 89

def inspect
  kind = if inline?
    "inline"
  elsif deferred?
    "deferred"
  else
    "stored"
  end
  "#<#{self.class} kind=#{kind.inspect} media_type=#{media_type.inspect} bytes=#{bytes.inspect}>"
end