Ruby - мова програмування для людини, а не для компʼютера

Вступ

Ruby (англ. «Рубін», читається «Ру́бі») — це інтерпретована, повністю об'єктноорієнтована мова програмування з чіткою динамічною типізацією. Мова вирізняється високою ефективністю розробки програм і увібрала в себе найкращі риси Perl, Java, Python, Smalltalk, Eiffel, Ada і Lisp. Ruby поєднує в собі Perl-подібний синтаксис з об'єктноорієнтованим підходом мови програмування Smalltalk. Також деякі риси запозичено із мов програмування Python, Lisp, Dylan та CLU.
- Трішки Вікіпедії

Ruby - це об’єктно-орієнтована мова програмування, яка була створена в Японії в 1995 році Юкихиро Мацумото. Вона має синтаксис, що нагадує природну мову, він робить її дуже доступною для новачків.

Ця мова програмування, що зосереджена на зручності та читабельності для програмістів. Вона пропонує лаконічний та експресивний синтаксис, що полегшує розробку та покращує продуктивність. Зосередження на зручності пронизує не лише саму мову, але й її екосистему, що включає готові бібліотеки та фреймворки. Ruby надає програмістам комфортне середовище, де вони можуть реалізовувати свої ідеї швидко та ефективно.

Про саму мову програмування тут можна багато чого пісати, але я хочу присвятити цю статтю більше прикладам, розібрати у порівнянні з декількома іншими мовами програмування. Можливо, деякі приклади будуть не дуже ефективні чи показові, але не суть. більша частина їх буде взята в інтернеті або згенерована AI помічником.

Для порівняння буду використовувати одну або декілька популярних мов програмування, а саме: JavaScript, Python, C++, Go та Java

Основна частина

Класичні приклади

  1. Код, який створює та виводить масив чисел від 1 до 1000

Ruby:

array = (1..1000).to_a
puts array

JavaScript:

let array = Array.from({length: 1000}, (_, i) => i + 1);
console.log(array);

Python:

array = list(range(1, 1001))
print(array)

C++:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> array;
    for (int i = 1; i <= 1000; i++) {
        array.push_back(i);
    }
    for (int num : array) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}

Go:

package main

import "fmt"

func main() {
    var array []int
    for i := 1; i <= 1000; i++ {
        array = append(array, i)
    }
    fmt.Println(array)
}

Java:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] array = new int[1000];
        for (int i = 0; i < 1000; i++) {
            array[i] = i + 1;
        }
        System.out.println(Arrays.toString(array));
    }
}

Звичайно, потрібно зважати також на ціну, яку ми платимо за таку зручність, а саме час виконання такого коду. Але все ж тут не про це. Тож, йдемо далі.

  1. Код, який 10 разів підряд виводить фразу "Привіт, Друкарня!"

Ruby:

10.times do 
  puts "Привіт, Друкарня!" 
end

JavaScript:

for (let i = 0; i < 10; i++) {
  console.log("Привіт, Друкарня!");
}

Python:

for _ in range(10):
    print("Привіт, Друкарня!")

C++:

#include <iostream>

int main() {
    for (int i = 0; i < 10; i++) {
        std::cout << "Привіт, Друкарня!" << std::endl;
    }
    return 0;
}

Go:

package main

import "fmt"

func main() {
    for i := 0; i < 10; i++ {
        fmt.Println("Привіт, Друкарня!")
    }
}

Java:

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println("Привіт, Друкарня!");
        }
    }
}

Ось тут починається справжня магія, ти наче говориш з програмою, кажеш їй що конкретно потрібно зробити. Такій код, мені здається, крозуміє навіть людина, абослютно далека від програмування.

  1. Код, який зможе почистити масив чисел від пустих значень та дублікатів

Ruby:

array = [1, 2, 3, nil, 4, 2, 3, nil, 5]
array.compact!.uniq!
puts array

JavaScript:

let array = [1, 2, 3, undefined, 4, 2, 3, undefined, 5];
array = array.filter((value, index, self) => value !== undefined && self.indexOf(value) === index);
console.log(array);

Python:

array = [1, 2, 3, None, 4, 2, 3, None, 5]
array = list(set(filter(None, array)))
print(array)

C++:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> array = {1, 2, 3, 0, 4, 2, 3, 0, 5};
    array.erase(std::remove(array.begin(), array.end(), 0), array.end());
    std::sort(array.begin(), array.end());
    array.erase(std::unique(array.begin(), array.end()), array.end());
    for (int num : array) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}

Go:

package main

import (
	"fmt"
)

func removeDuplicatesAndEmpty(array []int) []int {
	uniqueArray := make([]int, 0)
	seen := make(map[int]bool)
	for _, num := range array {
		if num != 0 && !seen[num] {
			uniqueArray = append(uniqueArray, num)
			seen[num] = true
		}
	}
	return uniqueArray
}

func main() {
	array := []int{1, 2, 3, 0, 4, 2, 3, 0, 5}
	array = removeDuplicatesAndEmpty(array)
	fmt.Println(array)
}

Java:

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Main {
    public static List<Integer> removeDuplicatesAndEmpty(List<Integer> array) {
        List<Integer> uniqueArray = new ArrayList<>();
        Set<Integer> seen = new HashSet<>();
        for (Integer num : array) {
            if (num != null && num != 0 && !seen.contains(num)) {
                uniqueArray.add(num);
                seen.add(num);
            }
        }
        return uniqueArray;
    }

    public static void main(String[] args) {
        List<Integer> array = new ArrayList<>();
        array.add(1);
        array.add(2);
        array.add(3);
        array.add(null);
        array.add(4);
        array.add(2);
        array.add(3);
        array.add(null);
        array.add(5);

        array = removeDuplicatesAndEmpty(array);

        for (Integer num : array) {
            System.out.print(num + " ");
        }
        System.out.println();
    }
}

Знову ж таки, мі тут не про кількість або якість рядків коду, ми про те, на скільки зручно буде розробнику писати та читати такий код.

ООП

Тепер давайте розглянемо трішки складніші приклади

Задача:

Створити клас Person з атрибутом name та age. Мати можливість читати та записувати ці атрибути. Класс має мати метод, який визначає чи персона повнолітня

Для прикладу створи 2 об'єкти цього класу: Іванко - 17 та Марічка - 22. Прочитай ім'я та вік, а також дізнайся чи повнолітня особа.

Ruby:

class Person
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def adult?
    @age >= 18
  end
end

ivanko = Person.new("Іванко", 17)
marichka = Person.new("Марічка", 22)

marichka.age = 23

puts "#{ivanko.name} - #{ivanko.age} років, повнолітній: #{ivanko.adult?}"
puts "#{marichka.name} - #{marichka.age} років, повнолітня: #{marichka.adult?}"

JavaScript:

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  adult() {
    return this.age >= 18;
  }
}

const ivanko = new Person("Іванко", 17);
const marichka = new Person("Марічка", 22);

marichka.age = 23;

console.log(`${ivanko.name} - ${ivanko.age} років, повнолітній: ${ivanko.adult()}`);
console.log(`${marichka.name} - ${marichka.age} років, повнолітня: ${marichka.adult()}`);

Python:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def adult(self):
        return self.age >= 18


ivanko = Person("Іванко", 17)
marichka = Person("Марічка", 22)

marichka.age = 23

print(f"{ivanko.name} - {ivanko.age} років, повнолітній: {ivanko.adult()}")
print(f"{marichka.name} - {marichka.age} років, повнолітня: {marichka.adult()}")

C++:

#include <iostream>
#include <string>

class Person {
public:
    std::string name;
    int age;

    Person(const std::string& name, int age) : name(name), age(age) {}

    bool adult() const {
        return age >= 18;
    }
};

int main() {
    Person ivanko("Іванко", 17);
    Person marichka("Марічка", 22);

    marichka.age = 23;

    std::cout << ivanko.name << " - " << ivanko.age << " років, повнолітній: " << std::boolalpha << ivanko.adult() << std::endl;
    std::cout << marichka.name << " - " << marichka.age << " років, повнолітня: " << std::boolalpha << marichka.adult() << std::endl;

    return 0;
}

Go:

package main

import (
	"fmt"
)

type Person struct {
	name string
	age  int
}

func (p Person) adult() bool {
	return p.age >= 18
}

func main() {
	ivanko := Person{name: "Іванко", age: 17}
	marichka := Person{name: "Марічка", age: 22}

	marichka.age = 23

	fmt.Printf("%s - %d років, повнолітній: %t\n", ivanko.name, ivanko.age, ivanko.adult())
	fmt.Printf("%s - %d років, повнолітня: %t\n", marichka.name, marichka.age, marichka.adult())
}

Java:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public boolean adult() {
        return age >= 18;
    }

    public static void main(String[] args) {
        Person ivanko = new Person("Іванко", 17);
        Person marichka = new Person("Марічка", 22);

        marichka.age = 23;

        System.out.printf("%s - %d років, повнолітній: %b\n", ivanko.name, ivanko.age, ivanko.adult());
        System.out.printf("%s - %d років, повнолітня: %b\n", marichka.name, marichka.age, marichka.adult());
    }
}

Файлова система

Задача:

Код, який зможе прочитати усі файли на диску з каталогу "~/Downloads" та розділити їх по папкам за наступним правилом:
small - <= 1 mb;
medium - 1 mb ... 10 mb;
big - 10 mb ... 1 gb;
huge > 1 gb

Ruby:

require 'fileutils'

def categorize_files(directory)
  FileUtils.mkdir_p(directory + '/small')
  FileUtils.mkdir_p(directory + '/medium')
  FileUtils.mkdir_p(directory + '/big')
  FileUtils.mkdir_p(directory + '/huge')

  Dir.glob("#{directory}/*").each do |file|
    size = File.size(file)

    if size <= 1 * 1024 * 1024
      FileUtils.mv(file, "#{directory}/small")
    elsif size > 1 * 1024 * 1024 && size <= 10 * 1024 * 1024
      FileUtils.mv(file, "#{directory}/medium")
    elsif size > 10 * 1024 * 1024 && size <= 1024 * 1024 * 1024
      FileUtils.mv(file, "#{directory}/big")
    else
      FileUtils.mv(file, "#{directory}/huge")
    end
  end
end

categorize_files('~/Downloads')

JavaScript:

const fs = require('fs');
const path = require('path');

function categorizeFiles(directory) {
  const smallDir = path.join(directory, 'small');
  const mediumDir = path.join(directory, 'medium');
  const bigDir = path.join(directory, 'big');
  const hugeDir = path.join(directory, 'huge');

  if (!fs.existsSync(smallDir)) {
    fs.mkdirSync(smallDir);
  }
  if (!fs.existsSync(mediumDir)) {
    fs.mkdirSync(mediumDir);
  }
  if (!fs.existsSync(bigDir)) {
    fs.mkdirSync(bigDir);
  }
  if (!fs.existsSync(hugeDir)) {
    fs.mkdirSync(hugeDir);
  }

  fs.readdirSync(directory).forEach((file) => {
    const filePath = path.join(directory, file);
    const size = fs.statSync(filePath).size;

    if (size <= 1 * 1024 * 1024) {
      fs.renameSync(filePath, path.join(smallDir, file));
    } else if (size > 1 * 1024 * 1024 && size <= 10 * 1024 * 1024) {
      fs.renameSync(filePath, path.join(mediumDir, file));
    } else if (size > 10 * 1024 * 1024 && size <= 1024 * 1024 * 1024) {
      fs.renameSync(filePath, path.join(bigDir, file));
    } else {
      fs.renameSync(filePath, path.join(hugeDir, file));
    }
  });
}

categorizeFiles('~/Downloads');

Python:

import os
import shutil

def categorize_files(directory):
    small_dir = os.path.join(directory, 'small')
    medium_dir = os.path.join(directory, 'medium')
    big_dir = os.path.join(directory, 'big')
    huge_dir = os.path.join(directory, 'huge')

    os.makedirs(small_dir, exist_ok=True)
    os.makedirs(medium_dir, exist_ok=True)
    os.makedirs(big_dir, exist_ok=True)
    os.makedirs(huge_dir, exist_ok=True)

    for file in os.listdir(directory):
        file_path = os.path.join(directory, file)
        if os.path.isfile(file_path):
            size = os.path.getsize(file_path)

            if size <= 1 * 1024 * 1024:
                shutil.move(file_path, os.path.join(small_dir, file))
            elif size > 1 * 1024 * 1024 and size <= 10 * 1024 * 1024:
                shutil.move(file_path, os.path.join(medium_dir, file))
            elif size > 10 * 1024 * 1024 and size <= 1024 * 1024 * 1024:
                shutil.move(file_path, os.path.join(big_dir, file))
            else:
                shutil.move(file_path, os.path.join(huge_dir, file))

categorize_files('~/Downloads')

C++:

#include <iostream>
#include <filesystem>
#include <fstream>

void categorizeFiles(const std::string& directory) {
    const std::string smallDir = directory + "/small";
    const std::string mediumDir = directory + "/medium";
    const std::string bigDir = directory + "/big";
    const std::string hugeDir = directory + "/huge";

    std::filesystem::create_directory(smallDir);
    std::filesystem::create_directory(mediumDir);
    std::filesystem::create_directory(bigDir);
    std::filesystem::create_directory(hugeDir);

    for (const auto& entry : std::filesystem::directory_iterator(directory)) {
        const std::string filePath = entry.path();
        if (std::filesystem::is_regular_file(filePath)) {
            const std::streampos fileSize = std::filesystem::file_size(filePath);

            if (fileSize <= 1 * 1024 * 1024) {
                std::filesystem::rename(filePath, smallDir + "/" + entry.path().filename().string());
            } else if (fileSize > 1 * 1024 * 1024 && fileSize <= 10 * 1024 * 1024) {
                std::filesystem::rename(filePath, mediumDir + "/" + entry.path().filename().string());
            } else if (fileSize > 10 * 1024 * 1024 && fileSize <= 1024 * 1024 * 1024) {
                std::filesystem::rename(filePath, bigDir + "/" + entry.path().filename().string());
            } else {
                std::filesystem::rename(filePath, hugeDir + "/" + entry.path().filename().string());
            }
        }
    }
}

int main() {
    categorizeFiles("~/Downloads");
    return 0;
}

Go:

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

func categorizeFiles(directory string) {
	smallDir := filepath.Join(directory, "small")
	mediumDir := filepath.Join(directory, "medium")
	bigDir := filepath.Join(directory, "big")
	hugeDir := filepath.Join(directory, "huge")

	os.MkdirAll(smallDir, os.ModePerm)
	os.MkdirAll(mediumDir, os.ModePerm)
	os.MkdirAll(bigDir, os.ModePerm)
	os.MkdirAll(hugeDir, os.ModePerm)

	files, err := ioutil.ReadDir(directory)
	if err != nil {
		fmt.Println(err)
		return
	}

	for _, file := range files {
		filePath := filepath.Join(directory, file.Name())
		if file.Mode().IsRegular() {
			fileSize := file.Size()

			if fileSize <= 1*1024*1024 {
				moveFile(filePath, filepath.Join(smallDir, file.Name()))
			} else if fileSize > 1*1024*1024 && fileSize <= 10*1024*1024 {
				moveFile(filePath, filepath.Join(mediumDir, file.Name()))
			} else if fileSize > 10*1024*1024 && fileSize <= 1024*1024*1024 {
				moveFile(filePath, filepath.Join(bigDir, file.Name()))
			} else {
				moveFile(filePath, filepath.Join(hugeDir, file.Name()))
			}
		}
	}
}

func moveFile(src, dst string) {
	input, err := os.Open(src)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer input.Close()

	output, err := os.Create(dst)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer output.Close()

	_, err = io.Copy(output, input)
	if err != nil {
		fmt.Println(err)
		return
	}

	err = os.Remove(src)
	if err != nil {
		fmt.Println(err)
		return
	}
}

func main() {
	categorizeFiles("~/Downloads")
}

Java:

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

public class FileCategorizer {
    public static void main(String[] args) {
        String directory = "~/Downloads";
        String smallDir = directory + "/small";
        String mediumDir = directory + "/medium";
        String bigDir = directory + "/big";
        String hugeDir = directory + "/huge";

        createDirectory(smallDir);
        createDirectory(mediumDir);
        createDirectory(bigDir);
        createDirectory(hugeDir);

        File[] files = new File(directory).listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isFile()) {
                    long fileSize = file.length();

                    if (fileSize <= 1 * 1024 * 1024) {
                        moveFile(file, smallDir);
                    } else if (fileSize > 1 * 1024 * 1024 && fileSize <= 10 * 1024 * 1024) {
                        moveFile(file, mediumDir);
                    } else if (fileSize > 10 * 1024 * 1024 && fileSize <= 1024 * 1024 * 1024) {
                        moveFile(file, bigDir);
                    } else {
                        moveFile(file, hugeDir);
                    }
                }
            }
        }
    }

    private static void createDirectory(String directory) {
        File dir = new File(directory);
        if (!dir.exists()) {
            dir.mkdirs();
        }
    }

    private static void moveFile(File file, String destinationDirectory) {
        try {
            Path sourcePath = file.toPath();
            Path destinationPath = new File(destinationDirectory, file.getName()).toPath();
            Files.move(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Висновки

А от висновки робіть самі. Я тільки хотів показати, що від програмування також можна отримувати задоволення, не пишучи і не запам’ятовуючи 30-50% “інформаційного шуму” ві написаного вами коду.

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Yuri V
Yuri V@yuri_v

Full Stack SE 💻 💎 ⚛

104Прочитань
3Автори
6Читачі
На Друкарні з 16 квітня

Вам також сподобається

Коментарі (3)

Завдяки вашому довгочиту я звернула увагу на цю мову програмування, і я би хотіла писати в яких сферах програмування його частіше використовують? Розробка ігор чи може розробка програм на android чи ще щось?

Вам також сподобається