tabstabs 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +421 -0
- data/Rakefile +5 -0
- data/lib/tabs_tabs.rb +26 -0
- data/lib/tabs_tabs/config.rb +65 -0
- data/lib/tabs_tabs/helpers.rb +27 -0
- data/lib/tabs_tabs/metrics/counter.rb +69 -0
- data/lib/tabs_tabs/metrics/counter/stats.rb +51 -0
- data/lib/tabs_tabs/metrics/task.rb +72 -0
- data/lib/tabs_tabs/metrics/task/token.rb +89 -0
- data/lib/tabs_tabs/metrics/value.rb +91 -0
- data/lib/tabs_tabs/metrics/value/stats.rb +55 -0
- data/lib/tabs_tabs/resolution.rb +65 -0
- data/lib/tabs_tabs/resolutionable.rb +48 -0
- data/lib/tabs_tabs/resolutions/day.rb +40 -0
- data/lib/tabs_tabs/resolutions/hour.rb +40 -0
- data/lib/tabs_tabs/resolutions/minute.rb +40 -0
- data/lib/tabs_tabs/resolutions/month.rb +40 -0
- data/lib/tabs_tabs/resolutions/week.rb +40 -0
- data/lib/tabs_tabs/resolutions/year.rb +40 -0
- data/lib/tabs_tabs/storage.rb +105 -0
- data/lib/tabs_tabs/tabs_tabs.rb +117 -0
- data/lib/tabs_tabs/version.rb +3 -0
- data/spec/lib/tabs_tabs/config_spec.rb +60 -0
- data/spec/lib/tabs_tabs/metrics/counter/stats_spec.rb +42 -0
- data/spec/lib/tabs_tabs/metrics/counter_spec.rb +196 -0
- data/spec/lib/tabs_tabs/metrics/task/token_spec.rb +18 -0
- data/spec/lib/tabs_tabs/metrics/task_spec.rb +103 -0
- data/spec/lib/tabs_tabs/metrics/value/stats_spec.rb +61 -0
- data/spec/lib/tabs_tabs/metrics/value_spec.rb +160 -0
- data/spec/lib/tabs_tabs/resolution_spec.rb +52 -0
- data/spec/lib/tabs_tabs/resolutionable_spec.rb +53 -0
- data/spec/lib/tabs_tabs/resolutions/day_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/hour_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/minute_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/month_spec.rb +23 -0
- data/spec/lib/tabs_tabs/resolutions/week_spec.rb +24 -0
- data/spec/lib/tabs_tabs/resolutions/year_spec.rb +23 -0
- data/spec/lib/tabs_tabs/storage_spec.rb +138 -0
- data/spec/lib/tabs_tabs_spec.rb +223 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/custom_resolutions.rb +40 -0
- data/tabs_tabs.gemspec +31 -0
- metadata +213 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9fea0109dd26d3768ee616097bfbd79a15f5373d
|
4
|
+
data.tar.gz: eb981d035be4b2ce63fd169e4dd365797be77d71
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 020fabcb549a614424bc49aba23aec060e173999ae773255f52260493d151bfa83d37606cc04b99be5a620190f47f99d36babb37043d8a150c375f4d76c5489e
|
7
|
+
data.tar.gz: 7ab0dc4c3508f9123feb3efea1591f21564556f0b7604f8926dba6d7b0b9e995decba93042a3e8cc692145f1408a99c31672df2791d45a6bb426a16586d09a7c
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.0
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 JC Grubbs
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,421 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/FHG-IMW/tabstabs.svg?branch=master)](https://travis-ci.org/FHG-IMW/tabstabs)
|
2
|
+
# TabsTabs
|
3
|
+
|
4
|
+
TabsTabs is a redis-backed metrics tracker for time-based events that supports counts, sums,
|
5
|
+
averages, and min/max, and task based stats sliceable by the minute, hour, day, week, month, and year.
|
6
|
+
|
7
|
+
This gem is a fork of [Tabs](https://github.com/devmynd/tabs). We want to keep the project alive
|
8
|
+
and compatible with resent Ruby and Rails versions.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'TabsTabs'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install TabsTabs
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
Metrics come in three flavors: counters, values, and tasks.
|
27
|
+
|
28
|
+
### Counter Metrics
|
29
|
+
|
30
|
+
A counter metric simply records the number of events that occur within a given timeframe. To create a counter metric called ‘website-visits’, simply call:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
TabsTabs .create_metric("website-visits", "counter")
|
34
|
+
```
|
35
|
+
|
36
|
+
TabsTabs will also create a counter metric automatically the first time you
|
37
|
+
increment the counter.
|
38
|
+
|
39
|
+
To increment a metric counter, simply call:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
TabsTabs .increment_counter("website-visits")
|
43
|
+
```
|
44
|
+
|
45
|
+
If you need to retroactively increment the counter for a specific
|
46
|
+
timestamp, just pass it in.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
TabsTabs .increment_counter("wibsite-visits", Time.now - 2.days)
|
50
|
+
```
|
51
|
+
|
52
|
+
To retrieve the counts for a given time period just call `TabsTabs #get_stats` with the name of the metric, a range of times defining the period for which you want stats, and the resolution at which the data should be aggregated.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
TabsTabs .get_stats("website-visits", 10.days.ago..Time.now, :hour)
|
56
|
+
```
|
57
|
+
|
58
|
+
This will return stats for the last 10 days by hour in the form of a `TabsTabs ::Metrics::Counter::Stats` object. This object is enumerable so you can iterate through the results like so:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
results = TabsTabs .get_stats("website-visits", 10.days.ago..Time.now, :hour)
|
62
|
+
results.each { |r| puts r }
|
63
|
+
|
64
|
+
#=>
|
65
|
+
{ timestamp: 2000-01-01 00:00:00 UTC, count: 1 }
|
66
|
+
{ timestamp: 2000-01-01 01:00:00 UTC, count: 0 }
|
67
|
+
{ timestamp: 2000-01-01 02:00:00 UTC, count: 10 }
|
68
|
+
{ timestamp: 2000-01-01 03:00:00 UTC, count: 1 }
|
69
|
+
{ timestamp: 2000-01-01 04:00:00 UTC, count: 0 }
|
70
|
+
{ timestamp: 2000-01-01 05:00:00 UTC, count: 0 }
|
71
|
+
{ timestamp: 2000-01-01 06:00:00 UTC, count: 3 }
|
72
|
+
{ timestamp: 2000-01-01 07:00:00 UTC, count: 0 }
|
73
|
+
...
|
74
|
+
```
|
75
|
+
|
76
|
+
The results object also provides the following methods:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
results.total #=> The count total for the given period
|
80
|
+
results.min #=> The min count for any timestamp in the period
|
81
|
+
results.max #=> The max count for any timestamp in the period
|
82
|
+
results.avg #=> The avg count for timestamps in the period
|
83
|
+
results.period #=> The timestamp range that was requested
|
84
|
+
results.resolution #=> The resolution requested
|
85
|
+
```
|
86
|
+
|
87
|
+
Timestamps for the given period in which no events occurred will be "filled in" with a count value to make visualizations easier.
|
88
|
+
|
89
|
+
The timestamps are also normalized. For example, in hour resolution, the minutes and seconds of the timestamps are set to 00:00. Likewise for the week resolution, the day is set to the first day of the week.
|
90
|
+
|
91
|
+
Lastly, you can access the overall total for a counter (for all time)
|
92
|
+
using the `counter_total` method.
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
TabsTabs .counter_total("website-visits") #=> 476873
|
96
|
+
```
|
97
|
+
|
98
|
+
### Value Metrics
|
99
|
+
|
100
|
+
Value metrics record a value at a point in time and calculate the min, max, avg, and sum for a given time resolution. Creating a value metric is easy:
|
101
|
+
|
102
|
+
To record a value, simply call `TabsTabs #record_value`.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
TabsTabs .record_value("new-user-age", 32)
|
106
|
+
```
|
107
|
+
|
108
|
+
If you need to retroactively record a value for a specific
|
109
|
+
timestamp, just pass it in.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
TabsTabs .increment_counter("new-user-age", 19, Time.now - 2.days)
|
113
|
+
```
|
114
|
+
|
115
|
+
This will also create a value metric the first time, you can manually create
|
116
|
+
a metric as well:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
TabsTabs .create_metric("new-user-age", "value")
|
120
|
+
```
|
121
|
+
|
122
|
+
Retrieving the stats for a value metric is just like retrieving a counter metric.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
TabsTabs .get_stats("new-user-age", 6.months.ago..Time.now, :month)
|
126
|
+
```
|
127
|
+
|
128
|
+
This will return a `TabsTabs ::Metrics::Value::Stats` object. Again, this
|
129
|
+
object is enumerable and encapsulates all the timestamps within the
|
130
|
+
given period.
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
results = TabsTabs .get_stats("new-user-age", 6.months.ago..Time.now, :month)
|
134
|
+
results.each { |r| puts r }
|
135
|
+
#=>
|
136
|
+
{ timestamp: 2000-01-01 00:00:00, count: 9, min: 19, max: 54, sum: 226, avg: 38 }
|
137
|
+
{ timestamp: 2000-02-01 01:00:00, count: 0, min: 0, max: 0, sum: 0, avg: 0 }
|
138
|
+
{ timestamp: 2000-03-01 02:00:00, count: 2, min: 22, max: 34, sum: 180, avg: 26 }
|
139
|
+
...
|
140
|
+
```
|
141
|
+
|
142
|
+
The results object also provides some aggregates and other methods:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
results.count #=> The total count of recorded values for the period
|
146
|
+
results.sum #=> The sum of all values for the period
|
147
|
+
results.min #=> The min value for any timestamp in the period
|
148
|
+
results.max #=> The max value for any timestamp in the period
|
149
|
+
results.avg #=> The avg value for timestamps in the period
|
150
|
+
results.period #=> The timestamp range that was requested
|
151
|
+
results.resolution #=> The resolution requested
|
152
|
+
```
|
153
|
+
|
154
|
+
### Task Metrics
|
155
|
+
|
156
|
+
Task metrics allow you to track the beginning and ending of a process.
|
157
|
+
For example, tracking a user who downloads you mobile application and
|
158
|
+
later visits your website to make a purchase.
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
TabsTabs .start_task("mobile-to-purchase", "2g4hj17787s")
|
162
|
+
```
|
163
|
+
|
164
|
+
The first argument is the metric key and the second is a unique token
|
165
|
+
used to identify the given process. You can use any string for the
|
166
|
+
token but it needs to be unique. Use the `complete_task` method to
|
167
|
+
finish the task:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
TabsTabs .complete_task("mobile-to-purchase", "2g4hj17787s")
|
171
|
+
```
|
172
|
+
|
173
|
+
If you need to retroactively start/complete a task at a specific
|
174
|
+
timestamp, just pass it in.
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
TabsTabs .start_task("mobile-to-purchase", "2g4hj17787s", Time.now - 2.days)
|
178
|
+
TabsTabs .complete_task("mobile-to-purchase", "2g4hj17787s", Time.now - 1.days)
|
179
|
+
```
|
180
|
+
|
181
|
+
Retrieving stats for a task metric is just like the other types:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
TabsTabs .get_stats("mobile-to-purchase", 6.hours.ago..Time.now, :minute)
|
185
|
+
```
|
186
|
+
|
187
|
+
This will return a `TabsTabs ::Metrics::Task::Stats` object:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
results = TabsTabs .get_stats("mobile-to-purchase", 6.hours.ago..Time.now, :minute)
|
191
|
+
results.started_within_period #=> Number of items started in period
|
192
|
+
results.completed_within_period #=> Number of items completed in period
|
193
|
+
results.started_and_completed_within_period #=> Items wholly started/completed in period
|
194
|
+
results.completion_rate #=> Rate of completion in the given resolution
|
195
|
+
results.average_completion_time #=> Average time for the task to be completed
|
196
|
+
```
|
197
|
+
|
198
|
+
### Resolutions
|
199
|
+
|
200
|
+
When TabsTabs increments a counter or records a value it does so for each of the following "resolutions". You may supply any of these as the last argument to the `TabsTabs #get_stats` method.
|
201
|
+
|
202
|
+
:minute, :hour, :day, :week, :month, :year
|
203
|
+
|
204
|
+
It automatically aggregates multiple events for the same period. For instance when you increment a counter metric, 1 will be added for each of the resolutions for the current time. Repeating the event 5 minutes later will increment a different minute slot, but the same hour, date, week, etc. When you retrieve metrics, all timestamps will be in UTC.
|
205
|
+
|
206
|
+
#### Custom Resolutions
|
207
|
+
|
208
|
+
If the built-in resolutions above don't work you can add your own. All
|
209
|
+
that's necessary is a module that conforms to the following protocol:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
module SecondResolution
|
213
|
+
include TabsTabs ::Resolutionable
|
214
|
+
extend self
|
215
|
+
|
216
|
+
PATTERN = "%Y-%m-%d-%H-%M-%S"
|
217
|
+
|
218
|
+
def name
|
219
|
+
:seconds
|
220
|
+
end
|
221
|
+
|
222
|
+
def serialize(timestamp)
|
223
|
+
timestamp.strftime(PATTERN)
|
224
|
+
end
|
225
|
+
|
226
|
+
def deserialize(str)
|
227
|
+
dt = DateTime.strptime(str, PATTERN)
|
228
|
+
self.normalize(dt)
|
229
|
+
end
|
230
|
+
|
231
|
+
def from_seconds(s)
|
232
|
+
s / 1
|
233
|
+
end
|
234
|
+
|
235
|
+
def to_seconds
|
236
|
+
1
|
237
|
+
end
|
238
|
+
|
239
|
+
def add(timestamp, num_of_seconds)
|
240
|
+
timestamp + num_of_seconds.seconds
|
241
|
+
end
|
242
|
+
|
243
|
+
def normalize(ts)
|
244
|
+
Time.utc(ts.year, ts.month, ts.day, ts.hour, ts.min, ts.sec)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
```
|
249
|
+
|
250
|
+
A little description on each of the above methods:
|
251
|
+
|
252
|
+
*`name`*: unique symbol used to reference registered resolution
|
253
|
+
|
254
|
+
*`serialize`*: converts the timestamp to a string. The return value
|
255
|
+
here will be used as part of the Redis key storing values associated
|
256
|
+
with a given metric.
|
257
|
+
|
258
|
+
*`deserialize`*: converts the string representation of a timestamp back
|
259
|
+
into an actual DateTime value.
|
260
|
+
|
261
|
+
*`from_seconds`*: should return the number of periods in the given
|
262
|
+
number of seconds. For example, there are 60 seconds in a minute.
|
263
|
+
|
264
|
+
*`to_seconds`*: should return the number of seconds in '1' of these time periods. For example, there are 3600 seconds in an hour.
|
265
|
+
|
266
|
+
*`add`*: should add the number of seconds in the given resolution to the
|
267
|
+
supplied timestamp.
|
268
|
+
|
269
|
+
*`normalize`*: should simply return the first timestamp for the period.
|
270
|
+
For example, the week resolution returns the first hour of the first day
|
271
|
+
of the week.
|
272
|
+
|
273
|
+
*NOTE: If you're doing a custom resolution, you should probably look into
|
274
|
+
the code a bit.*
|
275
|
+
|
276
|
+
Once you have a module that conforms to the resolution protocol you need
|
277
|
+
to register it with TabsTabs . You can do this in one of two ways:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
tabstabs
|
281
|
+
TabsTabs ::Resolution.register(SecondResolution)
|
282
|
+
|
283
|
+
# or, you can use the config block described below
|
284
|
+
```
|
285
|
+
|
286
|
+
#### Removing a Resolution
|
287
|
+
|
288
|
+
You can also remove any resolution (custom or built-in) by calling the `unregister_resolutions` method in the config block (see config section below). Or, you can remove manually by calling:
|
289
|
+
|
290
|
+
```ruby
|
291
|
+
TabsTabs ::Resolution.unregister(:minute, :hour)
|
292
|
+
```
|
293
|
+
|
294
|
+
### Inspecting Metrics
|
295
|
+
|
296
|
+
You can list all metrics using `list_metrics`:
|
297
|
+
|
298
|
+
```ruby
|
299
|
+
TabsTabs .list_metrics #=> ["website-visits", "new-user-age"]
|
300
|
+
```
|
301
|
+
|
302
|
+
You can check a metric's type (counter of value) by calling
|
303
|
+
`metric_type`:
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
TabsTabs .metric_type("website-visits") #=> "counter"
|
307
|
+
```
|
308
|
+
|
309
|
+
And you can quickly check if a metric exists:
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
TabsTabs .metric_exists?("foobar") #=> false
|
313
|
+
```
|
314
|
+
|
315
|
+
### Drop a Metric
|
316
|
+
|
317
|
+
To drop a metric, just call `TabsTabs #drop_metric`
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
TabsTabs .drop_metric!("website-visits")
|
321
|
+
```
|
322
|
+
|
323
|
+
This will drop all recorded values for the metric so it may not be un-done...be careful.
|
324
|
+
|
325
|
+
To drop only a specific resolution for a metric, just call `TabsTabs #drop_resolution_for_metric!`
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
TabsTabs .drop_resolution_for_metric!("website-visits", :minute)
|
329
|
+
```
|
330
|
+
|
331
|
+
Even more dangerous, you can drop all metrics...be very careful.
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
TabsTabs .drop_all_metrics!
|
335
|
+
```
|
336
|
+
### Aging Out Old Metrics
|
337
|
+
|
338
|
+
You can use the expiration features to age out old metrics that may no longer be in your operational data set. For example, you may want to keep monthly or yearly data around but the minute or day level data isn't necessary past a certain date. You can set expirations for any resolution:
|
339
|
+
|
340
|
+
```ruby
|
341
|
+
TabsTabs .configure do |config|
|
342
|
+
config.set_expirations(minute: 1.day, day: 1.week)
|
343
|
+
end
|
344
|
+
```
|
345
|
+
|
346
|
+
The expiration date will start counting at the beginning of the end of the given resolution. Meaning that for a month resolution the given expiration time would start at the end of a given month. A month resolution metric recorded in January with an expiration of 2 weeks would expire after the 2nd week of February.
|
347
|
+
|
348
|
+
*NOTE: You cannot expire task metrics at this time, only counter and
|
349
|
+
values.*
|
350
|
+
|
351
|
+
### Configuration
|
352
|
+
|
353
|
+
TabsTabs just works out of the box. However, if you want to override the default Redis connection or decimal precision, this is how:
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
TabsTabs .configure do |config|
|
357
|
+
|
358
|
+
# set it to an existing connection
|
359
|
+
config.redis = Redis.current
|
360
|
+
|
361
|
+
# pass a config hash that will be passed to Redis.new
|
362
|
+
config.redis = { :host => 'localhost', :port => 6379 }
|
363
|
+
|
364
|
+
tabstabs
|
365
|
+
tabstabs
|
366
|
+
config.prefix = "my_app"
|
367
|
+
|
368
|
+
# override default decimal precision (5)
|
369
|
+
# affects stat averages and task completion rate
|
370
|
+
config.decimal_precision = 2
|
371
|
+
|
372
|
+
# registers a custom resolution
|
373
|
+
config.register_resolution :second, SecondResolution
|
374
|
+
|
375
|
+
# unregisters any resolution
|
376
|
+
config.unregister_resolutions(:minute, :hour)
|
377
|
+
|
378
|
+
# sets TTL for redis keys of specific resolutions
|
379
|
+
config.set_expirations({ minute: 1.hour, hour: 1.day })
|
380
|
+
|
381
|
+
end
|
382
|
+
```
|
383
|
+
|
384
|
+
#### Prefixing
|
385
|
+
|
386
|
+
Many applications use a single Redis instance for a number of uses:
|
387
|
+
background jobs, ephemeral data, TabsTabs , etc. To avoid key collisions,
|
388
|
+
and to make it easier to drop all of your TabsTabs data without affecting
|
389
|
+
other parts of your system (or if more than one app shares the Redis
|
390
|
+
instance) you can prefix a given 'instance'.
|
391
|
+
|
392
|
+
Setting the prefix config option will cause all of the keys that TabsTabs
|
393
|
+
stores to use this format:
|
394
|
+
|
395
|
+
```
|
396
|
+
tabstabs:#{prefix}:#{key}..."
|
397
|
+
```
|
398
|
+
|
399
|
+
## Change Log & Breaking Changes
|
400
|
+
|
401
|
+
### v2.0.0
|
402
|
+
|
403
|
+
Fork of [Tabs](https://github.com/devmynd/tabs) due to its discontinuation
|
404
|
+
and incompatibility with newer Redis versions.
|
405
|
+
|
406
|
+
- Relaxed redis-rb version requirement
|
407
|
+
- Updated specs to new syntax
|
408
|
+
|
409
|
+
## Contributing
|
410
|
+
|
411
|
+
1. Fork it
|
412
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
413
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
414
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
415
|
+
5. Create new Pull Request
|
416
|
+
|
417
|
+
|
418
|
+
## Special Thanks
|
419
|
+
|
420
|
+
Thanks to [@DevMynd](https://github.com/devmynd) for creating the initial version
|
421
|
+
of this gem!
|