Skip to content

Commit

Permalink
Merge pull request #5 from kbrock/master
Browse files Browse the repository at this point in the history
Try Redis with links to help user type less
  • Loading branch information
alexmchale committed Jun 14, 2011
2 parents f36651c + 60e6301 commit 467b97d
Show file tree
Hide file tree
Showing 18 changed files with 371 additions and 255 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -1 +1,4 @@
.sass-cache
.bundle
tmp/**
log/**
9 changes: 9 additions & 0 deletions Gemfile
@@ -0,0 +1,9 @@
source :rubygems

gem 'sinatra', '~> 1.2.6', :require => 'sinatra/base'
gem 'haml', '~> 3.1.2'
gem 'sass', '~>3.1.2'
gem 'json', '~>1.5.1'
gem 'redis', '~>2.2.1'
gem 'rdiscount', '~>1.6.8'
gem 'andand', '~>1.3.1'
26 changes: 26 additions & 0 deletions Gemfile.lock
@@ -0,0 +1,26 @@
GEM
remote: http://rubygems.org/
specs:
andand (1.3.1)
haml (3.1.2)
json (1.5.1)
rack (1.3.0)
rdiscount (1.6.8)
redis (2.2.1)
sass (3.1.2)
sinatra (1.2.6)
rack (~> 1.1)
tilt (< 2.0, >= 1.2.2)
tilt (1.3.2)

PLATFORMS
ruby

DEPENDENCIES
andand (~> 1.3.1)
haml (~> 3.1.2)
json (~> 1.5.1)
rdiscount (~> 1.6.8)
redis (~> 2.2.1)
sass (~> 3.1.2)
sinatra (~> 1.2.6)
10 changes: 10 additions & 0 deletions config.ru
@@ -1,3 +1,13 @@
require 'rubygems'
require 'bundler'

Bundler.require

log = File.new(File.join(File.dirname(__FILE__),'log','sinatra.log'), "a")

STDOUT.reopen(log)
STDERR.reopen(log)

require "try-redis.rb"

use Rack::Static, :urls => %w( /css /images /javascripts ), :root => "public"
Expand Down
196 changes: 107 additions & 89 deletions public/javascripts/terminal.js
@@ -1,7 +1,88 @@
$(document).ready(function () {
var history = [];
var historyCursor = 0;
var historyValues = [];
var historyCursor = 0;

function submitCommand(text, dontClearInput) {
historyValues.push(text);
historyCursor = historyValues.length;

append("<a href=\"#run\">" + escapeHtml(text)+"</a>", "input", escapeHtml("> "),true);
scrollDown();

if (!dontClearInput) {
$("#input").val("");
}

jQuery.getJSON("eval", { command: text }, function (data) {
if (data.response !== undefined) {
append(JSON.stringify(data.response), "response");
} else if (data.error !== undefined) {
append(data.error, "error", "", true);
} else if (data.notification !== undefined) {
append(data.notification, "notification", "", true);
} else {
append("Invalid response from TRY-REDIS server.", "error");
}

scrollDown();
});
};

function append(str, klass, prefix, isHtml) {
if (prefix === undefined) {
prefix = "";
}

if (!isHtml) {
prefix = escapeHtml(prefix);
str = escapeHtml(str);
}

var message =
'<div class="line ' + klass + '">' +
'<div class="nopad">' +
'<span class="prompt">' + prefix + '</span>' +
str +
'</div></div>';

$("#log").append(message);
};

function scrollDown() {
$("#log").attr({ scrollTop: $("#log").attr("scrollHeight") });
};

function escapeHtml(str) {
str = str.replace(/&/g, "&amp;");
str = str.replace(/</g, "&lt;");
str = str.replace(/>/g, "&gt;");
str = str.replace(/\n/g, "<br>");

return str;
};

function cursorToEnd(input, text) {
input.val(text);
setCaretToPos(input.get(0), text.length);
};

function setSelectionRange(input, selectionStart, selectionEnd) {
if (input.setSelectionRange) {
input.focus();
input.setSelectionRange(selectionStart, selectionEnd);
} else if (input.createTextRange) {
var range = input.createTextRange();
range.collapse(true);
range.moveEnd('character', selectionEnd);
range.moveStart('character', selectionStart);
range.select();
}
};

function setCaretToPos(input, pos) {
setSelectionRange(input, pos, pos);
};

$(document).ready(function () {
$("#input").focus();

$("#input").keydown(function (event) {
Expand All @@ -13,17 +94,17 @@ $(document).ready(function () {
return false;
} else if (event.keyCode == 38) {
if (historyCursor > 0) {
var text = history[--historyCursor];
var text = historyValues[--historyCursor];
cursorToEnd($("#input"), escapeHtml(text));
}

return false;
} else if (event.keyCode == 40) {
if (historyCursor < history.length - 1) {
var text = history[++historyCursor];
if (historyCursor < historyValues.length - 1) {
var text = historyValues[++historyCursor];
cursorToEnd($("#input"), escapeHtml(text));
} else {
historyCursor = history.length
historyCursor = historyValues.length
$("#input").val("");
}

Expand All @@ -34,86 +115,23 @@ $(document).ready(function () {
$("#toolbar").slideDown(500, function () {
$("#input").focus();
});

function submitCommand(text, dontClearInput) {
history.push(text);
historyCursor = history.length;

append(text, "input", "> ");
scrollDown();

if (!dontClearInput) {
$("#input").val("");
}

jQuery.getJSON("eval", { command: text }, function (data) {
if (data.response !== undefined) {
append(JSON.stringify(data.response), "response");
} else if (data.error !== undefined) {
append(data.error, "error");
} else if (data.notification !== undefined) {
append(data.notification, "notification", "", true);
} else {
append("Invalid response from TRY-REDIS server.", "error");
}

scrollDown();
});
};

function append(str, klass, prefix, isHtml) {
if (prefix === undefined) {
prefix = "";
}

if (!isHtml) {
prefix = escapeHtml(prefix);
str = escapeHtml(str);
}

var message =
'<div class="line ' + klass + '">' +
'<div class="nopad">' +
'<span class="prompt">' + prefix + '</span>' +
str +
'</div></div>';

$("#log").append(message);
};

function scrollDown() {
$("#log").attr({ scrollTop: $("#log").attr("scrollHeight") });
};

function escapeHtml(str) {
str = str.replace(/&/g, "&amp;");
str = str.replace(/</g, "&lt;");
str = str.replace(/>/g, "&gt;");
str = str.replace(/\n/g, "<br>");

return str;
};

function cursorToEnd(input, text) {
input.val(text);
setCaretToPos(input.get(0), text.length);
};

function setSelectionRange(input, selectionStart, selectionEnd) {
if (input.setSelectionRange) {
input.focus();
input.setSelectionRange(selectionStart, selectionEnd);
} else if (input.createTextRange) {
var range = input.createTextRange();
range.collapse(true);
range.moveEnd('character', selectionEnd);
range.moveStart('character', selectionStart);
range.select();
}
};

function setCaretToPos(input, pos) {
setSelectionRange(input, pos, pos);
};

$("a[href='#help']").live('click',function () {
submitCommand("help " + $(this).text());
return false;
});
$("a[href='#run']").live('click',function () {
submitCommand($(this).text());
return false;
});
/*
$("a[data-run-command]").live('click',function () {
submitCommand($.data(this,'run-command'))
return false;
});
$("a[href^='#']").live('click',function () {
var cmd=unescape($(this).attr('href').substr(1));
submitCommand(cmd);
return false;
});
*/
});
28 changes: 15 additions & 13 deletions try-redis.rb
@@ -1,15 +1,7 @@
#!/usr/bin/env ruby

require "rubygems"
require "sinatra/base"
require "haml"
require "sass"
require "json"
require "redis"
require "shellwords"
require "logger"
require "rdiscount"
require "andand"

module NamespaceTools
def namespace_input(ns, command, *args)
Expand Down Expand Up @@ -133,6 +125,12 @@ def remove_namespace(namespace, key)
end

class TryRedis < Sinatra::Base
#see the logging for development mode
configure :development do
enable :logging
disable :dump_errors
end

enable :sessions
enable :static

Expand Down Expand Up @@ -192,7 +190,7 @@ def execute_redis(argv)
raise "I'm sorry, I don't recognize that command. #{help}" unless argv.kind_of? Array

# Connect to the Redis server.
redis = Redis.new(:logger => Logger.new(STDOUT))
redis = Redis.new(:logger => Logger.new(File.join(File.dirname(__FILE__),'log','redis.log')))

if result = bypass(redis, argv)
result
Expand Down Expand Up @@ -252,12 +250,12 @@ def helpdocs
raw_docs =
Dir["redis-doc/*.markdown"].map do |filename|
command = filename.scan(/redis-doc\/(.*).markdown/).first.first
doc = RDiscount.new(File.read(filename)).to_html
doc = file_to_html(filename)

[ command, doc ]
end

cmds = raw_docs.map {|c, d| c.upcase}.sort.join(", ")
cmds = raw_docs.map {|c, d| "<a href=\"#help\">#{c.upcase}</a>"}.sort.join(", ")
raw_docs << [ "", "Please type HELP for one of these commands: " + cmds ]

@helpdocs ||= Hash[*raw_docs.flatten]
Expand All @@ -279,7 +277,7 @@ def tutorial(index)
doc = tutorialdocs[index]

if (1 ... tutorialdocs.count - 1).include? index
doc += '<p class="tutorial_next">Type NEXT to continue the tutorial.</p>'
doc += '<p class="tutorial_next">Type <a href="#run">NEXT</a> to continue the tutorial.</p>'
end

doc
Expand All @@ -289,7 +287,11 @@ def tutorial(index)
def tutorialdocs
@tutorialdocs ||=
Dir["tutorial/*.markdown"].sort.map do |filename|
RDiscount.new(File.read(filename)).to_html
file_to_html(filename)
end
end

def file_to_html(filename)
RDiscount.new(File.read(filename)).to_html
end
end
4 changes: 2 additions & 2 deletions tutorial/00.markdown
@@ -1,5 +1,5 @@
Welcome to **Try Redis**, a demonstration of the
[Redis](http://code.google.com/p/redis/) database!
[Redis](redis.io) database!

Please type TUTORIAL to begin a brief tutorial, HELP to see a list of supported
Please type [TUTORIAL](#run) to begin a brief tutorial, [HELP](#run) to see a list of supported
commands, or any valid Redis command to play with the database.
10 changes: 7 additions & 3 deletions tutorial/01.markdown
@@ -1,12 +1,16 @@
Redis is what is called a key-value store, often referred to as a NoSQL
database. The essence of a key-value store is the ability to store some data,
called a value, inside a key. This data can later be retrieved only if we know
the exact key used to store it. We can use the command SET to store the value
the exact key used to store it. We can use the command [SET](#help) to store the value
"fido" at key "server:name":

SET server:name "fido"
<pre><code>
<a href="#run">SET server:name "fido"</a>
</code></pre>

Redis will store our data permanently, so we can later ask "What is the value
stored at key server:name?" and Redis will reply with "fido":

GET server:name => "fido"
<pre><code>
<a href="#run">GET server:name</a> => "fido"
</code></pre>

0 comments on commit 467b97d

Please sign in to comment.