skvs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in skvs.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/skvs ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "skvs"
4
+
5
+ Sinatra::Application.run!(:port => 7654)
@@ -0,0 +1,3 @@
1
+ module Skvs
2
+ VERSION = "0.0.1"
3
+ end
data/lib/skvs.rb ADDED
@@ -0,0 +1,73 @@
1
+ require "skvs/version"
2
+ require "sinatra"
3
+ require "redis"
4
+ require "cgi"
5
+
6
+ get "/" do
7
+ keys = redis.keys("skvs:#{params[:q]}*").sort
8
+ @count = keys.count
9
+ keys = keys.first(load_count + 1)
10
+
11
+ if keys.size > load_count
12
+ keys.pop
13
+ @oversized = true
14
+ end
15
+
16
+ if keys.any?
17
+ values = redis.mget(*keys)
18
+ @data = keys.map{|k| k.split(":", 2).last }.zip(values)
19
+ else
20
+ @data = []
21
+ end
22
+
23
+ erb :index
24
+ end
25
+
26
+ get "/*" do
27
+ content_type "text/plain"
28
+ redis_get params[:splat]
29
+ end
30
+
31
+ put "/*" do
32
+ redis_set params[:splat], request.body.read
33
+ nil
34
+ end
35
+
36
+ post "/_set" do
37
+ redis_set params[:key], params[:value]
38
+ redirect url("/")
39
+ end
40
+
41
+ helpers do
42
+ def load_count
43
+ [params[:load_count].to_i, 5].max
44
+ end
45
+
46
+ def h(v)
47
+ CGI.escapeHTML(v)
48
+ end
49
+
50
+ def hbr(v)
51
+ CGI.escapeHTML(v).gsub("\n", "\n<br/>")
52
+ end
53
+
54
+ def key(*k)
55
+ "skvs:#{k.flatten.join("/")}"
56
+ end
57
+
58
+ def redis
59
+ @redis ||= Redis.new
60
+ end
61
+
62
+ def redis_set(k, v)
63
+ if v.to_s == ""
64
+ redis.del key(*k)
65
+ else
66
+ redis.set key(*k), v
67
+ end
68
+ end
69
+
70
+ def redis_get(k)
71
+ redis.get key(k)
72
+ end
73
+ end
@@ -0,0 +1,173 @@
1
+ <html>
2
+ <head>
3
+ <style>
4
+ table{
5
+ border-collapse:separate;
6
+ border-spacing: 0 20px;
7
+
8
+ width: 100%;
9
+ }
10
+
11
+ table td, table th{
12
+ width: 50%;
13
+ padding: 0 10px;
14
+ }
15
+
16
+ table tfoot a{
17
+ text-decoration: underline;
18
+ }
19
+
20
+ table td{
21
+ border-left: 1px solid #eee;
22
+ }
23
+
24
+ table th{
25
+ text-align: right;
26
+ font-weight: bold;
27
+ border-right: 1px solid #fff;
28
+ }
29
+
30
+ table tr:hover th{
31
+ border-right: 1px solid #eee;
32
+ }
33
+
34
+ * {
35
+ font-weight: inherit;
36
+ text-decoration: inherit;
37
+ color: inherit;
38
+ }
39
+ strong {
40
+ font-weight: bold;
41
+ }
42
+
43
+ body {
44
+ font-family: "helvetica neue", arial, sans-serif;
45
+ font-weight: 200;
46
+ }
47
+
48
+ #search, tfoot {
49
+ text-align: center;
50
+ }
51
+
52
+ h1, td *, th *, th, td{
53
+ vertical-align: top;
54
+ }
55
+
56
+ h1 {
57
+ text-align: center;
58
+ font-weight: bold;
59
+ }
60
+ textarea {
61
+ padding: 2px;
62
+ }
63
+
64
+ </style>
65
+ <title>Simple Key/Value Store (SKVS)</title>
66
+ </head>
67
+ <body>
68
+ <h1>Simple Key/Value Store (SKVS)</h1>
69
+
70
+ <form id="search" method="get" action="<%= url("/") %>">
71
+ <input type='search' placeholder='search' name='q' value="<%=h params[:q].to_s %>" />
72
+ </form>
73
+
74
+ <form id="main" method="post" action="<%= url("/_set") %>">
75
+
76
+ <table id="data">
77
+ <thead>
78
+ <tr>
79
+ <th>
80
+ <input form="main" name="key" placeholder="key" required />
81
+ </th>
82
+ <td>
83
+ <textarea form="main" name="value" placeholder="value" ></textarea>
84
+ <input form="main" type="submit" value="set" />
85
+ </td>
86
+ </tr>
87
+ </thead>
88
+ <tfoot>
89
+ <tr>
90
+ <td colspan="2">
91
+ <% if @count > load_count %>
92
+ Showing <strong><%= load_count %></strong> of <strong><%= @count %></strong>,
93
+ <a href="<%= url("/?load_count=#{load_count*2}&q=#{URI.encode(params[:q].to_s)}") %>">
94
+ load more?
95
+ </a>
96
+ <% else %>
97
+ Showing all <strong><%= @count %></strong>.
98
+ <% end %>
99
+ </td>
100
+ </tr>
101
+ </tfoot>
102
+ <tbody>
103
+ <% @data.each do |k,v| %>
104
+ <tr>
105
+ <th><a href="<%= url("/#{k}") %>"><%=h k %></a></th>
106
+ <% if v.length < 100 %>
107
+ <td><%=hbr v %></td>
108
+ <% else %>
109
+ <td class="truncated"><%=hbr v[0..100] %>...</td>
110
+ <% end %>
111
+ </tr>
112
+ <% end %>
113
+ </tbody>
114
+ </table>
115
+
116
+ </form>
117
+
118
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript" charset="utf-8"></script>
119
+
120
+ <script type="text/javascript" charset="utf-8">
121
+ $(function(){
122
+ $("input[name=key]").focus();
123
+ $("tbody").on("click", "td", function(){
124
+ var $t = $(this),
125
+ key = $t.parent("tr").find("th").text();
126
+
127
+ if($t.hasClass("truncated")){
128
+ $.get(<%= url("/").inspect %>+key, function(value){
129
+ $("input[name=key]").val(key);
130
+ $("textarea[name=value]").val(value).focus().select();
131
+ });
132
+ }else{
133
+ $("input[name=key]").val(key);
134
+ $("textarea[name=value]").val($t.text()).focus().select();
135
+ }
136
+ });
137
+
138
+
139
+ var update = function(url){
140
+ $.get(url, function(data){
141
+ var doc = $(data);
142
+ $("#data tbody").replaceWith(doc.find("#data tbody"));
143
+ $("#data tfoot").replaceWith(doc.find("#data tfoot"));
144
+ $("#search input").val(doc.find("input[type=search]").val());
145
+ });
146
+ }
147
+
148
+
149
+ var oldUrl = null;
150
+ var seachCallback = function(el){
151
+ var url = "/?q="+encodeURIComponent($(this).val());
152
+ if(oldUrl === url){
153
+ return;
154
+ }
155
+ oldUrl = url;
156
+ window.history.pushState({}, "", url);
157
+ update(url);
158
+ };
159
+
160
+ $(window).on("popstate", function(){
161
+ update(document.location);
162
+ })
163
+
164
+ $("#search input")
165
+ .on("keyup", seachCallback)
166
+ .on("change", seachCallback)
167
+ .on("search", seachCallback);
168
+
169
+ });
170
+ </script>
171
+
172
+ </body>
173
+ </html>
data/readme.markdown ADDED
@@ -0,0 +1,34 @@
1
+ SKVS - Simple Key/Value Store
2
+ =============================
3
+
4
+ A dirt simple HTTP key value store, with a fancy UI.
5
+
6
+ Usage
7
+ -----
8
+ 1. Install the gem:
9
+
10
+ $ gem install skvs
11
+
12
+ 2. Start the server:
13
+
14
+ $ skvs
15
+
16
+ 3. Navigate the the UI:
17
+
18
+ [http://localhost:7654/](http://localhost:7654/)
19
+
20
+
21
+ Example Bash Client
22
+ -------------------
23
+
24
+ function skvs_pull(){
25
+ echo $(curl -s -o - "http://localhost:7654/$1")
26
+ }
27
+
28
+ function skvs_push(){
29
+ local key
30
+ key=$1
31
+ shift
32
+ curl -XPUT --data-binary "$*" -s -o /dev/null "http://localhost:7654/$key"
33
+ }
34
+
data/skvs.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "skvs/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "skvs"
7
+ s.version = Skvs::VERSION
8
+ s.authors = ["Tom Lea"]
9
+ s.email = ["commit@tomlea.co.uk"]
10
+ s.homepage = ""
11
+ s.summary = %q{Simple Key/Value Store}
12
+ s.description = %q{A dirt simple HTTP key value store, with a fancy UI.
13
+ }
14
+
15
+ s.rubyforge_project = "skvs"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency "redis"
23
+ s.add_runtime_dependency "sinatra"
24
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skvs
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Tom Lea
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-09 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: redis
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: sinatra
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description: "A dirt simple HTTP key value store, with a fancy UI.\n "
49
+ email:
50
+ - commit@tomlea.co.uk
51
+ executables:
52
+ - skvs
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gitignore
59
+ - Gemfile
60
+ - Rakefile
61
+ - bin/skvs
62
+ - lib/skvs.rb
63
+ - lib/skvs/version.rb
64
+ - lib/views/index.erb
65
+ - readme.markdown
66
+ - skvs.gemspec
67
+ homepage: ""
68
+ licenses: []
69
+
70
+ post_install_message:
71
+ rdoc_options: []
72
+
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 3
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ requirements: []
94
+
95
+ rubyforge_project: skvs
96
+ rubygems_version: 1.8.13
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Simple Key/Value Store
100
+ test_files: []
101
+