Ruby GUI with Glimmer
Tags: ruby, glimmer, gui, programming
Published: 2023-06-30 01:50:56

From the very first time I started getting into development and programming, I always felt like I wanted to create my very own GUI. Whether it was for something as simple as cheating in a flash game 🦹🏽‍♂️ or something more useful like setting a timer or calculating expenses, creating an app with an actual interface always interested me. Prior to this I had used PythonAutoGUI and others. However, a couple of weeks ago, I stumbled upon a Ruby library that makes creating a fully functional GUI super easy. Obvisouly, I had to try it out. So in this post, I'll walk through how I used this library to create a simple currency converter.


![application preview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtlvkcgfw5hthiuw8l7j.gif)
Code Walkthrough:
First, install installing and including the `glimmer-dsl-libui` gem, `dotenv gem`, and a few other standard libraries for handling URLs, HTTP requests, and JSON parsing. I'm using Dotenv and loading a local .env file in my project holding the API_KEY.

```ruby
# Requirements
require 'glimmer-dsl-libui'
require 'dotenv'
require 'uri'
require 'net/http'
require 'json'

Dotenv.load
include Glimmer
```

The next step was to define the currencies and base values I want to work with.

```ruby
# DATA
currencies = ['USD', 'EUR', 'SEK', 'JPY', 'KRW']
base_values = ['USD', 'EUR', 'SEK', 'JPY', 'KRW']
currencies = currencies.join('%2C%20')

```
Then I had to make sure to use the above values and create a method that fetches the values of these currencies from my [selected API](https://apilayer.com/marketplace/exchangerates_data-api), and then use this data to create items for each currency that includes the symbol, rate and a place holder value of 0. These items are stored in an array, which is returned at the end.

```ruby
def get_data(currency_array, base)
  data = []
  url = URI("https://api.apilayer.com/exchangerates_data/latest?symbols=#{currency_array}&base=USD")

  https = Net::HTTP.new(url.host, url.port)
  https.use_ssl = true

  request = Net::HTTP::Get.new(url)
  request['apikey'] = ENV['API_KEY']

  response = https.request(request)
  response_hash = JSON.parse(response.body)

  response_hash['rates'].each do |currency, rate|
    item = [currency, rate, 0]
    data.append(item)
  end
  data
end
```

Now to the main code block. Here we call the get_data method, passing in the currencies array and `USD` as arguments. This retrieves the updated exchange rate data for the specified currencies relative to `USD`.

```ruby
# Fetches the exchange rate for each currency to USD.
updated_data = get_data(currencies, 'USD')
```
Next, the application window is created using the window method from the `glimmer` library. I've also named it and set the window dimensions.

Inside the window, we create a vertical box to hold the table and input field, basically like a "grid". The table is created using the table method and consists of three columns: "Currency," "Market Value," and "Converted Value."

Then using the `cell_rows` method, we pass in the `updated_data_array`. 

```ruby
window('Currency Converter', 1080, 800) {
  vertical_box {
    table {
      text_column('Currency')
      text_column('Market Value')
      text_column('Converted Value')

       cell_rows updated_data
    }
#...
```

On the bottom of the app, I added an input field using the `search_entry` method. This input field enter a value to convert. 

The `stretch false` is pretty much just a bool telling the input field not to stretch vertically.

```ruby
 # Input Field
    search_entry { |value|
      stretchy false
#...
```
To make the input field "responsive" to changes, I defined a on_changed block. In short the block takes the value in the input field, and copies the data array and replaces it with an updated one.

```ruby
 # Action on input
      on_changed do
        new_value = value.text
        new_data ||= updated_data.dup
#...
```
We then iterate over each currency item in new_data and update the converted value based on the new input. The converted value is calculated and rounded to two decimals. The updated values are then stored back in the new_data array, which is rendered in the app.

```ruby
# Iterates over each of the currencies added, and replaces the default "0" with the actual value.
        new_data.each do |currency|
          currency[2] = 0
          new_total = (currency[2]) + new_value.to_i * currency[1]
          currency[2] = new_total.round(2)
        end
      end
    }
  }
}.show
```

That's all there is to it really. It was fun trying a completely new library that I had no previous experience of, or heard about before and just figuring things out using the provided documentation.

You can find the full code [here](https://github.com/smackdh/glimmer_app).