Permalink
Browse files

simple ruby http api, user api wrapper, examples, ajax viewer

  • Loading branch information...
1 parent de90bdf commit 1c151f037a3681cd6624e8f2a40a5606de979242 Pavel committed May 21, 2010
Showing with 312 additions and 0 deletions.
  1. +161 −0 apis/gbase.rb
  2. +39 −0 apis/gbase_examples.rb
  3. +11 −0 apis/viewer/README
  4. +19 −0 apis/viewer/app.rb
  5. +82 −0 apis/viewer/view.html
View
@@ -0,0 +1,161 @@
+require 'rubygems'
+require 'httparty'
+require 'singleton'
+
+# == VertexDB API realization via HTTP
+# requires HTTParty
+#
+class GBase
+ include HTTParty
+ base_uri 'localhost:8080'
+ format :json
+
+ include Singleton
+
+ for met in %w{mkdir rm read link write size select}
+ class_eval "def self.#{met} (*args); self.instance.#{met} *args; end; \n"
+ end
+
+ # original api realization
+ def mkdir node
+ get node_name(node) + action(:mkdir)
+ end
+
+ def rm node, key
+ get node_name(node) + action(:rm, :key => key)
+ end
+
+ def size node
+ get node_name(node) + action(:size)
+ end
+
+ def link node, to_path, key
+ get node_name(node) + action(:link, :key => key, :toPath => to_path)
+ end
+
+ def read node, key
+ get node_name(node) + action(:read, :key => key)
+ end
+
+ def write node, key, mode, body
+ post node_name(node) + action(:write, :key => key, :mode => mode), :body => body.to_s
+ end
+
+ def select node, op, options = {}
+ options[:op] = op
+ get node_name(node) + action(:select, options)
+ end
+
+ def backup!
+ get '/' + action(:backup)
+ end
+
+ private
+ # adds slash in the begining of the string if there is not yet
+ # 'items' => '/items'
+ # '/items' => '/items'
+ def node_name path
+ path.strip!
+ path = '/' + path if path[0] != '/'
+ path
+ end
+
+ # generate action argument
+ # action(:read, :key => 'node') => '?action=read&key=node
+ def action act, add_args = {}
+ '?action=' + act.to_s.strip + args(add_args)
+ end
+
+ # {:key => 'position', :arg2 => 'arg_value'} => &key=position&position=arg_value
+ def args ha
+ return '' if ha.empty?
+ '&' + ha.to_a.map {|key, val| key.to_s + '=' + val.to_s.strip }.join('&')
+ end
+
+ def get *args
+ self.class.get *args
+ end
+
+ def post *args
+ self.class.post *args
+ end
+end
+
+
+class PrettyVertex
+ def initialize
+ @db = GBase.instance
+ end
+
+ # writes create path and write hash of attributes there
+ def write path, content = {}
+ @db.mkdir path
+ links = []
+
+ parser = Proc.new do |scope, hash|
+ hash.each do |key, value|
+
+ # run it recursive
+ if value.is_a? Hash
+ @db.mkdir join(scope, key.to_s)
+ parser.call join(scope, key.to_s), value
+ next
+ end
+
+ # if key starts with '_' - write value, else make links
+ if key.to_s[0, 1] == '_'
+ @db.write scope, key, 'set', value
+ else
+ # store links, becouse distanation node may not exists yet
+ links << [join(scope, value.to_s), join(scope, key.to_s)]
+ end
+ end
+ end
+
+ # run recursive runner
+ parser.call path, content
+ # make links
+ links.each {|p| link p[0], p[1] }
+ end
+
+ # create path of distanation and make link
+ def link node, p2
+ link_dir, link_name = split_path p2
+ @db.mkdir link_dir unless link_dir == ''
+ @db.link node, link_dir, link_name
+ end
+
+ # deletes key
+ def delete path
+ pre_path, key = split_path path
+ @db.rm pre_path, key
+ end
+
+ # deletes all nodes
+ def clear!
+ @db.select '/', 'rm'
+ end
+
+ def join *paths
+ parts = File.join(*paths).split '/'
+ res = []
+ parts.each do |part|
+ if part == '..'
+ res.pop
+ else
+ res << part
+ end
+ end
+ res.join '/'
+ end
+
+ alias_method :rm, :delete
+
+ private
+ # '/path/to/item/name' => ['/path/to]/item', 'name']
+ def split_path path
+ pre_path = path[0, path.rindex('/').to_i]
+ key = path[pre_path.size + 1, path.size - pre_path.size - 1]
+ [pre_path, key]
+ end
+end
View
@@ -0,0 +1,39 @@
+require 'gbase'
+
+
+base = PrettyVertex.new
+base.clear!
+base.write 'items/1', {:_name => 'Super car', :_about => 'Harder better faster stronger!', :_cost => 7000, :_count => 100}
+base.write 'catalogs/1', {:_name => 'Cars'}
+base.link 'items/1', 'catalogs/1/items/1'
+base.link 'catalogs/1', 'items/1/catalog'
+
+base.write 'people', {
+ 1 => {:_name => 'Poul', :has_wife => '../3', :has_chldren => {
+ 1 => '../2',
+ 2 => '../4'
+ }
+ },
+
+ 2 => {:_name => 'Jane', :has_husband => '../4', :has_father => '../1', :has_mother => '../3', :has_chldren => {
+ 1 => '../../5',
+ 2 => '../../6'
+ }
+ },
+
+ 3 => { :_name => 'Jessica', :has_husband => '../1', :has_chldren => {
+ 1 => '../../2',
+ 2 => '../../4'
+ }
+ },
+
+ 4 => {:_name => 'Harry', :has_wife => '../2', :has_father => '../1', :has_mother => '../3', :has_chldren => {
+ 1 => '../../5',
+ 2 => '../../6',
+ 3 => '../../7'
+ }},
+
+ 5 => {:_name => 'Sarah', :has_mother => '../2', :has_father => '../4' },
+ 6 => {:_name => 'Matthew', :has_mother => '../2', :has_father => '../4'},
+ 7 => {:_name => 'Jack', :has_father => '../4'}
+}
View
@@ -0,0 +1,11 @@
+This is simple sinatra application for viewing vertexDB
+for installing you need ruby 1.8.7, rubygems
+then run
+
+ $ sudo gem install sinatra yajl
+
+to run viewer
+
+ $ ruby app.rb
+
+applivation will be avalible at http://localhost:4567/
View
@@ -0,0 +1,19 @@
+require 'rubygems'
+require 'sinatra'
+require 'yajl'
+
+require '../gbase'
+
+set :views, File.expand_path(File.dirname(__FILE__))
+set :public, File.expand_path(File.dirname(__FILE__))
+
+get '/' do
+ File.open('./view.html') {|f| f.read }
+end
+
+get '/select' do
+ db = GBase.instance
+ value = db.select params[:path], params[:op]
+ content_type :json
+ Yajl::Encoder.encode(value.clone)
+end
View
@@ -0,0 +1,82 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <title>view</title>
+ <script type="text/javascript" charset="utf-8" src="http://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools-yui-compressed.js"></script>
+ </head>
+
+ <body>
+ <div id="node_/">
+
+ </div>
+
+ <style type="text/css" media="screen">
+ div {
+ font-size: 14px;
+ line-height: 14px;
+ margin: 4px 0;
+ margin-left: 25px;
+ padding-bottom: 3px;
+ }
+
+ a {
+ margin-left: 10px;
+ font-size: 13px;
+ color: #33d;
+ }
+
+ i, b {
+ margin-right: 10px;
+ }
+
+ b {
+ color: #444;
+ }
+
+ small {
+ color: #444;
+ }
+
+ </style>
+ </body>
+ <script type="text/javascript" charset="utf-8">
+ window.addEvent('domready', function () {
+ loadContent('/');
+ });
+
+ function loadContent(path) {
+ node = $('node_' + path);
+
+ // closing if loaded
+ if (node.loaded) {
+ node.getElements('div').destroy();
+ node.getElement('a').set('text', 'load');
+ node.loaded = false;
+ return;
+ }
+
+ new Request.JSON({url: '/select', onSuccess: function(result){
+ $each(result, function(val, key) {
+
+
+ if (key[0] == '_') {
+ var row = new Element('div', {html: '<i>' + key + '</i> <span>' + val + '</span>', id: 'node_' + path + key + '/'}).inject(node);
+ } else {
+ var row = new Element('div', {html: '<b>' + key + '</b> <small>(' + val + ')</small>', id: 'node_' + path + key + '/'}).inject(node);
+ var a = new Element('a', {'text': 'load'}).inject(row);
+ a.addEvent('click', function () {
+ loadContent(path + key + '/');
+ });
+ }
+
+ node.loaded = true;
+ if (path != '/') {
+ node.getElement('a').set('text', 'close');
+ }
+ });
+ }}).get({'path': path, 'op': 'object'});
+ }
+ </script>
+</html>

0 comments on commit 1c151f0

Please sign in to comment.