x-resources 1.0.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 +7 -0
- data/.yardopts +9 -0
- data/CHANGELOG.md +254 -0
- data/LICENSE.txt +21 -0
- data/README.md +148 -0
- data/lib/x/resources/abstract_class.rb +29 -0
- data/lib/x/resources/actions/direct_messages.rb +99 -0
- data/lib/x/resources/actions/engagement.rb +95 -0
- data/lib/x/resources/actions/lists.rb +126 -0
- data/lib/x/resources/actions/posts.rb +77 -0
- data/lib/x/resources/actions/relationships.rb +91 -0
- data/lib/x/resources/actions.rb +22 -0
- data/lib/x/resources/api.rb +40 -0
- data/lib/x/resources/attributes.rb +203 -0
- data/lib/x/resources/batch.rb +43 -0
- data/lib/x/resources/batch_finders.rb +185 -0
- data/lib/x/resources/bookmark_folder.rb +23 -0
- data/lib/x/resources/community.rb +137 -0
- data/lib/x/resources/cursor.rb +493 -0
- data/lib/x/resources/direct_message.rb +325 -0
- data/lib/x/resources/direct_message_conversations.rb +147 -0
- data/lib/x/resources/errors.rb +104 -0
- data/lib/x/resources/finders.rb +255 -0
- data/lib/x/resources/identity.rb +65 -0
- data/lib/x/resources/includes.rb +216 -0
- data/lib/x/resources/list.rb +336 -0
- data/lib/x/resources/lookups/communities.rb +56 -0
- data/lib/x/resources/lookups/direct_messages.rb +86 -0
- data/lib/x/resources/lookups/lists.rb +44 -0
- data/lib/x/resources/lookups/media.rb +72 -0
- data/lib/x/resources/lookups/posts.rb +198 -0
- data/lib/x/resources/lookups/spaces.rb +87 -0
- data/lib/x/resources/lookups/trends.rb +38 -0
- data/lib/x/resources/lookups/users.rb +221 -0
- data/lib/x/resources/lookups.rb +25 -0
- data/lib/x/resources/marshalling.rb +93 -0
- data/lib/x/resources/matching_rule.rb +107 -0
- data/lib/x/resources/media.rb +278 -0
- data/lib/x/resources/media_ids.rb +74 -0
- data/lib/x/resources/memo.rb +54 -0
- data/lib/x/resources/page.rb +394 -0
- data/lib/x/resources/page_limit.rb +80 -0
- data/lib/x/resources/pages.rb +270 -0
- data/lib/x/resources/parallel.rb +82 -0
- data/lib/x/resources/personalized_trend.rb +124 -0
- data/lib/x/resources/place.rb +107 -0
- data/lib/x/resources/poll.rb +75 -0
- data/lib/x/resources/post.rb +615 -0
- data/lib/x/resources/post_collections.rb +67 -0
- data/lib/x/resources/post_counts.rb +215 -0
- data/lib/x/resources/post_search.rb +86 -0
- data/lib/x/resources/post_usage.rb +203 -0
- data/lib/x/resources/post_writes.rb +140 -0
- data/lib/x/resources/published_count.rb +31 -0
- data/lib/x/resources/references.rb +121 -0
- data/lib/x/resources/relation_writes.rb +54 -0
- data/lib/x/resources/relationships.rb +77 -0
- data/lib/x/resources/resource.rb +535 -0
- data/lib/x/resources/serialization.rb +58 -0
- data/lib/x/resources/shape.rb +167 -0
- data/lib/x/resources/space.rb +332 -0
- data/lib/x/resources/topic.rb +59 -0
- data/lib/x/resources/trend.rb +130 -0
- data/lib/x/resources/user.rb +502 -0
- data/lib/x/resources/user_collections.rb +213 -0
- data/lib/x/resources/user_finders.rb +282 -0
- data/lib/x/resources/utils.rb +358 -0
- data/lib/x/resources/value_equality.rb +38 -0
- data/lib/x/resources/value_marshalling.rb +89 -0
- data/lib/x/resources/version.rb +25 -0
- data/lib/x/resources.rb +22 -0
- data/sig/manifest.yaml +7 -0
- data/sig/x-resources.rbs +813 -0
- metadata +140 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "memo"
|
|
4
|
+
|
|
5
|
+
module X
|
|
6
|
+
module Resources
|
|
7
|
+
# A group of stubs, no more than one lookup takes, that hydrate together in one request rather than one each
|
|
8
|
+
# @api private
|
|
9
|
+
class Batch
|
|
10
|
+
# Initialize a batch over some identifiers
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
13
|
+
# @param klass [Class] the class of the resources, which BatchFinders extends
|
|
14
|
+
# @param ids [Array<String, Integer>] the identifiers
|
|
15
|
+
# @param client [Object] the client used to make the requests
|
|
16
|
+
# @return [Batch] a new batch
|
|
17
|
+
def initialize(klass, ids, client:)
|
|
18
|
+
@klass = klass
|
|
19
|
+
@ids = ids
|
|
20
|
+
@client = client
|
|
21
|
+
@memo = Memo.new
|
|
22
|
+
freeze
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# The resource of one identifier, looking up every identifier of the batch at once
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
28
|
+
# @param id [String, Integer] the identifier
|
|
29
|
+
# @return [Resource, nil] the resource, or nil if it was not found
|
|
30
|
+
def fetch(id) = resources[id]
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# The resources of the batch, keyed by identifier
|
|
35
|
+
# @api private
|
|
36
|
+
# @return [Hash{Object => Resource}] the resources
|
|
37
|
+
def resources
|
|
38
|
+
@memo.fetch { @klass.find_all(@ids, client: @client).to_h { |resource| [resource.id, resource] } }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
private_constant :Batch
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "finders"
|
|
4
|
+
require_relative "parallel"
|
|
5
|
+
require_relative "utils"
|
|
6
|
+
|
|
7
|
+
module X
|
|
8
|
+
module Resources
|
|
9
|
+
# Class methods that look resources up many at a time, extended into each resource class the API can look up that way
|
|
10
|
+
#
|
|
11
|
+
# A resource the API looks up only one at a time, such as a list, a community, or a direct message event, extends
|
|
12
|
+
# Finders alone, and so answers neither find_all nor hydrate_all, rather than answer them only to raise.
|
|
13
|
+
#
|
|
14
|
+
# Internal to x-resources: the methods it gives a resource class, such as X::Post.find_all, are public API, but the
|
|
15
|
+
# module is only how they are shared, and which classes extend or include it can change within 1.x.
|
|
16
|
+
#
|
|
17
|
+
# @api semipublic
|
|
18
|
+
module BatchFinders
|
|
19
|
+
include Finders
|
|
20
|
+
|
|
21
|
+
# Maximum number of identifiers accepted by a batch lookup endpoint
|
|
22
|
+
# @api private
|
|
23
|
+
MAX_BATCH_SIZE = 100
|
|
24
|
+
|
|
25
|
+
# Default number of batch lookups a request makes at once, which matches the chunks an upload sends at once
|
|
26
|
+
# @api private
|
|
27
|
+
DEFAULT_CONCURRENCY = 4
|
|
28
|
+
|
|
29
|
+
# The message of the error raised for a concurrency that would look nothing up
|
|
30
|
+
# @api private
|
|
31
|
+
INVALID_CONCURRENCY = "concurrency must be an Integer of at least 1, not %s"
|
|
32
|
+
private_constant :INVALID_CONCURRENCY
|
|
33
|
+
|
|
34
|
+
# The message of the error raised for resources to hydrate that are not of the class hydrating them
|
|
35
|
+
# @api private
|
|
36
|
+
FOREIGN_RESOURCE = "%s.hydrate_all hydrates %s resources, not %s"
|
|
37
|
+
private_constant :FOREIGN_RESOURCE
|
|
38
|
+
|
|
39
|
+
# Replace the resources that are not hydrated with the full resources
|
|
40
|
+
#
|
|
41
|
+
# A resource that hydrate would look up is looked up, which is a stub and also a resource a response included
|
|
42
|
+
# without every field, so what comes back is hydrated throughout. A resource that was not found is dropped, as
|
|
43
|
+
# is nil, which a reference to no resource reads as, such as the author of a post whose response named none,
|
|
44
|
+
# and a hydrated resource is kept as it is, so resources that are all hydrated need no lookup. What was found is
|
|
45
|
+
# stored in each original, so hydrating one of them afterwards costs no request, unless params override a
|
|
46
|
+
# default field or expansion parameter: what such a lookup found is not the full resource, so it is returned
|
|
47
|
+
# without being stored, and hydrating an original fetches the full resource. A resource that holds what hydrate
|
|
48
|
+
# returns, because hydrate or an earlier hydrate_all stored it, is replaced with that, and looked up again by no
|
|
49
|
+
# request, since the API bills each resource a lookup returns.
|
|
50
|
+
#
|
|
51
|
+
# @api public
|
|
52
|
+
# @param resources [Array<Resource, nil>] the resources, some of which may not be hydrated, and some nil
|
|
53
|
+
# @param client [Object] the client used to make the requests
|
|
54
|
+
# @param concurrency [Integer] the number of batch lookups made at once, four by default, which must be at
|
|
55
|
+
# least one
|
|
56
|
+
# @param params [Hash] query parameters merged over the default parameters; one that overrides a default field
|
|
57
|
+
# or expansion parameter to leave some out builds resources that are not hydrated, so hydrate fetches the rest
|
|
58
|
+
# @return [Array<Resource>] the resources, in order, with the ones that were not hydrated replaced, frozen
|
|
59
|
+
# @raise [ArgumentError] if the concurrency is less than one
|
|
60
|
+
# @raise [ArgumentError] if a resource is not of this class, which a lookup of its identifier would find
|
|
61
|
+
# another resource for, before a request
|
|
62
|
+
# @yieldparam problem [Problem] each problem the API reported, such as a resource that was not found
|
|
63
|
+
# @example Look up every field of the authors of posts, the ones a search included among them
|
|
64
|
+
# X::User.hydrate_all(posts.map(&:author), client: client)
|
|
65
|
+
# @example Expand only the authors a search did not include, which the API bills for alone
|
|
66
|
+
# X::User.hydrate_all(posts.filter_map(&:author).select(&:stub?), client: client)
|
|
67
|
+
def hydrate_all(resources, client:, concurrency: DEFAULT_CONCURRENCY, **params, &)
|
|
68
|
+
resources = resources.compact
|
|
69
|
+
validate_class!(resources)
|
|
70
|
+
partial = resources.reject { |resource| settled?(resource) }
|
|
71
|
+
replace = replacer(find_all(partial, client:, concurrency:, **params, &), params)
|
|
72
|
+
resources.filter_map { |resource| settled?(resource) ? resource.hydrate : replace.call(resource) }.freeze
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Look up many resources by identifier, in parallel batches
|
|
76
|
+
#
|
|
77
|
+
# The resources come back in the order of the identifiers they were asked for by, whatever order the batches
|
|
78
|
+
# were answered in, one for each identifier that was found, so an identifier asked for twice comes back twice,
|
|
79
|
+
# as hydrate_all keeps a resource it is given twice. Each identifier is asked for once, however often it is
|
|
80
|
+
# given.
|
|
81
|
+
#
|
|
82
|
+
# @api public
|
|
83
|
+
# @param ids [Array<String, Integer, Resource>] the identifiers, or resources of this class
|
|
84
|
+
# @param client [Object] the client used to make the requests
|
|
85
|
+
# @param concurrency [Integer] the number of batches looked up at once, four by default, which must be at least
|
|
86
|
+
# one; each is a request of up to 100 identifiers, so a lower number spends a rate limit more slowly
|
|
87
|
+
# @param params [Hash] query parameters merged over the default parameters; one that overrides a default field
|
|
88
|
+
# or expansion parameter to leave some out builds resources that are not hydrated, so hydrate fetches the rest
|
|
89
|
+
# @return [Array<Resource>] the resources that were found, one for each identifier that names one, frozen
|
|
90
|
+
# @raise [ArgumentError] if the concurrency is less than one
|
|
91
|
+
# @raise [ArgumentError] if an identifier is not one, or is a resource of another class, before a request
|
|
92
|
+
# @yieldparam problem [Problem] each problem the API reported, such as an identifier that was not found
|
|
93
|
+
# @example Look up many posts by identifier, reporting the ones that were not found
|
|
94
|
+
# X::Post.find_all([1234567890, 1234567891], client: client) { |problem| warn problem.detail }
|
|
95
|
+
# @example Look up many posts one batch at a time, to spend a rate limit more slowly
|
|
96
|
+
# X::Post.find_all(ids, client: client, concurrency: 1)
|
|
97
|
+
def find_all(ids, client:, concurrency: DEFAULT_CONCURRENCY, **params, &)
|
|
98
|
+
ids = ids.map { |id| Utils.id_of(id, self) }
|
|
99
|
+
in_order_of(lookup_in_batches(endpoint!, batch_key, ids, client:, concurrency:, **params, &), ids)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# What replaces each resource that is not hydrated, from what a lookup found
|
|
105
|
+
#
|
|
106
|
+
# A lookup of every field found the full resource, which is stored in the original, as is a resource it did not
|
|
107
|
+
# find. A lookup of some fields found what is returned in its place, and nothing is stored.
|
|
108
|
+
#
|
|
109
|
+
# @api private
|
|
110
|
+
# @param found [Array<Resource>] the resources the lookup found
|
|
111
|
+
# @param params [Hash] the query parameters the lookup was given, merged over the default parameters
|
|
112
|
+
# @return [Proc] a callable passed a resource that is not hydrated, which returns what replaces it, or nil
|
|
113
|
+
def replacer(found, params)
|
|
114
|
+
by_id = found.to_h { |resource| [resource.id, resource] }
|
|
115
|
+
return ->(resource) { by_id[resource.id] } unless fully_requested_by?(Utils.merge_params(default_params, params))
|
|
116
|
+
|
|
117
|
+
->(resource) { resource.__send__(:hydrated_with, by_id[resource.id]) }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Look up values in parallel batches, asking for each value once
|
|
121
|
+
# @api private
|
|
122
|
+
# @param path [String] the batch lookup endpoint path
|
|
123
|
+
# @param key [Symbol] the query parameter the values go in, such as ids or usernames
|
|
124
|
+
# @param values [Array<String>] the values
|
|
125
|
+
# @param client [Object] the client used to make the requests
|
|
126
|
+
# @param concurrency [Integer] the number of batches looked up at once
|
|
127
|
+
# @param params [Hash] query parameters merged over the default parameters; one that overrides a default field
|
|
128
|
+
# or expansion parameter to leave some out builds resources that are not hydrated, so hydrate fetches the rest
|
|
129
|
+
# @return [Array<Resource>] the resources that were found, in the order the batches were answered in
|
|
130
|
+
# @raise [ArgumentError] if the concurrency is less than one
|
|
131
|
+
# @yieldparam problem [Problem] each problem the responses reported
|
|
132
|
+
def lookup_in_batches(path, key, values, client:, concurrency:, **params, &)
|
|
133
|
+
validate_concurrency!(concurrency)
|
|
134
|
+
query = Utils.merge_params(default_params, params)
|
|
135
|
+
bodies = Parallel.map(values.uniq.each_slice(MAX_BATCH_SIZE), concurrency:) { |batch| get(path, client:, query: query.merge(Utils.query(key => batch))) }
|
|
136
|
+
bodies.flat_map { |body| collection_built_from(reporting(body, &), client:, hydrated: fully_requested_by?(query), query:) }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Order resources as the identifiers that name them, one for each identifier
|
|
140
|
+
#
|
|
141
|
+
# An identifier is read as the resource reads its own, so that one asked for as a String of digits matches the
|
|
142
|
+
# Integer of the resource.
|
|
143
|
+
#
|
|
144
|
+
# @api private
|
|
145
|
+
# @param resources [Array<Resource>] the resources found
|
|
146
|
+
# @param ids [Array<String>] the identifiers asked for
|
|
147
|
+
# @return [Array<Resource>] the resource each identifier names, in the order of the identifiers, frozen
|
|
148
|
+
def in_order_of(resources, ids)
|
|
149
|
+
convert = Attributes::CONVERTERS.fetch(id_type)
|
|
150
|
+
by_id = resources.to_h { |resource| [resource.id, resource] }
|
|
151
|
+
ids.filter_map { |id| by_id[convert.call(id)] }.freeze
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Check whether hydrating a resource costs no request
|
|
155
|
+
# @api private
|
|
156
|
+
# @param resource [Resource] the resource
|
|
157
|
+
# @return [Boolean] true if the resource is hydrated, or holds what hydrate returns
|
|
158
|
+
def settled?(resource) = resource.hydrated? || resource.__send__(:hydration_stored?)
|
|
159
|
+
|
|
160
|
+
# Check that a number of batches to look up at once is an Integer of at least one
|
|
161
|
+
#
|
|
162
|
+
# Anything that is not an Integer, such as a String read from an environment variable, raises ArgumentError too,
|
|
163
|
+
# rather than NoMethodError from the check.
|
|
164
|
+
#
|
|
165
|
+
# @api private
|
|
166
|
+
# @param concurrency [Integer] the number of batches looked up at once
|
|
167
|
+
# @return [void]
|
|
168
|
+
# @raise [ArgumentError] if the concurrency is not an Integer, or is less than one
|
|
169
|
+
def validate_concurrency!(concurrency)
|
|
170
|
+
raise ArgumentError, format(INVALID_CONCURRENCY, concurrency.inspect) unless concurrency.instance_of?(Integer) && concurrency.positive?
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Check that resources to hydrate are of this class, whose endpoint looks them up
|
|
174
|
+
# @api private
|
|
175
|
+
# @param resources [Array<Resource>] the resources
|
|
176
|
+
# @return [void]
|
|
177
|
+
# @raise [ArgumentError] if a resource is not of this class
|
|
178
|
+
def validate_class!(resources)
|
|
179
|
+
foreign = resources.grep_v(self).first
|
|
180
|
+
raise ArgumentError, format(FOREIGN_RESOURCE, self, self, foreign.class) unless foreign.nil?
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
private_constant :BatchFinders
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "resource"
|
|
4
|
+
|
|
5
|
+
module X
|
|
6
|
+
# A folder the authenticated user keeps bookmarks in
|
|
7
|
+
#
|
|
8
|
+
# The API offers no lookup of a folder, so a folder is read from the bookmark folders of the user it belongs to,
|
|
9
|
+
# which X::User#bookmark_folders pages through, and the class answers no finder. from_id builds one from its
|
|
10
|
+
# identifier, which X::User#bookmarks takes as the folder to read the posts of, but hydrate and refresh raise
|
|
11
|
+
# UnsupportedOperation for one that is not hydrated, since there is nothing to look it up with.
|
|
12
|
+
#
|
|
13
|
+
# @api public
|
|
14
|
+
class BookmarkFolder < Resource
|
|
15
|
+
# @!attribute [r] name
|
|
16
|
+
# The name of the folder
|
|
17
|
+
# @api public
|
|
18
|
+
# @return [String, nil] the name
|
|
19
|
+
# @example Get the name
|
|
20
|
+
# folder.name # => "Ruby"
|
|
21
|
+
attribute :name
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
require_relative "cursor"
|
|
5
|
+
require_relative "finders"
|
|
6
|
+
require_relative "resource"
|
|
7
|
+
|
|
8
|
+
module X
|
|
9
|
+
module Resources
|
|
10
|
+
# A community of users who post to one another
|
|
11
|
+
# @api public
|
|
12
|
+
class ::X::Community < Resource
|
|
13
|
+
extend Finders
|
|
14
|
+
|
|
15
|
+
# The mixins of the class by their full names, which YARD needs to resolve them in a class opened under X
|
|
16
|
+
#
|
|
17
|
+
# @!parse
|
|
18
|
+
# extend X::Resources::Finders
|
|
19
|
+
|
|
20
|
+
# Every public community field
|
|
21
|
+
#
|
|
22
|
+
# A minor release may add to it the fields the API adds, so that a lookup asks for them too; see
|
|
23
|
+
# {Resource#hydrated?} for what that means for a resource looked up with a list of fields of its own.
|
|
24
|
+
FIELDS = %w[access created_at description id join_policy member_count name].freeze
|
|
25
|
+
# Maximum number of communities per page of a search
|
|
26
|
+
# @api private
|
|
27
|
+
MAX_RESULTS = 100
|
|
28
|
+
private_constant :MAX_RESULTS
|
|
29
|
+
|
|
30
|
+
class << self
|
|
31
|
+
# The API endpoint used to look up communities by identifier
|
|
32
|
+
#
|
|
33
|
+
# @api private
|
|
34
|
+
# @return [String] the endpoint
|
|
35
|
+
# @example Get the endpoint
|
|
36
|
+
# X::Community.__send__(:endpoint) # => "communities"
|
|
37
|
+
def endpoint = "communities"
|
|
38
|
+
|
|
39
|
+
# The query parameter that selects community fields
|
|
40
|
+
#
|
|
41
|
+
# @api private
|
|
42
|
+
# @return [String] the fields parameter
|
|
43
|
+
# @example Get the fields parameter
|
|
44
|
+
# X::Community.__send__(:fields_key) # => "community.fields"
|
|
45
|
+
def fields_key = "community.fields"
|
|
46
|
+
|
|
47
|
+
private :endpoint, :fields_key
|
|
48
|
+
|
|
49
|
+
# The default query parameters requesting every community field
|
|
50
|
+
#
|
|
51
|
+
# @api public
|
|
52
|
+
# @return [Hash{String => Array<String>}] the default query parameters
|
|
53
|
+
# @example Get the default parameters
|
|
54
|
+
# X::Community.default_params["community.fields"]
|
|
55
|
+
def default_params = {"community.fields" => FIELDS}
|
|
56
|
+
|
|
57
|
+
# Search communities
|
|
58
|
+
#
|
|
59
|
+
# @api public
|
|
60
|
+
# @param query [String] the search query
|
|
61
|
+
# @param client [Object] the client used to make the requests
|
|
62
|
+
# @param params [Hash] query parameters merged over the default parameters
|
|
63
|
+
# @return [Cursor] a cursor over the matching communities
|
|
64
|
+
# @example Print the communities matching a query
|
|
65
|
+
# X::Community.search("ruby", client: client).each { |community| puts community.name }
|
|
66
|
+
def search(query, client:, **params)
|
|
67
|
+
Cursor.__send__(:build, self, "communities/search", client:, params: {query:, max_results: MAX_RESULTS}.merge(params),
|
|
68
|
+
token_param: "next_token", min_results: 10)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @!attribute [r] name
|
|
73
|
+
# The name
|
|
74
|
+
# @api public
|
|
75
|
+
# @return [String, nil] the name
|
|
76
|
+
# @example Get the name
|
|
77
|
+
# community.name
|
|
78
|
+
attribute :name
|
|
79
|
+
|
|
80
|
+
# @!attribute [r] description
|
|
81
|
+
# The description
|
|
82
|
+
# @api public
|
|
83
|
+
# @return [String, nil] the description
|
|
84
|
+
# @example Get the description
|
|
85
|
+
# community.description
|
|
86
|
+
attribute :description
|
|
87
|
+
|
|
88
|
+
# @!attribute [r] created_at
|
|
89
|
+
# The creation time
|
|
90
|
+
# @api public
|
|
91
|
+
# @return [Time, nil] the creation time
|
|
92
|
+
# @example Get the creation time
|
|
93
|
+
# community.created_at
|
|
94
|
+
attribute :created_at, :time
|
|
95
|
+
|
|
96
|
+
# @!attribute [r] member_count
|
|
97
|
+
# The number of members
|
|
98
|
+
# @api public
|
|
99
|
+
# @return [Integer, nil] the member count
|
|
100
|
+
# @example Get the member count
|
|
101
|
+
# community.member_count
|
|
102
|
+
attribute :member_count, :integer
|
|
103
|
+
|
|
104
|
+
# @!attribute [r] access
|
|
105
|
+
# Who can see the community's posts, as the API names it
|
|
106
|
+
# @api public
|
|
107
|
+
# @return [String, nil] the access level
|
|
108
|
+
# @example Get the access level
|
|
109
|
+
# community.access
|
|
110
|
+
attribute :access
|
|
111
|
+
|
|
112
|
+
# @!attribute [r] join_policy
|
|
113
|
+
# How users become members, as the API names it
|
|
114
|
+
# @api public
|
|
115
|
+
# @return [String, nil] the join policy
|
|
116
|
+
# @example Get the join policy
|
|
117
|
+
# community.join_policy
|
|
118
|
+
attribute :join_policy
|
|
119
|
+
|
|
120
|
+
# The permalink of the community
|
|
121
|
+
#
|
|
122
|
+
# @api public
|
|
123
|
+
# @return [String] the x.com address of the community
|
|
124
|
+
# @example Get the permalink
|
|
125
|
+
# community.permalink # => "https://x.com/i/communities/1234567890"
|
|
126
|
+
def permalink = "https://x.com/i/communities/#{id}"
|
|
127
|
+
|
|
128
|
+
# The permalink of the community as a URI
|
|
129
|
+
#
|
|
130
|
+
# @api public
|
|
131
|
+
# @return [URI::Generic] the x.com address of the community
|
|
132
|
+
# @example Get the address as a URI
|
|
133
|
+
# community.uri # => #<URI::HTTPS https://x.com/i/communities/1234567890>
|
|
134
|
+
def uri = URI(permalink)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|