run_once 1.0

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.
@@ -0,0 +1 @@
1
+ v1.0. First version
@@ -0,0 +1,6 @@
1
+ CHANGELOG
2
+ Manifest
3
+ README
4
+ Rakefile
5
+ lib/run_once.rb
6
+ test/test_all.rb
data/README ADDED
@@ -0,0 +1,47 @@
1
+
2
+ run_once
3
+ ---------
4
+
5
+ This gem lets a code block run only once every N seconds.
6
+
7
+ For example:
8
+
9
+ > loop { RunOnce.in(3) { puts Time.now } }
10
+ 2011-07-31 10:29:02 +1000
11
+ 2011-07-31 10:29:05 +1000
12
+ 2011-07-31 10:29:08 +1000
13
+ ...
14
+
15
+
16
+ Usage
17
+ -----
18
+
19
+ First, gem install 'run_once'. RunOnce uses a text file to keep track of
20
+ the state and puts it in /tmp by default. The file is locked during update
21
+ so you can safely use it from multiple threads.
22
+
23
+ require 'run_once'
24
+
25
+ RunOnce.use_file = 'run_once.db'
26
+ # or
27
+ RunOnce.use_path = '/tmp/'
28
+
29
+
30
+ Caller Context
31
+ --------------
32
+
33
+ RunOnce looks at the ruby stack to know where its being called from, so you
34
+ can use it in different places in the same program.
35
+
36
+ Sometimes you may set the context manually using with_context(). You can
37
+ re-use the same context in different places in your program, for example to
38
+ make sure warning emails of any kind are only sent once every 2 minutes, eg:
39
+
40
+ RunOnce.with_context('email alert').in(120) { EmailAlert.deliver ... }
41
+
42
+
43
+ Contact the author
44
+ ------------------
45
+
46
+ Andrew Snow <andrew@modulus.org>
47
+ Andys^ on irc.freenode.net
@@ -0,0 +1,7 @@
1
+ require 'echoe'
2
+ Echoe.new('run_once') do |g|
3
+ g.summary = "Ruby Gem to limit rate of code execution to every N seconds"
4
+ g.author = 'Andrew Snow'
5
+ g.email = 'andrew@modulus.org'
6
+ g.url = "https://github.com/andys/run_once"
7
+ end
@@ -0,0 +1,82 @@
1
+
2
+ class RunOnce
3
+ class << self
4
+ attr_accessor :db_file
5
+
6
+ def use_path=(path)
7
+ self.use_file = path + "/#{self}.db.#{$$}"
8
+ end
9
+
10
+ def use_file=(file)
11
+ self.db_file = file
12
+ File.open(@db_file, 'a+') { }
13
+ end
14
+
15
+ def get_a_context
16
+ self.new(caller[1])
17
+ end
18
+
19
+ def with_context(context)
20
+ new(context)
21
+ end
22
+
23
+ def in(seconds, &bl)
24
+ get_a_context.in(seconds, &bl)
25
+ end
26
+
27
+ def update_db(key, val)
28
+ formatted_val = '%015.3f' % val.to_f
29
+ File.open(@db_file, 'w+') do |io|
30
+ io.flock(File::LOCK_EX)
31
+ io.rewind
32
+ io.puts key if !search_db(io,key)
33
+ io.puts formatted_val
34
+ end
35
+ end
36
+
37
+ def lookup_db(key)
38
+ retval = nil
39
+ File.open(@db_file, 'r') do |io|
40
+ io.flock(File::LOCK_SH)
41
+ retval = io.readline.strip if search_db(io,key)
42
+ end
43
+ retval
44
+ end
45
+
46
+ protected
47
+ def search_db(io, key)
48
+ retval = nil
49
+ keywithnewline = "#{key}\n"
50
+ while(retval.nil? && line = io.gets)
51
+ if(line == keywithnewline)
52
+ retval = true
53
+ else
54
+ io.gets # skip over the next value
55
+ end
56
+ end
57
+ retval
58
+ end
59
+ end
60
+
61
+ @db_file = "/tmp/#{self}.db.#{$$}"
62
+
63
+ def initialize(context)
64
+ @context = context
65
+ end
66
+
67
+ def in(seconds)
68
+ if(!last_happened || last_happened && (Time.now.to_f > (last_happened + seconds.to_f)))
69
+ update_last_happened
70
+ yield
71
+ end
72
+ end
73
+
74
+ def last_happened
75
+ @last_happened ||= (self.class.lookup_db(@context).to_f rescue nil)
76
+ end
77
+
78
+ def update_last_happened
79
+ self.class.update_db(@context, Time.now.to_f)
80
+ end
81
+
82
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{run_once}
5
+ s.version = "1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Andrew Snow"]
9
+ s.date = %q{2011-07-31}
10
+ s.description = %q{Ruby Gem to limit rate of code execution to every N seconds}
11
+ s.email = %q{andrew@modulus.org}
12
+ s.extra_rdoc_files = ["CHANGELOG", "README", "lib/run_once.rb"]
13
+ s.files = ["CHANGELOG", "Manifest", "README", "Rakefile", "lib/run_once.rb", "test/test_all.rb", "run_once.gemspec"]
14
+ s.homepage = %q{https://github.com/andys/run_once}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Run_once", "--main", "README"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{run_once}
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{Ruby Gem to limit rate of code execution to every N seconds}
20
+ s.test_files = ["test/test_all.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
+ else
28
+ end
29
+ else
30
+ end
31
+ end
@@ -0,0 +1,67 @@
1
+
2
+ require 'test/unit'
3
+ require "./#{File.dirname(__FILE__)}/../lib/run_once.rb"
4
+
5
+ class TestRunOnce < Test::Unit::TestCase
6
+ class TestException < Exception ; end
7
+
8
+ def setup
9
+ @fn = './run_once.db'
10
+ File.unlink @fn rescue nil
11
+ RunOnce.use_file = @fn
12
+ end
13
+
14
+ def teardown
15
+ File.unlink @fn rescue nil
16
+ end
17
+
18
+ def test_db_file
19
+ assert File.exists?(@fn)
20
+ end
21
+
22
+ def test_db_ops
23
+ assert_equal nil, RunOnce.lookup_db('A')
24
+ RunOnce.update_db('A', 1.1)
25
+ assert_equal 1.1, RunOnce.lookup_db('A').to_f
26
+ RunOnce.update_db('A', 2.2)
27
+ assert_equal 2.2, RunOnce.lookup_db('A').to_f
28
+ end
29
+
30
+ def test_manual_context
31
+ assert_raises TestException do
32
+ RunOnce.with_context('test').in(0.5) { raise TestException.new }
33
+ end
34
+ 3.times do
35
+ assert_nothing_raised TestException do
36
+ RunOnce.with_context('test').in(0.5) { raise TestException.new }
37
+ end
38
+ sleep 0.1
39
+ end
40
+ sleep 0.3
41
+ assert_raises TestException do
42
+ RunOnce.with_context('test').in(0.5) { raise TestException.new }
43
+ end
44
+ end
45
+
46
+ def test_auto_context
47
+ block = lambda do
48
+ RunOnce.in(0.5) { raise TestException.new }
49
+ end
50
+ assert_raises TestException, &block
51
+ 3.times do
52
+ assert_nothing_raised TestException, &block
53
+ sleep 0.1
54
+ end
55
+ sleep 0.3
56
+ assert_raises TestException, &block
57
+ end
58
+
59
+ def test_1_sec
60
+ stop_time = Time.now + 0.95
61
+ counter = 0
62
+ while(stop_time > Time.now)
63
+ RunOnce.in(0.1) { counter += 1 }
64
+ end
65
+ assert_equal 10, counter
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: run_once
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ version: "1.0"
9
+ platform: ruby
10
+ authors:
11
+ - Andrew Snow
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2011-07-31 00:00:00 +10:00
17
+ default_executable:
18
+ dependencies: []
19
+
20
+ description: Ruby Gem to limit rate of code execution to every N seconds
21
+ email: andrew@modulus.org
22
+ executables: []
23
+
24
+ extensions: []
25
+
26
+ extra_rdoc_files:
27
+ - CHANGELOG
28
+ - README
29
+ - lib/run_once.rb
30
+ files:
31
+ - CHANGELOG
32
+ - Manifest
33
+ - README
34
+ - Rakefile
35
+ - lib/run_once.rb
36
+ - test/test_all.rb
37
+ - run_once.gemspec
38
+ has_rdoc: true
39
+ homepage: https://github.com/andys/run_once
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options:
44
+ - --line-numbers
45
+ - --inline-source
46
+ - --title
47
+ - Run_once
48
+ - --main
49
+ - README
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 1
67
+ - 2
68
+ version: "1.2"
69
+ requirements: []
70
+
71
+ rubyforge_project: run_once
72
+ rubygems_version: 1.3.7
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Ruby Gem to limit rate of code execution to every N seconds
76
+ test_files:
77
+ - test/test_all.rb