duly_noted 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/DOCS.md +9 -11
- data/README.md +27 -8
- data/lib/duly_noted.rb +24 -34
- data/lib/duly_noted/helpers.rb +6 -5
- data/lib/duly_noted/updater.rb +30 -5
- data/lib/duly_noted/version.rb +1 -1
- data/spec/duly_noted_spec.rb +23 -27
- metadata +22 -22
data/DOCS.md
CHANGED
@@ -21,10 +21,6 @@ The **DulyNoted** module contains five main methods:
|
|
21
21
|
|
22
22
|
`meta_fields`: An array of fields to retrieve from the meta hash. If not specified, the entire hash will be grabbed. Fields will be converted to strings, because redis converts all hash keys and values to strings.
|
23
23
|
|
24
|
-
`ref_id`: If you need to reference the metric later, perhaps to add more metadata later on, you can set a reference id that you can use to update the metric. The `ref_id` must be unique across `metric_name`s.
|
25
|
-
|
26
|
-
`editable_for`: If you want to clear `ref_id`s out, you can set the metric to only be editable for a certain amount of time. `editable_for` is defined in seconds. After that amount of time, you will no longer be able to edit the meta data, and you may use that `ref_id` again. By default, `ref_id`s never expire.
|
27
|
-
|
28
24
|
`time_start`: The start of the time range to grab the data from. **Important:** `time_start` should always be the time farthest in the past.
|
29
25
|
|
30
26
|
`time_end`: The end of the time range to grab the data from. **Important:** `time_end` should always be the time closest to the present.
|
@@ -35,9 +31,11 @@ The **DulyNoted** module contains five main methods:
|
|
35
31
|
|
36
32
|
##Track
|
37
33
|
|
38
|
-
_parameters: `metric_name`, `for`(optional), `generated_at`(optional), `meta`(optional)
|
34
|
+
_parameters: `metric_name`, `for`(optional), `generated_at`(optional), `meta`(optional)_
|
35
|
+
|
36
|
+
_returns: `id` for editing metadata_
|
39
37
|
|
40
|
-
Use track to track an event, like a page view, or a download. Use the `for` option to give an event a context. For instance, for page views, you might set `for` to `home_page`, so that you know which page was viewed. You can also store metadata along with your metric with the `meta` hash.
|
38
|
+
Use track to track an event, like a page view, or a download. Use the `for` option to give an event a context. For instance, for page views, you might set `for` to `home_page`, so that you know which page was viewed. You can also store metadata along with your metric with the `meta` hash.
|
41
39
|
|
42
40
|
###Usage
|
43
41
|
|
@@ -45,21 +43,21 @@ Use track to track an event, like a page view, or a download. Use the `for` opt
|
|
45
43
|
|
46
44
|
DulyNoted.track("video_plays", for: ["user_7261", "video_917216"], meta: {amount_watched: 0})
|
47
45
|
|
48
|
-
DulyNoted.track("purchases", for: "user_281", generated_at: 1.day.ago
|
46
|
+
DulyNoted.track("purchases", for: "user_281", generated_at: 1.day.ago)
|
49
47
|
|
50
48
|
|
51
49
|
|
52
50
|
##Update
|
53
51
|
|
54
|
-
_parameters: `
|
52
|
+
_parameters: `id`, `meta`(optional)_
|
55
53
|
|
56
|
-
Use update to add, or edit the metadata stored with a metric.
|
54
|
+
Use update to add, or edit the metadata stored with a metric.
|
57
55
|
|
58
56
|
###Usage
|
59
57
|
|
60
|
-
DulyNoted.track("page_views",
|
58
|
+
DulyNoted.track("page_views", meta: {time_on_page: 0, browser: "chrome"}) # => 5673
|
61
59
|
|
62
|
-
DulyNoted.update(
|
60
|
+
DulyNoted.update(5673, meta: { time_on_page: 30 })
|
63
61
|
|
64
62
|
|
65
63
|
|
data/README.md
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
_Currently being updated for v1.0.0..._
|
2
|
-
|
3
1
|
#Duly Noted
|
4
2
|
[![Build Status](https://secure.travis-ci.org/willcosgrove/duly_noted.png?branch=master)](http://travis-ci.org/willcosgrove/duly_noted)
|
5
3
|
|
@@ -10,6 +8,10 @@ Duly noted is a redis backed stats and metrics tracker. It works as follows:
|
|
10
8
|
This would log one page view for the home page. Then to see how many page views the home page has gotten, you would simply call:
|
11
9
|
|
12
10
|
DulyNoted.count("page_views", for: "homepage")
|
11
|
+
|
12
|
+
To count how many page views there have been across all pages, you can call:
|
13
|
+
|
14
|
+
DulyNoted.count("page_views")
|
13
15
|
|
14
16
|
You can also store meta data with your metrics by passing your data in a hash to the `meta` key like so:
|
15
17
|
|
@@ -29,6 +31,8 @@ You can also just specify a `time_range` like so:
|
|
29
31
|
|
30
32
|
This will return the page view count for the home page for the past day.
|
31
33
|
|
34
|
+
There are a few other things it can do, check out the [docs]("http://willcosgrove.github.com/duly_noted") for more info.
|
35
|
+
|
32
36
|
##Install
|
33
37
|
|
34
38
|
You probably already guessed it, but to install just
|
@@ -43,24 +47,39 @@ to your `gemfile` and run `bundle install`
|
|
43
47
|
|
44
48
|
##What's New
|
45
49
|
|
50
|
+
### 1.0.1
|
51
|
+
* Obliterated `ref_id`s, and everything they stood for. Not really everything they stood for. Now each metric gets its own unique id.
|
52
|
+
* `#track` now returns the id of the metric you just tracked
|
53
|
+
* id's are unique across all of duly_noted, so when you update them with `#update` you don't need to specify which metric_name
|
54
|
+
* The first time you run a duly_noted command after updating the gem, it will attempt to update your redis schema. I did this on my own duly_noted setup with about 110k worth of unique metrics tracked, a DB size of 19MB, and a key count of 6 to a DB size of 35MB and a key count of 110600 in 75.26 seconds. In the next version, I'm either going to move the id keys into a hash, so it doesn't pollute the global keyspace any more than it has to, or, I'm going to set a default expire time on each id reference key. I'm leaning towards the expiration idea, because I don't think people have a use for being able to update any metric entry at any time.
|
55
|
+
|
56
|
+
### 1.0.0
|
57
|
+
* `for` is no longer required on `count` and `query`. If you call one of them without `for` it will count all of whatever metric you specified
|
58
|
+
* Added the `chart` method, which allows you to pull out your data in a handy way that's perfect for giving it to a charting library
|
59
|
+
* Now pipelines all of the keys that are set in the `track` method
|
60
|
+
* Added errors so that you know when something's gone wrong!
|
61
|
+
* Added the Updater which will do redis schema upgrades automatically when duly_noted does another major upgrade
|
62
|
+
* A special `count_x_by_y` dynamic method. Say you've tracked page views, and in the meta hash, you've stored their browser name. Now you want a breakdown of page views by browser, well… `DulyNoted.count_page_views_by_browser` would do just that. Yay metaprogramming!
|
63
|
+
* Added the ability to expire `ref_id`s. So if you know that you'll only need to edit your metadata for, say, the next 10 minutes, you can set the `editable_for` options to `10.minutes` in the `track`, or in the `update` method. By default, `ref_id`s never expire.
|
64
|
+
* Some other little behind the scenes methods to help for the big surprise in 1.5.0
|
65
|
+
|
46
66
|
### 0.1.0
|
47
67
|
|
48
68
|
* Added the `time_range` option to `count`, and `query`
|
49
69
|
|
50
70
|
* Added the `meta_fields` option to `query`, which takes an array of fields to pull out from the meta hash
|
51
71
|
|
52
|
-
* Added the `ref_id` option to `query`, which takes a reference id and will return an array with one meta hash. I was going back and forth on whether or not it should wrap the hash in an array. It doesn't need to be, but I thought, just to make it
|
72
|
+
* Added the `ref_id` option to `query`, which takes a reference id and will return an array with one meta hash. I was going back and forth on whether or not it should wrap the hash in an array. It doesn't need to be, but I thought, just to make it consistent with it's usual output, I should make it return an array.
|
53
73
|
|
54
74
|
* Enough bug fixes to make it production ready! Yay!
|
55
75
|
|
56
76
|
|
57
|
-
##
|
58
|
-
|
59
|
-
* Count by meta fields: How many page views from each browser?
|
77
|
+
##What's Gonna Be New
|
60
78
|
|
61
|
-
|
79
|
+
###1.5.0
|
80
|
+
* A sinatra app to view and peruse your metrics (think, resque)
|
81
|
+
* Resolution decay: currently, duly_noted stores all metrics at the highest resolution, timestamped down to a fraction of a second. With resolution decay, you can specify fall offs so that after, say, a month, they'll be grouped by day. So after a month has passed, you couldn't go back to a day and see it by hour, only total for that day. This will tremendously cut back on space, and is, of course, totally customizable.
|
62
82
|
|
63
|
-
* Maybe some Rails view helpers to generate some code for a Javascript charting library, or Google Charts API.
|
64
83
|
|
65
84
|
##Contributing
|
66
85
|
If you want to help, you should do it. Fork it, fix it, and send me a pull request. I will be delighted.
|
data/lib/duly_noted.rb
CHANGED
@@ -72,10 +72,6 @@ module DulyNoted
|
|
72
72
|
#
|
73
73
|
# `meta_fields`: An array of fields to retrieve from the meta hash. If not specified, the entire hash will be grabbed. Fields will be converted to strings, because redis converts all hash keys and values to strings.
|
74
74
|
#
|
75
|
-
# `ref_id`: If you need to reference the metric later, perhaps to add more metadata later on, you can set a reference id that you can use to update the metric. The `ref_id` must be unique across `metric_name`s.
|
76
|
-
#
|
77
|
-
# `editable_for`: If you want to clear `ref_id`s out, you can set the metric to only be editable for a certain amount of time. `editable_for` is defined in seconds. After that amount of time, you will no longer be able to edit the meta data, and you may use that `ref_id` again. By default, `ref_id`s never expire.
|
78
|
-
#
|
79
75
|
# `time_start`: The start of the time range to grab the data from. **Important:** `time_start` should always be the time farthest in the past.
|
80
76
|
#
|
81
77
|
# `time_end`: The end of the time range to grab the data from. **Important:** `time_end` should always be the time closest to the present.
|
@@ -84,16 +80,14 @@ module DulyNoted
|
|
84
80
|
|
85
81
|
# ##Track
|
86
82
|
|
87
|
-
# _parameters: `metric_name`, `for`(optional), `generated_at`(optional), `meta`(optional)
|
88
|
-
|
83
|
+
# _parameters: `metric_name`, `for`(optional), `generated_at`(optional), `meta`(optional)_
|
84
|
+
#
|
85
|
+
# _returns: `id` for editing metadata_
|
86
|
+
#
|
89
87
|
# Use track to track an event, like a page view, or a download. Use the `for` option
|
90
88
|
# to give an event a context. For instance, for page views, you might set `for` to
|
91
89
|
# `home_page`, so that you know which page was viewed. You can also store metadata
|
92
|
-
# along with your metric with the `meta` hash.
|
93
|
-
# at a later time, you can set a `ref_id`, which can be used to tell `#update`
|
94
|
-
# exactly which metric you want to update. `ref_id`s have to be unique across
|
95
|
-
# `metric_name`s, and if you want to free up your `ref_id`s, you can set them to expire
|
96
|
-
# after a certain number of seconds with `editable_for`.
|
90
|
+
# along with your metric with the `meta` hash.
|
97
91
|
#
|
98
92
|
# ###Usage
|
99
93
|
|
@@ -107,49 +101,45 @@ module DulyNoted
|
|
107
101
|
#
|
108
102
|
# DulyNoted.track("purchases",
|
109
103
|
# for: "user_281",
|
110
|
-
# generated_at: 1.day.ago
|
111
|
-
# ref_id: "pid_28172",
|
112
|
-
# editable_for: 30)
|
104
|
+
# generated_at: 1.day.ago)
|
113
105
|
|
114
106
|
def track(metric_name, options={})
|
115
107
|
options = {:generated_at => Time.now}.merge(options)
|
116
108
|
key = build_key(metric_name)
|
109
|
+
key_without_for = key.dup
|
110
|
+
id = DulyNoted.redis.incr "dnid"
|
117
111
|
key << assemble_for(options)
|
118
112
|
DulyNoted.redis.pipelined do
|
119
|
-
DulyNoted.redis.sadd build_key("metrics"),
|
120
|
-
DulyNoted.redis.zadd key, options[:generated_at].to_f, "#{key}:#{
|
121
|
-
DulyNoted.redis.set "
|
122
|
-
DulyNoted.redis.expire "#{build_key(metric_name)}:ref:#{options[:ref_id]}", options[:editable_for] if options[:editable_for]
|
113
|
+
DulyNoted.redis.sadd build_key("metrics", false), key_without_for
|
114
|
+
DulyNoted.redis.zadd key, options[:generated_at].to_f, "#{key}:#{id}:meta"
|
115
|
+
DulyNoted.redis.set "dnid:#{id}", "#{key}:#{id}:meta" # set alias key
|
123
116
|
if options[:meta] # set meta data
|
124
|
-
DulyNoted.redis.mapped_hmset "#{key}:#{
|
117
|
+
DulyNoted.redis.mapped_hmset "#{key}:#{id}:meta", options[:meta]
|
125
118
|
options[:meta].keys.each do |field|
|
126
119
|
DulyNoted.redis.sadd "#{key}:fields", field
|
127
120
|
end
|
128
121
|
end
|
129
122
|
end
|
123
|
+
id
|
130
124
|
end
|
131
125
|
|
132
126
|
# ##Update
|
133
127
|
#
|
134
|
-
# _parameters: `
|
128
|
+
# _parameters: `id`, `meta`(optional)_
|
135
129
|
#
|
136
|
-
# Use update to add, or edit the metadata stored with a metric.
|
130
|
+
# Use update to add, or edit the metadata stored with a metric.
|
137
131
|
#
|
138
132
|
# ###Usage
|
139
133
|
#
|
140
134
|
# DulyNoted.track("page_views",
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
# "a_unique_id",
|
145
|
-
# meta: { time_on_page: 30 },
|
146
|
-
# editable_for: 30)
|
135
|
+
# meta: {time_on_page: 0, browser: "chrome"}) # => 5673
|
136
|
+
# DulyNoted.update(5673,
|
137
|
+
# meta: { time_on_page: 30 })
|
147
138
|
|
148
|
-
def update(
|
149
|
-
key =
|
150
|
-
key << ":ref:#{ref_id}"
|
139
|
+
def update(id, options={})
|
140
|
+
key = "dnid:#{id}"
|
151
141
|
real_key = DulyNoted.redis.get key
|
152
|
-
raise
|
142
|
+
raise InvalidId if real_key == nil
|
153
143
|
DulyNoted.redis.mapped_hmset real_key, options[:meta] if options[:meta]
|
154
144
|
end
|
155
145
|
|
@@ -171,8 +161,8 @@ module DulyNoted
|
|
171
161
|
key = build_key(metric_name)
|
172
162
|
parse_time_range(options)
|
173
163
|
key << assemble_for(options)
|
174
|
-
if options[:
|
175
|
-
key
|
164
|
+
if options[:id]
|
165
|
+
key = "dnid:#{options[:id]}"
|
176
166
|
real_key = DulyNoted.redis.get key
|
177
167
|
if options[:meta_fields]
|
178
168
|
options[:meta_fields].collect! { |x| x.to_s }
|
@@ -382,6 +372,6 @@ module DulyNoted
|
|
382
372
|
class NotValidMetric < StandardError; end
|
383
373
|
class InvalidOptions < StandardError; end
|
384
374
|
class InvalidStep < StandardError; end
|
385
|
-
class
|
375
|
+
class InvalidId < StandardError; end
|
386
376
|
class UpdateError < StandardError; end
|
387
377
|
end
|
data/lib/duly_noted/helpers.rb
CHANGED
@@ -23,12 +23,13 @@ module DulyNoted
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def find_keys(key)
|
26
|
+
def find_keys(key, redis=nil)
|
27
|
+
redis ||= DulyNoted.redis
|
27
28
|
keys = []
|
28
|
-
keys +=
|
29
|
-
keys -=
|
30
|
-
keys -=
|
31
|
-
keys -=
|
29
|
+
keys += redis.keys("#{key}*")
|
30
|
+
keys -= redis.keys("#{key}:*:meta")
|
31
|
+
keys -= redis.keys("#{key}:ref:*")
|
32
|
+
keys -= redis.keys("#{key}*fields")
|
32
33
|
end
|
33
34
|
|
34
35
|
def parse_time_range(options)
|
data/lib/duly_noted/updater.rb
CHANGED
@@ -1,11 +1,37 @@
|
|
1
1
|
require "duly_noted/version"
|
2
|
+
require "duly_noted/helpers"
|
2
3
|
|
3
4
|
module DulyNoted
|
4
5
|
module Updater
|
5
6
|
def update_schema(schema_version, redis)
|
6
|
-
|
7
|
+
time = Time.now
|
8
|
+
if schema_version = [1,0,0]
|
9
|
+
#update to 1.0.1
|
10
|
+
puts "Updating schema to comply with duly_noted 1.0.1"
|
11
|
+
metrics = redis.smembers "dn:metrics"
|
12
|
+
metrics.each do |metric|
|
13
|
+
keys = find_keys(metric, redis)
|
14
|
+
keys.each do |key|
|
15
|
+
events = redis.zrange key, 0, -1
|
16
|
+
events.each do |event|
|
17
|
+
id = redis.incr "dnid"
|
18
|
+
redis.zadd(key, redis.zscore(key, event), event.gsub(/:\d{10}.\d+:/, ":#{id}:"))
|
19
|
+
redis.set("dnid:#{id}", "#{key}:#{id}:meta")
|
20
|
+
if(redis.exists(event))
|
21
|
+
redis.mapped_hmset "#{key}:#{id}:meta", redis.hgetall(event)
|
22
|
+
redis.del(event)
|
23
|
+
end
|
24
|
+
redis.zrem(key, event)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
redis.keys("*:ref:*").each do |ref_keys|
|
29
|
+
redis.del(ref_keys)
|
30
|
+
end
|
31
|
+
schema_version = [1,0,1]
|
32
|
+
end
|
7
33
|
redis.set "dn:version", VERSION
|
8
|
-
puts "All up to date"
|
34
|
+
puts "All up to date. Completed updates in #{Time.now-time} seconds."
|
9
35
|
return true
|
10
36
|
end
|
11
37
|
|
@@ -14,9 +40,8 @@ module DulyNoted
|
|
14
40
|
if !schema_version.nil?
|
15
41
|
schema_version = schema_version.split(".")
|
16
42
|
current_version = VERSION.split(".")
|
17
|
-
if schema_version
|
18
|
-
|
19
|
-
if update_schema(schema_version.join("."), redis)
|
43
|
+
if schema_version != current_version
|
44
|
+
if update_schema(schema_version, redis)
|
20
45
|
check_schema(redis)
|
21
46
|
else
|
22
47
|
raise UpdateError
|
data/lib/duly_noted/version.rb
CHANGED
data/spec/duly_noted_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe DulyNoted do
|
4
4
|
before :each do
|
5
|
-
DulyNoted.redis.
|
5
|
+
DulyNoted.redis.flushdb
|
6
6
|
Timecop.return
|
7
7
|
end
|
8
8
|
|
@@ -32,27 +32,23 @@ describe DulyNoted do
|
|
32
32
|
DulyNoted.track "page_views", :generated_at => Time.now-10
|
33
33
|
DulyNoted.count "page_views", :time_range => Time.now-11..Time.now-9
|
34
34
|
end
|
35
|
-
it "will allow you to set expirations on `ref_id`s" do
|
36
|
-
DulyNoted.track "page_views", :meta => {:open => true}, :ref_id => "unique", :editable_for => 0
|
37
|
-
expect { DulyNoted.update("page_views", "unique") }.to raise_error(DulyNoted::InvalidRefId)
|
38
|
-
end
|
39
35
|
end
|
40
36
|
|
41
37
|
describe "#update" do
|
42
38
|
it "overwrites duplicate keys" do
|
43
|
-
DulyNoted.track "page_views", :meta => {:seconds_open => 0}
|
44
|
-
DulyNoted.update
|
39
|
+
id = DulyNoted.track "page_views", :meta => {:seconds_open => 0}
|
40
|
+
DulyNoted.update id, :meta => {:seconds_open => 5}
|
45
41
|
DulyNoted.query("page_views").should include({"seconds_open" => "5"})
|
46
42
|
DulyNoted.query("page_views").should_not include({"seconds_open" => "0"})
|
47
43
|
end
|
48
44
|
it "doesn't replace old hash" do
|
49
|
-
DulyNoted.track "page_views", :meta => {:seconds_open => 0}
|
50
|
-
DulyNoted.update
|
45
|
+
id = DulyNoted.track "page_views", :meta => {:seconds_open => 0}
|
46
|
+
DulyNoted.update id, :meta => {:ip_address => "19.27.182.32"}
|
51
47
|
DulyNoted.query("page_views").should include({"seconds_open" => "0", "ip_address" => "19.27.182.32"})
|
52
48
|
end
|
53
49
|
it "does not require that `for:` be set to update" do
|
54
|
-
DulyNoted.track "page_views", :for => "home", :meta => {:seconds_open => 0}
|
55
|
-
DulyNoted.update
|
50
|
+
id = DulyNoted.track "page_views", :for => "home", :meta => {:seconds_open => 0}
|
51
|
+
DulyNoted.update id, :meta => {:seconds_open => 5}
|
56
52
|
DulyNoted.query("page_views").should include({"seconds_open" => "5"})
|
57
53
|
end
|
58
54
|
end
|
@@ -62,11 +58,11 @@ describe DulyNoted do
|
|
62
58
|
DulyNoted.track "page_views", :meta => {:seconds_open => 0, :browser => "chrome"}
|
63
59
|
DulyNoted.query("page_views").should include({"seconds_open" => "0", "browser" => "chrome"})
|
64
60
|
end
|
65
|
-
it "can query a certain
|
66
|
-
DulyNoted.track "page_views", :meta => {:seconds_open => 0, :browser => "chrome"}
|
61
|
+
it "can query a certain id" do
|
62
|
+
id = DulyNoted.track "page_views", :meta => {:seconds_open => 0, :browser => "chrome"}
|
67
63
|
DulyNoted.track "page_views", :meta => {:seconds_open => 10, :browser => "firefox"}
|
68
|
-
DulyNoted.query("page_views", :
|
69
|
-
DulyNoted.query("page_views", :
|
64
|
+
DulyNoted.query("page_views", :id => id).should include({"seconds_open" => "0", "browser" => "chrome"})
|
65
|
+
DulyNoted.query("page_views", :id => id).should_not include({"seconds_open" => "10", "browser" => "firefox"})
|
70
66
|
end
|
71
67
|
it "can grab only specific fields from the hash" do
|
72
68
|
DulyNoted.track "page_views", :meta => {:seconds_open => 0, :browser => "chrome"}
|
@@ -123,19 +119,19 @@ describe DulyNoted do
|
|
123
119
|
DulyNoted.chart("page_views", :time_range => Time.now-(3)..Time.now-(1), :step => (1)).should eq({(Time.now-3).to_i => 1, (Time.now-2).to_i => 2, (Time.now-1).to_i => 3})
|
124
120
|
end
|
125
121
|
it "can count events between a time range, without a step set" do
|
126
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:
|
127
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:
|
128
|
-
DulyNoted.chart("page_views", :time_range => Chronic.parse("yesterday at
|
122
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:30pm")
|
123
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:20pm")
|
124
|
+
DulyNoted.chart("page_views", :time_range => Chronic.parse("yesterday at 12pm")...Chronic.parse("yesterday at 2pm"), :data_points => 2).should eq({Chronic.parse("yesterday at 12pm").to_i => 1, Chronic.parse("yesterday at 1pm").to_i => 1})
|
129
125
|
end
|
130
126
|
it "will take time_start, step, and data_points options to build a chart" do
|
131
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:
|
132
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:
|
133
|
-
DulyNoted.chart("page_views", :time_start => Chronic.parse("yesterday at
|
127
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:30pm")
|
128
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:20pm")
|
129
|
+
DulyNoted.chart("page_views", :time_start => Chronic.parse("yesterday at 12pm"), :step => (3600), :data_points => 2).should eq({Chronic.parse("yesterday at 12pm").to_i => 1, Chronic.parse("yesterday at 1pm").to_i => 1})
|
134
130
|
end
|
135
131
|
it "will take time_end, step, and data_points options to build a chart" do
|
136
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:
|
137
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:
|
138
|
-
DulyNoted.chart("page_views", :time_end => Chronic.parse("yesterday at
|
132
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:30pm")
|
133
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:20pm")
|
134
|
+
DulyNoted.chart("page_views", :time_end => Chronic.parse("yesterday at 2pm"), :step => (3600), :data_points => 2).should eq({Chronic.parse("yesterday at 2pm").to_i => 1, Chronic.parse("yesterday at 1pm").to_i => 1})
|
139
135
|
end
|
140
136
|
it "should raise InvalidStep if you give it a step of zero" do
|
141
137
|
DulyNoted.track "page_views"
|
@@ -146,9 +142,9 @@ describe DulyNoted do
|
|
146
142
|
expect { DulyNoted.chart("page_views", :time_end => Time.now, :step => 60*60) }.to raise_error(DulyNoted::InvalidOptions)
|
147
143
|
end
|
148
144
|
it "should chart everything if no time range is specified" do
|
149
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:
|
150
|
-
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:
|
151
|
-
DulyNoted.chart("page_views", :data_points => 2).should eq({Chronic.parse("yesterday at 12:
|
145
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 12:30pm")
|
146
|
+
DulyNoted.track "page_views", :generated_at => Chronic.parse("yesterday at 1:20pm")
|
147
|
+
DulyNoted.chart("page_views", :data_points => 2).should eq({Chronic.parse("yesterday at 12:30pm").to_i => 1, Chronic.parse("yesterday at 12:55pm").to_i => 1})
|
152
148
|
end
|
153
149
|
end
|
154
150
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duly_noted
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03-
|
12
|
+
date: 2012-03-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
16
|
-
requirement: &
|
16
|
+
requirement: &70148931411020 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70148931411020
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70148931410600 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70148931410600
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &70148931410180 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70148931410180
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rb-fsevent
|
49
|
-
requirement: &
|
49
|
+
requirement: &70148931409760 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70148931409760
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: guard-rspec
|
60
|
-
requirement: &
|
60
|
+
requirement: &70148931409340 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70148931409340
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: guard-bundler
|
71
|
-
requirement: &
|
71
|
+
requirement: &70148931408920 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70148931408920
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: chronic
|
82
|
-
requirement: &
|
82
|
+
requirement: &70148931408500 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70148931408500
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: timecop
|
93
|
-
requirement: &
|
93
|
+
requirement: &70148931424440 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70148931424440
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: ruby_gntp
|
104
|
-
requirement: &
|
104
|
+
requirement: &70148931424020 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70148931424020
|
113
113
|
description: a simple redis based stat-tracker
|
114
114
|
email:
|
115
115
|
- will@willcosgrove.com
|
@@ -146,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
146
|
version: '0'
|
147
147
|
segments:
|
148
148
|
- 0
|
149
|
-
hash:
|
149
|
+
hash: -502772928455294375
|
150
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
151
|
none: false
|
152
152
|
requirements:
|
@@ -155,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
155
|
version: '0'
|
156
156
|
segments:
|
157
157
|
- 0
|
158
|
-
hash:
|
158
|
+
hash: -502772928455294375
|
159
159
|
requirements: []
|
160
160
|
rubyforge_project:
|
161
161
|
rubygems_version: 1.8.16
|