trifle-ruby 3.0.1 → 3.0.4
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.
- 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
|
+
[](https://badge.fury.io/rb/trifle-ruby)
|
4
|
+

|
5
|
+
[](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
|