rbender 0.5.35 → 0.7.3
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 +5 -5
- data/bin/rbender +47 -3
- data/lib/rbender/base.rb +184 -182
- data/lib/rbender/config_handler.rb +39 -39
- data/lib/rbender/fly_settings.rb +30 -0
- data/lib/rbender/keyboard.rb +79 -80
- data/lib/rbender/keyboard_inline.rb +29 -15
- data/lib/rbender/methods.rb +453 -376
- data/lib/rbender/mongo_client.rb +2 -1
- data/lib/rbender/{sessionmanager.rb → session_manager.rb} +11 -14
- data/lib/rbender/state.rb +305 -241
- data/templates/sample.rb +2 -1
- metadata +7 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: a793668dab825c522287f029506745b94cd5cf86d5aba5af6a5ca8bc59525389
|
|
4
|
+
data.tar.gz: fcacdcb1c9990bf38b6089546dacd78a7ca57c95856bb8799a6396ed104ffb2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21fef267a733b01635afe9ba9cdf1bbba98eae94d64d7ffd53989a73901658223fee1b13db35b31d8dbbd91c4092524ece637e425a40d199968b2095f94da95c
|
|
7
|
+
data.tar.gz: 1d014f730e8eaec9b504d9751d4bc332b4ab54e0d1133244675e6bbea94ad47ffad3cc1c278499ec02e70074d8366082467895fc422cdab3d1176e248fb1e3da
|
data/bin/rbender
CHANGED
|
@@ -37,6 +37,14 @@ class OptParser
|
|
|
37
37
|
exit
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
opts.on("-d", "Set bot's working directory") do |dir|
|
|
41
|
+
if File.directory?(dir)
|
|
42
|
+
options.directory = dir
|
|
43
|
+
else
|
|
44
|
+
raise ArgumentError, "#{dir} isn't working directory"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
global.order!
|
|
@@ -53,8 +61,10 @@ def create_project(options, args)
|
|
|
53
61
|
unless args[0] =~ /\w{3,16}/ and args[1] == nil
|
|
54
62
|
raise ArgumentError, "Name must be from 3 to 16 english letters without spaces"
|
|
55
63
|
end
|
|
64
|
+
|
|
56
65
|
name = args[0]
|
|
57
66
|
name_undrscr = RBender::ConfigHandler.underscore(name)
|
|
67
|
+
|
|
58
68
|
begin
|
|
59
69
|
FileUtils.mkdir name
|
|
60
70
|
rescue
|
|
@@ -83,7 +93,6 @@ def create_project(options, args)
|
|
|
83
93
|
config.save
|
|
84
94
|
|
|
85
95
|
puts "Project #{name} successfully created"
|
|
86
|
-
|
|
87
96
|
end
|
|
88
97
|
|
|
89
98
|
def run(options, args)
|
|
@@ -92,15 +101,48 @@ def run(options, args)
|
|
|
92
101
|
rescue
|
|
93
102
|
puts 'Main file or config are missing!'
|
|
94
103
|
end
|
|
104
|
+
wd = options.directory || Dir.pwd
|
|
105
|
+
Dir.chdir(wd)
|
|
95
106
|
title = RBender::ConfigHandler.underscore(settings['title'])
|
|
96
|
-
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
recursive_require("#{Dir.pwd}/lib/")
|
|
110
|
+
load "#{wd}/#{title}.rb"
|
|
111
|
+
recursive_load("#{Dir.pwd}/screens/")
|
|
112
|
+
recursive_load("#{Dir.pwd}/states/")
|
|
113
|
+
|
|
114
|
+
|
|
97
115
|
bot_frame = RBender.instance
|
|
116
|
+
|
|
98
117
|
#TODO: add mode setting
|
|
99
|
-
RBender::ConfigHandler.config_path =
|
|
118
|
+
RBender::ConfigHandler.config_path = wd
|
|
100
119
|
bot_frame.set_params(settings)
|
|
101
120
|
bot_frame.run!
|
|
102
121
|
end
|
|
103
122
|
|
|
123
|
+
def recursive_require(file_path)
|
|
124
|
+
return unless Dir.exist? file_path
|
|
125
|
+
Dir.foreach(file_path) do |file|
|
|
126
|
+
next if file == "." || file == ".."
|
|
127
|
+
if File.extname(file) == ".rb"
|
|
128
|
+
require "#{file_path}/#{file}"
|
|
129
|
+
elsif File.directory? "#{file_path}/#{file}"
|
|
130
|
+
recursive_require("#{file_path}#{file}")
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def recursive_load(file_path)
|
|
136
|
+
return unless Dir.exist? file_path
|
|
137
|
+
Dir.foreach(file_path) do |file|
|
|
138
|
+
next if file == "." || file == ".."
|
|
139
|
+
if File.extname(file) == ".rb"
|
|
140
|
+
load "#{file_path}/#{file}"
|
|
141
|
+
elsif File.directory? "#{file_path}/#{file}"
|
|
142
|
+
recursive_load("#{file_path}#{file}")
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
104
146
|
# --- EXECUTE CODE ______
|
|
105
147
|
begin
|
|
106
148
|
options = OptParser.parse(ARGV.dup)
|
|
@@ -111,6 +153,8 @@ begin
|
|
|
111
153
|
create_project(options, ARGV.dup)
|
|
112
154
|
when "start"
|
|
113
155
|
run(options, ARGV.dup)
|
|
156
|
+
else
|
|
157
|
+
puts "Wrong command #{command}"
|
|
114
158
|
end
|
|
115
159
|
rescue ArgumentError => e
|
|
116
160
|
puts "Wrong argument: #{e}"
|
data/lib/rbender/base.rb
CHANGED
|
@@ -1,195 +1,197 @@
|
|
|
1
|
-
|
|
2
|
-
# require_relative 'sessionmanager'
|
|
3
|
-
|
|
4
|
-
require 'rbender/sessionmanager'
|
|
1
|
+
require 'rbender/session_manager'
|
|
5
2
|
require 'rbender/keyboard_inline'
|
|
6
3
|
require 'rbender/mongo_client'
|
|
7
4
|
require 'rbender/state'
|
|
8
5
|
require 'rbender/config_handler'
|
|
9
6
|
require 'rbender/methods'
|
|
10
7
|
require 'rbender/keyboard'
|
|
11
|
-
|
|
8
|
+
require 'rbender/fly_settings'
|
|
12
9
|
|
|
13
10
|
require 'telegram/bot'
|
|
14
11
|
|
|
15
|
-
|
|
16
12
|
class RBender::Base
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
13
|
+
attr_accessor :api
|
|
14
|
+
include RBender::SessionManager
|
|
15
|
+
|
|
16
|
+
public
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
@states = {}
|
|
20
|
+
@global_state = nil
|
|
21
|
+
@modules_block
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def modules(&modules_block)
|
|
25
|
+
@modules_block = modules_block
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Runs the bot with server
|
|
29
|
+
def run!
|
|
30
|
+
puts "Bot is loading...".green
|
|
31
|
+
puts "Bot is running...".green
|
|
32
|
+
Telegram::Bot::Client.run(@token) do |bot|
|
|
33
|
+
@api = bot.api
|
|
34
|
+
|
|
35
|
+
unless @modules_block.nil?
|
|
36
|
+
instance_exec(@api, @mongo_client, &@modules_block)
|
|
37
|
+
end
|
|
38
|
+
bot.listen do |message| # When message has gotten
|
|
39
|
+
begin
|
|
40
|
+
process_message(message)
|
|
41
|
+
rescue => ex
|
|
42
|
+
puts ex.message.red
|
|
43
|
+
puts ex.backtrace_locations
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# @param [Hash] params - hash with params
|
|
51
|
+
#
|
|
52
|
+
# Available parameters:
|
|
53
|
+
# * mongo (required) connection string
|
|
54
|
+
# * bot_name (required) name of bot
|
|
55
|
+
# * token (required) token
|
|
56
|
+
def set_params(params)
|
|
57
|
+
RBender::MongoClient.setup(params['title'], params['mongo'])
|
|
58
|
+
|
|
59
|
+
session_setup(RBender::MongoClient.client)
|
|
60
|
+
|
|
61
|
+
@token = params['development']['token']
|
|
62
|
+
RBender::ConfigHandler.token = @token
|
|
63
|
+
|
|
64
|
+
# if params.has_key? localizations
|
|
65
|
+
#
|
|
66
|
+
# end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Adds new state to the bot.
|
|
70
|
+
# @param [String] state_name - name of the state
|
|
71
|
+
# @param [Block] block - actions while state has invocked
|
|
72
|
+
#
|
|
73
|
+
def state(state_name, &block)
|
|
74
|
+
if @states.has_key? state_name
|
|
75
|
+
raise "State :#{state_name} is duplicated!"
|
|
76
|
+
else
|
|
77
|
+
@states[state_name] = block
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def global(&block)
|
|
83
|
+
if @global_state
|
|
84
|
+
raise 'Global state already defined: You\'ve trying to define too much :global blocks'
|
|
85
|
+
else
|
|
86
|
+
@global_state = block
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def process_message(message)
|
|
93
|
+
chat_id = message&.from&.id || message&.chat&.id # Unique chat ID
|
|
94
|
+
|
|
95
|
+
session = session(chat_id, message)
|
|
96
|
+
|
|
97
|
+
state = session[:state] # User's state
|
|
98
|
+
state_block = @states[state] # Block of the state
|
|
99
|
+
state_object = RBender::State.new message, # Object to invoke
|
|
100
|
+
@api,
|
|
101
|
+
session,
|
|
102
|
+
&state_block
|
|
103
|
+
|
|
104
|
+
state_object.instance_eval(&@global_state) unless @global_state.nil?
|
|
105
|
+
state_object.build
|
|
106
|
+
state_object.invoke
|
|
107
|
+
|
|
108
|
+
if is_start_message? message
|
|
109
|
+
state_object.invoke_before if state_object.has_before?
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
save_session session
|
|
113
|
+
|
|
114
|
+
state_new = session[:state] # New user's state
|
|
115
|
+
|
|
116
|
+
on_state_changed(state_object,
|
|
117
|
+
state,
|
|
118
|
+
state_new,
|
|
119
|
+
message,
|
|
120
|
+
session)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def on_state_changed(state_object, state_old, state_new, message, session)
|
|
124
|
+
if state_new != state_old # If state has changed
|
|
125
|
+
state_object.invoke_after if state_object.has_after? #invoke after hook for an old state
|
|
126
|
+
|
|
127
|
+
state_new_block = @states[state_new]
|
|
128
|
+
state_object = RBender::State.new message,
|
|
129
|
+
@api,
|
|
130
|
+
session,
|
|
131
|
+
&state_new_block
|
|
132
|
+
|
|
133
|
+
state_object.instance_eval(&@global_state) unless @global_state.nil?
|
|
134
|
+
state_object.build
|
|
135
|
+
|
|
136
|
+
if state_object.has_keyboard? # Invoke a keyboard if it's exists
|
|
137
|
+
state_object.build_keyboard
|
|
138
|
+
state_object.invoke_keyboard
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
state_object.invoke_before if state_object.has_before? #invoke before hook for a new state
|
|
142
|
+
save_session session
|
|
143
|
+
else
|
|
144
|
+
if state_object.has_keyboard? # Invoke a keyboard if it's exists
|
|
145
|
+
unless state_object.get_keyboard.one_time? or not state_object.get_keyboard.force_invoked?
|
|
146
|
+
state_object.build_keyboard
|
|
147
|
+
state_object.invoke_keyboard
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def session(chat_id, message)
|
|
154
|
+
if has_session?(chat_id)
|
|
155
|
+
session = load_session(chat_id)
|
|
156
|
+
else # If user is new
|
|
157
|
+
session = { state: :start,
|
|
158
|
+
state_stack: [],
|
|
159
|
+
keyboard_switchers: {},
|
|
160
|
+
keyboard_switch_groups: {},
|
|
161
|
+
lang: :default,
|
|
162
|
+
chat_id: chat_id
|
|
163
|
+
}
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if (message.try(:chat) rescue nil)
|
|
167
|
+
session[:chat] = {
|
|
168
|
+
chat_id: message.chat.id,
|
|
169
|
+
description: message.chat.description,
|
|
170
|
+
invite_link: message.chat.invite_link,
|
|
171
|
+
title: message.chat.title,
|
|
172
|
+
first_name: message.chat.first_name,
|
|
173
|
+
last_name: message.chat.last_name,
|
|
174
|
+
user_name: message.chat.username
|
|
175
|
+
}
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
session[:user].freeze # User's data must be immutable!
|
|
179
|
+
|
|
180
|
+
if is_start_message? message
|
|
181
|
+
session[:state] = :start
|
|
182
|
+
session[:state_stack] = []
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
session
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def is_start_message?(message)
|
|
189
|
+
if message.instance_of? Telegram::Bot::Types::Message
|
|
190
|
+
message.text == '/start' ? true : false
|
|
191
|
+
else
|
|
192
|
+
false
|
|
193
|
+
end
|
|
194
|
+
end
|
|
193
195
|
end
|
|
194
196
|
|
|
195
197
|
|