<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: slick phantom</title>
    <description>The latest articles on Forem by slick phantom (@slick_phantom).</description>
    <link>https://forem.com/slick_phantom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3638290%2F8521d9b6-6d09-489f-b40f-98aeaa0426f7.jpeg</url>
      <title>Forem: slick phantom</title>
      <link>https://forem.com/slick_phantom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/slick_phantom"/>
    <language>en</language>
    <item>
      <title>From Ruby to Crystal: Why I ported telegem to telecr</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Wed, 15 Apr 2026 10:30:22 +0000</pubDate>
      <link>https://forem.com/slick_phantom/from-ruby-to-crystal-why-i-ported-telegem-to-telecr-29m</link>
      <guid>https://forem.com/slick_phantom/from-ruby-to-crystal-why-i-ported-telegem-to-telecr-29m</guid>
      <description>&lt;p&gt;After my work on &lt;strong&gt;telegem&lt;/strong&gt; (a Ruby gem for creating DSLs), I began to notice the stark differences between interpreted and compiled languages. &lt;/p&gt;

&lt;p&gt;Ruby is fast, but for high-concurrency needs like Telegram bots, I wanted to see what &lt;strong&gt;Crystal&lt;/strong&gt; could do. To my surprise, porting the logic worked beautifully. Today, I’m excited to announce &lt;strong&gt;telecr&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Telecr?
&lt;/h2&gt;

&lt;p&gt;Telecr is a fast, fiber-based library for creating Telegram bots in Crystal. Think of it as &lt;strong&gt;telegem&lt;/strong&gt; with superpowers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blazing Fast:&lt;/strong&gt; Leverages Crystal's performance and fiber-based concurrency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safe:&lt;/strong&gt; Catch errors at compile time before they hit production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disk Backup:&lt;/strong&gt; Reliable data handling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean DSL:&lt;/strong&gt; Designed for a great developer experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Look at the DSL
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt; &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; 
   &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"welcome"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Join the Project
&lt;/h2&gt;

&lt;p&gt;I'm officially opening this up for contributions and improvements! You can find the source code and documentation here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/slick-lab" rel="noopener noreferrer"&gt;
        slick-lab
      &lt;/a&gt; / &lt;a href="https://github.com/slick-lab/telecr" rel="noopener noreferrer"&gt;
        telecr
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A modern fiber based crystal framework for create telegram bots 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Telecr&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Telegram bot framework for Crystal. Inspired by telegem (Ruby).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitlab.com/telegem-cr/telecr/-/pipelines" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/754a7117bacdd1bc0a1ec36ac12560458e29e4117277e7218bd76a4f61756511/68747470733a2f2f6769746c61622e636f6d2f74656c6567656d2d63722f74656c6563722f6261646765732f6d61696e2f706970656c696e652e737667" alt="Pipeline Status"&gt;&lt;/a&gt;
&lt;a href="https://gitlab.com/telegem-cr/telecr/-/jobs" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7048465af4c7cf561c9a8ea2c08c4ffc8d910e9dae556b4ccb46aabfae05028a/68747470733a2f2f6769746c61622e636f6d2f74656c6567656d2d63722f74656c6563722f6261646765732f6d61696e2f636f7665726167652e737667" alt="Coverage"&gt;&lt;/a&gt;
&lt;a href="https://gitlab.com/telegem-cr/telecr/-/releases" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ffc6cad9864aa86680af6b5937defffa8ece46783321fa3aab567f52b4b88e09/68747470733a2f2f6769746c61622e636f6d2f74656c6567656d2d63722f74656c6563722f2d2f6261646765732f72656c656173652e737667" alt="Latest Release"&gt;&lt;/a&gt;
&lt;a href="https://crystal-lang.org" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f46a981a992e98567768f42816efea994d39c1db57ea30625e53982476ac7f1b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6372797374616c2d312e302b2d626c61636b" alt="Crystal"&gt;&lt;/a&gt;
&lt;a href="https://opensource.org/licenses/MIT" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fdf2982b9f5d7489dcf44570e714e3a15fce6253e0cc6b5aa61a075aac2ff71b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d79656c6c6f772e737667" alt="License: MIT"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Documentation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Full API documentation is available at: &lt;a href="https://telecr-f83754.gitlab.io" rel="nofollow noopener noreferrer"&gt;https://telecr.gitlab.io&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Add to your &lt;code&gt;shard.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-ent"&gt;dependencies&lt;/span&gt;:
  &lt;span class="pl-ent"&gt;telecr&lt;/span&gt;:
    &lt;span class="pl-ent"&gt;github&lt;/span&gt;: &lt;span class="pl-s"&gt;slick-lab/telecr&lt;/span&gt;
    &lt;span class="pl-ent"&gt;version&lt;/span&gt;: &lt;span class="pl-s"&gt;~&amp;gt; 1.0.0&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;shards install&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Quick Start&lt;/p&gt;
&lt;div class="highlight highlight-source-crystal notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;require&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;telecr&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;

bot &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;Telecr&lt;/span&gt;.new(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;YOUR_BOT_TOKEN&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)

bot.command(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;start&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;) &lt;span class="pl-k"&gt;do&lt;/span&gt; |&lt;span class="pl-smi"&gt;ctx&lt;/span&gt;|
  ctx.reply(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Welcome to Telecr!&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&lt;span class="pl-k"&gt;end&lt;/span&gt;

bot.start_polling&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Features&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full Telegram Bot API support&lt;/li&gt;
&lt;li&gt;Polling and webhook modes&lt;/li&gt;
&lt;li&gt;Middleware system (session, rate limiting, file upload)&lt;/li&gt;
&lt;li&gt;Reply and inline keyboards&lt;/li&gt;
&lt;li&gt;Type-safe context objects&lt;/li&gt;
&lt;li&gt;Session management with disk backup&lt;/li&gt;
&lt;li&gt;File upload to shrine storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Usage&lt;/p&gt;
&lt;p&gt;Basic Bot&lt;/p&gt;
&lt;div class="highlight highlight-source-crystal notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;bot &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;Telecr&lt;/span&gt;.new(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;TOKEN&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)

bot.command(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;start&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;) &lt;span class="pl-k"&gt;do&lt;/span&gt; |&lt;span class="pl-smi"&gt;ctx&lt;/span&gt;|
  ctx.reply(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Hello! I'm a Telecr bot.&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&lt;span class="pl-k"&gt;end&lt;/span&gt;

bot.hears(&lt;span class="pl-sr"&gt;/hi/i&lt;/span&gt;) &lt;span class="pl-k"&gt;do&lt;/span&gt; |&lt;span class="pl-smi"&gt;ctx&lt;/span&gt;|
  ctx.reply(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;Hi there!&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&lt;span class="pl-k"&gt;end&lt;/span&gt;

bot.start_polling&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/slick-lab/telecr" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;I'm curious—have any of you moved a project from Ruby to Crystal? What was your biggest "aha!" moment during the port?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>crystal</category>
      <category>telegram</category>
      <category>showdev</category>
    </item>
    <item>
      <title>From Ruby to Crystal a detailed guide</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Sun, 15 Mar 2026 12:04:08 +0000</pubDate>
      <link>https://forem.com/youngsoftwaredev/from-ruby-to-crystal-a-detailed-guide-3dde</link>
      <guid>https://forem.com/youngsoftwaredev/from-ruby-to-crystal-a-detailed-guide-3dde</guid>
      <description>&lt;p&gt;I love Ruby. I still maintain telegem, a Telegram bot framework used by real people. Ruby pays my bills and makes me happy.&lt;/p&gt;

&lt;p&gt;But I also wanted speed. I wanted binaries. I wanted to stop debugging "undefined method for nil" at 3 AM.&lt;/p&gt;

&lt;p&gt;So I tried Crystal.&lt;/p&gt;

&lt;p&gt;It looked just like Ruby. I was confident. Then the compiler yelled at me. For days. For weeks. For 64 failed pipelines.&lt;/p&gt;

&lt;p&gt;This guide is what I wish I had on day one.&lt;/p&gt;

&lt;p&gt;The Complete Guide: Ruby to Crystal&lt;/p&gt;

&lt;p&gt;I just published a comprehensive, free guide for Rubyists moving to Crystal. It covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Quick Comparison - The "looks the same" trap&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Side-by-side code examples showing where Ruby and Crystal diverge. Read →&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &amp;amp;. Problem - Why your favorite operator will fight you&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How safe navigation works (and doesn't work) in Crystal, and the reliable patterns that always compile. Read →&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Type System - Friend, not foe&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Understanding union types, nil checking, and why the compiler is actually saving you. Read →&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hashes &amp;amp; Collections - NamedTuples will surprise you&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The three ways to store data in Crystal and when to use each. Read →&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Classes &amp;amp; Modules - Same but different&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instance variables, property shortcuts, and why self. sometimes saves the day. Read →&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Require Order - The dependency dance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why order matters and how to structure your project to avoid headaches. Read →&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Common Errors Decoded - What the compiler is actually saying&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A translator for those scary error messages. Read →&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why Crystal - The case for switching&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Performance, safety, and peace of mind. Read →&lt;/p&gt;

&lt;p&gt;🛠 Projects Built While Learning&lt;/p&gt;

&lt;p&gt;The guide is free, but if you want to see real Crystal code, check out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tg-auth - Telegram authentication for Crystal&lt;/li&gt;
&lt;li&gt;telecr - Telegram bot framework (the Crystal version of telegem)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📖 Read the Guide&lt;/p&gt;

&lt;p&gt;GitHub Repo: slick-phantom/ruby-crystal&lt;/p&gt;

&lt;p&gt;The guide is completely free, open source, and ready for contributions. If you find something confusing, open an issue. If you want to improve it, send a PR.&lt;/p&gt;




&lt;p&gt;Ruby gave me joy. Crystal gives me peace&lt;/p&gt;

</description>
      <category>learning</category>
      <category>performance</category>
      <category>ruby</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I got tired or rewriting the same blog backend so I created a solution</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Sun, 01 Mar 2026 10:28:35 +0000</pubDate>
      <link>https://forem.com/slick_phantom/i-got-tired-or-rewriting-the-same-blog-backend-so-i-created-a-solution-55ga</link>
      <guid>https://forem.com/slick_phantom/i-got-tired-or-rewriting-the-same-blog-backend-so-i-created-a-solution-55ga</guid>
      <description>&lt;p&gt;Inkwell v0.1 — A lightweight, binary-compiled blog engine for developers who just want to ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;A client asked me to build a blog site. Cool. Built it.&lt;/p&gt;

&lt;p&gt;Another client asked. Same thing. Built it again.&lt;/p&gt;

&lt;p&gt;Third time? I caught myself writing the &lt;strong&gt;same create/post/delete/admin logic&lt;/strong&gt; from scratch. Again.&lt;/p&gt;

&lt;p&gt;I thought: &lt;em&gt;There has to be a better way.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Search
&lt;/h2&gt;

&lt;p&gt;I went looking. Surely someone has solved this.&lt;/p&gt;

&lt;p&gt;Found some stuff on GitHub. Looked promising until I dug deeper.&lt;/p&gt;

&lt;p&gt;Good features? Locked behind paywalls.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Blog engine shouldn't be paid for.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So I decided to build one myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Build
&lt;/h2&gt;

&lt;p&gt;I needed something:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compiled to binary&lt;/strong&gt; — runs anywhere, no dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt; — no slow interpreted stuff&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No bloat&lt;/strong&gt; — does one thing well&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Started with Go. Made sense. But I was still learning and progress was slow.&lt;/p&gt;

&lt;p&gt;Switched to Dart. Things clicked. Built the core logic. Struggled through some parts. Learned a ton. Kept going.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Inkwell v0.1
&lt;/h2&gt;

&lt;p&gt;It's basic. It's buggy. &lt;strong&gt;It works.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; &lt;span class="s2"&gt;"https://gitlab.com/dart.co/inkwell/-/raw/main/install.sh"&lt;/span&gt; | bash
./inkwell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First run generates an admin token. Save it. Use it for X-API-KEY headers.&lt;/p&gt;

&lt;p&gt;What It Does&lt;/p&gt;

&lt;p&gt;For readers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET /posts — list all blog posts (reads from posts/ folder)

&lt;ul&gt;
&lt;li&gt;GET /posts/:slug — get a single post as markdown&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;GET /search?q=query — search posts by filename and content&lt;/li&gt;

&lt;li&gt;GET /feed.xml — RSS feed&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For you (admin):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;POST /admin/posts — create new post&lt;/li&gt;
&lt;li&gt;PUT /admin/posts/:slug — update post&lt;/li&gt;
&lt;li&gt;DELETE /admin/posts/:slug — delete post&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All admin endpoints need your X-API-KEY.&lt;/p&gt;

&lt;p&gt;How It Works&lt;/p&gt;

&lt;p&gt;send posts to the create endpoint or read the Readme&lt;/p&gt;

&lt;p&gt;The API reads them, serves them, searches them. No database. No config. No paywall.&lt;/p&gt;

&lt;p&gt;The Current State&lt;/p&gt;

&lt;p&gt;v0.1 is a prototype. I'll be honest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Core features work (create, read, search, RSS)&lt;/li&gt;
&lt;li&gt;⚠️ Storage is just files (not fully safe, but lightweight)
-🐛 It's buggy in places&lt;/li&gt;
&lt;li&gt;🔧 Better storage solution coming in future versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for a solo dev who just wants to blog without the bloat? It gets the job done.&lt;/p&gt;

&lt;p&gt;What's Next&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix the bugs (help welcome!)&lt;/li&gt;
&lt;li&gt;Find a better storage solution (keeping it lightweight)&lt;/li&gt;
&lt;li&gt;Stable v1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try It&lt;br&gt;
&lt;a href="https://gitlab.com/dart.co/inkwell" rel="noopener noreferrer"&gt;git&lt;/a&gt;&lt;br&gt;
Star it if you like the idea. Open issues if you find bugs. PRs if you want to help.&lt;/p&gt;

&lt;p&gt;Or just use it and tell me what sucks. I can take it.&lt;/p&gt;

&lt;p&gt;Built because rewriting the same code three times is two times too many.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>blog</category>
      <category>backend</category>
    </item>
    <item>
      <title>Ubuntu: From "Linux for Human Beings" to "Linux for People with Fiber Optics"</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Mon, 16 Feb 2026 11:12:57 +0000</pubDate>
      <link>https://forem.com/slick_phantom/ubuntu-from-linux-for-human-beings-to-linux-for-people-with-fiber-optics-2jkp</link>
      <guid>https://forem.com/slick_phantom/ubuntu-from-linux-for-human-beings-to-linux-for-people-with-fiber-optics-2jkp</guid>
      <description>&lt;p&gt;I've been using Ubuntu for a while now. It was my first Linux distro — the one everyone recommended. "It just works," they said.&lt;/p&gt;

&lt;p&gt;It doesn't anymore.&lt;/p&gt;




&lt;p&gt;What Used to Be Good&lt;/p&gt;

&lt;p&gt;Remember when installing software was simple?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;spotify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. Done. No drama.&lt;/p&gt;

&lt;p&gt;Ubuntu was the gateway drug to Linux. It was intuitive. It respected that not everyone has Google Fiber.&lt;/p&gt;




&lt;p&gt;What Changed&lt;/p&gt;

&lt;p&gt;Now try installing Spotify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;snap &lt;span class="nb"&gt;install &lt;/span&gt;spotify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks simple. But behind the scenes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;core20 (20.04) 2024-05-07 from Canonical✓ downloaded
Wait... still downloading...
Error: Network failure
Retry? [y/N]:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your internet fails during download? Start over from scratch.&lt;/p&gt;




&lt;p&gt;The Runtime Nightmare&lt;/p&gt;

&lt;p&gt;Every Snap app brings its own runtime baggage:&lt;/p&gt;

&lt;p&gt;· Telegram needs core18&lt;br&gt;
· Spotify needs core20&lt;br&gt;
· VLC needs core22&lt;br&gt;
· Something else needs core24&lt;/p&gt;

&lt;p&gt;That's four copies of essentially the same thing. Hundreds of megabytes each. Duplicated. Wasted.&lt;/p&gt;

&lt;p&gt;My system now has multiple core runtimes taking up space. For what? So Canonical can push Snap?&lt;/p&gt;




&lt;p&gt;Who Is This For?&lt;/p&gt;

&lt;p&gt;The current Ubuntu experience assumes:&lt;/p&gt;

&lt;p&gt;· ✅ Fast, unlimited internet&lt;br&gt;
· ✅ New hardware with storage to waste&lt;br&gt;
· ✅ Time to troubleshoot failed downloads&lt;br&gt;
· ✅ No concern about data costs&lt;/p&gt;

&lt;p&gt;That's not "Linux for human beings." That's "Linux for privileged beings."&lt;/p&gt;




&lt;p&gt;What About the Rest of Us?&lt;/p&gt;

&lt;p&gt;· Students with old laptops&lt;br&gt;
· People in areas with bad internet&lt;br&gt;
· Anyone paying per megabyte&lt;br&gt;
· Users who just want things to work&lt;/p&gt;

&lt;p&gt;We exist. We're just not the target audience anymore.&lt;/p&gt;




&lt;p&gt;The Alternative&lt;/p&gt;

&lt;p&gt;Linux Mint Xfce.&lt;/p&gt;

&lt;p&gt;· No Snap by default&lt;br&gt;
· Normal apt packages&lt;br&gt;
· Flatpak if needed (one runtime for all)&lt;br&gt;
· Actually works offline&lt;br&gt;
· Runs well on older hardware&lt;/p&gt;

&lt;p&gt;One install. Apps install immediately. No core18/core20/core22 madness.&lt;/p&gt;

&lt;p&gt;It's what Ubuntu used to be.&lt;/p&gt;




&lt;p&gt;Bottom Line&lt;/p&gt;

&lt;p&gt;Ubuntu had a good run. But it's no longer for everyone.&lt;/p&gt;

&lt;p&gt;If you're struggling with forced Snap, duplicate runtimes, and offline installs that fail — you're not alone. And there are better options.&lt;/p&gt;

&lt;p&gt;Sometimes the most popular choice isn't the right choice anymore.&lt;/p&gt;

&lt;p&gt;Now am not criticizing Ubuntu it’s a great distro with gnome as default it’s cool with slick designs but the snap canonical is pushing is a terrible idea &lt;/p&gt;




</description>
      <category>ubuntu</category>
      <category>linux</category>
    </item>
    <item>
      <title>Telegem first public plugin</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Thu, 05 Feb 2026 11:33:11 +0000</pubDate>
      <link>https://forem.com/slick_phantom/telegem-first-public-plugin-e7j</link>
      <guid>https://forem.com/slick_phantom/telegem-first-public-plugin-e7j</guid>
      <description>&lt;h2&gt;
  
  
  Extract PDFs, JSON &amp;amp; HTML in Your Telegram Bot with Telegem's New Plugin
&lt;/h2&gt;

&lt;p&gt;Building a Telegram bot that processes documents? Stop wrestling with file parsing. Telegem's new &lt;code&gt;FileExtractor&lt;/code&gt; plugin lets you extract text from PDFs, parse JSON, and process HTML files in 3 lines of Ruby.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What This Solves
&lt;/h2&gt;

&lt;p&gt;Before: Your users send PDFs/JSON files → You write 50+ lines of parsing code + install dependencies + handle edge cases.&lt;/p&gt;

&lt;p&gt;After: Your users send files → You call one method → Get clean extracted text.&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# In your Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'telegem'&lt;/span&gt;

&lt;span class="c1"&gt;# Install the optional dependency for PDF support&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'pdf-reader'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎯 Real-World Examples&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;PDF Invoice Processor
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'invoice'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mime_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'application/pdf'&lt;/span&gt;
    &lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Plugins&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileExtractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file_id&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="c1"&gt;# Find amounts in invoice text&lt;/span&gt;
      &lt;span class="n"&gt;amounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/\$\d+\.\d{2}/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"📊 Found &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;amounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; payment amounts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;JSON Config Validator
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;document: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_with?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.json'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Plugins&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileExtractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file_id&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"✅ Valid JSON with &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; keys"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"❌ Invalid JSON: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;HTML to Markdown Converter
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'html'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mime_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;
    &lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Plugins&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileExtractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file_id&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="c1"&gt;# Convert HTML to plain text (simplified)&lt;/span&gt;
      &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:content&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"📝 Extracted &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; characters"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🔧 How It Works Under the Hood&lt;/p&gt;

&lt;p&gt;The plugin handles the tedious parts for you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Downloads the file from Telegram's servers&lt;/li&gt;
&lt;li&gt;Auto detects file type&lt;/li&gt;
&lt;li&gt;Processes it with the appropriate library (PDF::Reader for PDFs, JSON.parse for JSON)&lt;/li&gt;
&lt;li&gt;Cleans up temp files automatically&lt;/li&gt;
&lt;li&gt;Returns a consistent hash format:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;content: &lt;/span&gt;&lt;span class="s2"&gt;"Extracted text here..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;pages: &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# PDF only&lt;/span&gt;
  &lt;span class="ss"&gt;file_size: &lt;/span&gt;&lt;span class="mi"&gt;45210&lt;/span&gt;    &lt;span class="c1"&gt;# All file types&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ Important Security Notes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ✅ SAFE - Use only Telegram-generated file_ids&lt;/span&gt;
&lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Plugins&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileExtractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# From Telegram context&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ❌ DANGEROUS - Never use user input&lt;/span&gt;
&lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Plugins&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileExtractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_input&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# Malicious users could hack your server&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎨 Advanced: Processing Replies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Extract from replied-to PDFs&lt;/span&gt;
&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'extract'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply_to_message&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;
    &lt;span class="n"&gt;file_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply_to_message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file_id&lt;/span&gt;

    &lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Plugins&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileExtractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;file_type: :pdf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract_pdf&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;"✅ Done"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"❌ Failed: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📈 Why This Matters&lt;/p&gt;

&lt;p&gt;Most bot frameworks make you handle file parsing manually. Telegem's approach:&lt;/p&gt;

&lt;p&gt;· Reduces boilerplate from 50+ lines to 3&lt;br&gt;
· Handles edge cases (encrypted PDFs, malformed JSON)&lt;br&gt;
· Auto-cleans temp files (no memory leaks)&lt;br&gt;
· Works seamlessly with Telegem's async architecture&lt;/p&gt;

&lt;p&gt;🚀 Get Started&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a new bot&lt;/span&gt;
gem &lt;span class="nb"&gt;install &lt;/span&gt;telegem

&lt;span class="c"&gt;# Check out the full example&lt;/span&gt;
git clone https://gitlab.com/ruby-telegem/telegem-examples
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💬 Your Turn&lt;/p&gt;

&lt;p&gt;What document processing tasks are you building with Telegram bots? Have you tried Telegem's new plugin? Share your use cases below!&lt;/p&gt;




&lt;p&gt;Telegem is a modern, async-first Telegram Bot framework for Ruby. Built with ❤️ by &lt;a class="mentioned-user" href="https://dev.to/slick_phantom"&gt;@slick_phantom&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>opensource</category>
      <category>news</category>
    </item>
    <item>
      <title>Why should we choose telegem over telegram-bot-ruby a established gem</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Sun, 18 Jan 2026 19:42:38 +0000</pubDate>
      <link>https://forem.com/slick_phantom/why-should-we-choose-telegem-over-telegram-bot-ruby-a-established-gem-2kf6</link>
      <guid>https://forem.com/slick_phantom/why-should-we-choose-telegem-over-telegram-bot-ruby-a-established-gem-2kf6</guid>
      <description>&lt;h2&gt;
  
  
  In this post we are going to be two giants
&lt;/h2&gt;

&lt;p&gt;providing ways to create telegram bots &lt;/p&gt;

&lt;p&gt;Let’s take a deep dive into telegram-bot-ruby&lt;/p&gt;

&lt;h2&gt;
  
  
  telegram-bot-ruby
&lt;/h2&gt;

&lt;p&gt;telegram-bot-ruby as I will call it tbr is a very good gem for creating telegram bots &lt;br&gt;
it was quickly adopted by rubyist with many tutorials on sitepoint medium…&lt;br&gt;
example code of tbr&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'telegram/bot'&lt;/span&gt;

&lt;span class="c1"&gt;# Get your token from @BotFather on Telegram&lt;/span&gt;
&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'YOUR_BOT_TOKEN_HERE'&lt;/span&gt;

&lt;span class="no"&gt;Telegram&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Bot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Bot has been started...'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;
    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'/start'&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;chat_id: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;! I'm a simple Ruby bot. Try /time or /roll"&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'/time'&lt;/span&gt;
      &lt;span class="n"&gt;current_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"%Y-%m-%d %H:%M:%S"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;chat_id: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s2"&gt;"Current time: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'/roll'&lt;/span&gt;
      &lt;span class="c1"&gt;# Roll a random number between 1 and 100&lt;/span&gt;
      &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;chat_id: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s2"&gt;"🎲 You rolled: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="s1"&gt;'/photo'&lt;/span&gt;
      &lt;span class="c1"&gt;# Send a cat photo (using a placeholder service)&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_photo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;chat_id: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;photo: &lt;/span&gt;&lt;span class="s1"&gt;'https://cataas.com/cat'&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="sr"&gt;/hello|hi|hey/i&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;chat_id: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s2"&gt;"👋 Hi there!"&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;chat_id: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s2"&gt;"I don't understand. Try /start to see commands."&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;what you notice &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;tbr is quite nice very nice it works out of the box but as you can see above it’s verbose Raw json raw api method nested arrays …&lt;/p&gt;

&lt;p&gt;handling state conversions is very verbose and explicit &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;let’s picture a bot that does many functions 
The developers will have to handle spaghetti codes hard for a contributor without reading tbr docs to contribute &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Then this is where telegem comes in&lt;/strong&gt;&lt;br&gt;
Telegem isn’t to replace tbr &lt;br&gt;
instead it offers what tbr doesn’t and offers a clean dsl &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no more verbose codes &lt;/li&gt;
&lt;li&gt;no more raw json &lt;/li&gt;
&lt;li&gt;no complexity or complex docs &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Telegem superpowers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;scene: one of Telegem great features &lt;br&gt;
&lt;strong&gt;what scenes&lt;/strong&gt; &lt;br&gt;
Let’s take it as a system that automatically gets the text moves to the next step handles multiple conversations &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;psuedo code&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;signup&lt;/em&gt; &lt;br&gt;
with scene it’s easy &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What’s your name &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your email &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;your password &lt;br&gt;
reply your account has been saved this is your api key &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;implementation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scene&lt;/span&gt; &lt;span class="ss"&gt;:signup&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:ask_name&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"👤 What's your full name?"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:ask_email&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_scene_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"📧 What's your email address?"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:ask_password&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_scene_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"🔐 Choose a password:"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ss"&gt;:complete&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_scene_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Generate fake token (in real app, use JWT or similar)&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Get all data&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scene_data&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class="no"&gt;TEXT&lt;/span&gt;&lt;span class="sh"&gt;
      ✅ Account Created!

      📋 Details:
      Name: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
      Email: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
      Password: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/./&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;

      🔑 Your Token: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;

      Save this token for future access!
&lt;/span&gt;&lt;span class="no"&gt;    TEXT&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;leave_scene&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;usage: &lt;code&gt;bot.command 'signup' do |ctx|&lt;br&gt;
  ctx.enter_scene(:signup)&lt;br&gt;
end&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;telegem scene just works out of the box automatically moves the next step &lt;/p&gt;

&lt;p&gt;Another method is &lt;strong&gt;ctx&lt;/strong&gt;&lt;br&gt;
ctx is an army you have different units and methods to use &lt;br&gt;
ctx.reply&lt;br&gt;
ctx.from.id&lt;br&gt;
ctx.from.full_name&lt;br&gt;
we won’t be talking about all this as it will take lot of time &lt;br&gt;
our main focus will be &lt;code&gt;ctx.reply&lt;/code&gt;&lt;br&gt;
I find this method very easy to use &lt;br&gt;
Basically let’s compare with tbr &lt;/p&gt;

&lt;p&gt;telegem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"welcome to the world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this is very easy unlike &lt;br&gt;
tbr:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="ss"&gt;chat_id: &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s2"&gt;"welcome to the world"&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;digging up for chat.id &lt;br&gt;
you just write ctx.reply&lt;/p&gt;

&lt;p&gt;what’s more cool &lt;br&gt;
you can use ctx.reply with options&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keyboard&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="s2"&gt;"dev.to"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"hashnode"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; 
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"welcome to the world"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;parse_mode: &lt;/span&gt;&lt;span class="s1"&gt;'Markdown'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;reply_markup: &lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am trying to keep this as short as possible &lt;/p&gt;

&lt;p&gt;TL;DR &lt;br&gt;
 tbr is an old battle-tested gem with lots of tutorials and answers to most questions &lt;br&gt;
telegem is a new async first gem focus on non thread and modern features such as auto ssl using a one line command &lt;code&gt;telegem-ssl&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  use
&lt;/h2&gt;

&lt;p&gt;use tbr if you want answers to most questions you could possible get &lt;br&gt;
use telegem if you want a modern day gem with cool features that remove complex api methods &lt;/p&gt;

</description>
      <category>telegram</category>
      <category>bot</category>
      <category>api</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Telegem v3.1.0 is here</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Sun, 18 Jan 2026 14:07:09 +0000</pubDate>
      <link>https://forem.com/slick_phantom/telegem-v310-is-here-3nad</link>
      <guid>https://forem.com/slick_phantom/telegem-v310-is-here-3nad</guid>
      <description>&lt;p&gt;Telegem now has a stable version release and also some improvements &lt;/p&gt;

&lt;h2&gt;
  
  
  fixes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;fixed the critical httpx bug preventing your bots from sending messages &lt;/li&gt;
&lt;li&gt;fixed hanging scene system &lt;/li&gt;
&lt;li&gt;fixed auto ssl detection method &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  New features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;file extraction(file to text) plugins 
&lt;strong&gt;docs coming soon&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;new improvised scene system &amp;amp; middleware &lt;/li&gt;
&lt;li&gt; Rate limit added can be used as a method also &lt;/li&gt;
&lt;li&gt;Added cli for ssl
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;telegem-ssl your-domain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;telegem-ssl 
&lt;span class="c"&gt;#then enter domain when promted  &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; telegem doesn’t create a ssl it uses certbot &lt;br&gt;
And should be only be used when using webhook mode &lt;/p&gt;

&lt;h2&gt;
  
  
  upcoming features
&lt;/h2&gt;

&lt;p&gt;Oops 😬 won’t spill the tea 👍&lt;/p&gt;

</description>
      <category>telegem</category>
      <category>telegram</category>
      <category>ruby</category>
      <category>gem</category>
    </item>
    <item>
      <title>Telegem v3.0.4 users : critical bug alert &amp; call for help</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Sat, 17 Jan 2026 18:50:19 +0000</pubDate>
      <link>https://forem.com/slick_phantom/telegem-v304-users-critical-bug-alert-call-for-help-2cp9</link>
      <guid>https://forem.com/slick_phantom/telegem-v304-users-critical-bug-alert-call-for-help-2cp9</guid>
      <description>&lt;p&gt;If you are using v3.0.4 you might be experiencing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ERROR &lt;span class="nt"&gt;--&lt;/span&gt; : ❌ Unhandled error: NoMethodError: undefined method &lt;span class="sb"&gt;`&lt;/span&gt;await&lt;span class="s1"&gt;' for an instance of HTTPX::Response(plugin)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This bug prevents your bot from sending responses or overall functionality &lt;/p&gt;

&lt;p&gt;The issue is compatibility with httpx async api &lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;Telegem v3.0.4 used an async pattern (response.await) that worked with old httpx versions but newer httpx release probably changed their async Api. This caused all api calls to fail when trying to send responses &lt;br&gt;
especially the &lt;code&gt;ctx.reply&lt;/code&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Temporary solution
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem uninstall httpx
gem &lt;span class="nb"&gt;install &lt;/span&gt;httpx &lt;span class="nt"&gt;-v&lt;/span&gt; 0.22.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;we could use your help&lt;/strong&gt;&lt;br&gt;
Httpx is a fantastic library/gem with incredible performance. But it’s async api changes rapidly.As a solo maintainer &lt;br&gt;
I could use some help from the community &lt;/p&gt;

&lt;h2&gt;
  
  
  Ways to contribute
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;TEST different httpx async patterns and share what works &lt;/li&gt;
&lt;li&gt;Help document httpx compatibility across different versions &lt;/li&gt;
&lt;li&gt;Submit MR(pr for github-ish) for more robust httpx handling &lt;/li&gt;
&lt;li&gt;Share your use case &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s make Telegem rock-solid together  &lt;/p&gt;

</description>
      <category>help</category>
      <category>telegram</category>
      <category>telegem</category>
      <category>ruby</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Sat, 17 Jan 2026 09:26:56 +0000</pubDate>
      <link>https://forem.com/slick_phantom/-e7h</link>
      <guid>https://forem.com/slick_phantom/-e7h</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/alexandrecalaca/ruby-one-of-the-top-5-highest-paying-technologies-according-to-stack-overflow-5dc7" class="crayons-story__hidden-navigation-link"&gt;Ruby: One of the top 5 highest-paying technologies, according to Stack overflow&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/alexandrecalaca" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F795109%2F9bf23429-1053-4890-909d-96e25f3a7327.jpeg" alt="alexandrecalaca profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/alexandrecalaca" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Alexandre Calaça
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Alexandre Calaça
                
              
              &lt;div id="story-author-preview-content-2106645" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/alexandrecalaca" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F795109%2F9bf23429-1053-4890-909d-96e25f3a7327.jpeg" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Alexandre Calaça&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/alexandrecalaca/ruby-one-of-the-top-5-highest-paying-technologies-according-to-stack-overflow-5dc7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Nov 16 '24&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/alexandrecalaca/ruby-one-of-the-top-5-highest-paying-technologies-according-to-stack-overflow-5dc7" id="article-link-2106645"&gt;
          Ruby: One of the top 5 highest-paying technologies, according to Stack overflow
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ruby"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ruby&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/rails"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;rails&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/alexandrecalaca/ruby-one-of-the-top-5-highest-paying-technologies-according-to-stack-overflow-5dc7" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/fire-f60e7a582391810302117f987b22a8ef04a2fe0df7e3258a5f49332df1cec71e.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;7&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/alexandrecalaca/ruby-one-of-the-top-5-highest-paying-technologies-according-to-stack-overflow-5dc7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              2&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ruby</category>
      <category>webdev</category>
      <category>rails</category>
      <category>programming</category>
    </item>
    <item>
      <title>Create a Telegram bot quote bot in Ruby</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Sat, 17 Jan 2026 08:53:00 +0000</pubDate>
      <link>https://forem.com/slick_phantom/create-a-telegram-bot-quote-bot-in-ruby-2j85</link>
      <guid>https://forem.com/slick_phantom/create-a-telegram-bot-quote-bot-in-ruby-2j85</guid>
      <description>&lt;h2&gt;
  
  
  Create a bot quote bot to be precise
&lt;/h2&gt;




&lt;p&gt;&lt;u&gt;Requirements&lt;/u&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Must have an ide &lt;br&gt;
 Basic or advanced knowledge in Ruby&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;project_folder/
├── bot.rb
├── quote.rb
├── help.rb
├── start.rb
└── Gemfile

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note: no .env here cause it’s meant to be secure and not to be commited to git&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let’s start with start.rb
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#start.rb&lt;/span&gt;
 &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Start&lt;/span&gt; 
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="vi"&gt;@bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt; 
        &lt;span class="n"&gt;start_handler&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; 
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_handler&lt;/span&gt;
      &lt;span class="vi"&gt;@bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"welcome to quote_bot use /quote to get astonishing quotes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;this file uses telegem two methods one .command this helps you with handling / commands e.g /help /start /quote and so on 
second is the ctx.reply method this is used to send a reply back to the current chat it automatically adds the &lt;span class="nb"&gt;id &lt;/span&gt;and it can take &lt;span class="k"&gt;**&lt;/span&gt;options e.g reply_markup, parse_mode and so on with &lt;span class="nb"&gt;time &lt;/span&gt;you will eventually see how they are been used 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;help.rb
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#help.rb &lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Help&lt;/span&gt; 
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
     &lt;span class="vi"&gt;@bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt;
     &lt;span class="n"&gt;send_help_message&lt;/span&gt; 
   &lt;span class="k"&gt;end&lt;/span&gt; 
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_help_message&lt;/span&gt; 
    &lt;span class="vi"&gt;@bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
   &lt;span class="n"&gt;help_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class="no"&gt;TEXT&lt;/span&gt; &lt;span class="sh"&gt;
     use /quote to get quotes 
   use /help to show this help message 
&lt;/span&gt;&lt;span class="no"&gt;   TEXT&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;help_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;parse_mode: &lt;/span&gt;&lt;span class="s1"&gt;'Markdown'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;end&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-quote.rb &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;this is where knowledge in some gems is required in this special case we using httparty&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'httparty'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'json'&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Quote&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt; 
     &lt;span class="n"&gt;find_quotes&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt; 
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_quotes&lt;/span&gt;
    &lt;span class="vi"&gt;@bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"quote"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
     &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;HTTParty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://zenquotes.io/api/random"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
      &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;quote_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt; 
       &lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;quote_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'q'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
       &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;quote_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class="no"&gt;TEXT&lt;/span&gt;&lt;span class="sh"&gt;
    QUOTE OF THE DAY 
    quote: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
     author: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
     credit: zenquotes
&lt;/span&gt;&lt;span class="no"&gt;    TEXT &lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;parse_mode: &lt;/span&gt;&lt;span class="s1"&gt;'Markdown'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; 
     &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"failed to fetch code"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="k"&gt;end&lt;/span&gt; 
   &lt;span class="k"&gt;end&lt;/span&gt; 
 &lt;span class="k"&gt;end&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-bot.rb the main file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#bot.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'telegem'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'dotenv/load'&lt;/span&gt;

&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'help'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'start'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'quote'&lt;/span&gt;

&lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'BOT_TOKEN'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="no"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Help&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Quote&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_polling&lt;/span&gt; 
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"bot has started"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;now we need our Gemfile
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s1"&gt;'https://rubygems.org'&lt;/span&gt; 

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"telegem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt;3.0.4"&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"httparty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt;0.21.0"&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"dotenv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt;2.8"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;important&lt;/strong&gt; don’t forget your .env&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BOT_TOKEN=&amp;lt;your token here&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Now we need to install and run using bundle
&lt;/h1&gt;

&lt;p&gt;-if you don’t have bundle gem still works or run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;now you can run using bundle but first let’s install all gems we need
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then now we run our code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more detailed examples &lt;br&gt;
Visit &lt;a href="https://gitlab.com/ruby-telegem/telegem" rel="noopener noreferrer"&gt;repo&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Star the repo &lt;/li&gt;
&lt;li&gt;Visit the examples to study more examples &lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>telegram</category>
      <category>telegem</category>
      <category>ruby</category>
    </item>
    <item>
      <title>How to create telegram bots in Ruby</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Thu, 15 Jan 2026 13:47:55 +0000</pubDate>
      <link>https://forem.com/slick_phantom/how-to-create-telegram-bots-4ej4</link>
      <guid>https://forem.com/slick_phantom/how-to-create-telegram-bots-4ej4</guid>
      <description>&lt;h2&gt;
  
  
  You must have heard or used telegram bots
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;now the deep question is how are they created&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We are going to see to that get your ide ready cause we gonna create a bot in 5 minutes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A ready good ide with Ruby installed &lt;/li&gt;
&lt;li&gt;basic or advanced knowledge in Ruby &lt;/li&gt;
&lt;li&gt;bot token from &lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you don’t know how to get your bot token check out this post 👉 &lt;a href="https://dev.to/slick_phantom/how-to-get-your-telegram-token-3nl"&gt;telegram_token&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After getting you token &lt;br&gt;
Create a GEMFILE&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s1"&gt;'https://rubygems.org'&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'telegem'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 3.0.4'&lt;/span&gt;

&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'dotenv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 2.8'&lt;/span&gt;

&lt;span class="c1"&gt;#add any other gem you wish httparty nethttp json e.t.c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;if using bundle&lt;/em&gt; use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or gem if using gem&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it’s pretty much recommended to use bundle but gem still works &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;next let’s create our file 
create a .env file with your token
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BOT_TOKEN=11234:445849489449
replace with your actual token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#bot.rb &lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'telegem'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'dotenv/load'&lt;/span&gt;

&lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Telegem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'BOT_TOKEN'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 

&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
  &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"welcome to test2bot"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
 &lt;span class="k"&gt;end&lt;/span&gt; 

&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
 &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"**u need help**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;parse_mode: &lt;/span&gt;&lt;span class="s1"&gt;'Markdown'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt; 

&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_polling&lt;/span&gt; 
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"bot has started"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this is all to a simple bot with /start command &lt;br&gt;
/help &lt;br&gt;
for more in-depth tutorial &lt;br&gt;
check 👉 &lt;a href="https://gitlab.com/ruby-telegem/telegem/-/tree/main/examples" rel="noopener noreferrer"&gt;more-rut&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>ruby</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to get your telegram token</title>
      <dc:creator>slick phantom</dc:creator>
      <pubDate>Thu, 15 Jan 2026 13:22:46 +0000</pubDate>
      <link>https://forem.com/slick_phantom/how-to-get-your-telegram-token-3nl</link>
      <guid>https://forem.com/slick_phantom/how-to-get-your-telegram-token-3nl</guid>
      <description>&lt;p&gt;Creating a token from botfather is very easy in few steps &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;download telegram if you haven’t &lt;/li&gt;
&lt;li&gt;click on link [&lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt;](t.me/botfather] &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;start chat &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovgtmh58ee8dmmffyxfj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovgtmh58ee8dmmffyxfj.png" alt="Image" width="800" height="1422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select &lt;br&gt;
/newbot from the list of command options &lt;/p&gt;

&lt;p&gt;You will/would be ask to name the bot &lt;br&gt;
You could use any name of your choice &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iamgreat &lt;/li&gt;
&lt;li&gt;one for life &lt;/li&gt;
&lt;li&gt;ccdezzzz &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then you will be asked for a username you might experience some issues here cause a bot can make username that has been talking so u have to be creative e.g &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iamgreatbot , i_am_great_bot, iamgreate_bot &lt;/li&gt;
&lt;li&gt;one_for_life_bot, on_today &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;if successful you will receive a token &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;it’s best practice and recommend to keep your token super safe with  .env never commit to git or share &lt;br&gt;
for team consider using .config.example with example token not real token &lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>telegram</category>
      <category>telegem</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
