single_increase_by 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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