Diffs
Net_KyotoTycoon/trunk/license.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2010, Shinya Ohyanagi.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of Shinya Ohyanagi, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Net_KyotoTycoon/trunk/tests/KyotoTycoon/MiscTest.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * Spec of \Net\KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net;
+use Net;
+
+/**
+ * @see prepare
+ */
+require_once dirname(__DIR__) . '/prepare.php';
+
+/**
+ * @see \Net\KyotoTycoon
+ */
+require_once 'Net/KyotoTycoon.php';
+
+/**
+ * Misc test.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class MiscTest extends \PHPUnit_Framework_TestCase
+{
+ private $_kt = null;
+ private static $_port = null;
+ public static function setUpBeforeClass()
+ {
+ require_once dirname(__DIR__) . '/Util.php';
+ Net\KyotoTycoon\Test\Util::run();
+ self::$_port = Net\KyotoTycoon\Test\Util::$port;
+ }
+
+ public static function tearDownAfterClass()
+ {
+ Net\KyotoTycoon\Test\Util::shutdown();
+ }
+
+ public function setUp()
+ {
+ $params = array('port' => self::$_port);
+ $this->_kt = new KyotoTycoon($params);
+ }
+
+ public function testShouldEchoInputData()
+ {
+ $input = array('foo' => 'bar', 'hoge' => 'fuga');
+ $got = $this->_kt->echoBack($input);
+ $this->assertSame($input, $got);
+ }
+
+ public function testShouldReturnServerReport()
+ {
+ $got = $this->_kt->report();
+ $this->assertTrue(count($got) > 0);
+ }
+
+ public function testShouldReturnServerStatus()
+ {
+ $got = $this->_kt->status();
+ $this->assertTrue(isset($got['count']));
+ $this->assertTrue(isset($got['size']));
+ }
+
+ public function testShouldRunSynchronize()
+ {
+ $got = $this->_kt->synchronize();
+ $this->assertTrue($got);
+ }
+
+ public function testShouldRunVacuum()
+ {
+ $this->_kt->vacuum();
+ $got = $this->_kt->vacuum(1);
+ $this->assertTrue($got instanceof KyotoTycoon);
+ }
+
+ public function testShouldClearDatabase()
+ {
+ $this->_kt->set('clr_1', 'foo');
+ $this->assertSame($this->_kt->get('clr_1'), 'foo');
+ $this->_kt->clear();
+ $this->assertSame($this->_kt->get('clr_1'), null);
+ }
+}
Net_KyotoTycoon/trunk/tests/KyotoTycoon/CursorTest.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * Spec of \Net\KyotoTycoon\Cursor.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net;
+use Net;
+
+/**
+ * @see prepare
+ */
+require_once dirname(__DIR__) . '/prepare.php';
+
+/**
+ * @see \Net\KyotoTycoon
+ */
+require_once 'Net/KyotoTycoon.php';
+
+/**
+ * Misc test.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class CursorTest extends \PHPUnit_Framework_TestCase
+{
+ private $_kt = null;
+ private $_cursor = null;
+ private static $_port = null;
+ public static function setUpBeforeClass()
+ {
+ require_once dirname(__DIR__) . '/Util.php';
+ Net\KyotoTycoon\Test\Util::run();
+ self::$_port = Net\KyotoTycoon\Test\Util::$port;
+ }
+
+ public static function tearDownAfterClass()
+ {
+ Net\KyotoTycoon\Test\Util::shutdown();
+ }
+
+ public function setUp()
+ {
+ $params = array('port' => self::$_port);
+ $this->_kt = new KyotoTycoon($params);
+ $this->_cursor = $this->_kt->makeCursor(1);
+ }
+
+ public function testShouldReturnFalseWhenEmptyData()
+ {
+ $this->assertSame($this->_cursor->jump(), false);
+ }
+
+ public function testShouldReturnTrueWhenDataExists()
+ {
+ $this->_kt->setBulk(array('a' => 1, 'b' => '2', 'c' => 3));
+ $this->assertSame($this->_cursor->jump('b'), true);
+ $this->_kt->clear();
+ }
+
+ public function testShouldMoveCursor()
+ {
+ $this->_kt->setBulk(array('a' => 1, 'b' => '2', 'c' => 3));
+ $this->assertSame($this->_cursor->jump('b'), true);
+ $this->assertSame($this->_cursor->getKey(), 'b');
+ $this->assertSame($this->_cursor->getValue(), '2');
+
+ $this->_cursor->setValue('OK');
+ $this->assertSame($this->_cursor->getValue(), 'OK');
+ $this->assertSame($this->_cursor->get(1), array('b', 'OK'));
+ list($k, $v) = $this->_cursor->get();
+ $this->assertNotSame($k, 'b');
+ $this->assertSame($this->_kt->get($k), '1');
+ $this->_kt->clear();
+ }
+
+ public function testShouldRemoveCursor()
+ {
+ $this->_kt->setBulk(array('a' => 1, 'b' => '2', 'c' => 3));
+ $this->assertSame($this->_cursor->jump('b'), true);
+ $this->assertSame($this->_cursor->getKey(), 'b');
+ list($k, $v) = $this->_cursor->get();
+ $this->assertSame($this->_kt->get($k), '2');
+ $this->assertSame($this->_cursor->remove(), true);
+ $this->assertSame($this->_kt->get($k), null);
+ $this->_kt->clear();
+ }
+
+ public function testShouldDeleteCursor()
+ {
+ $this->_kt->setBulk(array('a' => 1, 'b' => '2', 'c' => 3));
+ $this->assertSame($this->_cursor->jump('b'), true);
+ $this->assertSame($this->_cursor->getKey(), 'b');
+ $this->_cursor->remove();
+ $this->assertTrue(
+ $this->_cursor->delete() instanceof KyotoTycoon\Cursor
+ );
+ $this->assertSame($this->_cursor->getKey(), null);
+ $this->_kt->clear();
+ }
+}
Net_KyotoTycoon/trunk/tests/KyotoTycoon/BasicTest.php
@@ -0,0 +1,254 @@
+<?php
+/**
+ * Spec of \Net\KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net;
+use Net;
+
+/**
+ * @see prepare
+ */
+require_once dirname(__DIR__) . '/prepare.php';
+
+/**
+ * @see \Net\KyotoTycoon
+ */
+require_once 'Net/KyotoTycoon.php';
+
+/**
+ * Basic test.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class BasicTest extends \PHPUnit_Framework_TestCase
+{
+ private $_kt = null;
+ private static $_port = null;
+ public static function setUpBeforeClass()
+ {
+ require_once dirname(__DIR__) . '/Util.php';
+ Net\KyotoTycoon\Test\Util::run();
+ self::$_port = Net\KyotoTycoon\Test\Util::$port;
+ }
+
+ public static function tearDownAfterClass()
+ {
+ Net\KyotoTycoon\Test\Util::shutdown();
+ }
+
+ public function setUp()
+ {
+ $params = array('port' => self::$_port);
+ $this->_kt = new KyotoTycoon($params);
+ }
+
+ public function testShouldSetPlainData()
+ {
+ $this->_kt->set('test', 'ok');
+ $this->assertSame($this->_kt->get('test'), 'ok');
+ $this->_kt->remove('test');
+ }
+
+ public function testShouldGetPlainData()
+ {
+ $this->_kt->set('test', 'ok');
+ $this->assertSame($this->_kt->get('test'), 'ok');
+ $this->_kt->remove('test');
+ }
+
+ public function testShouldReturnTrueRemoveData()
+ {
+ $this->_kt->set('test', 'ok');
+ $this->assertSame($this->_kt->remove('test'), true);
+ }
+
+ public function testShouldReturnFalseWhenFailToRemoveData()
+ {
+ $this->_kt->remove('test');
+ $this->assertSame($this->_kt->remove('test'), false);
+ }
+
+ public function testShouldReturnNullWhenDataNotSet()
+ {
+ $this->_kt->remove('test');
+ $this->assertSame( $this->_kt->get('test'), null);
+ }
+
+ public function testShouldSetBinaryData()
+ {
+ $this->_kt->remove("te\x00st");
+ $this->_kt->set("te\x00st", "o\x015\x00k");
+ $this->assertSame($this->_kt->get("te\x00st"), "o\x015\x00k");
+ $this->_kt->remove("te\x00st");
+ }
+
+ public function testShouldGetBinaryData()
+ {
+ $this->_kt->remove("te\x00st");
+ $this->_kt->set("te\x00st", "o\x015\x00k");
+ $this->assertSame($this->_kt->get("te\x00st"), "o\x015\x00k");
+ $this->_kt->remove("te\x00st");
+ }
+
+ public function testShouldReturnTrueWhenRemoveBinaryData()
+ {
+ $this->_kt->remove("te\x00st");
+ $this->_kt->set("te\x00st", "o\x015\x00k");
+ $this->assertSame($this->_kt->remove("te\x00st"), true);
+ }
+
+ public function testShouldAddData()
+ {
+ $this->_kt->remove('add_t1');
+ $this->assertSame($this->_kt->add('add_t1', 'ok'), true);
+ $this->assertSame($this->_kt->get('add_t1'), 'ok');
+ $this->_kt->remove('add_t1');
+ }
+
+ public function testShouldReturnFalseWhenDataAlreadyAdded()
+ {
+ $this->_kt->remove('add_t1');
+ $this->_kt->add('add_t1', 'ok');
+ $this->assertSame($this->_kt->add('add_t1', 'ng'), false);
+ $this->assertSame($this->_kt->get('add_t1'), 'ok');
+ $this->_kt->remove('add_t1');
+ }
+
+ public function testShouldReplaceData()
+ {
+ $this->_kt->remove('rep_t1');
+ $this->_kt->set('rep_t1', 'ng');
+ $this->assertSame($this->_kt->replace('rep_t1', 'ok'), true);
+ $this->assertSame($this->_kt->get('rep_t1'), 'ok');
+ $this->_kt->remove('rep_t1');
+ }
+
+ public function testShouldReturnFalseWhenReplaceableDataDataExist()
+ {
+ $this->_kt->remove('rep_t1');
+ $this->assertSame($this->_kt->replace('rep_t1', 'ok'), false);
+ $this->assertSame($this->_kt->get('rep_t1'), null);
+ }
+
+ public function testShouldAppendData()
+ {
+ $this->_kt->remove('app_t1');
+ $this->_kt->append('app_t1', 'o1');
+ $this->assertSame($this->_kt->get('app_t1'), 'o1');
+ $this->_kt->append('app_t1', 'o2');
+ $this->assertSame($this->_kt->get('app_t1'), 'o1o2');
+ $this->_kt->remove('app_t1');
+ }
+
+ public function testShouldIncrementData()
+ {
+ $this->_kt->remove('inc_t1');
+ $this->assertSame($this->_kt->increment('inc_t1', '25'), 25);
+ $this->assertSame($this->_kt->increment('inc_t1', '11'), 36);
+ $this->_kt->remove('inc_t1');
+ }
+
+ public function testShouldIncrementDoubleData()
+ {
+ $this->_kt->remove('inc_t2');
+ $this->assertSame($this->_kt->incrementDouble('inc_t2', '2.5'), 2.5);
+ $this->assertSame($this->_kt->incrementDouble('inc_t2', '1.1'), 3.6);
+ $this->_kt->remove('inc_t2');
+ }
+
+ public function testShouldComplareAndSwapData()
+ {
+ $this->_kt->remove('cas_t1');
+ $this->assertSame($this->_kt->cas('cas_t1', 'a', 'b'), false);
+ $this->assertSame($this->_kt->cas('cas_t1', null, 'b'), true);
+ $this->assertSame($this->_kt->cas('cas_t1', 'a', 'b'), false);
+ $this->assertSame($this->_kt->cas('cas_t1', null, 'c'), false);
+ $this->assertSame($this->_kt->cas('cas_t1', 'b', 'c'), true);
+ $this->assertSame($this->_kt->cas('cas_t1', 'b', null), false);
+ $this->assertSame($this->_kt->cas('cas_t1', 'c', null), true);
+ $this->assertSame($this->_kt->get('cas_t1'), null);
+ $this->_kt->remove('cas_t1');
+ }
+
+ public function testShouldSetBulkData()
+ {
+ $this->_kt->clear();
+ $data = array('a' => 1, 'b' => 2, 'c' => 3);
+ $this->assertSame($this->_kt->setBulk($data), 3);
+ foreach ($data as $k => $v) {
+ $this->assertSame($this->_kt->get($k), strval($v));
+ }
+ $this->_kt->removeBulk(array(1, 2, 3));
+ }
+
+ public function testShouldGetBulkData()
+ {
+ $this->_kt->clear();
+ $data = array('a' => 1, 'b' => 2, 'c' => 3);
+ $this->assertSame($this->_kt->setBulk($data), 3);
+ $this->assertSame(
+ $this->_kt->getBulk(array('a', 'b', 'c')),
+ array('a' => '1', 'b' => '2', 'c' => '3')
+ );
+ $this->_kt->removeBulk($data);
+ }
+
+ public function testShouldRemoveBulkData()
+ {
+ $this->_kt->clear();
+ $data = array('a' => 1, 'b' => 2, 'c' => 3);
+ $this->assertSame($this->_kt->setBulk($data), 3);
+ $this->_kt->removeBulk($data);
+ $this->assertSame($this->_kt->getBulk(array('a', 'b', 'c')), array());
+ }
+}
Net_KyotoTycoon/trunk/tests/KyotoTycoon/ScriptTest.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Spec of \Net\KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net;
+use Net;
+
+/**
+ * @see prepare
+ */
+require_once dirname(__DIR__) . '/prepare.php';
+
+/**
+ * @see \Net\KyotoTycoon
+ */
+require_once 'Net/KyotoTycoon.php';
+
+/**
+ * Script test.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class ScriptTest extends \PHPUnit_Framework_TestCase
+{
+ private $_kt = null;
+ private static $_port = null;
+ public static function setUpBeforeClass()
+ {
+ require_once dirname(__DIR__) . '/Util.php';
+ $script = sprintf('-scr %s ', dirname(__DIR__) . '/myecho.lua');
+ Net\KyotoTycoon\Test\Util::run($script);
+ self::$_port = Net\KyotoTycoon\Test\Util::$port;
+ }
+
+ public static function tearDownAfterClass()
+ {
+ Net\KyotoTycoon\Test\Util::shutdown();
+ }
+
+ public function setUp()
+ {
+ $params = array('port' => self::$_port);
+ $this->_kt = new KyotoTycoon($params);
+ }
+
+ public function testShouldRunMyechoScript()
+ {
+ $input = array('foo' => 'bar', 'hoge' => 'fuga');
+ $got = $this->_kt->playScript('myecho', $input);
+ $this->assertSame($got, $input);
+ }
+}
Net_KyotoTycoon/trunk/tests/TsvRpc/ParserTest.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Parser test
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @see http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc;
+
+/**
+ * @see prepare
+ */
+require_once dirname(__DIR__) . '/prepare.php';
+
+/**
+ * Spec of Parser library.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @see http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+class ParserTest extends \PHPUnit_Framework_TestCase
+{
+ private $_parser = null;
+ public function setUp()
+ {
+ require_once 'HTTP/TsvRpc/Parser.php';
+ $this->_parser = new Parser();
+ }
+
+ public function testShouldReturnPlaneStringWhenEnocdingNotSet()
+ {
+ $this->assertSame(
+ $this->_parser->encodeTsvrpc(array('foo' => 'bar')),
+ "foo\tbar"
+ );
+ }
+
+ public function testShouldReturnBase64StringWhenBSet()
+ {
+ $this->assertSame(
+ $this->_parser->encodeTsvrpc(array('foo' => 'bar'), 'B'),
+ "Zm9v\tYmFy"
+ );
+ }
+
+ public function testShouldReturnUriEncodedStringWhenUSet()
+ {
+ $this->assertSame(
+ $this->_parser->encodeTsvrpc(array('foo' => "\0"), 'U'),
+ "foo\t%00"
+ );
+ }
+
+ public function testShouldReturnQuotedPrintableStringWhenQSet()
+ {
+ $this->assertSame(
+ $this->_parser->encodeTsvrpc(array('foo' => "\0"), 'Q'),
+ "foo\t=00"
+ );
+ }
+
+ public function testShouldReturnArrayWhenTsvStringSet()
+ {
+ $this->assertSame(
+ $this->_parser->decodeTsvrpc("foo\tbar"),
+ array('foo' => 'bar')
+ );
+ }
+
+ public function testShouldReturnArrayWhenBase64EncodedStringSet()
+ {
+ $this->assertSame(
+ $this->_parser->decodeTsvrpc("Zm9v\tYmFy", 'B'),
+ array('foo' => 'bar')
+ );
+ }
+
+ public function testShouldReturnArrayWhenUrlEncodedStringSet()
+ {
+ $this->assertSame(
+ $this->_parser->decodeTsvrpc("foo\t%00", 'U'),
+ array('foo' => "\0")
+ );
+ }
+
+ public function testShouldReturnArrayWhenQuotedPrintableEncodedStringSet()
+ {
+ $this->assertSame(
+ $this->_parser->decodeTsvrpc("foo\t=00", 'Q'),
+ array('foo' => "\0")
+ );
+ }
+}
Net_KyotoTycoon/trunk/tests/TsvRpc/UtilTest.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Spec of \HTTP\TsvRpc\Util.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc;
+
+/**
+ * @see prepare
+ */
+require_once dirname(__DIR__) . '/prepare.php';
+
+/**
+ * Spec of Util.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+class UtilTest extends \PHPUnit_Framework_TestCase
+{
+ private $_util = null;
+ public function setUp()
+ {
+ require_once 'HTTP/TsvRpc/Util.php';
+ $this->_util = new Util();
+ }
+
+ public function testShouldReturnNullWhenEmptyStringSet()
+ {
+ $this->assertSame(
+ $this->_util->parseContentType(''),
+ null
+ );
+ }
+
+ public function testShouldReturnNullFooStringSet()
+ {
+ $this->assertSame(
+ $this->_util->parseContentType('foo'),
+ null
+ );
+ }
+
+ public function testShouldReturnEmptyStringWhenText_tab_separated_valuesSet()
+ {
+ $this->assertSame(
+ $this->_util->parseContentType('text/tab-separated-values;'),
+ ''
+ );
+ }
+
+ public function testShouldReturnEmptyStringWhenColencBSet()
+ {
+ $this->assertSame(
+ $this->_util->parseContentType('text/tab-separated-values; colenc=B'),
+ 'B'
+ );
+ }
+
+ public function testShouldReturnEmptyStringWhenColencUSet()
+ {
+ $this->assertSame(
+ $this->_util->parseContentType('text/tab-separated-values; colenc=U'),
+ 'U'
+ );
+ }
+
+ public function testShouldReturnEmptyStringWhenColencQSet()
+ {
+ $this->assertSame(
+ $this->_util->parseContentType('text/tab-separated-values; colenc=Q'),
+ 'Q'
+ );
+ }
+}
Net_KyotoTycoon/trunk/tests/Util.php
@@ -0,0 +1,168 @@
+<?php
+/**
+ * Start ktserver.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+namespace Net\KyotoTycoon\Test;
+
+/**
+ * Util
+ *
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+class Util
+{
+ /**
+ * Pid.
+ */
+ private static $_pid = null;
+
+ /**
+ * KyotoTycoon port.
+ */
+ public static $port = null;
+
+ /**
+ * Run ktserver.
+ *
+ * @access public
+ * @return int Pid
+ */
+ public static function run($option = null)
+ {
+ $port = 10000 + rand(0, 1000);
+ while ($port < 20000) {
+ if (self::checkPort($port) === false) {
+ break;
+ }
+ $port ++;
+ }
+ $ktserver = exec('which ktserver');
+ if ($ktserver === '') {
+ throw Exception('This test requires "ktserver".');
+ }
+ if (is_null($option)) {
+ $command = sprintf(
+ '%s -port %s > /dev/null 2>&1 & echo $!',
+ $ktserver, $port
+ );
+ } else {
+ $command = sprintf(
+ '%s -port %s %s > /dev/null 2>&1 & echo $!',
+ $ktserver, $port, $option
+ );
+ }
+ usleep(100);
+ exec($command, $op);
+ $pid = intval($op[0]);
+ self::$_pid = $pid;
+ self::$port = $port;
+
+ return $pid;
+ }
+
+ /**
+ * Get status running.
+ *
+ * @access public
+ * @return bool true:Process running, false:Process stop
+ */
+ public static function status()
+ {
+ if (self::$_pid === null) {
+ return false;
+ }
+
+ $command = 'ps -p ' . self::$_pid;
+ exec($command, $op);
+ if (!isset($op[1])) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Shutdown process.
+ *
+ * @access public
+ * @return bool true:Shutdown success, false:Shutdown fail
+ */
+ public static function shutdown()
+ {
+ if (self::$_pid === null) {
+ return;
+ }
+
+ if (self::status() === false) {
+ return;
+ }
+ $command = 'kill -9 ' . self::$_pid;
+ exec($command);
+ if (self::status() == false) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * checkPort
+ *
+ * @param mixed $port Port number
+ * @access public
+ * @return bool true:Port availble, Port already used.
+ */
+ public static function checkPort($port)
+ {
+ $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
+ $remote = @socket_connect($socket, '127.0.0.1', $port);
+ socket_close($socket);
+
+ return $remote;
+ }
+}
Net_KyotoTycoon/trunk/tests/myecho.lua
@@ -0,0 +1,9 @@
+kt = __kyototycoon__
+db = kt.db
+
+function myecho(inmap, outmap)
+ for key, value in pairs(inmap) do
+ outmap[key] = value
+ end
+ return kt.RVSUCCESS
+end
Net_KyotoTycoon/trunk/tests/prepare.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Scripts for PHPUnit
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+
+error_reporting(E_ALL | E_STRICT);
+$src = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'src';
+set_include_path(get_include_path()
+ . PATH_SEPARATOR . $src
+);
+
+require_once 'PHPUnit/Framework/TestCase.php';
Net_KyotoTycoon/trunk/src/HTTP/TsvRpc/Parser.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * TSV-RPC parser.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc;
+
+/**
+ * TSV-RPC parser.
+ *
+ * <pre>
+ * This module is port from Perl TSVRPC::Parser
+ * See also @link.
+ * </pre>
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+class Parser
+{
+ /**
+ * Encode plain array to TSV with $encoding.
+ *
+ * @param array $data Array data to encode
+ * @param mixed $encoding Encode type
+ * @access public
+ * @return String Encoded string
+ */
+ public function encodeTsvrpc(array $data, $encoding = null)
+ {
+ $encoders = array(
+ 'U' => function($value) { return urlencode($value); },
+ 'Q' => function($value) { return quoted_printable_encode($value); },
+ 'B' => function($value) { return base64_encode($value); }
+ );
+
+ if (isset($encoders[$encoding])) {
+ $encoder = $encoders[$encoding];
+ } else {
+ // When $encoding is not in $encoders, nothing to do.
+ $encoder = function($value) { return $value; };
+ }
+ $res = array();
+ foreach ($data as $k => $v) {
+ $res[] = $encoder($k) . "\t" . $encoder($v);
+ }
+
+ return implode("\n", $res);
+ }
+
+ /**
+ * Decode TSV to plain array.
+ *
+ * @param mixed $data String data to decode
+ * @param mixed $encoding Encode type
+ * @access public
+ * @return array Decoded data
+ */
+ public function decodeTsvrpc($data, $encoding = null)
+ {
+ $decoders = array(
+ 'U' => function($value) { return urldecode($value); },
+ 'Q' => function($value) { return quoted_printable_decode($value); },
+ 'B' => function($value) { return base64_decode($value); }
+ );
+
+ if (isset($decoders[$encoding])) {
+ $decoder = $decoders[$encoding];
+ } else {
+ // When $encoding is not in $decoders, nothing to do.
+ $decoder = function($value) { return $value; };
+ }
+ $res = array();
+ if ($data === '') {
+ return $res;
+ }
+
+ $lines = explode("\n", $data);
+ foreach ($lines as $line) {
+ if ($line === '') {
+ continue;
+ }
+
+ list($k, $v) = array_map($decoder, explode("\t", $line));
+ $res[$k] = $v;
+ }
+
+ return $res;
+ }
+}
Net_KyotoTycoon/trunk/src/HTTP/TsvRpc/Util.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * TSV-RPC util.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc;
+
+/**
+ * TSV-RPC util.
+ *
+ * <pre>
+ * This module is port from Perl TSVRPC::Parser
+ * See also @link.
+ * </pre>
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/lib/TSVRPC/Parser.pm
+ */
+class Util
+{
+ /**
+ * Parse content-type.
+ *
+ * @param mixed $contentType Content-type
+ * @access public
+ * @return mixed B|U|Q|'' or null
+ */
+ public static function parseContentType($contentType)
+ {
+ $pattern = '#text/tab-separated-values(?:; colenc=([BUQ]))?#';
+ if (preg_match_all($pattern, $contentType, $match)) {
+ return isset($match[1][0]) ? $match[1][0] : '';
+ }
+
+ return null;
+ }
+}
Net_KyotoTycoon/trunk/src/HTTP/TsvRpc/Client.php
@@ -0,0 +1,222 @@
+<?php
+/**
+ * TSV-RPC client library.
+ *
+ * This module is port from Perl Cache::KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use HTTP\TsvRpc\Parser
+ * @use HTTP\TsvRpc\Util
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace HTTP\TsvRpc;
+use HTTP\TsvRpc\Parser,
+ HTTP\TsvRpc\Util,
+ HTTP\TsvRpc\Exception;
+
+/**
+ * Client
+ *
+ * <pre>
+ * This module is port from Perl Cache::KyotoTycoon.
+ * See also @link.
+ * </pre>
+ *
+ * @use HTTP\TsvRpc\Parser
+ * @use HTTP\TsvRpc\Util
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class Client
+{
+ /**
+ * Version.
+ */
+ const VERSION = '0.0.1';
+
+ /**
+ * Base url.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_base = null;
+
+ /**
+ * HTTP Client.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_client = null;
+
+ /**
+ * Content-Type parser.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_parser = null;
+
+ /**
+ * Last content data.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_lastContent = null;
+
+ /**
+ * Constructor
+ *
+ * @param array $args
+ * @access public
+ * @return void
+ */
+ public function __construct(array $args)
+ {
+ $base = '';
+ if (isset($args['base'])) {
+ $base = $args['base'];
+ } else {
+ throw Exception("Missing argument named 'base' for rpc base url.");
+ }
+ $base = rtrim($base, '\//') . '/';
+ $timeout = isset($args['timeout']) ? $args['timeout'] : 1;
+ $agent = isset($args['agent']) ?: __CLASS__ . '/' . self::VERSION;
+
+ $adapter = isset($args['adapter']) ?: 'HTTP_Request2_Adapter_Socket';
+ $config = array('adapter' => $adapter, 'timeout' => $timeout);
+ $client = new \HTTP_Request2(
+ null, \HTTP_Request2::METHOD_POST, $config
+ );
+ $client->setHeader('user-agent', $agent);
+
+ $this->_client = $client;
+ $this->_base = $base;
+ $this->_parser = new Parser();
+ }
+
+ /**
+ * Send request.
+ *
+ * @param mixed $method Rpc method
+ * @param mixed $args Args
+ * @param string $encoding B(base64), U(Urlencode), Q(Quoted printable)
+ * @access public
+ * @return mixed Status code and HTTP body
+ */
+ public function call($method, $args = array(), $encoding = 'B')
+ {
+ $content = $this->_parser->encodeTsvrpc($args, $encoding);
+ $client = $this->_client;
+ $uri = $this->_base . $method;
+ $headers = array(
+ 'Content-Type' => "text/tab-separated-values; colenc=$encoding",
+ 'Content-Length' => mb_strlen($content),
+ 'Connection' => 'Keep-Alive',
+ 'Keep-Alive' => 300,
+ );
+ $client->setHeader($headers)->setUrl($uri)->setBody($content);
+ $response = $client->send();
+ if ($response) {
+ $code = $response->getStatus();
+ $responseHeaders = $response->getHeader();
+ $contentType = $responseHeaders['content-type'];
+ $resEncoding = Util::parseContentType($contentType);
+
+ // Decode by content-type B|Q|U
+ $body = $this->_parser->decodeTsvrpc(
+ $response->getBody(), $resEncoding
+ );
+ $this->_lastContent = $body;
+ return array('code' => $code, 'body' => $body);
+ }
+
+ throw new Exception('Fail to call ' . $uri);
+ }
+
+ /**
+ * Get last content.
+ *
+ * <pre>
+ * This is a debug method.
+ * </pre>
+ *
+ * @access public
+ * @return mixed
+ */
+ public function getLastContent()
+ {
+ return $this->_lastContent;
+ }
+
+ /**
+ * Autoload class.
+ *
+ * @param mixed $class
+ * @access public
+ * @return void
+ */
+ public static function autoload($className)
+ {
+ // Autoload class.
+ // http://groups.google.com/group/php-standards/web/psr-0-final-proposal
+ if (!class_exists($className, false)) {
+ $className = ltrim($className, '\\');
+ $fileName = '';
+ $namespace = '';
+ if ($lastNsPos = strripos($className, '\\')) {
+ $namespace = substr($className, 0, $lastNsPos);
+ $className = substr($className, $lastNsPos + 1);
+ $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
+ }
+ $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+ require_once $fileName;
+ }
+ }
+}
Net_KyotoTycoon/trunk/src/HTTP/TsvRpc/Exception.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Exception for \HTTP\TsvRpc.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+
+namespace HTTP\TsvRpc;
+
+/**
+ * Exception.
+ *
+ * @use HTTP\TsvRpc
+ * @category HTTP
+ * @package HTTP\TsvRpc
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+class Exception extends \Exception
+{
+}
Net_KyotoTycoon/trunk/src/Net/KyotoTycoon/Cursor.php
@@ -0,0 +1,399 @@
+<?php
+/**
+ * Cursor class for KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net\KyotoTycoon
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net\KyotoTycoon;
+use Net\KyotoTycoon;
+
+/**
+ * Cursor class for KyotoTycoon.
+ *
+ * <pre>
+ * This module is port from Perl Cache::KyotoTycoon.
+ * See also @link.
+ * </pre>
+ *
+ * @use Net\KyotoTycoon
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+
+ */
+class Cursor
+{
+ /**
+ * Db.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_db = null;
+
+ /**
+ * Cursor.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_cursor = null;
+
+ /**
+ * Client.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_client = null;
+
+ /**
+ * Status Code.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_statusCode = null;
+
+ /**
+ * Construct.
+ *
+ * @param mixed $id
+ * @param mixed $db
+ * @param mixed $client
+ * @access public
+ * @return void
+ */
+ public function __construct($id, $db, $client)
+ {
+ $this->_db = $db;
+ $this->_client = $client;
+ $this->_cursor = $id;
+
+ // Status code.
+ $this->_statusCode = new StatusCode();
+ }
+
+ /**
+ * Get error message.
+ *
+ * @param mixed $code Status code
+ * @access private
+ * @return String Error message
+ */
+ private function _errmsg($code)
+ {
+ return $this->_statusCode->errmsg($code);
+ }
+
+ /**
+ * Call jump.
+ *
+ * <pre>
+ * Jump the cursor to the first record for forward scan.
+ * </pre>
+ *
+ * @param mixed $key
+ * @access public
+ * @return mixed
+ */
+ public function jump($key = null)
+ {
+ $args = array('DB' => $this->_db, 'CUR' => $this->_cursor);
+ if (!is_null($key)) {
+ $args['key'] = $key;
+ }
+ $response = $this->_client->call('cur_jump', $args);
+
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call jump_back.
+ *
+ * <pre>
+ * Jump the cursor to the last record for backward scan.
+ * </pre>
+ *
+ * @param mixed $key
+ * @access public
+ * @return mixed
+ */
+ public function jumpBack($key = null)
+ {
+ $args = array('DB' => $this->_db, 'CUR' => $this->_cursor);
+ if (!is_null($key)) {
+ $args['key'] = $key;
+ }
+ $response = $this->_client->call('cur_jump_back', $args);
+
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call step.
+ *
+ * <pre>
+ * Step the cursor to the next record.
+ * </pre>
+ *
+ * @access public
+ * @return mixed
+ */
+ public function step()
+ {
+ $args = array('CUR' => $this->_cursor);
+ $response = $this->_client->call('cur_step', $args);
+
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call step_back.
+ *
+ * <pre>
+ * Step the cursor to the previous record.
+ * </pre>
+ *
+ * @access public
+ * @return mixed
+ */
+ public function stepBack()
+ {
+ $args = array('CUR' => $this->_cursor);
+ $response = array('code' => 0, 'body' => null);
+ $response = $this->_client->call('cur_step_back', $args);
+
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call set_value.
+ *
+ * <pre>
+ * Set the value of the current record.
+ * </pre>
+ *
+ * @param mixed $value
+ * @param mixed $xt
+ * @param mixed $step
+ * @access public
+ * @return mixed
+ */
+ public function setValue($value, $xt = null, $step = null)
+ {
+ $args = array('CUR' => $this->_cursor, 'value' => $value);
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+ if (!is_null($step)) {
+ $args['step'] = '';
+ }
+
+ $response = $this->_client->call('cur_set_value', $args);
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call remove.
+ *
+ * <pre>
+ * Remove the current record.
+ * </pre>
+ *
+ * @access public
+ * @return mixed
+ */
+ public function remove()
+ {
+ $args = array('CUR' => $this->_cursor);
+ $response = $this->_client->call('cur_remove', $args);
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call get_key.
+ *
+ * <pre>
+ * Get the key of the current record.
+ * </pre>
+ *
+ * @param mixed $step
+ * @access public
+ * @return mixed
+ */
+ public function getKey($step = null)
+ {
+ $args = array('CUR' => $this->_cursor);
+ if (!is_null($step)) {
+ $args['step'] = '';
+ }
+ $response = $this->_client->call('cur_get_key', $args);
+
+ if ($response['code'] === 200) {
+ return $response['body']['key'];
+ } else if ($response['code'] === 450) {
+ return null;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call get_value.
+ *
+ * <pre>
+ * Get the value of the current record.
+ * </pre>
+ *
+ * @param mixed $step
+ * @access public
+ * @return mixed
+ */
+ public function getValue($step = null)
+ {
+ $args = array('CUR' => $this->_cursor);
+ if (!is_null($step)) {
+ $args['step'] = '';
+ }
+ $response = $this->_client->call('cur_get_value', $args);
+
+ if ($response['code'] === 200) {
+ return $response['body']['value'];
+ } else if ($response['code'] === 450) {
+ return null;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call get.
+ *
+ * <pre>
+ * Get a pair of the key and the value of the current record.
+ * </pre>
+ *
+ * @param mixed $step
+ * @access public
+ * @return mixed
+ */
+ public function get($step = null)
+ {
+ $args = array('CUR' => $this->_cursor);
+ if (!is_null($step)) {
+ $args['step'] = '';
+ }
+
+ $response = $this->_client->call('cur_get', $args);
+ if ($response['code'] === 200) {
+ return array($response['body']['key'], $response['body']['value']);
+ } else if ($response['code'] === 450) {
+ return null;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call delete.
+ *
+ * <pre>
+ * Delete the cursor immidiately.
+ * </pre>
+ *
+ * @access public
+ * @return mixed Fluent interface or error message.
+ */
+ public function delete()
+ {
+ $args = array('CUR' => $this->_cursor);
+ $response = $this->_client->call('cur_delete', $args);
+ if ($response['code'] === 200) {
+ return $this;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+}
Net_KyotoTycoon/trunk/src/Net/KyotoTycoon/Exception.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Exception for \Net\KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net
+ * @use KyotoTycoon
+ * @category Net
+ * @package \Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+
+namespace Net\KyotoTycoon;
+use Net,
+ KyotoTycoon;
+
+/**
+ * Exception.
+ *
+ * @use Net
+ * @use KyotoTycoon
+ * @category Net
+ * @package \Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ */
+class Exception extends \Exception
+{
+}
Net_KyotoTycoon/trunk/src/Net/KyotoTycoon/StatusCode.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Status code for \Net\KyotoTycoon.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net\KyotoTycoon
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+
+namespace Net\KyotoTycoon;
+use Net\KyotoTycoon;
+
+/**
+ * StatusCode
+ *
+ * @use Net\KyotoTycoon
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class StatusCode
+{
+ /**
+ * Status code.
+ *
+ * @var array
+ * @access private
+ */
+ private $_statusCode = array(
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing', // RFC 2518 (WebDAV)
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status', // RFC 2518 (WebDAV)
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Large',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Request Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 422 => 'Unprocessable Entity', // RFC 2518 (WebDAV)
+ 423 => 'Locked', // RFC 2518 (WebDAV)
+ 424 => 'Failed Dependency', // RFC 2518 (WebDAV)
+ 425 => 'No code', // WebDAV Advanced Collections
+ 426 => 'Upgrade Required', // RFC 2817
+ 449 => 'Retry with', // unofficial Microsoft
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ 506 => 'Variant Also Negotiates', // RFC 2295
+ 507 => 'Insufficient Storage', // RFC 2518 (WebDAV)
+ 509 => 'Bandwidth Limit Exceeded', // unofficial
+ 510 => 'Not Extended', // RFC 2774
+ );
+
+ /**
+ * Error message.
+ *
+ * @param mixed $code Status code
+ * @access private
+ * @return String Error message
+ */
+ public function errmsg($code)
+ {
+ $msg = isset($this->_statusCode[$code]) ?: 'Unknown';
+ return sprintf(
+ 'Net\KyotoTycoon unexpected response code: %s %s', $code, $msg
+ );
+ }
+}
Net_KyotoTycoon/trunk/src/Net/KyotoTycoon.php
@@ -0,0 +1,735 @@
+<?php
+/**
+ * KyotoTycoon client library.
+ *
+ * PHP version 5.3
+ *
+ * Copyright (c) 2010 Shinya Ohyanagi, All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Shinya Ohyanagi nor the names of his
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright (c) 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://fallabs.com/kyototycoon/
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+namespace Net;
+use Net\KyotoTycoon\StatusCode,
+ Net\KyotoTycoon\Exception,
+ Net\KyotoTycoon\Cursor,
+ HTTP\TsvRpc\Client;
+
+/**
+ * KyotoTycoon
+ *
+ * <pre>
+ * This module is port from Perl Cache::KyotoTycoon.
+ * See also @link.
+ * </pre>
+ *
+ * @use Net
+ * @category Net
+ * @package Net\KyotoTycoon
+ * @version $id$
+ * @copyright 2010 Shinya Ohyanagi
+ * @author Shinya Ohyanagi <sohyanagi@gmail.com>
+ * @license New BSD License
+ * @link http://fallabs.com/kyototycoon/
+ * @link http://search.cpan.org/~tokuhirom/Cache-KyotoTycoon/
+ */
+class KyotoTycoon
+{
+ /**
+ * Version.
+ */
+ const VERSION = '0.0.1';
+
+ /**
+ * Status code.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_statusCode = null;
+
+ /**
+ * Client.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_client = null;
+
+ /**
+ * Db.
+ *
+ * @var mixed
+ * @access private
+ */
+ private $_db = null;
+
+ /**
+ * Error message.
+ *
+ * @param mixed $code Status code.
+ * @access private
+ * @return String Error message.
+ */
+ private function _errmsg($code)
+ {
+ return $this->_statusCode->errmsg($code);
+ }
+
+ /**
+ * Create client to access KyotoTycoon.
+ *
+ * @param array $args
+ * @access public
+ * @return void
+ */
+ public function __construct(array $args = array())
+ {
+ spl_autoload_register(array(__CLASS__, 'autoload'));
+ $host = isset($args['host']) ? $args['host'] : '127.0.0.1';
+ $port = isset($args['port']) ? $args['port'] : 1978;
+ $base = "http://$host:$port/rpc/";
+ $timeout = isset($args['timeout']) ? $args['timeout'] : 1;
+ $client = new Client(
+ array(
+ 'timeout' => $timeout,
+ 'base' => $base
+ )
+ );
+
+ $this->_db = 0;
+ $this->_client = $client;
+ $this->_statusCode = new StatusCode();
+ }
+
+ /**
+ * Set TSV-RPC client.
+ *
+ * @param mixed $client TSV-RPC client
+ * @access public
+ * @return \Net\KyotoTycoon Fluent interface
+ */
+ public function setClient($client)
+ {
+ $this->_client = $client;
+ return $this;
+ }
+
+ /**
+ * Set db.
+ *
+ * @param mixed $db
+ * @access public
+ * @return \Net\KyotoTycoon Fluent interface.
+ */
+ public function db($db)
+ {
+ $this->_db = $db;
+ return $this;
+ }
+
+ /**
+ * Make cursor
+ *
+ * @param mixed $id
+ * @access public
+ * @return \Net\KyotoTycoon\Cursor
+ */
+ public function makeCursor($id)
+ {
+ $cursor = new Cursor($id, $this->_db, $this->_client);
+ return $cursor;
+ }
+
+ /**
+ * Call echo.
+ *
+ * <pre>
+ * Echo back the input data as the output data
+ * echo() is reserved name in PHP. This method is same as echo().
+ * </pre>
+ *
+ * @param mixed $args
+ * @access public
+ * @return mixed Response of RPC call
+ */
+ public function echoBack($args)
+ {
+ $response = $this->_client->call('echo', $args);
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return $response['body'];
+ }
+
+ /**
+ * Call report.
+ *
+ * <pre>
+ * Get the report of the server information.
+ * </pre>
+ *
+ * @access public
+ * @return mixed Response of RPC call
+ */
+ public function report()
+ {
+ $response = $this->_client->call('report');
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return $response['body'];
+ }
+
+ /**
+ * Call play_script.
+ *
+ * <pre>
+ * Call a procedure of the scripting extension.
+ * </pre>
+ *
+ * @param mixed $name
+ * @param array $input
+ * @access public
+ * @return mixed Response of RPC call
+ */
+ public function playScript($name, array $input)
+ {
+ $args = array('name' => $name);
+ foreach ($input as $k => $v) {
+ $args["_$k"] = $v;
+ }
+ $response = $this->_client->call('play_script', $args);
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+ $body = $response['body'];
+ $res = array();
+ foreach ($body as $k => $v) {
+ $res[ltrim($k, '_')] = $v;
+ }
+
+ return $res;
+ }
+
+ /**
+ * Call status.
+ *
+ * <pre>
+ * Get the miscellaneous status information.
+ * </pre>
+ *
+ * @access public
+ * @return mixed Response of RPC call
+ */
+ public function status()
+ {
+ $response = $this->_client->call('status', array('DB' => $this->_db));
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return $response['body'];
+ }
+
+ /**
+ * Call clear
+ *
+ * <pre>
+ * Remove all records.
+ * </pre>
+ *
+ * @access public
+ * @return mixed Fluent interface when clear success or error message.
+ */
+ public function clear()
+ {
+ $response = $this->_client->call('clear', array('DB' => $this->_db));
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Call synchronize
+ *
+ * <pre>
+ * Synchronize updated contents with the file and the device.
+ * </pre>
+ *
+ * @param mixed $hard
+ * @param mixed $command
+ * @access public
+ * @return mixed Status 200 return true, status 450 return false
+ */
+ public function synchronize($hard = null, $command = null)
+ {
+ $args = array('DB' => $this->_db);
+ $args['hard'] = $hard;
+ if (!is_null($command)) {
+ $args['command'] = $command;
+ }
+
+ $response = $this->_client->call('synchronize', $args);
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call set.
+ *
+ * <pre>
+ * Set the value of a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @param mixed $value
+ * @param mixed $xt
+ * @access public
+ * @return mixed Fluent interface or error message
+ */
+ public function set($key, $value, $xt = null)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+
+ $response = $this->_client->call('set', $args);
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Call add.
+ *
+ * <pre>
+ * Add a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @param mixed $value
+ * @param mixed $xt
+ * @access public
+ * @return mixed true:Success to add, false: Fail to add or error message
+ */
+ public function add($key, $value, $xt = null)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+
+ $response = $this->_client->call('add', $args);
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call replace.
+ *
+ * <pre>
+ * Replace a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @param mixed $value
+ * @param mixed $xt
+ * @access public
+ * @return mixed True:success, False:fail or error message.
+ */
+ public function replace($key, $value, $xt = null)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+
+ $response = $this->_client->call('replace', $args);
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ return $this->_errmsg($response['code']);
+ }
+
+ /**
+ * Call append.
+ *
+ * <pre>
+ * Set the value of a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @param mixed $value
+ * @param mixed $xt
+ * @access public
+ * @return mixed Fluent interface or error message
+ */
+ public function append($key, $value, $xt = null)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key, 'value' => $value);
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+ $response = $this->_client->call('append', $args);
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Call increment.
+ *
+ * <pre>
+ * Add a number to the numeric integer value of a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @param mixed $num
+ * @param mixed $xt
+ * @access public
+ * @return mixed Response of RPC call
+ */
+ public function increment($key, $num, $xt = null)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key, 'num' => $num);
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+ $response = $this->_client->call('increment', $args);
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return intval($response['body']['num']);
+ }
+
+ /**
+ * Call incrementDouble.
+ *
+ * <pre>
+ * Add a number to the numeric double value of a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @param mixed $num
+ * @param mixed $xt
+ * @access public
+ * @return mixed Response of RPC call
+ */
+ public function incrementDouble($key, $num, $xt = null)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key, 'num' => $num);
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+ $response = $this->_client->call('increment_double', $args);
+ if ($response['code'] !== 200) {
+ return $this->_errmsg($response['code']);
+ }
+
+ return doubleval($response['body']['num']);
+ }
+
+ /**
+ * Call cas.
+ *
+ * <pre>
+ * Perform compare-and-swap.
+ * </pre>
+ *
+ * @param mixed $key
+ * @param mixed $oval
+ * @param mixed $nval
+ * @param mixed $xt
+ * @access public
+ * @throws \Net\KyotoTycoon\Exception
+ * @return Bool True: Status code is 200, False: Status code is 450
+ */
+ public function cas($key, $oval = null, $nval = null, $xt = null)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key);
+ $list = array('oval' => $oval, 'nval' => $nval, 'xt' => $xt);
+
+ foreach ($list as $k => $v) {
+ if (!is_null($v)) {
+ $args[$k] = $v;
+ }
+ }
+ $response = $this->_client->call('cas', $args);
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ throw new Exception($this->_errmsg($response['code']));
+ }
+
+ /**
+ * Call remove.
+ *
+ * <pre>
+ * Remove a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @access public
+ * @throws \Net\KyotoTycoon\Exception
+ * @return Bool True: Status code is 200, False: Status code is 450.
+ */
+ public function remove($key)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key);
+ $response = $this->_client->call('remove', $args);
+
+ if ($response['code'] === 200) {
+ return true;
+ } else if ($response['code'] === 450) {
+ return false;
+ }
+
+ throw new Exception($this->_errmsg($response['code']));
+ }
+
+ /**
+ * Call get.
+ *
+ * <pre>
+ * Retrieve the value of a record.
+ * </pre>
+ *
+ * @param mixed $key
+ * @access public
+ * @throws \Net\KyotoTycoon\Exception
+ * @return mixed Response of RPC call
+ */
+ public function get($key)
+ {
+ $args = array('DB' => $this->_db, 'key' => $key);
+ $response = $this->_client->call('get', $args);
+
+ if ($response['code'] === 200) {
+ return $response['body']['value'];
+ } else if ($response['code'] === 450) {
+ return null;
+ }
+
+ throw new Exception($this->_errmsg($response['code']));
+ }
+
+ /**
+ * Call set_bulk.
+ *
+ * <pre>
+ * Store records at once.
+ * </pre>
+ *
+ * @param array $vals
+ * @param mixed $xt
+ * @access public
+ * @throws \Net\KyotoTycoon\Exception
+ * @return mixed Response of RPC call
+ */
+ public function setBulk(array $vals, $xt = null)
+ {
+ $args = array('DB' => $this->_db);
+ foreach ($vals as $k => $v) {
+ $args["_$k"] = $v;
+ }
+ if (!is_null($xt)) {
+ $args['xt'] = $xt;
+ }
+ $response = $this->_client->call('set_bulk', $args);
+ if ($response['code'] !== 200) {
+ throw new Exception($this->_errmsg($response['code']));
+ }
+
+ return intval($response['body']['num']);
+ }
+
+ /**
+ * Call remove_bulk.
+ *
+ * <pre>
+ * Store records at once.
+ * </pre>
+ *
+ * @param mixed $keys
+ * @access public
+ * @throws \Net\KyotoTycoon\Exception
+ * @return mixed
+ */
+ public function removeBulk($keys)
+ {
+ $args = array('DB' => $this->_db);
+ foreach ($keys as $k => $v) {
+ $args["_$k"] = '';
+ }
+
+ $response = $this->_client->call('remove_bulk', $args);
+ if ($response['code'] !== 200) {
+ throw new Exception($this->_errmsg($response['code']));
+ }
+
+ return intval($response['body']['num']);
+ }
+
+ /**
+ * Call get_bulk.
+ *
+ * <pre>
+ * Retrieve records at once.
+ * </pre>
+ *
+ * @param array $keys
+ * @access public
+ * @throws \Net\KyotoTycoon\Exception
+ * @return mixed Response of RPC call
+ */
+ public function getBulk(array $keys)
+ {
+ $args = array('DB' => $this->_db);
+ foreach ($keys as $k) {
+ $args["_$k"] = '';
+ }
+
+ $response = $this->_client->call('get_bulk', $args);
+ if ($response['code'] !== 200) {
+ throw new Exception($this->_errmsg($response['code']));
+ }
+ $body = $response['body'];
+ $ret = array();
+ foreach ($body as $k => $v) {
+ if (preg_match('/^_(.+)$/', $k, $match)) {
+ $ret[$match[1]] = $v;
+ }
+ }
+
+ if (intval($body['num']) !== count($ret)) {
+ throw new Exception('Fatal error');
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Call vacuum.
+ *
+ * <pre>
+ * Scan the database and eliminate regions of expired records.
+ * </pre>
+ *
+ * @param mixed $step
+ * @access public
+ * @return \Net\KyotoTycoon Fluent interface.
+ */
+ public function vacuum($step = null)
+ {
+ $args = array('DB' => $this->_db);
+ if (!is_null($step)) {
+ $args['step'] = $step;
+ }
+ $response = $this->_client->call('vacuum', $args);
+ if ($response['code'] !== 200) {
+ throw new Exception($this->_errmsg($response['code']));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get last content.
+ *
+ * @access public
+ * @return mixed Last content or null
+ */
+ public function getLastContent()
+ {
+ return $this->_client->getLastContent();
+ }
+
+ /**
+ * Autoload class.
+ *
+ * @param mixed $class
+ * @access public
+ * @return void
+ */
+ public static function autoload($className)
+ {
+ // Autoload class.
+ // http://groups.google.com/group/php-standards/web/psr-0-final-proposal
+ if (!class_exists($className, false)) {
+ $className = ltrim($className, '\\');
+ $fileName = '';
+ $namespace = '';
+ if ($lastNsPos = strripos($className, '\\')) {
+ $namespace = substr($className, 0, $lastNsPos);
+ $className = substr($className, $lastNsPos + 1);
+ $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
+ }
+ $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+
+ require_once $fileName;
+ }
+ }
+}
Net_KyotoTycoon/trunk/examples/simple.php
@@ -0,0 +1,12 @@
+<?php
+// Start KyotoTycoon port 19780
+// $ ktserver -port 19780
+error_reporting(E_ALL | E_STRICT);
+$src = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'src';
+set_include_path(get_include_path() . $src);
+
+require_once 'Net/KyotoTycoon.php';
+$kt = new \Net\KyotoTycoon(array('port' => 19780));
+$kt->set('test_php', 'Hello KyotoTycoon!!');
+var_dump($kt->get('test_php'));
+$kt->clear();