single_increase_by 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ae57378362a4e4032e09fbfb2d1ae6a6fcb57deeac03d8c19cd1ba21875360b9
4
+ data.tar.gz: a1cfce6a2e86bf725d556708badf9dfcb07acfd5613e7988a494d7394cb6df05
5
+ SHA512:
6
+ metadata.gz: e66bc9d7f842e46b5a4780de93b1384a1c4bebab7a65aa23b1d4e918717fe77f36fb23e0f5eafce7df11b53dbf18370c1e352750ab03836a9bde1ea2ead77c0f
7
+ data.tar.gz: d1343610cb5e8ce9d519b3389546c5e0f75fc3898de21aa27047eb165e0b74190d6c0339af636525b203071e322dfc2eeee08c199be4dea261093e53abba6827
@@ -0,0 +1,70 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+
7
+ template:
8
+ setup-cache-version: &setup-cache-version
9
+ run:
10
+ name: Write CACHE_VERSION to file
11
+ command: echo $CACHE_VERSION > ~/cache_version.txt && echo CACHE_VERSION=$CACHE_VERSION
12
+ restore-bundle: &restore-bundle
13
+ restore_cache:
14
+ name: Restore bundled gem
15
+ key: gem-bundle-{{ checksum "Gemfile.lock" }}-v-{{ checksum "~/cache_version.txt" }}
16
+ save-bundle: &save-bundle
17
+ save_cache:
18
+ name: Save bundled gem
19
+ key: gem-bundle-{{ checksum "Gemfile.lock" }}-v-{{ checksum "~/cache_version.txt" }}
20
+ paths:
21
+ - ./vendor/bundle
22
+ - /usr/local/bundle/config
23
+
24
+
25
+ jobs:
26
+ build: &containerized
27
+ docker:
28
+ - image: cimg/ruby:2.7.6-node
29
+ environment:
30
+ - REDIS_URL: redis://127.0.0.1:6379
31
+ - image: redis:3.2
32
+
33
+ working_directory: ~/repo
34
+
35
+ steps:
36
+ - checkout
37
+ - <<: *setup-cache-version
38
+ - <<: *restore-bundle
39
+ - run:
40
+ name: install dependencies
41
+ command: |
42
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
43
+ - <<: *save-bundle
44
+
45
+ - run: dockerize -wait tcp://localhost:6379 -timeout 5s
46
+
47
+ - run:
48
+ name: run tests
49
+ command: |
50
+ mkdir /tmp/test-results
51
+ TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
52
+
53
+ bundle exec rspec --format progress \
54
+ --format RspecJunitFormatter \
55
+ --out /tmp/test-results/rspec.xml \
56
+ --format progress \
57
+ $TEST_FILES
58
+
59
+ # collect reports
60
+ - store_test_results:
61
+ path: /tmp/test-results
62
+ - store_artifacts:
63
+ path: /tmp/test-results
64
+ destination: test-results
65
+
66
+ workflows:
67
+ version: 2
68
+ build:
69
+ jobs:
70
+ - build
@@ -0,0 +1,32 @@
1
+ name: Ruby Gem
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ packages: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v3
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: '3.2'
20
+ bundler-cache: true
21
+
22
+ - name: Publish to GPR
23
+ run: |
24
+ mkdir -p $HOME/.gem
25
+ touch $HOME/.gem/credentials
26
+ chmod 0600 $HOME/.gem/credentials
27
+ printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
28
+ gem build *.gemspec
29
+ gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
30
+ env:
31
+ GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
32
+ OWNER: ${{ github.repository_owner }}
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ *.o
12
+ *.a
13
+ mkmf.log
14
+ .env
15
+ uploads
16
+ tags
17
+ .byebug_history
18
+ .DS_Store
19
+ log/redis.9736.log
20
+ .pryrc
21
+ .pry_history
22
+ log/
23
+ node_modules/
24
+ output/
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.7.6
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in single_increase_by.gemspec
4
+ gemspec
5
+
6
+ gem 'thor'
7
+ gem 'parallel'
8
+ gem "bundler"
9
+ gem "rspec"
10
+ gem "byebug"
11
+ gem "redis_test", "~> 0.4.0"
12
+ gem "rspec_junit_formatter"
13
+ gem "activesupport"
data/Gemfile.lock ADDED
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ single_increase_by (0.0.4)
5
+ hashie
6
+ redis
7
+ wolverine
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (7.0.5)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 1.6, < 2)
15
+ minitest (>= 5.1)
16
+ tzinfo (~> 2.0)
17
+ byebug (11.1.3)
18
+ concurrent-ruby (1.2.2)
19
+ connection_pool (2.4.1)
20
+ diff-lcs (1.5.0)
21
+ hashie (5.0.0)
22
+ i18n (1.13.0)
23
+ concurrent-ruby (~> 1.0)
24
+ minitest (5.18.0)
25
+ parallel (1.23.0)
26
+ redis (5.2.0)
27
+ redis-client (>= 0.22.0)
28
+ redis-client (0.22.2)
29
+ connection_pool
30
+ redis_test (0.4.1)
31
+ rspec (3.12.0)
32
+ rspec-core (~> 3.12.0)
33
+ rspec-expectations (~> 3.12.0)
34
+ rspec-mocks (~> 3.12.0)
35
+ rspec-core (3.12.2)
36
+ rspec-support (~> 3.12.0)
37
+ rspec-expectations (3.12.3)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.12.0)
40
+ rspec-mocks (3.12.5)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.12.0)
43
+ rspec-support (3.12.0)
44
+ rspec_junit_formatter (0.6.0)
45
+ rspec-core (>= 2, < 4, != 2.12.0)
46
+ thor (1.2.2)
47
+ tzinfo (2.0.6)
48
+ concurrent-ruby (~> 1.0)
49
+ wolverine (0.3.5)
50
+ redis (>= 3.0.0)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ activesupport
57
+ bundler
58
+ byebug
59
+ parallel
60
+ redis_test (~> 0.4.0)
61
+ rspec
62
+ rspec_junit_formatter
63
+ single_increase_by!
64
+ thor
65
+
66
+ BUNDLED WITH
67
+ 2.4.12
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # SingleIncreaseBy
2
+
3
+
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ source "https://rubygems.pkg.github.com/remitano" do
9
+ gem "single_increase_by", "0.0.1"
10
+ end
11
+ ```
12
+
13
+
14
+
15
+ ## Initialize
16
+
17
+ ```
18
+ SingleIncreaseBy.redis = redis
19
+
20
+ ```
21
+
22
+
23
+
24
+ ## Usage
25
+
26
+ ```
27
+ object = SingleIncreaseBy::Model.new("User:1:PointCount")
28
+ object.get
29
+
30
+ ret = object.incr_amount(amount: 0.1, operation: "support_st01_get_point")
31
+
32
+ ```
33
+
@@ -0,0 +1,61 @@
1
+ local Model = {}
2
+
3
+ function Model.get(attribute_key)
4
+ return redis.call("GET", attribute_key)
5
+ end
6
+
7
+ function Model.set(attribute_key, value)
8
+ redis.call("SET", attribute_key, value)
9
+ return value
10
+ end
11
+
12
+ function Model.incr_amount(attribute_key, change, operation)
13
+ local amount_str = Model.get(attribute_key)
14
+
15
+ local message, ok = Model._check_operation(attribute_key, operation, change, amount_str)
16
+ if not ok then
17
+ return message, ok
18
+ elseif message ~= nil then
19
+ return message, ok
20
+ end
21
+
22
+ if number.is_zero(change) then
23
+ return redis.error_reply("change must not == 0"), false
24
+ end
25
+
26
+ local amount = number.tofloat(amount_str)
27
+ local new_amount = number.add(amount, change)
28
+
29
+ Model._store_operation(attribute_key, operation, change)
30
+ redis.call("SET", attribute_key, new_amount)
31
+ return tostring(new_amount), true
32
+ end
33
+
34
+ function Model.set_expire(attribute_key, time_in_second)
35
+ redis.call("EXPIRE", attribute_key, time_in_second)
36
+ end
37
+
38
+ function Model._store_operation(attribute_key, operation, change)
39
+ local six_months = 6 * 30 * 24 * 60 * 60
40
+ redis.call("SETEX", Model._operation_key(attribute_key, operation), six_months, change)
41
+ end
42
+
43
+ function Model._check_operation(attribute_key, operation, change, default)
44
+ if operation ~= "reconcile" then
45
+ local existing = redis.call("GET", Model._operation_key(attribute_key, operation))
46
+ if existing ~= false then
47
+ if tonumber(existing) == change then
48
+ return default, true
49
+ else
50
+ local error = redis.error_reply(string.format("operation executed with change=%s", existing));
51
+ return error, false
52
+ end
53
+ end
54
+ end
55
+
56
+ return nil, true
57
+ end
58
+
59
+ function Model._operation_key(attribute_key, operation)
60
+ return string.format("single-increase-by:%s:%s", attribute_key, operation)
61
+ end
@@ -0,0 +1,7 @@
1
+ <%= include_partial 'shared/_number.lua' %>
2
+ <%= include_partial 'model/_base.lua' %>
3
+ redis.replicate_commands()
4
+
5
+ local attribute_key = ARGV[1]
6
+ local result = Model.get(attribute_key)
7
+ return result
@@ -0,0 +1,9 @@
1
+ <%= include_partial 'shared/_number.lua' %>
2
+ <%= include_partial 'model/_base.lua' %>
3
+ redis.replicate_commands()
4
+
5
+ local attribute_key = ARGV[1]
6
+ local change = tonumber(ARGV[2])
7
+ local operation = ARGV[3]
8
+ local result, ok = Model.incr_amount(attribute_key, change, operation)
9
+ return result
@@ -0,0 +1,8 @@
1
+ <%= include_partial 'shared/_number.lua' %>
2
+ <%= include_partial 'model/_base.lua' %>
3
+ redis.replicate_commands()
4
+
5
+ local attribute_key = ARGV[1]
6
+ local value = ARGV[2]
7
+ local result = Model.set(attribute_key, value)
8
+ return result
@@ -0,0 +1,8 @@
1
+ <%= include_partial 'shared/_number.lua' %>
2
+ <%= include_partial 'model/_base.lua' %>
3
+ redis.replicate_commands()
4
+
5
+ local attribute_key = ARGV[1]
6
+ local time_in_second = tonumber(ARGV[2])
7
+ local result = Model.set_expire(attribute_key, time_in_second)
8
+ return result
@@ -0,0 +1,93 @@
1
+ local number = {}
2
+
3
+ function number.tofloat(value)
4
+ if value then
5
+ return tonumber(value)
6
+ else
7
+ return 0
8
+ end
9
+ end
10
+
11
+ function number.tostring(number)
12
+ return string.format("%12.12f", number)
13
+ end
14
+
15
+ function number.round(value, scale)
16
+ return number.tofloat(string.format("%."..scale.."f", value))
17
+ end
18
+
19
+ function number.floor(value, scale)
20
+ local value_str10 = string.format("%.10f", value)
21
+ local value_str = string.sub(value_str10, 1, - 10 + scale - 1)
22
+ return number.tofloat(value_str)
23
+ end
24
+
25
+ function number.round8(value)
26
+ return number.round(value, 8)
27
+ end
28
+
29
+ function number.round9(value)
30
+ return number.round(value, 9)
31
+ end
32
+
33
+ function number.floor8(value)
34
+ return number.floor(value, 8)
35
+ end
36
+
37
+ function number.floor4(value)
38
+ return number.floor(value, 4)
39
+ end
40
+
41
+ -- return the possible rounding scale because lua floating number can hold only 15 significant digits
42
+ -- update: reduce rounding scale to 14 since with 15, there is some case the add method does not work well
43
+ function number.rounding_scale(value)
44
+ return 14 - math.ceil(math.log(math.abs(value)) / math.log(10))
45
+ end
46
+
47
+ function number.add(a, b)
48
+ local rounding_scale = math.min(
49
+ math.max(
50
+ number.rounding_scale(a),
51
+ number.rounding_scale(b)
52
+ ),
53
+ 9
54
+ )
55
+
56
+ return number.round(a + b, rounding_scale)
57
+ end
58
+
59
+ function number.is_zero(a)
60
+ return number.round9(a) == 0
61
+ end
62
+
63
+ function number.is_less_than(a, b)
64
+ return number.compare(a, b) < 0
65
+ end
66
+
67
+ function number.is_less_than_or_equal(a, b)
68
+ return number.compare(a, b) <= 0
69
+ end
70
+
71
+ function number.is_greater_than(a, b)
72
+ return number.compare(a, b) > 0
73
+ end
74
+
75
+ function number.is_greater_than_or_equal(a, b)
76
+ return number.compare(a, b) >= 0
77
+ end
78
+
79
+ function number.is_equal(a, b)
80
+ return number.compare(a, b) == 0
81
+ end
82
+
83
+ -- deal with lua only have 15 significant digits for floating number
84
+ function number.compare(a, b)
85
+ local scale = 9
86
+ if a ~= 0 then
87
+ scale = number.rounding_scale(a)
88
+ if scale > 9 then
89
+ scale = 9
90
+ end
91
+ end
92
+ return number.round(a - b, scale)
93
+ end
@@ -0,0 +1,32 @@
1
+ name: Ruby Gem
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ packages: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v3
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: '3.2'
20
+ bundler-cache: true
21
+
22
+ - name: Publish to GPR
23
+ run: |
24
+ mkdir -p $HOME/.gem
25
+ touch $HOME/.gem/credentials
26
+ chmod 0600 $HOME/.gem/credentials
27
+ printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
28
+ gem build *.gemspec
29
+ gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
30
+ env:
31
+ GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
32
+ OWNER: ${{ github.repository_owner }}
@@ -0,0 +1,32 @@
1
+ module SingleIncreaseBy
2
+ class Model
3
+ attr_reader :attribute_key
4
+
5
+ def initialize(attribute_key)
6
+ @attribute_key = attribute_key
7
+ end
8
+
9
+ def get
10
+ SingleIncreaseBy.wolverine.model.get(argv: [attribute_key])
11
+ end
12
+
13
+ def set(value)
14
+ SingleIncreaseBy.wolverine.model.set(argv: [attribute_key, value])
15
+ end
16
+
17
+ def set_expire(time_in_second)
18
+ SingleIncreaseBy.wolverine.model.set_expire(argv: [attribute_key, time_in_second])
19
+ end
20
+
21
+ def incr_amount(amount:, operation:)
22
+ require_identifier!(operation)
23
+ SingleIncreaseBy.wolverine.model.incr_amount(argv: [attribute_key, amount, operation])
24
+ end
25
+
26
+ private
27
+
28
+ def require_identifier!(identifier)
29
+ raise OperationIdentifierMissing if identifier.blank?
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module SingleIncreaseBy
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,98 @@
1
+ require "logger"
2
+ require 'wolverine'
3
+ require 'shellwords'
4
+
5
+ module SingleIncreaseBy
6
+ class OperationIdentifierMissing < StandardError
7
+ end
8
+
9
+ module LuaErrorExt
10
+ def generate_backtrace(file, line_number)
11
+ content = Wolverine::Script.new(file).instance_variable_get('@content')
12
+ puts "===========evaluated #{file}=========="
13
+ system "echo #{Shellwords.escape(content)} | cat -n"
14
+ super
15
+ end
16
+ end
17
+
18
+ module ScriptExt
19
+ def call redis, *args
20
+ keys = (args.first[:keys] || []).map { |k| Shellwords.escape(k) }
21
+ argv = (args.first[:argv] || []).map { |v| Shellwords.escape(v) }
22
+
23
+ cmd = [
24
+ "redis-cli",
25
+ "-h", redis.connection[:host],
26
+ "-p", redis.connection[:port],
27
+ "--ldb-sync-mode --eval #{tmp_file}",
28
+ *keys,
29
+ ",",
30
+ *argv,
31
+ ].join(" ")
32
+
33
+ puts cmd
34
+
35
+ system(cmd)
36
+ end
37
+
38
+ def tmp_file
39
+ @tmp_file ||= File.expand_path("../../tmp/lua-#{@digest}.lua", __FILE__).tap do |file_name|
40
+ File.write(file_name, @content)
41
+ end
42
+ end
43
+ end
44
+
45
+ class << self
46
+ attr_reader :read_wolverines
47
+
48
+ def redis=(redis)
49
+ wolverine.config.redis = redis
50
+ end
51
+
52
+ def redis
53
+ wolverine.config.redis
54
+ end
55
+
56
+ def read_redises=(redises)
57
+ return (@read_wolverines = nil) unless redises.present?
58
+ @read_wolverines = redises.map do |redis|
59
+ Wolverine.new.tap do |wolf|
60
+ wolf.config.redis = redis
61
+ end
62
+ end
63
+ end
64
+
65
+ def enable_verbose_lua_error
66
+ Wolverine::LuaError.prepend(LuaErrorExt)
67
+ end
68
+
69
+ def enable_ldb_debugging
70
+ Wolverine::Script.prepend(ScriptExt)
71
+ end
72
+
73
+ def array_to_ostruct(arr)
74
+ OpenStruct.new(Hash[arr.each_slice(2).to_a])
75
+ end
76
+
77
+ def wolverine
78
+ @wolverine ||= Wolverine.new.tap do |wolf|
79
+ wolf.config.script_path = Pathname.new(File.expand_path("../../app/wolverine", __FILE__))
80
+ end
81
+ end
82
+
83
+ def read_wolverine
84
+ if read_wolverines.blank?
85
+ wolverine
86
+ else
87
+ read_wolverines.sample
88
+ end
89
+ end
90
+
91
+ def with_readonly
92
+ yield read_wolverine
93
+ end
94
+ end
95
+ end
96
+
97
+ Dir[File.expand_path("../single_increase_by/*.rb", __FILE__)].each { |f| require f }
98
+ Dir[File.expand_path("../single_increase_by/**/*.rb", __FILE__)].each { |f| require f }
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'single_increase_by/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "single_increase_by"
8
+ spec.version = "#{SingleIncreaseBy::VERSION}"
9
+ spec.authors = ["Tan Nguyen"]
10
+ spec.email = ["tannguyenanh@gmail.com"]
11
+ spec.summary = %q{Perform single_increase_by operation}
12
+ spec.description = %q{Perform single_increase_by operation}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "redis"
22
+ spec.add_dependency "wolverine"
23
+ spec.add_dependency "hashie"
24
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Model#incr_amount" do
4
+ context "operation is nil" do
5
+ it "raise error" do
6
+ model = SingleIncreaseBy::Model.new("coin:1")
7
+ expect {
8
+ model.incr_amount(amount: 0.1, operation: nil)
9
+ }.to raise_error(SingleIncreaseBy::OperationIdentifierMissing)
10
+ end
11
+ end
12
+
13
+ context "operation is empty string" do
14
+ it "raise error" do
15
+ expect {
16
+ model = SingleIncreaseBy::Model.new("coin:1")
17
+ model.incr_amount(amount: 0.1, operation: "")
18
+ }.to raise_error(SingleIncreaseBy::OperationIdentifierMissing)
19
+ end
20
+ end
21
+
22
+ context "positive incr" do
23
+ it "incr the balance" do
24
+ model = SingleIncreaseBy::Model.new("coin:1")
25
+ ret = model.incr_amount(amount: 0.1, operation: "operation1")
26
+ expect(ret.to_d).to eq 0.1
27
+ amount = model.get
28
+ expect(amount.to_d.round(8)).to eq 0.1
29
+ end
30
+ end
31
+
32
+ context "negative incr" do
33
+ it "decr the balance" do
34
+ model = SingleIncreaseBy::Model.new("coin:1")
35
+ ret = model.incr_amount(amount: 0.1, operation: "operation1")
36
+ expect(ret.to_d).to eq 0.1
37
+ ret = model.incr_amount(amount: -0.1, operation: "operation2")
38
+ expect(ret.to_d).to eq 0.0
39
+ end
40
+ end
41
+
42
+ context "redo action" do
43
+ it "keeps same value" do
44
+ model = SingleIncreaseBy::Model.new("coin:1")
45
+ ret = model.incr_amount(amount: 0.1, operation: "operation1")
46
+ expect(ret.to_d).to eq 0.1
47
+ ret = model.incr_amount(amount: 0.1, operation: "operation2")
48
+ expect(ret.to_d.round(8)).to eq 0.2
49
+ ret = model.incr_amount(amount: 0.1, operation: "operation1")
50
+ expect(ret.to_d.round(8)).to eq 0.2
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Model#set_expire" do
4
+ context "set expire key" do
5
+ it "set expire successfully" do
6
+ model = SingleIncreaseBy::Model.new("coin:1")
7
+ ret = model.incr_amount(amount: 0.1, operation: "operation1")
8
+ expect(ret.to_d).to eq 0.1
9
+ amount = model.get
10
+ expect(amount.to_d.round(8)).to eq 0.1
11
+
12
+ model.set_expire(60) # 60 seconds
13
+ expect(SingleIncreaseBy.redis.ttl("coin:1")).to be_between(40.seconds, 60.seconds)
14
+ model.set_expire(120) # 60 seconds
15
+ expect(SingleIncreaseBy.redis.ttl("coin:1")).to be_between(90.seconds, 120.seconds)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Model#set" do
4
+ context "value is already have" do
5
+ it "raise error" do
6
+ model = SingleIncreaseBy::Model.new("coin:1")
7
+ ret = model.incr_amount(amount: 0.1, operation: "operation1")
8
+ expect(ret.to_d).to eq 0.1
9
+ amount = model.get
10
+ expect(amount.to_d.round(8)).to eq 0.1
11
+
12
+ model.set(5)
13
+ amount = model.get
14
+ expect(amount.to_d.round(8)).to eq 5
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'single_increase_by'
4
+ require 'byebug'
5
+ require 'active_support'
6
+ require 'active_support/core_ext'
7
+
8
+ # Requires helpers
9
+ Dir[File.expand_path("./spec/helpers/**/*.rb")].each { |f| require f }
10
+
11
+ # Requires supporting ruby files with custom matchers and macros, etc,
12
+ # in spec/support/ and its subdirectories.
13
+ Dir[File.expand_path("./spec/support/**/*.rb")].each { |f| require f }
14
+
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+ RSpec.configure do |config|
17
+ config.treat_symbols_as_metadata_keys_with_true_values = true
18
+ config.run_all_when_everything_filtered = true
19
+ config.filter_run :focus
20
+
21
+ # Run specs in random order to surface order dependencies. If you find an
22
+ # order dependency and want to debug it, you can fix the order by providing
23
+ # the seed, which is printed after each run.
24
+ # --seed 1234
25
+ config.order = 'random'
26
+ end
27
+
28
+ SingleIncreaseBy.enable_verbose_lua_error
@@ -0,0 +1,34 @@
1
+ require 'redis'
2
+
3
+ RSpec.configure do |config|
4
+ if ENV["CI"]
5
+ config.after(:each) do
6
+ SingleIncreaseBy.redis.flushdb
7
+ end
8
+ else
9
+ require 'redis_test'
10
+ config.before(:suite) do
11
+ ENV['TEST_REDIS_PORT'] = '6380'
12
+
13
+ RedisTest.start
14
+ ENV['REDIS_URL'] = "" # make sure default redis url is unset
15
+ #RedisTest.start(log_to_stdout: true)
16
+ SingleIncreaseBy.redis = Redis.new(url: RedisTest.server_url)
17
+ end
18
+
19
+ config.before(:each) do
20
+ SingleIncreaseBy.redis.set("ENVIRONMENT", "test")
21
+ end
22
+
23
+ config.after(:each) do
24
+ RedisTest.clear
25
+ # notice that will flush the Redis db, so it's less
26
+ # desirable to put that in a config.before(:each) since it may clean any
27
+ # data that you try to put in redis prior to that
28
+ end
29
+
30
+ config.after(:suite) do
31
+ RedisTest.stop
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ class Waiter
2
+ def self.wait(timeout = 1)
3
+ Timeout.timeout(timeout) do
4
+ loop do
5
+ break if yield
6
+ sleep 0.01
7
+ end
8
+ end
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: single_increase_by
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Tan Nguyen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-09-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: redis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: wolverine
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: hashie
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Perform single_increase_by operation
56
+ email:
57
+ - tannguyenanh@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".circleci/config.yml"
63
+ - ".github/workflows/gem-push.yml"
64
+ - ".gitignore"
65
+ - ".tool-versions"
66
+ - Gemfile
67
+ - Gemfile.lock
68
+ - README.md
69
+ - app/wolverine/model/_base.lua
70
+ - app/wolverine/model/get.lua
71
+ - app/wolverine/model/incr_amount.lua
72
+ - app/wolverine/model/set.lua
73
+ - app/wolverine/model/set_expire.lua
74
+ - app/wolverine/shared/_number.lua
75
+ - github/workflows/publish-gem.yml
76
+ - lib/single_increase_by.rb
77
+ - lib/single_increase_by/model.rb
78
+ - lib/single_increase_by/version.rb
79
+ - single_increase_by.gemspec
80
+ - spec/lib/single_increase_by/model/incr_total_spec.rb
81
+ - spec/lib/single_increase_by/model/set_expire_spec.rb
82
+ - spec/lib/single_increase_by/model/set_spec.rb
83
+ - spec/spec_helper.rb
84
+ - spec/support/redis_test.rb
85
+ - spec/support/waiter.rb
86
+ homepage: ''
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.4.10
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: Perform single_increase_by operation
109
+ test_files:
110
+ - spec/lib/single_increase_by/model/incr_total_spec.rb
111
+ - spec/lib/single_increase_by/model/set_expire_spec.rb
112
+ - spec/lib/single_increase_by/model/set_spec.rb
113
+ - spec/spec_helper.rb
114
+ - spec/support/redis_test.rb
115
+ - spec/support/waiter.rb