---
theme: gaia
paginate: true
title: Ruby-Schulung Linuxhotel Oktober 2026
---
<style>
  section {
    background: #fefefe;
    color: #004;
  }
  section.invert {
    background: #004;
    color: #fefefe;
  }

  section.lead h1 {
    font-size: 3em;
  }

  section.small p, section.small li {
    font-size: 0.6em;
  }

  section marp-pre {
    background: #002;
    border-radius: 5px;
  }

  section code {
    background: #002;
    border-radius: 5px;
  }

</style>

<!-- class: lead -->
# Dokumentation

---
<!-- class: -->

# RDoc vs. YARD

| RDoc | YARD |
| ---- | ---- |
| Stdlib | Gem |
| "Nur" Text | @tags |

---

# RDoc

```ruby
##
# Add water to the water tank (+amount+ in ml/g)
def add_water(amount)
  @water += amount
end
```

![w:800](images/rdoc.png)

---

# YARD

```ruby
##
# Add coffee to the hopper
# @param amount [Integer, #read] Amount in grams
# @return [Integer] Amount of coffee in the hopper after the refill
def add_coffee(amount)
  @coffee += amount
end
```

![w:800](images/yard.png)

---

<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)

# Praxis

---
<!-- class: -->

# RDoc oder YARD
- Docs:
  - [RDoc](https://ruby.github.io/rdoc/)
  - [YARD](https://yardoc.org/index.html)
- Rake Task einbinden
- Methoden dokumentieren

---

# Webanwendungen mit Sinatra

- Simpler Ansatz, Webanwendungen mit Ruby zu entwickeln
- Gegenentwurf zum “schwergewichtigen” Ruby on Rails
- Sehr einfache API, ﬂexibel erweiterbar
- Ideal für einfache Anwendungen und Web-APIs
- `gem install sinatra` / `bundle add sinatra`
- [Website](https://sinatrarb.com/)


---

# Sinatra DSL

```ruby
require "sinatra"
get '/' do
  "Willkommen"
end

post '/login' do
  "Willkommen #{params[:user]}"
end
```

---
# Templates

```ruby
get '/now' do
  @now = Time.now
  erb :now
end
```

```ruby
<p>Current time: <%= @now %></p>
```

---

# Layouts

- Layouts sind Templates, die ein yield enthalten
- Ideal für üblichen HTML-Rahmen, ﬁxe Header und Footer
- Default: layout.erb für ERb-Templates
- Für jedes Template konﬁgurierbar

---
# Parameter

```ruby
post '/login' do
  @username = params[:username]
  erb :welcome
end
```
---

# Parameter in der URL


```ruby
get '/posts/:id' do |id|
  @id = id
  erb :post
end
```

```ruby
<h3>Post: <%= @id %></h3>
```

---
# Praxis

---
# Webbasierte Kaffeemaschine

Entwickelt eine Webseite, über die sich Eure
Kaffeemaschine fernsteuern lässt.

---

# Webbasierte Kaffeemaschine

- Erst mal mit Sinatra spielen
- Als gem einbinden
- Annahme: Webserver läuft in single thread / single process

---
<!-- class: lead -->
# Concurrency

---
<!-- class: -->
# Ein Beispiel

Quelle: [maikhel](https://maikhel.github.io/blog/celluloid-concurrent-ruby/)

---
# Teil 1: Fetch

```ruby
class DataRequester
  def initialize(url)
    @url = url
  end

  def call
    uri = URI(@url)
    response = Net::HTTP.get_response(uri)
    JSON.parse(response.body)["value"]
  end
end
```
---

# Synchron

```ruby
class SyncService
  API_ENDPOINT = 'https://api.chucknorris.io/jokes/random'.freeze

  def self.call(requests_count)
    jokes = []
    requests_count.times do
      jokes << DataRequester.new(API_ENDPOINT).call
    end

    jokes
  end
end
```
---

```ruby
class AsyncThreadsService
  API_ENDPOINT = "https://api.chucknorris.io/jokes/random".freeze

  def self.call(requests_count)
    jokes = Queue.new
    threads = []

    requests_count.times do
      thread = Thread.new do
        jokes << DataRequester.new(API_ENDPOINT).call
      end
      threads << thread
    end
    threads.each(&:join)
    jokes
  end
end
```
---

```ruby
require 'concurrent'
class AsyncConcurrentService
  API_ENDPOINT = "https://api.chucknorris.io/jokes/random".freeze

  def self.call(requests_count)
    # jokes = Concurrent::Array.new
    futures = []

    requests_count.times do
      requester = DataRequester.new(API_ENDPOINT)
      futures << Concurrent::Promises.future { requester.call }
    end
    futures.map(&:value)
  end
end
```

---
<!-- class: lead -->
# UI / TUI

---

# TUI (Text UI)

- ncurses
- ...
- ratatui
---
# GUI

- tk
- FX (Java)
- wxWindows
- Glimmer
---
# Gaming

- gosu
- Dragon Ruby (non-free)

---

<!-- class: lead -->
![bg contain opacity:0.2](images/pet.jpg)

# Praxis

---
<!-- class: -->

# Auswahl

- Glimmer-SWT
- Glimmer LibUI
- Glimmer.*
- ratatui
- gosu

---

# Aufgabe

- Kaffeemaschine?
- Addressdatenbank?
- Pong?

---
<!-- class: lead -->
# Metaprogramming

---
<!-- class: -->

# Introspektion

- `.methods`
- `.method()`
- `.instance_methods`
- `.respond_to?`

---

# Dynamic dispatch

- `method_missing`

---

# Beispiel: nokogiri builder

```ruby
require 'nokogiri'

builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
  xml.RootElement do
    xml.Test do
      xml.Foo "Hallo"
    end
  end
end

puts builder.to_xml
```

---

# Ruby Golf, die zweite
