Class: X::Post

Inherits:
Resource show all
Extended by:
BatchFinders, PostCounts, PostSearch, PostWrites
Includes:
PostCollections, References
Defined in:
x-objects/lib/x/objects/post.rb

Overview

A post, also known as a tweet

Constant Summary collapse

FIELDS =

Every public post field; the identifiers of referenced resources come with their expansions

The metrics that only the author, or an advertiser, may read, non_public_metrics, organic_metrics, and promoted_metrics, are left out, since a field that depends on who is authenticated would make every request fail for a client that cannot read it, as are the fields of Community Notes and of suggested sources, which the API gives to the programs they belong to. So is source, which the API has deprecated: a field it stops taking would make every request that asks for it fail. Nor does a post read it; a request that names it in its post.fields finds it in Resource#attrs.

A minor release may add to it the fields the API adds, so that a lookup asks for them too; see Resource#hydrated? for what that means for a resource looked up with a list of fields of its own.

%w[article article_title attachments card_uri community_id context_annotations conversation_id
created_at display_text_range edit_controls entities geo id lang media_metadata note_post paid_partnership
possibly_sensitive public_metrics reply_settings scopes text withheld].freeze
EXPANSIONS =

The expansions of the resources a post refers to that the object layer resolves

The identifiers of a post's edit history come with every post, so the edit_history_post_ids expansion, which would include each version of the post again, including the post itself, is left out, as is entities.mentions.username, which would include each user the post mentions, since nothing reads them.

A minor release may add to it the expansions the API adds, so that a lookup asks for them too; see Resource#hydrated? for what that means for a resource looked up with a list of expansions of its own.

%w[attachments.media_keys attachments.media_source_tweet attachments.poll_ids author_id geo.place_id
in_reply_to_user_id referenced_posts].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from X::Resource

Instance Attribute Details

#article ⇒ Hash? (readonly)

The article the post publishes, with its title

Examples:

Get the title of an article

post.article&.fetch("title")

Returns:

  • (Hash, nil) —

    the article



235
# File 'x-objects/lib/x/objects/post.rb', line 235

attribute :article, :object

#article_title ⇒ Hash? (readonly)

What the API describes of the title of the article the post publishes

Examples:

Get the metadata of the title of an article

post.article_title

Returns:

  • (Hash, nil) —

    the metadata of the article, or nil for a post that publishes none



243
# File 'x-objects/lib/x/objects/post.rb', line 243

attribute :article_title, :object

#attachments ⇒ Hash? (readonly)

The attachment keys and identifiers

Examples:

Get the attachments

post.attachments

Returns:

  • (Hash, nil) —

    the attachments



332
# File 'x-objects/lib/x/objects/post.rb', line 332

attribute :attachments, :object

#author_id ⇒ Integer? (readonly)

The identifier of the author

Examples:

Get the author identifier

post.author_id

Returns:

  • (Integer, nil) —

    the author identifier



132
# File 'x-objects/lib/x/objects/post.rb', line 132

attribute :author_id, :integer

#bookmark_count ⇒ Integer? (readonly)

The number of bookmarks

Examples:

Get the bookmark count

post.bookmark_count

Returns:

  • (Integer, nil) —

    the bookmark count



412
# File 'x-objects/lib/x/objects/post.rb', line 412

attribute :bookmark_count, :integer, key: %w[public_metrics bookmark_count]

#card_uri ⇒ String? (readonly)

The URI of the card the post shows

Examples:

Get the card URI

post.card_uri

Returns:

  • (String, nil) —

    the card URI



227
# File 'x-objects/lib/x/objects/post.rb', line 227

attribute :card_uri

#community_id ⇒ Integer? (readonly)

The identifier of the community the post was made in

Examples:

Get the community identifier

post.community_id

Returns:

  • (Integer, nil) —

    the community identifier



148
# File 'x-objects/lib/x/objects/post.rb', line 148

attribute :community_id, :integer

#context_annotations ⇒ Array<Hash> (readonly)

The context annotations

Examples:

Get the context annotations

post.context_annotations

Returns:

  • (Array<Hash>) —

    the context annotations, empty if there are none



315
# File 'x-objects/lib/x/objects/post.rb', line 315

attribute :context_annotations, :objects

#conversation_id ⇒ Integer? (readonly)

The identifier of the first post in the conversation

Examples:

Get the conversation identifier

post.conversation_id

Returns:

  • (Integer, nil) —

    the conversation identifier



140
# File 'x-objects/lib/x/objects/post.rb', line 140

attribute :conversation_id, :integer

#coordinates ⇒ Array<Numeric>? (readonly)

The longitude and latitude the post was tagged with

Examples:

Get the coordinates

post.coordinates # => [-122.4, 37.8]

Returns:

  • (Array<Numeric>, nil) —

    the longitude and latitude, each an Integer when the API gives a whole number



340
# File 'x-objects/lib/x/objects/post.rb', line 340

attribute :coordinates, key: %w[geo coordinates coordinates]

#created_at ⇒ Time? (readonly)

The time when the post was created

Examples:

Get the creation time

post.created_at

Returns:

  • (Time, nil) —

    the creation time



124
# File 'x-objects/lib/x/objects/post.rb', line 124

attribute :created_at, :time

#display_text_range ⇒ Range<Integer>? (readonly)

The range of characters of the text the API gives the post that is shown

It leaves out the mentions a reply begins with and the link to media it ends with. It is a range of the text the post holds itself, which for a long post is the text cut short, not the full text #text reads.

Examples:

Read the text that is shown

post.display_text_range&.then { |range| post.attrs["text"][range] }

Returns:

  • (Range<Integer>, nil) —

    the range, which leaves out its end, or nil if the response holds none

Raises:

  • (InvalidAttribute) —

    if the response holds something other than the start and end of a range



208
# File 'x-objects/lib/x/objects/post.rb', line 208

attribute :display_text_range, :range

#edit_controls ⇒ Hash? (readonly)

The edit controls

Examples:

Get the edit controls

post.edit_controls

Returns:

  • (Hash, nil) —

    the edit controls



195
# File 'x-objects/lib/x/objects/post.rb', line 195

attribute :edit_controls, :object

#edit_history_post_ids ⇒ Array<Integer> (readonly)

The identifiers of every version of the post

Examples:

Get the edit history identifiers

post.edit_history_post_ids

Returns:

  • (Array<Integer>) —

    the edit history identifiers, empty if there are none



187
# File 'x-objects/lib/x/objects/post.rb', line 187

attribute :edit_history_post_ids, :integers, tweet_key: %w[edit_history_tweet_ids]

#geo ⇒ Hash? (readonly)

The tagged place and coordinates

Examples:

Get the geo details

post.geo

Returns:

  • (Hash, nil) —

    the geo details



348
# File 'x-objects/lib/x/objects/post.rb', line 348

attribute :geo, :object

#impression_count ⇒ Integer? (readonly)

The number of impressions

Examples:

Get the impression count

post.impression_count

Returns:

  • (Integer, nil) —

    the impression count



420
# File 'x-objects/lib/x/objects/post.rb', line 420

attribute :impression_count, :integer, key: %w[public_metrics impression_count]

#in_reply_to_user_id ⇒ Integer? (readonly)

The identifier of the user being replied to

Examples:

Get the replied-to user identifier

post.in_reply_to_user_id

Returns:

  • (Integer, nil) —

    the replied-to user identifier



156
# File 'x-objects/lib/x/objects/post.rb', line 156

attribute :in_reply_to_user_id, :integer

#lang ⇒ String? (readonly)

The BCP 47 language tag

Examples:

Get the language

post.lang

Returns:

  • (String, nil) —

    the language tag



116
# File 'x-objects/lib/x/objects/post.rb', line 116

attribute :lang

#like_count ⇒ Integer? (readonly)

The number of likes

Examples:

Get the like count

post.like_count

Returns:

  • (Integer, nil) —

    the like count



396
# File 'x-objects/lib/x/objects/post.rb', line 396

attribute :like_count, :integer, key: %w[public_metrics like_count]

#media_metadata ⇒ Array<Hash> (readonly)

What the post describes of the media it attaches

Examples:

Get the metadata of the media

post.

Returns:

  • (Array<Hash>) —

    the metadata of each medium, empty if there is none



251
# File 'x-objects/lib/x/objects/post.rb', line 251

attribute :media_metadata, :objects

#note_post ⇒ Hash? (readonly)

The full text and entities of a long post

Examples:

Get the note details

post.note_post

Returns:

  • (Hash, nil) —

    the note details



364
# File 'x-objects/lib/x/objects/post.rb', line 364

attribute :note_post, :object, tweet_key: %w[note_tweet]

Whether the post is a paid partnership

Examples:

Check whether a post is a paid partnership

post.paid_partnership?

Returns:

  • (Boolean, nil) —

    true if the post is a paid partnership



259
# File 'x-objects/lib/x/objects/post.rb', line 259

attribute :paid_partnership, :boolean

#possibly_sensitive ⇒ Boolean? (readonly)

Whether the post may contain sensitive content

Examples:

Check whether a post may be sensitive

post.possibly_sensitive?

Returns:

  • (Boolean, nil) —

    true if the post may be sensitive



164
# File 'x-objects/lib/x/objects/post.rb', line 164

attribute :possibly_sensitive, :boolean

#public_metrics ⇒ Hash? (readonly)

The public metrics

Examples:

Get the public metrics

post.public_metrics

Returns:

  • (Hash, nil) —

    the public metrics



372
# File 'x-objects/lib/x/objects/post.rb', line 372

attribute :public_metrics, :object

#quote_count ⇒ Integer? (readonly)

The number of quotes

Examples:

Get the quote count

post.quote_count

Returns:

  • (Integer, nil) —

    the quote count



404
# File 'x-objects/lib/x/objects/post.rb', line 404

attribute :quote_count, :integer, key: %w[public_metrics quote_count]

#referenced_posts ⇒ Array<Hash> (readonly)

The referenced posts with their types and identifiers

Examples:

Get the referenced posts

post.referenced_posts

Returns:

  • (Array<Hash>) —

    the referenced posts, empty if there are none



323
# File 'x-objects/lib/x/objects/post.rb', line 323

attribute :referenced_posts, :objects, tweet_key: %w[referenced_tweets]

#reply_count ⇒ Integer? (readonly)

The number of replies

Examples:

Get the reply count

post.reply_count

Returns:

  • (Integer, nil) —

    the reply count



388
# File 'x-objects/lib/x/objects/post.rb', line 388

attribute :reply_count, :integer, key: %w[public_metrics reply_count]

#reply_settings ⇒ String? (readonly)

Who can reply: everyone, mentionedUsers, or following

Examples:

Get the reply settings

post.reply_settings

Returns:

  • (String, nil) —

    the reply settings



179
# File 'x-objects/lib/x/objects/post.rb', line 179

attribute :reply_settings

#repost_count ⇒ Integer? (readonly)

The number of reposts

Examples:

Get the repost count

post.repost_count

Returns:

  • (Integer, nil) —

    the repost count



380
# File 'x-objects/lib/x/objects/post.rb', line 380

attribute :repost_count, :integer, key: %w[public_metrics repost_count], tweet_key: %w[public_metrics retweet_count]

#scopes ⇒ Hash? (readonly)

Who may see the post

A post its author shared with followers alone holds {"followers" => true}.

Examples:

Check whether the post is shared with followers alone

post.scopes&.fetch("followers", false)

Returns:

  • (Hash, nil) —

    the scopes



219
# File 'x-objects/lib/x/objects/post.rb', line 219

attribute :scopes, :object

#withheld ⇒ Hash? (readonly)

The withholding details

Examples:

Get the withholding details

post.withheld

Returns:

  • (Hash, nil) —

    the withholding details



356
# File 'x-objects/lib/x/objects/post.rb', line 356

attribute :withheld, :object

Class Method Details

.default_params ⇒ Hash{String => Array<String>}

The default query parameters requesting every post field and expansion

Examples:

Get the default parameters

X::Post.default_params["post.fields"]

Returns:

  • (Hash{String => Array<String>}) —

    the default query parameters



87
88
89
90
# File 'x-objects/lib/x/objects/post.rb', line 87

def default_params
  {"post.fields" => FIELDS, "user.fields" => User::FIELDS, "media.fields" => Media::FIELDS,
   "poll.fields" => Poll::FIELDS, "place.fields" => Place::FIELDS, "expansions" => EXPANSIONS}
end

Instance Method Details

#author ⇒ User?

The author, resolved from the includes or as a stub holding only its identifier

Examples:

Get the author's username

post.author.username

Returns:

  • (User, nil) —

    the author



428
# File 'x-objects/lib/x/objects/post.rb', line 428

reference :author, :User, key: %w[author_id]

#community ⇒ Community?

The community the post was made in, as a stub holding only its identifier

Examples:

Get the community's name

post.community.hydrate.name

Returns:



444
# File 'x-objects/lib/x/objects/post.rb', line 444

reference :community, :Community, key: %w[community_id]

#delete ⇒ Boolean

Delete this post as the authenticated user

Examples:

Delete a post

post.delete

Returns:

  • (Boolean) —

    true if the post was deleted



532
533
534
# File 'x-objects/lib/x/objects/post.rb', line 532

def delete
  self.class.delete(self, client: client!)
end

#entities ⇒ Hash?

The entities found in the full text

The entities, such as links, mentions, and hashtags, come from note_post for a long post, whose note the API gives entities when the full text has any, and from the post itself for a short one, so that each lies where #text holds it. A long post whose note holds none has none: the entities the post holds itself, such as its annotations, lie in the text cut short, which attrs holds.

Examples:

Get the entities

post.entities

Returns:

  • (Hash, nil) —

    the entities

Raises:

  • (InvalidAttribute) —

    if the response holds a note_post, or entities, that is not an object



280
# File 'x-objects/lib/x/objects/post.rb', line 280

def entities = Shape.read_object("#{self.class}#entities", full["entities"])

#expanded_text ⇒ String?

The text with every shortened link replaced by the URL it stands for

A link the API expanded to no URL is left as it is. A link without a url to replace is not one the API documents, so it raises, as any value of a response that cannot be read does, rather than being passed over.

Every link is replaced in one pass over the text, so a URL a link stands for is never read for the links after it, and holds what it holds, even the shortened url of another link of the post. A url that begins another, longer one is not read in it.

The rest of the text is as #text reads it, HTML-escaped as the API sends it, and each URL is HTML-escaped as it is put in, since the API sends a URL as it is, so the whole text is escaped alike: unescape it to display it.

Examples:

Display a post with its links in full

CGI.unescapeHTML(post.expanded_text)

Returns:

  • (String, nil) —

    the text with expanded links

Raises:

  • (InvalidAttribute) —

    if the response holds a link that is not an object with a url that is a String



521
522
523
524
# File 'x-objects/lib/x/objects/post.rb', line 521

def expanded_text
  expansions = urls.to_h { |link| Utils.read("#{self.class}#expanded_text", link) { expansion(link) } }
  text&.gsub(Regexp.union(expansions.keys.sort_by { |url| -url.length }), expansions)
end

#hide_reply ⇒ Boolean

Hide this reply, as the author of the post it replies to

Examples:

Hide a reply

reply.hide_reply

Returns:

  • (Boolean) —

    true if the reply is now hidden



542
543
544
# File 'x-objects/lib/x/objects/post.rb', line 542

def hide_reply
  self.class.hide_reply(self, client: client!)
end

#in_reply_to_user ⇒ User?

The user being replied to, resolved from the includes or built as a stub

Examples:

Get the replied-to user

post.in_reply_to_user

Returns:

  • (User, nil) —

    the replied-to user



436
# File 'x-objects/lib/x/objects/post.rb', line 436

reference :in_reply_to_user, :User, key: %w[in_reply_to_user_id]

#matching_rules ⇒ Array<MatchingRule>

The rules of the filtered stream this post matched

A post the filtered stream delivers names the rules it matched, and any other post names none. The streaming client of x-streaming builds the posts of a stream given X::Post as its object_class.

Examples:

Print the tags of the rules each post of the filtered stream matched

streaming_client.stream("tweets/search/stream", object_class: X::Post) { |post| p post.matching_rules.map(&:tag) }

Returns:

  • (Array<MatchingRule>) —

    the rules, empty for a post that did not come from the filtered stream

Raises:

  • (InvalidAttribute) —

    if the response holds the rules as something other than a list of objects, or a rule without an identifier that is a number, or with a tag that is not a String



302
303
304
305
# File 'x-objects/lib/x/objects/post.rb', line 302

def matching_rules
  reader = "#{self.class}#matching_rules"
  Shape.objects(reader, attrs["matching_rules"]).map { |rule| Utils.read(reader, rule) { MatchingRule.new(rule) } }.freeze
end

#media ⇒ Array<Media>

The attached media, from the includes or as stubs holding only their keys

Examples:

Get the media URLs

post.media.map(&:url)

Returns:

  • (Array<Media>) —

    the media



460
# File 'x-objects/lib/x/objects/post.rb', line 460

references :media, :Media, key: %w[attachments media_keys]

#media_source_posts ⇒ Array<Post> Also known as: media_source_tweets

The posts the attached media was first posted with

A post that attaches media another post was made with, as one that shares a video does, names that post as the source of the media. Each is read from the includes, or built as a stub holding only its identifier.

Examples:

Credit the author of shared media

post.media_source_posts.map { |source| source.author&.username }

Returns:

  • (Array<Post>) —

    the posts, empty if the media was first posted with this post, or it has none



480
# File 'x-objects/lib/x/objects/post.rb', line 480

references :media_source_posts, :Post, key: %w[attachments media_source_tweet_id]

Check whether the post is a paid partnership

Examples:

Check whether the post is a paid partnership

post.paid_partnership?

Returns:

  • (Boolean) —

    true if the post is a paid partnership



# File 'x-objects/lib/x/objects/post.rb', line 261

The permalink of the post, by the author's username when known

Examples:

Get the permalink

post.permalink # => "https://x.com/sferik/status/1234567890"

Returns:

  • (String) —

    the x.com address of the post



494
# File 'x-objects/lib/x/objects/post.rb', line 494

def permalink = "https://x.com/#{author&.username || "i"}/status/#{id}"

#place ⇒ Place?

The tagged place, from the includes or as a stub holding only its identifier

Examples:

Get the place

post.place

Returns:

  • (Place, nil) —

    the place



452
# File 'x-objects/lib/x/objects/post.rb', line 452

reference :place, :Place, key: %w[geo place_id]

#polls ⇒ Array<Poll>

The attached polls, from the includes or as stubs holding only their identifiers

Examples:

Get the poll options

post.polls.first.options

Returns:

  • (Array<Poll>) —

    the polls



468
# File 'x-objects/lib/x/objects/post.rb', line 468

references :polls, :Poll, key: %w[attachments poll_ids]

#possibly_sensitive? ⇒ Boolean

Check whether the post may contain sensitive content

Examples:

Check whether the post may contain sensitive content

post.possibly_sensitive?

Returns:

  • (Boolean) —

    true if the post may be sensitive



# File 'x-objects/lib/x/objects/post.rb', line 166

#text ⇒ String?

The full text

A long post, of more than 280 characters, holds its full text in note_post, and a text cut short with an ellipsis and a link to the post; this reads the full text.

It is the text as the API sends it, which escapes &, <, and > as &, <, and >, and it stays so throughout 1.x, so unescape it to display it.

Examples:

Get the text

post.text # => "Ruby &amp; Rails"

Display the text

CGI.unescapeHTML(post.text) # => "Ruby & Rails"

Returns:

  • (String, nil) —

    the text, HTML-escaped as the API sends it

Raises:

  • (InvalidAttribute) —

    if the response holds a note_post that is not an object



108
# File 'x-objects/lib/x/objects/post.rb', line 108

def text = full["text"]

#unhide_reply ⇒ Boolean

Show this reply after hiding it, as the author of the post it replies to

Examples:

Show a hidden reply

reply.unhide_reply

Returns:

  • (Boolean) —

    true if the reply is no longer hidden



552
553
554
# File 'x-objects/lib/x/objects/post.rb', line 552

def unhide_reply
  self.class.unhide_reply(self, client: client!)
end

#uri ⇒ URI::Generic

The permalink of the post as a URI

Examples:

Get the address as a URI

post.uri # => #<URI::HTTPS https://x.com/sferik/status/1234567890>

Returns:

  • (URI::Generic) —

    the x.com address of the post



502
# File 'x-objects/lib/x/objects/post.rb', line 502

def uri = URI(permalink)

#urls ⇒ Array<Hash>

The links in the full text, each with its shortened url and its expanded_url

Examples:

Get the links

post.urls # => [{"url" => "https://t.co/...", "expanded_url" => "https://github.com/sferik/x-ruby", ...}]

Returns:

  • (Array<Hash>) —

    the links, empty if there are none

Raises:

  • (InvalidAttribute) —

    if the response holds entities, or links, that are not what the API documents



289
# File 'x-objects/lib/x/objects/post.rb', line 289

def urls = Shape.objects("#{self.class}#urls", entities&.[]("urls"))