[node-osmium] 03/10: Imported Upstream version 0.1.1

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Mar 6 17:09:12 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository node-osmium.

commit 80ef48b13d5f2b35469efc5a28b3dd7c42e25b32
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Mar 6 15:16:29 2015 +0100

    Imported Upstream version 0.1.1
---
 .travis.yml                         |  12 +-
 Makefile                            |   8 +-
 README.md                           |  98 +++++++------
 binding.gyp                         |   9 +-
 configure                           |   3 -
 demo/geojson-stream/index.js        |   9 +-
 package.json                        |  15 +-
 src/buffer.hpp                      |   9 +-
 src/{file.hpp => file_wrap.cpp}     |  63 ++-------
 src/file_wrap.hpp                   |  59 ++++++++
 src/handler.cpp                     | 170 ++++++++++++++++++++++
 src/handler.hpp                     | 274 ++----------------------------------
 src/node_osmium.cpp                 |  25 +++-
 src/osm_node_wrap.cpp               |  78 ++++++++++
 src/osm_node_wrap.hpp               |  55 ++++++++
 src/osm_object_wrap.cpp             |  28 ++++
 src/osm_object_wrap.hpp             |  42 ++++++
 src/osm_relation_wrap.cpp           |  88 ++++++++++++
 src/osm_relation_wrap.hpp           |  56 ++++++++
 src/osm_way_wrap.cpp                | 108 ++++++++++++++
 src/osm_way_wrap.hpp                |  55 ++++++++
 src/{reader.hpp => reader_wrap.cpp} | 140 +++++++-----------
 src/reader_wrap.hpp                 |  68 +++++++++
 test/osmium.test.js                 |  27 +++-
 24 files changed, 1017 insertions(+), 482 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 999579c..0f23dda 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,9 +2,14 @@ language: node_js
 
 node_js:
  - "0.10"
- - "0.8"
 
 before_install:
+ # first test install of binary
+ - npm install --verbose
+ - make test
+
+install:
+ # next test source compile, so get dependencies
  - sudo apt-add-repository --yes ppa:mapnik/boost
  - sudo apt-add-repository --yes ppa:ubuntu-toolchain-r/test
  - sudo apt-get -y update -qq
@@ -14,12 +19,9 @@ before_install:
  - make && sudo make install
  - cd ../../
 
-install:
- - npm install mocha
-
 before_script:
  - git clone https://github.com/osmcode/libosmium.git ../libosmium
- - CXX=g++-4.7 npm install --verbose
+ - CXX=g++-4.7 npm install
 
 script:
  - make test
diff --git a/Makefile b/Makefile
index 32df7b4..bca59f3 100755
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,17 @@
 all: osmium.node
 
-osmium.node:
+./build:
+	`npm explore npm -g -- pwd`/bin/node-gyp-bin/node-gyp configure
+
+osmium.node: binding.gyp Makefile ./build
 	`npm explore npm -g -- pwd`/bin/node-gyp-bin/node-gyp --verbose build
 
 clean:
-	@rm -rf ./build
+	rm -rf ./build
 	rm -f lib/osmium.node
 
 rebuild:
 	@make clean
-	@./configure
 	@make
 
 test/data/berlin-latest.osm.pbf:
diff --git a/README.md b/README.md
index 042ad4c..a69b503 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,67 @@
 # node-osmium
 
-Node.js bindings to [libosmium](https://github.com/osmcode/libosmium).
+Fast and flexible Javascript library for working with OpenStreetMap data.
+
+Provides a bindings to the [libosmium](https://github.com/osmcode/libosmium) C++ library.
 
 [![Build Status](https://secure.travis-ci.org/osmcode/node-osmium.png)](http://travis-ci.org/osmcode/node-osmium)
 
 # Depends
 
- - Compiler that supports `-std=c++11` (>= clang++ 3.2 || >= g++ 4.8)
  - Node.js v0.10.x
+
+# Installing
+
+By default, binaries are provided and no external depedencies and no compile is needed.
+
+Just do:
+
+    npm install osmium
+
+We currently provide binaries for 64 bit OS X and 64 bit Linux. Running `npm install` on other
+platforms will fall back to a source compile (see `Developing` below for build details).
+
+# Usage
+
+## Get the bounds of an `.osm` file
+
+```js
+var osmium = require('osmium');
+var file = new osmium.File("test/data/winthrop.osm");
+var reader = new osmium.Reader(file);
+console.log(reader.header())
+{ generator: 'CGImap 0.2.0',
+  bounds: [ -120.2024, 48.4636, -120.1569, 48.4869 ] }
+```
+
+## Parse a `.pbf` file and create a node handler callback to count total nodes
+
+```js
+var osmium = require('osmium');
+var file = new osmium.File("test/data/winthrop.osm");
+var reader = new osmium.Reader(file);
+var handler = new osmium.Handler();
+var nodes = 0;
+handler.on('node',function(node) {
+    ++nodes;
+});
+reader.apply(handler);
+console.log(nodes);
+1525
+```
+
+# Developing
+
+If you wish to develop on `node-osmium` you can check out the code and then build like:
+
+    git clone https://github.com/osmcode/node-osmium.git
+    cd node-osmium
+    make
+    make test
+
+## Source build dependencies
+
+ - Compiler that supports `-std=c++11` (>= clang++ 3.2 || >= g++ 4.8)
  - Boost >= 1.49 with development headers
  - OSM-Binary
  - Protocol buffers
@@ -42,43 +96,3 @@ Set depedencies up on OS X like:
     ./scripts/build_osm-pbf.sh
     # NOTE: in the same terminal then run the build commands
     # Or from a different terminal re-run `source MacOSX.sh`
-
-# Building
-
-To build the bindings:
-
-    git clone https://github.com/osmcode/libosmium.git
-    git clone https://github.com/osmcode/node-osmium.git
-    cd node-osmium
-    npm install
-
-# Testing
-
-Run the tests like:
-
-    npm install mocha
-    make test
-
-# Troubleshooting
-
-If you hit a test error like the below it means you need to run `make test` instead of just `npm test` so that the test data is downloaded:
-
-    1) osmium should be able to create an osmium.Reader:
-         TypeError: Open failed
-
-If you hit an error like the below it means you need a more recent compiler that implements the C++11 language standard
-
-    cc1plus: error: unrecognized command line option ‘-std=c++11’
-
-This error indicates you need the boost development headers installed:
-
-    ../../include/osmium/osm/location.hpp:40:31: fatal error: boost/operators.hpp: No such file or directory
-
-An error like this indicates that your compiler is too old and does not support all needed c++11 features
-
-    ../../include/osmium/io/header.hpp:55:51: sorry, unimplemented: non-static data member initializers
-    ../../include/osmium/io/header.hpp:55:51: error: ISO C++ forbids in-class initialization of non-const static member ‘m_has_multiple_object_versions’
-
-And error like this indicates that you need to do `export CXXFLAGS=-fPIC` and then recompile `libosmpbf`:
-
-    /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libosmpbf.a(fileformat.pb.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
diff --git a/binding.gyp b/binding.gyp
index 3adfc7a..e262a27 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -8,7 +8,14 @@
     {
       "target_name": "<(module_name)",
       "sources": [
-        "src/node_osmium.cpp"
+        "src/node_osmium.cpp",
+        "src/handler.cpp",
+        "src/file_wrap.cpp",
+        "src/reader_wrap.cpp",
+        "src/osm_object_wrap.cpp",
+        "src/osm_node_wrap.cpp",
+        "src/osm_way_wrap.cpp",
+        "src/osm_relation_wrap.cpp"
       ],
       "include_dirs": [
           "../libosmium/include/",
diff --git a/configure b/configure
deleted file mode 100755
index d0184d1..0000000
--- a/configure
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-`npm explore npm -g -- pwd`/bin/node-gyp-bin/node-gyp configure $@
\ No newline at end of file
diff --git a/demo/geojson-stream/index.js b/demo/geojson-stream/index.js
index fac9e63..b1da769 100755
--- a/demo/geojson-stream/index.js
+++ b/demo/geojson-stream/index.js
@@ -15,8 +15,13 @@ var argv = require('minimist')(process.argv, {
     string: 'output',
 });
 
-if (!argv.output || typeof(argv.output) != 'string') throw new Error('--output argument required (path to a new file or the keyword "stdout")');
-if (!argv.input || typeof(argv.input) != 'string') throw new Error('--input argument required (path to an osm file)');
+function stop(msg) {
+    console.error(msg);
+    process.exit(-1);
+}
+
+if (!argv.output || typeof(argv.output) != 'string') stop('--output argument required (path to a new file or the keyword "stdout")');
+if (!argv.input || typeof(argv.input) != 'string') stop('--input argument required (path to an osm file)');
 
 var reader = new osmium.Reader(argv.input);
 
diff --git a/package.json b/package.json
index d496fcd..f2cd1de 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
     "contributors": [
         "Jochen Topf <joto>"
     ],
-    "version": "0.1.0",
+    "version": "0.1.1",
     "main": "./lib/osmium.js",
     "bugs": {
         "email": "dane at mapbox.com",
@@ -23,14 +23,25 @@
         "type": "git",
         "url": "git://github.com/osmcode/node-osmium.git"
     },
-    "licenses": [ { "type": "Boost" } ],
+    "binary": {
+        "module_name": "osmium",
+        "module_path": "./lib",
+        "remote_uri": "http://node-osmium.s3.amazonaws.com",
+        "template": "{module_name}-v{major}.{minor}.{patch}-{node_abi}-{platform}-{arch}.tar.gz"
+    },
+    "dependencies": {
+        "node-pre-gyp": "~0.1.4"
+    },
+    "bundledDependencies":["node-pre-gyp"],
     "devDependencies": {
         "mocha": "*"
     },
+    "licenses": [ { "type": "Boost" } ],
     "engines": {
         "node": ">= 0.6.13 < 0.11.0"
     },
     "scripts": {
+        "install": "node-pre-gyp rebuild",
         "test": "mocha -R spec"
     }
 }
diff --git a/src/buffer.hpp b/src/buffer.hpp
index 43c17db..ccb28a1 100644
--- a/src/buffer.hpp
+++ b/src/buffer.hpp
@@ -1,7 +1,10 @@
+// c++11
+#include <sstream>
+
 // v8
 #include <v8.h>
 
-// node
+// node.js
 #include <node.h>
 #include <node_version.h>
 #include <node_object_wrap.h>
@@ -21,8 +24,8 @@ namespace node_osmium {
 
         static Persistent<FunctionTemplate> constructor;
         static void Initialize(Handle<Object> target);
-        static Handle<Value> New(Arguments const& args);
-        static Handle<Value> dump(Arguments const& args);
+        static Handle<Value> New(const Arguments& args);
+        static Handle<Value> dump(const Arguments& args);
         Buffer(reader_ptr reader);
         void _ref() {
             Ref();
diff --git a/src/file.hpp b/src/file_wrap.cpp
similarity index 59%
rename from src/file.hpp
rename to src/file_wrap.cpp
index b2b10eb..c3abc55 100644
--- a/src/file.hpp
+++ b/src/file_wrap.cpp
@@ -1,71 +1,24 @@
 
-#include <memory>
-#include <string>
-
-// v8
-#include <v8.h>
-
-// node
-#include <node.h>
-#include <node_version.h>
-#include <node_object_wrap.h>
-
-// osmium
-#include <osmium/io/file.hpp>
-
-using namespace v8;
+#include "file_wrap.hpp"
 
 namespace node_osmium {
 
-    typedef std::shared_ptr<osmium::io::File> file_ptr;
-
-    class File : public node::ObjectWrap {
-
-    public:
-
-        static Persistent<FunctionTemplate> constructor;
-        static void Initialize(Handle<Object> target);
-        static Handle<Value> New(Arguments const& args);
-
-        File(const std::string& filename = "", const std::string& format = "");
-
-        void _ref() {
-            Ref();
-        }
-
-        void _unref() {
-            Unref();
-        }
-
-        file_ptr get() {
-            return this_;
-        }
-
-    private:
-
-        ~File() {
-        }
-
-        file_ptr this_;
-
-    };
-
-    Persistent<FunctionTemplate> File::constructor;
+    Persistent<FunctionTemplate> FileWrap::constructor;
 
-    void File::Initialize(Handle<Object> target) {
+    void FileWrap::Initialize(Handle<Object> target) {
         HandleScope scope;
-        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(File::New));
+        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(FileWrap::New));
         constructor->InstanceTemplate()->SetInternalFieldCount(1);
         constructor->SetClassName(String::NewSymbol("File"));
         target->Set(String::NewSymbol("File"), constructor->GetFunction());
     }
 
-    File::File(const std::string& filename, const std::string& format) :
+    FileWrap::FileWrap(const std::string& filename, const std::string& format) :
         ObjectWrap(),
         this_(std::make_shared<osmium::io::File>(filename, format)) {
     }
 
-    Handle<Value> File::New(Arguments const& args) {
+    Handle<Value> FileWrap::New(const Arguments& args) {
         HandleScope scope;
         if (!args.IsConstructCall()) {
             return ThrowException(Exception::Error(String::New("Cannot call constructor as function, you need to use 'new' keyword")));
@@ -89,10 +42,10 @@ namespace node_osmium {
                 }
                 format = *String::Utf8Value(args[1]);
             }
-            File* q = new File(filename, format);
+            FileWrap* q = new FileWrap(filename, format);
             q->Wrap(args.This());
             return args.This();
-        } catch (std::exception const& ex) {
+        } catch (const std::exception& ex) {
             return ThrowException(Exception::TypeError(String::New(ex.what())));
         }
         return Undefined();
diff --git a/src/file_wrap.hpp b/src/file_wrap.hpp
new file mode 100644
index 0000000..6a521c6
--- /dev/null
+++ b/src/file_wrap.hpp
@@ -0,0 +1,59 @@
+#ifndef FILE_WRAP_HPP
+#define FILE_WRAP_HPP
+
+// c++11
+#include <exception>
+#include <memory>
+#include <string>
+
+// v8
+#include <v8.h>
+
+// node.js
+#include <node.h>
+#include <node_version.h>
+#include <node_object_wrap.h>
+
+// osmium
+#include <osmium/io/file.hpp>
+
+using namespace v8;
+
+namespace node_osmium {
+
+    typedef std::shared_ptr<osmium::io::File> file_ptr;
+
+    class FileWrap : public node::ObjectWrap {
+
+    public:
+
+        static Persistent<FunctionTemplate> constructor;
+        static void Initialize(Handle<Object> target);
+        static Handle<Value> New(const Arguments& args);
+
+        FileWrap(const std::string& filename = "", const std::string& format = "");
+
+        void _ref() {
+            Ref();
+        }
+
+        void _unref() {
+            Unref();
+        }
+
+        file_ptr get() {
+            return this_;
+        }
+
+    private:
+
+        ~FileWrap() {
+        }
+
+        file_ptr this_;
+
+    };
+
+} // namespace node_osmium
+
+#endif // FILE_WRAP_HPP
diff --git a/src/handler.cpp b/src/handler.cpp
new file mode 100644
index 0000000..77d52c9
--- /dev/null
+++ b/src/handler.cpp
@@ -0,0 +1,170 @@
+
+#include "handler.hpp"
+#include "osm_node_wrap.hpp"
+#include "osm_way_wrap.hpp"
+#include "osm_relation_wrap.hpp"
+
+namespace node_osmium {
+
+    Persistent<FunctionTemplate> JSHandler::constructor;
+
+    void JSHandler::Initialize(Handle<Object> target) {
+        HandleScope scope;
+        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(JSHandler::New));
+        constructor->InstanceTemplate()->SetInternalFieldCount(1);
+        constructor->SetClassName(String::NewSymbol("Handler"));
+        NODE_SET_PROTOTYPE_METHOD(constructor, "on", on);
+        NODE_SET_PROTOTYPE_METHOD(constructor, "options", options);
+        target->Set(String::NewSymbol("Handler"), constructor->GetFunction());
+    }
+
+    JSHandler::JSHandler() :
+        ObjectWrap(),
+        node_callback_for_tagged_only(false),
+        done_cb() {
+        done_cb.Clear();
+    }
+
+    JSHandler::~JSHandler() {
+        if (!done_cb.IsEmpty()) {
+            done_cb.Dispose();
+        }
+        if (!node_cb.IsEmpty()) {
+            node_cb.Dispose();
+        }
+        if (!way_cb.IsEmpty()) {
+            way_cb.Dispose();
+        }
+        if (!relation_cb.IsEmpty()) {
+            relation_cb.Dispose();
+        }
+    }
+
+    Handle<Value> JSHandler::New(const Arguments& args) {
+        HandleScope scope;
+        if (args[0]->IsExternal()) {
+            Local<External> ext = Local<External>::Cast(args[0]);
+            void* ptr = ext->Value();
+            JSHandler* b =  static_cast<JSHandler*>(ptr);
+            b->Wrap(args.This());
+            return args.This();
+        } else {
+            JSHandler* h = new JSHandler();
+            h->Wrap(args.This());
+            return args.This();
+        }
+        return Undefined();
+    }
+
+    Handle<Value> JSHandler::options(const Arguments& args) {
+        if (args.Length() == 1) {
+            if (args[0]->IsObject()) {
+                Local<Value> tagged_nodes_only = args[0]->ToObject()->Get(String::New("tagged_nodes_only"));
+                if (tagged_nodes_only->IsBoolean()) {
+                    JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(args.This());
+                    handler->node_callback_for_tagged_only = tagged_nodes_only->BooleanValue();
+                }
+            }
+        }
+        return Undefined();
+    }
+
+    Handle<Value> JSHandler::on(const Arguments& args) {
+        HandleScope scope;
+        if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsFunction()) {
+            return ThrowException(Exception::TypeError(String::New("please provide an event name and callback function")));
+        }
+        std::string callback_name = *String::Utf8Value(args[0]->ToString());
+        Local<Function> callback = Local<Function>::Cast(args[1]);
+        if (callback->IsNull() || callback->IsUndefined()) {
+            return ThrowException(Exception::TypeError(String::New("please provide a valid callback function for second arg")));
+        }
+        JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(args.This());
+        if (callback_name == "node") {
+            if (!handler->node_cb.IsEmpty()) {
+                handler->node_cb.Dispose();
+            }
+            handler->node_cb = Persistent<Function>::New(callback);
+        } else if (callback_name == "way") {
+            if (!handler->way_cb.IsEmpty()) {
+                handler->way_cb.Dispose();
+            }
+            handler->way_cb = Persistent<Function>::New(callback);
+        } else if (callback_name == "relation") {
+            if (!handler->relation_cb.IsEmpty()) {
+                handler->relation_cb.Dispose();
+            }
+            handler->relation_cb = Persistent<Function>::New(callback);
+        } else if (callback_name == "done") {
+            if (!handler->done_cb.IsEmpty()) {
+                handler->done_cb.Dispose();
+            }
+            handler->done_cb = Persistent<Function>::New(callback);
+        }
+        return scope.Close(Undefined());
+    }
+
+    void JSHandler::dispatch_object(const osmium::io::InputIterator<osmium::io::Reader, osmium::Object>& it) {
+        HandleScope scope;
+        switch (it->type()) {
+            case osmium::item_type::node:
+                if (!node_cb.IsEmpty() && (!node_callback_for_tagged_only || !it->tags().empty())) {
+                    const int argc = 1;
+
+                    Handle<Value> ext = External::New(new OSMNodeWrap(it));
+                    Local<Object> obj = OSMNodeWrap::constructor->GetFunction()->NewInstance(1, &ext);
+                    Local<Value> argv[argc] = { obj };
+
+                    TryCatch trycatch;
+                    Handle<Value> v = node_cb->Call(Context::GetCurrent()->Global(), argc, argv);
+                    if (v.IsEmpty()) {
+                        Handle<Value> exception = trycatch.Exception();
+                        String::AsciiValue exception_str(exception);
+                        printf("Exception: %s\n", *exception_str);
+                        exit(1);
+                    }
+                }
+                break;
+            case osmium::item_type::way:
+                if (!way_cb.IsEmpty()) {
+                    const int argc = 1;
+
+                    Handle<Value> ext = External::New(new OSMWayWrap(it));
+                    Local<Object> obj = OSMWayWrap::constructor->GetFunction()->NewInstance(1, &ext);
+                    Local<Value> argv[argc] = { obj };
+
+                    TryCatch trycatch;
+                    Handle<Value> v = way_cb->Call(Context::GetCurrent()->Global(), argc, argv);
+                    if (v.IsEmpty()) {
+                        Handle<Value> exception = trycatch.Exception();
+                        String::AsciiValue exception_str(exception);
+                        printf("Exception: %s\n", *exception_str);
+                        exit(1);
+                    }
+                }
+                break;
+            case osmium::item_type::relation:
+                if (!relation_cb.IsEmpty()) {
+                    const int argc = 1;
+
+                    Handle<Value> ext = External::New(new OSMRelationWrap(it));
+                    Local<Object> obj = OSMRelationWrap::constructor->GetFunction()->NewInstance(1, &ext);
+                    Local<Value> argv[argc] = { obj };
+
+                    TryCatch trycatch;
+                    Handle<Value> v = relation_cb->Call(Context::GetCurrent()->Global(), argc, argv);
+                    if (v.IsEmpty()) {
+                        Handle<Value> exception = trycatch.Exception();
+                        String::AsciiValue exception_str(exception);
+                        printf("Exception: %s\n", *exception_str);
+                        exit(1);
+                    }
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+} // namespace node_osmium
+
diff --git a/src/handler.hpp b/src/handler.hpp
index d997804..351f319 100644
--- a/src/handler.hpp
+++ b/src/handler.hpp
@@ -1,11 +1,10 @@
 // c++11
-#include <memory>
-#include <iostream>
+#include <string>
 
 // v8
 #include <v8.h>
 
-// node
+// node.js
 #include <node.h>
 #include <node_version.h>
 #include <node_object_wrap.h>
@@ -14,6 +13,8 @@
 // osmium
 #include <osmium/handler.hpp>
 #include <osmium/osm.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/io/reader.hpp>
 #include <osmium/geom/wkb.hpp>
 #include <osmium/geom/wkt.hpp>
 
@@ -21,15 +22,15 @@ namespace node_osmium {
 
     using namespace v8;
 
-    class JSHandler : public node::ObjectWrap, public osmium::handler::Handler {
+    class JSHandler : public node::ObjectWrap {
 
     public:
 
         static Persistent<FunctionTemplate> constructor;
         static void Initialize(Handle<Object> target);
-        static Handle<Value> New(Arguments const& args);
-        static Handle<Value> on(Arguments const& args);
-        static Handle<Value> options(Arguments const& args);
+        static Handle<Value> New(const Arguments& args);
+        static Handle<Value> on(const Arguments& args);
+        static Handle<Value> options(const Arguments& args);
         JSHandler();
 
         void _ref() {
@@ -40,163 +41,7 @@ namespace node_osmium {
             Unref();
         }
 
-        void node(const osmium::Node& node) {
-            HandleScope scope;
-            if (!node_cb.IsEmpty() && (!node_callback_for_tagged_only || !node.tags().empty())) {
-                const int argc = 1;
-                Local<Object> obj = Object::New();
-                obj->Set(String::NewSymbol("id"), Number::New(node.id()));
-                obj->Set(String::NewSymbol("version"), Number::New(node.version()));
-                obj->Set(String::NewSymbol("visible"), Boolean::New(node.visible()));
-                obj->Set(String::NewSymbol("changeset"), Number::New(node.changeset()));
-                obj->Set(String::NewSymbol("timestamp"), Number::New(node.timestamp()));
-                std::string iso { node.timestamp().to_iso() };
-                obj->Set(String::NewSymbol("timestamp_iso"), String::New(iso.c_str()));
-                obj->Set(String::NewSymbol("uid"), Number::New(node.uid()));
-                obj->Set(String::NewSymbol("user"), String::New(node.user()));
-                obj->Set(String::NewSymbol("lon"), Number::New(node.lon()));
-                obj->Set(String::NewSymbol("lat"), Number::New(node.lat()));
-
-                {
-                    std::string wkb { wkb_factory.create_point(node) };
-#if NODE_VERSION_AT_LEAST(0, 10, 0)
-                    obj->Set(String::NewSymbol("wkb"), node::Buffer::New(wkb.data(), wkb.size())->handle_);
-#else
-                    obj->Set(String::NewSymbol("wkb"), node::Buffer::New(const_cast<char*>(wkb.data()), wkb.size())->handle_);
-#endif
-                }
-
-                {
-                    std::string wkt { wkt_factory.create_point(node) };
-                    obj->Set(String::NewSymbol("wkt"), String::New(wkt.c_str()));
-                }
-
-                Local<Object> tags = Object::New();
-                for (auto& tag : node.tags()) {
-                    tags->Set(String::NewSymbol(tag.key()), String::New(tag.value()));
-                }
-                obj->Set(String::NewSymbol("tags"), tags);
-
-                Local<Value> argv[argc] = { obj };
-
-                TryCatch trycatch;
-                Handle<Value> v = node_cb->Call(Context::GetCurrent()->Global(), argc, argv);
-                if (v.IsEmpty()) {
-                    Handle<Value> exception = trycatch.Exception();
-                    String::AsciiValue exception_str(exception);
-                    printf("Exception: %s\n", *exception_str);
-                    exit(1);
-                }
-            }
-        }
-
-        void way(const osmium::Way& way) {
-            HandleScope scope;
-            if (!way_cb.IsEmpty()) {
-                const int argc = 1;
-                Local<Object> obj = Object::New();
-                obj->Set(String::NewSymbol("id"), Number::New(way.id()));
-                obj->Set(String::NewSymbol("version"), Number::New(way.version()));
-                obj->Set(String::NewSymbol("visible"), Boolean::New(way.visible()));
-                obj->Set(String::NewSymbol("changeset"), Number::New(way.changeset()));
-                obj->Set(String::NewSymbol("timestamp"), Number::New(way.timestamp()));
-                std::string iso { way.timestamp().to_iso() };
-                obj->Set(String::NewSymbol("timestamp_iso"), String::New(iso.c_str()));
-                obj->Set(String::NewSymbol("uid"), Number::New(way.uid()));
-                obj->Set(String::NewSymbol("user"), String::New(way.user()));
-
-                try {
-                    std::string wkb { wkb_factory.create_linestring(way) };
-#if NODE_VERSION_AT_LEAST(0, 10, 0)
-                    obj->Set(String::NewSymbol("wkb"), node::Buffer::New(wkb.data(), wkb.size())->handle_);
-#else
-                    obj->Set(String::NewSymbol("wkb"), node::Buffer::New(const_cast<char*>(wkb.data()), wkb.size())->handle_);
-#endif
-                } catch (osmium::geom::geometry_error&) {
-                    obj->Set(String::NewSymbol("wkb"), Undefined());
-                }
-
-                try {
-                    std::string wkt { wkt_factory.create_linestring(way) };
-                    obj->Set(String::NewSymbol("wkt"), String::New(wkt.c_str()));
-                } catch (osmium::geom::geometry_error&) {
-                    obj->Set(String::NewSymbol("wkt"), Undefined());
-                }
-
-                Local<Object> tags = Object::New();
-                for (auto& tag : way.tags()) {
-                    tags->Set(String::NewSymbol(tag.key()), String::New(tag.value()));
-                }
-                obj->Set(String::NewSymbol("tags"), tags);
-
-                Local<Array> nodes = Array::New(way.nodes().size());
-                int i = 0;
-                for (auto& node : way.nodes()) {
-                    nodes->Set(i, Number::New(node.ref()));
-                    ++i;
-                }
-                obj->Set(String::NewSymbol("nodes"), nodes);
-
-                Local<Value> argv[argc] = { obj };
-
-                TryCatch trycatch;
-                Handle<Value> v = way_cb->Call(Context::GetCurrent()->Global(), argc, argv);
-                if (v.IsEmpty()) {
-                    Handle<Value> exception = trycatch.Exception();
-                    String::AsciiValue exception_str(exception);
-                    printf("Exception: %s\n", *exception_str);
-                    exit(1);
-                }
-            }
-        }
-
-        void relation(const osmium::Relation& relation) {
-            HandleScope scope;
-            if (!relation_cb.IsEmpty()) {
-                const int argc = 1;
-                Local<Object> obj = Object::New();
-                obj->Set(String::NewSymbol("id"), Number::New(relation.id()));
-                obj->Set(String::NewSymbol("version"), Number::New(relation.version()));
-                obj->Set(String::NewSymbol("visible"), Boolean::New(relation.visible()));
-                obj->Set(String::NewSymbol("changeset"), Number::New(relation.changeset()));
-                obj->Set(String::NewSymbol("timestamp"), Number::New(relation.timestamp()));
-                std::string iso { relation.timestamp().to_iso() };
-                obj->Set(String::NewSymbol("timestamp_iso"), String::New(iso.c_str()));
-                obj->Set(String::NewSymbol("uid"), Number::New(relation.uid()));
-                obj->Set(String::NewSymbol("user"), String::New(relation.user()));
-
-                Local<Object> tags = Object::New();
-                for (auto& tag : relation.tags()) {
-                    tags->Set(String::NewSymbol(tag.key()), String::New(tag.value()));
-                }
-                obj->Set(String::NewSymbol("tags"), tags);
-
-                Local<Array> members = Array::New();
-                int i = 0;
-                char typec[2] = " ";
-                for (auto& member : relation.members()) {
-                    Local<Object> jsmember = Object::New();
-                    typec[0] = osmium::item_type_to_char(member.type());
-                    jsmember->Set(String::NewSymbol("type"), String::New(typec));
-                    jsmember->Set(String::NewSymbol("ref"), Number::New(member.ref()));
-                    jsmember->Set(String::NewSymbol("role"), String::New(member.role()));
-                    members->Set(i, jsmember);
-                    ++i;
-                }
-                obj->Set(String::NewSymbol("members"), members);
-
-                Local<Value> argv[argc] = { obj };
-
-                TryCatch trycatch;
-                Handle<Value> v = relation_cb->Call(Context::GetCurrent()->Global(), argc, argv);
-                if (v.IsEmpty()) {
-                    Handle<Value> exception = trycatch.Exception();
-                    String::AsciiValue exception_str(exception);
-                    printf("Exception: %s\n", *exception_str);
-                    exit(1);
-                }
-            }
-        }
+        void dispatch_object(const osmium::io::InputIterator<osmium::io::Reader, osmium::Object>& it);
 
         void done() {
             if (!done_cb.IsEmpty()) {
@@ -214,107 +59,8 @@ namespace node_osmium {
     private:
 
         ~JSHandler();
-        osmium::geom::WKBFactory wkb_factory;
-        osmium::geom::WKTFactory wkt_factory;
-    };
-
-    Persistent<FunctionTemplate> JSHandler::constructor;
-
-    void JSHandler::Initialize(Handle<Object> target) {
-        HandleScope scope;
-        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(JSHandler::New));
-        constructor->InstanceTemplate()->SetInternalFieldCount(1);
-        constructor->SetClassName(String::NewSymbol("Handler"));
-        NODE_SET_PROTOTYPE_METHOD(constructor, "on", on);
-        NODE_SET_PROTOTYPE_METHOD(constructor, "options", options);
-        target->Set(String::NewSymbol("Handler"),constructor->GetFunction());
-    }
-
-    JSHandler::JSHandler() :
-        ObjectWrap(),
-        node_callback_for_tagged_only(false),
-        done_cb() {
-        done_cb.Clear();
-    }
-
-    JSHandler::~JSHandler() {
-        if (!done_cb.IsEmpty()) {
-            done_cb.Dispose();
-        }
-        if (!node_cb.IsEmpty()) {
-            node_cb.Dispose();
-        }
-        if (!way_cb.IsEmpty()) {
-            way_cb.Dispose();
-        }
-        if (!relation_cb.IsEmpty()) {
-            relation_cb.Dispose();
-        }
-    }
-
-    Handle<Value> JSHandler::New(const Arguments& args) {
-        HandleScope scope;
-        if (args[0]->IsExternal()) {
-            Local<External> ext = Local<External>::Cast(args[0]);
-            void* ptr = ext->Value();
-            JSHandler* b =  static_cast<JSHandler*>(ptr);
-            b->Wrap(args.This());
-            return args.This();
-        } else {
-            JSHandler* h = new JSHandler();
-            h->Wrap(args.This());
-            return args.This();
-        }
-        return Undefined();
-    }
 
-    Handle<Value> JSHandler::options(const Arguments& args) {
-        if (args.Length() == 1) {
-            if (args[0]->IsObject()) {
-                Local<Value> tagged_nodes_only = args[0]->ToObject()->Get(String::NewSymbol("tagged_nodes_only"));
-                if (tagged_nodes_only->IsBoolean()) {
-                    JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(args.This());
-                    handler->node_callback_for_tagged_only = tagged_nodes_only->BooleanValue();
-                }
-            }
-        }
-        return Undefined();
-    }
-
-    Handle<Value> JSHandler::on(const Arguments& args) {
-        HandleScope scope;
-        if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsFunction()) {
-            return ThrowException(Exception::TypeError(String::New("please provide an event name and callback function")));
-        }
-        Local<String> callback_name = args[0]->ToString();
-        Local<Function> callback = Local<Function>::Cast(args[1]);
-        if (callback->IsNull() || callback->IsUndefined()) {
-            return ThrowException(Exception::TypeError(String::New("please provide a valid callback function for second arg")));
-        }
-        JSHandler * handler = node::ObjectWrap::Unwrap<JSHandler>(args.This());
-        if (callback_name == String::NewSymbol("node")) {
-            if (!handler->node_cb.IsEmpty()) {
-                handler->node_cb.Dispose();
-            }
-            handler->node_cb = Persistent<Function>::New(callback);
-        } else if (callback_name == String::NewSymbol("way")) {
-            if (!handler->way_cb.IsEmpty()) {
-                handler->way_cb.Dispose();
-            }
-            handler->way_cb = Persistent<Function>::New(callback);
-        } else if (callback_name == String::NewSymbol("relation")) {
-            if (!handler->relation_cb.IsEmpty()) {
-                handler->relation_cb.Dispose();
-            }
-            handler->relation_cb = Persistent<Function>::New(callback);
-        } else if (callback_name == String::NewSymbol("done")) {
-            if (!handler->done_cb.IsEmpty()) {
-                handler->done_cb.Dispose();
-            }
-            handler->done_cb = Persistent<Function>::New(callback);
-        }
-        return scope.Close(Undefined());
-    }
+    };
 
 } // namespace node_osmium
 
diff --git a/src/node_osmium.cpp b/src/node_osmium.cpp
index 60a3119..268d67c 100644
--- a/src/node_osmium.cpp
+++ b/src/node_osmium.cpp
@@ -1,13 +1,20 @@
 // v8
 #include <v8.h>
 
-// node
+// node.js
 #include <node.h>
 
+// osmium
+#include <osmium/geom/wkb.hpp>
+#include <osmium/geom/wkt.hpp>
+
 // node-osmium
+#include "osm_node_wrap.hpp"
+#include "osm_way_wrap.hpp"
+#include "osm_relation_wrap.hpp"
 #include "handler.hpp"
-#include "file.hpp"
-#include "reader.hpp"
+#include "file_wrap.hpp"
+#include "reader_wrap.hpp"
 #include "buffer.hpp"
 
 namespace node_osmium {
@@ -15,13 +22,19 @@ namespace node_osmium {
     extern "C" {
         static void start(v8::Handle<v8::Object> target) {
             v8::HandleScope scope;
+            node_osmium::OSMNodeWrap::Initialize(target);
+            node_osmium::OSMWayWrap::Initialize(target);
+            node_osmium::OSMRelationWrap::Initialize(target);
             node_osmium::JSHandler::Initialize(target);
-            node_osmium::Buffer::Initialize(target);
-            node_osmium::File::Initialize(target);
-            node_osmium::Reader::Initialize(target);
+//            node_osmium::Buffer::Initialize(target);
+            node_osmium::FileWrap::Initialize(target);
+            node_osmium::ReaderWrap::Initialize(target);
         }
     }
 
+    osmium::geom::WKBFactory wkb_factory;
+    osmium::geom::WKTFactory wkt_factory;
+
 } // namespace node_osmium
 
 NODE_MODULE(osmium, node_osmium::start)
diff --git a/src/osm_node_wrap.cpp b/src/osm_node_wrap.cpp
new file mode 100644
index 0000000..d67b3c9
--- /dev/null
+++ b/src/osm_node_wrap.cpp
@@ -0,0 +1,78 @@
+
+#include <osmium/geom/wkb.hpp>
+#include <osmium/geom/wkt.hpp>
+
+#include "osm_node_wrap.hpp"
+
+namespace node_osmium {
+
+    extern osmium::geom::WKBFactory wkb_factory;
+    extern osmium::geom::WKTFactory wkt_factory;
+
+    Persistent<FunctionTemplate> OSMNodeWrap::constructor;
+
+    void OSMNodeWrap::Initialize(Handle<Object> target) {
+        HandleScope scope;
+        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(OSMNodeWrap::New));
+        constructor->InstanceTemplate()->SetInternalFieldCount(1);
+        constructor->SetClassName(String::NewSymbol("Node"));
+        NODE_SET_PROTOTYPE_METHOD(constructor, "tags", tags);
+        NODE_SET_PROTOTYPE_METHOD(constructor, "wkb", wkb);
+        NODE_SET_PROTOTYPE_METHOD(constructor, "wkt", wkt);
+        target->Set(String::NewSymbol("Node"), constructor->GetFunction());
+    }
+
+    OSMNodeWrap::OSMNodeWrap(const input_iterator& it) :
+        OSMObjectWrap(it) {
+    }
+
+    OSMNodeWrap::~OSMNodeWrap() {
+    }
+
+    Handle<Value> OSMNodeWrap::New(const Arguments& args) {
+        HandleScope scope;
+        if (args[0]->IsExternal()) {
+            Local<External> ext = Local<External>::Cast(args[0]);
+            void* ptr = ext->Value();
+            OSMNodeWrap* node = static_cast<OSMNodeWrap*>(ptr);
+            node->Wrap(args.This());
+            osmium::Node& obj = static_cast<osmium::Node&>(*(node->m_it));
+            args.This()->Set(String::New("id"), Number::New(obj.id()));
+            args.This()->Set(String::New("version"), Number::New(obj.version()));
+            args.This()->Set(String::New("changeset"), Number::New(obj.changeset()));
+            args.This()->Set(String::New("visible"), Boolean::New(obj.visible()));
+            args.This()->Set(String::New("timestamp"), Number::New(obj.timestamp()));
+            args.This()->Set(String::New("timestamp_iso"), String::New(obj.timestamp().to_iso().c_str(), obj.timestamp().to_iso().size()));
+            args.This()->Set(String::New("uid"), Number::New(obj.uid()));
+            args.This()->Set(String::New("user"), String::New(obj.user()));
+            args.This()->Set(String::New("lon"), Number::New(obj.lon()));
+            args.This()->Set(String::New("lat"), Number::New(obj.lat()));
+
+            return args.This();
+        } else {
+            return ThrowException(Exception::TypeError(String::New("osmium.Node cannot be created in Javascript")));
+        }
+        return Undefined();
+    }
+
+    Handle<Value> OSMNodeWrap::wkb(const Arguments& args) {
+        HandleScope scope;
+        osmium::Node& node = static_cast<osmium::Node&>(*(node::ObjectWrap::Unwrap<OSMNodeWrap>(args.This())->m_it));
+
+        std::string wkb { wkb_factory.create_point(node) };
+#if NODE_VERSION_AT_LEAST(0, 10, 0)
+        return scope.Close(node::Buffer::New(wkb.data(), wkb.size())->handle_);
+#else
+        return scope.Close(node::Buffer::New(const_cast<char*>(wkb.data()), wkb.size())->handle_);
+#endif
+    }
+
+    Handle<Value> OSMNodeWrap::wkt(const Arguments& args) {
+        HandleScope scope;
+        osmium::Node& node = static_cast<osmium::Node&>(*(node::ObjectWrap::Unwrap<OSMNodeWrap>(args.This())->m_it));
+
+        std::string wkt { wkt_factory.create_point(node) };
+
+        return scope.Close(String::New(wkt.c_str()));
+    }
+} // namespace node_osmium
diff --git a/src/osm_node_wrap.hpp b/src/osm_node_wrap.hpp
new file mode 100644
index 0000000..4994f01
--- /dev/null
+++ b/src/osm_node_wrap.hpp
@@ -0,0 +1,55 @@
+#ifndef NODE_WRAP_HPP
+#define NODE_WRAP_HPP
+
+// v8
+#include <v8.h>
+
+// node
+#include <node.h>
+#include <node_version.h>
+#include <node_object_wrap.h>
+#include <node_buffer.h>
+
+// osmium
+#include <osmium/osm/node.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/io/reader.hpp>
+
+#include "osm_object_wrap.hpp"
+
+using namespace v8;
+
+namespace node_osmium {
+
+    class OSMNodeWrap : public OSMObjectWrap {
+
+    public:
+
+        static Persistent<FunctionTemplate> constructor;
+        static void Initialize(Handle<Object> target);
+        static Handle<Value> New(const Arguments& args);
+        static Handle<Value> wkb(const Arguments& args);
+        static Handle<Value> wkt(const Arguments& args);
+        OSMNodeWrap(const input_iterator&);
+
+        void _ref() {
+            Ref();
+        }
+
+        void _unref() {
+            Unref();
+        }
+
+        osmium::Node& object() {
+            return static_cast<osmium::Node&>(*m_it);
+        }
+
+    private:
+
+        ~OSMNodeWrap();
+
+    };
+
+} // namespace node_osmium
+
+#endif // NODE_WRAP_HPP
diff --git a/src/osm_object_wrap.cpp b/src/osm_object_wrap.cpp
new file mode 100644
index 0000000..0caacc4
--- /dev/null
+++ b/src/osm_object_wrap.cpp
@@ -0,0 +1,28 @@
+
+#include "osm_object_wrap.hpp"
+
+namespace node_osmium {
+
+    Handle<Value> OSMObjectWrap::tags(const Arguments& args) {
+        HandleScope scope;
+
+        osmium::Object& object = *(node::ObjectWrap::Unwrap<OSMObjectWrap>(args.This())->m_it);
+
+        if (args.Length() == 0) {
+            Local<Object> tags = Object::New();
+            for (auto& tag : object.tags()) {
+                tags->Set(String::New(tag.key()), String::New(tag.value()));
+            }
+            return scope.Close(tags);
+        } else if (args.Length() == 1) {
+            const char* value = object.tags().get_value_by_key(*String::Utf8Value(args[0]));
+            if (value) {
+                return scope.Close(String::New(value));
+            } else {
+                return Undefined();
+            }
+        }
+        return Undefined();
+    }
+
+} // namespace node_osmium
diff --git a/src/osm_object_wrap.hpp b/src/osm_object_wrap.hpp
new file mode 100644
index 0000000..805d3e7
--- /dev/null
+++ b/src/osm_object_wrap.hpp
@@ -0,0 +1,42 @@
+#ifndef OSM_OBJECT_WRAP_HPP
+#define OSM_OBJECT_WRAP_HPP
+
+// v8
+#include <v8.h>
+
+// node
+#include <node.h>
+#include <node_version.h>
+#include <node_object_wrap.h>
+#include <node_buffer.h>
+
+// osmium
+#include <osmium/io/reader.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/osm/object.hpp>
+
+using namespace v8;
+
+namespace node_osmium {
+
+    typedef osmium::io::InputIterator<osmium::io::Reader, osmium::Object> input_iterator;
+
+    class OSMObjectWrap : public node::ObjectWrap {
+
+    protected:
+
+        input_iterator m_it;
+
+    public:
+
+        static Handle<Value> tags(const Arguments& args);
+
+        OSMObjectWrap(const input_iterator& it) :
+            m_it(it) {
+        }
+
+    }; // class OSMObjectWrap
+
+} // namespace node_osmium
+
+#endif // OSM_OBJECT_WRAP_HPP
diff --git a/src/osm_relation_wrap.cpp b/src/osm_relation_wrap.cpp
new file mode 100644
index 0000000..1c16b16
--- /dev/null
+++ b/src/osm_relation_wrap.cpp
@@ -0,0 +1,88 @@
+
+#include <osm_relation_wrap.hpp>
+
+namespace node_osmium {
+
+    Persistent<FunctionTemplate> OSMRelationWrap::constructor;
+
+    void OSMRelationWrap::Initialize(Handle<Object> target) {
+        HandleScope scope;
+        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(OSMRelationWrap::New));
+        constructor->InstanceTemplate()->SetInternalFieldCount(1);
+        constructor->SetClassName(String::NewSymbol("Relation"));
+        NODE_SET_PROTOTYPE_METHOD(constructor, "tags", tags);
+        NODE_SET_PROTOTYPE_METHOD(constructor, "members", members);
+        target->Set(String::NewSymbol("Relation"), constructor->GetFunction());
+    }
+
+    OSMRelationWrap::OSMRelationWrap(const input_iterator& it) :
+        OSMObjectWrap(it) {
+    }
+
+    OSMRelationWrap::~OSMRelationWrap() {
+    }
+
+    Handle<Value> OSMRelationWrap::New(const Arguments& args) {
+        HandleScope scope;
+        if (args[0]->IsExternal()) {
+            Local<External> ext = Local<External>::Cast(args[0]);
+            void* ptr = ext->Value();
+            OSMRelationWrap* relation = static_cast<OSMRelationWrap*>(ptr);
+            relation->Wrap(args.This());
+            osmium::Relation& obj = static_cast<osmium::Relation&>(*(relation->m_it));
+            args.This()->Set(String::New("id"), Number::New(obj.id()));
+            args.This()->Set(String::New("version"), Number::New(obj.version()));
+            args.This()->Set(String::New("changeset"), Number::New(obj.changeset()));
+            args.This()->Set(String::New("visible"), Boolean::New(obj.visible()));
+            args.This()->Set(String::New("timestamp"), Number::New(obj.timestamp()));
+            args.This()->Set(String::New("timestamp_iso"), String::New(obj.timestamp().to_iso().c_str(), obj.timestamp().to_iso().size()));
+            args.This()->Set(String::New("uid"), Number::New(obj.uid()));
+            args.This()->Set(String::New("user"), String::New(obj.user()));
+            return args.This();
+        } else {
+            return ThrowException(Exception::TypeError(String::New("osmium.Relation cannot be created in Javascript")));
+        }
+        return Undefined();
+    }
+
+    Handle<Value> OSMRelationWrap::members(const Arguments& args) {
+        HandleScope scope;
+        osmium::Relation& relation = static_cast<osmium::Relation&>(*(node::ObjectWrap::Unwrap<OSMRelationWrap>(args.This())->m_it));
+
+        if (args.Length() == 0) {
+            Local<Array> members = Array::New();
+            int i = 0;
+            char typec[2] = " ";
+            for (auto& member : relation.members()) {
+                Local<Object> jsmember = Object::New();
+                typec[0] = osmium::item_type_to_char(member.type());
+                jsmember->Set(String::New("type"), String::New(typec));
+                jsmember->Set(String::New("ref"), Number::New(member.ref()));
+                jsmember->Set(String::New("role"), String::New(member.role()));
+                members->Set(i, jsmember);
+                ++i;
+            }
+            return scope.Close(members);
+        } else if (args.Length() == 1) {
+            if (args[0]->IsNumber()) {
+                int n = static_cast<int>(args[0]->ToNumber()->Value());
+                if (n > 0 && n < static_cast<int>(relation.members().size())) {
+                    auto it = relation.members().begin();
+                    std::advance(it, n);
+                    osmium::RelationMember& member = *it;
+                    Local<Object> jsmember = Object::New();
+                    char typec[2] = " ";
+                    typec[0] = osmium::item_type_to_char(member.type());
+                    jsmember->Set(String::New("type"), String::New(typec));
+                    jsmember->Set(String::New("ref"), Number::New(member.ref()));
+                    jsmember->Set(String::New("role"), String::New(member.role()));
+                    return scope.Close(jsmember);
+                }
+            }
+        }
+
+        return Undefined();
+    }
+
+} // namespace node_osmium
+
diff --git a/src/osm_relation_wrap.hpp b/src/osm_relation_wrap.hpp
new file mode 100644
index 0000000..d65877e
--- /dev/null
+++ b/src/osm_relation_wrap.hpp
@@ -0,0 +1,56 @@
+#ifndef RELATION_WRAP_HPP
+#define RELATION_WRAP_HPP
+
+// c++
+#include <iterator>
+
+// v8
+#include <v8.h>
+
+// node
+#include <node.h>
+#include <node_version.h>
+#include <node_object_wrap.h>
+
+// osmium
+#include <osmium/osm/relation.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/io/reader.hpp>
+
+#include "osm_object_wrap.hpp"
+
+using namespace v8;
+
+namespace node_osmium {
+
+    class OSMRelationWrap : public OSMObjectWrap {
+
+    public:
+
+        static Persistent<FunctionTemplate> constructor;
+        static void Initialize(Handle<Object> target);
+        static Handle<Value> New(const Arguments& args);
+        static Handle<Value> members(const Arguments& args);
+        OSMRelationWrap(const input_iterator&);
+
+        void _ref() {
+            Ref();
+        }
+
+        void _unref() {
+            Unref();
+        }
+
+        osmium::Relation& object() {
+            return static_cast<osmium::Relation&>(*m_it);
+        }
+
+    private:
+
+        ~OSMRelationWrap();
+
+    };
+
+} // namespace node_osmium
+
+#endif // RELATION_WRAP_HPP
diff --git a/src/osm_way_wrap.cpp b/src/osm_way_wrap.cpp
new file mode 100644
index 0000000..a3a3723
--- /dev/null
+++ b/src/osm_way_wrap.cpp
@@ -0,0 +1,108 @@
+
+#include <osmium/geom/wkb.hpp>
+#include <osmium/geom/wkt.hpp>
+
+#include "osm_way_wrap.hpp"
+
+namespace node_osmium {
+
+    extern osmium::geom::WKBFactory wkb_factory;
+    extern osmium::geom::WKTFactory wkt_factory;
+
+    Persistent<FunctionTemplate> OSMWayWrap::constructor;
+
+    void OSMWayWrap::Initialize(Handle<Object> target) {
+        HandleScope scope;
+        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(OSMWayWrap::New));
+        constructor->InstanceTemplate()->SetInternalFieldCount(1);
+        constructor->SetClassName(String::NewSymbol("Way"));
+        NODE_SET_PROTOTYPE_METHOD(constructor, "tags", tags);
+        NODE_SET_PROTOTYPE_METHOD(constructor, "wkb", wkb);
+        NODE_SET_PROTOTYPE_METHOD(constructor, "wkt", wkt);
+        NODE_SET_PROTOTYPE_METHOD(constructor, "nodes", nodes);
+        target->Set(String::NewSymbol("Way"), constructor->GetFunction());
+    }
+
+    OSMWayWrap::OSMWayWrap(const input_iterator& it) :
+        OSMObjectWrap(it) {
+    }
+
+    OSMWayWrap::~OSMWayWrap() {
+    }
+
+    Handle<Value> OSMWayWrap::New(const Arguments& args) {
+        HandleScope scope;
+        if (args[0]->IsExternal()) {
+            Local<External> ext = Local<External>::Cast(args[0]);
+            void* ptr = ext->Value();
+            OSMWayWrap* way = static_cast<OSMWayWrap*>(ptr);
+            way->Wrap(args.This());
+            osmium::Way& obj = static_cast<osmium::Way&>(*(way->m_it));
+            args.This()->Set(String::New("id"), Number::New(obj.id()));
+            args.This()->Set(String::New("version"), Number::New(obj.version()));
+            args.This()->Set(String::New("changeset"), Number::New(obj.changeset()));
+            args.This()->Set(String::New("visible"), Boolean::New(obj.visible()));
+            args.This()->Set(String::New("timestamp"), Number::New(obj.timestamp()));
+            args.This()->Set(String::New("timestamp_iso"), String::New(obj.timestamp().to_iso().c_str(), obj.timestamp().to_iso().size()));
+            args.This()->Set(String::New("uid"), Number::New(obj.uid()));
+            args.This()->Set(String::New("user"), String::New(obj.user()));
+            return args.This();
+        } else {
+            return ThrowException(Exception::TypeError(String::New("osmium.Way cannot be created in Javascript")));
+        }
+        return Undefined();
+    }
+
+    Handle<Value> OSMWayWrap::wkb(const Arguments& args) {
+        HandleScope scope;
+        osmium::Way& way = static_cast<osmium::Way&>(*(node::ObjectWrap::Unwrap<OSMWayWrap>(args.This())->m_it));
+
+        try {
+            std::string wkb { wkb_factory.create_linestring(way) };
+#if NODE_VERSION_AT_LEAST(0, 10, 0)
+            return scope.Close(node::Buffer::New(wkb.data(), wkb.size())->handle_);
+#else
+            return scope.Close(node::Buffer::New(const_cast<char*>(wkb.data()), wkb.size())->handle_);
+#endif
+        } catch (osmium::geom::geometry_error&) {
+            return scope.Close(Undefined());
+        }
+    }
+
+    Handle<Value> OSMWayWrap::wkt(const Arguments& args) {
+        HandleScope scope;
+        osmium::Way& way = static_cast<osmium::Way&>(*(node::ObjectWrap::Unwrap<OSMWayWrap>(args.This())->m_it));
+
+        try {
+            std::string wkt { wkt_factory.create_linestring(way) };
+            return scope.Close(String::New(wkt.c_str()));
+        } catch (osmium::geom::geometry_error&) {
+            return scope.Close(Undefined());
+        }
+    }
+
+    Handle<Value> OSMWayWrap::nodes(const Arguments& args) {
+        HandleScope scope;
+        osmium::Way& way = static_cast<osmium::Way&>(*(node::ObjectWrap::Unwrap<OSMWayWrap>(args.This())->m_it));
+
+        if (args.Length() == 0) {
+            Local<Array> nodes = Array::New(way.nodes().size());
+            int i = 0;
+            for (auto& wn : way.nodes()) {
+                nodes->Set(i, Number::New(wn.ref()));
+                ++i;
+            }
+            return scope.Close(nodes);
+        } else if (args.Length() == 1) {
+            if (args[0]->IsNumber()) {
+                int n = static_cast<int>(args[0]->ToNumber()->Value());
+                if (n > 0 && n < static_cast<int>(way.nodes().size())) {
+                    return scope.Close(Number::New(way.nodes()[n].ref()));
+                }
+            }
+        }
+        return Undefined();
+    }
+
+} // namespace node_osmium
+
diff --git a/src/osm_way_wrap.hpp b/src/osm_way_wrap.hpp
new file mode 100644
index 0000000..9de530e
--- /dev/null
+++ b/src/osm_way_wrap.hpp
@@ -0,0 +1,55 @@
+#ifndef WAY_WRAP_HPP
+#define WAY_WRAP_HPP
+
+// v8
+#include <v8.h>
+
+// node
+#include <node.h>
+#include <node_version.h>
+#include <node_object_wrap.h>
+
+// osmium
+#include <osmium/osm/way.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/io/reader.hpp>
+
+#include "osm_object_wrap.hpp"
+
+using namespace v8;
+
+namespace node_osmium {
+
+    class OSMWayWrap : public OSMObjectWrap {
+
+    public:
+
+        static Persistent<FunctionTemplate> constructor;
+        static void Initialize(Handle<Object> target);
+        static Handle<Value> New(const Arguments& args);
+        static Handle<Value> wkb(const Arguments& args);
+        static Handle<Value> wkt(const Arguments& args);
+        static Handle<Value> nodes(const Arguments& args);
+        OSMWayWrap(const input_iterator&);
+
+        void _ref() {
+            Ref();
+        }
+
+        void _unref() {
+            Unref();
+        }
+
+        osmium::Way& object() {
+            return static_cast<osmium::Way&>(*m_it);
+        }
+
+    private:
+
+        ~OSMWayWrap();
+
+    };
+
+} // namespace node_osmium
+
+#endif // WAY_WRAP_HPP
diff --git a/src/reader.hpp b/src/reader_wrap.cpp
similarity index 58%
rename from src/reader.hpp
rename to src/reader_wrap.cpp
index 4d93d8b..73f6c2b 100644
--- a/src/reader.hpp
+++ b/src/reader_wrap.cpp
@@ -1,71 +1,15 @@
 
-// c++11
-#include <memory>
-#include <sstream>
-
-// v8
-#include <v8.h>
-
-// node
-#include <node.h>
-#include <node_version.h>
-#include <node_object_wrap.h>
-
-// osmium
-#include <osmium/io/any_input.hpp> // bring in XML and PBF support
-#include <osmium/io/reader.hpp>
-#include <osmium/visitor.hpp>
-#include <osmium/handler/node_locations_for_ways.hpp>
-#include <osmium/index/map/dummy.hpp>
-#include <osmium/index/map/stl_map.hpp>
-#include <osmium/index/map/sparse_table.hpp>
-
-typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
-typedef osmium::index::map::SparseTable<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
-typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
-
-using namespace v8;
+#include "reader_wrap.hpp"
+#include "file_wrap.hpp"
+#include "handler.hpp"
 
 namespace node_osmium {
 
-    typedef std::shared_ptr<osmium::io::Reader> reader_ptr;
-
-    class Reader : public node::ObjectWrap {
-
-    public:
-
-        static Persistent<FunctionTemplate> constructor;
-        static void Initialize(Handle<Object> target);
-        static Handle<Value> New(Arguments const& args);
-        static Handle<Value> header(Arguments const& args);
-        static Handle<Value> apply(Arguments const& args);
-        static Handle<Value> close(Arguments const& args);
-        Reader(osmium::io::File& infile, osmium::osm_entity::flags entities);
-
-        void _ref() {
-            Ref();
-        }
-
-        void _unref() {
-            Unref();
-        }
-
-        reader_ptr get() {
-            return this_;
-        }
-
-    private:
+    Persistent<FunctionTemplate> ReaderWrap::constructor;
 
-        ~Reader();
-        reader_ptr this_;
-        osmium::io::Header header_;
-    };
-
-    Persistent<FunctionTemplate> Reader::constructor;
-
-    void Reader::Initialize(Handle<Object> target) {
+    void ReaderWrap::Initialize(Handle<Object> target) {
         HandleScope scope;
-        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Reader::New));
+        constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(ReaderWrap::New));
         constructor->InstanceTemplate()->SetInternalFieldCount(1);
         constructor->SetClassName(String::NewSymbol("Reader"));
         NODE_SET_PROTOTYPE_METHOD(constructor, "header", header);
@@ -74,15 +18,15 @@ namespace node_osmium {
         target->Set(String::NewSymbol("Reader"), constructor->GetFunction());
     }
 
-    Reader::Reader(osmium::io::File& file, osmium::osm_entity::flags entities) :
+    ReaderWrap::ReaderWrap(osmium::io::File& file, osmium::osm_entity::flags entities) :
         ObjectWrap(),
         this_(std::make_shared<osmium::io::Reader>(file, entities)),
         header_(this_->header()) {
     }
 
-    Reader::~Reader() { }
+    ReaderWrap::~ReaderWrap() { }
 
-    Handle<Value> Reader::New(const Arguments& args) {
+    Handle<Value> ReaderWrap::New(const Arguments& args) {
         HandleScope scope;
         if (!args.IsConstructCall()) {
             return ThrowException(Exception::Error(String::New("Cannot call constructor as function, you need to use 'new' keyword")));
@@ -99,17 +43,17 @@ namespace node_osmium {
                 read_which_entities = osmium::osm_entity::flags::nothing;
                 Local<Object> options = args[1]->ToObject();
 
-                Local<Value> want_nodes = options->Get(String::NewSymbol("node"));
+                Local<Value> want_nodes = options->Get(String::New("node"));
                 if (want_nodes->IsBoolean() && want_nodes->BooleanValue()) {
                     read_which_entities |= osmium::osm_entity::flags::node;
                 }
 
-                Local<Value> want_ways = options->Get(String::NewSymbol("way"));
+                Local<Value> want_ways = options->Get(String::New("way"));
                 if (want_ways->IsBoolean() && want_ways->BooleanValue()) {
                     read_which_entities |= osmium::osm_entity::flags::way;
                 }
 
-                Local<Value> want_relations = options->Get(String::NewSymbol("relation"));
+                Local<Value> want_relations = options->Get(String::New("relation"));
                 if (want_relations->IsBoolean() && want_relations->BooleanValue()) {
                     read_which_entities |= osmium::osm_entity::flags::relation;
                 }
@@ -117,41 +61,41 @@ namespace node_osmium {
             }
             if (args[0]->IsString()) {
                 osmium::io::File file(*String::Utf8Value(args[0]));
-                Reader* q = new Reader(file, read_which_entities);
+                ReaderWrap* q = new ReaderWrap(file, read_which_entities);
                 q->Wrap(args.This());
                 return args.This();
-            } else if (args[0]->IsObject() && File::constructor->HasInstance(args[0]->ToObject())) {
+            } else if (args[0]->IsObject() && FileWrap::constructor->HasInstance(args[0]->ToObject())) {
                 Local<Object> file_obj = args[0]->ToObject();
-                File* file_wrap = node::ObjectWrap::Unwrap<File>(file_obj);
-                Reader* q = new Reader(*(file_wrap->get()), read_which_entities);
+                FileWrap* file_wrap = node::ObjectWrap::Unwrap<FileWrap>(file_obj);
+                ReaderWrap* q = new ReaderWrap(*(file_wrap->get()), read_which_entities);
                 q->Wrap(args.This());
                 return args.This();
             } else {
                 return ThrowException(Exception::TypeError(String::New("please provide a File object or string for the first argument when creating a Reader")));
             }
-        } catch (std::exception const& ex) {
+        } catch (const std::exception& ex) {
             return ThrowException(Exception::TypeError(String::New(ex.what())));
         }
         return Undefined();
     }
 
-    Handle<Value> Reader::header(const Arguments& args) {
+    Handle<Value> ReaderWrap::header(const Arguments& args) {
         HandleScope scope;
         Local<Object> obj = Object::New();
-        Reader* reader = node::ObjectWrap::Unwrap<Reader>(args.This());
-        osmium::io::Header const& header = reader->header_;
-        obj->Set(String::NewSymbol("generator"), String::New(header.get("generator").c_str()));
-        osmium::Box const& bounds = header.box();
+        ReaderWrap* reader = node::ObjectWrap::Unwrap<ReaderWrap>(args.This());
+        const osmium::io::Header& header = reader->header_;
+        obj->Set(String::New("generator"), String::New(header.get("generator").c_str()));
+        const osmium::Box& bounds = header.box();
         Local<Array> arr = Array::New(4);
-        arr->Set(0,Number::New(bounds.bottom_left().lon()));
-        arr->Set(1,Number::New(bounds.bottom_left().lat()));
-        arr->Set(2,Number::New(bounds.top_right().lon()));
-        arr->Set(3,Number::New(bounds.top_right().lat()));
-        obj->Set(String::NewSymbol("bounds"),arr);
+        arr->Set(0, Number::New(bounds.bottom_left().lon()));
+        arr->Set(1, Number::New(bounds.bottom_left().lat()));
+        arr->Set(2, Number::New(bounds.top_right().lon()));
+        arr->Set(3, Number::New(bounds.top_right().lat()));
+        obj->Set(String::New("bounds"), arr);
         return scope.Close(obj);
     }
 
-    Handle<Value> Reader::apply(const Arguments& args) {
+    Handle<Value> ReaderWrap::apply(const Arguments& args) {
         HandleScope scope;
 
         if (args.Length() != 1 && args.Length() != 2) {
@@ -171,31 +115,47 @@ namespace node_osmium {
             if (!args[1]->IsObject()) {
                 return ThrowException(Exception::TypeError(String::New("second argument must be 'option' object")));
             }
-            Local<Value> wlh = args[1]->ToObject()->Get(String::NewSymbol("with_location_handler"));
+            Local<Value> wlh = args[1]->ToObject()->Get(String::New("with_location_handler"));
             if (wlh->BooleanValue()) {
                 with_location_handler = true;
             }
         }
 
         JSHandler* handler = node::ObjectWrap::Unwrap<JSHandler>(obj);
-        Reader* reader = node::ObjectWrap::Unwrap<Reader>(args.This());
+        ReaderWrap* reader = node::ObjectWrap::Unwrap<ReaderWrap>(args.This());
         reader_ptr r_ptr = reader->get();
 
         if (with_location_handler) {
             index_pos_type index_pos;
             index_neg_type index_neg;
             location_handler_type location_handler(index_pos, index_neg);
-            osmium::apply(*r_ptr, location_handler, *handler);
+
+            osmium::io::InputIterator<osmium::io::Reader, osmium::Object> it(*r_ptr);
+            osmium::io::InputIterator<osmium::io::Reader, osmium::Object> end;
+
+            for (; it != end; ++it) {
+                osmium::apply_item(*it, location_handler);
+                handler->dispatch_object(it);
+            }
+
+            handler->done();
         } else {
-            osmium::apply(*r_ptr, *handler);
+            osmium::io::InputIterator<osmium::io::Reader, osmium::Object> it(*r_ptr);
+            osmium::io::InputIterator<osmium::io::Reader, osmium::Object> end;
+
+            for (; it != end; ++it) {
+                handler->dispatch_object(it);
+            }
+
+            handler->done();
         }
 
         return Undefined();
     }
 
-    Handle<Value> Reader::close(const Arguments& args) {
+    Handle<Value> ReaderWrap::close(const Arguments& args) {
         HandleScope scope;
-        Reader* reader = node::ObjectWrap::Unwrap<Reader>(args.This());
+        ReaderWrap* reader = node::ObjectWrap::Unwrap<ReaderWrap>(args.This());
         reader_ptr r_ptr = reader->get();
         r_ptr->close();
         return Undefined();
diff --git a/src/reader_wrap.hpp b/src/reader_wrap.hpp
new file mode 100644
index 0000000..2c4f757
--- /dev/null
+++ b/src/reader_wrap.hpp
@@ -0,0 +1,68 @@
+#ifndef READER_WRAP_HPP
+#define READER_WRAP_HPP
+
+// c++11
+#include <exception>
+#include <memory>
+
+// v8
+#include <v8.h>
+
+// node.js
+#include <node.h>
+#include <node_version.h>
+#include <node_object_wrap.h>
+
+// osmium
+#include <osmium/io/any_input.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/visitor.hpp>
+#include <osmium/handler/node_locations_for_ways.hpp>
+#include <osmium/index/map/dummy.hpp>
+#include <osmium/index/map/stl_map.hpp>
+#include <osmium/index/map/sparse_table.hpp>
+
+typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> index_neg_type;
+typedef osmium::index::map::SparseTable<osmium::unsigned_object_id_type, osmium::Location> index_pos_type;
+typedef osmium::handler::NodeLocationsForWays<index_pos_type, index_neg_type> location_handler_type;
+
+using namespace v8;
+
+namespace node_osmium {
+
+    typedef std::shared_ptr<osmium::io::Reader> reader_ptr;
+
+    class ReaderWrap : public node::ObjectWrap {
+
+    public:
+
+        static Persistent<FunctionTemplate> constructor;
+        static void Initialize(Handle<Object> target);
+        static Handle<Value> New(const Arguments& args);
+        static Handle<Value> header(const Arguments& args);
+        static Handle<Value> apply(const Arguments& args);
+        static Handle<Value> close(const Arguments& args);
+        ReaderWrap(osmium::io::File& infile, osmium::osm_entity::flags entities);
+
+        void _ref() {
+            Ref();
+        }
+
+        void _unref() {
+            Unref();
+        }
+
+        reader_ptr get() {
+            return this_;
+        }
+
+    private:
+
+        ~ReaderWrap();
+        reader_ptr this_;
+        osmium::io::Header header_;
+    };
+
+} // namespace node_osmium
+
+#endif // READER_WRAP_HPP
diff --git a/test/osmium.test.js b/test/osmium.test.js
index 2906bbd..40659f2 100644
--- a/test/osmium.test.js
+++ b/test/osmium.test.js
@@ -36,7 +36,7 @@ describe('osmium', function() {
         var reader2 = new osmium.Reader(file2);
         nodes = 0;
         handler.on('done',function() {
-            assert.equal(nodes,1525);
+            assert.equal(nodes, 1525);
             done();
         });
         reader2.apply(handler);
@@ -44,8 +44,8 @@ describe('osmium', function() {
 
     it('should be able to get node data from handler parameter', function(done) {
         var handler = new osmium.Handler();
-        var nodes = 0, ways = 0;
-        handler.on('node',function(node) {
+        var nodes = 0, ways = 0, relations = 0;
+        handler.on('node', function(node) {
             if (nodes == 0) {
                 assert.equal(node.id, 50031066);
                 assert.equal(node.lon, -120.1891610);
@@ -54,16 +54,31 @@ describe('osmium', function() {
                 assert.equal(node.id, 50031085);
                 assert.equal(node.lon, -120.1929190);
             }
+            if (node.id == 1564464078) {
+                assert.equal(node.changeset, 10220832);
+                assert.equal(node.tags().amenity, 'pub');
+                assert.equal(node.tags('name'), 'Old Schoolhouse Brewery');
+            }
             ++nodes;
         });
-        handler.on('way',function(way) {
+        handler.on('way', function(way) {
             if (ways == 0) {
                 assert.equal(way.id, 6091729);
+                assert.equal(way.nodes(1), 50253602);
+                assert.deepEqual(way.nodes(), [50253600, 50253602, 50137292, 50137371, 50253605, 50253608]);
             }
             ++ways;
         });
-        handler.on('done',function() {
-            assert.equal(nodes,1525);
+        handler.on('relation', function(relation) {
+            if (relations == 0) {
+                assert.equal(relation.id, 237891);
+                assert.deepEqual(relation.members()[0], ['w', 40512249, 'outer']);
+                assert.deepEqual(relation.members(3), ['w', 40512257, 'inner']);
+            }
+            ++relations;
+        });
+        handler.on('done', function() {
+            assert.equal(nodes, 1525);
             done();
         });
         var reader = new osmium.Reader(__dirname+"/data/winthrop.osm", { 'node': true, 'way': true });

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/node-osmium.git



More information about the Pkg-grass-devel mailing list