De Ruby à Rust
D'un MVP à une solution Rock Solid
Philosophies fondamentales
Deux objectifs distincts

Points communs et concepts partagés
Malgré leurs philosophies différentes, Ruby et Rust partagent des concepts modernes qui facilitent la transition de l'un à l'autre.

Les grandes différences structurelles
Les différences fondamentales expliquent leurs cas d'usage respectifs.

La cohérence d’apprentissage
Du prototypage à la production

Similitudes du code
Similitudes dans le langage et la syntaxe

Traits (Rust) vs Modules/Mixins (Ruby)

Focus : Syntaxe des blocs et closures
Blocs avec paramètres
ruby
# Ruby
numbers.map { |x| x * 2 }
numbers.select { |x| x > 5 }rust
// Rust
numbers.iter().map(|x| x * 2)
numbers.iter().filter(|&x| x > 5)Blocs multi-lignes
ruby
# Ruby
items.each do |item|
puts item.name
item.process
endrust
// Rust
items.iter().for_each(|item| {
println!("{}", item.name);
item.process();
});Pattern matching

Voir vidéo et Post

Match sur valeurs
ruby
# Ruby (depuis 2.7)
case value
in 0
"zero"
in 1..10
"small"
in x if x > 100
"big"
endrust
// Rust
match value {
0 => "zero",
1..=10 => "small",
x if x > 100 => "big",
_ => "other"
}Destructuration
ruby
# Ruby
case point
in {x: 0, y: 0}
"origin"
in {x: x, y: 0}
"on x-axis at #{x}"
endrust
// Rust
match point {
Point { x: 0, y: 0 } => "origin",
Point { x, y: 0 } => format!("on x-axis at {}", x),
_ => "somewhere else"
}Méthodes chaînées et programmation fonctionnelle
Transformations de collections

ruby
# Ruby
numbers
.select { |x| x.even? }
.map { |x| x * 2 }
.sumrust
// Rust
numbers
.iter()
.filter(|&x| x % 2 == 0)
.map(|x| x * 2)
.sum()Opérations complexes
ruby
# Ruby
users
.group_by(&:department)
.transform_values { |users| users.map(&:salary).sum }rust
// Rust
users
.iter()
.into_group_map_by(|user| &user.department)
.into_iter()
.map(|(dept, users)| (dept, users.iter().map(|u| u.salary).sum()))
.collect()Itérateurs et énumération

Création et utilisation d'itérateurs
ruby
# Ruby
(1..10)
.lazy
.map { |x| x * x }
.select { |x| x > 20 }
.first(3)rust
// Rust
(1..=10)
.map(|x| x * x)
.filter(|&x| x > 20)
.take(3)
.collect::<Vec<_>>()Itération avec index
ruby
# Ruby
items.each_with_index do |item, index|
puts "#{index}: #{item}"
endrust
// Rust
items.iter().enumerate().for_each(|(index, item)| {
println!("{}: {}", index, item);
});Conventions de nommage
Snake case

ruby
# Ruby
def calculate_total_price(items)
base_price = items.sum(&:price)
tax_amount = base_price * TAX_RATE
base_price + tax_amount
endrust
// Rust
fn calculate_total_price(items: &[Item]) -> f64 {
let base_price: f64 = items.iter().map(|item| item.price).sum();
let tax_amount = base_price * TAX_RATE;
base_price + tax_amount
}Gestion des collections
Création et manipulation

ruby
# Ruby
hash = { name: "John", age: 30 }
hash[:email] = "john@example.com"
hash.each { |k, v| puts "#{k}: #{v}" }rust
// Rust
use std::collections::HashMap;
let mut hash = HashMap::new();
hash.insert("name", "John");
hash.insert("age", "30");
hash.insert("email", "john@example.com");
hash.iter().for_each(|(k, v)| println!("{}: {}", k, v));Gestion des modules et namespaces
Organisation du code

ruby
# Ruby
module Authentication
class User
def authenticate(password)
# ...
end
end
endrust
// Rust
mod authentication {
pub struct User {
// fields
}
impl User {
pub fn authenticate(&self, password: &str) -> bool {
// ...
}
}
}Tests intégrés
Tests unitaires
ruby
# Ruby
require 'minitest/autorun'
class TestCalculator < Minitest::Test
def test_addition
assert_equal 4, Calculator.add(2, 2)
end
endrust
// Rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_addition() {
assert_eq!(Calculator::add(2, 2), 4);
}
}Ces similitudes syntaxiques facilitent grandement la transition entre les deux langages, même si les concepts sous-jacents (ownership, borrowing en Rust vs garbage collection en Ruby) sont très différents.
Différences du code
Gestion des erreurs et Options

Valeurs optionnelles
ruby
# Ruby
def find_user(id)
users.find { |u| u.id == id }
end
user = find_user(123)
puts user&.name || "Unknown"rust
// Rust
fn find_user(id: u32) -> Option<&User> {
users.iter().find(|u| u.id == id)
}
let user = find_user(123);
println!("{}", user.map_or("Unknown".to_string(), |u| u.name.clone()));Chaînage avec gestion d'erreur
ruby
# Ruby
result = fetch_data(id)
&.then { |data| process_data(data) }
&.then { |processed| save_data(processed) }rust
// Rust
let result = fetch_data(id)
.and_then(|data| process_data(data))
.and_then(|processed| save_data(processed));Métaprogrammation et macros
Génération de code
ruby
# Ruby
[:name, :email, :phone].each do |attr|
define_method("#{attr}_present?") do
!send(attr).nil? && !send(attr).empty?
end
endrust
// Rust
macro_rules! generate_presence_check {
($($field:ident),*) => {
$(
fn paste::paste! { [<$field _present>] }(&self) -> bool {
!self.$field.is_empty()
}
)*
};
}Définition et structures de classes

ruby
# Ruby
class Point
attr_accessor :x, :y
def initialize(x, y)
@x, @y = x, y
end
def distance_from_origin
Math.sqrt(x**2 + y**2)
end
endrust
// Rust
struct Point {
x: f64,
y: f64,
}
impl Point {
fn new(x: f64, y: f64) -> Self {
Point { x, y }
}
fn distance_from_origin(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}Similitude des outils
Similitudes dans les outils de développement

Détails des outils de développement

Comparaison complète : Ruby vs Rust pour le développement de bibliothèques
Structure des projets

Ruby (Gem)
simple_calculator/
├── lib/
│ ├── simple_calculator.rb
│ ├── simple_calculator/
│ │ ├── calculator.rb
│ │ └── converter.rb
├── spec/
│ ├── spec_helper.rb
│ ├── simple_calculator_spec.rb
│ ├── simple_calculator/
│ │ ├── calculator_spec.rb
│ │ └── converter_spec.rb
├── .yardopts
├── Gemfile
├── Rakefile
├── simple_calculator.gemspec
└── README.mdRust (Crate)
simple_calculator/
├── src/
│ ├── lib.rs
│ ├── calculator.rs
│ └── converter.rs
├── tests/
│ └── integration_tests.rs
├── Cargo.toml
├── Cargo.lock
└── README.mdCode source
Ruby (Gem)
lib/simple_calculator.rb
require "simple_calculator/calculator"
require "simple_calculator/converter"
# A simple calculator library for basic operations and conversions
#
# @example Basic usage
# SimpleCalculator.add(2, 3) # => 5
# SimpleCalculator.subtract(5, 3) # => 2
#
# @example Temperature conversion
# SimpleCalculator.celsius_to_fahrenheit(0) # => 32
module SimpleCalculator
VERSION = "0.1.0"
# Adds two numbers
#
# @param a [Numeric] First number
# @param b [Numeric] Second number
# @return [Numeric] Sum of a and b
# @raise [TypeError] If arguments are not numeric
def self.add(a, b)
Calculator.new.add(a, b)
end
# Subtracts second number from first
#
# @param a [Numeric] First number
# @param b [Numeric] Second number
# @return [Numeric] Result of a - b
# @raise [TypeError] If arguments are not numeric
def self.subtract(a, b)
Calculator.new.subtract(a, b)
end
# Converts Celsius to Fahrenheit
#
# @param celsius [Numeric] Temperature in Celsius
# @return [Numeric] Temperature in Fahrenheit
# @raise [TypeError] If argument is not numeric
def self.celsius_to_fahrenheit(celsius)
Converter.new.celsius_to_fahrenheit(celsius)
end
endlib/simple_calculator/calculator.rb
module SimpleCalculator
# Performs basic arithmetic operations
class Calculator
# Adds two numbers
#
# @param a [Numeric] First number
# @param b [Numeric] Second number
# @return [Numeric] Sum of a and b
# @raise [TypeError] If arguments are not numeric
def add(a, b)
validate_numbers(a, b)
a + b
end
# Subtracts second number from first
#
# @param a [Numeric] First number
# @param b [Numeric] Second number
# @return [Numeric] Result of a - b
# @raise [TypeError] If arguments are not numeric
def subtract(a, b)
validate_numbers(a, b)
a - b
end
private
# Validates that arguments are numeric
#
# @param a [Object] First object to check
# @param b [Object] Second object to check
# @raise [TypeError] If arguments are not numeric
def validate_numbers(a, b)
raise TypeError, "Arguments must be numbers"
unless a.is_a?(Numeric) && b.is_a?(Numeric)
end
end
endlib/simple_calculator/converter.rb
module SimpleCalculator
# Performs temperature conversions
class Converter
# Converts Celsius to Fahrenheit
#
# @param celsius [Numeric] Temperature in Celsius
# @return [Numeric] Temperature in Fahrenheit
# @raise [TypeError] If argument is not numeric
def celsius_to_fahrenheit(celsius)
raise TypeError, "Argument must be a number"
unless celsius.is_a?(Numeric)
(celsius * 9.0/5.0) + 32
end
end
endRust (Crate)
src/lib.rs
//! A simple calculator library for basic operations and conversions
//!
//! # Examples
//!
//! ```
//! // Basic usage
//! use simple_calculator::{add, subtract};
//! assert_eq!(add(2.0, 3.0), 5.0);
//! assert_eq!(subtract(5.0, 3.0), 2.0);
//!
//! // Temperature conversion
//! use simple_calculator::celsius_to_fahrenheit;
//! assert_eq!(celsius_to_fahrenheit(0.0), 32.0);
//! ```
pub mod calculator;
pub mod converter;
// Re-export main functionality
pub use calculator::Calculator;
pub use converter::Converter;
// Define custom error type
use thiserror::Error;
/// Errors that can occur in calculator operations
#[derive(Error, Debug)]
pub enum CalculatorError {
/// Indicates an invalid input was provided
#[error("Invalid input: {0}")]
InvalidInput(String),
}
/// Adds two numbers
///
/// # Examples
///
/// ```
/// use simple_calculator::add;
/// assert_eq!(add(2.0, 3.0), 5.0);
/// ```
pub fn add(a: f64, b: f64) -> f64 {
Calculator::new().add(a, b)
}
/// Subtracts the second number from the first
///
/// # Examples
///
/// ```
/// use simple_calculator::subtract;
/// assert_eq!(subtract(5.0, 3.0), 2.0);
/// ```
pub fn subtract(a: f64, b: f64) -> f64 {
Calculator::new().subtract(a, b)
}
/// Converts a temperature from Celsius to Fahrenheit
///
/// # Examples
///
/// ```
/// use simple_calculator::celsius_to_fahrenheit;
/// assert_eq!(celsius_to_fahrenheit(0.0), 32.0);
/// assert_eq!(celsius_to_fahrenheit(100.0), 212.0);
/// ```
pub fn celsius_to_fahrenheit(celsius: f64) -> f64 {
Converter::new().celsius_to_fahrenheit(celsius)
}src/calculator.rs
use crate::CalculatorError;
/// A calculator for basic arithmetic operations
pub struct Calculator;
impl Calculator {
/// Creates a new calculator
pub fn new() -> Self {
Calculator
}
/// Adds two numbers
///
/// # Examples
///
/// ```
/// use simple_calculator::Calculator;
/// let calc = Calculator::new();
/// assert_eq!(calc.add(2.0, 3.0), 5.0);
/// ```
pub fn add(&self, a: f64, b: f64) -> f64 {
a + b
}
/// Subtracts the second number from the first
///
/// # Examples
///
/// ```
/// use simple_calculator::Calculator;
/// let calc = Calculator::new();
/// assert_eq!(calc.subtract(5.0, 3.0), 2.0);
/// ```
pub fn subtract(&self, a: f64, b: f64) -> f64 {
a - b
}
/// Divides the first number by the second, returning an error if
/// the divisor is zero
///
/// # Examples
///
/// ```
/// use simple_calculator::Calculator;
/// let calc = Calculator::new();
/// assert_eq!(calc.safe_divide(6.0, 2.0).unwrap(), 3.0);
/// assert!(calc.safe_divide(6.0, 0.0).is_err());
/// ```
pub fn safe_divide(&self, a: f64, b: f64) -> Result<f64, CalculatorError> {
if b == 0.0 {
return Err(CalculatorError::InvalidInput("Division by zero"
.to_string()));
}
Ok(a / b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
let calc = Calculator::new();
assert_eq!(calc.add(2.0, 3.0), 5.0);
}
#[test]
fn test_subtract() {
let calc = Calculator::new();
assert_eq!(calc.subtract(5.0, 3.0), 2.0);
}
#[test]
fn test_safe_divide() {
let calc = Calculator::new();
assert_eq!(calc.safe_divide(6.0, 2.0).unwrap(), 3.0);
assert!(calc.safe_divide(6.0, 0.0).is_err());
}
}lib/converter.rs
/// A simple temperature conversion library.
impl Converter {
/// Creates a new instance of `Converter`.
///
/// # Examples
///
/// ```
/// use simple_calculator::Calculator;
/// let converter = Converter::new();
/// ```
pub fn new() -> Self {
Converter
}
/// Converts a temperature from Celsius to Fahrenheit.
///
/// The formula used is: `(Celsius * 9/5) + 32`.
///
/// # Arguments
///
/// * `celsius` - A `f64` value representing the temperature in Celsius.
///
/// # Returns
///
/// A `f64` value representing the equivalent temperature in Fahrenheit.
pub fn celsius_to_fahrenheit(&self, celsius: f64) -> f64 {
celsius * 9.0 / 5.0 + 32.0
}
}
#[cfg(test)]
mod tests {
use super::celsius_to_fahrenheit;
#[test]
fn test_celsius_to_fahrenheit_conversions() {
const EPSILON: f64 = 1e-9;
// Test case : Freezing point
let celsius_freezing = 0.0;
let expected_fahrenheit_freezing = 32.0;
let result_freezing = celsius_to_fahrenheit(celsius_freezing);
assert!(
(result_freezing - expected_fahrenheit_freezing).abs() < EPSILON,
"Failed at freezing point: expected {}, got {}",
expected_fahrenheit_freezing, result_freezing
);
}
}
Tests
Ruby (RSpec)
spec/spec_helper.rb
require "simple_calculator"
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations
.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
config.filter_run_when_matching :focus
config.example_status_persistence_file_path = "spec/examples.txt"
config.disable_monkey_patching!
config.warnings = true
if config.files_to_run.one?
config.default_formatter = "doc"
end
config.order = :random
Kernel.srand config.seed
endspec/simple_calculator_spec.rb
require 'spec_helper'
RSpec.describe SimpleCalculator do
it "has a version number" do
expect(SimpleCalculator::VERSION).not_to be nil
end
describe ".add" do
it "adds two numbers correctly" do
expect(SimpleCalculator.add(2, 3)).to eq(5)
end
it "raises TypeError for non-numeric arguments" do
expect { SimpleCalculator.add("2", 3) }
.to raise_error(TypeError)
end
end
describe ".subtract" do
it "subtracts two numbers correctly" do
expect(SimpleCalculator.subtract(5, 3)).to eq(2)
end
it "raises TypeError for non-numeric arguments" do
expect { SimpleCalculator.subtract(5, "3") }
.to raise_error(TypeError)
end
end
describe ".celsius_to_fahrenheit" do
it "converts 0°C to 32°F" do
expect(SimpleCalculator.celsius_to_fahrenheit(0)).to eq(32)
end
it "converts 100°C to 212°F" do
expect(SimpleCalculator.celsius_to_fahrenheit(100)).to eq(212)
end
it "raises TypeError for non-numeric arguments" do
expect { SimpleCalculator.celsius_to_fahrenheit("zero") }
.to raise_error(TypeError)
end
end
endRust (Tests)
tests/integration_tests.rs
use simple_calculator::{add, subtract, celsius_to_fahrenheit, Calculator};
#[test]
fn test_crate_level_functions() {
assert_eq!(add(2.0, 3.0), 5.0);
assert_eq!(subtract(5.0, 3.0), 2.0);
assert_eq!(celsius_to_fahrenheit(0.0), 32.0);
}
#[test]
fn test_calculator_safe_divide() {
let calc = Calculator::new();
let result = calc.safe_divide(10.0, 2.0);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 5.0);
let error_result = calc.safe_divide(10.0, 0.0);
assert!(error_result.is_err());
}Configuration des projets
Ruby (Gem)
Gemfile
source "https://rubygems.org"
gemspec
group :development, :test do
gem "rspec", "~> 3.10"
gem "yard", "~> 0.9.27"
gem "redcarpet", "~> 3.5"
# Pour le rendu Markdown dans YARD
gem "rake", "~> 13.0"
endRakefile
require "bundler/gem_tasks"
require "rspec/core/rake_task"
require "yard"
RSpec::Core::RakeTask.new(:spec)
YARD::Rake::YardocTask.new do |t|
t.files = ["lib/**/*.rb"]
t.options = ["--markup", "markdown"]
t.stats_options = ["--list-undoc"]
end
task :default => [:spec, :yard]simple_calculator.gemspec
lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "simple_calculator"
Gem::Specification.new do |spec|
spec.name = "simple_calculator"
spec.version = SimpleCalculator::VERSION
spec.authors = ["Example Author"]
spec.email = ["author@example.com"]
spec.summary = "A simple calculator gem"
spec.description = "Performs basic calculations and conversions"
spec.homepage = "https://github.com/example/simple_calculator"
spec.license = "MIT"
spec.files = Dir["lib/**/*", "README.md"]
spec.require_paths = ["lib"]
spec.add_development_dependency "bundler", "~> 2.0"
spec.add_development_dependency "rake", "~> 13.0"
spec.add_development_dependency "rspec", "~> 3.10"
spec.add_development_dependency "yard", "~> 0.9.27"
end.yardopts
--markup markdown
--markup-provider redcarpet
--readme README.md
--title "SimpleCalculator Documentation"
--protected
--private
--embed-mixins
--output-dir doc/yardRust (Crate)
Cargo.toml
[package]
name = "simple_calculator"
version = "0.1.0"
edition = "2021"
authors = ["Example Author <author@example.com>"]
description = "A simple calculator library"
license = "MIT"
repository = "https://github.com/example/simple_calculator"
documentation = "https://docs.rs/simple_calculator"
readme = "README.md"
[dependencies]
thiserror = "1.0"
[dev-dependencies]
criterion = "0.3"
[lib]
name = "simple_calculator"
path = "src/lib.rs"Comparaison des outils de documentation
Ruby (YARD)

YARD est un outil de documentation pour Ruby qui génère une documentation HTML à partir des commentaires dans le code.
Installation et configuration
# Installation
gem install yard
# Génération de la documentation
yard doc
# ou
rake yardExemple de commentaire YARD
# Converts Celsius to Fahrenheit
#
# @param celsius [Numeric] Temperature in Celsius
# @return [Numeric] Temperature in Fahrenheit
# @example
# converter = Converter.new
# converter.celsius_to_fahrenheit(0) # => 32
# @raise [TypeError] If argument is not numeric
def celsius_to_fahrenheit(celsius)
# implementation
endRust (Rustdoc)
Rustdoc est intégré à Rust et génère automatiquement la documentation à partir des commentaires de documentation (doc comments).
Installation et configuration
# Aucune installation nécessaire, rustdoc est inclus avec Rust
# Génération de la documentation
cargo doc --no-deps --open
# Options courantes
cargo doc --document-private-items # Inclure les éléments privés
cargo doc --no-deps # Ne pas inclure les dépendancesExemple de commentaire Rustdoc
/// Converts a temperature from Celsius to Fahrenheit
///
/// # Examples
///
/// ```
/// use simple_calculator::Converter;
/// let converter = Converter::new();
/// assert_eq!(converter.celsius_to_fahrenheit(0.0), 32.0);
/// ```
pub fn celsius_to_fahrenheit(&self, celsius: f64) -> f64 {
// implementation
}Comparaison des systèmes de build et de tâches
Ruby (Rake)

Rake est un outil de build pour Ruby, similaire à Make, qui permet de définir des tâches.
Installation et configuration
# Installation
gem install rake
# Création d'un Rakefile
touch RakefileExemple de Rakefile
require "bundler/gem_tasks"
require "rspec/core/rake_task"
require "yard"
# Définition des tâches RSpec
RSpec::Core::RakeTask.new(:spec)
# Définition des tâches YARD
YARD::Rake::YardocTask.new do |t|
t.files = ["lib/**/*.rb"]
t.options = ["--markup", "markdown"]
t.stats_options = ["--list-undoc"]
end
# Tâche personnalisée
desc "Exécute les tests et vérifie la couverture de documentation"
task :quality => [:spec, :yard]
# Tâche par défaut
task :default => :qualityExécution des tâches
# Exécuter la tâche par défaut
rake
# Exécuter une tâche spécifique
rake spec
rake yard
rake quality
# Lister toutes les tâches disponibles
rake -TRust (Cargo)

Cargo est le gestionnaire de paquets et système de build de Rust, intégré au langage.
Installation et configuration
# Aucune installation nécessaire,
# Cargo est inclus avec Rust
# Création d'un nouveau projet
cargo new simple_calculator --libExemple de commandes Cargo
# Compiler le projet
cargo build
# Exécuter les tests
cargo test
# Générer la documentation
cargo doc
# Vérifier le code sans compiler
cargo check
# Publier sur crates.io
cargo publishPersonnalisation avec Cargo Make
Pour des tâches plus complexes, on peut utiliser Cargo Make, un outil tiers :
# Installation
cargo install cargo-make
# Création d'un
# fichier Makefile.toml
touch Makefile.tomlExemple de Makefile.toml
[tasks.format]
command = "cargo"
args = ["fmt", "--all"]
[tasks.lint]
command = "cargo"
args = ["clippy", "--all-targets", "--all-features"]
[tasks.test]
command = "cargo"
args = ["test"]
[tasks.doc]
command = "cargo"
args = ["doc", "--no-deps", "--open"]
[tasks.ci]
dependencies = [
"format",
"lint",
"test",
"doc"
]
[tasks.default]
dependencies = ["ci"]Exécution des tâches
# Exécuter la tâche par défaut
cargo make
# Exécuter une tâche spécifique
cargo make format
cargo make test
cargo make ciTableau comparatif
| Fonctionnalité | Ruby | Rust |
|---|---|---|
| Système de build | Rake | Cargo |
| Documentation | YARD | Rustdoc |
| Tests | RSpec | Tests intégrés + Cargo test |
| Gestion des dépendances | Bundler | Cargo |
| Publication | RubyGems | crates.io |
| Formatage | Rubocop | rustfmt |
| Analyse statique | Rubocop | Clippy |
| Exécution des tâches | rake task | cargo command |
| Personnalisation | Rakefile | Cargo Make (tiers) |
Comparaison détaillée des systèmes de documentation
| Aspect | YARD (Ruby) | Rustdoc (Rust) |
|---|---|---|
| Intégration | Externe, via gem | Intégré au langage |
| Syntaxe | Tags (@param, @return, etc.) | Markdown avec sections (#Examples, etc.) |
| Tests dans la doc | Non exécutables | Exécutés comme tests (cargo test --doc) |
| Génération | yard doc ou rake yard | cargo doc |
| Hébergement | Rubydoc.info (manuel) | docs.rs (automatique) |
| Thème | Personnalisable | Standard, peu personnalisable |
| Recherche | Basique | Avancée, avec index |
| Liens vers le code source | Oui | Oui |
| Graphiques | Diagrammes de classes | Non |
| Statistiques | Couverture de documentation | Non |
Exemple d'utilisation

Ruby
Installation de la gem
gem install simple_calculatorUtilisation
require 'simple_calculator'
# Utilisation des fonctions de module
puts SimpleCalculator.add(2, 3) # => 5
puts SimpleCalculator.subtract(5, 3) # => 2
puts SimpleCalculator.celsius_to_fahrenheit(0) # => 32
# Utilisation directe des classes
calculator = SimpleCalculator::Calculator.new
puts calculator.add(2, 3) # => 5
converter = SimpleCalculator::Converter.new
puts converter.celsius_to_fahrenheit(100) # => 212Rust
Installation du crate
cargo add simple_calculatorUtilisation
use simple_calculator::{add, subtract, celsius_to_fahrenheit, Calculator, Converter};
fn main() {
// Utilisation des fonctions de module
println!("{}", add(2.0, 3.0)); // => 5
println!("{}", subtract(5.0, 3.0)); // => 2
println!("{}", celsius_to_fahrenheit(0.0)); // => 32
// Utilisation directe des structures
let calculator = Calculator::new();
println!("{}", calculator.add(2.0, 3.0)); // => 5
// Gestion d'erreurs avec Result
match calculator.safe_divide(10.0, 2.0) {
Ok(result) => println!("10 / 2 = {}", result),
Err(e) => println!("Erreur: {}", e),
}
let converter = Converter::new();
println!("{}", converter.celsius_to_fahrenheit(100.0)); // => 212
}Workflow de développement

Ruby
Publication
# Mettre à jour la version dans lib/simple_calculator/version.rb
rake releaseDocumentation
bundle exec yard
open doc/yard/index.htmlTests
bundle exec rspecDéveloppement
# Éditer les fichiers dans lib/
vim lib/simple_calculator.rbCréation du projet
bundle gem simple_calculatorRust
Publication
# Mettre à jour la version dans Cargo.toml
cargo publishDocumentation
cargo doc --openTests
cargo testDéveloppement
# Éditer les fichiers dans src/
vim src/lib.rsCréation du projet
cargo new simple_calculator --libEcosystèmes & communautés
Similitudes dans la communauté
& gouvernance

Similitudes dans les domaines d'application

Similitudes dans l'apprentissage et adoption

Similitudes dans l'écosystème

Conclusion

