trifle-ruby 3.0.1 → 3.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +37 -0
- data/.gitpod.yml +18 -0
- data/.gitpod/Dockerfile +1 -0
- data/.gitpod/Dockerfile-base +77 -0
- data/.rubocop.yml +5 -4
- data/Gemfile.lock +2 -1
- data/README.md +62 -11
- data/lib/trifle/ruby.rb +22 -22
- data/lib/trifle/ruby/configuration.rb +10 -2
- data/lib/trifle/ruby/driver/README.md +59 -0
- data/lib/trifle/ruby/driver/redis.rb +8 -2
- data/lib/trifle/ruby/nocturnal.rb +44 -31
- data/lib/trifle/ruby/operations/timeseries/increment.rb +34 -0
- data/lib/trifle/ruby/operations/timeseries/values.rb +39 -0
- data/lib/trifle/ruby/version.rb +1 -1
- data/trifle-ruby.gemspec +1 -1
- metadata +10 -5
- data/lib/trifle/ruby/client.rb +0 -21
- data/lib/trifle/ruby/resource.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b971ae3e2273b7b060d1556aa8716015ac92b7c162d8d64e2ce43a9ad18d185
|
4
|
+
data.tar.gz: 9ad14a866e880d9885b4b233be51139283baff70b2af9c09ce85ab882e754a92
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5ec3d8760a919408b5e16664c16a49ccb8a8e48a3a194e45e3ea997c0d8048a187bcfc53da7ba973ba9afd0d89e402a20a9cf8d47efd9176bc36111351cfd00
|
7
|
+
data.tar.gz: 365cc57ff1247b480decaf732bb0cc7f969c1f7e85e5c3c221598e28ef492d6cfc4483766818f765a595f8254a53fce4611d2d2afd2138f640bf9e3997f03621
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ main ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ main ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
strategy:
|
21
|
+
matrix:
|
22
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
23
|
+
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- name: Set up Ruby
|
27
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
28
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
29
|
+
# uses: ruby/setup-ruby@v1
|
30
|
+
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
31
|
+
with:
|
32
|
+
ruby-version: ${{ matrix.ruby-version }}
|
33
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
34
|
+
- name: Rspec
|
35
|
+
run: bundle exec rspec
|
36
|
+
- name: Rubocop
|
37
|
+
run: bundle exec rubocop
|
data/.gitpod.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
image:
|
2
|
+
file: .gitpod/Dockerfile
|
3
|
+
tasks:
|
4
|
+
- init: bundle install
|
5
|
+
command: ./bin/console
|
6
|
+
- command: redis-server
|
7
|
+
github:
|
8
|
+
prebuilds:
|
9
|
+
# enable for the master/default branch (defaults to true)
|
10
|
+
master: true
|
11
|
+
# enable for all branches in this repo (defaults to false)
|
12
|
+
branches: false
|
13
|
+
# enable for pull requests coming from this repo (defaults to true)
|
14
|
+
pullRequests: true
|
15
|
+
# add a check to pull requests (defaults to true)
|
16
|
+
addCheck: true
|
17
|
+
# add a "Review in Gitpod" button as a comment to pull requests (defaults to false)
|
18
|
+
addComment: false
|
data/.gitpod/Dockerfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
FROM trifle/gitpod:0.1.0
|
@@ -0,0 +1,77 @@
|
|
1
|
+
FROM ubuntu:20.04
|
2
|
+
|
3
|
+
ENV TZ=Europe/Bratislava
|
4
|
+
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
5
|
+
|
6
|
+
RUN useradd gitpod -u 33333
|
7
|
+
RUN mkdir -p /home/gitpod && chown gitpod:gitpod /home/gitpod
|
8
|
+
|
9
|
+
# install ubuntu packages
|
10
|
+
RUN apt-get update -q \
|
11
|
+
&& apt-get install -y \
|
12
|
+
build-essential \
|
13
|
+
apt-transport-https \
|
14
|
+
bash \
|
15
|
+
xterm \
|
16
|
+
xvfb \
|
17
|
+
x11vnc \
|
18
|
+
libpq-dev \
|
19
|
+
git \
|
20
|
+
curl \
|
21
|
+
wget \
|
22
|
+
unzip \
|
23
|
+
dirmngr \
|
24
|
+
gpg \
|
25
|
+
gnupg2 \
|
26
|
+
locales \
|
27
|
+
autoconf \
|
28
|
+
libncurses5-dev \
|
29
|
+
libgl1-mesa-dev \
|
30
|
+
libglu1-mesa-dev \
|
31
|
+
libpng-dev \
|
32
|
+
unixodbc-dev \
|
33
|
+
libssl-dev \
|
34
|
+
libreadline-dev \
|
35
|
+
zlib1g-dev \
|
36
|
+
ffmpeg \
|
37
|
+
tmux \
|
38
|
+
runit-systemd \
|
39
|
+
htop \
|
40
|
+
vim \
|
41
|
+
&& apt-get clean
|
42
|
+
|
43
|
+
#set the locale
|
44
|
+
RUN locale-gen en_US.UTF-8
|
45
|
+
ENV LANG en_US.UTF-8
|
46
|
+
ENV LANGUAGE en_US:en
|
47
|
+
ENV LC_ALL en_US.UTF-8
|
48
|
+
|
49
|
+
RUN curl -fsSL https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add -
|
50
|
+
RUN echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list
|
51
|
+
|
52
|
+
RUN apt-get update -q \
|
53
|
+
&& apt-get install -y \
|
54
|
+
postgresql postgresql-contrib \
|
55
|
+
# mongodb-org \
|
56
|
+
redis-server \
|
57
|
+
mariadb-server \
|
58
|
+
&& apt-get clean
|
59
|
+
|
60
|
+
USER gitpod
|
61
|
+
|
62
|
+
#install asdf
|
63
|
+
ENV ASDF_ROOT /home/gitpod/.asdf
|
64
|
+
ENV PATH "${ASDF_ROOT}/bin:${ASDF_ROOT}/shims:$PATH"
|
65
|
+
RUN git clone https://github.com/asdf-vm/asdf.git ${ASDF_ROOT} --branch v0.8.0
|
66
|
+
|
67
|
+
RUN asdf plugin-add ruby https://github.com/asdf-vm/asdf-ruby.git
|
68
|
+
|
69
|
+
# install ruby
|
70
|
+
ENV RUBY_VERSION 3.0.0
|
71
|
+
RUN ASDF_RUBY_BUILD_VERSION=v20201225 asdf install ruby ${RUBY_VERSION} \
|
72
|
+
&& asdf global ruby ${RUBY_VERSION}
|
73
|
+
|
74
|
+
# throw errors if Gemfile has been modified since Gemfile.lock
|
75
|
+
RUN gem install bundler
|
76
|
+
|
77
|
+
CMD ["bash"]
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
inherit_mode:
|
2
|
+
merge:
|
3
|
+
- Exclude
|
4
|
+
|
1
5
|
AllCops:
|
2
|
-
TargetRubyVersion: '
|
6
|
+
TargetRubyVersion: '2.6'
|
3
7
|
Exclude:
|
4
8
|
- 'bin/**/*'
|
5
9
|
- 'Rakefile'
|
@@ -9,6 +13,3 @@ AllCops:
|
|
9
13
|
|
10
14
|
Style/Documentation:
|
11
15
|
Enabled: false
|
12
|
-
#
|
13
|
-
# Layout/LineLength:
|
14
|
-
# Max: 80
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# Trifle
|
2
2
|
|
3
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/trifle-ruby.svg)](https://badge.fury.io/rb/trifle-ruby)
|
4
|
+
![Ruby](https://github.com/trifle-io/trifle-ruby/workflows/Ruby/badge.svg?branch=main)
|
5
|
+
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/trifle-io/trifle-ruby)
|
6
|
+
|
7
|
+
Simple analytics backed by Redis, Postgres, MongoDB, Google Analytics, Segment, or whatever. [^1]
|
4
8
|
|
5
9
|
Trifle is a _way too_ simple timeline analytics that helps you track custom metrics. Automatically increments counters for each enabled range. It supports timezones and different week beginning.
|
6
10
|
|
@@ -35,28 +39,24 @@ Trifle::Ruby.configure do |config|
|
|
35
39
|
end
|
36
40
|
```
|
37
41
|
|
42
|
+
### Track values
|
43
|
+
|
38
44
|
Available ranges are `:minute`, `:hour`, `:day`, `:week`, `:month`, `:quarter`, `:year`.
|
39
45
|
|
40
46
|
Now track your first metrics
|
41
47
|
```ruby
|
42
|
-
Trifle::Ruby.track(key: 'event::logs', at: Time.
|
48
|
+
Trifle::Ruby.track(key: 'event::logs', at: Time.now, values: {count: 1, duration: 2, lines: 241})
|
43
49
|
=> [{2021-01-25 16:00:00 +0100=>{:count=>1, :duration=>2, :lines=>241}}, {2021-01-25 00:00:00 +0100=>{:count=>1, :duration=>2, :lines=>241}}]
|
44
50
|
# or do it few more times
|
45
|
-
Trifle::Ruby.track(key: 'event::logs', at: Time.
|
51
|
+
Trifle::Ruby.track(key: 'event::logs', at: Time.now, values: {count: 1, duration: 1, lines: 56})
|
46
52
|
=> [{2021-01-25 16:00:00 +0100=>{:count=>1, :duration=>1, :lines=>56}}, {2021-01-25 00:00:00 +0100=>{:count=>1, :duration=>1, :lines=>56}}]
|
47
|
-
Trifle::Ruby.track(key: 'event::logs', at: Time.
|
53
|
+
Trifle::Ruby.track(key: 'event::logs', at: Time.now, values: {count: 1, duration: 5, lines: 361})
|
48
54
|
=> [{2021-01-25 16:00:00 +0100=>{:count=>1, :duration=>5, :lines=>361}}, {2021-01-25 00:00:00 +0100=>{:count=>1, :duration=>5, :lines=>361}}]
|
49
55
|
```
|
50
56
|
|
51
|
-
You can then retrieve your values for specific `range`.
|
52
|
-
```ruby
|
53
|
-
Trifle::Ruby.values_for(key: 'event::logs', from: Time.now.beginning_of_day, to: Time.now.end_of_day, range: :day)
|
54
|
-
=> [{2021-01-25 00:00:00 +0100=>{"count"=>3, "duration"=>8, "lines"=>658}}]
|
55
|
-
```
|
56
|
-
|
57
57
|
You can also store nested counters like
|
58
58
|
```ruby
|
59
|
-
Trifle::Ruby.track(key: 'event::logs', at: Time.
|
59
|
+
Trifle::Ruby.track(key: 'event::logs', at: Time.now, values: {
|
60
60
|
count: 1,
|
61
61
|
duration: {
|
62
62
|
parsing: 21,
|
@@ -67,12 +67,63 @@ Trifle::Ruby.track(key: 'event::logs', at: Time.zone.now, values: {
|
|
67
67
|
})
|
68
68
|
```
|
69
69
|
|
70
|
+
### Get values
|
71
|
+
|
72
|
+
Retrieve your values for specific `range`.
|
73
|
+
```ruby
|
74
|
+
Trifle::Ruby.values(key: 'event::logs', from: Time.now, to: Time.now, range: :day)
|
75
|
+
=> [{2021-01-25 00:00:00 +0100=>{"count"=>3, "duration"=>8, "lines"=>658}}]
|
76
|
+
```
|
77
|
+
|
78
|
+
### Configuration
|
79
|
+
|
80
|
+
Configuration allows you to specify:
|
81
|
+
- `driver` - backend driver used to persist and retrieve data.
|
82
|
+
- `track_ranges` - list of timeline ranges you would like to track. Value must be list of symbols, defaults to `[:minute, :hour, :day, :week, :month, :quarter, :year]`.
|
83
|
+
- `separator` - keys can get serialized in backend, separator is used to join these values. Value must be string, defaults to `::`.
|
84
|
+
- `time_zone` - TZInfo zone to properly generate range for timeline values. Value must be valid TZ string identifier, otherwise it defaults and fallbacks to `'GMT'`.
|
85
|
+
- `beginning_of_week` - first day of week. Value must be string, defaults to `:monday`.
|
86
|
+
|
87
|
+
Gem expecs global configuration to be present. You can do this by creating initializer, or calling it on the beginning of your ruby script.
|
88
|
+
|
89
|
+
Custom configuration can be passed as a keyword argument to `Resource` objects and all module methods (`track`, `values`). This way you can pass different driver or ranges for different type of data youre storing - ie set different ranges or set expiration date on your data.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
configuration = Trifle::Ruby::Configuration.new
|
93
|
+
configuration.driver = Trifle::Ruby::Driver::Redis.new
|
94
|
+
configuration.track_ranges = [:day]
|
95
|
+
configuration.time_zone = 'GMT'
|
96
|
+
configuration.separator = '#'
|
97
|
+
|
98
|
+
# or use different driver
|
99
|
+
mongo_configuration = Trifle::Ruby::Configuration.new
|
100
|
+
mongo_configuration.driver = Trifle::Ruby::Driver::MongoDB.new
|
101
|
+
mongo_configuration.time_zone = 'Asia/Dubai'
|
102
|
+
```
|
103
|
+
|
104
|
+
You can then pass it into module methods.
|
105
|
+
```ruby
|
106
|
+
Trifle::Ruby.track(key: 'event#checkout', at: Time.now, values: {count: 1}, config: configuration)
|
107
|
+
|
108
|
+
Trifle::Ruby.track(key: 'event#checkout', at: Time.now, values: {count: 1}, config: mongo_configuration)
|
109
|
+
```
|
110
|
+
|
111
|
+
### Driver
|
112
|
+
|
113
|
+
Driver is a wrapper around existing client libraries that talk to DB or API. It is used to store and retrieve values. You can read more in [Driver Readme](https://github.com/trifle-io/trifle-ruby/tree/main/lib/trifle/ruby/driver).
|
114
|
+
|
70
115
|
## Development
|
71
116
|
|
72
117
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
73
118
|
|
74
119
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
75
120
|
|
121
|
+
## Gitpod
|
122
|
+
|
123
|
+
This repository comes Gitpod ready. If you wanna try and get your hands dirty with Trifle, click [here](https://gitpod.io/#https://github.com/trifle-io/trifle-ruby) and watch magic happening.
|
124
|
+
|
125
|
+
It launches from custom base image that includes Redis, MongoDB, Postgres & MariaDB. This should give you enough playground to launch `./bin/console` and start messing around. You can see the Gitpod image in the [hub](https://hub.docker.com/r/trifle/gitpod).
|
126
|
+
|
76
127
|
## Contributing
|
77
128
|
|
78
129
|
Bug reports and pull requests are welcome on GitHub at https://github.com/trifle-io/trifle-ruby.
|
data/lib/trifle/ruby.rb
CHANGED
@@ -3,43 +3,43 @@
|
|
3
3
|
require 'trifle/ruby/driver/redis'
|
4
4
|
require 'trifle/ruby/mixins/packer'
|
5
5
|
require 'trifle/ruby/nocturnal'
|
6
|
-
require 'trifle/ruby/client'
|
7
6
|
require 'trifle/ruby/configuration'
|
8
|
-
require 'trifle/ruby/
|
7
|
+
require 'trifle/ruby/operations/timeseries/increment'
|
8
|
+
require 'trifle/ruby/operations/timeseries/values'
|
9
9
|
require 'trifle/ruby/version'
|
10
10
|
|
11
11
|
module Trifle
|
12
12
|
module Ruby
|
13
13
|
class Error < StandardError; end
|
14
|
+
class DriverNotFound < Error; end
|
14
15
|
|
15
|
-
def self.
|
16
|
-
@
|
16
|
+
def self.default
|
17
|
+
@default ||= Configuration.new
|
17
18
|
end
|
18
19
|
|
19
20
|
def self.configure
|
20
|
-
yield(
|
21
|
+
yield(default)
|
21
22
|
|
22
|
-
|
23
|
+
default
|
23
24
|
end
|
24
25
|
|
25
|
-
def self.
|
26
|
-
|
26
|
+
def self.track(key:, at:, values:, config: nil)
|
27
|
+
Trifle::Ruby::Operations::Timeseries::Increment.new(
|
28
|
+
key: key,
|
29
|
+
at: at,
|
30
|
+
values: values,
|
31
|
+
config: config
|
32
|
+
).perform
|
27
33
|
end
|
28
34
|
|
29
|
-
def self.
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.values_for(key:, from:, to:, range:)
|
40
|
-
Nocturnal.timeline(from: from, to: to, range: range).map do |at|
|
41
|
-
Resource.new(key: key, range: range, at: at).values
|
42
|
-
end
|
35
|
+
def self.values(key:, from:, to:, range:, config: nil)
|
36
|
+
Trifle::Ruby::Operations::Timeseries::Values.new(
|
37
|
+
key: key,
|
38
|
+
from: from,
|
39
|
+
to: to,
|
40
|
+
range: range,
|
41
|
+
config: config
|
42
|
+
).perform
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -5,19 +5,21 @@ require 'tzinfo'
|
|
5
5
|
module Trifle
|
6
6
|
module Ruby
|
7
7
|
class Configuration
|
8
|
-
|
8
|
+
attr_writer :driver
|
9
|
+
attr_accessor :track_ranges, :separator, :time_zone,
|
9
10
|
:beginning_of_week
|
10
11
|
|
11
12
|
def initialize
|
12
13
|
@separator = '::'
|
13
14
|
@ranges = %i[minute hour day week month quarter year]
|
14
15
|
@beginning_of_week = :monday
|
16
|
+
@time_zone = 'GMT'
|
15
17
|
end
|
16
18
|
|
17
19
|
def tz
|
18
20
|
TZInfo::Timezone.get(@time_zone)
|
19
21
|
rescue TZInfo::InvalidTimezoneIdentifier => e
|
20
|
-
puts "Trifle: #{e} - #{
|
22
|
+
puts "Trifle: #{e} - #{time_zone}; Defaulting to GMT."
|
21
23
|
|
22
24
|
TZInfo::Timezone.get('GMT')
|
23
25
|
end
|
@@ -28,6 +30,12 @@ module Trifle
|
|
28
30
|
@ranges & track_ranges
|
29
31
|
end
|
30
32
|
|
33
|
+
def driver
|
34
|
+
raise DriverNotFound if @driver.nil?
|
35
|
+
|
36
|
+
@driver
|
37
|
+
end
|
38
|
+
|
31
39
|
private
|
32
40
|
|
33
41
|
def blank?(obj)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Driver
|
2
|
+
|
3
|
+
Driver is a wrapper class that persists and retrieves values from backend. It needs to implement:
|
4
|
+
- `inc(key:, **values)` method to store values
|
5
|
+
- `get(key:)` method to retrieve values
|
6
|
+
|
7
|
+
## Packer Mixin
|
8
|
+
|
9
|
+
Some databases cannot store nested hashes/values. Or they cannot perform increment on nested values that does not exist. For this reason you can use Packer mixin that helps you convert values to dot notation.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class Sample
|
13
|
+
include Trifle::Ruby::Mixins::Packer
|
14
|
+
end
|
15
|
+
|
16
|
+
values = { a: 1, b: { c: 22, d: 33 } }
|
17
|
+
=> {:a=>1, :b=>{:c=>22, :d=>33}}
|
18
|
+
|
19
|
+
packed = Sample.pack(hash: values)
|
20
|
+
=> {"a"=>1, "b.c"=>22, "b.d"=>33}
|
21
|
+
|
22
|
+
Sample.unpack(hash: packed)
|
23
|
+
=> {"a"=>1, "b"=>{"c"=>22, "d"=>33}}
|
24
|
+
```
|
25
|
+
|
26
|
+
## Dummy driver
|
27
|
+
|
28
|
+
Sample of using custom driver that does, well, nothing useful.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
irb(main):001:1* class Dummy
|
32
|
+
irb(main):002:2* def inc(key:, **values)
|
33
|
+
irb(main):003:2* puts "Dumping #{key} => #{values}"
|
34
|
+
irb(main):004:1* end
|
35
|
+
irb(main):005:2* def get(key:)
|
36
|
+
irb(main):006:2* puts "Random for #{key}"
|
37
|
+
irb(main):007:2* { count: rand(1000) }
|
38
|
+
irb(main):008:1* end
|
39
|
+
irb(main):009:0> end
|
40
|
+
=> :get
|
41
|
+
|
42
|
+
irb(main):010:0> c = Trifle::Ruby::Configuration.new
|
43
|
+
=> #<Trifle::Ruby::Configuration:0x00007fe179aed848 @separator="::", @ranges=[:minute, :hour, :day, :week, :month, :quarter, :year], @beginning_of_week=:monday, @time_zone="GMT">
|
44
|
+
|
45
|
+
irb(main):011:0> c.driver = Dummy.new
|
46
|
+
=> #<Dummy:0x00007fe176302ac8>
|
47
|
+
|
48
|
+
irb(main):012:0> c.track_ranges = [:minute, :hour]
|
49
|
+
=> [:minute, :hour]
|
50
|
+
|
51
|
+
irb(main):013:0> Trifle::Ruby.track(key: 'sample', at: Time.now, values: {count: 1}, config: c)
|
52
|
+
Dumping sample::minute::1611696240 => {:count=>1}
|
53
|
+
Dumping sample::hour::1611694800 => {:count=>1}
|
54
|
+
=> [{2021-01-26 21:24:00 +0000=>{:count=>1}}, {2021-01-26 21:00:00 +0000=>{:count=>1}}]
|
55
|
+
|
56
|
+
irb(main):014:0> Trifle::Ruby.values(key: 'sample', from: Time.now, to: Time.now, range: :hour, config: c)
|
57
|
+
Random for sample::hour::1611694800
|
58
|
+
=> [{2021-01-26 21:00:00 +0000=>{:count=>405}}]
|
59
|
+
```
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'redis'
|
4
|
+
require_relative '../mixins/packer'
|
4
5
|
|
5
6
|
module Trifle
|
6
7
|
module Ruby
|
7
8
|
module Driver
|
8
9
|
class Redis
|
10
|
+
include Mixins::Packer
|
9
11
|
attr_accessor :prefix
|
10
12
|
|
11
13
|
def initialize(client = ::Redis.current, prefix: 'trfl')
|
@@ -15,14 +17,18 @@ module Trifle
|
|
15
17
|
|
16
18
|
def inc(key:, **values)
|
17
19
|
pkey = [@prefix, key].join('::')
|
18
|
-
|
20
|
+
|
21
|
+
self.class.pack(hash: values).each do |k, c|
|
19
22
|
@client.hincrby(pkey, k, c)
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
26
|
def get(key:)
|
24
27
|
pkey = [@prefix, key].join('::')
|
25
|
-
|
28
|
+
|
29
|
+
self.class.unpack(
|
30
|
+
hash: @client.hgetall(pkey)
|
31
|
+
)
|
26
32
|
end
|
27
33
|
end
|
28
34
|
end
|
@@ -2,25 +2,31 @@
|
|
2
2
|
|
3
3
|
module Trifle
|
4
4
|
module Ruby
|
5
|
-
class Nocturnal
|
5
|
+
class Nocturnal # rubocop:disable Metrics/ClassLength
|
6
6
|
DAYS_INTO_WEEK = {
|
7
7
|
sunday: 0, monday: 1, tuesday: 2, wednesday: 3,
|
8
8
|
thursday: 4, friday: 5, saturday: 6
|
9
9
|
}.freeze
|
10
10
|
|
11
|
-
def self.timeline(from:, to:, range:)
|
11
|
+
def self.timeline(from:, to:, range:, config: nil)
|
12
12
|
list = []
|
13
|
-
|
14
|
-
|
13
|
+
from = new(from, config: config).send(range)
|
14
|
+
to = new(to, config: config).send(range)
|
15
|
+
item = from.dup
|
16
|
+
while item <= to
|
15
17
|
list << item
|
16
|
-
item = Nocturnal.new(
|
18
|
+
item = Nocturnal.new(item, config: config).send("next_#{range}")
|
17
19
|
end
|
18
20
|
list
|
19
21
|
end
|
20
22
|
|
21
|
-
def initialize(at)
|
23
|
+
def initialize(at, config: nil)
|
22
24
|
@at = at
|
23
|
-
@
|
25
|
+
@config = config
|
26
|
+
end
|
27
|
+
|
28
|
+
def config
|
29
|
+
@config || Trifle::Ruby.default
|
24
30
|
end
|
25
31
|
|
26
32
|
def change(**fractions)
|
@@ -31,71 +37,76 @@ module Trifle
|
|
31
37
|
fractions.fetch(:hour, @at.hour),
|
32
38
|
fractions.fetch(:minute, @at.min),
|
33
39
|
0, # second
|
34
|
-
|
40
|
+
config.tz.utc_offset
|
35
41
|
)
|
36
42
|
end
|
37
43
|
|
38
|
-
def
|
44
|
+
def minute
|
39
45
|
change
|
40
46
|
end
|
41
47
|
|
42
48
|
def next_minute
|
43
49
|
Nocturnal.new(
|
44
|
-
|
45
|
-
|
50
|
+
minute + 60,
|
51
|
+
config: config
|
52
|
+
).minute
|
46
53
|
end
|
47
54
|
|
48
|
-
def
|
55
|
+
def hour
|
49
56
|
change(minute: 0)
|
50
57
|
end
|
51
58
|
|
52
59
|
def next_hour
|
53
60
|
Nocturnal.new(
|
54
|
-
|
55
|
-
|
61
|
+
hour + 60 * 60,
|
62
|
+
config: config
|
63
|
+
).hour
|
56
64
|
end
|
57
65
|
|
58
|
-
def
|
66
|
+
def day
|
59
67
|
change(hour: 0, minute: 0)
|
60
68
|
end
|
61
69
|
|
62
70
|
def next_day
|
63
71
|
Nocturnal.new(
|
64
|
-
|
65
|
-
|
72
|
+
day + 60 * 60 * 24,
|
73
|
+
config: config
|
74
|
+
).day
|
66
75
|
end
|
67
76
|
|
68
|
-
def
|
69
|
-
today =
|
77
|
+
def week
|
78
|
+
today = day
|
70
79
|
|
71
80
|
(today.to_date - days_to_week_start).to_time
|
72
81
|
end
|
73
82
|
|
74
83
|
def next_week
|
75
84
|
Nocturnal.new(
|
76
|
-
|
77
|
-
|
85
|
+
week + 60 * 60 * 24 * 7,
|
86
|
+
config: config
|
87
|
+
).week
|
78
88
|
end
|
79
89
|
|
80
90
|
def days_to_week_start
|
81
91
|
start_day_number = DAYS_INTO_WEEK.fetch(
|
82
|
-
|
92
|
+
config.beginning_of_week
|
83
93
|
)
|
84
94
|
|
85
95
|
(@at.wday - start_day_number) % 7
|
86
96
|
end
|
87
97
|
|
88
|
-
def
|
98
|
+
def month
|
89
99
|
change(day: 1, hour: 0, minute: 0)
|
90
100
|
end
|
91
101
|
|
92
102
|
def next_month
|
93
103
|
Nocturnal.new(
|
94
|
-
|
95
|
-
|
104
|
+
month + 60 * 60 * 24 * 31,
|
105
|
+
config: config
|
106
|
+
).month
|
96
107
|
end
|
97
108
|
|
98
|
-
def
|
109
|
+
def quarter
|
99
110
|
first_quarter_month = @at.month - (2 + @at.month) % 3
|
100
111
|
|
101
112
|
change(
|
@@ -108,18 +119,20 @@ module Trifle
|
|
108
119
|
|
109
120
|
def next_quarter
|
110
121
|
Nocturnal.new(
|
111
|
-
|
112
|
-
|
122
|
+
quarter + 60 * 60 * 24 * 31 * 3,
|
123
|
+
config: config
|
124
|
+
).quarter
|
113
125
|
end
|
114
126
|
|
115
|
-
def
|
127
|
+
def year
|
116
128
|
change(month: 1, day: 1, hour: 0, minute: 0)
|
117
129
|
end
|
118
130
|
|
119
131
|
def next_year
|
120
132
|
Nocturnal.new(
|
121
|
-
|
122
|
-
|
133
|
+
year + 60 * 60 * 24 * 31 * 12,
|
134
|
+
config: config
|
135
|
+
).year
|
123
136
|
end
|
124
137
|
end
|
125
138
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trifle
|
4
|
+
module Ruby
|
5
|
+
module Operations
|
6
|
+
module Timeseries
|
7
|
+
class Increment
|
8
|
+
attr_reader :key, :values
|
9
|
+
|
10
|
+
def initialize(**keywords)
|
11
|
+
@key = keywords.fetch(:key)
|
12
|
+
@at = keywords.fetch(:at)
|
13
|
+
@values = keywords.fetch(:values)
|
14
|
+
@config = keywords[:config]
|
15
|
+
end
|
16
|
+
|
17
|
+
def config
|
18
|
+
@config || Trifle::Ruby.default
|
19
|
+
end
|
20
|
+
|
21
|
+
def perform
|
22
|
+
config.ranges.map do |range|
|
23
|
+
at = Nocturnal.new(@at, config: config).send(range)
|
24
|
+
config.driver.inc(
|
25
|
+
key: [key, range, at.to_i].join(config.separator),
|
26
|
+
**values
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Trifle
|
4
|
+
module Ruby
|
5
|
+
module Operations
|
6
|
+
module Timeseries
|
7
|
+
class Values
|
8
|
+
attr_reader :key, :range
|
9
|
+
|
10
|
+
def initialize(**keywords)
|
11
|
+
@key = keywords.fetch(:key)
|
12
|
+
@from = keywords.fetch(:from)
|
13
|
+
@to = keywords.fetch(:to)
|
14
|
+
@range = keywords.fetch(:range)
|
15
|
+
@config = keywords[:config]
|
16
|
+
end
|
17
|
+
|
18
|
+
def config
|
19
|
+
@config || Trifle::Ruby.default
|
20
|
+
end
|
21
|
+
|
22
|
+
def timeline
|
23
|
+
Nocturnal.timeline(from: @from, to: @to, range: range)
|
24
|
+
end
|
25
|
+
|
26
|
+
def perform
|
27
|
+
timeline.map do |at|
|
28
|
+
{
|
29
|
+
at => config.driver.get(
|
30
|
+
key: [key, range, at.to_i].join(config.separator)
|
31
|
+
)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/trifle/ruby/version.rb
CHANGED
data/trifle-ruby.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
'automatically storing them for each range.'\
|
12
12
|
'Supports multiple backend drivers.'
|
13
13
|
spec.homepage = "https://github.com/trifle-io/trifle-ruby"
|
14
|
-
spec.required_ruby_version = Gem::Requirement.new('>=
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.6')
|
15
15
|
|
16
16
|
spec.metadata['homepage_uri'] = spec.homepage
|
17
17
|
spec.metadata['source_code_uri'] = "https://github.com/trifle-io/trifle-ruby"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trifle-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jozef Vaclavik
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -130,7 +130,11 @@ executables: []
|
|
130
130
|
extensions: []
|
131
131
|
extra_rdoc_files: []
|
132
132
|
files:
|
133
|
+
- ".github/workflows/ruby.yml"
|
133
134
|
- ".gitignore"
|
135
|
+
- ".gitpod.yml"
|
136
|
+
- ".gitpod/Dockerfile"
|
137
|
+
- ".gitpod/Dockerfile-base"
|
134
138
|
- ".rspec"
|
135
139
|
- ".rubocop.yml"
|
136
140
|
- ".ruby-version"
|
@@ -144,12 +148,13 @@ files:
|
|
144
148
|
- bin/console
|
145
149
|
- bin/setup
|
146
150
|
- lib/trifle/ruby.rb
|
147
|
-
- lib/trifle/ruby/client.rb
|
148
151
|
- lib/trifle/ruby/configuration.rb
|
152
|
+
- lib/trifle/ruby/driver/README.md
|
149
153
|
- lib/trifle/ruby/driver/redis.rb
|
150
154
|
- lib/trifle/ruby/mixins/packer.rb
|
151
155
|
- lib/trifle/ruby/nocturnal.rb
|
152
|
-
- lib/trifle/ruby/
|
156
|
+
- lib/trifle/ruby/operations/timeseries/increment.rb
|
157
|
+
- lib/trifle/ruby/operations/timeseries/values.rb
|
153
158
|
- lib/trifle/ruby/version.rb
|
154
159
|
- trifle-ruby.gemspec
|
155
160
|
homepage: https://github.com/trifle-io/trifle-ruby
|
@@ -165,7 +170,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
165
170
|
requirements:
|
166
171
|
- - ">="
|
167
172
|
- !ruby/object:Gem::Version
|
168
|
-
version: '
|
173
|
+
version: '2.6'
|
169
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
175
|
requirements:
|
171
176
|
- - ">="
|
data/lib/trifle/ruby/client.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Trifle
|
4
|
-
module Ruby
|
5
|
-
class Client
|
6
|
-
def get(key:)
|
7
|
-
driver.get(key: key)
|
8
|
-
end
|
9
|
-
|
10
|
-
def inc(key:, **values)
|
11
|
-
driver.inc(key: key, **values)
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def driver
|
17
|
-
@driver ||= Trifle::Ruby.config.driver
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/trifle/ruby/resource.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Trifle
|
4
|
-
module Ruby
|
5
|
-
class Resource
|
6
|
-
include Mixins::Packer
|
7
|
-
attr_accessor :key, :range, :at
|
8
|
-
|
9
|
-
def initialize(key:, range:, at:)
|
10
|
-
@key = key
|
11
|
-
@range = range
|
12
|
-
@at = at
|
13
|
-
end
|
14
|
-
|
15
|
-
def full_key
|
16
|
-
[key, range, at.to_i].join(Trifle::Ruby.config.separator)
|
17
|
-
end
|
18
|
-
|
19
|
-
def increment(**values)
|
20
|
-
packed = self.class.pack(hash: values)
|
21
|
-
Trifle::Ruby.client.inc(key: full_key, **packed)
|
22
|
-
{
|
23
|
-
at => values
|
24
|
-
}
|
25
|
-
end
|
26
|
-
|
27
|
-
def values
|
28
|
-
{
|
29
|
-
at => self.class.unpack(
|
30
|
-
hash: Trifle::Ruby.client.get(key: full_key)
|
31
|
-
)
|
32
|
-
}
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|