@icarusmx/creta 1.0.23 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +2 -1
- package/bin/creta.js +53 -14
- package/lessons/lesson7-object-definition.js +392 -0
- package/package.json +11 -3
package/bin/creta.js
CHANGED
|
@@ -12,6 +12,7 @@ import { Lesson3OnlyWay } from '../lessons/lesson3-only-way.js'
|
|
|
12
12
|
import { Lesson4OperationSignatures } from '../lessons/lesson4-operation-signatures.js'
|
|
13
13
|
import { Lesson5InterfaceSet } from '../lessons/lesson5-interface-set.js'
|
|
14
14
|
import { Lesson6InterfaceDesign } from '../lessons/lesson6-interface-design.js'
|
|
15
|
+
import { Lesson7ObjectDefinition } from '../lessons/lesson7-object-definition.js'
|
|
15
16
|
|
|
16
17
|
const ENUNCIADOS = [
|
|
17
18
|
{
|
|
@@ -49,6 +50,12 @@ const ENUNCIADOS = [
|
|
|
49
50
|
texto: "El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces.",
|
|
50
51
|
nivel: "Diseño",
|
|
51
52
|
enfoque: "Metodología de desarrollo"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 7,
|
|
56
|
+
texto: "Un objeto es un conjunto de datos y procedimientos que operan sobre esos datos.",
|
|
57
|
+
nivel: "Definición",
|
|
58
|
+
enfoque: "Naturaleza del objeto"
|
|
52
59
|
}
|
|
53
60
|
]
|
|
54
61
|
|
|
@@ -579,8 +586,8 @@ async function unstuckProject(level) {
|
|
|
579
586
|
|
|
580
587
|
function showHelp() {
|
|
581
588
|
console.log("\n📚 Comandos disponibles:")
|
|
582
|
-
console.log(" creta - Explora los
|
|
583
|
-
console.log(" creta enunciados - Explora los
|
|
589
|
+
console.log(" creta - Explora los 7 enunciados fundamentales (comando principal) 🧠")
|
|
590
|
+
console.log(" creta enunciados - Explora los 7 enunciados fundamentales 🧠")
|
|
584
591
|
console.log(" creta portafolio - Crea tu portafolio personal (reto completo)")
|
|
585
592
|
console.log(" creta portafolio-1 - Desbloquea nivel 1 (navbar) 🔓")
|
|
586
593
|
console.log(" creta portafolio-2 - Desbloquea nivel 2 (navbar + hero) 🔓")
|
|
@@ -666,7 +673,7 @@ Salgamos de este laberinto 🏛️
|
|
|
666
673
|
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
667
674
|
process.stdin.setRawMode(false)
|
|
668
675
|
process.stdin.removeListener('data', onKeyPress)
|
|
669
|
-
console.log("\
|
|
676
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
670
677
|
resolve()
|
|
671
678
|
return
|
|
672
679
|
}
|
|
@@ -725,7 +732,7 @@ async function startMainMenuFallback() {
|
|
|
725
732
|
const respuesta = await askQuestion("Elige una opción (1-2) o 'q' para salir: ")
|
|
726
733
|
|
|
727
734
|
if (respuesta.toLowerCase() === 'q') {
|
|
728
|
-
console.log("
|
|
735
|
+
console.log("Hecho con <3 por icarus.mx")
|
|
729
736
|
rl.close()
|
|
730
737
|
return
|
|
731
738
|
}
|
|
@@ -822,8 +829,8 @@ async function startEnunciadosSelectorInteractive() {
|
|
|
822
829
|
let formattedText = enunciado.texto
|
|
823
830
|
if (enunciado.id === 4) {
|
|
824
831
|
// Special formatting for enunciado 4 with list items
|
|
825
|
-
formattedText = formattedText.replace(/\n([abc])\)/g, '\n
|
|
826
|
-
formattedText = formattedText.replace(/\n\nEstos tres elementos/g, '\n\n
|
|
832
|
+
formattedText = formattedText.replace(/\n([abc])\)/g, '\n $1)')
|
|
833
|
+
formattedText = formattedText.replace(/\n\nEstos tres elementos/g, '\n\n Estos tres elementos')
|
|
827
834
|
}
|
|
828
835
|
console.log(`${highlight}${prefix}${index + 1}. ${formattedText}${reset}`)
|
|
829
836
|
console.log("")
|
|
@@ -837,7 +844,7 @@ async function startEnunciadosSelectorInteractive() {
|
|
|
837
844
|
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
838
845
|
process.stdin.setRawMode(false)
|
|
839
846
|
process.stdin.removeListener('data', onKeyPress)
|
|
840
|
-
console.log("\
|
|
847
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
841
848
|
resolve()
|
|
842
849
|
return
|
|
843
850
|
}
|
|
@@ -965,6 +972,22 @@ async function startEnunciadosSelectorInteractive() {
|
|
|
965
972
|
console.log("- Proyectos específicos para internalizar la idea")
|
|
966
973
|
await returnToMainMenu()
|
|
967
974
|
}
|
|
975
|
+
} else if (enunciadoSeleccionado.id === 7) {
|
|
976
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
977
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
978
|
+
|
|
979
|
+
try {
|
|
980
|
+
const lesson7 = new Lesson7ObjectDefinition()
|
|
981
|
+
await lesson7.start()
|
|
982
|
+
await returnToMainMenu()
|
|
983
|
+
} catch (error) {
|
|
984
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
985
|
+
console.log("\n🚀 Próximamente:")
|
|
986
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
987
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
988
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
989
|
+
await returnToMainMenu()
|
|
990
|
+
}
|
|
968
991
|
} else {
|
|
969
992
|
console.log("\n🚀 Próximamente:")
|
|
970
993
|
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
@@ -1028,17 +1051,17 @@ async function startEnunciadosSelectorFallback() {
|
|
|
1028
1051
|
console.log("")
|
|
1029
1052
|
})
|
|
1030
1053
|
|
|
1031
|
-
const respuesta = await askQuestion("Elige un número (1-
|
|
1054
|
+
const respuesta = await askQuestion("Elige un número (1-7) o 'q' para salir: ")
|
|
1032
1055
|
|
|
1033
1056
|
if (respuesta.toLowerCase() === 'q') {
|
|
1034
|
-
console.log("
|
|
1057
|
+
console.log("Hecho con <3 por icarus.mx")
|
|
1035
1058
|
rl.close()
|
|
1036
1059
|
return
|
|
1037
1060
|
}
|
|
1038
1061
|
|
|
1039
1062
|
const numeroSeleccionado = parseInt(respuesta)
|
|
1040
1063
|
|
|
1041
|
-
if (numeroSeleccionado >= 1 && numeroSeleccionado <=
|
|
1064
|
+
if (numeroSeleccionado >= 1 && numeroSeleccionado <= 7) {
|
|
1042
1065
|
const enunciadoSeleccionado = ENUNCIADOS[numeroSeleccionado - 1]
|
|
1043
1066
|
|
|
1044
1067
|
// Check if we have a lesson implementation for this enunciado
|
|
@@ -1154,6 +1177,22 @@ async function startEnunciadosSelectorFallback() {
|
|
|
1154
1177
|
console.log("- Proyectos específicos para internalizar la idea")
|
|
1155
1178
|
}
|
|
1156
1179
|
return
|
|
1180
|
+
} else if (enunciadoSeleccionado.id === 7) {
|
|
1181
|
+
console.log(`${enunciadoSeleccionado.texto}`)
|
|
1182
|
+
rl.close()
|
|
1183
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
1184
|
+
|
|
1185
|
+
try {
|
|
1186
|
+
const lesson7 = new Lesson7ObjectDefinition()
|
|
1187
|
+
await lesson7.start()
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
1190
|
+
console.log("\n🚀 Próximamente:")
|
|
1191
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
1192
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
1193
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
1194
|
+
}
|
|
1195
|
+
return
|
|
1157
1196
|
} else {
|
|
1158
1197
|
console.log("\n🚀 Próximamente:")
|
|
1159
1198
|
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
@@ -1165,7 +1204,7 @@ async function startEnunciadosSelectorFallback() {
|
|
|
1165
1204
|
}
|
|
1166
1205
|
|
|
1167
1206
|
} else {
|
|
1168
|
-
console.log("❌ Opción no válida. Elige un número entre 1 y
|
|
1207
|
+
console.log("❌ Opción no válida. Elige un número entre 1 y 7.")
|
|
1169
1208
|
}
|
|
1170
1209
|
|
|
1171
1210
|
rl.close()
|
|
@@ -1244,7 +1283,7 @@ async function startProyectosSelectorInteractive() {
|
|
|
1244
1283
|
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
1245
1284
|
process.stdin.setRawMode(false)
|
|
1246
1285
|
process.stdin.removeListener('data', onKeyPress)
|
|
1247
|
-
console.log("\
|
|
1286
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
1248
1287
|
resolve()
|
|
1249
1288
|
return
|
|
1250
1289
|
}
|
|
@@ -1306,7 +1345,7 @@ async function returnToMainMenu() {
|
|
|
1306
1345
|
console.clear()
|
|
1307
1346
|
await startMainMenu()
|
|
1308
1347
|
} else {
|
|
1309
|
-
console.log("\
|
|
1348
|
+
console.log("\nHecho con <3 por icarus.mx")
|
|
1310
1349
|
rl.close()
|
|
1311
1350
|
}
|
|
1312
1351
|
}
|
|
@@ -1336,7 +1375,7 @@ async function startProyectosSelectorFallback() {
|
|
|
1336
1375
|
const respuesta = await askQuestion("Elige una opción (1-4) o 'q' para salir: ")
|
|
1337
1376
|
|
|
1338
1377
|
if (respuesta.toLowerCase() === 'q') {
|
|
1339
|
-
console.log("
|
|
1378
|
+
console.log("Hecho con <3 por icarus.mx")
|
|
1340
1379
|
rl.close()
|
|
1341
1380
|
return
|
|
1342
1381
|
}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// LECCIÓN 7: Un objeto es un conjunto de datos y procedimientos que operan sobre esos datos
|
|
4
|
+
// Enfoque práctico: Comparación entre código procedural vs orientado a objetos
|
|
5
|
+
|
|
6
|
+
import { createInterface } from 'readline'
|
|
7
|
+
|
|
8
|
+
export class Lesson7ObjectDefinition {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.rl = createInterface({
|
|
11
|
+
input: process.stdin,
|
|
12
|
+
output: process.stdout
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async start() {
|
|
17
|
+
await this.waitForEnter("\nPresiona Enter para comenzar...")
|
|
18
|
+
|
|
19
|
+
await this.practicalExercise()
|
|
20
|
+
await this.conclusion()
|
|
21
|
+
|
|
22
|
+
this.rl.close()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async practicalExercise() {
|
|
26
|
+
console.clear()
|
|
27
|
+
console.log("Exploraremos qué ES un objeto comparando dos enfoques:")
|
|
28
|
+
console.log("1. Datos separados + funciones sueltas")
|
|
29
|
+
console.log("2. Objeto = datos + procedimientos unidos")
|
|
30
|
+
|
|
31
|
+
await this.waitForEnter("\nPresiona Enter para continuar...")
|
|
32
|
+
|
|
33
|
+
await this.step1_ProceduralApproach()
|
|
34
|
+
await this.step2_ObjectOrientedApproach()
|
|
35
|
+
await this.step3_ComparisonAndBenefits()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async step1_ProceduralApproach() {
|
|
39
|
+
console.clear()
|
|
40
|
+
console.log("🔧 Enfoque Procedural: Datos Separados")
|
|
41
|
+
console.log("=" .repeat(50))
|
|
42
|
+
|
|
43
|
+
console.log("\n💳 Ejemplo: Sistema de Cuenta Bancaria")
|
|
44
|
+
console.log("\n📊 Datos sueltos:")
|
|
45
|
+
|
|
46
|
+
const dataCode = `// Datos de la cuenta
|
|
47
|
+
let accountNumber = "001-234567"
|
|
48
|
+
let ownerName = "María González"
|
|
49
|
+
let balance = 5000
|
|
50
|
+
let isActive = true`
|
|
51
|
+
|
|
52
|
+
this.printCodeWithColors("Variables globales", dataCode)
|
|
53
|
+
|
|
54
|
+
await this.waitForEnter("\nPresiona Enter para ver las funciones...")
|
|
55
|
+
|
|
56
|
+
console.log("\n⚙️ Funciones separadas que operan sobre esos datos:")
|
|
57
|
+
|
|
58
|
+
const functionsCode = `function deposit(amount) {
|
|
59
|
+
if (!isActive) {
|
|
60
|
+
console.log("Cuenta inactiva")
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
if (amount <= 0) {
|
|
64
|
+
console.log("Cantidad inválida")
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
balance += amount
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function withdraw(amount) {
|
|
72
|
+
if (!isActive) return false
|
|
73
|
+
if (amount <= 0) return false
|
|
74
|
+
if (amount > balance) {
|
|
75
|
+
console.log("Fondos insuficientes")
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
balance -= amount
|
|
79
|
+
return true
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getBalance() {
|
|
83
|
+
return isActive ? balance : 0
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function deactivate() {
|
|
87
|
+
isActive = false
|
|
88
|
+
}`
|
|
89
|
+
|
|
90
|
+
this.printCodeWithColors("Funciones sueltas", functionsCode)
|
|
91
|
+
|
|
92
|
+
await this.waitForEnter("\nPresiona Enter para ver el problema...")
|
|
93
|
+
|
|
94
|
+
console.clear()
|
|
95
|
+
console.log("❌ Problemas del enfoque procedural:")
|
|
96
|
+
console.log("=" .repeat(50))
|
|
97
|
+
|
|
98
|
+
console.log("\n1️⃣ Datos expuestos globalmente:")
|
|
99
|
+
console.log(" • Cualquier código puede modificar 'balance' directamente")
|
|
100
|
+
console.log(" • No hay protección de los datos")
|
|
101
|
+
|
|
102
|
+
console.log("\n2️⃣ Funciones no están vinculadas a datos:")
|
|
103
|
+
console.log(" • deposit() asume que 'balance' existe")
|
|
104
|
+
console.log(" • ¿Qué pasa si necesitamos múltiples cuentas?")
|
|
105
|
+
|
|
106
|
+
console.log("\n3️⃣ Difícil de escalar:")
|
|
107
|
+
|
|
108
|
+
const problemCode = `// ¿Cómo manejamos dos cuentas?
|
|
109
|
+
let balance1 = 5000
|
|
110
|
+
let balance2 = 3000
|
|
111
|
+
let accountNumber1 = "001"
|
|
112
|
+
let accountNumber2 = "002"
|
|
113
|
+
|
|
114
|
+
// Las funciones solo trabajan con una cuenta
|
|
115
|
+
deposit(100) // ¿A cuál cuenta?`
|
|
116
|
+
|
|
117
|
+
this.printCodeWithColors("Escalabilidad problemática", problemCode)
|
|
118
|
+
|
|
119
|
+
await this.waitForEnter("\nPresiona Enter para ver la solución...")
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async step2_ObjectOrientedApproach() {
|
|
123
|
+
console.clear()
|
|
124
|
+
console.log("✨ Enfoque Orientado a Objetos: Datos + Procedimientos")
|
|
125
|
+
console.log("=" .repeat(50))
|
|
126
|
+
|
|
127
|
+
console.log("\n💡 Un objeto AGRUPA datos y procedimientos")
|
|
128
|
+
console.log("Los datos quedan unidos con sus procedimientos")
|
|
129
|
+
|
|
130
|
+
await this.waitForEnter("\nPresiona Enter para ver el código...")
|
|
131
|
+
|
|
132
|
+
const objectCode = `class BankAccount {
|
|
133
|
+
// Constructor: inicializa los DATOS del objeto
|
|
134
|
+
constructor(accountNumber, ownerName, initialBalance) {
|
|
135
|
+
this.accountNumber = accountNumber
|
|
136
|
+
this.ownerName = ownerName
|
|
137
|
+
this.balance = initialBalance
|
|
138
|
+
this.isActive = true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// PROCEDIMIENTOS que operan sobre ESTOS datos específicos
|
|
142
|
+
deposit(amount) {
|
|
143
|
+
if (!this.isActive) {
|
|
144
|
+
console.log("Cuenta inactiva")
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
147
|
+
if (amount <= 0) {
|
|
148
|
+
console.log("Cantidad inválida")
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
this.balance += amount
|
|
152
|
+
return true
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
withdraw(amount) {
|
|
156
|
+
if (!this.isActive) return false
|
|
157
|
+
if (amount <= 0) return false
|
|
158
|
+
if (amount > this.balance) {
|
|
159
|
+
console.log("Fondos insuficientes")
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
this.balance -= amount
|
|
163
|
+
return true
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getBalance() {
|
|
167
|
+
return this.isActive ? this.balance : 0
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
deactivate() {
|
|
171
|
+
this.isActive = false
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
getAccountInfo() {
|
|
175
|
+
return {
|
|
176
|
+
number: this.accountNumber,
|
|
177
|
+
owner: this.ownerName,
|
|
178
|
+
balance: this.getBalance(),
|
|
179
|
+
status: this.isActive ? 'Activa' : 'Inactiva'
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}`
|
|
183
|
+
|
|
184
|
+
this.printCodeWithColors("Clase BankAccount", objectCode)
|
|
185
|
+
|
|
186
|
+
await this.waitForEnter("\nPresiona Enter para ver múltiples instancias...")
|
|
187
|
+
|
|
188
|
+
console.clear()
|
|
189
|
+
console.log("🎯 Múltiples objetos = Múltiples conjuntos de datos")
|
|
190
|
+
console.log("=" .repeat(50))
|
|
191
|
+
|
|
192
|
+
const usageCode = `// Crear múltiples cuentas es simple
|
|
193
|
+
const account1 = new BankAccount("001-234567", "María González", 5000)
|
|
194
|
+
const account2 = new BankAccount("001-789012", "Juan Pérez", 3000)
|
|
195
|
+
|
|
196
|
+
// Cada objeto tiene SUS PROPIOS datos
|
|
197
|
+
account1.deposit(500)
|
|
198
|
+
account2.withdraw(200)
|
|
199
|
+
|
|
200
|
+
console.log(account1.getBalance()) // 5500
|
|
201
|
+
console.log(account2.getBalance()) // 2800
|
|
202
|
+
|
|
203
|
+
// Los procedimientos operan sobre los datos del objeto específico
|
|
204
|
+
account1.deactivate()
|
|
205
|
+
console.log(account1.isActive) // false
|
|
206
|
+
console.log(account2.isActive) // true ← No afectado`
|
|
207
|
+
|
|
208
|
+
this.printCodeWithColors("Uso del objeto", usageCode)
|
|
209
|
+
|
|
210
|
+
await this.waitForEnter("\nPresiona Enter para ver las ventajas...")
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async step3_ComparisonAndBenefits() {
|
|
214
|
+
console.clear()
|
|
215
|
+
console.log("📊 Comparación Directa")
|
|
216
|
+
console.log("=" .repeat(50))
|
|
217
|
+
|
|
218
|
+
console.log("\n🔴 Enfoque Procedural:")
|
|
219
|
+
console.log(" Datos: let balance = 5000")
|
|
220
|
+
console.log(" Procedimiento: function deposit(amount) { balance += amount }")
|
|
221
|
+
console.log(" ❌ Separados, sin relación formal")
|
|
222
|
+
|
|
223
|
+
console.log("\n🟢 Enfoque Orientado a Objetos:")
|
|
224
|
+
console.log(" Datos: this.balance = 5000")
|
|
225
|
+
console.log(" Procedimiento: deposit(amount) { this.balance += amount }")
|
|
226
|
+
console.log(" ✅ Unidos en el MISMO objeto")
|
|
227
|
+
|
|
228
|
+
await this.waitForEnter("\nPresiona Enter para ver ejemplo visual...")
|
|
229
|
+
|
|
230
|
+
console.clear()
|
|
231
|
+
console.log("🎨 Visualización del Concepto")
|
|
232
|
+
console.log("=" .repeat(50))
|
|
233
|
+
|
|
234
|
+
console.log("\n┌─────────────────────────────────────┐")
|
|
235
|
+
console.log("│ OBJETO: account1 │")
|
|
236
|
+
console.log("├─────────────────────────────────────┤")
|
|
237
|
+
console.log("│ DATOS: │")
|
|
238
|
+
console.log("│ • accountNumber = \"001-234567\" │")
|
|
239
|
+
console.log("│ • ownerName = \"María González\" │")
|
|
240
|
+
console.log("│ • balance = 5000 │")
|
|
241
|
+
console.log("│ • isActive = true │")
|
|
242
|
+
console.log("├─────────────────────────────────────┤")
|
|
243
|
+
console.log("│ PROCEDIMIENTOS: │")
|
|
244
|
+
console.log("│ • deposit(amount) │")
|
|
245
|
+
console.log("│ • withdraw(amount) │")
|
|
246
|
+
console.log("│ • getBalance() │")
|
|
247
|
+
console.log("│ • deactivate() │")
|
|
248
|
+
console.log("└─────────────────────────────────────┘")
|
|
249
|
+
|
|
250
|
+
console.log("\n📌 Nota clave:")
|
|
251
|
+
console.log("Los procedimientos SOLO operan sobre los datos de ESTE objeto")
|
|
252
|
+
console.log("account1.deposit() modifica account1.balance")
|
|
253
|
+
console.log("account2.deposit() modifica account2.balance")
|
|
254
|
+
|
|
255
|
+
await this.waitForEnter("\nPresiona Enter para ver otro ejemplo...")
|
|
256
|
+
|
|
257
|
+
console.clear()
|
|
258
|
+
console.log("🎮 Ejemplo 2: Sistema de Carrito de Compras")
|
|
259
|
+
console.log("=" .repeat(50))
|
|
260
|
+
|
|
261
|
+
const cartCode = `class ShoppingCart {
|
|
262
|
+
// DATOS del carrito
|
|
263
|
+
constructor(userId) {
|
|
264
|
+
this.userId = userId
|
|
265
|
+
this.items = []
|
|
266
|
+
this.totalAmount = 0
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// PROCEDIMIENTOS que operan sobre estos datos
|
|
270
|
+
addItem(product, quantity) {
|
|
271
|
+
const item = { product, quantity, price: product.price * quantity }
|
|
272
|
+
this.items.push(item)
|
|
273
|
+
this.totalAmount += item.price
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
removeItem(productId) {
|
|
277
|
+
const itemIndex = this.items.findIndex(i => i.product.id === productId)
|
|
278
|
+
if (itemIndex > -1) {
|
|
279
|
+
this.totalAmount -= this.items[itemIndex].price
|
|
280
|
+
this.items.splice(itemIndex, 1)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
getTotal() {
|
|
285
|
+
return this.totalAmount
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
getItemCount() {
|
|
289
|
+
return this.items.reduce((sum, item) => sum + item.quantity, 0)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
clear() {
|
|
293
|
+
this.items = []
|
|
294
|
+
this.totalAmount = 0
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Uso
|
|
299
|
+
const cart = new ShoppingCart("user123")
|
|
300
|
+
cart.addItem({ id: 1, name: "Libro", price: 299 }, 2)
|
|
301
|
+
cart.addItem({ id: 2, name: "Café", price: 85 }, 1)
|
|
302
|
+
|
|
303
|
+
console.log(cart.getTotal()) // 683
|
|
304
|
+
console.log(cart.getItemCount()) // 3`
|
|
305
|
+
|
|
306
|
+
this.printCodeWithColors("Clase ShoppingCart", cartCode)
|
|
307
|
+
|
|
308
|
+
await this.waitForEnter("\nPresiona Enter para la conclusión...")
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async conclusion() {
|
|
312
|
+
console.clear()
|
|
313
|
+
console.log("🎓 Conclusión: Definición del Objeto")
|
|
314
|
+
console.log("=" .repeat(50))
|
|
315
|
+
|
|
316
|
+
console.log("\n💎 Enunciado fundamental:")
|
|
317
|
+
console.log("'Un objeto es un conjunto de datos y procedimientos")
|
|
318
|
+
console.log(" que operan sobre esos datos'")
|
|
319
|
+
|
|
320
|
+
console.log("\n🔍 Desglose:")
|
|
321
|
+
console.log("1️⃣ CONJUNTO → agrupación unificada")
|
|
322
|
+
console.log("2️⃣ DATOS → información del objeto (this.balance, this.name)")
|
|
323
|
+
console.log("3️⃣ PROCEDIMIENTOS → funciones del objeto (deposit, withdraw)")
|
|
324
|
+
console.log("4️⃣ OPERAN SOBRE → los procedimientos modifican/leen los datos")
|
|
325
|
+
|
|
326
|
+
console.log("\n✅ Ventajas demostradas:")
|
|
327
|
+
console.log("• Encapsulación: datos y operaciones juntos")
|
|
328
|
+
console.log("• Modularidad: cada objeto es independiente")
|
|
329
|
+
console.log("• Escalabilidad: múltiples instancias fácilmente")
|
|
330
|
+
console.log("• Organización: responsabilidades claras")
|
|
331
|
+
|
|
332
|
+
console.log("\n📚 Ejemplos vistos:")
|
|
333
|
+
console.log("• BankAccount: balance + deposit/withdraw")
|
|
334
|
+
console.log("• ShoppingCart: items + addItem/removeItem")
|
|
335
|
+
|
|
336
|
+
console.log("\n🔗 Conexión con otros enunciados:")
|
|
337
|
+
console.log("• Enunciado 1: Estos objetos son los que descomponemos del sistema")
|
|
338
|
+
console.log("• Enunciado 2: Estos objetos interactúan mediante solicitudes")
|
|
339
|
+
console.log("• Enunciado 5: La interfaz expone los procedimientos disponibles")
|
|
340
|
+
|
|
341
|
+
console.log("\n💭 Reflexión:")
|
|
342
|
+
console.log("Antes de diseñar cómo los objetos interactúan,")
|
|
343
|
+
console.log("debemos entender QUÉ ES un objeto:")
|
|
344
|
+
console.log("datos + procedimientos, unidos e inseparables.")
|
|
345
|
+
|
|
346
|
+
await this.waitForEnter("\n✨ ¡Lección 7 completada! Presiona Enter para continuar...")
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
formatCode(code) {
|
|
350
|
+
const colors = {
|
|
351
|
+
keyword: '\x1b[35m',
|
|
352
|
+
property: '\x1b[32m',
|
|
353
|
+
string: '\x1b[33m',
|
|
354
|
+
comment: '\x1b[90m',
|
|
355
|
+
reset: '\x1b[0m'
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return code
|
|
359
|
+
.replace(/\b(class|constructor|return|if|const|let|new|function)\b/g, `${colors.keyword}$1${colors.reset}`)
|
|
360
|
+
.replace(/\bthis\./g, `${colors.property}this.${colors.reset}`)
|
|
361
|
+
.replace(/'([^']*)'/g, `${colors.string}'$1'${colors.reset}`)
|
|
362
|
+
.replace(/"([^"]*)"/g, `${colors.string}"$1"${colors.reset}`)
|
|
363
|
+
.replace(/\/\/.*$/gm, `${colors.comment}$&${colors.reset}`)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
printCodeWithColors(title, code) {
|
|
367
|
+
console.log(`\n${title}`)
|
|
368
|
+
console.log("━".repeat(50))
|
|
369
|
+
|
|
370
|
+
code.split('\n').forEach(line => {
|
|
371
|
+
const formattedLine = this.formatCode(line)
|
|
372
|
+
console.log(formattedLine)
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
console.log("━".repeat(50))
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async waitForEnter(message) {
|
|
379
|
+
return new Promise((resolve) => {
|
|
380
|
+
this.rl.question(message, () => {
|
|
381
|
+
console.log("\n\n")
|
|
382
|
+
resolve()
|
|
383
|
+
})
|
|
384
|
+
})
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Para usar la lección independientemente
|
|
389
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
390
|
+
const lesson = new Lesson7ObjectDefinition()
|
|
391
|
+
await lesson.start()
|
|
392
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@icarusmx/creta",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Salgamos de este laberinto.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"creta": "./bin/creta.js"
|
|
8
8
|
},
|
|
9
|
-
"keywords": [
|
|
9
|
+
"keywords": [
|
|
10
|
+
"cli",
|
|
11
|
+
"icarus",
|
|
12
|
+
"creta",
|
|
13
|
+
"scythe",
|
|
14
|
+
"software school"
|
|
15
|
+
],
|
|
10
16
|
"author": "Guillermo Rodríguez López",
|
|
11
|
-
"publishConfig": {
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
12
20
|
"license": "MIT",
|
|
13
21
|
"dependencies": {
|
|
14
22
|
"chalk": "^5.3.0",
|