progress_tracker 0.0.1

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
+ SHA1:
3
+ metadata.gz: df21ecd837ae3df9bde25bb75176b76b74babba1
4
+ data.tar.gz: fdc09b64c60c0b47579458b6b665b65584cd0bea
5
+ SHA512:
6
+ metadata.gz: c21785f5a9253a41c869b221aae9e295b3a524ff2f5e2387d0b1285bad7cd10d4a158dd6c3e46162e6005b35af19c2c5d973963a96f81e737941cf03c7989d3b
7
+ data.tar.gz: 64c5f45f120e788bbe67ecda28f830d8a4cc0c8c884b934245d35af5e75339d0bc970e4276463df5145d5c8e81d8a26f01bd0013c38a70ab496238149a1aedad
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in progress_tracker.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Dan Cheail <dan@undumb.com>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # ProgressTracker
2
+
3
+ ProgressTracker is a very simple API for logging and retreiving the progress of
4
+ a given background task. It lets you track the progress / status of multiple
5
+ objects, and retrieve them as a single set.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'progress_tracker'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install progress_tracker
20
+
21
+ ## Usage
22
+
23
+ Track objects associated with a simple name, or emable the user of a class / id pair
24
+
25
+ pt = ProgressTracker.new(:thing)
26
+ pt = ProgressTracker.new(:billing_cycle, id)
27
+
28
+ # Sane Defaults
29
+ pt = ProgressTracker.new(:foo, 10)
30
+ pt.to_hash # => { progress: 0, message: "" }
31
+
32
+
33
+ Update the progess / messages on the base object
34
+
35
+ pt.progress 50
36
+ pt.message "String"
37
+ pt.status "BAD"
38
+
39
+ Or, just chuck anything you want in there
40
+
41
+ pt.update progress: 50, message: "Strang.", status: "BAD", herpy: "derpy"
42
+
43
+ Alternatviely, track seperate, named sub-objects, again with name or class / id pair
44
+
45
+ pt.track :cycle
46
+ pt.track :bill, 10
47
+ pt.track :bill, 11
48
+ pt.track :bill, 13
49
+
50
+ # update progress percentage
51
+ pt.cycle.progress 34
52
+ pt.bill(34).progress 92
53
+
54
+ # update status message
55
+ pt.cycle.message "Message"
56
+ pt.bill(34).message "Message"
57
+
58
+ # or, update them both at the same time
59
+ pt.cycle.update progress: 14, message: "Message"
60
+ pt.bill(34).update progress: 14, message: "Message"
61
+
62
+ Then, in an new context, re-initialise and retreive a complete overview:
63
+
64
+ pt = ProgressTracker.new(:billing_cycle, id)
65
+ pt.to_hash # => {
66
+ _base: { progress: 19, message: "Message" },
67
+ cycle: { progress: 19, message: "Message" },
68
+ bill_10: { progress: 19, message: "Message" },
69
+ bill_11: { progress: 19, message: "Message" },
70
+ bill_13: { progress: 19, message: "Message" },
71
+ }
72
+
73
+ And easily convert it to JSON as needed:
74
+
75
+ pt.to_json
76
+
77
+ ## Contributing
78
+
79
+ 1. Fork it
80
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
81
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
82
+ 4. Push to the branch (`git push origin my-new-feature`)
83
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,95 @@
1
+ module ProgressTracker
2
+ class Base
3
+
4
+ # Enable the selection of a Redis connection
5
+ class << self
6
+ attr_accessor :redis_connection
7
+ end
8
+
9
+ # And default to using the established global var (yes, I know. Bad.)
10
+ @redis_connection = $redis
11
+
12
+ # Instance-level access to Redis (actually a Redis::Namespace)
13
+ attr_reader :redis, :base_key
14
+
15
+ # All sub-objects tracked with Base#track
16
+ attr_reader :tracked_object_keys
17
+
18
+ # The tracked object that this instance currently refers to
19
+ attr_accessor :current_tracked_object
20
+
21
+ # Just so we've always got values...
22
+ DEFAULTS = { progress: 0, message: "" }
23
+
24
+ def initialize(object_name, object_id = nil)
25
+ @base_key = _ck(object_name, object_id)
26
+
27
+ @redis = ::Redis::Namespace.new(@base_key, redis: ProgressTracker::Base.redis_connection)
28
+
29
+ # initialize or fetch our tracked object keys from Redis, ensuring we at least have _base present
30
+ @tracked_object_keys = Set.new(redis.smembers("tracked-object-keys").map(&:to_sym) << :_base)
31
+
32
+ @current_tracked_object = :_base
33
+ end
34
+
35
+ # Build a compound key and store it for future reference
36
+ def track(object_name, object_id = nil)
37
+ new_key = _ck(object_name, object_id)
38
+
39
+ redis.sadd "tracked-object-keys", new_key
40
+ tracked_object_keys << new_key
41
+ end
42
+
43
+ # grab all the keys related to this set from redis
44
+ def to_hash
45
+ tracked_object_keys.inject({}) do |hash, key|
46
+ hash.tap do |h|
47
+ h[key] = DEFAULTS.merge(redis.hgetall(key).symbolize_keys)
48
+
49
+ # Make sure :progress is always returned as an integer
50
+ h[key][:progress] = h[key][:progress].to_i
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ # If a method is called that matches the name of a tracked object, return
57
+ # a new instance of self with the @current_tracked_object set
58
+ # to the correct key
59
+ def method_missing(meth, *args)
60
+ meth_key = _ck(meth, args.first)
61
+
62
+ if tracked_object_keys.include?(meth_key)
63
+ self.dup.tap do |t|
64
+ t.current_tracked_object = meth_key
65
+ end
66
+ else
67
+ raise NoMethodError
68
+ end
69
+ end
70
+
71
+
72
+ def update(hsh)
73
+ redis.hmset current_tracked_object, *hsh.to_a.flatten
74
+ end
75
+
76
+ def progress(value)
77
+ update progress: value.to_i
78
+ end
79
+
80
+ def message(msg)
81
+ update message: msg
82
+ end
83
+
84
+ private
85
+
86
+ # build a compound key in the format (name_id)
87
+ def _ck(object_name, object_id = nil)
88
+ if object_id
89
+ :"#{object_name}_#{object_id}"
90
+ else
91
+ object_name.to_sym
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,3 @@
1
+ module ProgressTracker
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'set'
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/hash/keys'
5
+
6
+ require 'redis'
7
+ require 'redis/namespace'
8
+
9
+ require 'progress_tracker/version'
10
+ require 'progress_tracker/base'
11
+
12
+ module ProgressTracker
13
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'progress_tracker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "progress_tracker"
8
+ spec.version = ProgressTracker::VERSION
9
+ spec.authors = ["Dan Cheail"]
10
+ spec.email = ["dan@undumb.com"]
11
+ spec.description = %q{A very simple API for logging and retreiving the progress of a given background task using Redis.}
12
+ spec.summary = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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 "activesupport", "~> 4.0.0"
22
+ spec.add_dependency "redis", "~> 3.0.0"
23
+ spec.add_dependency "redis-namespace", "~> 1.3.1"
24
+
25
+ spec.add_development_dependency "mock_redis"
26
+ spec.add_development_dependency "rspec", "~> 2.14"
27
+ spec.add_development_dependency "bundler", "~> 1.3"
28
+ spec.add_development_dependency "rake"
29
+ end
@@ -0,0 +1,116 @@
1
+ Bundler.require(:default, :development)
2
+
3
+ require 'rspec'
4
+ require 'mock_redis'
5
+
6
+ require 'progress_tracker'
7
+
8
+ # FAKE REDIS!
9
+ ProgressTracker::Base.redis_connection = MockRedis.new
10
+
11
+ shared_examples "a ProgressTracker::Tracker instance" do
12
+ let(:setter_base) { ProgressTracker::Base.new(:paired_thing) }
13
+ let(:getter) { ProgressTracker::Base.new(:paired_thing) }
14
+
15
+ it "remembers the current progress" do
16
+ setter.progress 50
17
+ expect(_result(getter, :progress, setter.current_tracked_object)).to eql(50)
18
+ end
19
+
20
+ it "ensures that progress is an integer" do
21
+ setter.progress 50.34
22
+ expect(_result(getter, :progress, setter.current_tracked_object)).to eql(50)
23
+ end
24
+
25
+ it "remembers the latest message" do
26
+ msg = "So long, and thanks for all the fish."
27
+
28
+ setter.message msg
29
+ expect(_result(getter, :message, setter.current_tracked_object)).to eql(msg)
30
+ end
31
+
32
+
33
+ it "remembers several things at once" do
34
+ things = { progress: 42, message: "Share and enjoy." }
35
+ setter.update things
36
+
37
+ expect(getter.to_hash[setter.current_tracked_object]).to eql(things)
38
+ end
39
+
40
+ it "remembers arbitrary keys / values" do
41
+ setter.update foo: "bar!"
42
+ expect(getter.to_hash[setter.current_tracked_object][:foo]).to eql("bar!")
43
+ end
44
+ end
45
+
46
+
47
+ describe ProgressTracker::Base do
48
+
49
+ # make sure we're clearing out fake-redis after each test
50
+ after(:each) do
51
+ ProgressTracker::Base.redis_connection.flushdb
52
+ end
53
+
54
+ # shortcut for accessing deep hash keys
55
+ def _result(pt, field, key = :_base)
56
+ pt.to_hash[key][field]
57
+ end
58
+
59
+ let(:pt) { ProgressTracker::Base.new(:derp) }
60
+
61
+ it "must be initialized with at least a simple key" do
62
+ expect { ProgressTracker::Base.new }.to raise_error
63
+ expect { ProgressTracker::Base.new(:derp) }.not_to raise_error
64
+ end
65
+
66
+
67
+ it "can be initialized using a class / id compound key" do
68
+ expect { ProgressTracker::Base.new(:thing, 100) }.not_to raise_error
69
+ end
70
+
71
+
72
+ it "returns sane defaults" do
73
+ expect(pt.to_hash).to eql({ _base: { progress: 0, message: "" } })
74
+ end
75
+
76
+ it "can track mutliple sub-objects" do
77
+ pt.track :foo
78
+ pt.track :bar, 100
79
+
80
+ expect(pt.to_hash).to have_key(:foo)
81
+ expect(pt.to_hash).to have_key(:bar_100)
82
+ end
83
+
84
+ # it "ensures that any tracked sub-objects are re-cached when initialising a new tracker" do
85
+ # pt.track :foo
86
+ # pt.track :bar, 100
87
+
88
+ # pt2 = ProgressTracker::Base.new(pt.base_key)
89
+
90
+ # expect(pt2.to_hash).to have_key(:foo)
91
+ # expect(pt2.to_hash).to have_key(:bar_100)
92
+ # end
93
+
94
+ context "when operating on the base object" do
95
+ it_behaves_like "a ProgressTracker::Tracker instance" do
96
+ let(:setter) { setter_base }
97
+ end
98
+ end
99
+
100
+
101
+ context "when operating on a simple sub-object" do
102
+ it_behaves_like "a ProgressTracker::Tracker instance" do
103
+ before(:each) { setter_base.track :derp }
104
+ let(:setter) { setter_base.derp }
105
+ end
106
+ end
107
+
108
+ context "when tracking a compound-key sub-object" do
109
+ it_behaves_like "a ProgressTracker::Tracker instance" do
110
+ before(:each) { setter_base.track :derp, 100 }
111
+ let(:setter) { setter_base.derp(100) }
112
+ end
113
+ end
114
+
115
+ it "can go to json, too!"
116
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: progress_tracker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dan Cheail
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: redis
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 3.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 3.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis-namespace
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: mock_redis
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '2.14'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '2.14'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: A very simple API for logging and retreiving the progress of a given
112
+ background task using Redis.
113
+ email:
114
+ - dan@undumb.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - .rspec
121
+ - Gemfile
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - lib/progress_tracker.rb
126
+ - lib/progress_tracker/base.rb
127
+ - lib/progress_tracker/version.rb
128
+ - progress_tracker.gemspec
129
+ - spec/progress_tracker_spec.rb
130
+ homepage: ''
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - '>='
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.1.4
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: ''
154
+ test_files:
155
+ - spec/progress_tracker_spec.rb