redistat 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/.document +5 -0
- data/.gitignore +25 -0
- data/.rspec +2 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +20 -0
- data/README.md +44 -0
- data/Rakefile +71 -0
- data/VERSION +1 -0
- data/lib/redistat.rb +104 -0
- data/lib/redistat/collection.rb +16 -0
- data/lib/redistat/core_ext/date.rb +8 -0
- data/lib/redistat/core_ext/fixnum.rb +8 -0
- data/lib/redistat/core_ext/time.rb +3 -0
- data/lib/redistat/database.rb +10 -0
- data/lib/redistat/date.rb +93 -0
- data/lib/redistat/event.rb +94 -0
- data/lib/redistat/finder.rb +165 -0
- data/lib/redistat/finder/date_set.rb +95 -0
- data/lib/redistat/key.rb +54 -0
- data/lib/redistat/label.rb +27 -0
- data/lib/redistat/model.rb +50 -0
- data/lib/redistat/result.rb +23 -0
- data/lib/redistat/scope.rb +18 -0
- data/lib/redistat/summary.rb +24 -0
- data/spec/_redistat_spec.rb +34 -0
- data/spec/collection_spec.rb +13 -0
- data/spec/date_spec.rb +95 -0
- data/spec/event_spec.rb +83 -0
- data/spec/finder/date_set_spec.rb +525 -0
- data/spec/finder_spec.rb +112 -0
- data/spec/key_spec.rb +63 -0
- data/spec/label_spec.rb +28 -0
- data/spec/model_helper.rb +15 -0
- data/spec/model_spec.rb +60 -0
- data/spec/redis-test.conf +9 -0
- data/spec/result_spec.rb +21 -0
- data/spec/scope_spec.rb +27 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/summary_spec.rb +72 -0
- metadata +216 -0
data/.document
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
|
+
|
21
|
+
## PROJECT::SPECIFIC
|
22
|
+
.bundle/*
|
23
|
+
.yardoc/*
|
24
|
+
spec/db/*
|
25
|
+
doc
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.0.3)
|
5
|
+
diff-lcs (1.1.2)
|
6
|
+
i18n (0.4.2)
|
7
|
+
json (1.4.6)
|
8
|
+
redis (2.1.1)
|
9
|
+
rspec (2.1.0)
|
10
|
+
rspec-core (~> 2.1.0)
|
11
|
+
rspec-expectations (~> 2.1.0)
|
12
|
+
rspec-mocks (~> 2.1.0)
|
13
|
+
rspec-core (2.1.0)
|
14
|
+
rspec-expectations (2.1.0)
|
15
|
+
diff-lcs (~> 1.1.2)
|
16
|
+
rspec-mocks (2.1.0)
|
17
|
+
time_ext (0.2.6)
|
18
|
+
activesupport (>= 2.3.0)
|
19
|
+
yard (0.6.3)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
activesupport (>= 2.3.0)
|
26
|
+
i18n
|
27
|
+
json (>= 1.0.0)
|
28
|
+
redis (>= 2.0.0)
|
29
|
+
rspec (>= 2.0.1)
|
30
|
+
time_ext (>= 0.2.6)
|
31
|
+
yard (>= 0.6.1)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Jim Myhrberg.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Redistat
|
2
|
+
|
3
|
+
A Redis-backed statistics storage and querying library written in Ruby.
|
4
|
+
|
5
|
+
## Early Beta
|
6
|
+
|
7
|
+
Currently this is an early beta release. Readme and documentation is forthcoming.
|
8
|
+
|
9
|
+
For now, please check `spec/model_spec.rb` and `spec/model_helper.rb` to get started with how to use Redistat.
|
10
|
+
|
11
|
+
|
12
|
+
## Note on Patches/Pull Requests
|
13
|
+
|
14
|
+
* Fork the project.
|
15
|
+
* Make your feature addition or bug fix.
|
16
|
+
* Add tests for it. This is important so I don't break it in a
|
17
|
+
future version unintentionally.
|
18
|
+
* Commit, do not mess with rakefile, version, or history.
|
19
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
20
|
+
* Send me a pull request. Bonus points for topic branches.
|
21
|
+
|
22
|
+
|
23
|
+
## License and Copyright
|
24
|
+
|
25
|
+
Copyright (c) 2010 Jim Myhrberg.
|
26
|
+
|
27
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
28
|
+
a copy of this software and associated documentation files (the
|
29
|
+
"Software"), to deal in the Software without restriction, including
|
30
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
31
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
32
|
+
permit persons to whom the Software is furnished to do so, subject to
|
33
|
+
the following conditions:
|
34
|
+
|
35
|
+
The above copyright notice and this permission notice shall be
|
36
|
+
included in all copies or substantial portions of the Software.
|
37
|
+
|
38
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
39
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
40
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
41
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
42
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
43
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
44
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = 'redistat'
|
8
|
+
gem.summary = 'A Redis-backed statistics storage and querying library written in Ruby.'
|
9
|
+
gem.description = 'A Redis-backed statistics storage and querying library written in Ruby.'
|
10
|
+
gem.email = 'contact@jimeh.me'
|
11
|
+
gem.homepage = 'http://github.com/jimeh/redistat'
|
12
|
+
gem.authors = ['Jim Myhrberg']
|
13
|
+
gem.add_dependency 'activesupport', '>= 2.3.0'
|
14
|
+
gem.add_dependency 'json', '>= 1.0.0'
|
15
|
+
gem.add_dependency 'redis', '>= 2.0.0'
|
16
|
+
gem.add_dependency 'time_ext', '>= 0.2.6'
|
17
|
+
gem.add_development_dependency 'rspec', '>= 2.0.1'
|
18
|
+
gem.add_development_dependency 'yard', '>= 0.6.1'
|
19
|
+
end
|
20
|
+
Jeweler::GemcutterTasks.new
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Rspec
|
27
|
+
require 'rspec/core/rake_task'
|
28
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
end
|
31
|
+
|
32
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
33
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
34
|
+
spec.rcov = true
|
35
|
+
end
|
36
|
+
|
37
|
+
task :spec => :check_dependencies
|
38
|
+
|
39
|
+
task :default => [:start, :spec, :stop]
|
40
|
+
|
41
|
+
|
42
|
+
# Start/stop Redis test server
|
43
|
+
REDIS_DIR = File.expand_path(File.join("..", "spec"), __FILE__)
|
44
|
+
REDIS_CNF = File.join(REDIS_DIR, "redis-test.conf")
|
45
|
+
REDIS_PID = File.join(REDIS_DIR, "db", "redis.pid")
|
46
|
+
|
47
|
+
desc "Start the Redis test server"
|
48
|
+
task :start do
|
49
|
+
unless File.exists?(REDIS_PID)
|
50
|
+
system "redis-server #{REDIS_CNF}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Stop the Redis test server"
|
55
|
+
task :stop do
|
56
|
+
if File.exists?(REDIS_PID)
|
57
|
+
system "kill #{File.read(REDIS_PID)}"
|
58
|
+
system "rm #{REDIS_PID}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# YARD Documentation
|
64
|
+
begin
|
65
|
+
require 'yard'
|
66
|
+
YARD::Rake::YardocTask.new
|
67
|
+
rescue LoadError
|
68
|
+
task :yardoc do
|
69
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
70
|
+
end
|
71
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/redistat.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/hash_with_indifferent_access' if !Hash.respond_to?(:with_indifferent_access) # Active Support 2.x and 3.x
|
5
|
+
require 'redis'
|
6
|
+
require 'date'
|
7
|
+
require 'time'
|
8
|
+
require 'time_ext'
|
9
|
+
require 'json'
|
10
|
+
require 'digest/sha1'
|
11
|
+
|
12
|
+
require 'redistat/collection'
|
13
|
+
require 'redistat/database'
|
14
|
+
require 'redistat/date'
|
15
|
+
require 'redistat/event'
|
16
|
+
require 'redistat/finder'
|
17
|
+
require 'redistat/finder/date_set'
|
18
|
+
require 'redistat/key'
|
19
|
+
require 'redistat/label'
|
20
|
+
require 'redistat/model'
|
21
|
+
require 'redistat/result'
|
22
|
+
require 'redistat/scope'
|
23
|
+
require 'redistat/summary'
|
24
|
+
|
25
|
+
require 'redistat/core_ext/date'
|
26
|
+
require 'redistat/core_ext/time'
|
27
|
+
require 'redistat/core_ext/fixnum'
|
28
|
+
|
29
|
+
module Redistat
|
30
|
+
|
31
|
+
KEY_NEXT_ID = ".next_id"
|
32
|
+
KEY_EVENT = ".event:"
|
33
|
+
KEY_LEBELS = "Redistat.lables:"
|
34
|
+
KEY_EVENT_IDS = ".event_ids"
|
35
|
+
|
36
|
+
class InvalidOptions < ArgumentError; end
|
37
|
+
|
38
|
+
# Provides access to the Redis database. This is shared accross all models and instances.
|
39
|
+
def redis
|
40
|
+
threaded[:redis] ||= connection(*options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def redis=(connection)
|
44
|
+
threaded[:redis] = connection
|
45
|
+
end
|
46
|
+
|
47
|
+
def threaded
|
48
|
+
Thread.current[:redistat] ||= {}
|
49
|
+
end
|
50
|
+
|
51
|
+
# Connect to a redis database.
|
52
|
+
#
|
53
|
+
# @param options [Hash] options to create a message with.
|
54
|
+
# @option options [#to_s] :host ('127.0.0.1') Host of the redis database.
|
55
|
+
# @option options [#to_s] :port (6379) Port number.
|
56
|
+
# @option options [#to_s] :db (0) Database number.
|
57
|
+
# @option options [#to_s] :timeout (0) Database timeout in seconds.
|
58
|
+
# @example Connect to a database in port 6380.
|
59
|
+
# Redistat.connect(:port => 6380)
|
60
|
+
def connect(*options)
|
61
|
+
self.redis = nil
|
62
|
+
@options = options
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return a connection to Redis.
|
66
|
+
#
|
67
|
+
# This is a wapper around Redis.new(options)
|
68
|
+
def connection(*options)
|
69
|
+
Redis.new(*options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def options
|
73
|
+
@options = [] unless defined? @options
|
74
|
+
@options
|
75
|
+
end
|
76
|
+
|
77
|
+
# Clear the database.
|
78
|
+
def flush
|
79
|
+
redis.flushdb
|
80
|
+
end
|
81
|
+
|
82
|
+
module_function :connect, :connection, :flush, :redis, :redis=, :options, :threaded
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Redistat
|
2
|
+
class Collection < ::Array
|
3
|
+
|
4
|
+
attr_accessor :from
|
5
|
+
attr_accessor :till
|
6
|
+
attr_accessor :depth
|
7
|
+
attr_accessor :total
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@from = options[:from] ||= nil
|
11
|
+
@till = options[:till] ||= nil
|
12
|
+
@depth = options[:depth] ||= nil
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Redistat
|
2
|
+
class Date
|
3
|
+
|
4
|
+
attr_accessor :year
|
5
|
+
attr_accessor :month
|
6
|
+
attr_accessor :day
|
7
|
+
attr_accessor :hour
|
8
|
+
attr_accessor :min
|
9
|
+
attr_accessor :sec
|
10
|
+
attr_accessor :usec
|
11
|
+
attr_accessor :depth
|
12
|
+
|
13
|
+
DEPTHS = [:year, :month, :day, :hour, :min, :sec, :usec]
|
14
|
+
|
15
|
+
def initialize(input, depth = nil)
|
16
|
+
@depth = depth
|
17
|
+
if input.is_a?(::Time)
|
18
|
+
from_time(input)
|
19
|
+
elsif input.is_a?(::Date)
|
20
|
+
from_date(input)
|
21
|
+
elsif input.is_a?(::String)
|
22
|
+
from_string(input)
|
23
|
+
elsif input.is_a?(::Fixnum)
|
24
|
+
from_integer(input)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_t
|
29
|
+
::Time.local(@year, @month, @day, @hour, @min, @sec, @usec)
|
30
|
+
end
|
31
|
+
alias :to_time :to_t
|
32
|
+
|
33
|
+
def to_d
|
34
|
+
::Date.civil(@year, @month, @day)
|
35
|
+
end
|
36
|
+
alias :to_date :to_d
|
37
|
+
|
38
|
+
def to_i
|
39
|
+
to_time.to_i
|
40
|
+
end
|
41
|
+
alias :to_integer :to_i
|
42
|
+
|
43
|
+
def to_s(depth = nil)
|
44
|
+
depth ||= @depth ||= :sec
|
45
|
+
output = ""
|
46
|
+
DEPTHS.each_with_index do |current, i|
|
47
|
+
break if self.send(current).nil?
|
48
|
+
if current != :usec
|
49
|
+
output << self.send(current).to_s.rjust((i <= 0) ? 4 : 2, '0')
|
50
|
+
else
|
51
|
+
output << "." + self.send(current).to_s.rjust(6, '0')
|
52
|
+
end
|
53
|
+
break if current == depth
|
54
|
+
end
|
55
|
+
output
|
56
|
+
end
|
57
|
+
alias :to_string :to_s
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def from_time(input)
|
62
|
+
DEPTHS.each do |k|
|
63
|
+
send("#{k}=", input.send(k))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def from_date(input)
|
68
|
+
[:year, :month, :day].each do |k|
|
69
|
+
send("#{k}=", input.send(k))
|
70
|
+
end
|
71
|
+
[:hour, :min, :sec, :usec].each do |k|
|
72
|
+
send("#{k}=", 0)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def from_integer(input)
|
77
|
+
from_time(::Time.at(input))
|
78
|
+
end
|
79
|
+
|
80
|
+
def from_string(input)
|
81
|
+
input += "19700101000000"[input.size..-1] if input =~ /^\d\d\d[\d]+$/i
|
82
|
+
from_time(::Time.parse(input))
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
module DateHelper
|
88
|
+
def to_redistat(depth = nil)
|
89
|
+
Redistat::Date.new(self, depth)
|
90
|
+
end
|
91
|
+
alias :to_rs :to_redistat
|
92
|
+
end
|
93
|
+
end
|