diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 80d15df..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index 6d294de..ef427c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # misc .DS_Store -*.pyc \ No newline at end of file +*.pyc +/better-rust/target diff --git a/.vscode/settings.json b/.vscode/settings.json index 776675a..0c1637e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,12 +1,13 @@ { - "python.testing.unittestArgs": [ - "-v", - "-s", - "./5 - unit testing", - "-p", - "*_test.py" - ], - "python.testing.pytestEnabled": false, - "python.testing.nosetestsEnabled": false, - "python.testing.unittestEnabled": true -} \ No newline at end of file + "python.testing.unittestArgs": [ + "-v", + "-s", + "./5 - unit testing", + "-p", + "*_test.py" + ], + "python.testing.pytestEnabled": false, + "python.testing.nosetestsEnabled": false, + "python.testing.unittestEnabled": true, + "cSpell.words": ["liskov"] +} diff --git a/10 - object creation/singleton.py b/10 - object creation/singleton.py index ccf245c..54370fb 100644 --- a/10 - object creation/singleton.py +++ b/10 - object creation/singleton.py @@ -2,7 +2,7 @@ class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: - cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] class Logger(metaclass=Singleton): diff --git a/3 - strategy pattern/strategy-after-fn.py b/3 - strategy pattern/strategy-after-fn.py index 892a284..be51f17 100644 --- a/3 - strategy pattern/strategy-after-fn.py +++ b/3 - strategy pattern/strategy-after-fn.py @@ -1,51 +1,55 @@ +from dataclasses import dataclass, field import string import random from typing import List, Callable -from abc import ABC, abstractmethod -def generate_id(length=8): +def generate_id(length: int = 8) -> str: # helper function for generating an id return ''.join(random.choices(string.ascii_uppercase, k=length)) +@dataclass class SupportTicket: + id: str = field(init=False, default_factory=generate_id) + customer: str + issue: str - def __init__(self, customer, issue): - self.id = generate_id() - self.customer = customer - self.issue = issue +SupportTickets = List[SupportTicket] -def fifoOrdering(list: List[SupportTicket]) -> List[SupportTicket]: +Ordering = Callable[[SupportTickets], SupportTickets] + + +def fifo_ordering(list: SupportTickets) -> SupportTickets: return list.copy() -def filoOrdering(list: List[SupportTicket]) -> List[SupportTicket]: +def filo_ordering(list: SupportTickets) -> SupportTickets: list_copy = list.copy() list_copy.reverse() return list_copy -def randomOrdering(list: List[SupportTicket]) -> List[SupportTicket]: +def random_ordering(list: SupportTickets) -> SupportTickets: list_copy = list.copy() random.shuffle(list_copy) return list_copy -def blackHoleOrdering(list: List[SupportTicket]) -> List[SupportTicket]: +def blackhole_ordering(_: SupportTickets) -> SupportTickets: return [] class CustomerSupport: def __init__(self): - self.tickets = [] + self.tickets: SupportTickets = [] def create_ticket(self, customer, issue): self.tickets.append(SupportTicket(customer, issue)) - def process_tickets(self, ordering: Callable[[List[SupportTicket]], List[SupportTicket]]): + def process_tickets(self, ordering: Ordering): # create the ordered list ticket_list = ordering(self.tickets) @@ -66,13 +70,20 @@ def process_ticket(self, ticket: SupportTicket): print("==================================") -# create the application -app = CustomerSupport() +def main() -> None: + # create the application + app = CustomerSupport() + + # register a few tickets + app.create_ticket("John Smith", "My computer makes strange sounds!") + app.create_ticket("Linus Sebastian", + "I can't upload any videos, please help.") + app.create_ticket( + "Arjan Egges", "VSCode doesn't automatically solve my bugs.") + + # process the tickets + app.process_tickets(random_ordering) -# register a few tickets -app.create_ticket("John Smith", "My computer makes strange sounds!") -app.create_ticket("Linus Sebastian", "I can't upload any videos, please help.") -app.create_ticket("Arjan Egges", "VSCode doesn't automatically solve my bugs.") -# process the tickets -app.process_tickets(blackHoleOrdering) +if __name__ == '__main__': + main() diff --git a/4 - observer pattern/api_v2/event.py b/4 - observer pattern/api_v2/event.py index 8c4d1bf..254afcd 100644 --- a/4 - observer pattern/api_v2/event.py +++ b/4 - observer pattern/api_v2/event.py @@ -1,8 +1,9 @@ -subscribers = dict() +from collections import defaultdict + +# Default value of the dictionary will be list +subscribers = defaultdict(list) def subscribe(event_type: str, fn): - if not event_type in subscribers: - subscribers[event_type] = [] subscribers[event_type].append(fn) def post_event(event_type: str, data): diff --git a/7 - dealing with errors/advanced/logging-decorator.py b/7 - dealing with errors/advanced/logging-decorator.py index 2627ccf..d0e99f2 100644 --- a/7 - dealing with errors/advanced/logging-decorator.py +++ b/7 - dealing with errors/advanced/logging-decorator.py @@ -9,7 +9,7 @@ def create_logger(): logger = logging.getLogger('exc_logger') logger.setLevel(logging.INFO) - #c reate a file to store all the + # create a file to store all the # logged exceptions logfile = logging.FileHandler('exc_logger.log') diff --git a/9 - solid/dependency-inversion-after.py b/9 - solid/dependency-inversion-after.py index c8a8eef..f1ccfe1 100644 --- a/9 - solid/dependency-inversion-after.py +++ b/9 - solid/dependency-inversion-after.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -19,13 +20,14 @@ def total_price(self): total += self.quantities[i] * self.prices[i] return total + class Authorizer(ABC): @abstractmethod def is_authorized(self) -> bool: pass -class Authorizer_SMS(Authorizer): +class AuthorizerSMS(Authorizer): def __init__(self): self.authorized = False @@ -37,7 +39,8 @@ def verify_code(self, code): def is_authorized(self) -> bool: return self.authorized -class Authorizer_Google(Authorizer): + +class AuthorizerGoogle(Authorizer): def __init__(self): self.authorized = False @@ -49,7 +52,8 @@ def verify_code(self, code): def is_authorized(self) -> bool: return self.authorized -class Authorizer_Robot(Authorizer): + +class AuthorizerRobot(Authorizer): def __init__(self): self.authorized = False @@ -73,7 +77,7 @@ class DebitPaymentProcessor(PaymentProcessor): def __init__(self, security_code, authorizer: Authorizer): self.security_code = security_code self.authorizer = authorizer - + def pay(self, order): if not self.authorizer.is_authorized(): raise Exception("Not authorized") @@ -81,6 +85,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def __init__(self, security_code): @@ -91,6 +96,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class PaypalPaymentProcessor(PaymentProcessor): def __init__(self, email_address, authorizer: Authorizer): @@ -111,8 +117,8 @@ def pay(self, order): order.add_item("USB cable", 2, 5) print(order.total_price()) -authorizer = Authorizer_Robot() +authorizer = AuthorizerRobot() # authorizer.verify_code(465839) authorizer.not_a_robot() processor = PaypalPaymentProcessor("hi@arjancodes.com", authorizer) -processor.pay(order) \ No newline at end of file +processor.pay(order) diff --git a/9 - solid/dependency-inversion-before.py b/9 - solid/dependency-inversion-before.py index 17778ff..3244130 100644 --- a/9 - solid/dependency-inversion-before.py +++ b/9 - solid/dependency-inversion-before.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -19,6 +20,7 @@ def total_price(self): total += self.quantities[i] * self.prices[i] return total + class SMSAuthorizer: def __init__(self): @@ -44,7 +46,7 @@ class DebitPaymentProcessor(PaymentProcessor): def __init__(self, security_code, authorizer: SMSAuthorizer): self.security_code = security_code self.authorizer = authorizer - + def pay(self, order): if not self.authorizer.is_authorized(): raise Exception("Not authorized") @@ -52,6 +54,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def __init__(self, security_code): @@ -62,6 +65,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class PaypalPaymentProcessor(PaymentProcessor): def __init__(self, email_address, authorizer: SMSAuthorizer): @@ -85,4 +89,4 @@ def pay(self, order): authorizer = SMSAuthorizer() # authorizer.verify_code(465839) processor = PaypalPaymentProcessor("hi@arjancodes.com", authorizer) -processor.pay(order) \ No newline at end of file +processor.pay(order) diff --git a/9 - solid/interface-segregation-after-comp.py b/9 - solid/interface-segregation-after-comp.py index 17778ff..3244130 100644 --- a/9 - solid/interface-segregation-after-comp.py +++ b/9 - solid/interface-segregation-after-comp.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -19,6 +20,7 @@ def total_price(self): total += self.quantities[i] * self.prices[i] return total + class SMSAuthorizer: def __init__(self): @@ -44,7 +46,7 @@ class DebitPaymentProcessor(PaymentProcessor): def __init__(self, security_code, authorizer: SMSAuthorizer): self.security_code = security_code self.authorizer = authorizer - + def pay(self, order): if not self.authorizer.is_authorized(): raise Exception("Not authorized") @@ -52,6 +54,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def __init__(self, security_code): @@ -62,6 +65,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class PaypalPaymentProcessor(PaymentProcessor): def __init__(self, email_address, authorizer: SMSAuthorizer): @@ -85,4 +89,4 @@ def pay(self, order): authorizer = SMSAuthorizer() # authorizer.verify_code(465839) processor = PaypalPaymentProcessor("hi@arjancodes.com", authorizer) -processor.pay(order) \ No newline at end of file +processor.pay(order) diff --git a/9 - solid/interface-segregation-after.py b/9 - solid/interface-segregation-after.py index 50dc15d..c60aa18 100644 --- a/9 - solid/interface-segregation-after.py +++ b/9 - solid/interface-segregation-after.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -26,7 +27,8 @@ class PaymentProcessor(ABC): def pay(self, order): pass -class PaymentProcessor_SMS(PaymentProcessor): + +class PaymentProcessorSMS(PaymentProcessor): @abstractmethod def auth_sms(self, code): @@ -36,7 +38,8 @@ def auth_sms(self, code): def pay(self, order): pass -class DebitPaymentProcessor(PaymentProcessor_SMS): + +class DebitPaymentProcessor(PaymentProcessorSMS): def __init__(self, security_code): self.security_code = security_code @@ -45,7 +48,7 @@ def __init__(self, security_code): def auth_sms(self, code): print(f"Verifying SMS code {code}") self.verified = True - + def pay(self, order): if not self.verified: raise Exception("Not authorized") @@ -53,6 +56,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def __init__(self, security_code): @@ -63,7 +67,8 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" -class PaypalPaymentProcessor(PaymentProcessor_SMS): + +class PaypalPaymentProcessor(PaymentProcessorSMS): def __init__(self, email_address): self.email_address = email_address @@ -89,4 +94,4 @@ def pay(self, order): print(order.total_price()) processor = PaypalPaymentProcessor("hi@arjancodes.com") processor.auth_sms(465839) -processor.pay(order) \ No newline at end of file +processor.pay(order) diff --git a/9 - solid/interface-segregation-before.py b/9 - solid/interface-segregation-before.py index fceb703..c9cdf22 100644 --- a/9 - solid/interface-segregation-before.py +++ b/9 - solid/interface-segregation-before.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -30,6 +31,7 @@ def auth_sms(self, code): def pay(self, order): pass + class DebitPaymentProcessor(PaymentProcessor): def __init__(self, security_code): @@ -39,7 +41,7 @@ def __init__(self, security_code): def auth_sms(self, code): print(f"Verifying SMS code {code}") self.verified = True - + def pay(self, order): if not self.verified: raise Exception("Not authorized") @@ -47,6 +49,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def __init__(self, security_code): @@ -60,6 +63,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class PaypalPaymentProcessor(PaymentProcessor): def __init__(self, email_address): @@ -86,4 +90,4 @@ def pay(self, order): print(order.total_price()) processor = DebitPaymentProcessor("2349875") processor.auth_sms(465839) -processor.pay(order) \ No newline at end of file +processor.pay(order) diff --git a/9 - solid/liskov-substitution-after.py b/9 - solid/liskov-substitution-after.py index a1e89d6..5bf63c4 100644 --- a/9 - solid/liskov-substitution-after.py +++ b/9 - solid/liskov-substitution-after.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -26,16 +27,18 @@ class PaymentProcessor(ABC): def pay(self, order): pass + class DebitPaymentProcessor(PaymentProcessor): def __init__(self, security_code): self.security_code = security_code - + def pay(self, order): print("Processing debit payment type") print(f"Verifying security code: {self.security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def __init__(self, security_code): @@ -46,6 +49,7 @@ def pay(self, order): print(f"Verifying security code: {self.security_code}") order.status = "paid" + class PaypalPaymentProcessor(PaymentProcessor): def __init__(self, email_address): @@ -64,4 +68,4 @@ def pay(self, order): print(order.total_price()) processor = PaypalPaymentProcessor("hi@arjancodes.com") -processor.pay(order) \ No newline at end of file +processor.pay(order) diff --git a/9 - solid/liskov-substitution-before.py b/9 - solid/liskov-substitution-before.py index d8da03b..46fb51a 100644 --- a/9 - solid/liskov-substitution-before.py +++ b/9 - solid/liskov-substitution-before.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -20,25 +21,27 @@ def total_price(self): return total - class PaymentProcessor(ABC): @abstractmethod def pay(self, order, security_code): pass + class DebitPaymentProcessor(PaymentProcessor): def pay(self, order, security_code): print("Processing debit payment type") print(f"Verifying security code: {security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def pay(self, order, security_code): print("Processing credit payment type") print(f"Verifying security code: {security_code}") order.status = "paid" + class PaypalPaymentProcessor(PaymentProcessor): def pay(self, order, security_code): print("Processing paypal payment type") @@ -53,4 +56,4 @@ def pay(self, order, security_code): print(order.total_price()) processor = PaypalPaymentProcessor() -processor.pay(order, "hi@arjancodes.com") \ No newline at end of file +processor.pay(order, "hi@arjancodes.com") diff --git a/9 - solid/open-closed-after.py b/9 - solid/open-closed-after.py index 47e1d6f..9103aa3 100644 --- a/9 - solid/open-closed-after.py +++ b/9 - solid/open-closed-after.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class Order: def __init__(self): @@ -20,19 +21,20 @@ def total_price(self): return total - class PaymentProcessor(ABC): @abstractmethod def pay(self, order, security_code): pass + class DebitPaymentProcessor(PaymentProcessor): def pay(self, order, security_code): print("Processing debit payment type") print(f"Verifying security code: {security_code}") order.status = "paid" + class CreditPaymentProcessor(PaymentProcessor): def pay(self, order, security_code): print("Processing credit payment type") @@ -47,4 +49,4 @@ def pay(self, order, security_code): print(order.total_price()) processor = DebitPaymentProcessor() -processor.pay(order, "0372846") \ No newline at end of file +processor.pay(order, "0372846") diff --git a/9 - solid/open-closed-before.py b/9 - solid/open-closed-before.py index 70d0193..13bb60e 100644 --- a/9 - solid/open-closed-before.py +++ b/9 - solid/open-closed-before.py @@ -17,6 +17,7 @@ def total_price(self): total += self.quantities[i] * self.prices[i] return total + class PaymentProcessor: def pay_debit(self, order, security_code): print("Processing debit payment type") @@ -36,4 +37,4 @@ def pay_credit(self, order, security_code): print(order.total_price()) processor = PaymentProcessor() -processor.pay_debit(order, "0372846") \ No newline at end of file +processor.pay_debit(order, "0372846") diff --git a/9 - solid/single-responsibility-after.py b/9 - solid/single-responsibility-after.py index 70d0193..13bb60e 100644 --- a/9 - solid/single-responsibility-after.py +++ b/9 - solid/single-responsibility-after.py @@ -17,6 +17,7 @@ def total_price(self): total += self.quantities[i] * self.prices[i] return total + class PaymentProcessor: def pay_debit(self, order, security_code): print("Processing debit payment type") @@ -36,4 +37,4 @@ def pay_credit(self, order, security_code): print(order.total_price()) processor = PaymentProcessor() -processor.pay_debit(order, "0372846") \ No newline at end of file +processor.pay_debit(order, "0372846") diff --git a/9 - solid/single-responsibility-before.py b/9 - solid/single-responsibility-before.py index 6496d52..696a5d1 100644 --- a/9 - solid/single-responsibility-before.py +++ b/9 - solid/single-responsibility-before.py @@ -29,10 +29,11 @@ def pay(self, payment_type, security_code): else: raise Exception(f"Unknown payment type: {payment_type}") + order = Order() order.add_item("Keyboard", 1, 50) order.add_item("SSD", 1, 150) order.add_item("USB cable", 2, 5) print(order.total_price()) -order.pay("debit", "0372846") \ No newline at end of file +order.pay("debit", "0372846") diff --git a/better-rust/Cargo.lock b/better-rust/Cargo.lock new file mode 100644 index 0000000..a5c57b9 --- /dev/null +++ b/better-rust/Cargo.lock @@ -0,0 +1,130 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "better-rust" +version = "0.1.0" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "coupling_and_cohesion" +version = "0.1.0" +dependencies = [ + "macros", + "rand", +] + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "macros" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "solid" +version = "0.1.0" +dependencies = [ + "macros", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/better-rust/Cargo.toml b/better-rust/Cargo.toml new file mode 100644 index 0000000..1ba3465 --- /dev/null +++ b/better-rust/Cargo.toml @@ -0,0 +1,9 @@ +workspace = { members = ["solid", "macros", "coupling_and_cohesion"] } +[package] +name = "better-rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/better-rust/coupling_and_cohesion/Cargo.toml b/better-rust/coupling_and_cohesion/Cargo.toml new file mode 100644 index 0000000..7d0bc68 --- /dev/null +++ b/better-rust/coupling_and_cohesion/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "coupling_and_cohesion" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" +macros = { path = "../macros" } diff --git a/better-rust/coupling_and_cohesion/src/coupling_cohesion_after.rs b/better-rust/coupling_and_cohesion/src/coupling_cohesion_after.rs new file mode 100644 index 0000000..7106028 --- /dev/null +++ b/better-rust/coupling_and_cohesion/src/coupling_cohesion_after.rs @@ -0,0 +1,111 @@ +use std::collections::HashMap; +use rand::{self, Rng}; + +fn generate_random_string(length: usize, digits: bool) -> String { + rand::thread_rng() + .sample_iter(rand::distributions::Alphanumeric) + .map(char::from) + .filter(|c| if digits { c.is_digit(10) } else { !c.is_digit(10) }) + .map(|c| c.to_ascii_uppercase()) + .take(length) + .collect() +} + +#[derive(Clone)] +pub struct VehicleInfo { + pub brand: String, + pub electric: bool, + pub catalogue_price: u32, +} + +impl VehicleInfo { + pub fn new(brand: &str, electric: bool, catalogue_price: u32) -> Self { + Self { brand: brand.to_string(), electric, catalogue_price } + } + + pub fn compute_tax(&self) -> f32 { + let mut tax_percentage = 0.05; + if self.electric { + tax_percentage = 0.02; + } + + tax_percentage * self.catalogue_price as f32 + } + + pub fn print(&self) { + println!("Brand: {}", self.brand); + println!("Payable tax: {:#?}", self.compute_tax()); + } +} + +pub struct Vehicle { + pub id: String, + pub license_plate: String, + pub info: VehicleInfo, +} + +impl Vehicle { + pub fn new(id: &str, license_plate: String, info: VehicleInfo) -> Self { + Self { id: id.to_string(), license_plate, info } + } + + pub fn print(&self) { + println!("Registration complete. Vehicle information:"); + println!("Id: {}", self.id); + println!("License plate: {}", self.license_plate); + self.info.print(); + } +} +pub struct VehicleRegistry { + pub vehicle_info: HashMap, +} + +impl VehicleRegistry { + pub fn new() -> Self { + let mut vehicle_registry = Self { vehicle_info: HashMap::new() }; + + vehicle_registry.add_vehicle_info("Tesla Model 3", true, 60000); + vehicle_registry.add_vehicle_info("Volkswagen ID3", true, 35000); + vehicle_registry.add_vehicle_info("BMW 5", false, 45000); + vehicle_registry.add_vehicle_info("Tesla Model Y", true, 75000); + + vehicle_registry + } + + fn add_vehicle_info(&mut self, brand: &str, electric: bool, catalogue_price: u32) { + self.vehicle_info.insert(brand.to_string(), VehicleInfo::new(brand, electric, catalogue_price)); + } + + pub fn generate_vehicle_id(&self, length: usize) -> String { + generate_random_string(length, false) + } + + pub fn generate_vehicle_license(&self, id: &str) -> String { + let front = &id[0..2]; + let middle = generate_random_string(2, true); + let last = generate_random_string(2, false); + + format!("{front}-{middle}-{last}") + } + + pub fn create_vehicle(&self, brand: &str) -> Vehicle { + let id = self.generate_vehicle_id(12); + let license_plate = self.generate_vehicle_license(&id); + + Vehicle::new(&id, license_plate, self.vehicle_info.get(brand).unwrap().clone()) + } +} + +pub struct Application; + +impl Application { + pub fn register_vehicle(&self, brand: &str) { + // create a registry instance + let registry = VehicleRegistry::new(); + + let vehicle = registry.create_vehicle(brand); + + // print out the vehicle information + vehicle.print(); + } +} \ No newline at end of file diff --git a/better-rust/coupling_and_cohesion/src/coupling_cohesion_before.rs b/better-rust/coupling_and_cohesion/src/coupling_cohesion_before.rs new file mode 100644 index 0000000..0abc32c --- /dev/null +++ b/better-rust/coupling_and_cohesion/src/coupling_cohesion_before.rs @@ -0,0 +1,71 @@ +use rand::{self, Rng}; + +fn generate_random_string(length: usize, digits: bool) -> String { + rand::thread_rng() + .sample_iter(rand::distributions::Alphanumeric) + .map(char::from) + .filter(|c| if digits { c.is_digit(10) } else { !c.is_digit(10) }) + .map(|c| c.to_ascii_uppercase()) + .take(length) + .collect() +} + +pub struct VehicleRegistry; + +impl VehicleRegistry { + pub fn generate_vehicle_id(&self, length: usize) -> String { + generate_random_string(length, false) + } + + pub fn generate_vehicle_license(&self, id: &str) -> String { + let front = &id[0..2]; + let middle = generate_random_string(2, true); + let last = generate_random_string(2, false); + + format!("{front}-{middle}-{last}") + } +} + +pub struct Application; + +impl Application { + pub fn register_vehicle(&self, brand: &str) { + // create a registry instance + let registry = VehicleRegistry; + + // generate a vehicle id of length 12 + let vehicle_id = registry.generate_vehicle_id(12); + + // now generate a license plate for the vehicle + // using the first two characters of the vehicle id + let license_plate = registry.generate_vehicle_license(&vehicle_id); + + // compute the catalogue price + let mut catalogue_price = 0; + + if brand == "Tesla Model 3" { + catalogue_price = 60000; + } else if brand == "Volkswagen ID3" { + catalogue_price = 35000; + } else if brand == "BMW 5" { + catalogue_price = 45000; + } + + // compute the tax percentage (default 5% of the catalogue price, except for electric cars where it is 2%) + let mut tax_percentage = 0.05; + + if brand == "Tesla Model 3" || brand == "Volkswagen ID3" { + tax_percentage = 0.02; + } + + // compute the payable tax + let payable_tax = tax_percentage * catalogue_price as f32; + + // print out the vehicle registration information + println!("Registration complete. Vehicle information:"); + println!("Brand: {brand}"); + println!("Id: {vehicle_id}"); + println!("License plate: {license_plate}"); + println!("Payable tax: {payable_tax:?}"); + } +} \ No newline at end of file diff --git a/better-rust/coupling_and_cohesion/src/main.rs b/better-rust/coupling_and_cohesion/src/main.rs new file mode 100644 index 0000000..f735133 --- /dev/null +++ b/better-rust/coupling_and_cohesion/src/main.rs @@ -0,0 +1,26 @@ +mod coupling_cohesion_before; +mod coupling_cohesion_after; + +fn main() { + coupling_cohesion_before(); + + coupling_cohesion_after(); +} + +#[macros::example] +fn coupling_cohesion_before() { + use coupling_cohesion_before::*; + + let app = Application; + + app.register_vehicle("Volkswagen ID3"); +} + +#[macros::example] +fn coupling_cohesion_after() { + use coupling_cohesion_after::*; + + let app = Application; + + app.register_vehicle("Volkswagen ID3"); +} diff --git a/better-rust/macros/Cargo.toml b/better-rust/macros/Cargo.toml new file mode 100644 index 0000000..a907c20 --- /dev/null +++ b/better-rust/macros/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "macros" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "*", features = ["full"]} +quote = "1.0" \ No newline at end of file diff --git a/better-rust/macros/src/lib.rs b/better-rust/macros/src/lib.rs new file mode 100644 index 0000000..b1ac13e --- /dev/null +++ b/better-rust/macros/src/lib.rs @@ -0,0 +1,21 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn; + +#[proc_macro_attribute] +pub fn example(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(item as syn::ItemFn); + let ident = input.sig.ident; + let name = ident.clone().to_string(); + let block = input.block; + + let gen = quote! { + fn #ident() { + println!("running `{}`:\n", #name); + #block; + println!("-------------\n"); + } + }; + + gen.into() +} \ No newline at end of file diff --git a/better-rust/solid/Cargo.toml b/better-rust/solid/Cargo.toml new file mode 100644 index 0000000..d9f9dd6 --- /dev/null +++ b/better-rust/solid/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "solid" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +macros ={ path = "../macros" } \ No newline at end of file diff --git a/better-rust/solid/src/dependency_inversion_after.rs b/better-rust/solid/src/dependency_inversion_after.rs new file mode 100644 index 0000000..1ad88e6 --- /dev/null +++ b/better-rust/solid/src/dependency_inversion_after.rs @@ -0,0 +1,144 @@ +use std::cell::RefCell; + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub trait Authorizer { + fn is_authorized(&self) -> bool; +} + +pub struct SMSAuthorizer { + pub authorized: bool, +} + +impl SMSAuthorizer { + pub fn new() -> Self { + Self { authorized: false } + } + + pub fn verify_code(&mut self, code: u32) { + println!("Verifying SMS code {code}"); + self.authorized = true; + } +} + +impl Authorizer for SMSAuthorizer { + fn is_authorized(&self) -> bool { + self.authorized + } +} + +pub struct AuthorizerRobot { + pub authorized: bool, +} + +impl AuthorizerRobot { + pub fn new() -> Self { + Self { authorized: false } + } + + pub fn not_a_robot(&mut self) { + println!("Are you a robot?"); + self.authorized = true; + } +} + +impl Authorizer for AuthorizerRobot { + fn is_authorized(&self) -> bool { + self.authorized + } +} + +pub trait PaymentProcessor { + fn pay(&self, order: &mut Order); +} + +pub struct DebitPaymentProcessor<'a> { + pub security_code: &'a str, + pub authorizer: &'a RefCell, +} + +impl<'a> DebitPaymentProcessor<'a> { + pub fn new(security_code: &'a str, authorizer: &'a RefCell) -> Self { + Self { security_code, authorizer } + } +} + +impl PaymentProcessor for DebitPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + if !self.authorizer.borrow().is_authorized() { + panic!("Not authorized"); + } + + println!("Processing debit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct CreditPaymentProcessor<'a> { + pub security_code: &'a str, +} + +impl<'a> CreditPaymentProcessor<'a> { + pub fn new(security_code: &'a str) -> Self { + Self { security_code } + } +} + +impl PaymentProcessor for CreditPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + println!("Processing credit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct PaypalPaymentProcessor<'a> { + pub email_address: &'a str, + pub authorizer: &'a RefCell, +} + +impl<'a> PaypalPaymentProcessor<'a> { + pub fn new(email_address: &'a str, authorizer: &'a RefCell) -> Self { + Self { email_address, authorizer } + } +} + +impl PaymentProcessor for PaypalPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + if !self.authorizer.borrow().is_authorized() { + panic!("Not authorized"); + } + + println!("Processing paypal payment type"); + println!("Using email address: {}", {self.email_address}); + order.status = "paid"; + } +} diff --git a/better-rust/solid/src/dependency_inversion_before.rs b/better-rust/solid/src/dependency_inversion_before.rs new file mode 100644 index 0000000..38de58c --- /dev/null +++ b/better-rust/solid/src/dependency_inversion_before.rs @@ -0,0 +1,117 @@ +use std::cell::RefCell; + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub struct SMSAuthorizer { + pub authorized: bool, +} + +impl SMSAuthorizer { + pub fn new() -> Self { + Self { authorized: false } + } + + pub fn verify_code(&mut self, code: u32) { + println!("Verifying SMS code {code}"); + self.authorized = true; + } + + fn is_authorized(&self) -> bool { + self.authorized + } +} + +pub trait PaymentProcessor { + fn pay(&self, order: &mut Order); +} + +pub struct DebitPaymentProcessor<'a> { + pub security_code: &'a str, + pub authorizer: &'a RefCell, +} + +impl<'a> DebitPaymentProcessor<'a> { + pub fn new(security_code: &'a str, authorizer: &'a RefCell) -> Self { + Self { security_code, authorizer } + } +} + +impl PaymentProcessor for DebitPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + if !self.authorizer.borrow().is_authorized() { + panic!("Not authorized"); + } + + println!("Processing debit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct CreditPaymentProcessor<'a> { + pub security_code: &'a str, +} + +impl<'a> CreditPaymentProcessor<'a> { + pub fn new(security_code: &'a str) -> Self { + Self { security_code } + } +} + +impl PaymentProcessor for CreditPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + println!("Processing credit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct PaypalPaymentProcessor<'a> { + pub email_address: &'a str, + pub authorizer: &'a RefCell, +} + +impl<'a> PaypalPaymentProcessor<'a> { + pub fn new(email_address: &'a str, authorizer: &'a RefCell) -> Self { + Self { email_address, authorizer } + } +} + +impl PaymentProcessor for PaypalPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + if !self.authorizer.borrow().is_authorized() { + panic!("Not authorized"); + } + + println!("Processing paypal payment type"); + println!("Using email address: {}", {self.email_address}); + order.status = "paid"; + } +} diff --git a/better-rust/solid/src/interface_segregation_after.rs b/better-rust/solid/src/interface_segregation_after.rs new file mode 100644 index 0000000..38de58c --- /dev/null +++ b/better-rust/solid/src/interface_segregation_after.rs @@ -0,0 +1,117 @@ +use std::cell::RefCell; + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub struct SMSAuthorizer { + pub authorized: bool, +} + +impl SMSAuthorizer { + pub fn new() -> Self { + Self { authorized: false } + } + + pub fn verify_code(&mut self, code: u32) { + println!("Verifying SMS code {code}"); + self.authorized = true; + } + + fn is_authorized(&self) -> bool { + self.authorized + } +} + +pub trait PaymentProcessor { + fn pay(&self, order: &mut Order); +} + +pub struct DebitPaymentProcessor<'a> { + pub security_code: &'a str, + pub authorizer: &'a RefCell, +} + +impl<'a> DebitPaymentProcessor<'a> { + pub fn new(security_code: &'a str, authorizer: &'a RefCell) -> Self { + Self { security_code, authorizer } + } +} + +impl PaymentProcessor for DebitPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + if !self.authorizer.borrow().is_authorized() { + panic!("Not authorized"); + } + + println!("Processing debit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct CreditPaymentProcessor<'a> { + pub security_code: &'a str, +} + +impl<'a> CreditPaymentProcessor<'a> { + pub fn new(security_code: &'a str) -> Self { + Self { security_code } + } +} + +impl PaymentProcessor for CreditPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + println!("Processing credit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct PaypalPaymentProcessor<'a> { + pub email_address: &'a str, + pub authorizer: &'a RefCell, +} + +impl<'a> PaypalPaymentProcessor<'a> { + pub fn new(email_address: &'a str, authorizer: &'a RefCell) -> Self { + Self { email_address, authorizer } + } +} + +impl PaymentProcessor for PaypalPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + if !self.authorizer.borrow().is_authorized() { + panic!("Not authorized"); + } + + println!("Processing paypal payment type"); + println!("Using email address: {}", {self.email_address}); + order.status = "paid"; + } +} diff --git a/better-rust/solid/src/interface_segregation_before.rs b/better-rust/solid/src/interface_segregation_before.rs new file mode 100644 index 0000000..f3a503c --- /dev/null +++ b/better-rust/solid/src/interface_segregation_before.rs @@ -0,0 +1,105 @@ + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub trait PaymentProcessor { + fn auth_sms(&mut self, code: u32); + + fn pay(&self, order: &mut Order); +} + +pub struct DebitPaymentProcessor<'a> { + pub security_code: &'a str, + pub verified: bool, +} + +impl<'a> DebitPaymentProcessor<'a> { + pub fn new(security_code: &'a str) -> Self { + Self { security_code, verified: false } + } +} + +impl PaymentProcessor for DebitPaymentProcessor<'_> { + fn auth_sms(&mut self, code: u32) { + println!("Verifying SMS code {code}"); + self.verified = true; + } + + fn pay(&self, order: &mut Order) { + println!("Processing debit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct CreditPaymentProcessor<'a> { + pub security_code: &'a str, +} + +impl<'a> CreditPaymentProcessor<'a> { + pub fn new(security_code: &'a str) -> Self { + Self { security_code } + } +} + +impl PaymentProcessor for CreditPaymentProcessor<'_> { + fn auth_sms(&mut self, _code: u32) { + panic!("Credit card payments don't support SMS code authorization."); + } + + fn pay(&self, order: &mut Order) { + println!("Processing credit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct PaypalPaymentProcessor<'a> { + pub email_address: &'a str, + pub verified: bool, +} + +impl<'a> PaypalPaymentProcessor<'a> { + pub fn new(email_address: &'a str) -> Self { + Self { email_address, verified: false } + } +} + +impl PaymentProcessor for PaypalPaymentProcessor<'_> { + fn auth_sms(&mut self, code: u32) { + println!("Verifying SMS code {code}"); + self.verified = true; + } + + fn pay(&self, order: &mut Order) { + println!("Processing paypal payment type"); + println!("Using email address: {}", {self.email_address}); + order.status = "paid"; + } +} diff --git a/better-rust/solid/src/lib.rs b/better-rust/solid/src/lib.rs new file mode 100644 index 0000000..768e5b8 --- /dev/null +++ b/better-rust/solid/src/lib.rs @@ -0,0 +1,10 @@ +pub mod single_responsibility_before; +pub mod single_responsibility_after; +pub mod open_closed_before; +pub mod open_closed_after; +pub mod liskov_substitution_before; +pub mod liskov_substitution_after; +pub mod interface_segregation_before; +pub mod interface_segregation_after; +pub mod dependency_inversion_before; +pub mod dependency_inversion_after; \ No newline at end of file diff --git a/better-rust/solid/src/liskov_substitution_after.rs b/better-rust/solid/src/liskov_substitution_after.rs new file mode 100644 index 0000000..907ba08 --- /dev/null +++ b/better-rust/solid/src/liskov_substitution_after.rs @@ -0,0 +1,87 @@ + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub trait PaymentProcessor { + fn pay(&self, order: &mut Order); +} + +pub struct DebitPaymentProcessor<'a> { + pub security_code: &'a str, +} + +impl<'a> DebitPaymentProcessor<'a> { + pub fn new(security_code: &'a str) -> Self { + Self { security_code } + } +} + +impl PaymentProcessor for DebitPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + println!("Processing debit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct CreditPaymentProcessor<'a> { + pub security_code: &'a str, +} + +impl<'a> CreditPaymentProcessor<'a> { + pub fn new(security_code: &'a str) -> Self { + Self { security_code } + } +} + +impl PaymentProcessor for CreditPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + println!("Processing credit payment type"); + println!("Verifying security code: {}", {self.security_code}); + order.status = "paid"; + } +} + +pub struct PaypalPaymentProcessor<'a> { + pub email_address: &'a str, +} + +impl<'a> PaypalPaymentProcessor<'a> { + pub fn new(email_address: &'a str) -> Self { + Self { email_address } + } +} + +impl PaymentProcessor for PaypalPaymentProcessor<'_> { + fn pay(&self, order: &mut Order) { + println!("Processing paypal payment type"); + println!("Using email address: {}", {self.email_address}); + order.status = "paid"; + } +} diff --git a/better-rust/solid/src/liskov_substitution_before.rs b/better-rust/solid/src/liskov_substitution_before.rs new file mode 100644 index 0000000..133f647 --- /dev/null +++ b/better-rust/solid/src/liskov_substitution_before.rs @@ -0,0 +1,63 @@ + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub trait PaymentProcessor { + fn pay(&self, order: &mut Order, security_code: &str); +} + +pub struct DebitPaymentProcessor; + +impl PaymentProcessor for DebitPaymentProcessor { + fn pay(&self, order: &mut Order, security_code: &str) { + println!("Processing debit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } +} + +pub struct CreditPaymentProcessor; + +impl PaymentProcessor for CreditPaymentProcessor { + fn pay(&self, order: &mut Order, security_code: &str) { + println!("Processing credit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } +} + +pub struct PaypalPaymentProcessor; + +impl PaymentProcessor for PaypalPaymentProcessor { + fn pay(&self, order: &mut Order, security_code: &str) { + println!("Processing paypal payment type"); + println!("Using email address: {security_code}"); + order.status = "paid"; + } +} diff --git a/better-rust/solid/src/main.rs b/better-rust/solid/src/main.rs new file mode 100644 index 0000000..d6719f3 --- /dev/null +++ b/better-rust/solid/src/main.rs @@ -0,0 +1,139 @@ +use std::cell::RefCell; + +fn main() { + single_responsibility_before(); + + single_responsibility_after(); + + open_closed(); + + liskov_substitution(); + + interface_segregation_before(); + + interface_segregation_after(); + + dependency_inversion(); +} + +#[macros::example] +fn single_responsibility_before() { + use solid::single_responsibility_before::*; + + let mut order = Order::new(); + + order.add_item("Keyboard", 1, 50.0); + order.add_item("SSD", 1, 150.0); + order.add_item("USB cable", 2, 5.0); + + println!("{}", order.total_price()); + order.pay("debit", "0372846"); +} + +#[macros::example] +fn single_responsibility_after() { + use solid::single_responsibility_after::*; + + let mut order = Order::new(); + + order.add_item("Keyboard", 1, 50.0); + order.add_item("SSD", 1, 150.0); + order.add_item("USB cable", 2, 5.0); + + println!("{}", order.total_price()); + + let processor = PaymentProcessor {}; + + processor.pay_debit(&mut order, "0372846"); +} + +#[macros::example] +fn open_closed() { + use solid::open_closed_after::*; + + let mut order = Order::new(); + + order.add_item("Keyboard", 1, 50.0); + order.add_item("SSD", 1, 150.0); + order.add_item("USB cable", 2, 5.0); + + println!("{}", order.total_price()); + + let processor = DebitPaymentProcessor {}; + + processor.pay(&mut order, "0372846"); +} + +#[macros::example] +fn liskov_substitution() { + use solid::liskov_substitution_after::*; + + let mut order = Order::new(); + + order.add_item("Keyboard", 1, 50.0); + order.add_item("SSD", 1, 150.0); + order.add_item("USB cable", 2, 5.0); + + println!("{}", order.total_price()); + + let processor = PaypalPaymentProcessor::new("hi@arjancodes.com"); + + processor.pay(&mut order); +} + +#[macros::example] +fn interface_segregation_before() { + use solid::interface_segregation_before::*; + + let mut order = Order::new(); + + order.add_item("Keyboard", 1, 50.0); + order.add_item("SSD", 1, 150.0); + order.add_item("USB cable", 2, 5.0); + + println!("{}", order.total_price()); + + let mut processor = DebitPaymentProcessor::new("2349875"); + processor.auth_sms(465839); + processor.pay(&mut order); +} + +#[macros::example] +fn interface_segregation_after() { + use solid::interface_segregation_after::*; + + let mut order = Order::new(); + + order.add_item("Keyboard", 1, 50.0); + order.add_item("SSD", 1, 150.0); + order.add_item("USB cable", 2, 5.0); + + println!("{}", order.total_price()); + + let authorizer = RefCell::new(SMSAuthorizer::new()); + + let processor = PaypalPaymentProcessor::new("hi@arjancodes.com", &authorizer); + authorizer.borrow_mut().verify_code(465839); + processor.pay(&mut order); +} + +#[macros::example] +fn dependency_inversion() { + use solid::dependency_inversion_after::*; + + let mut order = Order::new(); + + order.add_item("Keyboard", 1, 50.0); + order.add_item("SSD", 1, 150.0); + order.add_item("USB cable", 2, 5.0); + + println!("{}", order.total_price()); + + // let authorizer = RefCell::new(SMSAuthorizer::new()); + let authorizer = RefCell::new(AuthorizerRobot::new()); + + let processor = PaypalPaymentProcessor::new("hi@arjancodes.com", &authorizer); + // authorizer.borrow_mut().verify_code(465839); + authorizer.borrow_mut().not_a_robot(); + processor.pay(&mut order); +} \ No newline at end of file diff --git a/better-rust/solid/src/open_closed_after.rs b/better-rust/solid/src/open_closed_after.rs new file mode 100644 index 0000000..8929db1 --- /dev/null +++ b/better-rust/solid/src/open_closed_after.rs @@ -0,0 +1,53 @@ + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub trait PaymentProcessor { + fn pay(&self, order: &mut Order, security_code: &str); +} + +pub struct DebitPaymentProcessor; + +impl PaymentProcessor for DebitPaymentProcessor { + fn pay(&self, order: &mut Order, security_code: &str) { + println!("Processing debit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } +} + +pub struct CreditPaymentProcessor; + +impl PaymentProcessor for CreditPaymentProcessor { + fn pay(&self, order: &mut Order, security_code: &str) { + println!("Processing credit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } +} diff --git a/better-rust/solid/src/open_closed_before.rs b/better-rust/solid/src/open_closed_before.rs new file mode 100644 index 0000000..fb3cfe7 --- /dev/null +++ b/better-rust/solid/src/open_closed_before.rs @@ -0,0 +1,45 @@ + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub struct PaymentProcessor; + +impl PaymentProcessor { + pub fn pay_debit(&self, order: &mut Order, security_code: &str) { + println!("Processing debit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } + + pub fn pay_credit(&self, order: &mut Order, security_code: &str) { + println!("Processing credit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } +} \ No newline at end of file diff --git a/better-rust/solid/src/single_responsibility_after.rs b/better-rust/solid/src/single_responsibility_after.rs new file mode 100644 index 0000000..fb3cfe7 --- /dev/null +++ b/better-rust/solid/src/single_responsibility_after.rs @@ -0,0 +1,45 @@ + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } +} + +pub struct PaymentProcessor; + +impl PaymentProcessor { + pub fn pay_debit(&self, order: &mut Order, security_code: &str) { + println!("Processing debit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } + + pub fn pay_credit(&self, order: &mut Order, security_code: &str) { + println!("Processing credit payment type"); + println!("Verifying security code: {security_code}"); + order.status = "paid"; + } +} \ No newline at end of file diff --git a/better-rust/solid/src/single_responsibility_before.rs b/better-rust/solid/src/single_responsibility_before.rs new file mode 100644 index 0000000..9c7f91f --- /dev/null +++ b/better-rust/solid/src/single_responsibility_before.rs @@ -0,0 +1,43 @@ + +pub struct Order<'a> { + pub items: Vec<&'a str>, + pub quantities: Vec, + pub prices: Vec, + pub status: &'a str, +} + +impl<'a> Order<'a> { + pub fn new() -> Self { + Self { items: vec![], quantities: vec![], prices: vec![], status: "open" } + } + + pub fn add_item(&mut self, name: &'a str, quantity: u32, price: f32) { + self.items.push(name); + self.quantities.push(quantity); + self.prices.push(price); + } + + pub fn total_price(&self) -> f32 { + let mut total: f32 = 0.0; + + for (i, price) in self.prices.iter().enumerate() { + total += self.quantities[i] as f32 * price; + } + + total + } + + pub fn pay(&mut self, payment_type: &str, security_code: &str) { + if payment_type == "debit" { + println!("Processing debit payment type"); + println!("Verifying security code: {security_code}"); + self.status = "paid"; + } else if payment_type == "credit" { + println!("Processing credit payment type"); + println!("Verifying security code: {security_code}"); + self.status = "paid"; + } else { + panic!("Unknown payment type: {payment_type}"); + } + } +} \ No newline at end of file diff --git a/better-rust/src/main.rs b/better-rust/src/main.rs new file mode 100644 index 0000000..7da3a48 --- /dev/null +++ b/better-rust/src/main.rs @@ -0,0 +1,4 @@ + +fn main() { + println!("Hello, world!"); +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3e1e305 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +flask +returns