From 53190de1686863b6d2715af570d74b09cc530343 Mon Sep 17 00:00:00 2001 From: Henry Steinhauer Date: Wed, 20 Apr 2022 15:15:03 +0200 Subject: [PATCH] Feature/Add counters module (#12) * feat: Add custom counters * feat: Add minitests for new counter feature * feat: Update minitests from new counter feature * feat: Add Counters section to README * feat: Add counter method tests and enrich README with an example of a counter --- README.md | 31 +++++++- lib/worker_tools/basics.rb | 1 + lib/worker_tools/counters.rb | 41 ++++++++++ lib/worker_tools/recorder.rb | 1 + lib/worker_tools/version.rb | 2 +- test/schema.rb | 2 +- test/worker_tools/counters_test.rb | 122 +++++++++++++++++++++++++++++ 7 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 lib/worker_tools/counters.rb create mode 100644 test/worker_tools/counters_test.rb diff --git a/README.md b/README.md index 03a9301..696a87d 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,36 @@ def perform(model_id) end ``` +## Counters + +There is a counter wrapper that you can use to add custom counters to the meta attribute. To do this, you need to complete the following tasks: +- include WorkerTools::Counters to your class +- add :counters to the wrappers method props +- call counters method with your custom counters +You can see an example below. After that, you can access your custom counters via the meta attribute. + +```ruby +class MyImporter + include WorkerTools::Counters + wrappers :counters + counters :foo, :bar + + def run + example_foo_counter_methods + end + + def example_foo_counter_methods + self.foo = 0 + + 10.times { increment_foo } + + puts foo # foo == 10 + end + + # .. +end +``` + ## Benchmark There is a benchmark wrapper that you can use to record the benchmark. The only thing you need to do is to include the benchmark module and append the name to the wrapper array. Below you can see an example of the integration. @@ -217,7 +247,6 @@ class MyImporter end ``` - ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/i22-digitalagentur/worker_tools. diff --git a/lib/worker_tools/basics.rb b/lib/worker_tools/basics.rb index 785ded7..366c22f 100644 --- a/lib/worker_tools/basics.rb +++ b/lib/worker_tools/basics.rb @@ -33,6 +33,7 @@ def run def perform(model_id = nil) @model_id = model_id + with_wrappers(wrapper_methods) do run end diff --git a/lib/worker_tools/counters.rb b/lib/worker_tools/counters.rb new file mode 100644 index 0000000..d6ab988 --- /dev/null +++ b/lib/worker_tools/counters.rb @@ -0,0 +1,41 @@ +module WorkerTools + module Counters + extend ActiveSupport::Concern + + included do + def self.counters(*args) + @counters ||= args.flatten + add_counter_methods + end + + def self.read_counters + @counters || [] + end + + def self.add_counter_methods + @counters.each do |name| + define_method name do + model.meta[name] + end + define_method "#{name}=" do |value| + model.meta[name] = value + end + define_method "increment_#{name}" do + model.meta[name] += 1 + end + end + end + + def with_wrapper_counters(&block) + reset_counters + block.call + end + + def reset_counters + self.class.read_counters.each do |name| + model.meta[name] = 0 + end + end + end + end +end diff --git a/lib/worker_tools/recorder.rb b/lib/worker_tools/recorder.rb index f8dbcfd..b870005 100644 --- a/lib/worker_tools/recorder.rb +++ b/lib/worker_tools/recorder.rb @@ -1,5 +1,6 @@ module WorkerTools module Recorder + def with_wrapper_recorder(&block) block.yield # this time we do want to catch Exception to attempt to handle some of the diff --git a/lib/worker_tools/version.rb b/lib/worker_tools/version.rb index ab6367f..22c7236 100644 --- a/lib/worker_tools/version.rb +++ b/lib/worker_tools/version.rb @@ -1,3 +1,3 @@ module WorkerTools - VERSION = '0.2.3'.freeze + VERSION = '0.2.2'.freeze end diff --git a/test/schema.rb b/test/schema.rb index b7bf4f5..506970d 100644 --- a/test/schema.rb +++ b/test/schema.rb @@ -5,7 +5,7 @@ t.integer 'kind', null: false t.integer 'state', default: 0, null: false t.text 'information' - t.json :meta, default: {} + t.json 'meta', default: {} t.timestamps end end diff --git a/test/worker_tools/counters_test.rb b/test/worker_tools/counters_test.rb new file mode 100644 index 0000000..5782ca4 --- /dev/null +++ b/test/worker_tools/counters_test.rb @@ -0,0 +1,122 @@ +require 'test_helper' + +describe WorkerTools::Counters do + class Counter + include WorkerTools::Basics + include WorkerTools::Counters + + wrappers :basics, :counters + counters :foo, :bar + + def model_class + Import + end + + def model_kind + 'foo' + end + + def run; end + end + + describe '#counters' do + before :each do + import = create_import + @importer = Counter.new + @importer.perform(import) + end + + it 'returns an array of counters' do + expect(@importer.class.read_counters).must_equal [:foo, :bar] + end + + it 'creates for each counter a getter method' do + @importer.class.read_counters.each do |counter| + expect(@importer.respond_to?(counter)).must_equal true + end + end + + it 'creates for each counter a setter method' do + @importer.class.read_counters.each do |counter| + expect(@importer.respond_to?("#{counter}=")).must_equal true + end + end + + it 'creates for each counter an incrementer method' do + @importer.class.read_counters.each do |counter| + expect(@importer.respond_to?("increment_#{counter}")).must_equal true + end + end + + describe '#counters_increment' do + it 'increments the counter by 1' do + @importer.class.read_counters.each do |counter| + @importer.send("#{counter}=", 0) + @importer.send("increment_#{counter}") + expect(@importer.send(counter)).must_equal 1 + end + end + end + + describe '#counter=' do + it 'overwrites the current counter value' do + @importer.class.read_counters.each do |counter| + @importer.send("#{counter}=", 5) + expect(@importer.send(counter)).must_equal 5 + end + + @importer.class.read_counters.each do |counter| + @importer.send("#{counter}=", 2) + expect(@importer.send(counter)).must_equal 2 + end + end + end + + describe '#counter' do + it 'returns value of counter' do + @importer.class.read_counters.each do |counter| + @importer.send("#{counter}=", 2) + expect(@importer.send(counter)).must_equal 2 + end + end + end + end + + describe '#with_wrapper_counters' do + before :each do + @import = create_import + @importer = Counter.new + end + + it 'should call reset_counters function' do + @importer.expects(:reset_counters).returns(true) + @importer.perform(@import) + end + + it 'raise error if model.meta not exist' do + err = assert_raises(StandardError) { @importer.with_wrapper_counters } + assert_includes err.message, 'Model not available' + end + end + + describe 'reset_counters' do + before :each do + import = create_import + @importer = Counter.new + @importer.perform(import) + end + + it 'resets the counters' do + @importer.class.read_counters.each do |counter| + @importer.send("#{counter}=", 1) + expect(@importer.send(counter)).must_equal 1 + end + + @importer.reset_counters + + @importer.class.read_counters.each do |counter| + expect(@importer.send(counter)).must_equal 0 + end + end + end +end