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 CHANGED
@@ -4,4 +4,5 @@ coverage
4
4
  rdoc
5
5
  pkg
6
6
  test/data
7
- demos/simple/public/sparks/*
7
+ dump.rdb
8
+ demos/**/public/sparks/*
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0
1
+ 2.1.0
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'lib' << 'test'
6
+ test.pattern = 'test/**/*_test.rb'
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
@@ -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>
@@ -3,8 +3,6 @@ require 'rubygems'
3
3
  require 'sinatra'
4
4
 
5
5
  require 'sparkplug'
6
- require 'sparkplug/handlers/csv_data'
7
- require 'sparkplug/cachers/filesystem'
8
6
 
9
7
  pub_dir = File.expand_path(File.join(File.dirname(__FILE__), 'public'))
10
8
  use Sparkplug, :prefix => 'sparks',
@@ -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:
@@ -1,4 +1,3 @@
1
- require 'sparkplug'
2
1
  require 'time'
3
2
 
4
3
  class Sparkplug
@@ -1,4 +1,3 @@
1
- require 'sparkplug/cachers/abstract'
2
1
  require 'fileutils'
3
2
 
4
3
  class Sparkplug
@@ -1,4 +1,3 @@
1
- require 'sparkplug/cachers/abstract'
2
1
  require 'fileutils'
3
2
 
4
3
  class Sparkplug
@@ -1,5 +1,3 @@
1
- require 'sparkplug'
2
-
3
1
  class Sparkplug
4
2
  module Handlers
5
3
  # Abstract class for retrieving the data and determining whether the cache
@@ -1,5 +1,3 @@
1
- require 'sparkplug/handlers/abstract_data'
2
-
3
1
  module Sparkplug::Handlers
4
2
  # Reads sparkline data from CSV files. Only the first line of numbers are
5
3
  # read. Requests for "/sparks/stats.csv" will pass a data_path of "stats.csv"
@@ -1,5 +1,3 @@
1
- require 'sparkplug/handlers/abstract_data'
2
-
3
1
  module Sparkplug::Handlers
4
2
  # Allows you to stub sparkline data in a global hash. Requests for
5
3
  # "/sparks/stats.csv" will pass a data_path of "stats.csv"
@@ -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.0.0"
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-11-01}
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.4}
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
+
@@ -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.0.0
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-11-01 00:00:00 -07:00
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.4
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.