sábado, 28 de enero de 2023

Node + Typescript, configuraciones y scripts útiles


Si ya configuraste el entorno como un campeon, veamos unos trucos para que todo vaya como piña. 

Recarga en frío: La recarga en frío es buena para el desarrollo local. Para hacer esto, tendremos que instalar y configurar en un par de paquetes más: ts-node para ejecutar el código de mecanografiado directamente sin tener que esperar a que se compilara, y nodemon, para observar los cambios en nuestro código y reiniciar automáticamente cuando un el archivo ha cambiado.


npm install --save-dev ts-node nodemon


Ahora debemos agregar una configuración de nodemon.json.


{

  "watch": ["src"],

  "ext": ".ts,.js",

  "ignore": [],

  "exec": "npx ts-node ./src/index.ts"

}


Y luego, para ejecutar el proyecto, todo lo que tenemos que hacer es ejecutar nodemon. Agreguemos un script para eso.


"start:dev": "npx nodemon",


Al ejecutar npm run start:dev, npx nodemon iniciará nuestra aplicación usando npx ts-node ./src/index.ts, buscando cambios en los archivos .ts y .js desde /src.


Para limpiar y compilar el proyecto para la producción, podemos agregar un script de compilación.

Instalamos rimraf, una herramienta multiplataforma que actúa como el comando rm -rf (simplemente borra todo lo que le indique).


npm install --save-dev rimraf


Y luego, agregamos esto en paquete.json.


"build": "rimraf ./build && tsc",


Ahora, cuando ejecutamos npm run build, rimraf eliminará nuestra carpeta de compilación anterior antes de que el compilador de TypeScript emita código nuevo para dist.


Para iniciar la aplicación en producción, todo lo que debemos hacer es ejecutar primero el comando de compilación y luego ejecutar el JavaScript compilado en build/index.js. El script de inicio se ve así.

"start": "npm run build && node build/index.js"


Y listo. 



Foldable y Traverse parte 5

foldLeft y foldRight son métodos de iteración flexibles, pero requieren mucho trabajo para definir acumuladores y funciones combinadoras. La clase de tipo Traverse es una herramienta de nivel superior que aprovecha Applicatives para proporcionar un patrón de iteración más conveniente y más legible.

Podemos demostrar Traverse utilizando los métodos Future.traverse y Future.sequence en la biblioteca estándar de Scala. Estos métodos proporcionan implementaciones específicas de Future del patrón poligonal. Como ejemplo, supongamos que tenemos una lista de servidores y un método para sondear un host por su tiempo de actividad:


import scala.concurrent._

import scala.concurrent.duration._

import scala.concurrent.ExecutionContext.Implicits.global

val hostnames = List(

    "alpha.example.com",

    "beta.example.com",

    "gamma.demo.com"

)

def getUptime(hostname: String): Future[Int] = Future(hostname.length * 60) // just for demonstration


Ahora, supongamos que queremos sondear todos los hosts y recopilar todos sus tiempos de actividad. No podemos simplemente asignar nombres de host porque el resultado, una Lista [Futuro [Int]], contendría más de un Futuro. Necesitamos reducir los resultados a un solo futuro para obtener algo que podamos bloquear. Comencemos haciendo esto manualmente usando un pliegue:


val allUptimes: Future[List[Int]] = hostnames.foldLeft(Future(List.empty[Int])) {

    (accum, host) =>

        val uptime = getUptime(host)

        for {

           accum  <- accum

           uptime <- uptime

        } yield accum :+ uptime

}

Await.result(allUptimes, 1.second)

// res0: List[Int] = List(1020, 960, 840)


Intuitivamente, iteramos sobre nombres de host, llamamos a func para cada elemento y combinamos los resultados en una lista. Esto suena simple, pero el código es bastante difícil de manejar debido a la necesidad de crear y combinar Futuros en cada iteración. Podemos mejorar mucho las cosas usando Future.traverse, que está hecho a medida para este patrón:


val allUptimes: Future[List[Int]] = Future.traverse(hostnames)(getUptime)

Await.result(allUptimes, 1.second)

// res2: List[Int] = List(1020, 960, 840)


Esto es mucho más claro y conciso. Veamos cómo funciona. Si ignoramos distracciones como CanBuildFrom y ExecutionContext, la implementación de Future.traverse en la biblioteca estándar se ve así:


def traverse[A, B](values: List[A])

(func: A => Future[B]): Future[List[B]] = values.foldLeft(Future(List.empty[B])) { 

    (accum, host) =>

        val item = func(host)

        for {

             accum <- accum

             item <- item

       } yield accum :+ item

}


Esto es esencialmente lo mismo que nuestro código de ejemplo anterior. Future.traverse está abstrayendo el dolor de plegar y definir acumuladores y funciones de combinación. Nos brinda una interfaz limpia de alto nivel para hacer lo que queramos:

  • empezar con una Lista[A];
  • proporcionar una función A => Futuro[B];
  • terminar con un Futuro[Lista[B]].
La biblioteca estándar también proporciona otro método, Future.sequence, que asume que comenzamos con List[Future[B]] y no necesitamos proporcionar una función de identidad:

object Future {
    def sequence[B](futures: List[Future[B]]): Future[List[B]] = traverse(futures)(identity)
// etc...
}

En este caso la comprensión intuitiva es aún más sencilla:

  • empezar con una Lista[Futuro[A]];
  • terminar con un Futuro[Lista[A]].
Future.traverse y Future.sequence resuelven un problema muy específico: nos permiten iterar sobre una secuencia de Futuros y acumular un resultado. Los ejemplos simplificados anteriores solo funcionan con Listas, pero el Future.traverse y Future.sequence funcionan con cualquier colección estándar de Scala.

La clase de tipo Traverse de Cats generaliza estos patrones para que funcionen con cualquier tipo de Aplicativo: Futuro, Opción, Validado, etc. 

martes, 24 de enero de 2023

Como crear un proyecto en Node + Typescript?


Empecemos, vamos a una cosola y creamos una carpeta : 

mkdir typescript-starter

cd typescript-starter


Ahora tenemos que crear el package.json

npm init -y


Luego agregamos Typescript como una dependencia de dev : 

npm install typescript --save-dev


Luego de instalar esto podemos usar el comando tsc. Además TypeScript tiene tipos implícitos, explícitos y ambientales. Los tipos ambientales son tipos que se agregan al ámbito de ejecución global. Dado que estamos usando Node, sería bueno si pudiéramos obtener seguridad de tipo y finalización automática en las API de Node como archivo, ruta, proceso, etc. Eso es lo que hará la instalación de la definición de tipo DefinitelyTyped para Node:

npm install @types/node --save-dev


tsconfig.json es el archivo donde typescript tiene todas sus definiciones y lo creamos con este comando: 

npx tsc --init --rootDir src --outDir build \

--esModuleInterop --resolveJsonModule --lib es6 \

--module commonjs --allowJs true --noImplicitAny true


  • rootDir: Aquí es donde TypeScript busca nuestro código. Lo hemos configurado para buscar en la carpeta src/. Ahí es donde escribiremos nuestro TypeScript.
  • outDir: Donde TypeScript pone nuestro código compilado. Queremos que vaya a una carpeta build/.
  • esModuleInterop: si estuvimos en el espacio de JavaScript durante los últimos años, es posible que haya reconocido que los sistemas de módulos se han descontrolado un poco (AMD, SystemJS, ES Modules, etc.). Para un tema que requiere una discusión mucho más larga, si usamos commonjs como nuestro sistema de módulos (para las aplicaciones de Node, debería hacerlo), entonces necesitamos que esto se establezca en verdadero.
  • resolveJsonModule: si usamos JSON en este proyecto, esta opción permite que TypeScript lo use.
  • lib: esta opción agrega tipos ambientales a nuestro proyecto, lo que nos permite confiar en funciones de diferentes versiones de Ecmascript, bibliotecas de prueba e incluso la API DOM del navegador. 
  • módulo: commonjs es el sistema de módulo de Nodo estándar en 2019. Usemos eso.
  • allowJs: si está convirtiendo un proyecto antiguo de JavaScript a TypeScript, esta opción le permitirá incluir archivos .js entre los .ts.
  • noImplicitAny: en los archivos TypeScript, no permita que se especifique un tipo de forma no explícita. Cada tipo debe tener un tipo específico o declararse explícitamente cualquiera. Sin anys implícitos.

Luego de ejecutar este comando, tenemos un archivo tsconfig.json algo así: 

{

  "compilerOptions": {

    /* Visit https://aka.ms/tsconfig to read more about this file */


    /* Projects */

    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */

    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */

    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */

    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */

    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */

    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */


    /* Language and Environment */

    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */

    "lib": ["es6"],                                      /* Specify a set of bundled library declaration files that describe the target runtime environment. */

    // "jsx": "preserve",                                /* Specify what JSX code is generated. */

    // "experimentalDecorators": true,                   /* Enable experimental support for TC39 stage 2 draft decorators. */

    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */

    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */

    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */

    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */

    // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */

    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */

    // "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */

    // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */


    /* Modules */

    "module": "commonjs",                                /* Specify what module code is generated. */

    "rootDir": "src",                                    /* Specify the root folder within your source files. */

    // "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */

    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */

    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */

    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */

    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */

    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */

    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */

    // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */

    "resolveJsonModule": true,                           /* Enable importing .json files. */

    // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */


    /* JavaScript Support */

    "allowJs": true,                                     /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */

    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */

    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */


    /* Emit */

    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */

    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */

    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */

    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */

    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */

    "outDir": "build",                                   /* Specify an output folder for all emitted files. */

    // "removeComments": true,                           /* Disable emitting comments. */

    // "noEmit": true,                                   /* Disable emitting files from a compilation. */

    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */

    // "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */

    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */

    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */

    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */

    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */

    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */

    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */

    // "newLine": "crlf",                                /* Set the newline character for emitting files. */

    // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */

    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */

    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */

    // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */

    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */

    // "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */


    /* Interop Constraints */

    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */

    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */

    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */

    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */

    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */


    /* Type Checking */

    "strict": true,                                      /* Enable all strict type-checking options. */

    "noImplicitAny": true,                               /* Enable error reporting for expressions and declarations with an implied 'any' type. */

    // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */

    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */

    // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */

    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */

    // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */

    // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */

    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */

    // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */

    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */

    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */

    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */

    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */

    // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */

    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */

    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */

    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */

    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */


    /* Completeness */

    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */

    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */

  }

}

Regrande y con muchas opciones, pero si borramos los comentarios queda así : 

{

  "compilerOptions": {

    "target": "es5",                          

    "module": "commonjs",                    

    "lib": ["es6"],                     

    "allowJs": true,

    "outDir": "build",                          

    "rootDir": "src",

    "strict": true,         

    "noImplicitAny": true,

    "esModuleInterop": true,

    "resolveJsonModule": true

  }

}


Ahora vamos a probar si anda, para eso creamos la carpeta src y un archivo de prueba: 


mkdir src

touch src/index.ts


Y ponemos algo de código, para eso abrimos el archivo y escribimos: 

console.log('Hello world!')


Y ahora compilamos : 

npx tsc


Luego de compilar vamos a tener una carpeta llamada build que va contener un archivo index.js que contiene : 


"use strict";

console.log('Hello world!');


Y listo!! 



lunes, 23 de enero de 2023

GORM, un ORM para Golang

 


Grom es un ORM simple para Golang. Tiene todas las características de un ORM moderno como : 

  • Asociaciones (uno uno, uno a muchos, muchos a muchos, polimorfismo, herencia con una tabla única)
  • Hooks o Ganchos
  • Carga ansiosa con Preload, Joins
  • Transacciones, Transacciones anidadas, Checkpoints y rollback del checkpoint
  • Inserción por lotes, FindInBatches, Buscar/Crear con mapa, CRUD con SQL Expr y Context Valuer
  • SQL Builder, Upsert, Bloqueo, Optimizador/Índice/Sugerencias de comentarios, Argumento con nombre, Subconsulta
  • Migraciones automáticas
  • API de complemento extensible y flexible: Resolución de base de datos (bases de datos múltiples, división de lectura/escritura) / Prometheus...

Para instalarlo tenemos que ejecutar estos comandos: 

go get -u gorm.io/gorm

go get -u gorm.io/driver/sqlite


Y ya con eso podemos empezar a utilizarlo. Veamos un ejemplo : 

package main

import (
  "gorm.io/gorm"
  "gorm.io/driver/sqlite"
)

type Product struct {
  gorm.Model
  Code  string
  Price uint
}

func main() {
  db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
  if err != nil {
    panic("failed to connect database")
  }

  // Migrate the schema
  db.AutoMigrate(&Product{})

  // Create
  db.Create(&Product{Code: "D42", Price: 100})

  // Read
  var product Product
  db.First(&product, 1) // find product with integer primary key
  db.First(&product, "code = ?", "D42") // find product with code D42

  // Update - update product's price to 200
  db.Model(&product).Update("Price", 200)
  // Update - update multiple fields
  db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) // non-zero fields
  db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"})

  // Delete - delete product
  db.Delete(&product, 1)
}

Dejo link: https://gorm.io/

 

sábado, 21 de enero de 2023

Pattern matching: las expresiones is y switch, y los operadores and, or y not en C# parte 5


Patron var 

Utiliza un patrón var para hacer coincidir cualquier expresión, incluido nulo, y asigna su resultado a una nueva variable local, como muestra el siguiente ejemplo:


static bool IsAcceptable(int id, int absLimit) =>

    SimulateDataFetch(id) is var results 

    && results.Min() >= -absLimit 

    && results.Max() <= absLimit;


static int[] SimulateDataFetch(int id)

{

    var rand = new Random();

    return Enumerable

               .Range(start: 0, count: 5)

               .Select(s => rand.Next(minValue: -10, maxValue: 11))

               .ToArray();

}


Un patrón var es útil cuando necesitamos una variable temporal dentro de una expresión booleana para contener el resultado de cálculos intermedios. También podemos usar un patrón var cuando necesitamos realizar más comprobaciones cuando las mayúsculas y minúsculas protegen una expresión o declaración de cambio, como muestra el siguiente ejemplo:

public record Point(int X, int Y);

static Point Transform(Point point) => point switch

{

    var (x, y) when x < y => new Point(-x, y),

    var (x, y) when x > y => new Point(x, -y),

    var (x, y) => new Point(x, y),

};


static void TestTransform()

{

    Console.WriteLine(Transform(new Point(1, 2)));  // output: Point { X = -1, Y = 2 }

    Console.WriteLine(Transform(new Point(5, 2)));  // output: Point { X = 5, Y = -2 }

}


En el ejemplo anterior, el patrón var (x, y) es equivalente a un patrón posicional (var x, var y).

En un patrón var, el tipo de una variable declarada es el tipo de tiempo de compilación de la expresión que se compara con el patrón.


Patrón descartar 

Utiliza un patrón de descarte _ para hacer coincidir cualquier expresión, incluido nulo, como muestra el siguiente ejemplo:

Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));  // output: 5.0

Console.WriteLine(GetDiscountInPercent(null));  // output: 0.0

Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));  // output: 0.0


static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch

{

    DayOfWeek.Monday => 0.5m,

    DayOfWeek.Tuesday => 12.5m,

    DayOfWeek.Wednesday => 7.5m,

    DayOfWeek.Thursday => 12.5m,

    DayOfWeek.Friday => 5.0m,

    DayOfWeek.Saturday => 2.5m,

    DayOfWeek.Sunday => 2.0m,

    _ => 0.0m,

};


En el ejemplo anterior, se usa un patrón de descarte para controlar valores nulos y enteros que no tienen el miembro correspondiente de la enumeración DayOfWeek. Eso garantiza que una expresión de cambio en el ejemplo maneje todos los valores de entrada posibles. Si no usa un patrón de descarte en una expresión de cambio y ninguno de los patrones de la expresión coincide con una entrada, el tiempo de ejecución genera una excepción. El compilador genera una advertencia si una expresión de cambio no maneja todos los valores de entrada posibles.

Un patrón de descarte no puede ser un patrón en una expresión is o una declaración de cambio. En esos casos, para hacer coincidir cualquier expresión, podemos usar un patrón var con un descarte: var _.


Patrón entre paréntesis

A partir de C# 9.0, podemos poner paréntesis alrededor de cualquier patrón. Por lo general, hace eso para enfatizar o cambiar la precedencia en patrones lógicos, como muestra el siguiente ejemplo:

if (input is not (float or double))

{

    return;

}

Patrones de lista

A partir de C# 11, puede hacer coincidir una matriz o una lista con una secuencia de patrones, como muestra el siguiente ejemplo:

int[] numbers = { 1, 2, 3 };


Console.WriteLine(numbers is [1, 2, 3]);  // True

Console.WriteLine(numbers is [1, 2, 4]);  // False

Console.WriteLine(numbers is [1, 2, 3, 4]);  // False

Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]);  // True

Como muestra el ejemplo anterior, un patrón de lista coincide cuando cada patrón anidado coincide con el elemento correspondiente de una secuencia de entrada. Puede usar cualquier patrón dentro de un patrón de lista. Para hacer coincidir cualquier elemento, use el patrón de descarte o, si también desea capturar el elemento, el patrón var, como muestra el siguiente ejemplo:

List<int> numbers = new() { 1, 2, 3 };

if (numbers is [var first, _, _])

{

    Console.WriteLine($"The first element of a three-item list is {first}.");

}

// Output:

// The first element of a three-item list is 1.

Los ejemplos anteriores comparan una secuencia de entrada completa con un patrón de lista. Para hacer coincidir los elementos solo al principio o al final de una secuencia de entrada, podemos usar el patrón de división .. dentro de un patrón de lista, como muestra el siguiente ejemplo:

Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]);  // True

Console.WriteLine(new[] { 1, 1 } is [_, _, ..]);  // True

Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]);  // False

Console.WriteLine(new[] { 1 } is [1, 2, ..]);  // False


Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]);  // True

Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]);  // False

Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]);  // True


Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]);  // True

Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]);  // True

Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]);  // False


Un patrón de división coincide con cero o más elementos. Puede usar como máximo un patrón de división en un patrón de lista.

También puede anidar un subpatrón dentro de un patrón de división, como muestra el siguiente ejemplo:

void MatchMessage(string message)

{

    var result = message is ['a' or 'A', .. var s, 'a' or 'A']

        ? $"Message {message} matches; inner part is {s}."

        : $"Message {message} doesn't match.";

    Console.WriteLine(result);

}


MatchMessage("aBBA");  // output: Message aBBA matches; inner part is BB.

MatchMessage("apron");  // output: Message apron doesn't match.


void Validate(int[] numbers)

{

    var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";

    Console.WriteLine(result);

}


Validate(new[] { -1, 0, 1 });  // output: not valid

Validate(new[] { -1, 0, 0, 1 });  // output: valid


Probando Fedora

Sigo probando distros de linux y ahora le toca el gran Fedora Linux. Que yo usaba en mi antigua pc personal y que andaba hermoso. Ahora instale la versión Gnome, no sé si no me pregunto si queria kde o no lo vi, en el proceso de instalación. 

Me cuesta mucho opinar porque es casi un gnome sin modificaciones. No esta nada personalizado, personalmente me gustan las distros que tienen un estilo propio, en este caso a simple vista no se ven cambios: Por supuesto trae todas las herramientas de administración que son super utiles pero en lo visual no suma mucho como opción de escritorio. 

Les dejo unos screenshots :

 






Dejo link: https://getfedora.org/es/

miércoles, 18 de enero de 2023

Pattern matching: las expresiones is y switch, y los operadores and, or y not en C# parte 4


Patrón posicional

Utiliza un patrón posicional para deconstruir un resultado de expresión y hacer coincidir los valores resultantes con los patrones anidados correspondientes, como muestra el siguiente ejemplo:

public readonly struct Point

{

    public int X { get; }

    public int Y { get; }


    public Point(int x, int y) => (X, Y) = (x, y);


    public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);

}


static string Classify(Point point) => point switch

{

    (0, 0) => "Origin",

    (1, 0) => "positive X basis end",

    (0, 1) => "positive Y basis end",

    _ => "Just a point",

};

En el ejemplo anterior, el tipo de una expresión contiene el método Deconstruct, que se utiliza para deconstruir el resultado de una expresión. También puede hacer coincidir expresiones de tipos de tupla con patrones posicionales. De esa manera, puede hacer coincidir varias entradas con varios patrones, como muestra el siguiente ejemplo:

static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)

    => (groupSize, visitDate.DayOfWeek) switch

    {

        (<= 0, _) => throw new ArgumentException("Group size must be positive."),

        (_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,

        (>= 5 and < 10, DayOfWeek.Monday) => 20.0m,

        (>= 10, DayOfWeek.Monday) => 30.0m,

        (>= 5 and < 10, _) => 12.0m,

        (>= 10, _) => 15.0m,

        _ => 0.0m,

    };

El ejemplo anterior usa patrones relacionales y lógicos, que están disponibles en C# 9.0 y versiones posteriores.

Se puede usar los nombres de los elementos de tupla y los parámetros de Deconstrucción en un patrón posicional, como muestra el siguiente ejemplo:

var numbers = new List<int> { 1, 2, 3 };

if (SumAndCount(numbers) is (Sum: var sum, Count: > 0))

{

    Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}");  // output: Sum of [1 2 3] is 6

}


static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers)

{

    int sum = 0;

    int count = 0;

    foreach (int number in numbers)

    {

        sum += number;

        count++;

    }

    return (sum, count);

}


También puede extender un patrón posicional de cualquiera de las siguientes maneras:

  • Agregue una verificación de tipo en tiempo de ejecución y una declaración de variable, como muestra el siguiente ejemplo:

public record Point2D(int X, int Y);

public record Point3D(int X, int Y, int Z);


static string PrintIfAllCoordinatesArePositive(object point) => point switch

{

    Point2D (> 0, > 0) p => p.ToString(),

    Point3D (> 0, > 0, > 0) p => p.ToString(),

    _ => string.Empty,

};

El ejemplo anterior usa registros posicionales que proporcionan implícitamente el método Deconstruct.

  • Se puede utilizar un patrón de propiedad dentro de un patrón posicional, como muestra el siguiente ejemplo:


public record WeightedPoint(int X, int Y)

{

    public double Weight { get; set; }

}


static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };


  • Y Tambien se puede combinar los dos usos anteriores, como muestra el siguiente ejemplo:


if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p)

{

    // ..

}


Un patrón posicional es un patrón recursivo. Es decir, puede utilizar cualquier patrón como patrón anidado.


Conoce 3 etapas para aumentar la innovación durante los cambios

 

Quiero compartir un ebook de la gente de oracle : 

lunes, 16 de enero de 2023

Pattern matching: las expresiones is y switch, y los operadores and, or y not en C# parte 3


Patrones lógicos

A partir de C# 9.0, utiliza los combinadores de patrones not, and y or para crear los siguientes patrones lógicos:

  • Negación que coincide con una expresión cuando el patrón negado no coincide con la expresión. El siguiente ejemplo muestra cómo puede negar un patrón nulo constante para verificar si una expresión no es nula:

if (input is not null)

{

    // ...

}

 

  • Conjuntiva (and) que coincide con una expresión cuando ambos patrones coinciden con la expresión. El siguiente ejemplo muestra cómo puede combinar patrones relacionales para verificar si un valor está en un cierto rango:

Console.WriteLine(Classify(13));  // output: High
Console.WriteLine(Classify(-100));  // output: Too low
Console.WriteLine(Classify(5.7));  // output: Acceptable

static string Classify(double measurement) => measurement switch
{
    < -40.0 => "Too low",
    >= -40.0 and < 0 => "Low",
    >= 0 and < 10.0 => "Acceptable",
    >= 10.0 and < 20.0 => "High",
    >= 20.0 => "Too high",
    double.NaN => "Unknown",
};

  • Disyuntiva (or) que coincide con una expresión cuando cualquiera de los patrones coincide con la expresión, como muestra el siguiente ejemplo:

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19)));  // output: winter

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9)));  // output: autumn

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11)));  // output: spring


static string GetCalendarSeason(DateTime date) => date.Month switch

{

    3 or 4 or 5 => "spring",

    6 or 7 or 8 => "summer",

    9 or 10 or 11 => "autumn",

    12 or 1 or 2 => "winter",

    _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),

};

Como muestra el ejemplo anterior, puede utilizar repetidamente los combinadores de patrones en un patrón.


Precedencia y orden de verificación

La siguiente lista ordena los combinadores de patrones comenzando desde la precedencia más alta hasta la más baja:

  • not
  • and
  • or

Para especificar explícitamente la precedencia, podemos usar paréntesis, como muestra el siguiente ejemplo:

static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');


Patrón de propiedad

Se utiliza un patrón de propiedad para hacer coincidir las propiedades o campos de una expresión con patrones anidados, como muestra el siguiente ejemplo:

static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };

Un patrón de propiedad coincide con una expresión cuando el resultado de una expresión no es nulo y cada patrón anidado coincide con la propiedad o el campo correspondiente del resultado de la expresión.

También puede agregar una verificación de tipo en tiempo de ejecución y una declaración de variable a un patrón de propiedad, como muestra el siguiente ejemplo:


Console.WriteLine(TakeFive("Hello, world!"));  // output: Hello

Console.WriteLine(TakeFive("Hi!"));  // output: Hi!

Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' }));  // output: 12345

Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' }));  // output: abc


static string TakeFive(object input) => input switch

{

    string { Length: >= 5 } s => s.Substring(0, 5),

    string s => s,


    ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),

    ICollection<char> symbols => new string(symbols.ToArray()),


    null => throw new ArgumentNullException(nameof(input)),

    _ => throw new ArgumentException("Not supported input type."),

};

Un patrón de propiedad es un patrón recursivo. Es decir, puede utilizar cualquier patrón como patrón anidado. Se puede utilizar un patrón de propiedad para hacer coincidir partes de datos con patrones anidados, como muestra el siguiente ejemplo:

public record Point(int X, int Y);

public record Segment(Point Start, Point End);


static bool IsAnyEndOnXAxis(Segment segment) =>

    segment is { Start: { Y: 0 } } or { End: { Y: 0 } };


El ejemplo anterior usa dos funciones disponibles en C# 9.0 y versiones posteriores: o combinador de patrones y tipos de registro.

A partir de C# 10, puede hacer referencia a propiedades o campos anidados dentro de un patrón de propiedad. Esta capacidad se conoce como patrón de propiedad extendida. Por ejemplo, puede refactorizar el método del ejemplo anterior en el siguiente código equivalente:


static bool IsAnyEndOnXAxis(Segment segment) =>

    segment is { Start.Y: 0 } or { End.Y: 0 };



sábado, 14 de enero de 2023

Probando OpenSuse

Sigo probando distros de linux y ahora le toca el gran OpenSuse. Que yo usaba en mi antigua pc personal y que andaba hermoso. Pero ahora lo estoy probando y me desilusiono un poquito.  

Lo veo muy similar al que usaba, como que se quedo un poco en el tiempo o capaz que soy yo que lo esperaba más evolucionado y no esta el menú que lo distinguia. 

Pero salvo esos detalles, no deja de estar muy bueno, les dejo unos screenshots : 






Dejo link : https://www.opensuse.org/


viernes, 13 de enero de 2023

Pattern matching: las expresiones is y switch, y los operadores and, or y not en C# parte 2


Patrón constante

Utiliza un patrón constante para probar si el resultado de una expresión es igual a una constante especificada, como muestra el siguiente ejemplo:


public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch

{

    1 => 12.0m,

    2 => 20.0m,

    3 => 27.0m,

    4 => 32.0m,

    0 => 0.0m,

    _ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),

};


En un patrón constante, se puede usar cualquier expresión constante, como:

  • un literal numérico entero o de coma flotante
  • un char
  • un literal de cadena.
  • un valor booleano verdadero o falso
  • un valor de enumeración
  • el nombre de un campo const declarado o local
  • nulo

La expresión debe ser un tipo que se pueda convertir al tipo constante, con una excepción: una expresión cuyo tipo sea Span<char> o ReadOnlySpan<char> se puede comparar con cadenas constantes en C# 11 y versiones posteriores.

Se puede utilizar un patrón constante para verificar si hay valores nulos, como muestra el siguiente ejemplo:


if (input is null)

{

    return;

}


El compilador garantiza que no se invoca ningún operador de igualdad sobrecargado por el usuario == cuando se evalúa la expresión x es nula.

A partir de C# 9.0, puede usar un patrón de constante nulo negado para verificar si no es nulo, como muestra el siguiente ejemplo:


if (input is not null)

{

    // ...

}


Patrones relacionales

A partir de C# 9.0, utiliza un patrón relacional para comparar el resultado de una expresión con una constante, como muestra el siguiente ejemplo:


Console.WriteLine(Classify(13));  // output: Too high

Console.WriteLine(Classify(double.NaN));  // output: Unknown

Console.WriteLine(Classify(2.4));  // output: Acceptable


static string Classify(double measurement) => measurement switch

{

    < -4.0 => "Too low",

    > 10.0 => "Too high",

    double.NaN => "Unknown",

    _ => "Acceptable",

};

En un patrón relacional, puede utilizar cualquiera de los operadores relacionales <, >, <= o >=. La parte derecha de un patrón relacional debe ser una expresión constante. La expresión constante puede ser de tipo entero, punto flotante, carácter o enumeración.

Para verificar si el resultado de una expresión está en un cierto rango, compárelo con una conjuntiva y un patrón, como muestra el siguiente ejemplo:


Console.WriteLine(GetCalendarSeason(new DateTime(2021, 3, 14)));  // output: spring

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 7, 19)));  // output: summer

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 2, 17)));  // output: winter


static string GetCalendarSeason(DateTime date) => date.Month switch

{

    >= 3 and < 6 => "spring",

    >= 6 and < 9 => "summer",

    >= 9 and < 12 => "autumn",

    12 or (>= 1 and < 3) => "winter",

    _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),

};


Si el resultado de una expresión es nulo o no se convierte al tipo de una constante mediante una conversión anulable o unboxing, un patrón relacional no coincide con una expresión.



jueves, 12 de enero de 2023

[eBook] Security as Code

 

EBOOK

[eBook] Security as Code

Hi Emanuel,

To build secure and resilient applications and keep pace with customer demand, your entire app-delivery team – developers, DevOps, and security engineering – must work together and move towards a comprehensive DevSecOps strategy that ensures consistent app security. In this eBook, authors BK Sarthak Das and Virginia Chu show you how to implement such a strategy. In Security as Code, you'll learn how to create a secure containerized application with Kubernetes using CI/CD tooling from AWS and open source providers.

In this eBook you will learn:

  • About enabling consistent app security by creating templates with declarative code to automate security and keep developers agile
  • How to set up infrastructure as code and run scans to detect misconfigured resources in your code
  • The top four high-level roles a DevSecOps team should have
  • How to secure your AWS environment and Amazon EKS cluster, with step-by-step exercises on implementing security as code within the CI/CD pipeline