sparkplug 2.0.0 → 2.1.0
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 +2 -1
- data/VERSION +1 -1
- data/demos/redis/Rakefile +10 -0
- data/demos/redis/lib/redis_demo/handler.rb +27 -0
- data/demos/redis/lib/redis_demo/spark_list.rb +111 -0
- data/demos/redis/sparkplug_redis.rb +74 -0
- data/demos/redis/test/redis_demo_test.rb +93 -0
- data/demos/redis/views/show.erb +35 -0
- data/demos/simple/sparkplug_demo.rb +0 -2
- data/lib/sparkplug.rb +12 -0
- data/lib/sparkplug/cachers/abstract.rb +0 -1
- data/lib/sparkplug/cachers/filesystem.rb +0 -1
- data/lib/sparkplug/cachers/memory.rb +0 -1
- data/lib/sparkplug/handlers/abstract_data.rb +0 -2
- data/lib/sparkplug/handlers/csv_data.rb +0 -2
- data/lib/sparkplug/handlers/stubbed_data.rb +0 -2
- data/sparkplug.gemspec +15 -3
- data/test/sparkplug_test.rb +0 -4
- metadata +11 -3
data/.gitignore
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.1.0
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RedisDemo
|
2
|
+
class Handler < Sparkplug::Handlers::AbstractData
|
3
|
+
attr_reader :list
|
4
|
+
|
5
|
+
def initialize(list)
|
6
|
+
@list = list
|
7
|
+
end
|
8
|
+
|
9
|
+
def data_path=(v)
|
10
|
+
v.sub!(/^\//, '')
|
11
|
+
@data_path = v
|
12
|
+
@plug = @list.find(@data_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def exists?
|
16
|
+
@plug.exists?
|
17
|
+
end
|
18
|
+
|
19
|
+
def updated_at
|
20
|
+
@plug.updated_at
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch
|
24
|
+
yield @plug.datapoints
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module RedisDemo
|
2
|
+
# Persists sparkline data to Redis. Data is pushed and popped from a Redis list.
|
3
|
+
class SparkList
|
4
|
+
attr_reader :redis, :plug_list
|
5
|
+
attr_accessor :prefix, :limit
|
6
|
+
|
7
|
+
# SparkList options
|
8
|
+
# :prefix => 'plug'
|
9
|
+
# :limit => 50
|
10
|
+
# :redis => {} # passed to Redis
|
11
|
+
def initialize(options = {})
|
12
|
+
@prefix = options[:prefix] || 'plug'
|
13
|
+
@limit = options[:limit] || 50
|
14
|
+
@index_key = "#{@prefix}:index"
|
15
|
+
@redis = Redis.new(options[:redis] || {})
|
16
|
+
@plug_list = PlugList.new(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
def find(name)
|
20
|
+
Plug.new(self, name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class PlugList
|
25
|
+
def initialize(list)
|
26
|
+
@list = list
|
27
|
+
@redis = @list.redis
|
28
|
+
@list_key = "#{@prefix}:sparkplug:list"
|
29
|
+
end
|
30
|
+
|
31
|
+
def add(plug)
|
32
|
+
@redis.sadd @list_key, plug.name
|
33
|
+
@redis.sort @list_key, :order => "ALPHA"
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete(plug)
|
37
|
+
@redis.srem @list_key, plug.name
|
38
|
+
end
|
39
|
+
|
40
|
+
def all
|
41
|
+
@redis.smembers(@list_key)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# represents a list of datapoints
|
46
|
+
class Plug
|
47
|
+
attr_reader :name
|
48
|
+
|
49
|
+
def initialize(list, name)
|
50
|
+
@list = list
|
51
|
+
@redis = @list.redis
|
52
|
+
@name = name
|
53
|
+
@name_key = @updated_key = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def add(value)
|
57
|
+
points = count
|
58
|
+
@redis.rpush(name_key, value.to_i)
|
59
|
+
if points.zero?
|
60
|
+
@list.plug_list.add(self)
|
61
|
+
end
|
62
|
+
excess = points + 1 - @list.limit
|
63
|
+
if excess > 0
|
64
|
+
excess.times { @redis.lpop(name_key) }
|
65
|
+
end
|
66
|
+
self.updated_at = Time.now.utc
|
67
|
+
end
|
68
|
+
|
69
|
+
def datapoints
|
70
|
+
@redis.lrange(name_key, 0, @list.limit-1).map! { |p| p.to_i }
|
71
|
+
end
|
72
|
+
|
73
|
+
def updated_at
|
74
|
+
value = @redis.get(updated_key)
|
75
|
+
value.nil? ? Time.now.utc : Time.parse(value)
|
76
|
+
end
|
77
|
+
|
78
|
+
def updated_at=(v)
|
79
|
+
@redis.set(updated_key, v.to_s)
|
80
|
+
end
|
81
|
+
|
82
|
+
def delete
|
83
|
+
@list.plug_list.delete(self)
|
84
|
+
@redis.delete(name_key)
|
85
|
+
@redis.delete(updated_key)
|
86
|
+
end
|
87
|
+
|
88
|
+
def exists?
|
89
|
+
count > 0
|
90
|
+
end
|
91
|
+
|
92
|
+
def count
|
93
|
+
@redis.llen(name_key)
|
94
|
+
end
|
95
|
+
|
96
|
+
def name_key
|
97
|
+
@name_key ||= plug_name(@name)
|
98
|
+
end
|
99
|
+
|
100
|
+
def updated_key
|
101
|
+
@updated_key ||= plug_name(@name, :updated)
|
102
|
+
end
|
103
|
+
|
104
|
+
# convert a simple plug name to a full plug name
|
105
|
+
def plug_name(plug, *extras)
|
106
|
+
s = "#{@list.prefix}:#{plug}"
|
107
|
+
extras.each { |e| s << ':' << e.to_s }
|
108
|
+
s
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
3
|
+
require 'rubygems'
|
4
|
+
require 'sinatra'
|
5
|
+
require 'redis'
|
6
|
+
require 'time'
|
7
|
+
|
8
|
+
require 'sparkplug'
|
9
|
+
require 'redis_demo/spark_list'
|
10
|
+
require 'redis_demo/handler'
|
11
|
+
|
12
|
+
config =
|
13
|
+
if ENV['CONFIG']
|
14
|
+
if File.exist?(ENV['CONFIG'])
|
15
|
+
require 'yaml'
|
16
|
+
YAML.load_file(ENV['CONFIG'])
|
17
|
+
else
|
18
|
+
puts "Config file #{ENV['CONFIG'].inspect} not found."
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
else
|
22
|
+
{}
|
23
|
+
end
|
24
|
+
|
25
|
+
$redis_list = RedisDemo::SparkList.new(config)
|
26
|
+
$handler = RedisDemo::Handler.new($redis_list)
|
27
|
+
pub_dir = File.expand_path(File.join(File.dirname(__FILE__), 'public'))
|
28
|
+
use Sparkplug, :prefix => 'sparks',
|
29
|
+
:handler => $handler,
|
30
|
+
:cacher => Sparkplug::Cachers::Filesystem.new(File.join(pub_dir, 'sparks'))
|
31
|
+
|
32
|
+
get '/' do
|
33
|
+
@plug_list = $redis_list.plug_list
|
34
|
+
erb :show
|
35
|
+
end
|
36
|
+
|
37
|
+
post '/modify' do
|
38
|
+
case params[:commit]
|
39
|
+
when /delete/i
|
40
|
+
$redis_list.find(params[:plug]).delete
|
41
|
+
redirect '/'
|
42
|
+
else
|
43
|
+
plug = $redis_list.find(params[:plug])
|
44
|
+
plug.add(params[:value])
|
45
|
+
redirect "/#{params[:plug]}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
post '/:plug/:value' do
|
50
|
+
plug = $redis_list.find(params[:plug])
|
51
|
+
plug.add(params[:value])
|
52
|
+
'ok'
|
53
|
+
end
|
54
|
+
|
55
|
+
get '/:plug.json' do
|
56
|
+
plug = $redis_list.find(params[:plug])
|
57
|
+
"[#{plug.datapoints * ","}]"
|
58
|
+
end
|
59
|
+
|
60
|
+
get '/:plug' do
|
61
|
+
@plug_list = $redis_list.plug_list
|
62
|
+
@plug = $redis_list.find(params[:plug])
|
63
|
+
erb :show
|
64
|
+
end
|
65
|
+
|
66
|
+
delete '/:plug' do
|
67
|
+
plug = $redis_list.find(params[:plug])
|
68
|
+
plug.delete
|
69
|
+
'deleted'
|
70
|
+
end
|
71
|
+
|
72
|
+
def h(s)
|
73
|
+
Rack::Utils.escape(s)
|
74
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/test'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
|
7
|
+
require 'sparkplug_redis'
|
8
|
+
|
9
|
+
$redis_list.redis.flushall
|
10
|
+
$redis_list.prefix = 'test'
|
11
|
+
$redis_list.limit = 5
|
12
|
+
sake = $redis_list.find('sake')
|
13
|
+
unagi = $redis_list.find('unagi')
|
14
|
+
sake.add 1
|
15
|
+
sake.add 2
|
16
|
+
sake.add 3
|
17
|
+
unagi.add 1
|
18
|
+
|
19
|
+
class RedisDemoTest < Test::Unit::TestCase
|
20
|
+
include Rack::Test::Methods
|
21
|
+
|
22
|
+
def app
|
23
|
+
Sinatra::Application
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_root_url
|
27
|
+
get '/'
|
28
|
+
assert last_response.ok?
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_adding_a_datapoint_for_new_plug
|
32
|
+
get '/koi.json'
|
33
|
+
assert_equal '[]', last_response.body
|
34
|
+
|
35
|
+
post '/koi/5'
|
36
|
+
assert last_response.ok?
|
37
|
+
|
38
|
+
get '/koi.json'
|
39
|
+
assert_equal '[5]', last_response.body
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_datapoint_limit
|
43
|
+
10.times do |i|
|
44
|
+
post "/shiira/#{i + 5}"
|
45
|
+
end
|
46
|
+
get "/shiira.json"
|
47
|
+
assert_equal "[10,11,12,13,14]", last_response.body
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_fetching_csv_data_for_existing_slug
|
51
|
+
get '/sake.json'
|
52
|
+
assert_equal '[1,2,3]', last_response.body
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_deletes_plug
|
56
|
+
get '/unagi.json'
|
57
|
+
assert_equal '[1]', last_response.body
|
58
|
+
|
59
|
+
delete '/unagi'
|
60
|
+
|
61
|
+
get '/unagi.json'
|
62
|
+
assert_equal '[]', last_response.body
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class RedisDemoPlugTest < Test::Unit::TestCase
|
67
|
+
def test_plug_list_stores_existing_plugs
|
68
|
+
assert $redis_list.plug_list.all.include?('sake')
|
69
|
+
assert !$redis_list.plug_list.all.include?('flounder')
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_adding_plug_adds_to_datapoint
|
73
|
+
assert !$redis_list.plug_list.all.include?('tamago')
|
74
|
+
$redis_list.find('tamago').add 5
|
75
|
+
assert $redis_list.plug_list.all.include?('tamago')
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_removing_plug_clears_from_datapoint
|
79
|
+
$redis_list.find('tamago').add 5
|
80
|
+
assert $redis_list.plug_list.all.include?('tamago')
|
81
|
+
$redis_list.find('tamago').delete
|
82
|
+
assert !$redis_list.plug_list.all.include?('tamago')
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_adding_datapoint_sets_updated_at
|
86
|
+
plug = $redis_list.find('shiira')
|
87
|
+
plug.add 1
|
88
|
+
date = plug.updated_at
|
89
|
+
sleep 1
|
90
|
+
plug.add 5
|
91
|
+
assert_not_equal date, plug.updated_at
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
4
|
+
<title>Sparkplug - Ruby Rack module for generating sparkline graphs on the fly</title>
|
5
|
+
<style type="text/css" media="screen">
|
6
|
+
h1, div, p {
|
7
|
+
font-family: verdana;
|
8
|
+
}
|
9
|
+
</style>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<h1>Sparkplug Redis Demo<% if @plug %>: <%=h @plug.name %><% end %></h1>
|
13
|
+
<% if @plug %>
|
14
|
+
<div>
|
15
|
+
<img src="/sparks/<%= @plug.name %>.png" />
|
16
|
+
</div>
|
17
|
+
<p>(if you can see this, the rack module works!)</p>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<p><strong>Existing:</strong> <%= @plug_list.all.map { |name| %(<a href="/#{h(name)}">#{h(name)}</a>) }.join(", ") %></p>
|
21
|
+
<% if @plug %>
|
22
|
+
<p><a href="/">Back</a></p>
|
23
|
+
<% end %>
|
24
|
+
<form action="/modify" method="post">
|
25
|
+
<div>
|
26
|
+
<label>Name: <input type="text" name="plug" value="<%= @plug.name if @plug %>" /></label><br />
|
27
|
+
<label>Value: <input type="text" name="value" value="" size="5" /></label><br />
|
28
|
+
<input type="submit" name="commit" value="Save">
|
29
|
+
<% if @plug %>
|
30
|
+
<input type="submit" name="commit" value="Delete">
|
31
|
+
<% end %>
|
32
|
+
</div>
|
33
|
+
</form>
|
34
|
+
</body>
|
35
|
+
</html>
|
data/lib/sparkplug.rb
CHANGED
@@ -3,6 +3,18 @@ require 'spark_pr'
|
|
3
3
|
# Render sparkline graphs dynamically from datapoints in a matching CSV file
|
4
4
|
# (or anything that there is a Handler for).
|
5
5
|
class Sparkplug
|
6
|
+
module Cachers
|
7
|
+
autoload :Abstract, 'sparkplug/cachers/abstract'
|
8
|
+
autoload :Filesystem, 'sparkplug/cachers/filesystem'
|
9
|
+
autoload :Memory, 'sparkplug/cachers/memory'
|
10
|
+
end
|
11
|
+
|
12
|
+
module Handlers
|
13
|
+
autoload :AbstractData, 'sparkplug/handlers/abstract_data'
|
14
|
+
autoload :CsvData, 'sparkplug/handlers/csv_data'
|
15
|
+
autoload :StubbedData, 'sparkplug/handlers/stubbed_data'
|
16
|
+
end
|
17
|
+
|
6
18
|
DEFAULT_SPARK_OPTIONS = {:has_min => true, :has_max => true, :height => 40, :step => 10}
|
7
19
|
|
8
20
|
# Options:
|
data/sparkplug.gemspec
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
1
4
|
# -*- encoding: utf-8 -*-
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
7
|
s.name = %q{sparkplug}
|
5
|
-
s.version = "2.
|
8
|
+
s.version = "2.1.0"
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["rick"]
|
9
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-12-29}
|
10
13
|
s.email = %q{technoweenie@gmail.com}
|
11
14
|
s.extra_rdoc_files = [
|
12
15
|
"LICENSE",
|
@@ -19,6 +22,14 @@ Gem::Specification.new do |s|
|
|
19
22
|
"README.rdoc",
|
20
23
|
"Rakefile",
|
21
24
|
"VERSION",
|
25
|
+
"demos/redis/Rakefile",
|
26
|
+
"demos/redis/lib/redis_demo/handler.rb",
|
27
|
+
"demos/redis/lib/redis_demo/spark_list.rb",
|
28
|
+
"demos/redis/public/sparks/foo.png",
|
29
|
+
"demos/redis/public/sparks/technoweenie.png",
|
30
|
+
"demos/redis/sparkplug_redis.rb",
|
31
|
+
"demos/redis/test/redis_demo_test.rb",
|
32
|
+
"demos/redis/views/show.erb",
|
22
33
|
"demos/simple/public/temps/portland/2007.csv",
|
23
34
|
"demos/simple/sparkplug_demo.rb",
|
24
35
|
"demos/simple/views/readme.erb",
|
@@ -36,7 +47,7 @@ Gem::Specification.new do |s|
|
|
36
47
|
s.homepage = %q{http://github.com/technoweenie/sparkplug}
|
37
48
|
s.rdoc_options = ["--charset=UTF-8"]
|
38
49
|
s.require_paths = ["lib"]
|
39
|
-
s.rubygems_version = %q{1.3.
|
50
|
+
s.rubygems_version = %q{1.3.5}
|
40
51
|
s.summary = %q{Rack module that dynamically generates sparkline graphs from a set of numbers.}
|
41
52
|
s.test_files = [
|
42
53
|
"test/sparkplug_test.rb"
|
@@ -52,3 +63,4 @@ Gem::Specification.new do |s|
|
|
52
63
|
else
|
53
64
|
end
|
54
65
|
end
|
66
|
+
|
data/test/sparkplug_test.rb
CHANGED
@@ -6,10 +6,6 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
6
6
|
require 'rack'
|
7
7
|
require 'rack/test'
|
8
8
|
require 'sparkplug'
|
9
|
-
require 'sparkplug/handlers/stubbed_data'
|
10
|
-
require 'sparkplug/handlers/csv_data'
|
11
|
-
require 'sparkplug/cachers/filesystem'
|
12
|
-
require 'sparkplug/cachers/memory'
|
13
9
|
|
14
10
|
class SparkplugTest < Test::Unit::TestCase
|
15
11
|
include Rack::Test::Methods
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sparkplug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rick
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-29 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -29,6 +29,14 @@ files:
|
|
29
29
|
- README.rdoc
|
30
30
|
- Rakefile
|
31
31
|
- VERSION
|
32
|
+
- demos/redis/Rakefile
|
33
|
+
- demos/redis/lib/redis_demo/handler.rb
|
34
|
+
- demos/redis/lib/redis_demo/spark_list.rb
|
35
|
+
- demos/redis/public/sparks/foo.png
|
36
|
+
- demos/redis/public/sparks/technoweenie.png
|
37
|
+
- demos/redis/sparkplug_redis.rb
|
38
|
+
- demos/redis/test/redis_demo_test.rb
|
39
|
+
- demos/redis/views/show.erb
|
32
40
|
- demos/simple/public/temps/portland/2007.csv
|
33
41
|
- demos/simple/sparkplug_demo.rb
|
34
42
|
- demos/simple/views/readme.erb
|
@@ -66,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
74
|
requirements: []
|
67
75
|
|
68
76
|
rubyforge_project:
|
69
|
-
rubygems_version: 1.3.
|
77
|
+
rubygems_version: 1.3.5
|
70
78
|
signing_key:
|
71
79
|
specification_version: 3
|
72
80
|
summary: Rack module that dynamically generates sparkline graphs from a set of numbers.
|