max_bot_api 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 +7 -0
- data/README.md +168 -0
- data/docs/01-your-first-bot.md +44 -0
- data/docs/02-listen-and-respond.md +64 -0
- data/docs/03-attachments.md +49 -0
- data/docs/04-keyboard.md +36 -0
- data/docs/05-uploads.md +50 -0
- data/docs/06-subscriptions.md +28 -0
- data/examples/attachments.rb +15 -0
- data/examples/basic_send.rb +12 -0
- data/examples/keyboard.rb +24 -0
- data/examples/long_poll.rb +18 -0
- data/examples/subscriptions.rb +15 -0
- data/examples/uploads.rb +14 -0
- data/examples/webhook_rack.rb +28 -0
- data/lib/max_bot_api/builders/keyboard_builder.rb +94 -0
- data/lib/max_bot_api/builders/message_builder.rb +196 -0
- data/lib/max_bot_api/client.rb +225 -0
- data/lib/max_bot_api/errors.rb +91 -0
- data/lib/max_bot_api/resources/bots.rb +23 -0
- data/lib/max_bot_api/resources/chats.rb +91 -0
- data/lib/max_bot_api/resources/debugs.rb +35 -0
- data/lib/max_bot_api/resources/messages.rb +138 -0
- data/lib/max_bot_api/resources/subscriptions.rb +38 -0
- data/lib/max_bot_api/resources/uploads.rb +115 -0
- data/lib/max_bot_api/updates/parser.rb +60 -0
- data/lib/max_bot_api/version.rb +6 -0
- data/lib/max_bot_api.rb +21 -0
- metadata +140 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'cgi'
|
|
4
|
+
|
|
5
|
+
module MaxBotApi
|
|
6
|
+
module Resources
|
|
7
|
+
# Messages API methods.
|
|
8
|
+
class Messages
|
|
9
|
+
def initialize(client)
|
|
10
|
+
@client = client
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# List messages with filters.
|
|
14
|
+
def get_messages(chat_id: nil, message_ids: nil, from: nil, to: nil, count: nil)
|
|
15
|
+
query = {}
|
|
16
|
+
query['chat_id'] = chat_id if chat_id && chat_id.to_i != 0
|
|
17
|
+
Array(message_ids).each do |mid|
|
|
18
|
+
query['message_ids'] ||= []
|
|
19
|
+
query['message_ids'] << mid
|
|
20
|
+
end
|
|
21
|
+
query['from'] = from if from && from.to_i != 0
|
|
22
|
+
query['to'] = to if to && to.to_i != 0
|
|
23
|
+
query['count'] = count if count && count.to_i > 0
|
|
24
|
+
|
|
25
|
+
@client.request(:get, 'messages', query: normalize_array_query(query))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Fetch a single message by ID.
|
|
29
|
+
# @param message_id [String]
|
|
30
|
+
def get_message(message_id:)
|
|
31
|
+
path = "messages/#{CGI.escape(message_id.to_s)}"
|
|
32
|
+
@client.request(:get, path)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Edit a message by ID.
|
|
36
|
+
# @param message_id [String]
|
|
37
|
+
# @param message [MaxBotApi::Builders::MessageBuilder, Hash]
|
|
38
|
+
def edit_message(message_id:, message:)
|
|
39
|
+
body = message_payload(message)
|
|
40
|
+
result = @client.request(:put, 'messages', query: { 'message_id' => message_id }, body: body)
|
|
41
|
+
return true if result.is_a?(Hash) && result[:success]
|
|
42
|
+
|
|
43
|
+
raise Error, (result[:message] || 'message update failed')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Delete a message by ID.
|
|
47
|
+
# @param message_id [String]
|
|
48
|
+
def delete_message(message_id:)
|
|
49
|
+
@client.request(:delete, 'messages', query: { 'message_id' => message_id })
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Answer a callback button press.
|
|
53
|
+
# @param callback_id [String]
|
|
54
|
+
# @param answer [Hash]
|
|
55
|
+
def answer_on_callback(callback_id:, answer:)
|
|
56
|
+
@client.request(:post, 'answers', query: { 'callback_id' => callback_id }, body: answer)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Build a keyboard using the helper.
|
|
60
|
+
def new_keyboard_builder
|
|
61
|
+
Builders::KeyboardBuilder.new
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Send a message builder without returning the created message.
|
|
65
|
+
# @param message [MaxBotApi::Builders::MessageBuilder, Hash]
|
|
66
|
+
def send(message)
|
|
67
|
+
send_message(message, with_result: false)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Send a message builder and return the created message hash.
|
|
71
|
+
# @param message [MaxBotApi::Builders::MessageBuilder, Hash]
|
|
72
|
+
def send_with_result(message)
|
|
73
|
+
send_message(message, with_result: true)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Check if a message can be sent to the provided phone numbers.
|
|
77
|
+
# @param message [MaxBotApi::Builders::MessageBuilder, Hash]
|
|
78
|
+
def check(message)
|
|
79
|
+
message = ensure_builder(message)
|
|
80
|
+
query = {}
|
|
81
|
+
query['access_token'] = message.bot_token if message.reset?
|
|
82
|
+
query['phone_numbers'] = Array(message.phone_numbers).join(',') if message.phone_numbers
|
|
83
|
+
|
|
84
|
+
result = @client.request(:get, 'notify/exists', query: query, reset: message.reset?)
|
|
85
|
+
numbers = Array(result[:existing_phone_numbers])
|
|
86
|
+
[!numbers.empty?, result]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# List phone numbers that exist in MAX.
|
|
90
|
+
# @param message [MaxBotApi::Builders::MessageBuilder, Hash]
|
|
91
|
+
def list_exist(message)
|
|
92
|
+
message = ensure_builder(message)
|
|
93
|
+
query = {}
|
|
94
|
+
query['access_token'] = message.bot_token if message.reset?
|
|
95
|
+
query['phone_numbers'] = Array(message.phone_numbers).join(',') if message.phone_numbers
|
|
96
|
+
|
|
97
|
+
result = @client.request(:get, 'notify/exists', query: query, reset: message.reset?)
|
|
98
|
+
numbers = Array(result[:existing_phone_numbers])
|
|
99
|
+
[numbers.empty? ? nil : numbers, result]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def send_message(message, with_result:)
|
|
105
|
+
message = ensure_builder(message)
|
|
106
|
+
query = {}
|
|
107
|
+
query['chat_id'] = message.chat_id if message.chat_id && message.chat_id.to_i != 0
|
|
108
|
+
query['user_id'] = message.user_id if message.user_id && message.user_id.to_i != 0
|
|
109
|
+
|
|
110
|
+
response = @client.request(:post, 'messages', query: query, body: message_payload(message),
|
|
111
|
+
reset: message.reset?)
|
|
112
|
+
return response[:message] if with_result && response.is_a?(Hash)
|
|
113
|
+
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def message_payload(message)
|
|
118
|
+
message.is_a?(Builders::MessageBuilder) ? message.to_h : message
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def ensure_builder(message)
|
|
122
|
+
return message if message.is_a?(Builders::MessageBuilder)
|
|
123
|
+
|
|
124
|
+
Builders::MessageBuilder.from_hash(message)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def normalize_array_query(query)
|
|
128
|
+
query.each_with_object({}) do |(key, value), acc|
|
|
129
|
+
acc[key] = if value.is_a?(Array)
|
|
130
|
+
value
|
|
131
|
+
else
|
|
132
|
+
value
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MaxBotApi
|
|
4
|
+
module Resources
|
|
5
|
+
# Webhook subscription methods.
|
|
6
|
+
class Subscriptions
|
|
7
|
+
def initialize(client)
|
|
8
|
+
@client = client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# List active subscriptions.
|
|
12
|
+
def get_subscriptions
|
|
13
|
+
@client.request(:get, 'subscriptions')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Create a webhook subscription.
|
|
17
|
+
# @param url [String]
|
|
18
|
+
# @param update_types [Array<String>]
|
|
19
|
+
# @param secret [String, nil]
|
|
20
|
+
def subscribe(url:, update_types: [], secret: nil)
|
|
21
|
+
body = {
|
|
22
|
+
url: url,
|
|
23
|
+
update_types: update_types,
|
|
24
|
+
secret: secret,
|
|
25
|
+
version: @client.version
|
|
26
|
+
}.compact
|
|
27
|
+
|
|
28
|
+
@client.request(:post, 'subscriptions', body: body)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Remove a webhook subscription.
|
|
32
|
+
# @param url [String]
|
|
33
|
+
def unsubscribe(url:)
|
|
34
|
+
@client.request(:delete, 'subscriptions', query: { 'url' => url })
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
require 'stringio'
|
|
5
|
+
|
|
6
|
+
module MaxBotApi
|
|
7
|
+
module Resources
|
|
8
|
+
# Upload helpers for media and photos.
|
|
9
|
+
class Uploads
|
|
10
|
+
UPLOAD_TYPES = {
|
|
11
|
+
photo: 'image',
|
|
12
|
+
video: 'video',
|
|
13
|
+
audio: 'audio',
|
|
14
|
+
file: 'file'
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def initialize(client)
|
|
18
|
+
@client = client
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Upload media from a local file.
|
|
22
|
+
# @param type [Symbol, String]
|
|
23
|
+
# @param filename [String]
|
|
24
|
+
def upload_media_from_file(type:, filename:)
|
|
25
|
+
File.open(filename, 'rb') do |fh|
|
|
26
|
+
upload_media_from_reader_with_name(type: type, io: fh, name: File.basename(filename))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Upload media from a remote URL.
|
|
31
|
+
# @param type [Symbol, String]
|
|
32
|
+
# @param url [String]
|
|
33
|
+
def upload_media_from_url(type:, url:)
|
|
34
|
+
response = Faraday.get(url.to_s)
|
|
35
|
+
name = attachment_name(response.headers)
|
|
36
|
+
upload_media_from_reader_with_name(type: type, io: StringIO.new(response.body), name: name)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Upload media from an IO object.
|
|
40
|
+
# @param type [Symbol, String]
|
|
41
|
+
# @param io [#read]
|
|
42
|
+
def upload_media_from_reader(type:, io:)
|
|
43
|
+
upload_media_from_reader_with_name(type: type, io: io, name: nil)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Upload media from IO with explicit name.
|
|
47
|
+
# @param type [Symbol, String]
|
|
48
|
+
# @param io [#read]
|
|
49
|
+
# @param name [String, nil]
|
|
50
|
+
def upload_media_from_reader_with_name(type:, io:, name: nil)
|
|
51
|
+
upload_media_from_reader_internal(type: type, io: io, name: name)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Upload a photo from a local file.
|
|
55
|
+
# @param path [String]
|
|
56
|
+
def upload_photo_from_file(path:)
|
|
57
|
+
upload_media_from_file(type: :photo, filename: path)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Upload a photo from base64 content.
|
|
61
|
+
# @param code [String]
|
|
62
|
+
def upload_photo_from_base64_string(code:)
|
|
63
|
+
decoded = Base64.decode64(code)
|
|
64
|
+
upload_media_from_reader_with_name(type: :photo, io: StringIO.new(decoded), name: nil)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Upload a photo from a remote URL.
|
|
68
|
+
# @param url [String]
|
|
69
|
+
def upload_photo_from_url(url:)
|
|
70
|
+
upload_media_from_url(type: :photo, url: url)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Upload a photo from an IO object.
|
|
74
|
+
# @param io [#read]
|
|
75
|
+
def upload_photo_from_reader(io:)
|
|
76
|
+
upload_media_from_reader(type: :photo, io: io)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Upload a photo from IO with explicit name.
|
|
80
|
+
# @param io [#read]
|
|
81
|
+
# @param name [String]
|
|
82
|
+
def upload_photo_from_reader_with_name(io:, name:)
|
|
83
|
+
upload_media_from_reader_with_name(type: :photo, io: io, name: name)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def upload_media_from_reader_internal(type:, io:, name: nil)
|
|
89
|
+
upload_type = UPLOAD_TYPES.fetch(type.to_sym) { type.to_s }
|
|
90
|
+
endpoint = @client.request(:post, 'uploads', query: { 'type' => upload_type })
|
|
91
|
+
|
|
92
|
+
file_name = name.to_s.empty? ? 'file' : name.to_s
|
|
93
|
+
file_part = Faraday::Multipart::FilePart.new(io, nil, file_name)
|
|
94
|
+
|
|
95
|
+
response = Faraday.post(endpoint[:url]) do |req|
|
|
96
|
+
req.body = { 'data' => file_part }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
raise Error, "upload failed: #{response.status}" unless response.status == 200
|
|
100
|
+
|
|
101
|
+
JSON.parse(response.body, symbolize_names: true)
|
|
102
|
+
rescue Faraday::Error => e
|
|
103
|
+
raise NetworkError.new(op: 'POST uploads', original_error: e)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def attachment_name(headers)
|
|
107
|
+
disposition = headers['content-disposition'].to_s
|
|
108
|
+
return '' if disposition.empty?
|
|
109
|
+
|
|
110
|
+
match = disposition.match(/filename="?([^";]+)"?/)
|
|
111
|
+
match ? match[1] : ''
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MaxBotApi
|
|
4
|
+
module Updates
|
|
5
|
+
# Update parsing helpers.
|
|
6
|
+
class Parser
|
|
7
|
+
# Parse a single update JSON string or hash.
|
|
8
|
+
# @param data [String, Hash]
|
|
9
|
+
# @param debug [Boolean]
|
|
10
|
+
# @return [Hash]
|
|
11
|
+
def self.parse_update(data, debug: false)
|
|
12
|
+
raw = data.is_a?(String) ? data : JSON.generate(data)
|
|
13
|
+
update = data.is_a?(Hash) ? deep_symbolize_keys(data) : JSON.parse(raw, symbolize_names: true)
|
|
14
|
+
|
|
15
|
+
update[:debug_raw] = raw if debug
|
|
16
|
+
normalize_attachments!(update)
|
|
17
|
+
update
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Parse a list of updates.
|
|
21
|
+
# @param data [String, Hash]
|
|
22
|
+
# @param debug [Boolean]
|
|
23
|
+
# @return [Hash]
|
|
24
|
+
def self.parse_update_list(data, debug: false)
|
|
25
|
+
list = data.is_a?(Hash) ? data : JSON.parse(data.to_s, symbolize_names: true)
|
|
26
|
+
updates = Array(list[:updates])
|
|
27
|
+
list[:updates] = updates.map { |u| parse_update(u, debug: debug) }
|
|
28
|
+
list
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Normalize attachment payloads to symbolized hashes.
|
|
32
|
+
def self.normalize_attachments!(update)
|
|
33
|
+
message = update.dig(:message)
|
|
34
|
+
body = message && message[:body]
|
|
35
|
+
if body && body[:attachments].is_a?(Array)
|
|
36
|
+
body[:attachments] = body[:attachments].map { |att| deep_symbolize_keys(att) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
linked_body = update.dig(:message, :link, :message, :attachments)
|
|
40
|
+
return unless linked_body.is_a?(Array)
|
|
41
|
+
|
|
42
|
+
update[:message][:link][:message][:attachments] = linked_body.map { |att| deep_symbolize_keys(att) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Deep symbolize hash keys.
|
|
46
|
+
def self.deep_symbolize_keys(value)
|
|
47
|
+
case value
|
|
48
|
+
when Hash
|
|
49
|
+
value.each_with_object({}) do |(k, v), acc|
|
|
50
|
+
acc[k.to_sym] = deep_symbolize_keys(v)
|
|
51
|
+
end
|
|
52
|
+
when Array
|
|
53
|
+
value.map { |item| deep_symbolize_keys(item) }
|
|
54
|
+
else
|
|
55
|
+
value
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/max_bot_api.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'faraday'
|
|
4
|
+
require 'faraday/multipart'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
require_relative 'max_bot_api/version'
|
|
8
|
+
require_relative 'max_bot_api/errors'
|
|
9
|
+
require_relative 'max_bot_api/client'
|
|
10
|
+
|
|
11
|
+
require_relative 'max_bot_api/builders/message_builder'
|
|
12
|
+
require_relative 'max_bot_api/builders/keyboard_builder'
|
|
13
|
+
|
|
14
|
+
require_relative 'max_bot_api/updates/parser'
|
|
15
|
+
|
|
16
|
+
require_relative 'max_bot_api/resources/bots'
|
|
17
|
+
require_relative 'max_bot_api/resources/chats'
|
|
18
|
+
require_relative 'max_bot_api/resources/messages'
|
|
19
|
+
require_relative 'max_bot_api/resources/subscriptions'
|
|
20
|
+
require_relative 'max_bot_api/resources/uploads'
|
|
21
|
+
require_relative 'max_bot_api/resources/debugs'
|
metadata
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: max_bot_api
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- ChatGPT Codex
|
|
8
|
+
- Dmitry Merkushin
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: base64
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.1'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: faraday
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.7'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.7'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: faraday-multipart
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: minitest
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '6.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '6.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: webmock
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.18'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '3.18'
|
|
83
|
+
description: Ruby gem that mirrors the MAX Bot API Go client.
|
|
84
|
+
email:
|
|
85
|
+
- merkushin@hey.com
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- README.md
|
|
91
|
+
- docs/01-your-first-bot.md
|
|
92
|
+
- docs/02-listen-and-respond.md
|
|
93
|
+
- docs/03-attachments.md
|
|
94
|
+
- docs/04-keyboard.md
|
|
95
|
+
- docs/05-uploads.md
|
|
96
|
+
- docs/06-subscriptions.md
|
|
97
|
+
- examples/attachments.rb
|
|
98
|
+
- examples/basic_send.rb
|
|
99
|
+
- examples/keyboard.rb
|
|
100
|
+
- examples/long_poll.rb
|
|
101
|
+
- examples/subscriptions.rb
|
|
102
|
+
- examples/uploads.rb
|
|
103
|
+
- examples/webhook_rack.rb
|
|
104
|
+
- lib/max_bot_api.rb
|
|
105
|
+
- lib/max_bot_api/builders/keyboard_builder.rb
|
|
106
|
+
- lib/max_bot_api/builders/message_builder.rb
|
|
107
|
+
- lib/max_bot_api/client.rb
|
|
108
|
+
- lib/max_bot_api/errors.rb
|
|
109
|
+
- lib/max_bot_api/resources/bots.rb
|
|
110
|
+
- lib/max_bot_api/resources/chats.rb
|
|
111
|
+
- lib/max_bot_api/resources/debugs.rb
|
|
112
|
+
- lib/max_bot_api/resources/messages.rb
|
|
113
|
+
- lib/max_bot_api/resources/subscriptions.rb
|
|
114
|
+
- lib/max_bot_api/resources/uploads.rb
|
|
115
|
+
- lib/max_bot_api/updates/parser.rb
|
|
116
|
+
- lib/max_bot_api/version.rb
|
|
117
|
+
homepage: https://github.com/creogen/max_bot_api
|
|
118
|
+
licenses:
|
|
119
|
+
- MIT
|
|
120
|
+
metadata:
|
|
121
|
+
homepage_uri: https://github.com/creogen/max_bot_api
|
|
122
|
+
source_code_uri: https://github.com/creogen/max_bot_api/tree/main
|
|
123
|
+
rdoc_options: []
|
|
124
|
+
require_paths:
|
|
125
|
+
- lib
|
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '3.1'
|
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
|
+
requirements:
|
|
133
|
+
- - ">="
|
|
134
|
+
- !ruby/object:Gem::Version
|
|
135
|
+
version: '0'
|
|
136
|
+
requirements: []
|
|
137
|
+
rubygems_version: 3.7.2
|
|
138
|
+
specification_version: 4
|
|
139
|
+
summary: Ruby client for MAX Bot API
|
|
140
|
+
test_files: []
|