pello.info News http://www.pello.info/index.php/rss2 pello.info News syndication 2014-07-24 10:07:30 http://www.pello.info/index.php/rss2 es Node.js + express routes + mongoose, simple and separated http://www.pello.info/index.php/blog/node-js-express-routes-mongoose-simple-and-separated http://www.pello.info/index.php/blog/node-js-express-routes-mongoose-simple-and-separated 2014-07-23 23:45:40 pelloxabier http://www.pello.info/index.php/blog/node-js-express-routes-mongoose-simple-and-separated express simple-express-mongoose This creates a directory with that name and an app.js with this content:
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

/// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});


module.exports = app;

Let's simplify to leave only the routes:

var express = require('express');
var index = require('./routes');
var guestbook = require('./routes/guestbook');


var app = express();

app.use(express.static('public'));

app.use('/', index);
app.use('/guestbook', guestbook);

app.listen(3000, function () {
        console.log('Listening on port 3000');
})
Requiring all routes just once

Applications tend to grow and so we would have to require every route in the main entrypoint for express. Instead of that we can require just the routes/index.js

exports.home = require('./home');
exports.guestbook = require('./guestbook');

Now app.js has simplified route requires

var express = require('express');
var routes = require('./routes'); // This will require 'routes/index.js' !!

var app = express();

app.use(express.static('public'));

app.use('/', routes.home);
app.use('/guestbook', routes.guestbook);

app.listen(3000, function () {
        console.log('Listening on port 3000');
})

I've seen samples where all routes are added to express with just one line of code, but it wasn't working here for me.

Adding MongoDB support

Ok, now we want to show guestbook messages from a MongoDB database. As we are using mongoose, we must define a schema for each collection, and so we'll create a guestbook.js file in a models folder. Here we could try the same procedure used for routes. We create a models/index.js file which connects to MongoDB and exports all mongoose schemas. Here is models/index.js

/**
 * models/index.js
 * All models are here to import all of them just with one command
 * in the main app.js, and by the way we connect to MongoDB
 * Better to use an external config.. I know.
 * https://github.com/pello-io/simple-express-mongoose
 * Pello Altadill - http://pello.info
 */
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/blog');

// optionally:
//mongoose.set('debug', true);

exports.GuestBook = require('./guestbook');

And this is the schema definition for the guestbook collection, mongoose style. MongoDB is a schemaless database but this driver forces you to define a schema.

The routes

Routes are separated, one file for the home request, other file for guestbook requests, and so forth as the app grows. home.js is pretty straightforward: when we receive a get request, just render the index.jade

And this is the route for guestbook.js, with the get and the post. post saves data and then redirects to get case.

app.js, finally

Here you have. There are more modules to load to improve this sample app, but at least routes and models now are kept apart.

You can clone, download, copy-paste this project from git. Don't forget to get the required node modules to make it work!

]]>
express simple-express-mongoose This creates a directory with that name and an app.js with this content:
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

/// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});


module.exports = app;

Let's simplify to leave only the routes:

var express = require('express');
var index = require('./routes');
var guestbook = require('./routes/guestbook');


var app = express();

app.use(express.static('public'));

app.use('/', index);
app.use('/guestbook', guestbook);

app.listen(3000, function () {
        console.log('Listening on port 3000');
})
Requiring all routes just once

Applications tend to grow and so we would have to require every route in the main entrypoint for express. Instead of that we can require just the routes/index.js

exports.home = require('./home');
exports.guestbook = require('./guestbook');

Now app.js has simplified route requires

var express = require('express');
var routes = require('./routes'); // This will require 'routes/index.js' !!

var app = express();

app.use(express.static('public'));

app.use('/', routes.home);
app.use('/guestbook', routes.guestbook);

app.listen(3000, function () {
        console.log('Listening on port 3000');
})

I've seen samples where all routes are added to express with just one line of code, but it wasn't working here for me.

Adding MongoDB support

Ok, now we want to show guestbook messages from a MongoDB database. As we are using mongoose, we must define a schema for each collection, and so we'll create a guestbook.js file in a models folder. Here we could try the same procedure used for routes. We create a models/index.js file which connects to MongoDB and exports all mongoose schemas. Here is models/index.js

/**
 * models/index.js
 * All models are here to import all of them just with one command
 * in the main app.js, and by the way we connect to MongoDB
 * Better to use an external config.. I know.
 * https://github.com/pello-io/simple-express-mongoose
 * Pello Altadill - http://pello.info
 */
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/blog');

// optionally:
//mongoose.set('debug', true);

exports.GuestBook = require('./guestbook');

And this is the schema definition for the guestbook collection, mongoose style. MongoDB is a schemaless database but this driver forces you to define a schema.

The routes

Routes are separated, one file for the home request, other file for guestbook requests, and so forth as the app grows. home.js is pretty straightforward: when we receive a get request, just render the index.jade

And this is the route for guestbook.js, with the get and the post. post saves data and then redirects to get case.

app.js, finally

Here you have. There are more modules to load to improve this sample app, but at least routes and models now are kept apart.

You can clone, download, copy-paste this project from git. Don't forget to get the required node modules to make it work!

]]> http://www.pello.info/index.php/blog/node-js-express-routes-mongoose-simple-and-separated
Setting different config files in Node.js http://www.pello.info/index.php/blog/setting-different-config-files-in-node-js http://www.pello.info/index.php/blog/setting-different-config-files-in-node-js 2014-07-22 00:52:26 pelloxabier http://www.pello.info/index.php/blog/setting-different-config-files-in-node-js External config files Node.JS logo

When it comes to configuration options it is always desirable to avoid hardcoding config values in our code. Even more, if we are using different config values in development and production environments it is necessary an easy way to switch from one to another. This also becomes useful when your code is public but you want to hide some config files. In Node.js there is more than one way to do this.

Using config module

Easy to install, easy to configure, easy to use. The module you need is named config and you can have it just doing npm install config or adding config in the dependencies section of your packages.json file:

{
  "name": "world-domination-project",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app"
  },
  "dependencies": {
    "express": "~4.2.0",
     "config": "~0.4.36",
     "mongoose": "*",
    "debug": "~0.7.4"
  }
}

The project is hosted on github, and just taking a look to the README you can set everything up.

Creating config files

First of all, in your project root you must create a folder called config with a mkdir config o whatever. If you love troubles and you don't like to be said what and where do you have to create folders, you'll have to set the $NODE_CONFIG_DIR variable.

If you want more details just read more about configuration files options. You can pick between many different flavors of config syntax: json, yaml, cofeescript, js,... What I am showing here is quite simple: a default config and a production configuration in json format.

config/default.json

default.json is the first file that config module tries to get. So this is fine for development, and this is how it looks like:

/**
 * default config file
 */
{
    "www" : {
        "port" : 3000
        },
    "db": {
        "host": "localhost",
        "port": "27017",
        "dbname": "blog",
        "username" : "",
        "password" : ""
        },
    "debug": {
        "level": 0
    }
}
config/production.json

Here comes the production config, with the same keys but with different values. As you may expect, ports, hosts, passwords, are different.

{
    "www" : {
        "port" : 80
    },
    "db": {
        "host": "imsokweliuse.mongolabs.net",
        "port": "27017",
        "dbname": "blog",
        "username" : "snowden",
        "password" : "changeme"
    },
    "debug": {
        "level": 1
    }
}
Applying config file

Very easily, just require config module and you are ready to go. The json file is loaded and everything is handled in a variable. If you want to apply the production.json file, you have to set NODE_ENV environment variable to production, this way: export $NODE_ENV=production. That is something that maybe in your production server is already set. As for the code, behold the config module working:

/**
* app.js - pello altadill
* @greetz to any
*/
...
var express = require('express');
var mongoose = require('mongoose');
var mongooseTypes = require("mongoose-types");
var config = require('config');

mongooseTypes.loadTypes(mongoose);

console.log("Show conf:" + config.www.port);

mongoose.connect('mongodb://'+config.db.username+':'+config.db.password+'@'+config.db.host+':'+config.db.port+'/'+config.db.dbname);
var app = express();
...

Yeah I know, maybe instead of splitting all the database config we should just set one url containing everything. Do it your way.

]]> External config files Node.JS logo

When it comes to configuration options it is always desirable to avoid hardcoding config values in our code. Even more, if we are using different config values in development and production environments it is necessary an easy way to switch from one to another. This also becomes useful when your code is public but you want to hide some config files. In Node.js there is more than one way to do this.

Using config module

Easy to install, easy to configure, easy to use. The module you need is named config and you can have it just doing npm install config or adding config in the dependencies section of your packages.json file:

{
  "name": "world-domination-project",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app"
  },
  "dependencies": {
    "express": "~4.2.0",
     "config": "~0.4.36",
     "mongoose": "*",
    "debug": "~0.7.4"
  }
}

The project is hosted on github, and just taking a look to the README you can set everything up.

Creating config files

First of all, in your project root you must create a folder called config with a mkdir config o whatever. If you love troubles and you don't like to be said what and where do you have to create folders, you'll have to set the $NODE_CONFIG_DIR variable.

If you want more details just read more about configuration files options. You can pick between many different flavors of config syntax: json, yaml, cofeescript, js,... What I am showing here is quite simple: a default config and a production configuration in json format.

config/default.json

default.json is the first file that config module tries to get. So this is fine for development, and this is how it looks like:

/**
 * default config file
 */
{
    "www" : {
        "port" : 3000
        },
    "db": {
        "host": "localhost",
        "port": "27017",
        "dbname": "blog",
        "username" : "",
        "password" : ""
        },
    "debug": {
        "level": 0
    }
}
config/production.json

Here comes the production config, with the same keys but with different values. As you may expect, ports, hosts, passwords, are different.

{
    "www" : {
        "port" : 80
    },
    "db": {
        "host": "imsokweliuse.mongolabs.net",
        "port": "27017",
        "dbname": "blog",
        "username" : "snowden",
        "password" : "changeme"
    },
    "debug": {
        "level": 1
    }
}
Applying config file

Very easily, just require config module and you are ready to go. The json file is loaded and everything is handled in a variable. If you want to apply the production.json file, you have to set NODE_ENV environment variable to production, this way: export $NODE_ENV=production. That is something that maybe in your production server is already set. As for the code, behold the config module working:

/**
* app.js - pello altadill
* @greetz to any
*/
...
var express = require('express');
var mongoose = require('mongoose');
var mongooseTypes = require("mongoose-types");
var config = require('config');

mongooseTypes.loadTypes(mongoose);

console.log("Show conf:" + config.www.port);

mongoose.connect('mongodb://'+config.db.username+':'+config.db.password+'@'+config.db.host+':'+config.db.port+'/'+config.db.dbname);
var app = express();
...

Yeah I know, maybe instead of splitting all the database config we should just set one url containing everything. Do it your way.

]]>
http://www.pello.info/index.php/blog/setting-different-config-files-in-node-js Enabling basic authentication for MongoDB databases http://www.pello.info/index.php/blog/enabling-basic-authentication-for-mongodb-databases http://www.pello.info/index.php/blog/enabling-basic-authentication-for-mongodb-databases 2014-07-20 00:37:15 pelloxabier http://www.pello.info/index.php/blog/enabling-basic-authentication-for-mongodb-databases

MongoDB is extremely easy to install and run. If you are not able to make it work maybe you could feel more confortable using Access or even excel. Well, sorry for that. This short article is but a quick and dirty guide to enable basic authentication in mongodb, and how to create one database with its own user (not a superadmin) with just read/write permissions.

If you run mongod without parameters, you will not have any auth mechanism protecting your data. That could be fine when you are in a testing environment or in your own laptop playing around, but not in production or in any publicly reachable site.

/opt/mongodb/bin/mongod --fork --syslog --dbpath /data/db --smallfiles --auth --bind_ip 127.0.0.1

You could also just apply iptables or any other firewall system to prevent intrusions.

Maybe you have noticed that bind_ip 127.0.0.1 parameter. In doing so mongod will be available only for local connections which but only in certain conditions: obviously your program must reside in the same machine. In addition to that, mongod should be a single and isolated instance. That means that this configuration is impossible in replica sets or sharding scenarios. And by the way, if you need to manage MongoDB instance you need a program for it; something like the phpmyadmin for mysql, for instace http://www.phpmoadmin.com/. With --fork the mongod process will go to background, --syslog will send all log messages to /var/log/whatever you have configured in syslog, --dbpath indicates the directory where MongoDB data files are and --smallfiles comes in handy for testing or development environments becauses it reduces the size of data files and journal files.

User and roles

Apart from some authentication systems, MongoDB has users and roles which can be applied to different databases. First, let's see how to create an admin user for admin database with god-like (root) permissions. It's also explained here.

Root permissions for all mongo databases:

use admin
db.createUser(
  {
    user: "admin",
    pwd: "KeepASecret",
    roles: [ "root" ]
    
  }
)
Successfully added user: { "user" : "admin", "roles" : [ "root" ] }

Now mongodb will not show you anything. Logout and log in again, this time using those credentials.

root@usurbil:# mongo -u admin -p KeepASecret admin
MongoDB shell version: 2.6.1
connecting to: admin
>

To check the permissions for a certain user:

db.runCommand(
  {
    usersInfo:"admin",
    showPrivileges:true
  }
)
One user just for one database

Somo basic permissions for just one db:

use myotherdb
db.createUser(
  {
    user: "myotherdbuser",
    pwd: "KeepASecret",
    roles: ["readWrite","dbAdmin"]
  }
)

That's it, fisrt we access admin database and then we run db.createUser command with obvious options in json sintax. If anything fails we can just stop mongod and re-run it without the --auth flag. If you try to access with your mongoshell using this admin user you'll get:

root@linux:# mongo  -u admin -p wrongpass admin
MongoDB shell version: 2.6.1
connecting to: admin
2014-07-18T01:32:04.702+0200 Error: 18 { ok: 0.0, errmsg: "auth failed", code: 18 } at src/mongo/shell/db.js:1210
exception: login failed
root@linux:# 

We could also log without any user and authenticate from the mongo shell

root@linux:# mongo --host localhost admin
MongoDB shell version: 2.6.1
connecting to: localhost:27017/admin
> db.auth({user: 'admin',pwd:'KeepASecret'})

Changing password

To change the password, enter as admin, change to the database of that user and execute changeUserPassword command

> use myotherdb
switched to db myotherdb
> db.changeUserPassword("myotherdbuser", "1234567")

Updating permissions

Database access are stored in collections of course, in db.system.users. So we can just execute update queries to add new roles, which is but an array where we can push or pop values.

 db.system.users.update({_id:"admin.admin"},{$push:{"roles":{"role":"root","db":"mytotherdb"}}})

To be honest, this is the kind of post that I use as a reminder. Hope that anybody reading this finds it useful. ;)

]]>

MongoDB is extremely easy to install and run. If you are not able to make it work maybe you could feel more confortable using Access or even excel. Well, sorry for that. This short article is but a quick and dirty guide to enable basic authentication in mongodb, and how to create one database with its own user (not a superadmin) with just read/write permissions.

If you run mongod without parameters, you will not have any auth mechanism protecting your data. That could be fine when you are in a testing environment or in your own laptop playing around, but not in production or in any publicly reachable site.

/opt/mongodb/bin/mongod --fork --syslog --dbpath /data/db --smallfiles --auth --bind_ip 127.0.0.1

You could also just apply iptables or any other firewall system to prevent intrusions.

Maybe you have noticed that bind_ip 127.0.0.1 parameter. In doing so mongod will be available only for local connections which but only in certain conditions: obviously your program must reside in the same machine. In addition to that, mongod should be a single and isolated instance. That means that this configuration is impossible in replica sets or sharding scenarios. And by the way, if you need to manage MongoDB instance you need a program for it; something like the phpmyadmin for mysql, for instace http://www.phpmoadmin.com/. With --fork the mongod process will go to background, --syslog will send all log messages to /var/log/whatever you have configured in syslog, --dbpath indicates the directory where MongoDB data files are and --smallfiles comes in handy for testing or development environments becauses it reduces the size of data files and journal files.

User and roles

Apart from some authentication systems, MongoDB has users and roles which can be applied to different databases. First, let's see how to create an admin user for admin database with god-like (root) permissions. It's also explained here.

Root permissions for all mongo databases:

use admin
db.createUser(
  {
    user: "admin",
    pwd: "KeepASecret",
    roles: [ "root" ]
    
  }
)
Successfully added user: { "user" : "admin", "roles" : [ "root" ] }

Now mongodb will not show you anything. Logout and log in again, this time using those credentials.

root@usurbil:# mongo -u admin -p KeepASecret admin
MongoDB shell version: 2.6.1
connecting to: admin
>

To check the permissions for a certain user:

db.runCommand(
  {
    usersInfo:"admin",
    showPrivileges:true
  }
)
One user just for one database

Somo basic permissions for just one db:

use myotherdb
db.createUser(
  {
    user: "myotherdbuser",
    pwd: "KeepASecret",
    roles: ["readWrite","dbAdmin"]
  }
)

That's it, fisrt we access admin database and then we run db.createUser command with obvious options in json sintax. If anything fails we can just stop mongod and re-run it without the --auth flag. If you try to access with your mongoshell using this admin user you'll get:

root@linux:# mongo  -u admin -p wrongpass admin
MongoDB shell version: 2.6.1
connecting to: admin
2014-07-18T01:32:04.702+0200 Error: 18 { ok: 0.0, errmsg: "auth failed", code: 18 } at src/mongo/shell/db.js:1210
exception: login failed
root@linux:# 

We could also log without any user and authenticate from the mongo shell

root@linux:# mongo --host localhost admin
MongoDB shell version: 2.6.1
connecting to: localhost:27017/admin
> db.auth({user: 'admin',pwd:'KeepASecret'})

Changing password

To change the password, enter as admin, change to the database of that user and execute changeUserPassword command

> use myotherdb
switched to db myotherdb
> db.changeUserPassword("myotherdbuser", "1234567")

Updating permissions

Database access are stored in collections of course, in db.system.users. So we can just execute update queries to add new roles, which is but an array where we can push or pop values.

 db.system.users.update({_id:"admin.admin"},{$push:{"roles":{"role":"root","db":"mytotherdb"}}})

To be honest, this is the kind of post that I use as a reminder. Hope that anybody reading this finds it useful. ;)

]]>
http://www.pello.info/index.php/blog/enabling-basic-authentication-for-mongodb-databases
Python language basics http://www.pello.info/index.php/blog/python-language-basics http://www.pello.info/index.php/blog/python-language-basics 2014-07-12 23:51:05 pelloxabier http://www.pello.info/index.php/blog/python-language-basics Python in 21 minutes (or so)

For a developer is not enough to know one programming language, it is often said that is good to know many of them. After all the language is but a mere tool to build programs. Python has been around for many years and one of my pending task was to take a look at it. Some friends (@Eugenia4v,@Claw_Shadow,@D00m3dr4v3n) are always telling me about the benefits of Python not to mention plenty of papers where Python is even recommended as the language of choice to get into programming. I guess that when Google itself has been using Python from the beginning, and when this language is a requirement for many job offers there is something about it. Despite the title of this post, I spent more than 21 minutes coding around and trying the basics so don't expect a deep dive into Python. This is just a quick guide

python logo

Python is: interpreted, weakly typed, (could be compilated), case sensitive, supports oop, functional, imperative programming,... apart from the classic definition, if you come from c style languages at first glance you'll notice the lack of semicolons. But the real change in Python is the use of indentation to create code blocks. So instead using brackets for if-else-loops-functions you have to use indents or tabs properly. This at least, somehow leads to mandatory code convention (they exists too), here there is no room for discussion about the most clear way to write an if-else structure; there is only "one style" so follow it or your code will not run at all. But to sum up, and above all, python was designed to be easy to read

All the sample code used in this post is included in one single file.

Writing and running hello world

So you have just installed python in you windows box or you are running a linux machine, which means that python is most likely in da house. Open any text editor, write this and save it with .py extension:

print 'Hello World desde España y olé' # testing utf-8 :P
print "Welcome to python \'resume\'"
print "New Line \n and ring the bell \a"

To run this we can just execute python filename.py, or give it execution perms and run it directly

If you want to test some python code directly in the interpreter, just run python and the python prompt will show up awaiting for your commands.

Comments

We have single line comments and multiline comments. The first line gives support for utf-8 characters.

# -*- coding: utf-8 -*-
# This is a single line comment
"""
some python in a few lines, by Pello Altadill
This is a multiple line comment
more suitable for long texts like this
greetz to any
"""

Variables

There are no types in python. Variable declaration is the simplest possible.

# variable definitions ###########
number = 666
negativeNumber = -42
decimals = 3.1415
name = "Legion"
anotherName = "Legion of Doom"
letterA = 'a'
letterB = "b"
godExists = True
itsMe = False
# multiline string, 
prayer = """Gods of war I call you,
my sword is by my side,
I seek a life of honor,
free from all false pride"""

# multiple assignment, c-style
a = b = c = 0

# but not strongly typed...
a = True
c = 'Hello'

a = 10
b = -a
c = 42
Operators

Comparing with other languages we have some extra operators here. Bit operators are omitted, but you've them all.

# expressions ##########
# arithmethyc
a = b + c
b = a - c
c = a * b
a = b / c # returns floating point
a = b // c # integer division
modulus = a % c
thePower = a ** 3

# of course this are available:
a += b
b -= c
c *= a
a /= b
b %= 42

# booleans, as always
theTruth = godExists and itsMe
theTruth = godExists or false
theTruth = not godExists

# comparison operators
areEqual = a == b
areNotEqual = a!= b   # a <> b works, but obsolete
isBigger = a > b 
isLess = a < b
biggerOrEqual = a >= b
lessOrEqual = a <= b

# combination of all of them
superTrue = ( (a-1) > b) or (not(c == (b*4)))

# concatenation use , in general. + for strings
print "My name is " , name
print a , " - " , b , " - " , c
# if whe use + whe must convert to string
print str(a) + "," + str(b) + "," + str(c)
print prayer

# del unbinds variable values
del prayer
# print prayer would now fail

Conditional

Python offers if, if-else, if-elsif-else but there is NO switch/case.

# conditional #########################
# single if
if godExists:
	print "God is real unless declared integer"

## single line if
if True:print 'I am single lined if'

anything = '1'
if anything:
	print "Yeah, anything different to 0 means True"

# 0, None, "", '', empty structures (),[],{} are the same as False
numberZero = 0
if not numberZero:
	print "And 0 is False"

# we can omit or put parenthesis
if (a<b or b==c):
	print "a less than b or b equals c"


# if-else
if a > b:
	print "a is bigger than b"
else:
	print "a is NOT bigger than b"

# elif 
if a > b:
	print "a is bigger than b"	
elif a < b:
	print "a is less than b"
elif a == b:
	print "a and b are equal"
elif a == 0:
	pass  # this a way to do NOTHING , as we can't leave a block empty
else:
	print "a and b are alien"

# THERE IS NO switch case
# but you can do it with a elif structure
Loops

for and while loops as always but... there is no do-while. for is very simple and works well as foreach.

# loops ###########################
# while loop
c = 3
while c>0 :
	print "a loop with c" , c
	c-=1

# for loop 
# for i in range(begin,end), does not reach end
for x in range(0,5):
	print "for loop with x " , x

# with different step
# range(5) = [0, 1, 2, 3, 4]
# for (i in range(begin,end, step))
for x in range(0,10,2):
	print "for loop inc 2 with x " , x
for x in range(5,0,-1):
	print "for loop dec with x " , x

# xrange(number): from 0 to number
for x in xrange(5):  #  0..4
	print "testing xrange: " , x

name = 'Python'
for x in name:
	print "for loop with string: " , x

# break and continue works in python as well 
# applied to while and for
# with break we stop and exit the loop
findTheX = 'sdfXsaf'
for x in findTheX:
	if x == "X":
		print "found the X, now exit"
		break

# with continue we finish current iteration and go for next
someVocals = '0a00i0e00u000a'
for x in someVocals:
	if x =='0':
		continue
	elif x =='a':
		print "a founded"
	elif x=='e':
		print "e founded"

# else clause ###### after for and while is executed after the normal
# execution of the iteration, but NOT when the execution has been
# interrupted by break, exceptions or returns.
counter = 0
for x in someVocals:
	if x == 'a':
		counter += 1
else:
	print "Total a letters found in " , someVocals , ": " , counter

# THERE IS NO do-while structure

Arguments and read from console

The most basic way to pass arguments to a python script is using the sys.argv list. But, there are other richer modules available to get arguments in getopt style.

print 'Total arguments: ' , number ,  len(sys.argv)
for a in sys.argv:
	print a

# reading from console
value = raw_input("write something")
print value
Tuples, lists, and dictionaries

We have three kind of basic structures, but beware, once defined tuples can't be changed: they are immutable

# STRUCTURES #############################
# Tuples = IMMUTABLE, ordered, sequence of arbitrary items
someValues = (42, 15, 69)
otherValues = ('Meaning', 42, True, -0.3)
newTuple = tuple('aeiou') # this creates ('a','e','i','o','u')
emptyTuple= ()

print "First: " , otherValues[0]
print "Last: " , otherValues[-1]

# This is a way to add an elemtn
otherValues+= (34,56)
# THIS IS NOT ALLOWED as a tuple is IMMUTABLE
# otherValues[0] = 'Satan'

# of course is iterable
for v in otherValues:
	print "Tuple: " , v

# Lists = MUTABLE, ordered, sequence of arbitrary items
superList = ['Python','Ruby','Go']
otherList = ['God',666, True]
emptyList = []

print "First: " , superList[0]
print "Last: " , superList[-1]

# This is a way to add an elemtn
superList+= ['NodeJS']
otherList[0] = 'Satan'

for x in superList:
	print "Superlist : " , x

# Dictionaries = MUTABLE, arbitrary collection of items
# indexed by arbitrary items = similar to hashtables, hash, maps, you name it.
ages = {'Gandalf':1432, 'Aragorn':543, 'Bilbo':112}
emptyDictionary = {}
# using the builtin function:
trigValues = dict(sin=34,cos=353.23,tan=34)
otherAges = dict([['Frodo',34],['Samwise',35]])

ages['Bilbo'] = 120
ages['Radagast'] = 1423

# iterating...
for key in ages:
	print key , " : " , ages[key]

# SLICING SEQUENCES
# We access an element with sequence[index]
# to get a slice of if: sequence[begin:length:stride]
# stride is the distance or leap
ports = [20, 21, 25, 80, 443, 110, 143];
webPorts = ports[3:2] 		# [80, 443]
ftpPorts = ports[:2]; 		# [20, 21]
somePorts = ports[1:6:2] 	# [21, 80, 110]

# Strings are IMMUTABLE!! and slicing works the same way
myName = "Pello Xabier Altadill Izura"
# so this is illegal
#myName[0] = 'L'

print myName[0] , " name: " , myName[:5]

If we want to manipulate these structures, we have many built-in methods available.

Functions

def, function name and parameters, that's all.

# function definition #################
def hello():
	print "hello"

def add(a,b):
	return a+b

def isEven(a):
	return (a%2==0)

def withDefaultValues(a, b=0, c=42):
	result = a + b - c
	print "Parameter values: "
	print "a is " , a
	print "b is " , b
	print "c is " , c
	return result

# calling functions
hello
hello()
a = add(600,66)
print "Result of addition: " , add(a,b)
b = isEven(a) 
print "Result of isEven for " , a , ": " , b

withDefaultValues(5)
withDefaultValues(15,-5)
Modules

Put code in a file called filename.py and we can reuse it in other files just by doing import filename. Of course, apart from OOP, there are other options to package and reuse code more efficiently.

This is our super module, which has one super function

# hello.py 
def sayHello(name=""):
	return "Hello " , name

And this is the code to import and use that module

# importing an external 'hello.py' source
import hello as myModule

print myModule.sayHello("my little friend")
Editors

You may heard something about IDLE. Run, don't look back.. fly you fools! We could always use eclipse with plugins, aptana,... or pycharm by jetbrains if we prefer a simpler sintax-highlighted text editor check these out:

One of the complains you may have heard about python is that version 3 and 2 are not compatible. Apart from that it is one of the languages that any coder should know (in addition to all object oriented c-style languages imho). What about the OOP? well, I was horrified when I saw some code. It looked as dirty as perl, or even more (I like perl btw). Maybe another day.

When it comes to language preferences, it's always the same. Some people don't like java at all. Many coders think that php is not a language to be taken seriously. Other radicals hate whatever.NET from Microsoft. There are always fierce Python and Ruby supporters. I think that you have to forget your preferences and try to learn them all and master a few of them. Which language is the best? it depends. After all, web servers are written in c++ (yeah, nodejs too) and that's fine. And on top of the webserver we have realms of webapps built with interpreted languages: php, python, ruby, java, c#, js, ... . As for the dbms: frequently coded in c++, with sql, js, json on top.

]]>
Python in 21 minutes (or so)

For a developer is not enough to know one programming language, it is often said that is good to know many of them. After all the language is but a mere tool to build programs. Python has been around for many years and one of my pending task was to take a look at it. Some friends (@Eugenia4v,@Claw_Shadow,@D00m3dr4v3n) are always telling me about the benefits of Python not to mention plenty of papers where Python is even recommended as the language of choice to get into programming. I guess that when Google itself has been using Python from the beginning, and when this language is a requirement for many job offers there is something about it. Despite the title of this post, I spent more than 21 minutes coding around and trying the basics so don't expect a deep dive into Python. This is just a quick guide

python logo

Python is: interpreted, weakly typed, (could be compilated), case sensitive, supports oop, functional, imperative programming,... apart from the classic definition, if you come from c style languages at first glance you'll notice the lack of semicolons. But the real change in Python is the use of indentation to create code blocks. So instead using brackets for if-else-loops-functions you have to use indents or tabs properly. This at least, somehow leads to mandatory code convention (they exists too), here there is no room for discussion about the most clear way to write an if-else structure; there is only "one style" so follow it or your code will not run at all. But to sum up, and above all, python was designed to be easy to read

All the sample code used in this post is included in one single file.

Writing and running hello world

So you have just installed python in you windows box or you are running a linux machine, which means that python is most likely in da house. Open any text editor, write this and save it with .py extension:

print 'Hello World desde España y olé' # testing utf-8 :P
print "Welcome to python \'resume\'"
print "New Line \n and ring the bell \a"

To run this we can just execute python filename.py, or give it execution perms and run it directly

If you want to test some python code directly in the interpreter, just run python and the python prompt will show up awaiting for your commands.

Comments

We have single line comments and multiline comments. The first line gives support for utf-8 characters.

# -*- coding: utf-8 -*-
# This is a single line comment
"""
some python in a few lines, by Pello Altadill
This is a multiple line comment
more suitable for long texts like this
greetz to any
"""

Variables

There are no types in python. Variable declaration is the simplest possible.

# variable definitions ###########
number = 666
negativeNumber = -42
decimals = 3.1415
name = "Legion"
anotherName = "Legion of Doom"
letterA = 'a'
letterB = "b"
godExists = True
itsMe = False
# multiline string, 
prayer = """Gods of war I call you,
my sword is by my side,
I seek a life of honor,
free from all false pride"""

# multiple assignment, c-style
a = b = c = 0

# but not strongly typed...
a = True
c = 'Hello'

a = 10
b = -a
c = 42
Operators

Comparing with other languages we have some extra operators here. Bit operators are omitted, but you've them all.

# expressions ##########
# arithmethyc
a = b + c
b = a - c
c = a * b
a = b / c # returns floating point
a = b // c # integer division
modulus = a % c
thePower = a ** 3

# of course this are available:
a += b
b -= c
c *= a
a /= b
b %= 42

# booleans, as always
theTruth = godExists and itsMe
theTruth = godExists or false
theTruth = not godExists

# comparison operators
areEqual = a == b
areNotEqual = a!= b   # a <> b works, but obsolete
isBigger = a > b 
isLess = a < b
biggerOrEqual = a >= b
lessOrEqual = a <= b

# combination of all of them
superTrue = ( (a-1) > b) or (not(c == (b*4)))

# concatenation use , in general. + for strings
print "My name is " , name
print a , " - " , b , " - " , c
# if whe use + whe must convert to string
print str(a) + "," + str(b) + "," + str(c)
print prayer

# del unbinds variable values
del prayer
# print prayer would now fail

Conditional

Python offers if, if-else, if-elsif-else but there is NO switch/case.

# conditional #########################
# single if
if godExists:
	print "God is real unless declared integer"

## single line if
if True:print 'I am single lined if'

anything = '1'
if anything:
	print "Yeah, anything different to 0 means True"

# 0, None, "", '', empty structures (),[],{} are the same as False
numberZero = 0
if not numberZero:
	print "And 0 is False"

# we can omit or put parenthesis
if (a<b or b==c):
	print "a less than b or b equals c"


# if-else
if a > b:
	print "a is bigger than b"
else:
	print "a is NOT bigger than b"

# elif 
if a > b:
	print "a is bigger than b"	
elif a < b:
	print "a is less than b"
elif a == b:
	print "a and b are equal"
elif a == 0:
	pass  # this a way to do NOTHING , as we can't leave a block empty
else:
	print "a and b are alien"

# THERE IS NO switch case
# but you can do it with a elif structure
Loops

for and while loops as always but... there is no do-while. for is very simple and works well as foreach.

# loops ###########################
# while loop
c = 3
while c>0 :
	print "a loop with c" , c
	c-=1

# for loop 
# for i in range(begin,end), does not reach end
for x in range(0,5):
	print "for loop with x " , x

# with different step
# range(5) = [0, 1, 2, 3, 4]
# for (i in range(begin,end, step))
for x in range(0,10,2):
	print "for loop inc 2 with x " , x
for x in range(5,0,-1):
	print "for loop dec with x " , x

# xrange(number): from 0 to number
for x in xrange(5):  #  0..4
	print "testing xrange: " , x

name = 'Python'
for x in name:
	print "for loop with string: " , x

# break and continue works in python as well 
# applied to while and for
# with break we stop and exit the loop
findTheX = 'sdfXsaf'
for x in findTheX:
	if x == "X":
		print "found the X, now exit"
		break

# with continue we finish current iteration and go for next
someVocals = '0a00i0e00u000a'
for x in someVocals:
	if x =='0':
		continue
	elif x =='a':
		print "a founded"
	elif x=='e':
		print "e founded"

# else clause ###### after for and while is executed after the normal
# execution of the iteration, but NOT when the execution has been
# interrupted by break, exceptions or returns.
counter = 0
for x in someVocals:
	if x == 'a':
		counter += 1
else:
	print "Total a letters found in " , someVocals , ": " , counter

# THERE IS NO do-while structure

Arguments and read from console

The most basic way to pass arguments to a python script is using the sys.argv list. But, there are other richer modules available to get arguments in getopt style.

print 'Total arguments: ' , number ,  len(sys.argv)
for a in sys.argv:
	print a

# reading from console
value = raw_input("write something")
print value
Tuples, lists, and dictionaries

We have three kind of basic structures, but beware, once defined tuples can't be changed: they are immutable

# STRUCTURES #############################
# Tuples = IMMUTABLE, ordered, sequence of arbitrary items
someValues = (42, 15, 69)
otherValues = ('Meaning', 42, True, -0.3)
newTuple = tuple('aeiou') # this creates ('a','e','i','o','u')
emptyTuple= ()

print "First: " , otherValues[0]
print "Last: " , otherValues[-1]

# This is a way to add an elemtn
otherValues+= (34,56)
# THIS IS NOT ALLOWED as a tuple is IMMUTABLE
# otherValues[0] = 'Satan'

# of course is iterable
for v in otherValues:
	print "Tuple: " , v

# Lists = MUTABLE, ordered, sequence of arbitrary items
superList = ['Python','Ruby','Go']
otherList = ['God',666, True]
emptyList = []

print "First: " , superList[0]
print "Last: " , superList[-1]

# This is a way to add an elemtn
superList+= ['NodeJS']
otherList[0] = 'Satan'

for x in superList:
	print "Superlist : " , x

# Dictionaries = MUTABLE, arbitrary collection of items
# indexed by arbitrary items = similar to hashtables, hash, maps, you name it.
ages = {'Gandalf':1432, 'Aragorn':543, 'Bilbo':112}
emptyDictionary = {}
# using the builtin function:
trigValues = dict(sin=34,cos=353.23,tan=34)
otherAges = dict([['Frodo',34],['Samwise',35]])

ages['Bilbo'] = 120
ages['Radagast'] = 1423

# iterating...
for key in ages:
	print key , " : " , ages[key]

# SLICING SEQUENCES
# We access an element with sequence[index]
# to get a slice of if: sequence[begin:length:stride]
# stride is the distance or leap
ports = [20, 21, 25, 80, 443, 110, 143];
webPorts = ports[3:2] 		# [80, 443]
ftpPorts = ports[:2]; 		# [20, 21]
somePorts = ports[1:6:2] 	# [21, 80, 110]

# Strings are IMMUTABLE!! and slicing works the same way
myName = "Pello Xabier Altadill Izura"
# so this is illegal
#myName[0] = 'L'

print myName[0] , " name: " , myName[:5]

If we want to manipulate these structures, we have many built-in methods available.

Functions

def, function name and parameters, that's all.

# function definition #################
def hello():
	print "hello"

def add(a,b):
	return a+b

def isEven(a):
	return (a%2==0)

def withDefaultValues(a, b=0, c=42):
	result = a + b - c
	print "Parameter values: "
	print "a is " , a
	print "b is " , b
	print "c is " , c
	return result

# calling functions
hello
hello()
a = add(600,66)
print "Result of addition: " , add(a,b)
b = isEven(a) 
print "Result of isEven for " , a , ": " , b

withDefaultValues(5)
withDefaultValues(15,-5)
Modules

Put code in a file called filename.py and we can reuse it in other files just by doing import filename. Of course, apart from OOP, there are other options to package and reuse code more efficiently.

This is our super module, which has one super function

# hello.py 
def sayHello(name=""):
	return "Hello " , name

And this is the code to import and use that module

# importing an external 'hello.py' source
import hello as myModule

print myModule.sayHello("my little friend")
Editors

You may heard something about IDLE. Run, don't look back.. fly you fools! We could always use eclipse with plugins, aptana,... or pycharm by jetbrains if we prefer a simpler sintax-highlighted text editor check these out:

One of the complains you may have heard about python is that version 3 and 2 are not compatible. Apart from that it is one of the languages that any coder should know (in addition to all object oriented c-style languages imho). What about the OOP? well, I was horrified when I saw some code. It looked as dirty as perl, or even more (I like perl btw). Maybe another day.

When it comes to language preferences, it's always the same. Some people don't like java at all. Many coders think that php is not a language to be taken seriously. Other radicals hate whatever.NET from Microsoft. There are always fierce Python and Ruby supporters. I think that you have to forget your preferences and try to learn them all and master a few of them. Which language is the best? it depends. After all, web servers are written in c++ (yeah, nodejs too) and that's fine. And on top of the webserver we have realms of webapps built with interpreted languages: php, python, ruby, java, c#, js, ... . As for the dbms: frequently coded in c++, with sql, js, json on top.

]]>
http://www.pello.info/index.php/blog/python-language-basics
A night out with Jasmine http://www.pello.info/index.php/blog/a-night-out-with-jasmine http://www.pello.info/index.php/blog/a-night-out-with-jasmine 2014-04-23 00:37:18 pelloxabier http://www.pello.info/index.php/blog/a-night-out-with-jasmine A night out with Jasmine

Unit testing is much more than a tool for ensuring that a program behaves as expected. Nowadays it's the key for new development techniques such as TDD and BDD in which you begin writing tests before the required code. It's all about requirements and behaviour; developers must focus on understanding the requirements instead of thinking about the way they implement the code. In the event that you've forgotten the fundamental benefits of unit testing here you have a quick reminder:

  • Obviously, you are testing that your code works
  • When changes are made you can automatically verify that everything works
  • Tests are a pretty good way to document the project.

Jasmine is a BDD framework for javascript code. In a nutshell, BDD it's an evolution of TDD where unit tests look like user stories, and so tests are defined in the same terms of the expected behaviour of the software units. When you discover functions names in Jasmine tests these simple definitions will make more sense.

Let's get our hands dirty, while you take a look at Jasmine's site http://jasmine.github.io/2.0/introduction.html you can get the master from the github site https://github.com/pivotal/jasmine/archive/master.zip

Or, if you are using node then just sigh, coff slightly, adjust your spectacles and simply try with this: npm -g install jasmine-node

Beware! at the time of writing this Jasmine is in 2.0 version and there are some changes and deprecated functions. So, be careful with what you read out there, check dates.

Ok, once jasmine is installed let's write this piece of code in a file called hello.js

exports.hello = function () {
	return 'Hello world';
};

Behold the almighty helloworld sample.

With Jasmine, the test file is expected to live in a dir called specs in a file called name.spec.js, so hello.spec.js in this case.

And this is what the test would look like:

/*
* specs/hello.spec.js
*/
var hl = require("../hello.js");

// testing hello function
describe("hello", function() {
	it('returns "Hello world"', function() {
		expect(hl.hello()).toEqual("Hello world");
	});
});

To run the test, in the same directory where hello.js resides we type jasmine-node command with the dir of the test and it will pass all specs files within


linux$ jasmine-node specs/
.

Finished in 0.020 seconds
1 tests, 1 assertions, 0 failures, 0 skipped
linux$ 

¿How could we test functions that are using a callback? In the same hello.js file we add this function:


exports.helloAsync = function (callback) {
	return callback(null,'Async Hello World');
};

And this is how the test should look like:

describe("helloAsync", function() {
	it("does an asynchronous call", function() {
		hl.helloAsync(function(err,response) {
			expect(response).toContain("Async Hello World");
		});
	});
});

Now if we run the test, we will check 2 test and 2 assertions:

linux$ jasmine-node specs/
..

Finished in 0.029 seconds
2 tests, 2 assertions, 0 failures, 0 skipped
linux$ 

Maybe you've noticed that in the second test instead of toEqual we're using .toContain. These are different matchers with different effects as indicated by their obvious names. As you can see, Jasmine drives us to write tests that apart from being 'extracool' can be read as natural language.

Developing a simply utility, TDD style

Our beloved system administrator wants a program to convert people names such as "john, doe" into account names like "john_doe". Remember, we are trying TDD now so focus on the requirement, and try not to think about using regular expressions or any kind of implementation details. TDD dictates to follow this steps:

  1. Write the test code
  2. Pass the test and see how it fails
  3. Write just the necessary code, quick and dirty, to turn the test from red to green
  4. Once the test is passed successfuly, refactor the code.
  5. Feel kwel, you earned a good cup of whatever

Ok, we create a specs dir, and inside a username.spec.js file containing our test of a code that right now it is but a ghost:


var username = require('../username.js');

describe('Test to ensure username is created', function () {
	it('returns name_surname with simple Name,Surname',function () {
		expect(username.create('john,doe')).toEqual('john_doe');
	});

});

Not only if we test this fails, but also if we run it this code FAILS. why? username.js does not exist, as simply as that. Well then, time for step 2 in TDD, we write our code in a file named username.js one dir level below.

/**
* username.js
* Pello Altadill Izura
* http://pello.info
*/

exports.create = function (personName) {
	var result = '';
	var parts = personName.split(',');
	result = parts[0] + '_' + parts[1];

	return result;
};

Now what we get is what we expected to:

linux$ jasmine-node specs/
.

Finished in 0.033 seconds
1 test, 1 assertion, 0 failures, 0 skipped

linux$

The requirements were minimal in order to show the process of TDD. But the world is not a pleasant place where everything just works fine. As Melissandre said, there is one hell, the one we are living in now. This could be a more realistic problem, which might be more useful to ilustrate some other Jasmine features.

Our Benevolent Dictator thinks that we deserve the honor to raise from the mud in which we creep and serve him with our bare hands, although we are not worthy of such a gift from a demigod. We want to get on well with OBD if we want him to lower the proxy constraints for us among other mundane privileges. He is in a need for a program that translates people names to system names with this specifications:

  • People names come with Name, Surname notation and they may be translated to name_surname
  • Names can come in either lower or uppercase
  • Names can come with extra spaces
  • Some people may have two names like 'John John, Kennedy' or 'Jar Jar, Binks' and they might be translated to name1name2_surname
  • Some names can be null or empty spaces ','. (That may be OBD's fault but It's better not to mention it)

We'll try to acomplish these specs, so our unit tests might look like this in Jasmine style:


var username = require('../username.js');

describe('Test to ensure username is created', function () {
	it('returns name_surname with simple Name,Surname',function () {
		expect(username.create('john,doe')).toEqual('john_doe');
	});

	it('converts any uppercase character to lowercase', function () {
		expect(username.create('Han,Solo')).toEqual('han_solo');
	});

	it('removes any space character', function () {
		expect(username.create('   Luke, Skywalker ')).toEqual('luke_skywalker');
	});

	it('returns multiple names together', function () {
		expect(username.create('Obi Wan,Kenobi')).toEqual('obiwan_kenobi');
	});

	it('throws error if name is empty', function () {
		expect(function() { 
					username.create(''); 
			   }).toThrow('Person name is empty');
	});
});

If we test all of this with our previous code Jasmine will scream our name:

linux$ jasmine-node specs/
.FFFF

Failures:

  1) Test to ensure username is created converts any uppercase character to lowercase
   Message:
     Expected 'Han_Solo' to equal 'han_solo'.
   Stacktrace:
     Error: Expected 'Han_Solo' to equal 'han_solo'.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:9:39)

  2) Test to ensure username is created removes any space character
   Message:
     Expected '   Luke_ Skywalker ' to equal 'luke_skywalker'.
   Stacktrace:
     Error: Expected '   Luke_ Skywalker ' to equal 'luke_skywalker'.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:13:50)

  3) Test to ensure username is created returns multiple names together
   Message:
     Expected 'Obi Wan_Kenobi' to equal 'obiwan_kenobi'.
   Stacktrace:
     Error: Expected 'Obi Wan_Kenobi' to equal 'obiwan_kenobi'.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:17:45)

  4) Test to ensure username is created returns empty string with spaces
   Message:
     Expected '_undefined' to equal ''.
   Stacktrace:
     Error: Expected '_undefined' to equal ''.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:21:31)

Finished in 0.061 seconds
5 tests, 5 assertions, 4 failures, 0 skipped

Let's fix each of the tests


/**
* username.js
* Pello Altadill Izura
* http://pello.info
*/

exports.create = function (personName) {
	var result = '';
	personName = personName.toLowerCase();
	personName = personName.replace(/\s/g,'');
	if (personName == '' ) {
		throw new Error('Person name is empty');
	}
	var parts = personName.split(',');
	result = parts[0] + '_' + parts[1];

	return result;
};

The \s replacement fixes many things. And now we throw an Error whenever a personName comes empty. Maybe this is not the preferred behaviour of our program, but It helps to show how to check if exceptions are thrown.

Jasmine matchers at a glance

We have already used .toEqual(), .toContain() and .toThrow(), but if you're familiar with unit testing you might expect many others to exist. So instead of blowing your mind with poor-man's wordgames, let's see what we have inside Jasmine's toolbox.

Negate matching

at any moment we can reverse the matcher using a not like this

expect(666).not.toEqual(333);
toEqual

Tests equality with primitive types: numbers, strings, booleans, null. But NOT with objects. Some examples:

		var one = {'name' : 'John'};
		var other = {'name' : 'John'};
		var another = one;
		var oneArray = [42, 15, 69];
		var otherArray = [42, 15, 69];
		var anotherArray = [6, 66, 666];
		var phrase = 'By demon be driven';


		expect(6).toEqual(6);
		expect(6).toEqual(6.0);
		expect(one).toEqual(other);
		expect(oneArray).toEqual(otherArray);
		expect(6).not.toEqual('6');
toBe

Tests equality between objects. Some examples:

		var one = {'name' : 'John'};
		var other = {'name' : 'John'};
		var another = one;
		var oneArray = [42, 15, 69];
		var otherArray = [42, 15, 69];
		var anotherArray = [6, 66, 666];

		expect(6).toBe(6);
		expect(6).not.toBe('6');
		expect(6).toBe(6.0);
		expect(one).toBe(another);
		expect(oneArray).not.toBe(otherArray);
		expect(one).not.toBe(other);
toContain

Checks if an element of a string or of an array is present. Some examples:

		var phrase = 'By demon be driven';

		expect(oneArray).toContain(42);
		expect(phrase).toContain('demon');
toBeTruthy

Checks if what we expect is true. Some examples:

		expect(true).toBeTruthy();
		expect(1).toBeTruthy();
		expect('Metallica').toBeTruthy();
		expect(66).toBeTruthy(); // anything but 0
toBeFalsy

Checks if what we expect is false. Some examples:

		var phrase = 'By demon be driven';

		expect(false).toBeFalsy();
		expect(0).toBeFalsy();
		expect('').toBeFalsy();
		expect(null).toBeFalsy();
		expect(undefined).toBeFalsy();
		expect(NaN).toBeFalsy();
		expect(true).not.toBeFalsy();
		expect(phrase).not.toBeFalsy();
toBeNull

Checks if something is null. Some examples:

		expect(null).toBeNull();
		expect('').not.toBeNull();
		expect([]).not.toBeNull();
toBeNaN

Checks if we have anything but a number. Some examples:

		var phrase = 'By demon be driven';

		expect(NaN).toBeNaN();
		expect(parseInt('One')).toBeNaN();
		expect(parseInt('666')).not.toBeNaN();
		expect(phrase).not.toBeNaN();
		expect(6).not.toBeNaN();
toBeDefined

Checks if a variable is defined. Some examples:

		var unnamed;
		var god = 'Cthulhu';
		var anotherGod = god;
		expect(god).toBeDefined();
		expect(another).toBeDefined();
		expect(666).toBeDefined();
		expect(true).toBeDefined();
		expect(null).toBeDefined(); // yes, it is
		expect(unnamed).not.toBeDefined();
toBeUndefined

Checks if a variable is not defined Some examples:

		var unnamable;
		var unnamed;
		expect(unnamable).toBeUndefined();
		expect(unnamed).toBeUndefined();
		expect(null).not.toBeUndefined();
		// This would throw Reference Error
		//expect(notDeclaredVar).toBeUndefined();
toBeGreaterThan

Checks if the value, integer or String is greater than other. Some examples:

		expect(6).toBeGreaterThan(5);
		expect('b').toBeGreaterThan('a');
		expect(6).not.toBeGreaterThan('6');
toBeLessThan

Checks if the value is lesser. Some examples:

		expect(5).toBeLessThan(6);
		expect(-5.1).toBeLessThan(-5.0);
		expect('a').toBeLessThan('b');
toBeCloseTo

Checks if a value is closed to another providing certain precision. When the precision is 0 it parses the number to Int. Some examples:

		expect(66.64).toBeCloseTo(66.62,1);
		expect(66.64).toBeCloseTo(67,0);
		expect(42.44).toBeCloseTo(42,0);
		expect(42.59).toBeCloseTo(43,0);
		expect(Math.PI).toBeCloseTo(3.14,2);
		expect(Math.PI).toBeCloseTo(3,0);
toMatch

This is great, we can check if the value matches a regular expression. Some examples:

		expect('Thorin Kili Gloin').toMatch(/gloin/i);
		expect('Jasmine').toMatch(/[a-z]+/i);
		expect('Jasmine and Eugene').not.toMatch(/^[a-z]+$/gi);
		expect('Jasmine and Eugene').toMatch(/^[a-z\s]+$/gi);
toThrow

As explained before, checks if an Error is thrown.

We'll try with this dumb function:
		var vomitError = function () {
			throw new Error('I puke errors');
		};

	it('checks toThrow',function () {
		expect(vomitError).toThrow();
	});
Creating our own matchers

Maybe you need a more specific matcher to be able to test something that Jasmine's default matchers are not capable of. Well, you can define your own matchers. Inside the describe block we can define our own matcher, in this case is one matcher to test if a String is complex enough to be a secure password.

	/**
	* customMatcher
	* toBeComplex
	* checks if a String contains alphanumeric and symbols
	* and a min lenght of 8
	*/
	beforeEach(function() {
		this.addMatchers({
			toBeComplex: function() {
				this.message = function() {
					return "Expected " + this.actual + " to be complex";
				};
					return this.actual.match(/[a-z]{1,}/) 
						&& this.actual.match(/[A-Z]{1,}/)
						&& this.actual.match(/[0-9]{1,}/)
						&& this.actual.match(/[\.\,\;\:\-\!\?\_]{1,}/)
						&& (this.actual.length>7);
			}
		});

	});

And now we can use our tester just like the others:

	// toBeComplex
	// Checks if a String is valid to be a password
	it('checks toBeComplex',function () {
		expect('Death-666').toBeComplex();
		expect('.-;.:,!?').not.toBeComplex();
		expect('Death66').not.toBeComplex();
		expect('josua').not.toBeComplex();
	});

'josua' has always been a very bad password.

If you need params in this matcher is quite easy to add them. We define a slightly different matcher now adding the minimun length.

			toBeComplexAndLongerThan: function(length) {
				this.message = function() {
					return "Expected " + this.actual + " to be complex and longer than " + length;
				};
					return this.actual.match(/[a-z]{1,}/) 
						&& this.actual.match(/[A-Z]{1,}/)
						&& this.actual.match(/[0-9]{1,}/)
						&& this.actual.match(/[\.\,\;\:\-\!\?\_]{1,}/)
						&& (this.actual.length>length);
			}

Now we test it:

		expect('Josua:It666').toBeComplexAndLongerThan(10);
Spies, spies everywhere

Matches are fine to check if our functions are returning what are expected to. But, how could we be sure that certain functions are being called? Jasmine as many other tools brings us the possibility to introuce the so called spies. By the way I introduce the use of setup/teardown like methods in Jasmine: beforeEach and afterEach.

First I'll show how to use the spies in a very simple problem, and after that we'll move to test a tcp server with async calls.

stringutils: this is a simple class with some methods to do simple stuff with strings.

/**
* stringutils.js
* Some String utils 
*/
exports.StringUtils = function () {

		this.len = function (string) {
			return string.length;
		};

		this.vowels = function (string) {
			var totalVowels = 0;

			for (var i = 0; i< this.len(string);i++) {
				if (string[i].match(/^[aeiou]{1}$/i)) {
					totalVowels++;
				}
			}

			return totalVowels;
		};

		this.reverse = function (string) {
			var gnirts = '';
			for (var i = this.len(string) -1;i>=0 ;i--) {
				gnirts += string[i];
			}

			return gnirts;
		}
};

Ok, I'm afraid that I'll not get rich with this, but should be enough to apply simple spies on it in this spec below:

var stringutils = require("../stringutils.js");

// testing hello function
describe("testing stringutils", function() {

	var myStringUtils;

	beforeEach(function() {
		myStringUtils = new stringutils.StringUtils();			
		spyOn(myStringUtils,'len');
		spyOn(myStringUtils,'vowels');
		spyOn(myStringUtils,'reverse');

		myStringUtils.len('Eugene');
		myStringUtils.vowels('Eugene');
		myStringUtils.reverse('Eugene');
    });

	it('calls len function',function () {
		expect(myStringUtils.len).toHaveBeenCalled();
		expect(myStringUtils.len).toHaveBeenCalledWith('Eugene');
	});

	it('calls vowels function',function () {
		expect(myStringUtils.vowels).toHaveBeenCalled();
		expect(myStringUtils.vowels).toHaveBeenCalledWith('Eugene');
	});


	it('calls reverse function',function () {
		expect(myStringUtils.reverse).toHaveBeenCalled();
		expect(myStringUtils.reverse).toHaveBeenCalledWith('Eugene');
	});

	afterEach(function () {

	});

});

To set spies, we have to call spyOn method. Then we can check if any method has been called and even we can test if they where called with certain parameters.

  • toHaveBeenCalled()
  • toHaveBeenCalledWith(something)

We could chain some of these to make the function behave as we want:

  • andCallFake: instead of call
  • andCallThrough(): calls the original functions that spyOn is faking
  • andReturn(arguments): show as the parameters when the spied function is called
  • andThrows(exception): throws an exception when the function is called
Another sample, a tcp server

Now let's try harder with a simple node tcp echo server. This is the server

/**
* echoserver.js
* Simple sample echo server writen in nodejs
* Pello Altadill
*/
var net = require('net');

exports.EchoServer = function (port, host) {

	var self = this;
	this.port = port || 1666;
	this.host = host || '0.0.0.0';
	this.server = net.createServer();
	this.timeout = 5000; // 5 secs
	this.keepAlive = true;
	this.keepAliveTime = this.timeout;
	this.clientSockets = [];

	this.init = function () {
		this.server.listen(this.port, this.host);
	};

	this.listening = function() {
		console.log('Server> Server listening on port ' + port);
	};

	this.connection = function(socket) {
		self.clientSockets.push(socket);
		console.log('Server> Connected to server, total clients: ' + self.clientSockets.length);
		
		// console.log(socket);
		if (this.keepAlive) {
			socket.setKeepAlive(this.keepAliveTime);
		} else {
			socket.setTimeout(this.timeout);
		}

		socket.on('timeout', function () {
			console.log('Server> timeout');
			socket.end();
		});

		socket.on('data', function (msg) {
			console.log('Server> Received data ' + msg);
			console.log('Server> Sending it back');
			socket.write(msg);
		});

		socket.on('close', function () {
			console.log('Server> Socket closed');
			var index = self.clientSockets.indexOf(socket);
			self.clientSockets.splice(index, 1);
		});
	};

	this.close = function(err) {
		console.log('Server> Connection closed ' + err);
	};

	this.error = function(err) {
		console.log('Server> Error on server ' + err);
	};
	
	this.close = function () {
		this.server.close();
		this.server.unref();
	};
	
	this.server.on('listening',this.listening);

	this.server.on('connection', this.connection); 

	this.server.on('close', this.close);

	this.server.on('error', this.error);

};

And this is a way to test some behaviours of the server

var server = require("../echoserver.js");
var net = require('net');
var myServer;

// testing hello function
describe("server", function() {

	var successCallBack;

	 beforeEach(function() {
  	
		successCallBack = jasmine.createSpy();

		myServer = new server.EchoServer(1666,'0.0.0.0');
		spyOn(myServer, 'init').andCallThrough();
		spyOn(myServer.server, 'listen').andCallThrough();
		spyOn(myServer, 'connection').andCallThrough();
		myServer.init();
			
    });

	it('Check server port', function() {
		expect(myServer.port).toEqual(1666);
	});

	it('Check server host', function() {
		expect(myServer.host).toEqual('0.0.0.0');
	});

	it('Check server init was called', function() {
		expect(myServer.init).toHaveBeenCalled();
	});

	it('Check server listen was called', function() {
		expect(myServer.server.listen).toHaveBeenCalled();
	});
	
	it('Check server connection was called', function() {
		var client = net.connect({ port: 1666 },
            	function() {
               		client.write('Eat this madafaka!');
            	}, successCallBack);

		waitsFor(function() {
			console.log('Waiting here: ' + successCallBack.callCount );
			return successCallBack.callCount > 0;
		}, "operation never completed", 10000);

		runs(function() {
			expect(successCallBack).toHaveBeenCalled();
		});

	});

	it('checks that server responds the same ', function(done) {
			var client = net.connect({ port: 1666 });
			client.write('hello there');
	 		client.on('data', function(data){
	 			console.log(data.toString());
    			expect(data.toString()).toBe('hello there');
    			done();
  			});

	});

	 afterEach(function() {
    });
});

The last test is testing the result of an asynchronous call and it needs to use done() callback. This is valid for Jasmine >= 2.0 versions now. Maybe you've read something about run/waitFor but now this seems to be the official way to do this.

Some references:
  • Jasmine introduction: http://jasmine.github.io/2.0/introduction.html
  • Jasmine wiki: https://github.com/pivotal/jasmine/wiki/Spies
  • Intro about Jasmine, web focused
  • Javascript Unit Testing, by Hazem Saleh PACKT
  • Javascript Testing with Jasmine, by OREILLY
]]>
A night out with Jasmine

Unit testing is much more than a tool for ensuring that a program behaves as expected. Nowadays it's the key for new development techniques such as TDD and BDD in which you begin writing tests before the required code. It's all about requirements and behaviour; developers must focus on understanding the requirements instead of thinking about the way they implement the code. In the event that you've forgotten the fundamental benefits of unit testing here you have a quick reminder:

  • Obviously, you are testing that your code works
  • When changes are made you can automatically verify that everything works
  • Tests are a pretty good way to document the project.

Jasmine is a BDD framework for javascript code. In a nutshell, BDD it's an evolution of TDD where unit tests look like user stories, and so tests are defined in the same terms of the expected behaviour of the software units. When you discover functions names in Jasmine tests these simple definitions will make more sense.

Let's get our hands dirty, while you take a look at Jasmine's site http://jasmine.github.io/2.0/introduction.html you can get the master from the github site https://github.com/pivotal/jasmine/archive/master.zip

Or, if you are using node then just sigh, coff slightly, adjust your spectacles and simply try with this: npm -g install jasmine-node

Beware! at the time of writing this Jasmine is in 2.0 version and there are some changes and deprecated functions. So, be careful with what you read out there, check dates.

Ok, once jasmine is installed let's write this piece of code in a file called hello.js

exports.hello = function () {
	return 'Hello world';
};

Behold the almighty helloworld sample.

With Jasmine, the test file is expected to live in a dir called specs in a file called name.spec.js, so hello.spec.js in this case.

And this is what the test would look like:

/*
* specs/hello.spec.js
*/
var hl = require("../hello.js");

// testing hello function
describe("hello", function() {
	it('returns "Hello world"', function() {
		expect(hl.hello()).toEqual("Hello world");
	});
});

To run the test, in the same directory where hello.js resides we type jasmine-node command with the dir of the test and it will pass all specs files within


linux$ jasmine-node specs/
.

Finished in 0.020 seconds
1 tests, 1 assertions, 0 failures, 0 skipped
linux$ 

¿How could we test functions that are using a callback? In the same hello.js file we add this function:


exports.helloAsync = function (callback) {
	return callback(null,'Async Hello World');
};

And this is how the test should look like:

describe("helloAsync", function() {
	it("does an asynchronous call", function() {
		hl.helloAsync(function(err,response) {
			expect(response).toContain("Async Hello World");
		});
	});
});

Now if we run the test, we will check 2 test and 2 assertions:

linux$ jasmine-node specs/
..

Finished in 0.029 seconds
2 tests, 2 assertions, 0 failures, 0 skipped
linux$ 

Maybe you've noticed that in the second test instead of toEqual we're using .toContain. These are different matchers with different effects as indicated by their obvious names. As you can see, Jasmine drives us to write tests that apart from being 'extracool' can be read as natural language.

Developing a simply utility, TDD style

Our beloved system administrator wants a program to convert people names such as "john, doe" into account names like "john_doe". Remember, we are trying TDD now so focus on the requirement, and try not to think about using regular expressions or any kind of implementation details. TDD dictates to follow this steps:

  1. Write the test code
  2. Pass the test and see how it fails
  3. Write just the necessary code, quick and dirty, to turn the test from red to green
  4. Once the test is passed successfuly, refactor the code.
  5. Feel kwel, you earned a good cup of whatever

Ok, we create a specs dir, and inside a username.spec.js file containing our test of a code that right now it is but a ghost:


var username = require('../username.js');

describe('Test to ensure username is created', function () {
	it('returns name_surname with simple Name,Surname',function () {
		expect(username.create('john,doe')).toEqual('john_doe');
	});

});

Not only if we test this fails, but also if we run it this code FAILS. why? username.js does not exist, as simply as that. Well then, time for step 2 in TDD, we write our code in a file named username.js one dir level below.

/**
* username.js
* Pello Altadill Izura
* http://pello.info
*/

exports.create = function (personName) {
	var result = '';
	var parts = personName.split(',');
	result = parts[0] + '_' + parts[1];

	return result;
};

Now what we get is what we expected to:

linux$ jasmine-node specs/
.

Finished in 0.033 seconds
1 test, 1 assertion, 0 failures, 0 skipped

linux$

The requirements were minimal in order to show the process of TDD. But the world is not a pleasant place where everything just works fine. As Melissandre said, there is one hell, the one we are living in now. This could be a more realistic problem, which might be more useful to ilustrate some other Jasmine features.

Our Benevolent Dictator thinks that we deserve the honor to raise from the mud in which we creep and serve him with our bare hands, although we are not worthy of such a gift from a demigod. We want to get on well with OBD if we want him to lower the proxy constraints for us among other mundane privileges. He is in a need for a program that translates people names to system names with this specifications:

  • People names come with Name, Surname notation and they may be translated to name_surname
  • Names can come in either lower or uppercase
  • Names can come with extra spaces
  • Some people may have two names like 'John John, Kennedy' or 'Jar Jar, Binks' and they might be translated to name1name2_surname
  • Some names can be null or empty spaces ','. (That may be OBD's fault but It's better not to mention it)

We'll try to acomplish these specs, so our unit tests might look like this in Jasmine style:


var username = require('../username.js');

describe('Test to ensure username is created', function () {
	it('returns name_surname with simple Name,Surname',function () {
		expect(username.create('john,doe')).toEqual('john_doe');
	});

	it('converts any uppercase character to lowercase', function () {
		expect(username.create('Han,Solo')).toEqual('han_solo');
	});

	it('removes any space character', function () {
		expect(username.create('   Luke, Skywalker ')).toEqual('luke_skywalker');
	});

	it('returns multiple names together', function () {
		expect(username.create('Obi Wan,Kenobi')).toEqual('obiwan_kenobi');
	});

	it('throws error if name is empty', function () {
		expect(function() { 
					username.create(''); 
			   }).toThrow('Person name is empty');
	});
});

If we test all of this with our previous code Jasmine will scream our name:

linux$ jasmine-node specs/
.FFFF

Failures:

  1) Test to ensure username is created converts any uppercase character to lowercase
   Message:
     Expected 'Han_Solo' to equal 'han_solo'.
   Stacktrace:
     Error: Expected 'Han_Solo' to equal 'han_solo'.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:9:39)

  2) Test to ensure username is created removes any space character
   Message:
     Expected '   Luke_ Skywalker ' to equal 'luke_skywalker'.
   Stacktrace:
     Error: Expected '   Luke_ Skywalker ' to equal 'luke_skywalker'.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:13:50)

  3) Test to ensure username is created returns multiple names together
   Message:
     Expected 'Obi Wan_Kenobi' to equal 'obiwan_kenobi'.
   Stacktrace:
     Error: Expected 'Obi Wan_Kenobi' to equal 'obiwan_kenobi'.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:17:45)

  4) Test to ensure username is created returns empty string with spaces
   Message:
     Expected '_undefined' to equal ''.
   Stacktrace:
     Error: Expected '_undefined' to equal ''.
    at null. (/root/nodejs/jasmine/users/specs/username.spec.js:21:31)

Finished in 0.061 seconds
5 tests, 5 assertions, 4 failures, 0 skipped

Let's fix each of the tests


/**
* username.js
* Pello Altadill Izura
* http://pello.info
*/

exports.create = function (personName) {
	var result = '';
	personName = personName.toLowerCase();
	personName = personName.replace(/\s/g,'');
	if (personName == '' ) {
		throw new Error('Person name is empty');
	}
	var parts = personName.split(',');
	result = parts[0] + '_' + parts[1];

	return result;
};

The \s replacement fixes many things. And now we throw an Error whenever a personName comes empty. Maybe this is not the preferred behaviour of our program, but It helps to show how to check if exceptions are thrown.

Jasmine matchers at a glance

We have already used .toEqual(), .toContain() and .toThrow(), but if you're familiar with unit testing you might expect many others to exist. So instead of blowing your mind with poor-man's wordgames, let's see what we have inside Jasmine's toolbox.

Negate matching

at any moment we can reverse the matcher using a not like this

expect(666).not.toEqual(333);
toEqual

Tests equality with primitive types: numbers, strings, booleans, null. But NOT with objects. Some examples:

		var one = {'name' : 'John'};
		var other = {'name' : 'John'};
		var another = one;
		var oneArray = [42, 15, 69];
		var otherArray = [42, 15, 69];
		var anotherArray = [6, 66, 666];
		var phrase = 'By demon be driven';


		expect(6).toEqual(6);
		expect(6).toEqual(6.0);
		expect(one).toEqual(other);
		expect(oneArray).toEqual(otherArray);
		expect(6).not.toEqual('6');
toBe

Tests equality between objects. Some examples:

		var one = {'name' : 'John'};
		var other = {'name' : 'John'};
		var another = one;
		var oneArray = [42, 15, 69];
		var otherArray = [42, 15, 69];
		var anotherArray = [6, 66, 666];

		expect(6).toBe(6);
		expect(6).not.toBe('6');
		expect(6).toBe(6.0);
		expect(one).toBe(another);
		expect(oneArray).not.toBe(otherArray);
		expect(one).not.toBe(other);
toContain

Checks if an element of a string or of an array is present. Some examples:

		var phrase = 'By demon be driven';

		expect(oneArray).toContain(42);
		expect(phrase).toContain('demon');
toBeTruthy

Checks if what we expect is true. Some examples:

		expect(true).toBeTruthy();
		expect(1).toBeTruthy();
		expect('Metallica').toBeTruthy();
		expect(66).toBeTruthy(); // anything but 0
toBeFalsy

Checks if what we expect is false. Some examples:

		var phrase = 'By demon be driven';

		expect(false).toBeFalsy();
		expect(0).toBeFalsy();
		expect('').toBeFalsy();
		expect(null).toBeFalsy();
		expect(undefined).toBeFalsy();
		expect(NaN).toBeFalsy();
		expect(true).not.toBeFalsy();
		expect(phrase).not.toBeFalsy();
toBeNull

Checks if something is null. Some examples:

		expect(null).toBeNull();
		expect('').not.toBeNull();
		expect([]).not.toBeNull();
toBeNaN

Checks if we have anything but a number. Some examples:

		var phrase = 'By demon be driven';

		expect(NaN).toBeNaN();
		expect(parseInt('One')).toBeNaN();
		expect(parseInt('666')).not.toBeNaN();
		expect(phrase).not.toBeNaN();
		expect(6).not.toBeNaN();
toBeDefined

Checks if a variable is defined. Some examples:

		var unnamed;
		var god = 'Cthulhu';
		var anotherGod = god;
		expect(god).toBeDefined();
		expect(another).toBeDefined();
		expect(666).toBeDefined();
		expect(true).toBeDefined();
		expect(null).toBeDefined(); // yes, it is
		expect(unnamed).not.toBeDefined();
toBeUndefined

Checks if a variable is not defined Some examples:

		var unnamable;
		var unnamed;
		expect(unnamable).toBeUndefined();
		expect(unnamed).toBeUndefined();
		expect(null).not.toBeUndefined();
		// This would throw Reference Error
		//expect(notDeclaredVar).toBeUndefined();
toBeGreaterThan

Checks if the value, integer or String is greater than other. Some examples:

		expect(6).toBeGreaterThan(5);
		expect('b').toBeGreaterThan('a');
		expect(6).not.toBeGreaterThan('6');
toBeLessThan

Checks if the value is lesser. Some examples:

		expect(5).toBeLessThan(6);
		expect(-5.1).toBeLessThan(-5.0);
		expect('a').toBeLessThan('b');
toBeCloseTo

Checks if a value is closed to another providing certain precision. When the precision is 0 it parses the number to Int. Some examples:

		expect(66.64).toBeCloseTo(66.62,1);
		expect(66.64).toBeCloseTo(67,0);
		expect(42.44).toBeCloseTo(42,0);
		expect(42.59).toBeCloseTo(43,0);
		expect(Math.PI).toBeCloseTo(3.14,2);
		expect(Math.PI).toBeCloseTo(3,0);
toMatch

This is great, we can check if the value matches a regular expression. Some examples:

		expect('Thorin Kili Gloin').toMatch(/gloin/i);
		expect('Jasmine').toMatch(/[a-z]+/i);
		expect('Jasmine and Eugene').not.toMatch(/^[a-z]+$/gi);
		expect('Jasmine and Eugene').toMatch(/^[a-z\s]+$/gi);
toThrow

As explained before, checks if an Error is thrown.

We'll try with this dumb function:
		var vomitError = function () {
			throw new Error('I puke errors');
		};

	it('checks toThrow',function () {
		expect(vomitError).toThrow();
	});
Creating our own matchers

Maybe you need a more specific matcher to be able to test something that Jasmine's default matchers are not capable of. Well, you can define your own matchers. Inside the describe block we can define our own matcher, in this case is one matcher to test if a String is complex enough to be a secure password.

	/**
	* customMatcher
	* toBeComplex
	* checks if a String contains alphanumeric and symbols
	* and a min lenght of 8
	*/
	beforeEach(function() {
		this.addMatchers({
			toBeComplex: function() {
				this.message = function() {
					return "Expected " + this.actual + " to be complex";
				};
					return this.actual.match(/[a-z]{1,}/) 
						&& this.actual.match(/[A-Z]{1,}/)
						&& this.actual.match(/[0-9]{1,}/)
						&& this.actual.match(/[\.\,\;\:\-\!\?\_]{1,}/)
						&& (this.actual.length>7);
			}
		});

	});

And now we can use our tester just like the others:

	// toBeComplex
	// Checks if a String is valid to be a password
	it('checks toBeComplex',function () {
		expect('Death-666').toBeComplex();
		expect('.-;.:,!?').not.toBeComplex();
		expect('Death66').not.toBeComplex();
		expect('josua').not.toBeComplex();
	});

'josua' has always been a very bad password.

If you need params in this matcher is quite easy to add them. We define a slightly different matcher now adding the minimun length.

			toBeComplexAndLongerThan: function(length) {
				this.message = function() {
					return "Expected " + this.actual + " to be complex and longer than " + length;
				};
					return this.actual.match(/[a-z]{1,}/) 
						&& this.actual.match(/[A-Z]{1,}/)
						&& this.actual.match(/[0-9]{1,}/)
						&& this.actual.match(/[\.\,\;\:\-\!\?\_]{1,}/)
						&& (this.actual.length>length);
			}

Now we test it:

		expect('Josua:It666').toBeComplexAndLongerThan(10);
Spies, spies everywhere

Matches are fine to check if our functions are returning what are expected to. But, how could we be sure that certain functions are being called? Jasmine as many other tools brings us the possibility to introuce the so called spies. By the way I introduce the use of setup/teardown like methods in Jasmine: beforeEach and afterEach.

First I'll show how to use the spies in a very simple problem, and after that we'll move to test a tcp server with async calls.

stringutils: this is a simple class with some methods to do simple stuff with strings.

/**
* stringutils.js
* Some String utils 
*/
exports.StringUtils = function () {

		this.len = function (string) {
			return string.length;
		};

		this.vowels = function (string) {
			var totalVowels = 0;

			for (var i = 0; i< this.len(string);i++) {
				if (string[i].match(/^[aeiou]{1}$/i)) {
					totalVowels++;
				}
			}

			return totalVowels;
		};

		this.reverse = function (string) {
			var gnirts = '';
			for (var i = this.len(string) -1;i>=0 ;i--) {
				gnirts += string[i];
			}

			return gnirts;
		}
};

Ok, I'm afraid that I'll not get rich with this, but should be enough to apply simple spies on it in this spec below:

var stringutils = require("../stringutils.js");

// testing hello function
describe("testing stringutils", function() {

	var myStringUtils;

	beforeEach(function() {
		myStringUtils = new stringutils.StringUtils();			
		spyOn(myStringUtils,'len');
		spyOn(myStringUtils,'vowels');
		spyOn(myStringUtils,'reverse');

		myStringUtils.len('Eugene');
		myStringUtils.vowels('Eugene');
		myStringUtils.reverse('Eugene');
    });

	it('calls len function',function () {
		expect(myStringUtils.len).toHaveBeenCalled();
		expect(myStringUtils.len).toHaveBeenCalledWith('Eugene');
	});

	it('calls vowels function',function () {
		expect(myStringUtils.vowels).toHaveBeenCalled();
		expect(myStringUtils.vowels).toHaveBeenCalledWith('Eugene');
	});


	it('calls reverse function',function () {
		expect(myStringUtils.reverse).toHaveBeenCalled();
		expect(myStringUtils.reverse).toHaveBeenCalledWith('Eugene');
	});

	afterEach(function () {

	});

});

To set spies, we have to call spyOn method. Then we can check if any method has been called and even we can test if they where called with certain parameters.

  • toHaveBeenCalled()
  • toHaveBeenCalledWith(something)

We could chain some of these to make the function behave as we want:

  • andCallFake: instead of call
  • andCallThrough(): calls the original functions that spyOn is faking
  • andReturn(arguments): show as the parameters when the spied function is called
  • andThrows(exception): throws an exception when the function is called
Another sample, a tcp server

Now let's try harder with a simple node tcp echo server. This is the server

/**
* echoserver.js
* Simple sample echo server writen in nodejs
* Pello Altadill
*/
var net = require('net');

exports.EchoServer = function (port, host) {

	var self = this;
	this.port = port || 1666;
	this.host = host || '0.0.0.0';
	this.server = net.createServer();
	this.timeout = 5000; // 5 secs
	this.keepAlive = true;
	this.keepAliveTime = this.timeout;
	this.clientSockets = [];

	this.init = function () {
		this.server.listen(this.port, this.host);
	};

	this.listening = function() {
		console.log('Server> Server listening on port ' + port);
	};

	this.connection = function(socket) {
		self.clientSockets.push(socket);
		console.log('Server> Connected to server, total clients: ' + self.clientSockets.length);
		
		// console.log(socket);
		if (this.keepAlive) {
			socket.setKeepAlive(this.keepAliveTime);
		} else {
			socket.setTimeout(this.timeout);
		}

		socket.on('timeout', function () {
			console.log('Server> timeout');
			socket.end();
		});

		socket.on('data', function (msg) {
			console.log('Server> Received data ' + msg);
			console.log('Server> Sending it back');
			socket.write(msg);
		});

		socket.on('close', function () {
			console.log('Server> Socket closed');
			var index = self.clientSockets.indexOf(socket);
			self.clientSockets.splice(index, 1);
		});
	};

	this.close = function(err) {
		console.log('Server> Connection closed ' + err);
	};

	this.error = function(err) {
		console.log('Server> Error on server ' + err);
	};
	
	this.close = function () {
		this.server.close();
		this.server.unref();
	};
	
	this.server.on('listening',this.listening);

	this.server.on('connection', this.connection); 

	this.server.on('close', this.close);

	this.server.on('error', this.error);

};

And this is a way to test some behaviours of the server

var server = require("../echoserver.js");
var net = require('net');
var myServer;

// testing hello function
describe("server", function() {

	var successCallBack;

	 beforeEach(function() {
  	
		successCallBack = jasmine.createSpy();

		myServer = new server.EchoServer(1666,'0.0.0.0');
		spyOn(myServer, 'init').andCallThrough();
		spyOn(myServer.server, 'listen').andCallThrough();
		spyOn(myServer, 'connection').andCallThrough();
		myServer.init();
			
    });

	it('Check server port', function() {
		expect(myServer.port).toEqual(1666);
	});

	it('Check server host', function() {
		expect(myServer.host).toEqual('0.0.0.0');
	});

	it('Check server init was called', function() {
		expect(myServer.init).toHaveBeenCalled();
	});

	it('Check server listen was called', function() {
		expect(myServer.server.listen).toHaveBeenCalled();
	});
	
	it('Check server connection was called', function() {
		var client = net.connect({ port: 1666 },
            	function() {
               		client.write('Eat this madafaka!');
            	}, successCallBack);

		waitsFor(function() {
			console.log('Waiting here: ' + successCallBack.callCount );
			return successCallBack.callCount > 0;
		}, "operation never completed", 10000);

		runs(function() {
			expect(successCallBack).toHaveBeenCalled();
		});

	});

	it('checks that server responds the same ', function(done) {
			var client = net.connect({ port: 1666 });
			client.write('hello there');
	 		client.on('data', function(data){
	 			console.log(data.toString());
    			expect(data.toString()).toBe('hello there');
    			done();
  			});

	});

	 afterEach(function() {
    });
});

The last test is testing the result of an asynchronous call and it needs to use done() callback. This is valid for Jasmine >= 2.0 versions now. Maybe you've read something about run/waitFor but now this seems to be the official way to do this.

Some references:
  • Jasmine introduction: http://jasmine.github.io/2.0/introduction.html
  • Jasmine wiki: https://github.com/pivotal/jasmine/wiki/Spies
  • Intro about Jasmine, web focused
  • Javascript Unit Testing, by Hazem Saleh PACKT
  • Javascript Testing with Jasmine, by OREILLY
]]>
http://www.pello.info/index.php/blog/a-night-out-with-jasmine
Arkapong http://www.pello.info/index.php/blog/arkapong http://www.pello.info/index.php/blog/arkapong 2014-04-07 07:35:33 pelloxabier http://www.pello.info/index.php/blog/arkapong

This a classic pong-like game that takes some ideas from Arkanoid. Basically two paddles try to hit the ball until one of them fails but, from time to time the rules can change if special bricks are touched.

  • Red: invert ball direction
  • White: triple ball
  • Yellow: smaller paddles
  • Blue: bigger paddles
  • Green: speed up ball
  • Orange: change ball up-down direction
  • Brown: minimize paddles
  • Pink: move paddles randomly

For one or two players, much more fun if you play it against someone else, the game is controlled with your fingers. You can set your preferred ball speed using the preferences screen.

There is another Arkapong out there, not released yet but It looks very interesting. It's a similar concept but this one is more based on Arkanoid

]]>

This a classic pong-like game that takes some ideas from Arkanoid. Basically two paddles try to hit the ball until one of them fails but, from time to time the rules can change if special bricks are touched.

  • Red: invert ball direction
  • White: triple ball
  • Yellow: smaller paddles
  • Blue: bigger paddles
  • Green: speed up ball
  • Orange: change ball up-down direction
  • Brown: minimize paddles
  • Pink: move paddles randomly

For one or two players, much more fun if you play it against someone else, the game is controlled with your fingers. You can set your preferred ball speed using the preferences screen.

There is another Arkapong out there, not released yet but It looks very interesting. It's a similar concept but this one is more based on Arkanoid

]]>
http://www.pello.info/index.php/blog/arkapong
Getting started with Node http://www.pello.info/index.php/blog/getting-started-with-node http://www.pello.info/index.php/blog/getting-started-with-node 2014-03-17 23:48:44 pelloxabier http://www.pello.info/index.php/blog/getting-started-with-node

Few days ago, a very dear friend of mine came up to my place with a present. It was a nodejs book. This is a new or maybe it would be more accurate to say an emergent technology which brings back an old idea that I used to hear of long time ago: a server side javascript. That was something that was supposed to exist somewhere, as it was mentioned in the prefaces of many javascript related papers: “javascript runs on the browser but there is also a server side…” for me it was just a sort of legend, without any proof of real existence or running implementation. Around 2009 Ryan Dahl, based on google chrome’s V8 javascript engine, started developing a server side platform to run javascript code. NodeJS environment, basically, lead us to event-driven programming, nonblocking I/O and function callbacks.

The core of NodeJS (or simply Node) is a very simplified base where you can build your applications. But you don’t need to develop everything from scratch, Node coders are a pretty active community that already has thousands of modules of all kinds covering every aspect you can think of.

If you want to start coding and running Node programs right now you can download it from their website. In the event that you feel the need for further explanation to install Node on your computer, do yourself a favor and don’t keep on trying. I’m serious here. Stay away from any computer, run away to the countryside, pick up berries, talk to birds and you’ll live happily ever after.

¿What kind of tools can be used for node? from console based to modern IDEs. Vim, Sublime or other simple editors for example. For debugging purposes your chrome browser can be attached to a node program. Also you can use Eclipse based Nodeclipse or a nonfree IDEs like WebStorm

Last summer I played around with Node, testing callbacks, event emitters, express, MongoDB drivers, among other things... From now on I’ll try to follow this book and write stuff about Node on a regular basis. Hope that you enjoy the ride.

]]>

Few days ago, a very dear friend of mine came up to my place with a present. It was a nodejs book. This is a new or maybe it would be more accurate to say an emergent technology which brings back an old idea that I used to hear of long time ago: a server side javascript. That was something that was supposed to exist somewhere, as it was mentioned in the prefaces of many javascript related papers: “javascript runs on the browser but there is also a server side…” for me it was just a sort of legend, without any proof of real existence or running implementation. Around 2009 Ryan Dahl, based on google chrome’s V8 javascript engine, started developing a server side platform to run javascript code. NodeJS environment, basically, lead us to event-driven programming, nonblocking I/O and function callbacks.

The core of NodeJS (or simply Node) is a very simplified base where you can build your applications. But you don’t need to develop everything from scratch, Node coders are a pretty active community that already has thousands of modules of all kinds covering every aspect you can think of.

If you want to start coding and running Node programs right now you can download it from their website. In the event that you feel the need for further explanation to install Node on your computer, do yourself a favor and don’t keep on trying. I’m serious here. Stay away from any computer, run away to the countryside, pick up berries, talk to birds and you’ll live happily ever after.

¿What kind of tools can be used for node? from console based to modern IDEs. Vim, Sublime or other simple editors for example. For debugging purposes your chrome browser can be attached to a node program. Also you can use Eclipse based Nodeclipse or a nonfree IDEs like WebStorm

Last summer I played around with Node, testing callbacks, event emitters, express, MongoDB drivers, among other things... From now on I’ll try to follow this book and write stuff about Node on a regular basis. Hope that you enjoy the ride.

]]>
http://www.pello.info/index.php/blog/getting-started-with-node
Calcular el IBAN con php http://www.pello.info/index.php/blog/calcular-el-iban-con-php http://www.pello.info/index.php/blog/calcular-el-iban-con-php 2014-01-18 00:01:21 pelloxabier http://www.pello.info/index.php/blog/calcular-el-iban-con-php Los organismos internaciones se han vuelto a poner de acuerdo para poner unificar los números de cuenta y gracias a ello todos los programadores y DBAs del mundo ya estamos enfrascados en la tarea de adaptar programas, validaciones, campos de las BBDD y un largo etcétera.

En cada país el código de cuenta corriente puede variar y a través del IBAN se intenta unificar la forma de esa cuenta de tal forma que sea validable. Este artículo de la wikipedia lo explica bastante bien, incluyendo los pasos tanto para generar un IBAN a partir de una CC como para validarlo

Hay una pequeña pega, la validación exige una operación mod sobre un número tan grande que es probable que muchos lenguajes no puedan llevarla a cabo. En la red existen ya muchas soluciones, esta es una. Ojo, aparte de que este ejemplo solo se ha probado con cuentas en el formato de 20 dígitos esto no ha sido más que una diversión. Tienes implementaciones mejores como php-iban

NOTA:Para evitar problemas con el copy paste o posibles fallos con algún caracter, puedes descargarte esto del repositorio de git

<?php
/**
* Iban
* Simple utility class to generate and validate IBAN account numbers
* Based on http://www.lawebdelprogramador.com/foros/Visual_Basic/1409866-Calculo_IBAN.html
* @author Pello Xabier Altadill Izura
* @version    $Id:$
* @link       http://www.pello.info
* @since      Available since 2014-01-17
* @greetz	Iban (Zabalza)
*  ... and you too
*/

class Iban {
   
   private static $LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	private static $COUNTRIES = array("DE","EN","IT","NO","FR","PL","RO","SR","BG","SL","NL","RU","HU","LT","TR","CA","SV","ZH","EL","ES","SQ","PT","CS","FI","SK","DA","HR","LV","ET","JA","KA","MN");

   
   /**
   * Given a 20 digit account number, 
   * generates and returns IBAN account
   * needs refactoring
   */
	public static function generate ($accountNumber, $countryCode, $ibanPrefix=false,$spaces=true) {
		
		$longAccount = "";
		$remainder = 0;
		$prefix = ($ibanPrefix)?'IBAN':'';

		// Remove space chars, if any
		$accountNumber = self::clear($accountNumber);

		if (self::invalidCountryCode($countryCode)) {
			return 'Invalid country code: ' . $countryCode;
		}		
		
		if (self::invalidAccountNumber($accountNumber)) {
			return 'Invalid account Number: ' . $accountNumber;
		}
		

		$longAccount =  self::rearrangeAccount($accountNumber,$countryCode);

		$remainder = self::calculateRemainder($longAccount);

		if ($spaces) {
	   	return self::addSpaces($prefix . $countryCode . sprintf('%02d',(98-$remainder)) . $accountNumber);
	   } else {
	   	return $prefix . $countryCode . sprintf('%02d',(98-$remainder)) . $accountNumber;
	   }
	}
	
	/**
	* validates an IBAN account
	*
	*/
	public static function validate ($ibanAccount) {
		$longAccount = '';
		
		$longAccount = self::clearIban($ibanAccount);

		$longAccount = self::rearrangeIban($longAccount);
		                        
		$longAccount =	substr($longAccount,2,strlen($longAccount) -2) . substr($longAccount,0, 2) ;
		
     
     	return (self::calculateRemainder($longAccount) == 1);
	}
	
	
	/**
	* checks for invalid countryCode in format or existence
	*/
	private function invalidCountryCode ($countryCode) {

		if (!preg_match('/^[A-Z]{2}$/i', $countryCode)) {
			return true;
		}

		// Maybe it could be faster a regex like DE|EN|IT|.. ?
		if (!in_array($countryCode,self::$COUNTRIES)) {
			return true;
		}
	
		return false;
	}

	/**
	* rearrangeAccount
	*/
	private function rearrangeAccount ($accountNumber,$countryCode) {
					return $accountNumber . 
								self::letterPosition(substr($countryCode,0, 1)) . 
                           self::letterPosition(substr($countryCode,1, 1)). "00";
	}

	/**
	* rearrangeIban
	*/
	private function rearrangeIban ($ibanAccount) {
					return 	substr($ibanAccount,2,strlen($ibanAccount) -2) .
		                         self::letterPosition(substr($ibanAccount,0, 1)) .
		                         	self::letterPosition(substr($ibanAccount,1, 1));
	}
	
	/**
	* workaround to perform mod operation with a big number.
	*/
	private function calculateRemainder($longNumber) {
		$division = 0;
		$remainder = 0;
		
     for ($i=0;$i

Si quieres probar esto, tendrías que escribir algo así: incluir el fichero anterior y usar directamente los métdoos estáticos de generar y validar. Hay un par de cuentas de ejemplo. Generar tiene dos parámetros opcionales. Uno booleano para decirle si queremos sacar la cuenta con el prefijo IBAN (false por defecto), y otro para decirle si queremos que saque el IBAN con separaciones (true por defecto).

<?php

include_once 'Iban.php';

//$example='2103 0166 32 1234567890';
//$expected_iban = 'ES5021030166321234567890';

$example='2100 0813 61 0123456789';
$expected_iban = 'ES79 2100 0813 6101 2345 6789';
 
echo Iban::generate($example,'ES') . ' == ';
echo $expected_iban;

if (Iban::validate('ES5021030166321234567890')) {
	echo 'valid IBAN';
	} else {
	echo 'invalid IBAN';
}

Habrás notado que el php no lo cierro con ?> . Eso es porque voy de superdelisto y de extrakwel. Pero en el fondo esto no ha sido más que un post con una rueda reinventada. Hay formas mucho más abreviadas de hacer esto.

]]> Los organismos internaciones se han vuelto a poner de acuerdo para poner unificar los números de cuenta y gracias a ello todos los programadores y DBAs del mundo ya estamos enfrascados en la tarea de adaptar programas, validaciones, campos de las BBDD y un largo etcétera.

En cada país el código de cuenta corriente puede variar y a través del IBAN se intenta unificar la forma de esa cuenta de tal forma que sea validable. Este artículo de la wikipedia lo explica bastante bien, incluyendo los pasos tanto para generar un IBAN a partir de una CC como para validarlo

Hay una pequeña pega, la validación exige una operación mod sobre un número tan grande que es probable que muchos lenguajes no puedan llevarla a cabo. En la red existen ya muchas soluciones, esta es una. Ojo, aparte de que este ejemplo solo se ha probado con cuentas en el formato de 20 dígitos esto no ha sido más que una diversión. Tienes implementaciones mejores como php-iban

NOTA:Para evitar problemas con el copy paste o posibles fallos con algún caracter, puedes descargarte esto del repositorio de git

<?php
/**
* Iban
* Simple utility class to generate and validate IBAN account numbers
* Based on http://www.lawebdelprogramador.com/foros/Visual_Basic/1409866-Calculo_IBAN.html
* @author Pello Xabier Altadill Izura
* @version    $Id:$
* @link       http://www.pello.info
* @since      Available since 2014-01-17
* @greetz	Iban (Zabalza)
*  ... and you too
*/

class Iban {
   
   private static $LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	private static $COUNTRIES = array("DE","EN","IT","NO","FR","PL","RO","SR","BG","SL","NL","RU","HU","LT","TR","CA","SV","ZH","EL","ES","SQ","PT","CS","FI","SK","DA","HR","LV","ET","JA","KA","MN");

   
   /**
   * Given a 20 digit account number, 
   * generates and returns IBAN account
   * needs refactoring
   */
	public static function generate ($accountNumber, $countryCode, $ibanPrefix=false,$spaces=true) {
		
		$longAccount = "";
		$remainder = 0;
		$prefix = ($ibanPrefix)?'IBAN':'';

		// Remove space chars, if any
		$accountNumber = self::clear($accountNumber);

		if (self::invalidCountryCode($countryCode)) {
			return 'Invalid country code: ' . $countryCode;
		}		
		
		if (self::invalidAccountNumber($accountNumber)) {
			return 'Invalid account Number: ' . $accountNumber;
		}
		

		$longAccount =  self::rearrangeAccount($accountNumber,$countryCode);

		$remainder = self::calculateRemainder($longAccount);

		if ($spaces) {
	   	return self::addSpaces($prefix . $countryCode . sprintf('%02d',(98-$remainder)) . $accountNumber);
	   } else {
	   	return $prefix . $countryCode . sprintf('%02d',(98-$remainder)) . $accountNumber;
	   }
	}
	
	/**
	* validates an IBAN account
	*
	*/
	public static function validate ($ibanAccount) {
		$longAccount = '';
		
		$longAccount = self::clearIban($ibanAccount);

		$longAccount = self::rearrangeIban($longAccount);
		                        
		$longAccount =	substr($longAccount,2,strlen($longAccount) -2) . substr($longAccount,0, 2) ;
		
     
     	return (self::calculateRemainder($longAccount) == 1);
	}
	
	
	/**
	* checks for invalid countryCode in format or existence
	*/
	private function invalidCountryCode ($countryCode) {

		if (!preg_match('/^[A-Z]{2}$/i', $countryCode)) {
			return true;
		}

		// Maybe it could be faster a regex like DE|EN|IT|.. ?
		if (!in_array($countryCode,self::$COUNTRIES)) {
			return true;
		}
	
		return false;
	}

	/**
	* rearrangeAccount
	*/
	private function rearrangeAccount ($accountNumber,$countryCode) {
					return $accountNumber . 
								self::letterPosition(substr($countryCode,0, 1)) . 
                           self::letterPosition(substr($countryCode,1, 1)). "00";
	}

	/**
	* rearrangeIban
	*/
	private function rearrangeIban ($ibanAccount) {
					return 	substr($ibanAccount,2,strlen($ibanAccount) -2) .
		                         self::letterPosition(substr($ibanAccount,0, 1)) .
		                         	self::letterPosition(substr($ibanAccount,1, 1));
	}
	
	/**
	* workaround to perform mod operation with a big number.
	*/
	private function calculateRemainder($longNumber) {
		$division = 0;
		$remainder = 0;
		
     for ($i=0;$i

Si quieres probar esto, tendrías que escribir algo así: incluir el fichero anterior y usar directamente los métdoos estáticos de generar y validar. Hay un par de cuentas de ejemplo. Generar tiene dos parámetros opcionales. Uno booleano para decirle si queremos sacar la cuenta con el prefijo IBAN (false por defecto), y otro para decirle si queremos que saque el IBAN con separaciones (true por defecto).

<?php

include_once 'Iban.php';

//$example='2103 0166 32 1234567890';
//$expected_iban = 'ES5021030166321234567890';

$example='2100 0813 61 0123456789';
$expected_iban = 'ES79 2100 0813 6101 2345 6789';
 
echo Iban::generate($example,'ES') . ' == ';
echo $expected_iban;

if (Iban::validate('ES5021030166321234567890')) {
	echo 'valid IBAN';
	} else {
	echo 'invalid IBAN';
}

Habrás notado que el php no lo cierro con ?> . Eso es porque voy de superdelisto y de extrakwel. Pero en el fondo esto no ha sido más que un post con una rueda reinventada. Hay formas mucho más abreviadas de hacer esto.

]]> http://www.pello.info/index.php/blog/calcular-el-iban-con-php MessageQueue con Spring http://www.pello.info/index.php/blog/messagequeue-con-spring http://www.pello.info/index.php/blog/messagequeue-con-spring 2014-01-06 00:08:52 pelloxabier http://www.pello.info/index.php/blog/messagequeue-con-spring

Hace unos meses salió aquí un ejemplo de ActiveMQ sin Spring ni nada, aunque lo relevante era mostrar la configuración y uso del servidor de mensajes. Vamos ahora a hacer exactamente lo mismo pero utilizando Spring. Cosa que tenía pendiente desde entonces.

Al igual que sucedía con JDBC, Spring trae unas plantillas para que nos podamos ahorrar toooodo ese código boilerplate tedioso, repetitivo que se precisa simplemente para hacer una operación sencilla. En este caso se trata de JmsTemplate.

Al contrario que otros ejemplos, aquí conviene empezar viendo el fichero xml con la definición de beans, en los que veremos cómo se declaran una serie de instancias precisas para interactuar con ActiveMQ.

El fichero de beans de Spring

Hay dos maneras de referise a la cola, puede ser de forma genérica como se ve en este ejemplo o haciendo uso de los prefijos de ActiveMQ (se ven comentados)






	







	








 

	

 
   
  
  
  
  	
  	
	
  
  
  
  
	
	
	
  
  

El emisor

Es un Thread que aleatoriamente manda una instancia de la clase Order, que no es más que un POJO que representa un pedido. Tanto en el emisor como en el receptor se aprecia que el código para interactuar con la cola de mensajes se reduce mucho.

package info.pello.spring.messagequeue;

import java.util.Random;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;


/**
 * Sends messages to apache MQ
 * @author Pello Altadill
 * @greetz to people I met in Andersen
 */
public class MessageSender extends Thread {

	private Random random;
	private JmsTemplate jmsTemplate;
	private String queueName;
	
	/**
	 * default constructor
	 */
	public MessageSender (String name) {
		super(name);
		random = new Random();
	}
	
	/**
	 * main thread loop
	 */
	public void run () {
		String [] products = {"BigMac","Chips","Coke"};
		Order order = null;
		int counter = 0;
		
		while (true) {
			try {
				sleep(random.nextInt(5));
				counter++;
				order = new Order(products[random.nextInt(3)], random.nextInt(5));
				System.out.println("["+counter+"] Sending order: " + order.toString());
				sendMessage(order);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}

	/**
	 * sends message to queue
	 * http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch23s03.html
	 * @param order
	 */
	private void sendMessage(final Order order) {

		jmsTemplate.send(queueName,
			new MessageCreator() {
				public Message createMessage(Session session) throws JMSException {
					return session.createObjectMessage(order);
				}
			}
		);

		
	}

	/**
	 * @return the jmsTemplate
	 */
	public JmsTemplate getJmsTemplate() {
		return jmsTemplate;
	}

	/**
	 * @param jmsTemplate the jmsTemplate to set
	 */
	public void setJmsTemplate(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	/**
	 * @return the queueName
	 */
	public String getQueueName() {
		return queueName;
	}

	/**
	 * @param queueName the queueName to set
	 */
	public void setQueueName(String queueName) {
		this.queueName = queueName;
	}
}
El receptor

Otro thread que va leyendo de la cola los pedidos.

package info.pello.spring.messagequeue;

import java.util.Random;

import javax.jms.JMSException;
import javax.jms.ObjectMessage;


import org.springframework.jms.core.JmsTemplate;


/**
 * Receives messages to apache MQ
 * @author Pello Altadill
 * @greetz to people I met in Andersen
 */
public class MessageReceiver extends Thread {
	
	private Random random;
	private String queueName;
	private JmsTemplate jmsTemplate;
	
	/**
	 * default constructor
	 */
	public MessageReceiver (String name) {
		super(name);
		random = new Random();
	}
	
	/**
	 * main thread loop
	 */
	public void run () {
		Order order = null;
		int counter = 0;
		
		while (true) {
			try {
				sleep(random.nextInt(5));
				order = receiveMessage();
				
				if (null != order) {
					counter++;
					System.out.println("["+counter+"] Order rcv: " + order.toString());
				} else {
					System.out.println("Order is null ");					
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}

	/**
	 * reads message from queue
	 * @return Order
	 */
	private Order receiveMessage() {
		try {
			ObjectMessage receivedMessage = (ObjectMessage) jmsTemplate.receive(queueName);
			Order order = (Order) receivedMessage.getObject();
			
			return order;
			} catch (JMSException jmsException) {
				System.err.println("Error reading msg: " + jmsException.getMessage());
			}
		
		return null;
		
	}


	/**
	 * @return the jmsTemplate
	 */
	public JmsTemplate getJmsTemplate() {
		return jmsTemplate;
	}

	/**
	 * @param jmsTemplate the jmsTemplate to set
	 */
	public void setJmsTemplate(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	/**
	 * @return the queueName
	 */
	public String getQueueName() {
		return queueName;
	}

	/**
	 * @param queueName the queueName to set
	 */
	public void setQueueName(String queueName) {
		this.queueName = queueName;
	}
}
La clase principal

Esta clase simplemente inicia el emisor y receptor.

package info.pello.spring.messagequeue;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Main program, starting point of our project
 * @author Pello Altadill
 * @greetz for those who keep on working even on xmas
 */
public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ApplicationContext context = new ClassPathXmlApplicationContext("messagequeue.xml");
		 
		MessageSender messageSender = (MessageSender) context.getBean("messageSender");
		MessageReceiver messageReceiver = (MessageReceiver) context.getBean("messageReceiver");

		messageSender.start();
		messageReceiver.start();
		
	}

}

Esto genera una serie de logs bastante verbosos, pero se va viendo como se pasan mensajes a través de activeMQ. Por cierto, en el servidor no hace falta hacer nada, más que ponerlo en marcha.

]]>

Hace unos meses salió aquí un ejemplo de ActiveMQ sin Spring ni nada, aunque lo relevante era mostrar la configuración y uso del servidor de mensajes. Vamos ahora a hacer exactamente lo mismo pero utilizando Spring. Cosa que tenía pendiente desde entonces.

Al igual que sucedía con JDBC, Spring trae unas plantillas para que nos podamos ahorrar toooodo ese código boilerplate tedioso, repetitivo que se precisa simplemente para hacer una operación sencilla. En este caso se trata de JmsTemplate.

Al contrario que otros ejemplos, aquí conviene empezar viendo el fichero xml con la definición de beans, en los que veremos cómo se declaran una serie de instancias precisas para interactuar con ActiveMQ.

El fichero de beans de Spring

Hay dos maneras de referise a la cola, puede ser de forma genérica como se ve en este ejemplo o haciendo uso de los prefijos de ActiveMQ (se ven comentados)






	







	








 

	

 
   
  
  
  
  	
  	
	
  
  
  
  
	
	
	
  
  

El emisor

Es un Thread que aleatoriamente manda una instancia de la clase Order, que no es más que un POJO que representa un pedido. Tanto en el emisor como en el receptor se aprecia que el código para interactuar con la cola de mensajes se reduce mucho.

package info.pello.spring.messagequeue;

import java.util.Random;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;


/**
 * Sends messages to apache MQ
 * @author Pello Altadill
 * @greetz to people I met in Andersen
 */
public class MessageSender extends Thread {

	private Random random;
	private JmsTemplate jmsTemplate;
	private String queueName;
	
	/**
	 * default constructor
	 */
	public MessageSender (String name) {
		super(name);
		random = new Random();
	}
	
	/**
	 * main thread loop
	 */
	public void run () {
		String [] products = {"BigMac","Chips","Coke"};
		Order order = null;
		int counter = 0;
		
		while (true) {
			try {
				sleep(random.nextInt(5));
				counter++;
				order = new Order(products[random.nextInt(3)], random.nextInt(5));
				System.out.println("["+counter+"] Sending order: " + order.toString());
				sendMessage(order);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}

	/**
	 * sends message to queue
	 * http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch23s03.html
	 * @param order
	 */
	private void sendMessage(final Order order) {

		jmsTemplate.send(queueName,
			new MessageCreator() {
				public Message createMessage(Session session) throws JMSException {
					return session.createObjectMessage(order);
				}
			}
		);

		
	}

	/**
	 * @return the jmsTemplate
	 */
	public JmsTemplate getJmsTemplate() {
		return jmsTemplate;
	}

	/**
	 * @param jmsTemplate the jmsTemplate to set
	 */
	public void setJmsTemplate(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	/**
	 * @return the queueName
	 */
	public String getQueueName() {
		return queueName;
	}

	/**
	 * @param queueName the queueName to set
	 */
	public void setQueueName(String queueName) {
		this.queueName = queueName;
	}
}
El receptor

Otro thread que va leyendo de la cola los pedidos.

package info.pello.spring.messagequeue;

import java.util.Random;

import javax.jms.JMSException;
import javax.jms.ObjectMessage;


import org.springframework.jms.core.JmsTemplate;


/**
 * Receives messages to apache MQ
 * @author Pello Altadill
 * @greetz to people I met in Andersen
 */
public class MessageReceiver extends Thread {
	
	private Random random;
	private String queueName;
	private JmsTemplate jmsTemplate;
	
	/**
	 * default constructor
	 */
	public MessageReceiver (String name) {
		super(name);
		random = new Random();
	}
	
	/**
	 * main thread loop
	 */
	public void run () {
		Order order = null;
		int counter = 0;
		
		while (true) {
			try {
				sleep(random.nextInt(5));
				order = receiveMessage();
				
				if (null != order) {
					counter++;
					System.out.println("["+counter+"] Order rcv: " + order.toString());
				} else {
					System.out.println("Order is null ");					
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}

	/**
	 * reads message from queue
	 * @return Order
	 */
	private Order receiveMessage() {
		try {
			ObjectMessage receivedMessage = (ObjectMessage) jmsTemplate.receive(queueName);
			Order order = (Order) receivedMessage.getObject();
			
			return order;
			} catch (JMSException jmsException) {
				System.err.println("Error reading msg: " + jmsException.getMessage());
			}
		
		return null;
		
	}


	/**
	 * @return the jmsTemplate
	 */
	public JmsTemplate getJmsTemplate() {
		return jmsTemplate;
	}

	/**
	 * @param jmsTemplate the jmsTemplate to set
	 */
	public void setJmsTemplate(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	/**
	 * @return the queueName
	 */
	public String getQueueName() {
		return queueName;
	}

	/**
	 * @param queueName the queueName to set
	 */
	public void setQueueName(String queueName) {
		this.queueName = queueName;
	}
}
La clase principal

Esta clase simplemente inicia el emisor y receptor.

package info.pello.spring.messagequeue;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Main program, starting point of our project
 * @author Pello Altadill
 * @greetz for those who keep on working even on xmas
 */
public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ApplicationContext context = new ClassPathXmlApplicationContext("messagequeue.xml");
		 
		MessageSender messageSender = (MessageSender) context.getBean("messageSender");
		MessageReceiver messageReceiver = (MessageReceiver) context.getBean("messageReceiver");

		messageSender.start();
		messageReceiver.start();
		
	}

}

Esto genera una serie de logs bastante verbosos, pero se va viendo como se pasan mensajes a través de activeMQ. Por cierto, en el servidor no hace falta hacer nada, más que ponerlo en marcha.

]]>
http://www.pello.info/index.php/blog/messagequeue-con-spring
Acceder a web desde Android con java.net http://www.pello.info/index.php/blog/acceder-a-web-desde-android-con-java-net http://www.pello.info/index.php/blog/acceder-a-web-desde-android-con-java-net 2013-11-23 10:36:35 pelloxabier http://www.pello.info/index.php/blog/acceder-a-web-desde-android-con-java-net Accceso a Web desde Android

Las aplicaciones para móviles se podrían dividir en tres grandes grupos: las que se ejecutan totalmente de forma local, las que tienen toda la información en la web y las que combinan las dos cosas. Si tenemos que acceder a la web desde Android y teniendo en cuenta que lo hacemos con java tenemos dos opciones por defecto:

  1. Usar las librerías básicas de java.net
  2. Usar HttpClient

HttpClient la librería de Apache
Logo pre-web ochentero

En este artículo ya mostraba un ejemplo de uso de HttpClient con Android. HttpClient es una librería que forma parte del proyecto Apache, ya va por la versión 4.3 y que aparte de tener cierto recorrido pues qué vamos a decir, tiene detrás a Apache y ya se sabe, esta gente puede decir aquella frase de los jubilados de vaya semanita: "yo traje la web a Internet chaval".

...
    /*
     * consultar
     * Hace una petición a la web
     * Todo a mano con httpclient
     * @param View v
     */
    public void consultar (View v) {
    	String url = etUrl.getText().toString();
    	HttpGet peticion = new HttpGet(url);
		HttpClient cliente = new DefaultHttpClient();
		
    	try {
			ResponseHandler respuesta = new BasicResponseHandler();
			String cuerpoRespuesta = cliente.execute(peticion,respuesta);

			if (cuerpoRespuesta != null && cuerpoRespuesta.length() > 0) {
				tvResultado.setText("OK\n: " + cuerpoRespuesta);
			} else {
				tvResultado.setText("Error\n"+cuerpoRespuesta);
			}

		} catch (ClientProtocolException e) {
			tvResultado.setText("Unexpected ClientProtocolException" + e);
		} catch (IOException e) {
			tvResultado.setText("Unexpected IOException" + e);
		}

    }
    
    /*
     * postear
     * Enví­a una petición a la web.. con POST pasando parámetros
     * @param View v
     */
    public void postear (View v) {
    	String url = etUrl.getText().toString();
    	String login = etLogin.getText().toString();
    	String password = etPassword.getText().toString();
    	
    	HttpPost peticion = null;
		HttpClient cliente = null;
		
		Vector parametros = new Vector();
		ResponseHandler respuesta = new BasicResponseHandler();
		
    	try {
    		parametros.add(new BasicNameValuePair("login", login));
    		parametros.add(new BasicNameValuePair("password", password));
    		
    		url +=  "?" + URLEncodedUtils.format(parametros, null);

    		peticion = new HttpPost(url);
			cliente = new DefaultHttpClient();
    		
			String cuerpoRespuesta = cliente.execute(peticion,respuesta);
	    	

			
			if (cuerpoRespuesta != null && cuerpoRespuesta.length() > 0) {
				tvResultado.setText("OK\n: " + cuerpoRespuesta);
			} else {
				tvResultado.setText("Inesperado: \n"+cuerpoRespuesta);
			}

		} catch (ClientProtocolException e) {
			tvResultado.setText("Unexpected ClientProtocolException" + e);
		} catch (IOException e) {
			tvResultado.setText("Unexpected IOException" + e);
		}  	
    }
...

Android trae la librería HttpClient por defecto, lo cual está muy bien, pero hay un pequeño problema. Parece ser que la versión de HttpClient que Android introduce por defecto siempre es una 4.0beta, y lo que es peor, no la cambian. Y es probable que por la web te encuentres muchos ejemplos de HttpClient y al trasladarlos a una aplicación Android haya muchas clases cruciales que no se reconocen. Así que en este post, para ejemplos simples lo que propongo es:

java.net: back to basics

A ver, si meter soporte para otras versiones de HttpClient puede ser tan simple como introducir ese jar en la App, o sencillamente buscar otras librerías que seguramente lo hacen muy bien. Esto no es más que una clase muy muy simple que tira de java.net para hacer dos cosas muy simples: GET y POST, con soporte para cookies, y sin necesidad de añadir librerías extras.



import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Hashtable;


/**
 * Simple class to make HTTP requests using standar java.net package
 * @author Pello Xabier Altadill Izura
 * @greetz 4 u
 */
public class WebRequest {
	private String userAgent;
	private String responseString;
	private int responseCode;
	private String exceptionMessage;
	private Hashtable cookies;
	
	/**
	 * default constructor
	 */
	public WebRequest () {
		this.userAgent = "EvilBlackDeathOfDoom browser v1.0";
		cookies = new Hashtable();
	}

	/**
	 * makes GET request to URL
	 * @param urlString to request
	 * @return true if everything went fine, false otherwise
	 */
	public boolean get (String urlString) {
		boolean result = false;
		responseString = "";
		exceptionMessage = "";
		String line = "";
		
		
		try {
				// Create an URL instance
			   URL url = new URL(urlString);
			   
		       // Create the HttpConnection
			   HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		       connection.setRequestProperty("User-Agent", userAgent); 
		       connection.setRequestMethod("GET");
		       setCookies(connection);

		        // Get input stream from server
		        BufferedReader in = new BufferedReader(new InputStreamReader(
		                                    connection.getInputStream()));
		    // Read response from server
		    while ((line = in.readLine()) != null) {
		    	responseString += line;
		    }
		    
		    in.close();
		return true;
		
	    } catch (IOException e) {
		  exceptionMessage = e.getMessage();
		  e.printStackTrace();
		} catch (Exception e) {
		  exceptionMessage = e.getMessage();	    	
		}
		
		return false;
		
	}
	
	/**
	 * makes POST request to URL
	 * @param url to request
	 * @param parameters for POST
	 * @return true if everything went fine, false otherwise
	 */
	public boolean post (String urlString, Hashtable parameters) {
		boolean result = false;
	    String line = "";
	    String postString = "";
	    String parameterValue = "";
		responseString = "";
		exceptionMessage = "";

			try {

		        URL url = new URL(urlString);
		        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		        connection.setRequestMethod("POST");
		        connection.setRequestProperty("User-Agent", userAgent); 
		        connection.setDoOutput(true);
		        setCookies(connection);

		        OutputStreamWriter output = new OutputStreamWriter(
		                                         connection.getOutputStream());
		        
		        
		        // We set parameters one by one
			    for (String parameterName : parameters.keySet()) {
			    	parameterValue = URLEncoder.encode(parameters.get(parameterName),"UTF-8");
			    	postString += parameterName + "=" +parameterValue +"&";
			     }
			    
			    output.write(postString);
		        output.close();

		        // Now we get the response
		        BufferedReader in = new BufferedReader(
		                                    new InputStreamReader(
		                                    connection.getInputStream()));
		        
		      getCookies(connection);
		      responseCode = connection.getResponseCode();
		      
		      while ((line = in.readLine()) != null) {
		        responseString += line;
		      }
		      in.close();
		     return true;
		     
		    } catch (IOException e) {
		      exceptionMessage = e.getMessage();
		      e.printStackTrace();
		    } catch (Exception e) {
			  exceptionMessage = e.getMessage();	    	
		      e.printStackTrace();
		    }
			return false;
	}
	
	/**
	 * sends previously saved cookies to server.
	 * This method restores cookie name=value pairs from cookies hashtable
	 * and puts them in request header:
	 *  cookiename1=value1; cookiename2=value2;..
	 * @param connection
	 */
	private void setCookies(HttpURLConnection connection) {
		String cookieString = "";

		// Get cookies name=value pair from hashtable
		for (String cookieName : cookies.keySet()) {
			cookieString += cookieName + "=" + cookies.get(cookieName) + ";";
		}
		
		// and put them in the request header
		System.out.println("Sending cookies to server: " + cookieString);
		connection.setRequestProperty("Cookies", cookieString);
	}

	/**
	 * retrieves Cookies sent by server
	 * Cookies come in this form:
	 *  Set-Cookie: name1=value1;
	 *  Set-Cookie: name2=value2;
	 *  ...
	 * So we have to retrieve every Set-Cookie line and parse cookie name and value
	 * This method stores cookie data in the cookies Hashtable for further use
	 * @param connection
	 */
	private void getCookies(HttpURLConnection connection) {
		String headerName=null;
		String cookieString = "";
        String cookieName = "";
        String cookieValue = "";        
        
		// We look up for Set-Cookie entries in header
		for (int i=1; (headerName = connection.getHeaderFieldKey(i))!=null; i++) {
		 	if (headerName.equals("Set-Cookie")) {                  
		 		cookieString = connection.getHeaderField(i);   
		        cookieString = cookieString.substring(0, cookieString.indexOf(";"));
		        cookieName = cookieString.substring(0, cookieString.indexOf("="));
		        cookieValue = cookieString.substring(cookieString.indexOf("=") + 1, cookieString.length());
		        cookies.put(cookieName, cookieValue);
		        System.out.println("One cookie, mmm yummy: " + cookieName + "=" + cookieValue);
		    }
		}
	}

	/**
	 * @return the userAgent
	 */
	public String getUserAgent() {
		return userAgent;
	}

	/**
	 * @param userAgent the userAgent to set
	 */
	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}

	/**
	 * @return the responseString
	 */
	public String getResponseString() {
		return responseString;
	}

	/**
	 * @param responseString the responseString to set
	 */
	public void setResponseString(String responseString) {
		this.responseString = responseString;
	}

	/**
	 * @return the responseCode
	 */
	public int getResponseCode() {
		return responseCode;
	}

	/**
	 * @param responseCode the responseCode to set
	 */
	public void setResponseCode(int responseCode) {
		this.responseCode = responseCode;
	}

	/**
	 * @return the exceptionMessage
	 */
	public String getExceptionMessage() {
		return exceptionMessage;
	}

	/**
	 * @param exceptionMessage the exceptionMessage to set
	 */
	public void setExceptionMessage(String exceptionMessage) {
		this.exceptionMessage = exceptionMessage;
	}
}

Esta sería la clase principal para hacer pruebas, que en este caso se hizo con éxito contra una aplicación php que me facilitó amablemente Eugenia. Como se puede apreciar hay un ejemplo de get y otro de post, y el uso de la clase WebRequest es muy muy sencillo.

import java.util.Hashtable;



/**
*
* @author Pello Altadill
* @greetz blue mugs
*/
public class Main {
	public static void main (String args[]) {
		WebRequest webRequest = new WebRequest();
		
		if (webRequest.get("http://192.168.77.104/labs/Ejemplo1DAM/index.php")) {
			System.out.println("OK: " + webRequest.getResponseString());
		} else {
			System.out.println("Error: " + webRequest.getExceptionMessage());			
		}
		
		Hashtable parameters = new Hashtable();
		parameters.put("usuario", "falken");
		parameters.put("password", "josua");
		
		if (webRequest.post("http://192.168.77.104/labs/Ejemplo1DAM/consultarUsuario.php", parameters)) {
			System.out.println("OK login: " + webRequest.getResponseString() + "\n" + webRequest.getResponseCode());
		} else {
			System.out.println("Error: " + webRequest.getExceptionMessage() + "\n" + webRequest.getResponseCode());			
		}
		

	}
}

Puedes descargarte este ejemplo aquí. Necesita bastantes mejoras y la primera sería añadir el soporte para redirects.

]]>
Accceso a Web desde Android

Las aplicaciones para móviles se podrían dividir en tres grandes grupos: las que se ejecutan totalmente de forma local, las que tienen toda la información en la web y las que combinan las dos cosas. Si tenemos que acceder a la web desde Android y teniendo en cuenta que lo hacemos con java tenemos dos opciones por defecto:

  1. Usar las librerías básicas de java.net
  2. Usar HttpClient

HttpClient la librería de Apache
Logo pre-web ochentero

En este artículo ya mostraba un ejemplo de uso de HttpClient con Android. HttpClient es una librería que forma parte del proyecto Apache, ya va por la versión 4.3 y que aparte de tener cierto recorrido pues qué vamos a decir, tiene detrás a Apache y ya se sabe, esta gente puede decir aquella frase de los jubilados de vaya semanita: "yo traje la web a Internet chaval".

...
    /*
     * consultar
     * Hace una petición a la web
     * Todo a mano con httpclient
     * @param View v
     */
    public void consultar (View v) {
    	String url = etUrl.getText().toString();
    	HttpGet peticion = new HttpGet(url);
		HttpClient cliente = new DefaultHttpClient();
		
    	try {
			ResponseHandler respuesta = new BasicResponseHandler();
			String cuerpoRespuesta = cliente.execute(peticion,respuesta);

			if (cuerpoRespuesta != null && cuerpoRespuesta.length() > 0) {
				tvResultado.setText("OK\n: " + cuerpoRespuesta);
			} else {
				tvResultado.setText("Error\n"+cuerpoRespuesta);
			}

		} catch (ClientProtocolException e) {
			tvResultado.setText("Unexpected ClientProtocolException" + e);
		} catch (IOException e) {
			tvResultado.setText("Unexpected IOException" + e);
		}

    }
    
    /*
     * postear
     * Enví­a una petición a la web.. con POST pasando parámetros
     * @param View v
     */
    public void postear (View v) {
    	String url = etUrl.getText().toString();
    	String login = etLogin.getText().toString();
    	String password = etPassword.getText().toString();
    	
    	HttpPost peticion = null;
		HttpClient cliente = null;
		
		Vector parametros = new Vector();
		ResponseHandler respuesta = new BasicResponseHandler();
		
    	try {
    		parametros.add(new BasicNameValuePair("login", login));
    		parametros.add(new BasicNameValuePair("password", password));
    		
    		url +=  "?" + URLEncodedUtils.format(parametros, null);

    		peticion = new HttpPost(url);
			cliente = new DefaultHttpClient();
    		
			String cuerpoRespuesta = cliente.execute(peticion,respuesta);
	    	

			
			if (cuerpoRespuesta != null && cuerpoRespuesta.length() > 0) {
				tvResultado.setText("OK\n: " + cuerpoRespuesta);
			} else {
				tvResultado.setText("Inesperado: \n"+cuerpoRespuesta);
			}

		} catch (ClientProtocolException e) {
			tvResultado.setText("Unexpected ClientProtocolException" + e);
		} catch (IOException e) {
			tvResultado.setText("Unexpected IOException" + e);
		}  	
    }
...

Android trae la librería HttpClient por defecto, lo cual está muy bien, pero hay un pequeño problema. Parece ser que la versión de HttpClient que Android introduce por defecto siempre es una 4.0beta, y lo que es peor, no la cambian. Y es probable que por la web te encuentres muchos ejemplos de HttpClient y al trasladarlos a una aplicación Android haya muchas clases cruciales que no se reconocen. Así que en este post, para ejemplos simples lo que propongo es:

java.net: back to basics

A ver, si meter soporte para otras versiones de HttpClient puede ser tan simple como introducir ese jar en la App, o sencillamente buscar otras librerías que seguramente lo hacen muy bien. Esto no es más que una clase muy muy simple que tira de java.net para hacer dos cosas muy simples: GET y POST, con soporte para cookies, y sin necesidad de añadir librerías extras.



import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Hashtable;


/**
 * Simple class to make HTTP requests using standar java.net package
 * @author Pello Xabier Altadill Izura
 * @greetz 4 u
 */
public class WebRequest {
	private String userAgent;
	private String responseString;
	private int responseCode;
	private String exceptionMessage;
	private Hashtable cookies;
	
	/**
	 * default constructor
	 */
	public WebRequest () {
		this.userAgent = "EvilBlackDeathOfDoom browser v1.0";
		cookies = new Hashtable();
	}

	/**
	 * makes GET request to URL
	 * @param urlString to request
	 * @return true if everything went fine, false otherwise
	 */
	public boolean get (String urlString) {
		boolean result = false;
		responseString = "";
		exceptionMessage = "";
		String line = "";
		
		
		try {
				// Create an URL instance
			   URL url = new URL(urlString);
			   
		       // Create the HttpConnection
			   HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		       connection.setRequestProperty("User-Agent", userAgent); 
		       connection.setRequestMethod("GET");
		       setCookies(connection);

		        // Get input stream from server
		        BufferedReader in = new BufferedReader(new InputStreamReader(
		                                    connection.getInputStream()));
		    // Read response from server
		    while ((line = in.readLine()) != null) {
		    	responseString += line;
		    }
		    
		    in.close();
		return true;
		
	    } catch (IOException e) {
		  exceptionMessage = e.getMessage();
		  e.printStackTrace();
		} catch (Exception e) {
		  exceptionMessage = e.getMessage();	    	
		}
		
		return false;
		
	}
	
	/**
	 * makes POST request to URL
	 * @param url to request
	 * @param parameters for POST
	 * @return true if everything went fine, false otherwise
	 */
	public boolean post (String urlString, Hashtable parameters) {
		boolean result = false;
	    String line = "";
	    String postString = "";
	    String parameterValue = "";
		responseString = "";
		exceptionMessage = "";

			try {

		        URL url = new URL(urlString);
		        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		        connection.setRequestMethod("POST");
		        connection.setRequestProperty("User-Agent", userAgent); 
		        connection.setDoOutput(true);
		        setCookies(connection);

		        OutputStreamWriter output = new OutputStreamWriter(
		                                         connection.getOutputStream());
		        
		        
		        // We set parameters one by one
			    for (String parameterName : parameters.keySet()) {
			    	parameterValue = URLEncoder.encode(parameters.get(parameterName),"UTF-8");
			    	postString += parameterName + "=" +parameterValue +"&";
			     }
			    
			    output.write(postString);
		        output.close();

		        // Now we get the response
		        BufferedReader in = new BufferedReader(
		                                    new InputStreamReader(
		                                    connection.getInputStream()));
		        
		      getCookies(connection);
		      responseCode = connection.getResponseCode();
		      
		      while ((line = in.readLine()) != null) {
		        responseString += line;
		      }
		      in.close();
		     return true;
		     
		    } catch (IOException e) {
		      exceptionMessage = e.getMessage();
		      e.printStackTrace();
		    } catch (Exception e) {
			  exceptionMessage = e.getMessage();	    	
		      e.printStackTrace();
		    }
			return false;
	}
	
	/**
	 * sends previously saved cookies to server.
	 * This method restores cookie name=value pairs from cookies hashtable
	 * and puts them in request header:
	 *  cookiename1=value1; cookiename2=value2;..
	 * @param connection
	 */
	private void setCookies(HttpURLConnection connection) {
		String cookieString = "";

		// Get cookies name=value pair from hashtable
		for (String cookieName : cookies.keySet()) {
			cookieString += cookieName + "=" + cookies.get(cookieName) + ";";
		}
		
		// and put them in the request header
		System.out.println("Sending cookies to server: " + cookieString);
		connection.setRequestProperty("Cookies", cookieString);
	}

	/**
	 * retrieves Cookies sent by server
	 * Cookies come in this form:
	 *  Set-Cookie: name1=value1;
	 *  Set-Cookie: name2=value2;
	 *  ...
	 * So we have to retrieve every Set-Cookie line and parse cookie name and value
	 * This method stores cookie data in the cookies Hashtable for further use
	 * @param connection
	 */
	private void getCookies(HttpURLConnection connection) {
		String headerName=null;
		String cookieString = "";
        String cookieName = "";
        String cookieValue = "";        
        
		// We look up for Set-Cookie entries in header
		for (int i=1; (headerName = connection.getHeaderFieldKey(i))!=null; i++) {
		 	if (headerName.equals("Set-Cookie")) {                  
		 		cookieString = connection.getHeaderField(i);   
		        cookieString = cookieString.substring(0, cookieString.indexOf(";"));
		        cookieName = cookieString.substring(0, cookieString.indexOf("="));
		        cookieValue = cookieString.substring(cookieString.indexOf("=") + 1, cookieString.length());
		        cookies.put(cookieName, cookieValue);
		        System.out.println("One cookie, mmm yummy: " + cookieName + "=" + cookieValue);
		    }
		}
	}

	/**
	 * @return the userAgent
	 */
	public String getUserAgent() {
		return userAgent;
	}

	/**
	 * @param userAgent the userAgent to set
	 */
	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}

	/**
	 * @return the responseString
	 */
	public String getResponseString() {
		return responseString;
	}

	/**
	 * @param responseString the responseString to set
	 */
	public void setResponseString(String responseString) {
		this.responseString = responseString;
	}

	/**
	 * @return the responseCode
	 */
	public int getResponseCode() {
		return responseCode;
	}

	/**
	 * @param responseCode the responseCode to set
	 */
	public void setResponseCode(int responseCode) {
		this.responseCode = responseCode;
	}

	/**
	 * @return the exceptionMessage
	 */
	public String getExceptionMessage() {
		return exceptionMessage;
	}

	/**
	 * @param exceptionMessage the exceptionMessage to set
	 */
	public void setExceptionMessage(String exceptionMessage) {
		this.exceptionMessage = exceptionMessage;
	}
}

Esta sería la clase principal para hacer pruebas, que en este caso se hizo con éxito contra una aplicación php que me facilitó amablemente Eugenia. Como se puede apreciar hay un ejemplo de get y otro de post, y el uso de la clase WebRequest es muy muy sencillo.

import java.util.Hashtable;



/**
*
* @author Pello Altadill
* @greetz blue mugs
*/
public class Main {
	public static void main (String args[]) {
		WebRequest webRequest = new WebRequest();
		
		if (webRequest.get("http://192.168.77.104/labs/Ejemplo1DAM/index.php")) {
			System.out.println("OK: " + webRequest.getResponseString());
		} else {
			System.out.println("Error: " + webRequest.getExceptionMessage());			
		}
		
		Hashtable parameters = new Hashtable();
		parameters.put("usuario", "falken");
		parameters.put("password", "josua");
		
		if (webRequest.post("http://192.168.77.104/labs/Ejemplo1DAM/consultarUsuario.php", parameters)) {
			System.out.println("OK login: " + webRequest.getResponseString() + "\n" + webRequest.getResponseCode());
		} else {
			System.out.println("Error: " + webRequest.getExceptionMessage() + "\n" + webRequest.getResponseCode());			
		}
		

	}
}

Puedes descargarte este ejemplo aquí. Necesita bastantes mejoras y la primera sería añadir el soporte para redirects.

]]>
http://www.pello.info/index.php/blog/acceder-a-web-desde-android-con-java-net