Class: X::UploadedMedia

Inherits:
Object
  • Object
show all
Defined in:
x-uploader/lib/x/uploader/uploaded_media.rb

Overview

Media that was uploaded: the response of an upload, or the status of its processing

Both hold the identifier and the media key, and the status of media that X processes, such as a video, holds the state of its processing. The object is frozen, and reads as the Hash it was built from with [], fetch, dig, key?, and to_json, so media works as it did when an upload returned a Hash.

The attributes hold the response as it arrived, so media is the String X sent, and the media writes itself as JSON with the identifier a String, which a reader of JSON that holds numbers as floats reads whole. The identifier is read as an Integer by id alone, as a resource of the object layer reads its own.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs) ⇒ UploadedMedia

Initialize uploaded media

The media must hold its identifier under the String key "id", as every upload and status response does, so that the media can be attached to a post, and #id raises for none.

Examples:

Refer to media that was uploaded before

X::UploadedMedia.new({"id" => "1880028106020515840"})

Parameters:

  • attrs (Hash{String => Object}) —

    the data of an upload or status response

Raises:

  • (ArgumentError) —

    if the attributes are not a Hash, or hold no "id" that is a media ID the API takes: an Integer that is not negative, or a String of digits alone, of 1 to 19 digits



57
58
59
60
61
62
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 57

def initialize(attrs)
  @attrs = deep_freeze(Hash.try_convert(attrs) || raise(ArgumentError, "attrs must be a Hash, not #{attrs.inspect}"))
  raise ArgumentError, format(NO_MEDIA_ID, self["id"].inspect) unless media_id?(self["id"])

  freeze
end

Instance Attribute Details

#attrs ⇒ Hash{String => Object} (readonly) Also known as: to_h

The response data the media was built from

Examples:

Get the attributes

media.attrs # => {"id" => "1880028106020515840", "media_key" => "3_1880028106020515840", ...}

Returns:

  • (Hash{String => Object}) —

    the frozen attributes



42
43
44
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 42

def attrs
  @attrs
end

Instance Method Details

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

Check whether another object is the same uploaded media

Examples:

Compare media

media == X::UploadedMedia.new(media.to_h) # => true

Parameters:

  • other (Object) —

    the object to compare

Returns:

  • (Boolean) —

    true if the other object is uploaded media with the same attributes



245
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 245

def ==(other) = other.instance_of?(self.class) && attrs.eql?(other.attrs)

#[](key) ⇒ Object?

Read an attribute of the response, as from the Hash an upload used to return

Examples:

Get the identifier

media["id"] # => "1880028106020515840"

Parameters:

  • key (String) —

    the name of the attribute

Returns:

  • (Object, nil) —

    the value, or nil if the response holds none



184
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 184

def [](key) = attrs[key]

#as_json ⇒ Hash{String => Object}

The attributes of the response, as an encoder asks of an object of its own

Examples:

Store the response of an upload beside a record of it

record.update(upload: media.as_json)

Returns:

  • (Hash{String => Object}) —

    the frozen attributes



225
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 225

def as_json(*) = attrs

#bytesize ⇒ Integer?

The size of the media in bytes

Examples:

Get the size

media.bytesize # => 1048576

Returns:

  • (Integer, nil) —

    the size, if the response reports it



106
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 106

def bytesize = self["size"]

#check_after_secs ⇒ Integer?

The seconds X asks to wait before checking the processing again

Examples:

Get the wait

media.check_after_secs # => 5

Returns:

  • (Integer, nil) —

    the seconds, if X asks for a wait



142
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 142

def check_after_secs = dig("processing_info", "check_after_secs")

#dig(*keys) ⇒ Object?

Read a nested attribute of the response

Examples:

Get the state of the processing

media.dig("processing_info", "state") # => "succeeded"

Parameters:

  • keys (Array<String, Integer>) —

    the names that lead to the attribute

Returns:

  • (Object, nil) —

    the value, or nil if the response holds none



208
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 208

def dig(*keys) = attrs.dig(*keys)

#encode_with(coder) ⇒ void

This method returns an undefined value.

Write the state Marshal writes as YAML

YAML would write the instance variables of the media, and read them back into one that is not frozen, so it says how it is written: each part of the state Marshal writes, under its name.

Examples:

Write media as YAML

YAML.dump(client.upload_media("image.png"))

Parameters:

  • coder (Psych::Coder) —

    the coder YAML writes the media with



301
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 301

def encode_with(coder) = YAML_KEYS.zip(marshal_dump) { |key, value| coder[key] = value }

#expires_after_secs ⇒ Integer?

The seconds after the response within which the media can be attached to a post

X counts them from when it sent the response, which the media does not hold, so they are read as X reported them: media rebuilt from its attributes later, as from JSON it was stored as, holds the seconds of the response it was built from, not those it has left.

Examples:

Get the time after which media just uploaded can no longer be attached

Time.now + media.expires_after_secs # => 2026-09-19 12:00:00 -0700

Returns:

  • (Integer, nil) —

    the seconds, if the response reports them



118
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 118

def expires_after_secs = self["expires_after_secs"]

#failed? ⇒ Boolean

Check whether the processing of the media failed

Examples:

Check whether a video failed to process

media.failed?

Returns:

  • (Boolean) —

    true if the processing failed



162
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 162

def failed? = state.eql?("failed")

#fetch(key, *default) {|key| ... } ⇒ Object

Fetch an attribute of the response, as from the Hash an upload used to return

Examples:

Fetch the identifier

media.fetch("id") # => "1880028106020515840"

Fetch what a response may hold none of

media.fetch("processing_info", nil)

Parameters:

  • key (String) —

    the name of the attribute

  • default (Array<Object>) —

    the value to return for an attribute the response does not hold, if any

Yield Parameters:

  • key (String) —

    the name of an attribute the response does not hold

Yield Returns:

  • (Object) —

    the value to return in its place

Returns:

  • (Object) —

    the value

Raises:

  • (KeyError) —

    if the response holds no such attribute and neither a default nor a block is given



199
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 199

def fetch(key, *default, &) = attrs.fetch(key, *default, &) # steep:ignore UnresolvedOverloading

#hash ⇒ Integer

The hash code of the media, which equal media share

Examples:

Count the media uploaded

uploads.uniq.size

Returns:

  • (Integer) —

    the hash code



254
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 254

def hash = [self.class, attrs].hash

#id ⇒ Integer

The numeric media ID, which a post attaches the media by

It is the media ID the upload endpoints and a new post take, which #media_id reads too. The X::Media of x-objects, the media of a post as the object layer reads it, is identified by its media key instead, so its id is the media key, which #media_key reads here; both classes answer media_id and media_key alike.

It is read as strictly as x-objects reads an identifier: an Integer as it is, and a String of digits alone, with no sign, underscore, or whitespace, as a decimal number, so that " 1_0 " is no identifier, rather than 10.

Examples:

Get the media ID

media.id # => 1880028106020515840

Returns:

  • (Integer) —

    the media ID, whether the response held it as a String or an Integer



77
78
79
80
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 77

def id
  value = fetch("id")
  value.instance_of?(Integer) ? value : Integer(value, 10)
end

#init_with(coder) ⇒ void

This method returns an undefined value.

Restore media YAML read, frozen, as Marshal restores one

Examples:

Read media written as YAML

YAML.unsafe_load(YAML.dump(media)).media_key

Parameters:

  • coder (Psych::Coder) —

    the coder YAML read the media with

Raises:



311
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 311

def init_with(coder) = marshal_load(coder.map.values_at(*YAML_KEYS))

#inspect ⇒ String

Summarize the media for the console

Examples:

Inspect media

media.inspect # => #<X::UploadedMedia id=1880028106020515840 media_key="3_1880028106020515840" state=nil>

Returns:

  • (String) —

    the class name, identifier, media key, and state



262
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 262

def inspect = "#<#{self.class} id=#{id} media_key=#{media_key.inspect} state=#{state.inspect}>"

#key?(key) ⇒ Boolean

Check whether the response holds an attribute

Examples:

Check whether X processes the media

media.key?("processing_info")

Parameters:

  • key (String) —

    the name of the attribute

Returns:

  • (Boolean) —

    true if the response holds the attribute, whatever its value



217
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 217

def key?(key) = attrs.key?(key)

#marshal_dump ⇒ Array(Integer, Hash{String => Object})

The state Marshal writes

What is written is plain data, led by the number of its format, so that media written by one release of 1.x is read by a later one: its attributes, as the response held them.

Examples:

Cache what an upload returned, to attach it later

Rails.cache.write("upload", client.upload_media("image.png"))

Returns:

  • (Array(Integer, Hash{String => Object})) —

    the number of the format, then the attributes



273
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 273

def marshal_dump = [MARSHAL_FORMAT, attrs]

#marshal_load(state) ⇒ void

This method returns an undefined value.

Restore media Marshal read, built as the constructor builds it, deep-frozen

Examples:

Read what an upload returned from a cache

Marshal.load(Marshal.dump(media)).media_key

Parameters:

  • state (Array) —

    the state Marshal wrote

Raises:

  • (UnsupportedMarshalFormat) —

    if the state is of a format this release does not read

  • (ArgumentError) —

    if the attributes of the state are not a Hash, or hold no "id" of the media



284
285
286
287
288
289
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 284

def marshal_load(state)
  format, attrs = state
  raise UnsupportedMarshalFormat, "#{self.class} reads format #{MARSHAL_FORMAT} of Marshal, not #{format.inspect}" unless MARSHAL_FORMAT.eql?(format)

  initialize(attrs)
end

#media_id ⇒ Integer

The numeric media ID, as the X::Media of x-objects names it

It is the same as #id, under the name that reads the same on uploaded media and on the media of a post.

Examples:

Get the media ID

media.media_id # => 1880028106020515840

Returns:

  • (Integer) —

    the media ID, whether the response held it as a String or an Integer



90
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 90

def media_id = id

#media_key ⇒ String?

The media key, which names the type of the media and its media ID

Examples:

Get the media key

media.media_key # => "3_1880028106020515840"

Returns:

  • (String, nil) —

    the media key, if the response holds one



98
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 98

def media_key = self["media_key"]

#processing? ⇒ Boolean

Check whether X is still processing the media

Media is still processing in the states X asks to be checked again in, pending and in_progress, alone. Media whose processing information names no state, or a state X does not document, is not, since X gives no time to check it again at, and it is not ready either.

Examples:

Check whether a video is still processing

media.processing?

Returns:

  • (Boolean) —

    true if the processing of the media is pending or in progress



154
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 154

def processing? = PROCESSING_STATES.include?(state)

#processing_info ⇒ Hash{String => Object}?

What X reports of the processing of the media

Examples:

Get the error of media that failed to process

media.processing_info&.dig("error", "message")

Returns:

  • (Hash{String => Object}, nil) —

    the processing information, or nil for media X does not process



126
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 126

def processing_info = self["processing_info"]

#ready? ⇒ Boolean

Check whether the media can be attached to a post

Media whose processing information names no state, or a state X does not document, is not ready, since X has not said that its processing succeeded. Neither is media that holds its identifier and media key alone, as media built from an identifier does, such as the media add_alt_text returns for one, since it holds no response of X to say whether X processes it; await_media_processing checks it.

Examples:

Check whether a video can be posted

media.ready?

Returns:

  • (Boolean) —

    true if a response of X holds no processing of the media, or its processing succeeded



175
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 175

def ready? = processing_info.nil? ? !attrs.except(*IDENTIFYING_KEYS).empty? : state.eql?("succeeded")

#state ⇒ String?

The state of the processing of the media

Examples:

Get the state

media.state # => "succeeded"

Returns:

  • (String, nil) —

    pending, in_progress, succeeded, or failed, or nil for media X does not process



134
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 134

def state = dig("processing_info", "state")

#to_json(state = nil) ⇒ String

The attributes of the response as JSON

Media written into the body of a request is the response it holds, rather than the object itself.

Examples:

Attach the media to a post

client.post("tweets", {text: "Look at this cat", media: {media_ids: [media.id.to_s]}})

Parameters:

  • state (JSON::State, nil) (defaults to: nil) —

    the state the encoder generating the JSON around it passes

Returns:

  • (String) —

    the JSON of the attributes



236
# File 'x-uploader/lib/x/uploader/uploaded_media.rb', line 236

def to_json(state = nil) = as_json.to_json(state)