telegem 3.0.6 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b1fc2ee7549822e2fbf1a1808f49e274de5a1d1f40be2acd3829087f10e2ace
4
- data.tar.gz: cf376724f4cd390e690cdaea90eace022eb555ea325416c017ad8a83523b2de9
3
+ metadata.gz: 5551464d15fac54752c3b598184502f34b986ff5450c9afc11dda12e582bc90a
4
+ data.tar.gz: 80e223030e618a3e2f997cb15e8692ea7f74b620035a3fdeebe795c42c8422f6
5
5
  SHA512:
6
- metadata.gz: c1fcf41f167133dfe32d92e7a903b1644b070f9d9544e9cf3de5475a06c6e7c4583770d9df0bea92d0729858700bfc0b955b82b7ec633afef967397e57e25362
7
- data.tar.gz: ef730bff829458909631028f04cc794cbad161be022ac0218521f11083d36fafb40ea6b18e10fab3e13c4f6501e7696942ea4ba2e697d470d9508186b73812d9
6
+ metadata.gz: 0604f9c803fdddd15e90f2b187404173bd512a827c262cb82a31a9f642a3595033a8415fadba3197c8bd9b12347686b1bf3d8fdc53ba973b43cce03db56bcc05
7
+ data.tar.gz: 81bd29e6218605f201b98d51d30cfe9650fbafb1b7c1645a257ccb946b6d2bec8e9b7fad2668c6c1daa057bae7f4dbc8711dbd3698ada5dfc402c2fc0f82205c
data/lib/core/bot.rb CHANGED
@@ -255,7 +255,7 @@ end
255
255
  if update.message&.text && @logger
256
256
  user = update.message.from
257
257
  cmd = update.message.text.split.first
258
- @logger.info("#{cmd} - #{user.username || user.first_name}")
258
+ @logger.info("#{cmd} - #{user.username}")
259
259
  end
260
260
 
261
261
  ctx = Context.new(update, self)
@@ -287,12 +287,20 @@ end
287
287
  end
288
288
  end
289
289
 
290
- unless @middleware.any? { |m, _, _| m.is_a?(Session::Middleware) }
291
- chain.use(Session::Middleware.new(@session_store))
292
- end
293
-
294
- chain
295
- end
290
+ unless @middleware.any? { |m, _, _| m.to_s =~ /Scene/ }
291
+ begin
292
+ require_relative '../session/scene_middleware'
293
+ chain.use(Telegem::Scene::Middleware.new)
294
+ rescue LoadError => e
295
+ @logger.debug("Scene middleware not available: #{e.message}") if @logger
296
+ end
297
+ end
298
+ unless @middleware.any? { |m, _, _| m.is_a?(Session::Middleware) }
299
+ chain.use(Session::Middleware.new(@session_store))
300
+ end
301
+
302
+ chain
303
+ end
296
304
 
297
305
  def dispatch_to_handlers(ctx)
298
306
  update_type = detect_update_type(ctx.update)
data/lib/core/context.rb CHANGED
@@ -321,7 +321,43 @@ module Telegem
321
321
  def uploading_document(**options)
322
322
  send_chat_action('upload_document', **options)
323
323
  end
324
-
324
+ def scene
325
+ session[:telegem_scene]&.[](:id)
326
+ end
327
+ def ask(question, **options)
328
+ scene_data = session[:telegem_scene]
329
+ if scene_data
330
+ scene_data[:waiting_for_response] = true
331
+ scene_data[:last_question] = question
332
+ end
333
+ reply(question, **options)
334
+ end
335
+ def scene_data
336
+ @session[:telegem_scene]&.[](:data) || {}
337
+ end
338
+ def current_scene
339
+ @session[:telegem_scene]&.[](:id)
340
+ end
341
+ def in_scene?
342
+ !current_scene.nil?
343
+ end
344
+ def leave_scene(**options)
345
+ scene_data = @session[:telegem_scene]
346
+ return unless scene_data
347
+ scene_id = scene_data[:id].to_sym
348
+ scene = @bot.scenes[scene_id]
349
+ result = scene&.leave(self, options[:reason] || :manual)
350
+ @session.delete(:telegem_scene)
351
+ @scene = nil
352
+ result
353
+ end
354
+ def next_step(step_name = nil)
355
+ scene_data = @session[:telegem_scene]
356
+ return unless scene_data
357
+ scene_id = scene_data[:id].to_sym
358
+ scene = @bot.scenes[scene_id]
359
+ scene&.next_step(self, step_name)
360
+ end
325
361
  def with_typing(&block)
326
362
  typing_request = typing
327
363
 
@@ -339,23 +375,12 @@ module Telegem
339
375
  end
340
376
 
341
377
  def enter_scene(scene_name, **options)
342
- return nil unless @bot.scenes[scene_name]
343
-
344
- @scene = scene_name
345
- @bot.scenes[scene_name].enter(self, **options)
346
- end
347
-
348
- def leave_scene(**options)
349
- return nil unless @scene && @bot.scenes[@scene]
350
-
351
- scene_name = @scene
352
- @scene = nil
353
- @bot.scenes[scene_name].leave(self, **options)
354
- end
355
-
356
- def current_scene
357
- @bot.scenes[@scene] if @scene
358
- end
378
+ scene = @bot.scenes[scene_name]
379
+ return nil unless scene
380
+ leave_scene if in_scene?
381
+ scene.enter(self, options[:step], options.except(:step))
382
+ scene_name
383
+ end
359
384
 
360
385
  def logger
361
386
  @bot.logger
@@ -0,0 +1,100 @@
1
+
2
+ module Telegem
3
+ class RateLimit
4
+ def initialize(**options)
5
+ @options = {
6
+ global: { max: 30, per: 1 }, # 30 reqs/second globally
7
+ user: { max: 5, per: 10 }, # 5 reqs/10 seconds per user
8
+ chat: { max: 20, per: 60 } # 20 reqs/minute per chat
9
+ }.merge(options)
10
+
11
+ @counters = {
12
+ global: Telegem::Session::MemoryStore.new,
13
+ user: Telegem::Session::MemoryStore.new,
14
+ chat: Telegem::Session::MemoryStore.new
15
+ }
16
+ end
17
+
18
+ def call(ctx, next_middleware)
19
+ return next_middleware.call(ctx) unless should_rate_limit?(ctx)
20
+
21
+ if limit_exceeded?(ctx)
22
+ ctx.logger&.warn("Rate limit exceeded for #{ctx.from&.id}")
23
+ return rate_limit_response(ctx)
24
+ end
25
+
26
+ increment_counters(ctx)
27
+ next_middleware.call(ctx)
28
+ end
29
+
30
+ private
31
+
32
+ def should_rate_limit?(ctx)
33
+
34
+ return false if ctx.update.poll?
35
+ return false if ctx.update.chat_member?
36
+ return true
37
+ end
38
+
39
+ def limit_exceeded?(ctx)
40
+ global_limit?(ctx) || user_limit?(ctx) || chat_limit?(ctx)
41
+ end
42
+
43
+ def global_limit?(ctx)
44
+ check_limit(:global, "global", ctx)
45
+ end
46
+
47
+ def user_limit?(ctx)
48
+ return false unless ctx.from&.id
49
+ check_limit(:user, "user:#{ctx.from.id}", ctx)
50
+ end
51
+
52
+ def chat_limit?(ctx)
53
+ return false unless ctx.chat&.id
54
+ check_limit(:chat, "chat:#{ctx.chat.id}", ctx)
55
+ end
56
+
57
+ def check_limit(type, key, ctx)
58
+ limit = @options[type]
59
+ return false unless limit
60
+
61
+ counter = @counters[type].get(key) || 0
62
+ counter >= limit[:max]
63
+ end
64
+
65
+ def increment_counters(ctx)
66
+ now = Time.now.to_i
67
+
68
+
69
+ if @options[:global]
70
+ key = "global"
71
+ cleanup_counter(:global, key, now)
72
+ @counters[:global].increment(key, 1, ttl: @options[:global][:per])
73
+ end
74
+
75
+
76
+ if @options[:user] && ctx.from&.id
77
+ key = "user:#{ctx.from.id}"
78
+ cleanup_counter(:user, key, now)
79
+ @counters[:user].increment(key, 1, ttl: @options[:user][:per])
80
+ end
81
+
82
+
83
+ if @options[:chat] && ctx.chat&.id
84
+ key = "chat:#{ctx.chat.id}"
85
+ cleanup_counter(:chat, key, now)
86
+ @counters[:chat].increment(key, 1, ttl: @options[:chat][:per])
87
+ end
88
+ end
89
+
90
+ def cleanup_counter(type, key, now)
91
+
92
+ end
93
+
94
+ def rate_limit_response(ctx)
95
+
96
+ ctx.reply("⏳ Please wait a moment before sending another request.") rescue nil
97
+ nil
98
+ end
99
+ end
100
+ end
data/lib/core/scene.rb CHANGED
@@ -1,90 +1,157 @@
1
- # lib/core/scene.rb - HTTPX VERSION (NO ASYNC GEM)
1
+
2
2
  module Telegem
3
3
  module Core
4
4
  class Scene
5
5
  attr_reader :id, :steps, :enter_callbacks, :leave_callbacks
6
-
6
+
7
7
  def initialize(id, default_step: :start, &block)
8
8
  @id = id
9
9
  @steps = {}
10
10
  @enter_callbacks = []
11
11
  @leave_callbacks = []
12
12
  @default_step = default_step
13
+ @timeout = 300 # 5 minutes default timeout
14
+
13
15
  instance_eval(&block) if block_given?
14
16
  end
15
-
17
+
16
18
  def step(name, &action)
17
19
  @steps[name.to_sym] = action
18
20
  self
19
21
  end
20
-
22
+
21
23
  def on_enter(&callback)
22
24
  @enter_callbacks << callback
23
25
  self
24
26
  end
25
-
27
+
26
28
  def on_leave(&callback)
27
29
  @leave_callbacks << callback
28
30
  self
29
31
  end
30
-
31
- def enter(ctx, step_name = nil)
32
+
33
+ def timeout(seconds)
34
+ @timeout = seconds
35
+ self
36
+ end
37
+
38
+
39
+ def enter(ctx, step_name = nil, **initial_data)
32
40
  step_name ||= @default_step
33
41
 
34
- # Store scene state in context
35
- ctx.scene = { id: @id, step: step_name.to_sym }
42
+
43
+ ctx.session[:telegem_scene] = {
44
+ id: @id.to_s,
45
+ step: step_name.to_s,
46
+ data: initial_data,
47
+ entered_at: Time.now.to_i,
48
+ timeout: @timeout,
49
+ waiting_for_response: false,
50
+ last_question: nil
51
+ }
36
52
 
37
- # Run enter callbacks
53
+ ctx.instance_variable_set(:@current_scene, self)
54
+
38
55
  @enter_callbacks.each { |cb| cb.call(ctx) }
39
56
 
40
- # Enter the first step
41
- process_step(ctx, step_name)
42
- end
43
57
 
44
- def leave(ctx)
45
- # Run leave callbacks
46
- @leave_callbacks.each { |cb| cb.call(ctx) }
47
-
48
- # Clear scene from context
49
- ctx.scene = nil
50
- nil
58
+ execute_step(ctx, step_name)
51
59
  end
60
+
52
61
 
53
- def process_step(ctx, step_name)
54
- step = @steps[step_name.to_sym]
62
+ def process(ctx)
63
+ scene_data = ctx.session[:telegem_scene]
64
+ return unless scene_data
55
65
 
56
- unless step
57
- ctx.logger.error("Unknown step #{step_name} in scene #{@id}")
58
- return nil
66
+
67
+ if Time.now.to_i - scene_data[:entered_at] > scene_data[:timeout]
68
+ leave(ctx, :timeout)
69
+ return
59
70
  end
60
71
 
61
- # Execute the step
62
- result = step.call(ctx)
63
-
64
- # Update step in context (unless step changed it)
65
- if ctx.scene && ctx.scene[:id] == @id
66
- ctx.scene[:step] = step_name.to_sym
72
+ if scene_data[:waiting_for_response] && ctx.message&.text
73
+ process_response(ctx, scene_data)
74
+ else
75
+
76
+ execute_step(ctx, scene_data[:step])
67
77
  end
78
+ end
79
+
80
+ def leave(ctx, reason = :manual)
81
+ scene_data = ctx.session.delete(:telegem_scene)
82
+ ctx.instance_variable_set(:@current_scene, nil)
68
83
 
69
- result
70
- rescue => e
71
- ctx.logger.error("Error processing step #{step_name} in scene #{@id}: #{e.message}")
72
- ctx.logger.error(e.backtrace.join("\n")) if e.backtrace
73
- nil
84
+
85
+ @leave_callbacks.each { |cb| cb.call(ctx, reason, scene_data[:data]) }
86
+
87
+ scene_data[:data]
74
88
  end
89
+
75
90
 
76
91
  def current_step(ctx)
77
- return nil unless ctx.scene && ctx.scene[:id] == @id
78
- ctx.scene[:step]
92
+ scene_data = ctx.session[:telegem_scene]
93
+ scene_data[:step] if scene_data
94
+ end
95
+
96
+
97
+ def scene_data(ctx)
98
+ ctx.session[:telegem_scene]&.[](:data) || {}
79
99
  end
100
+
101
+ private
80
102
 
81
- def reset(ctx)
82
- ctx.scene = { id: @id, step: @default_step }
83
- self
103
+ def execute_step(ctx, step_name)
104
+ action = @steps[step_name.to_sym]
105
+ return leave(ctx, :invalid_step) unless action
106
+
107
+ scene_data = ctx.session[:telegem_scene]
108
+ scene_data[:step] = step_name.to_s
109
+ scene_data[:waiting_for_response] = false
110
+ scene_data[:last_question] = nil
111
+
112
+
113
+ result = action.call(ctx, scene_data[:data])
114
+
115
+
116
+ if result.is_a?(Symbol) || result.is_a?(String)
117
+ next_step(ctx, result)
118
+ end
119
+
120
+ result
84
121
  end
122
+
123
+
124
+ def process_response(ctx, scene_data)
85
125
 
86
- def to_s
87
- "#<Scene #{@id}>"
126
+ current_step_name = scene_data[:step]
127
+ scene_data[:data][current_step_name] = ctx.message.text
128
+
129
+
130
+ scene_data[:waiting_for_response] = false
131
+
132
+ next_step(ctx)
133
+ end
134
+
135
+
136
+ def next_step(ctx, specific_step = nil)
137
+ scene_data = ctx.session[:telegem_scene]
138
+ return unless scene_data
139
+
140
+ current_step = scene_data[:step].to_sym
141
+ step_names = @steps.keys
142
+
143
+ if specific_step
144
+ next_step_name = specific_step.to_sym
145
+ else
146
+ current_index = step_names.index(current_step)
147
+ next_step_name = step_names[current_index + 1] if current_index
148
+ end
149
+
150
+ if next_step_name
151
+ execute_step(ctx, next_step_name)
152
+ else
153
+ leave(ctx, :completed)
154
+ end
88
155
  end
89
156
  end
90
157
  end
File without changes
@@ -0,0 +1,127 @@
1
+ require 'open-uri'
2
+ require 'tempfile'
3
+ require 'pdf-reader'
4
+ require 'docx'
5
+
6
+ module Telegem
7
+ module Plugins
8
+ class FileExtractor
9
+ SUPPORTED_TYPES = {
10
+ pdf: 'application/pdf',
11
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
12
+ txt: 'text/plain',
13
+ csv: 'text/csv',
14
+ html: 'text/html',
15
+ rtf: 'application/rtf',
16
+ odt: 'application/vnd.oasis.opendocument.text'
17
+ }
18
+
19
+ def initialize(**options)
20
+ @options = {
21
+ max_size: 10 * 1024 * 1024,
22
+ timeout: 30,
23
+ cache: true
24
+ }.merge(options)
25
+
26
+ @cache = Telegem::Session::MemoryStore.new
27
+ end
28
+
29
+ def call(ctx, next_middleware)
30
+ ctx.define_singleton_method(:extract_file_text) do |file_id = nil, **opts|
31
+ extract_from_context(self, file_id, opts)
32
+ end
33
+
34
+ ctx.define_singleton_method(:file_content) do
35
+ @_file_content
36
+ end
37
+
38
+ ctx.define_singleton_method(:file_metadata) do
39
+ @_file_metadata
40
+ end
41
+
42
+ next_middleware.call(ctx)
43
+ end
44
+
45
+ class << self
46
+ def extract_from_context(ctx, file_id = nil, **options)
47
+ message = ctx.update.message
48
+ return nil unless message
49
+
50
+ file_info = find_file_info(message, file_id)
51
+ return nil unless file_info
52
+
53
+ return file_info[:content] if file_info[:type] == :text
54
+
55
+ file_path = download_file(ctx.bot.api, file_info[:file_id], options)
56
+ return nil unless file_path
57
+
58
+ text = extract_text(file_path, file_info[:type])
59
+
60
+ if options.fetch(:cache, true)
61
+ ctx.instance_variable_set(:@_file_content, text)
62
+ ctx.instance_variable_set(:@_file_metadata, file_info)
63
+ end
64
+
65
+ text
66
+ end
67
+
68
+ private
69
+
70
+ def find_file_info(message, file_id)
71
+ return { file_id: file_id, type: :unknown } if file_id
72
+
73
+ if message.document
74
+ mime = message.document.mime_type || 'application/octet-stream'
75
+ type = SUPPORTED_TYPES.key(mime) || :unknown
76
+ { file_id: message.document.file_id, type: type, mime: mime, name: message.document.file_name }
77
+ elsif message.photo&.any?
78
+ { file_id: message.photo.last.file_id, type: :image, mime: 'image/jpeg' }
79
+ elsif message.video
80
+ { file_id: message.video.file_id, type: :video, mime: message.video.mime_type }
81
+ elsif message.audio
82
+ { file_id: message.audio.file_id, type: :audio, mime: message.audio.mime_type }
83
+ elsif message.voice
84
+ { file_id: message.voice.file_id, type: :audio, mime: 'audio/ogg' }
85
+ elsif message.text
86
+ { type: :text, content: message.text }
87
+ end
88
+ end
89
+
90
+ def download_file(api, file_id, options)
91
+ file = api.call('getFile', file_id: file_id)
92
+ return nil unless file && file['ok']
93
+
94
+ file_path = file['result']['file_path']
95
+ url = "https://api.telegram.org/file/bot#{api.token}/#{file_path}"
96
+
97
+ temp_file = Tempfile.new(['telegem', File.extname(file_path)])
98
+
99
+ URI.open(url, read_timeout: options[:timeout] || 30) do |remote|
100
+ temp_file.binmode
101
+ temp_file.write(remote.read)
102
+ end
103
+
104
+ temp_file.close
105
+ temp_file.path
106
+ rescue => e
107
+ nil
108
+ end
109
+
110
+ def extract_text(file_path, type)
111
+ case type
112
+ when :pdf
113
+ PDF::Reader.new(file_path).pages.map(&:text).join("\n")
114
+ when :docx
115
+ Docx::Document.open(file_path).text
116
+ when :txt, :html, :csv, :rtf, :odt
117
+ File.read(file_path, encoding: 'utf-8')
118
+ else
119
+ ""
120
+ end
121
+ rescue => e
122
+ "Error: #{e.message}"
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module Telegem
3
+ module Scene
4
+ class Middleware
5
+ def call(ctx, next_middleware)
6
+ # Check if user is in a scene
7
+ if ctx.session[:telegem_scene]
8
+ scene_data = ctx.session[:telegem_scene]
9
+ scene = ctx.bot.scenes[scene_data[:id].to_sym]
10
+
11
+ if scene
12
+ # Let scene handle it
13
+ scene.process(ctx)
14
+ return # Don't call regular handlers
15
+ end
16
+ end
17
+
18
+ # Not in scene, proceed normally
19
+ next_middleware.call(ctx)
20
+ end
21
+ end
22
+ end
23
+ end
data/lib/telegem.rb CHANGED
@@ -3,7 +3,7 @@ require 'logger'
3
3
  require 'json'
4
4
 
5
5
  module Telegem
6
- VERSION = "3.0.6".freeze
6
+ VERSION = "3.1.0".freeze
7
7
  end
8
8
 
9
9
  # Load core components
@@ -17,6 +17,8 @@ require_relative 'session/middleware'
17
17
  require_relative 'session/memory_store'
18
18
  require_relative 'markup/keyboard'
19
19
  # Webhook is loaded lazily when needed
20
+ require_relative 'plugins/file_extract'
21
+ require_relative 'session/scene_middleware'
20
22
 
21
23
  module Telegem
22
24
  # Main entry point: Telegem.new(token)
@@ -80,4 +82,4 @@ if ENV['TELEGEM_GLOBAL'] == 'true'
80
82
  def Telegem(token, **options)
81
83
  ::Telegem.new(token, **options)
82
84
  end
83
- end
85
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: telegem
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.6
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sick_phantom
@@ -13,98 +13,72 @@ dependencies:
13
13
  name: httpx
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 1.7.0
18
+ version: '0'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 1.7.0
25
+ version: '0'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: concurrent-ruby
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '1.2'
32
+ version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '1.2'
39
+ version: '0'
40
40
  - !ruby/object:Gem::Dependency
41
- name: rack
41
+ name: async
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '2.0'
47
- - - "<"
48
- - !ruby/object:Gem::Version
49
- version: '4.0'
46
+ version: '0'
50
47
  type: :runtime
51
48
  prerelease: false
52
49
  version_requirements: !ruby/object:Gem::Requirement
53
50
  requirements:
54
51
  - - ">="
55
52
  - !ruby/object:Gem::Version
56
- version: '2.0'
57
- - - "<"
58
- - !ruby/object:Gem::Version
59
- version: '4.0'
53
+ version: '0'
60
54
  - !ruby/object:Gem::Dependency
61
- name: puma
55
+ name: pdf-reader
62
56
  requirement: !ruby/object:Gem::Requirement
63
57
  requirements:
64
58
  - - ">="
65
59
  - !ruby/object:Gem::Version
66
- version: '5.0'
67
- - - "<"
68
- - !ruby/object:Gem::Version
69
- version: '7.0'
60
+ version: '0'
70
61
  type: :runtime
71
62
  prerelease: false
72
63
  version_requirements: !ruby/object:Gem::Requirement
73
64
  requirements:
74
65
  - - ">="
75
66
  - !ruby/object:Gem::Version
76
- version: '5.0'
77
- - - "<"
78
- - !ruby/object:Gem::Version
79
- version: '7.0'
67
+ version: '0'
80
68
  - !ruby/object:Gem::Dependency
81
- name: async
69
+ name: docx
82
70
  requirement: !ruby/object:Gem::Requirement
83
71
  requirements:
84
- - - "~>"
72
+ - - ">="
85
73
  - !ruby/object:Gem::Version
86
- version: '2.1'
74
+ version: '0'
87
75
  type: :runtime
88
76
  prerelease: false
89
77
  version_requirements: !ruby/object:Gem::Requirement
90
78
  requirements:
91
- - - "~>"
92
- - !ruby/object:Gem::Version
93
- version: '2.1'
94
- - !ruby/object:Gem::Dependency
95
- name: rake
96
- requirement: !ruby/object:Gem::Requirement
97
- requirements:
98
- - - "~>"
99
- - !ruby/object:Gem::Version
100
- version: '13.0'
101
- type: :development
102
- prerelease: false
103
- version_requirements: !ruby/object:Gem::Requirement
104
- requirements:
105
- - - "~>"
79
+ - - ">="
106
80
  - !ruby/object:Gem::Version
107
- version: '13.0'
81
+ version: '0'
108
82
  - !ruby/object:Gem::Dependency
109
83
  name: rspec
110
84
  requirement: !ruby/object:Gem::Requirement
@@ -119,34 +93,6 @@ dependencies:
119
93
  - - "~>"
120
94
  - !ruby/object:Gem::Version
121
95
  version: '3.12'
122
- - !ruby/object:Gem::Dependency
123
- name: simplecov
124
- requirement: !ruby/object:Gem::Requirement
125
- requirements:
126
- - - "~>"
127
- - !ruby/object:Gem::Version
128
- version: '0.22'
129
- type: :development
130
- prerelease: false
131
- version_requirements: !ruby/object:Gem::Requirement
132
- requirements:
133
- - - "~>"
134
- - !ruby/object:Gem::Version
135
- version: '0.22'
136
- - !ruby/object:Gem::Dependency
137
- name: webmock
138
- requirement: !ruby/object:Gem::Requirement
139
- requirements:
140
- - - "~>"
141
- - !ruby/object:Gem::Version
142
- version: '3.18'
143
- type: :development
144
- prerelease: false
145
- version_requirements: !ruby/object:Gem::Requirement
146
- requirements:
147
- - - "~>"
148
- - !ruby/object:Gem::Version
149
- version: '3.18'
150
96
  - !ruby/object:Gem::Dependency
151
97
  name: rubocop
152
98
  requirement: !ruby/object:Gem::Requirement
@@ -197,11 +143,15 @@ files:
197
143
  - lib/core/bot.rb
198
144
  - lib/core/composer.rb
199
145
  - lib/core/context.rb
146
+ - lib/core/rate_limit.rb
200
147
  - lib/core/scene.rb
201
148
  - lib/markup/.gitkeep
202
149
  - lib/markup/keyboard.rb
150
+ - lib/plugins/.gitkeep
151
+ - lib/plugins/file_extract.rb
203
152
  - lib/session/memory_store.rb
204
153
  - lib/session/middleware.rb
154
+ - lib/session/scene_middleware.rb
205
155
  - lib/telegem.rb
206
156
  - lib/webhook/.gitkeep
207
157
  - lib/webhook/server.rb
@@ -216,7 +166,7 @@ metadata:
216
166
  bug_tracker_uri: https://gitlab.com/ruby-telegem/telegem/-/issues
217
167
  documentation_uri: https://gitlab.com/ruby-telegem/telegem/-/tree/main/docs-src?ref_type=heads
218
168
  rubygems_mfa_required: 'false'
219
- post_install_message: "Thanks for installing Telegem 3.0.6!\n\n\U0001F4DA Documentation:
169
+ post_install_message: "Thanks for installing Telegem 3.1.0!\n\n\U0001F4DA Documentation:
220
170
  https://gitlab.com/ruby-telegem/telegem\n\n\U0001F510 For SSL Webhooks:\nRun: telegem-ssl
221
171
  your-domain.com\nThis sets up Let's Encrypt certificates automatically.\n\n\U0001F916
222
172
  Happy bot building!\n"