Вступ
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 до 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));
}
}
Звичайно, потрібно зважати також на ціну, яку ми платимо за таку зручність, а саме час виконання такого коду. Але все ж тут не про це. Тож, йдемо далі.
Код, який 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("Привіт, Друкарня!");
}
}
}
Ось тут починається справжня магія, ти наче говориш з програмою, кажеш їй що конкретно потрібно зробити. Такій код, мені здається, крозуміє навіть людина, абослютно далека від програмування.
Код, який зможе почистити масив чисел від пустих значень та дублікатів
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% “інформаційного шуму” ві написаного вами коду.