jueves, 22 de febrero de 2018

Java Json con Maven, gson, IntelliJ

Se muestra como manejar archivo json y convertirlo a elementos Java, se crea un projecto Maven en IntelliJ , se agrega al archivo pom la dependencia de librería gson (google json) , y se usa pruebas unitarias Junit, cuya librería se agrega como Maven para que no tenga dependencia con el IDE de IntelliJ.
  El archivo json es resultado de consulta de la Wikipedia donde se muestran los títulos y las revisiones de articulos se pueden obtener con la herramienta de MediaWiki API:revisions.

El archivo de ejemplo sample.json es de la forma siguiente
{
  "continue": {
    "rvcontinue": "201678237463842734692347826039",
    "continue": "||"  },
  "query": {
    "pages": {
      "12359849": {
        "pageid": 12359849,
        "ns": 0,
        "title": "Soup",
        "revisions": [
          {
            "user": "JuanitoPerez",
            "timestamp": "2018-02-03T11:09:23Z"          },
          {
            "user": "JuanitoLopez",
            "timestamp": "2018-02-03T12:09:23Z"          },
          {
            "user": "AnaPerez",
            "timestamp": "2018-02-03T13:09:23Z"          },
          {
            "user": "PepeJuanito",
            "timestamp": "2018-02-03T14:09:23Z"          }
        ]
      }
    }
  }
}

 

   En la primera version llegamos a abrir el archivo, leerlo y parsearlo.
   el contenido del parser nos da


   En esta otra versión llegamos al elemento pages pasando por el elemento query del archivo json


  El contenido de pages

   Como puede haber varias pages, las recorremos con un loop, usando pages.entrySet() que nos da un Map.Entry<String,JsonElement>, y de ahí llagamos a las revisions que se convierten en array.

 El contenido de las revisones de la primer "page".

   Se agrega al archivo json otra page, con otras cuatro revisions.

  En este caso se usa la librería gson (google json) para manejar los json files.

El github del ejercicio está en https://github.com/jalbertomr/JavaJsonGson.git

miércoles, 21 de febrero de 2018

Flux Pattern Design Node.js React Parte 2

Continuando con el ejercicio, solo falta dar funcionalidad a la edición de las tareas y las nuevas tareas

4.- Agregar la funcionalidad de editar las tareas con doble click.
    - Crear TodoEditStore que dará seguimiento al ID del TODO que será editado.
    - Crear las acciones startEditingTodo, stopEditingTodo.
    - Crear la acción de editTodo.
    - Creat el componente de vista TodoEdit, y darle funcionalidad.

TodoEditStore.js básicamente hará el seguimiento del id del todo que se está editando en el momento, y deacuerdo a las acciones startEditingTodo y stopEditingTodo actualizara el state denominado editing que indica si se esta editando alguna tarea en el momento, Este es usado en la Vista en el componente TodoItem.

   class TodoEditStore extends ReduceStore {
    constructor() {
        super(TodoDispatcher);
    }

    getInitialState() {
        return '';
    }

    reduce(state, action) {
        switch(action.type){
            case TodoActionTypes.START_EDITING_TODO:
                return action.id;

            case TodoActionTypes.STOP_EDITING_TODO:
                return '';

            default:
                return state;
        }
    }
}

export default new TodoEditStore();

En appContainer.js tenemos los Stores, y los States, vemos los States todo, editing, y draft. el todo es un map de tareas, el editing, tiene el ID del todo que se esta editando, y tiene '' cuando no se esta editando. del draft state esta orientado hacia el texto que se esta editando y es usado en AppView con el componente NewTodo. draft state es administado por TodoDraftStore.js, básicamente obedece a dos acciones ADD_TODO, que limpia el contenido por ser nuevo, y UPDATE_DRAFT que asigna al state draft el valor del texto de entrada.

function getStores() {
    return [
        TodoEditStore,
        TodoDraftStore,
        TodoStore,
    ];
}

function getState() {
    return {
        draft: TodoDraftStore.getState(),
        editing: TodoEditStore.getState(),
        todos: TodoStore.getState(),

        onAdd: TodoActions.addTodo,
        onDeleteTodo: TodoActions.deleteTodo,
        onDeleteCompletedTodos: TodoActions.deleteCompletedTodos,
        onEditTodo: TodoActions.editTodo,
        onStartEditingTodo: TodoActions.startEditingTodo,
        onStopEditingTodo: TodoActions.stopEditingTodo,
        onToggleTodo: TodoActions.toggleTodo,
        onToggleAllTodos: TodoActions.toggleAllTodos,
        onUpdateDraft:  TodoActions.updateDraft,
    };

Un mayor cambio se hace a AppView.js, ya que se reacomodan los componentes NewTodo y EditItem.

Finalmente después de hacer algunos debugs con console.log resolviendo algunos errores de nombre que no detecto javascript, concretamente TodoDispatch.UPDATE_DRAFT cuando debiera ser TodoActionTypes.UPDATE_DRAFT. Habrá que buscar una herramienta que nos ayude a debugear flux como es el caso de React Developer Tools que es un plugin para el Browser.




listo.

Para debugear aplicaciones flux, hay este enlace http://alt.js.org/
https://www.youtube.com/watch?v=LUksOCuRjkE

miércoles, 7 de febrero de 2018

Flux Pattern Design Node.js React Parte 1

referencias
http://facebook.github.io/flux/docs/overview.html#content

https://reactjs.org/blog/2014/07/30/flux-actions-and-the-dispatcher.html

https://github.com/facebook/flux/tree/master/examples/flux-todomvc/



Práctica de Flux

Github paso a paso de la práctica
https://github.com/jalbertomr/my-todomvc


Al realizar la práctica nos requiere de unos prerequisitos, estos son conocer ES6  ya que sa hacen uso de algunas de las nuevas características que se le incorporan al javascript. también no requiere tener noción de React y Flux.

1.- En el primer paso Getting Started, clonamos e instalamos el flux repo desde git a nuestra máquina, para después copiar e instalar el subdirectorio examples/flux-shell a examples/my-todomvc. al ejecutar el servicio npm run watch, veremos un hello World! en examples/my-todomvc/index.html

esto es por que tiene una configuración de aplicación minima

<DIR> src
.babelrc
.gitignore
package.json
README.md
webpack.config.js

En src/root.js

'use strict';

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<div>Hello World!</div>, document.getElementById('root'));

2.- En el segundo paso se copian archivos de configuración examples/todomvc-common
que tiene pocos archivos de utilerías comunes, entre ellos base.css que da formato de estilo a la página. index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Flux • TodoMVC</title>
    <link rel="stylesheet" href="todomvc-common/base.css">
  </head>
  <body>
    <section id="todoapp"></section>
    <footer id="info">
      <p>Double-click para editar tarea</p>
      <p>Parte de <a href="http://todomvc.com">TodoMVC</a></p>
    </footer>
    <script src="./bundle.js"></script>
  </body>
</html>
Se actualiza \my-todomvc\src\root.js para que haga referencia a <section id="todoapp"...
y se renderé.
ReactDOM.render(<div>Hola Mundito!</div>, document.getElementById('todoapp'));
Con esto veremos Hola Mundito! con presentación estilizada.

3.- En el tercer paso, se instala flux, con la siguiente estuctura de directorios y archivos.

src
├── containers
│   └── AppContainer.js
├── data
│   ├── TodoActions.js
│   ├── TodoActionTypes.js
│   ├── TodoDispatcher.js
│   └── TodoStore.js
├── root.js
└── views
    └── AppView.js
En TodoDispatcher, se importa de flux y se instancia.
import {Dispatcher} from 'flux';

export default new Dispatcher();

Se crean Actions y ActionTypes, TodoAction.js y TodoActionTypes.js que tendrán todas las actions de la aplicación.

data/TodoActionTypes.js tiene un enumerado de las acciones de la aplicación.
const ActionTypes = {
  ADD_TODO: 'ADD_TODO',
};

export default ActionTypes;
En data/TodoActions.js, cada function despacha una action.
import TodoActionTypes from './TodoActionTypes';
import TodoDispatcher from './TodoDispatcher';

const Actions = {
  addTodo(text) {
    TodoDispatcher.dispatch({
      type: TodoActionTypes.ADD_TODO,
      text,
    });
  },
};

export default Actions;
Ahora se levanta el Store. data/TodoStore.js este almacenará toda la información de los objetos de la aplicación. Se usa un map Immutable como state.
Immutable.js es una open source de facebook que nos permite manejar collections de datos, con métodos tradicionales más métodos nuevos referentes a la inmutabilidad.
Immutable es una forma de almacenar datos de forma eficiente con la característica de no modificar el valor original de los datos, sino considerar que cambian de estado. Al decir eficiente, significa que no se duplican valores del estado, sino solo los pequeños cambios se agregan al nuevo estado de los datos, esto se hace por medio de Structural Sharing, algo así como arboles que apuntan a los datos, y las raices de los arboles representan los estados.

import Immutable from 'immutable';
import {ReduceStore} from 'flux/utils';
import TodoActionTypes from './TodoActionTypes';
import TodoDispatcher from './TodoDispatcher';

class TodoStore extends ReduceStore {
  constructor() {
    super(TodoDispatcher);
  }

  getInitialState() {
    return Immutable.OrderedMap();
  }

  reduce(state, action) {
    switch (action.type) {
      case TodoActionTypes.ADD_TODO:
        // Do nothing for now, we will add logic here soon!
        return state;

      default:
        return state;
    }
  }
}

export default new TodoStore();
se hace una simple vista usando React, views/AppView.js
import React from 'react';

function AppView() {
  return <div>Hola desde Flux!</div>;
}

export default AppView;
Los CONTAINERS son los que conectan el STATE de los STORES a las VIEWS.

En containers/AppContainer.js se tiene:
import AppView from '../views/AppView';
import {Container} from 'flux/utils';
import TodoStore from '../data/TodoStore';

function getStores() {
  return [
    TodoStore,
  ];
}

function getState() {
  return {
    todos: TodoStore.getState(),
  };
}

export default Container.createFunctional(AppView, getStores, getState);
Finalmente se actualiza root.js de la aplicación para que renderé AppContainer.

import AppContainer from './containers/AppContainer';
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<AppContainer />, document.getElementById('todoapp'));
La aplicación dirá Hola desde Flux!

4.- Se renderean Todos.

Se usa Immutable.js para retener los datos de cada tarea. Esto nos da un a bonita API para actualizar información sin necesidad de preocuparnos por una actualización accidental de un Todo,

data/Todo.js

import Immutable from 'immutable';

const Todo = Immutable.Record({
  id: '',
  complete: false,
  text: '',
});

export default Todo;
Ahora actuializamos data/TodoStore.js, utilizando la estructura Todo,  y Counter.js para implementar la acción ADD_TODO.

import Counter from './Counter';
import Todo from './Todo';

class TodoStore extends ReduceStore {
  ...
  reduce(state, action) {
    switch (action.type) {
      case TodoActionTypes.ADD_TODO:
        // Don't add todos with no text.
        if (!action.text) {
          return state;
        }
        const id = Counter.increment();
        return state.set(id, new Todo({
          id,
          text: action.text,
          complete: false,
        }));

      default:
        return state;
    }
  }
}
Actualizamos la VISTA para que renderé los Todos que son almacenados. views/AppView.js

function AppView(props) {
  return (
    <div>
      <Header {...props} />
      <Main {...props} />
      <Footer {...props} />
    </div>
  );
}

function Header(props) {
  return (
    <header id="header">
      <h1>todos</h1>
    </header>
  );
}

function Main(props) {
  if (props.todos.size === 0) {
    return null;
  }
  return (
    <section id="main">
      <ul id="todo-list">
        {[...props.todos.values()].reverse().map(todo => (
          <li key={todo.id}>
            <div className="view">
              <input
                className="toggle"
                type="checkbox"
                checked={todo.complete}
                onChange={
                  // Empty function for now, we will implement this later.
                  () => {}
                }
              />
              <label>{todo.text}</label>
              <button
                className="destroy"
                onClick={
                  // Empty function for now, we will implement this later.
                  () => {}
                }
              />
            </div>
          </li>
        ))}
      </ul>
    </section>
  );
}

function Footer(props) {
  if (props.todos.size === 0) {
    return null;
  }
  return (
    <footer id="footer">
      <span id="todo-count">
        <strong>
          {props.todos.size}
        </strong>
        {' items left'}
      </span>
    </footer>
  );
}
Para probar la aplicación, creamos algunos Todos de prueba , después del rendereo inicial.
import AppContainer from './containers/AppContainer';
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<AppContainer />, document.getElementById('todoapp'));

// We will remove these lines later:

import TodoActions from './data/TodoActions';

TodoActions.addTodo('Mi Primer Tarea');
TodoActions.addTodo('Otra Tarea');
TodoActions.addTodo('Terminando el tutorial');
Aún no hay interactividad, por lo que los botones no funcionan aún.

5.- Agregando Interactividad.

Se agregan Actions a sata/TodoActionTypes.js y data/TodoActions.js

TodoActionTypes.js
const ActionTypes = {
  ADD_TODO: 'ADD_TODO',
  DELETE_TODO: 'DELETE_TODO',
  TOGGLE_TODO: 'TOGGLE_TODO',
};
TodoActions.js
const Actions = {
  addTodo(text) {
    TodoDispatcher.dispatch({
      type: TodoActionTypes.ADD_TODO,
      text,
    });
  },

  deleteTodo(id) {
    TodoDispatcher.dispatch({
      type: TodoActionTypes.DELETE_TODO,
      id,
    });
  },

  toggleTodo(id) {
    TodoDispatcher.dispatch({
      type: TodoActionTypes.TOGGLE_TODO,
      id,
    });
  },
};
Actualizamos data/TodoStore.js

class TodoStore extends ReduceStore {
  ...
  reduce(state, action) {
    switch (action.type) {
      ...
      case TodoActionTypes.DELETE_TODO:
        return state.delete(action.id);

      case TodoActionTypes.TOGGLE_TODO:
        return state.update(
          action.id,
          todo => todo.set('complete', !todo.complete),
        );
      ...
    }
  }
}
Ahora el Store ya es capaz de borrar y alternar una Tarea. En una aplicación de Flux el único lugar que debería tener conocimiento de Flux es el CONTAINER, esto significa que debemos definir los callbacks o funciones de llamado en AppContainer y hacer la transferencia a AppView, La Vista no  despacha las acciones directamente. Esto hace fácil de usar, probar y cambiar las vistas.

Se actualiza container/AppContainer.js
import TodoActions from '../data/TodoActions';

function getState() {
  return {
    todos: TodoStore.getState(),

    onDeleteTodo: TodoActions.deleteTodo,
    onToggleTodo: TodoActions.toggleTodo,
  };
}
Ahora necesitamos utilizar estos callbacks en la vista, para desplegar el número de Tareas completadas.
Actualizamos views/AppViews.js

function Main(props) {
  if (props.todos.size === 0) {
    return null;
  }
  return (
    <section id="main">
      <ul id="todo-list">
        {[...props.todos.values()].reverse().map(todo => (
          <li key={todo.id}>
            <div className="view">
              <input
                className="toggle"
                type="checkbox"
                checked={todo.complete}
                onChange={() => props.onToggleTodo(todo.id)}
              />
              <label>{todo.text}</label>
              <button
                className="destroy"
                onClick={() => props.onDeleteTodo(todo.id)}
              />
            </div>
          </li>
        ))}
      </ul>
    </section>
  );
}

function Footer(props) {
  if (props.todos.size === 0) {
    return null;
  }

  const remaining = props.todos.filter(todo => !todo.complete).size;
  const phrase = remaining === 1 ? ' item left' : ' items left';

  return (
    <footer id="footer">
      <span id="todo-count">
        <strong>
          {remaining}
        </strong>
        {phrase}
      </span>
    </footer>
  );
}
Al refrescar la página podremos borrar y alternar el estado de las Tareas.



6.- Agregando funcionalidad Extra

Una vez familiarizados con la estructura de la aplicación de tareas pendientes, la guía nos indica los  siguientes pasos en orden adecuado, y es de gran ayuda consultar el ejemplo original.

1.- Crear una vista NewTodo

    AppView.js se integra <NewTodo {...props} />



- Crear TodoDraftStore la cual dará seguimiento al contenido de NewTodo Input, está responderá a dos acciones:
  - UPDATE_DRAFT el cual cambia el contenido redactado.
  - ADD_TODO          el cual limpia el contenido redactado.

   Se integran estas acciones a TodoActionTypes.js, TodoActions.js


   Se crea TodoDraftStore.js

import {ReduceStore} from 'flux/utils';
import TodoActionTypes from './TodoActionTypes';
import TodoDispacher from './TodoDispatcher';

class TodoDraftStore extends ReduceStore{
    constructor() {
        super(TodoDispacher);
    }

    getInitialState() {
        return '';
    }

    reduce(state, action){
        switch (action.type) {
            case TodoActionTypes.ADD_TODO:
                return '';

            case TodoActionTypes.UPDATE_DRAFT:
                return action.text;

            default:
                return state;
        }
    }

}

export default new TodoDraftStore();


- Crear la acción updateDraft y pasarla a través del CONTAINER.

  Un FluxContainer es usado para subscribir un componente React a multiples STORES.
El Componente recibe información desde los STORES por medio del STATE.

  Se integra a AppContainer.js


Al final de appContainer.js se exporta la función

export default Container.createFunctional(AppView, getStores, getState);

Esta es una función alterna a la de Container.create(base: ReactClass, options: ?Object): ReactClass 
create(...) es usada para transformar una clase React en un CONTAINER que actualiza el STATE cuando cambios relevantes ocurren en STORE.

La cual está documentada en la página, pero no createFunctional(...
Así que tendremos que ver su definición en las flux/utils, concretemente en \flux\lib\FluxContainer.js

function createFunctional(viewFn, _getStores, _calculateState, options) {...
esta función nos permite conectar una functional stateless VIEW al STORE. viewFn es el AppView que contiene componentes React. La forma simple de viewFn es la siguiente:

// FooView.js
 *
 *   function FooView(props) {
 *     return <div>{props.value}</div>;
 *   }
 *
 *   module.exports = FooView;
 *
 *
 *   // FooContainer.js
 *
 *   function getStores() {
 *     return [FooStore];
 *   }
 *
 *   function calculateState() {
 *     return {
 *       value: FooStore.getState();
 *     };
 *   }
 *
 *   module.exports = FluxContainer.createFunctional(
 *     FooView,
 *     getStores,
 *     calculateState,
 *   );

En nuestro caso la AppView tiene la misma estructura, solo que un poco más elaborada.

- Amarra a la Vista.


2.- Agregar un botón de Limpiar Completadas en el footer

   se crea la accion deleteCompletedTodos en TodoActionTypes.js, TodoActions.js, En CONTAINER
se mapea en el STATE la llamada onDeleteCompletedTodos (AppContainer.js). y en el STORE se agrega el código en CASE para modificar el STATE. esto es quitando (filter) los todos.completed.

3.- Agregar un botón "Completadas Todas", en la sección Main de la vista.
   - Si algún TODO esta incompleto, marcarlos todos como completos.
   - Si todos están Completados, Marcarlos como InCompletos.


Es de Observar como se aplican operaciones de Programación funcional al STATE, como map, every, set, delete, filter...


4.- Agregar la habilidad de editar las Tareas con Doble click.

   - Crear TodoEditStore que dara seguimiento al ID del TODO que será editado.
   - Crear la acciones startEditingTodo y StopEditingTodo.
   - Crear la accion editTodo.
   - Crear el componente de vista TodoEdit, y darle funcionalidad.

  Continua...