Class: Tgbot::Bot

Inherits:
Object
  • Object
show all
Defined in:
lib/tgbot/core.rb

Overview

This bot supports a minimal usage of Telegram Bot APIs.

bot = Bot.new TOKEN, proxy: 'https://127.0.0.1:1080'

API’s methods’ input and output are hash.

bot.get_updates offset: 0 #=> { 'ok' => 'true', 'result' => [] }

It will check type of params before post method, and if invalid, it will raise an error with detail.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(token, **opts) ⇒ Bot

Initialize a bot, and call getMe at once to see if given token is valid. If everything ok, the bot will get its id and name and so on.

token

String = TOKEN of your bot from botfather

opts

Hash = Options passed to Faraday.new



24
25
26
27
28
# File 'lib/tgbot/core.rb', line 24

def initialize(token, **opts)
  @token = token
  get_connection(**opts)
  identify_self
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, **kwargs) ⇒ Object

Verify methods and params then call(post) it. ‘:get_me’ and ‘:getMe’ are both valid.



58
59
60
61
62
63
64
65
# File 'lib/tgbot/core.rb', line 58

def method_missing(meth, **kwargs)
  camelized_meth = camelize meth
  meth_body = METHODS[camelized_meth]
  super unless meth_body
  ret, params = meth_body.values_at 'ret', 'params'
  check_params! (JSON.parse JSON.generate kwargs), params
  call camelized_meth, kwargs
end

Instance Attribute Details

#tokenObject

Returns the value of attribute token.



18
19
20
# File 'lib/tgbot/core.rb', line 18

def token
  @token
end

Instance Method Details

#call(meth, kwargs) ⇒ Object



67
68
69
70
71
# File 'lib/tgbot/core.rb', line 67

def call meth, kwargs
  JSON.parse @conn.post("/bot#{@token}/#{meth}", kwargs).body
rescue
  {}
end

#camelize(meth) ⇒ Object

Transform ‘the_name’ to ‘theName’.



135
136
137
138
139
# File 'lib/tgbot/core.rb', line 135

def camelize meth
  ret = String(meth).split('_')
  ret.drop(1).map(&:capitalize!)
  ret.join
end

#check_params(kwargs, params) ⇒ Object

Check args to meet method declaration. Returns false if invalid.



113
114
115
116
117
118
# File 'lib/tgbot/core.rb', line 113

def check_params kwargs, params
  check_params!(kwargs, params)
  true
rescue
  false
end

#check_params!(kwargs, params) ⇒ Object

Check args to meet method declaration. Raises error if invalid.



74
75
76
77
78
79
80
81
82
# File 'lib/tgbot/core.rb', line 74

def check_params! kwargs, params
  params.each do |param, info|
    arg = kwargs[param]
    type, optional = info.values_at 'type', 'optional'
    if (arg.nil? && !optional) || (!arg.nil? && !check_type(arg, type))
      raise ArgumentError, "[#{param}] should be #{type}\n#{error_message_of_type type}"
    end
  end
end

#check_type(arg, type) ⇒ Object

Check arg to meet type declaration. Returns false if invalid.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/tgbot/core.rb', line 95

def check_type arg, type
  case type
  when 'True'    then return arg == true
  when 'Boolean' then return arg == true || arg == false
  when 'Integer' then return arg.is_a? Integer
  when 'Float'   then return arg.is_a? Float
  when 'String'  then return arg.is_a? String
  end
  if type[0] == '['
    return arg.is_a?(Array) ? arg.all? { |a| check_type a, type[1..-2] } : false
  elsif type.include? '|'
    return type.split('|').any? { |t| check_type arg, t }
  end
  return false unless TYPES[type]
  check_params(arg, TYPES[type])
end

#error_message_of_type(type) ⇒ Object

Get declaration of type in form of:

User := { id :: Integer, first_name :: String }


86
87
88
89
90
91
92
# File 'lib/tgbot/core.rb', line 86

def error_message_of_type type
  (type.delete('[]').split('|') - ['True', 'Boolean', 'Integer', 'Float', 'String']).map { |type|
    "#{type} := { #{TYPES[type].map { |field, info|
      "#{info['optional'] ? '' : '*'}#{field} :: #{info['type']}"
    }.join(', ')} }"
  }.join(' ')
end

#first_nameObject Also known as: name



42
# File 'lib/tgbot/core.rb', line 42

def first_name; @me && @me['first_name']; end

#get_connection(**opts) ⇒ Object

Connect to API_URL. It will take few seconds.

opts

Hash = Options passed to Faraday.new



48
49
50
51
52
53
54
# File 'lib/tgbot/core.rb', line 48

def get_connection(**opts)
  @conn = Faraday.new(url: API_URL, **opts) do |faraday|
    faraday.request :multipart
    faraday.request :url_encoded
    faraday.adapter Faraday.default_adapter
  end
end

#get_methodsObject



124
125
126
# File 'lib/tgbot/core.rb', line 124

def get_methods
  METHODS.keys.map { |e| underscore e }.map(&:to_sym)
end

#get_typesObject



120
121
122
# File 'lib/tgbot/core.rb', line 120

def get_types
  TYPES.keys.map(&:to_sym)
end

#idObject

Shortcuts for bot’s info.



41
# File 'lib/tgbot/core.rb', line 41

def id        ; @me && @me['id']        ; end

#identify_selfObject

Get bot’s info.



31
32
33
34
35
36
37
38
# File 'lib/tgbot/core.rb', line 31

def identify_self
  x = get_me
  if x['ok']
    @me = x['result']
  else
    raise ArgumentError, 'not found myself, check your token.'
  end
end

#inspectObject



141
142
143
# File 'lib/tgbot/core.rb', line 141

def inspect
  "#<Bot token=#{@token} id=#{id} first_name=#{first_name} username=#{username}>"
end

#underscore(str) ⇒ Object

Transform ‘TheName’ or ‘theName’ to ‘the_name’.



129
130
131
132
# File 'lib/tgbot/core.rb', line 129

def underscore str
  str.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
     .gsub(/([a-z\d])([A-Z])/,'\1_\2').downcase
end

#usernameObject



43
# File 'lib/tgbot/core.rb', line 43

def username  ; @me && @me['username']  ; end