class Tgbot
Constants
- APIDOC
- VERSION
Attributes
debug[RW]
Public Class Methods
new(token, proxy: nil, debug: false)
click to toggle source
# File lib/tgbot.rb, line 20 def initialize(token, proxy: nil, debug: false) @prefix = "/bot#{token}" @client = HTTP.persistent "https://api.telegram.org" if proxy addr, port = *proxy.split(':') @client = @client.via(addr, port.to_i) end @debug = debug @commands = [] @start = @finish = nil end
run(*args, &blk)
click to toggle source
# File lib/tgbot.rb, line 12 def self.run(*args, &blk) bot = new(*args) bot.instance_exec(bot, &blk) if blk bot.run end
Public Instance Methods
api_version()
click to toggle source
# File lib/tgbot.rb, line 181 def api_version search_in_doc(/changes/i, '')[0].desc[0].content[/\d+\.\d+/] end
finish(&blk)
click to toggle source
# File lib/tgbot.rb, line 36 def finish &blk @finish = blk end
on(pattern=nil, name: nil, before_all: false, after_all: false, &blk)
click to toggle source
# File lib/tgbot.rb, line 40 def on pattern=nil, name: nil, before_all: false, after_all: false, &blk if before_all && after_all raise ArgumentError, 'before_all and after_all can\'t both be true' end @commands << [pattern, name, before_all, after_all, blk] end
run(&blk)
click to toggle source
# File lib/tgbot.rb, line 148 def run &blk @offset = 0 @timeout = 2 @updates = [] instance_exec(self, &@start) if @start loop do while x = @updates.shift u = Update === x ? x : Update.new(self, x) @offset = u.update_id if u.update_id && @offset < u.update_id @tasks = @commands.select { |pattern, *| u.match? pattern } .group_by { |e| e[2] ? :before : e[3] ? :after : nil } .values_at(:before, nil, :after).compact.flatten(1) while t = @tasks.shift debug ">> #{t[1] || t[0]}" u.instance_exec(u.match(t[0]), u, t, &t[4]) end end res = get_updates offset: @offset + 1, limit: 7, timeout: 15 if res.ok @updates.push *res.result else debug "#{res.error_code}: #{res.description}" end end rescue HTTP::ConnectionError debug "connect failed, check proxy?" retry rescue Interrupt instance_exec(self, &@finish) if @finish ensure @client.close end
start(&blk)
click to toggle source
# File lib/tgbot.rb, line 32 def start &blk @start = blk end
Private Instance Methods
check_match(k, arg)
click to toggle source
# File lib/tgbot.rb, line 254 def check_match k, arg if Array === k if k.size > 1 k.any? { |t| t === arg } else Array === arg && arg.all? { |a| check_match k[0], a } end else return true if String === k # unknown types, like "User" k === arg end end
check_type(payload, schema)
click to toggle source
# File lib/tgbot.rb, line 267 def check_type payload, schema filtered = {} payload.each do |field, value| row = schema[field.to_s] if row&.any? { |k| check_match k, value } filtered[field] = value else debug "check_type failed at #{field} :: #{row&.join(' | ')} = #{value.inspect}" end end filtered end
json_to_ostruct(json)
click to toggle source
# File lib/tgbot.rb, line 198 def json_to_ostruct json JSON.parse(json, object_class: OpenStruct) end
make_payload(meth, *args)
click to toggle source
# File lib/tgbot.rb, line 202 def make_payload meth, *args defaults, schema = meth_info meth payload = {} args.each do |arg| if field = defaults.find { |k, _| k.any? { |l| check_match l, arg } }&.last defaults.delete_if { |_, v| v == field } payload[field] = arg end if Hash === arg defaults.delete_if { |_, v| arg.keys.include?(v) || arg.keys.include?(v.to_sym) } payload = payload.merge arg end end if !defaults.empty? debug "should 400: #{defaults.values.join(', ')} not specified" end check_type payload, schema end
meth_info(meth)
click to toggle source
# File lib/tgbot.rb, line 221 def meth_info meth unless table = (search_in_doc '', /^#{meth}$/)[0]&.table debug "don't find type of #{meth}" return {}, {} end defaults = table.select { |e| e.Required.match? /Yes/i } .map { |e| [e.Type.split(/\s+or\s+/).flat_map { |s| string_to_native_types s, false }.compact, e.Parameter] }.reject { |(ts, _para)| ts.empty? }.to_h schema = table .map { |e| [e.Parameter, e.Type.split(/\s+or\s+/).map { |s| string_to_native_types s }] }.to_h return defaults, schema end
method_missing(meth, *args, &blk)
click to toggle source
# File lib/tgbot.rb, line 187 def method_missing meth, *args, &blk meth = meth.to_s.split('_').map. with_index { |x, i| i.zero? ? x : (x[0].upcase + x[1..-1]) }.join payload = make_payload meth, *args debug "/#{meth} #{payload}" result = @client.post("#@prefix/#{meth}", form: payload).to_s result = json_to_ostruct(result) debug "=> #{result}" blk ? blk.call(result) : result end
search_in_doc(*hints)
click to toggle source
# File lib/tgbot.rb, line 280 def search_in_doc *hints doc = [APIDOC] hints.each do |hint| if nxt = doc.flat_map { |x| x['children'] }.select { |x| x['name'][hint] } doc = nxt else return nil end end json_to_ostruct JSON.generate doc end
string_to_native_types(s, keep_unknown=true)
click to toggle source
# File lib/tgbot.rb, line 241 def string_to_native_types s, keep_unknown=true if s['Array of '] return [string_to_native_types(s[9..-1], keep_unknown)] end case s when 'String' then String when 'Integer' then Integer when 'Boolean' then [true, false] else keep_unknown ? s : nil end end