diff --git a/.gitignore b/.gitignore
index c422267..ae9ab10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,5 @@
-composer.phar
/vendor/
-
-# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
-# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
-# composer.lock
+composer.lock
+composer.phar
+.DS_Store
+Thumbs.db
diff --git a/README.md b/README.md
index a75c869..598daa7 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,49 @@
-# php5-tiny-bbcode
-A tiny BBCode implementation for old PHP5
+# Tiny BBCode implementation for PHP 5.4+
+
+This library includes a lightweight implementation of a BBCode subset to HTML translator.
+
+## Features
+
+* It's tiny, yep.
+* PSR-4 autoloading compliant structure
+* Unit-Testing with PHPUnit
+* Easy to use to any framework or even a plain php file
+
+## Installation
+
+The suggested installation method is via [composer](https://getcomposer.org/):
+
+```sh
+php composer.phar require "igorakaamigo/php5-tiny-bbcode"
+```
+
+## Usage
+
+```php
+use \Igorakaamigo\Utils\BBCode;
+
+echo BBCode::convert('[b]A bold string[/b]');
+```
+
+### Supported BBCodes
+
+* [b]Bold string[/b]
+* [i]Italic string[/i]
+* [u]Underline string[/u]
+* [s]Strikethrough string[/s]
+* [url]http://www.domain.tld[/url]
+* [url=http://www.domain.tld]Another way to render a link[/url]
+* [img]http://www.domain.tld/upload/image.png[/img]
+* [quote]A quotation[/quote]
+* [code]A program code sample[/code]
+* [size=12]A text written using a 12px-sized font[/size]
+* [size="10pt"]A text written using a 10pt-sized font[/size]
+* [color="#33FF33"]A green text line[/color]
+* [ul], [ol], [li] – list-related tags
+* [table], [tr], [td] – table-related tags
+
+## Contributing
+
+OMG! Really? Thanks a lot!
+
+Fork --> modify --> pull-request
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..6d564bf
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,32 @@
+{
+ "name": "igorakaamigo/php5-tiny-bbcode",
+ "description": "A tiny BBCode implementation for old PHP5.",
+ "keywords": [
+ "php5",
+ "library",
+ "utils",
+ "bbcode"
+ ],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Igor M Osipov",
+ "email": "osipov.igor.amigo@gmail.com"
+ }
+ ],
+ "type": "library",
+ "require": {
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "5.4.*"
+ },
+ "autoload": {
+ "psr-4": {
+ "Igorakaamigo\\Utils\\": "src/"
+ }
+ },
+ "scripts": {
+ "test": "phpunit"
+ }
+}
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..f1e6dbb
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,12 @@
+\1',
+ '#\[url\](.*?)\[/url\]#si' => '\1',
+ '#\[url=(.*?)\](.*?)\[/url\]#si' => '\2',
+ '#\[img\](.*?)\[/img\]#si' => '',
+ '#\[quote(=".*?")?\](.*?)\[/quote\]#si' => '
\2', + '#\[code\](.*?)\[/code\]#si' => '
\1',
+ '#\[size=(\d+)\](.*?)\[/size\]#si' => '\2',
+ '#\[size="(.*?)"\](.*?)\[/size\]#si' => '\2',
+ '#\[color="(.*?)"\](.*?)\[/color\]#si' => '\2',
+ '#\[li\](.*?)\[/li\]#si' => 'A & paragraph
+
';
+ $source = '[url=http://www.google.com/][img]http://www.domain.tld/upload/123.png[/img][/url]';
+ $this->assertEquals($expected, BBCode::convert($source));
+ }
+
+ public function testItShouldDealWithTagB()
+ {
+ $this->_itShouldBehaveLikeASimpleWrapperTag('b', function ($v) {
+ return "$v";
+ });
+ }
+
+ private function _itShouldBehaveLikeASimpleWrapperTag($tagName, $tagBuilder)
+ {
+ $expected = "A leading part {$tagBuilder('A tag value')} A trailing part";
+ $source = "A leading part [$tagName]A tag value[/$tagName] A trailing part";
+ $this->assertEquals($expected, BBCode::convert($source), 'It should render a correct markup');
+
+ $uTag = strtoupper($tagName);
+ $source = "A leading part [$uTag]A tag value[/$uTag] A trailing part";
+ $this->assertEquals($expected, BBCode::convert($source), 'Tag names should be case-insensitive');
+
+ $expected = "A leading part {$tagBuilder('
+ A tag value
+ ')} A trailing part";
+ $source = "A leading part [$tagName]
+ A tag value
+ [/$tagName] A trailing part";
+ $this->assertEquals($expected, BBCode::convert($source),
+ 'Tag content should be processed as a multiline string');
+ }
+
+ public function testItShouldDealWithTagI()
+ {
+ $this->_itShouldBehaveLikeASimpleWrapperTag('i', function ($v) {
+ return "$v";
+ });
+ }
+
+ public function testItShouldDealWithTagU()
+ {
+ $this->_itShouldBehaveLikeASimpleWrapperTag('u', function ($v) {
+ return "$v";
+ });
+ }
+
+ public function testItShouldDealWithTagS()
+ {
+ $this->_itShouldBehaveLikeASimpleWrapperTag('s', function ($v) {
+ return "$v"; + }); + $this->_itShouldBehaveLikeAnAttributedWrapperTag('quote', '"Quote author"', function ($v) { + return "
$v"; + }); + } + + public function testItShouldDealWithTagCode() + { + $this->_itShouldBehaveLikeASimpleWrapperTag('code', function ($v) { + return "
$v";
+ });
+ }
+
+ public function testItShouldDealWithTagSize()
+ {
+ $this->_itShouldBehaveLikeAnAttributedWrapperTag('size', '20', function ($v) {
+ return "$v";
+ });
+ $this->_itShouldBehaveLikeAnAttributedWrapperTag('size', '"20em"', function ($v) {
+ return "$v";
+ });
+ }
+
+ public function testItShouldDealWithTagColor()
+ {
+ $this->_itShouldBehaveLikeAnAttributedWrapperTag('color', '"#AABBCC"', function ($v) {
+ return "$v";
+ });
+ }
+}