bean_counter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ require 'forwardable'
2
+ require 'beaneater'
3
+ require 'bean_counter/version'
4
+ require 'bean_counter/core'
5
+ require 'bean_counter/strategy'
6
+ require 'bean_counter/strategies/stalk_climber_strategy'
7
+ require 'bean_counter/enqueued_expectation'
8
+ require 'bean_counter/tube_expectation'
@@ -0,0 +1,115 @@
1
+ module BeanCounter
2
+
3
+ # Use StalkClimberStrategy by default because it works with standard Beanstalkd
4
+ DEFAULT_STRATEGY = :'BeanCounter::Strategy::StalkClimberStrategy'
5
+
6
+ class << self
7
+ # Beanstalkd server urls to be used by BeanCounter
8
+ attr_writer :beanstalkd_url
9
+ end
10
+
11
+ # :call-seq:
12
+ # beanstalkd_url() => Array[String]
13
+ #
14
+ # Returns an array of parsed beanstalkd urls.
15
+ # Server urls provided via the environment variable +BEANSTALKD_URL+ are given
16
+ # precedence. When setting beanstalkd_url from the environment, urls are
17
+ # expected in a comma separated list. If ENV['BEANSTALKD_URL'] is not set
18
+ # BeanCounter::beanstalkd_url is checked and parsed next. Finally, if
19
+ # BeanCounter::beanstalkd_url has not been set, the configuration for Beaneater is
20
+ # checked and parsed. If no beanstalkd_url can be determined a RuntimeError is raised.
21
+ # URLs can be provided in any of three supported formats:
22
+ # * localhost (host only)
23
+ # * 192.168.1.100:11300 (host and port)
24
+ # * beanstalk://127.0.0.1:11300 (host and port prefixed by beanstalk scheme)
25
+ #
26
+ # In short, a host is the only required component. If no port is provided, the default
27
+ # beanstalkd port of 11300 is assumed. If a scheme other than beanstalk is provided
28
+ # a StalkClimber::ConnectionPool::InvalidURIScheme error is raised.
29
+ #
30
+ # $ BEANSTALKD_URL='127.0.0.1,beanstalk://localhost:11300,localhost:11301' rake test
31
+ # BeanCounter.beanstalkd_url
32
+ # #=> ['127.0.0.1', 'beanstalk://localhost:11300', 'localhost:11301']
33
+ #
34
+ # BeanCounter.beanstalkd_url = 'beanstalk://localhost'
35
+ # BeanCounter.beanstalkd_url
36
+ # #=> 'beanstalk://localhost'
37
+ #
38
+ # Beaneater.configure do |config|
39
+ # config.beanstalkd_url = ['localhost', 'localhost:11301']
40
+ # end
41
+ #
42
+ # BeanCounter.beanstalkd_url
43
+ # #=> ['localhost', 'localhost:11301']
44
+ def self.beanstalkd_url
45
+ @hosts_from_env = ENV['BEANSTALKD_URL']
46
+ @hosts_from_env = @hosts_from_env.split(',').map!(&:strip) unless @hosts_from_env.nil?
47
+ beanstalkd_url = @hosts_from_env || @beanstalkd_url || Beaneater.configuration.beanstalkd_url
48
+ raise 'Could not determine beanstalkd url' if beanstalkd_url.to_s == ''
49
+ return beanstalkd_url
50
+ end
51
+
52
+
53
+ # :call-seq:
54
+ # default_strategy() => subclass of BeanCounter::Strategy
55
+ #
56
+ # Return a previously materialized default strategy or materialize a new default
57
+ # strategy for use. See BeanCounter::Strategy::materialize_strategy for more
58
+ # information on the materialization process.
59
+ def self.default_strategy
60
+ return @default_strategy ||= BeanCounter::Strategy.materialize_strategy(DEFAULT_STRATEGY)
61
+ end
62
+
63
+
64
+ # :call-seq:
65
+ # reset!(tube_name = nil) => Boolean
66
+ # Uses the strategy to delete all jobs from the +tube_name+ tube. If +tube_name+
67
+ # is not provided, all jobs on the beanstalkd server are deleted.
68
+ #
69
+ # It should be noted that jobs that are reserved can only be deleted by the
70
+ # reserving connection and thus cannot be deleted via this method. As such,
71
+ # care may need to be taken to ensure that jobs are not left in a reserved
72
+ # state.
73
+ #
74
+ # Returns true if all encountered jobs were deleted successfully. Returns
75
+ # false if any of the jobs enumerated could not be deleted.
76
+ def self.reset!(tube_name = nil)
77
+ partial_failure = false
78
+ strategy.jobs.each do |job|
79
+ success = strategy.delete_job(job) if tube_name.nil? || strategy.job_matches?(job, :tube => tube_name)
80
+ partial_failure ||= success
81
+ end
82
+ return !partial_failure
83
+ end
84
+
85
+
86
+ # Returns a list of known subclasses of BeanCounter::Strategy.
87
+ # Typically this list represents the strategies available for interacting
88
+ # with beanstalkd.
89
+ def self.strategies
90
+ return BeanCounter::Strategy.strategies
91
+ end
92
+
93
+
94
+ # Sets the strategy that BeanCounter should use when interacting with
95
+ # beanstalkd. The value provided for +strategy_identifier+ will be used to
96
+ # materialize an instance of the matching strategy class. If the provided
97
+ # +strategy_identifier+ is nil, any existing strategy will be cleared and
98
+ # the next call to BeanCounter::strategy will use the default strategy.
99
+ def self.strategy=(strategy_identifier)
100
+ if strategy_identifier.nil?
101
+ @strategy = nil
102
+ else
103
+ @strategy = BeanCounter::Strategy.materialize_strategy(strategy_identifier).new
104
+ end
105
+ end
106
+
107
+
108
+ # Returns a previously materialized strategy if one exists. If no previous
109
+ # strategy exists, a new instance of the default strategy is instantiated
110
+ # and returned.
111
+ def self.strategy
112
+ return @strategy ||= default_strategy.new
113
+ end
114
+
115
+ end
@@ -0,0 +1,130 @@
1
+ class BeanCounter::EnqueuedExpectation
2
+
3
+ extend Forwardable
4
+
5
+ def_delegators BeanCounter, :strategy
6
+
7
+ # The value that the expectation expects
8
+ attr_reader :expected
9
+
10
+ # The number of matching jobs the expectation expects
11
+ attr_reader :expected_count
12
+
13
+ # The jobs found by the expecation during matching
14
+ attr_reader :found
15
+
16
+
17
+ # Iterates over the provided collection searching for jobs matching the
18
+ # Hash of expected options provided at instantiation.
19
+ def collection_matcher(collection)
20
+ @found = collection.send(expected_count? ? :select : :detect) do |job|
21
+ strategy.job_matches?(job, expected)
22
+ end
23
+
24
+ @found = [@found] unless expected_count? || @found.nil?
25
+
26
+ expected_count? ? expected_count === found.to_a.length : !found.nil?
27
+ end
28
+
29
+
30
+ # Returns a Boolean indicating whether a specific number of jobs are expected.
31
+ def expected_count?
32
+ return !!expected_count
33
+ end
34
+
35
+
36
+ # Builds the failure message used in the event of a positive expectation
37
+ # failure
38
+ def failure_message
39
+ if found.nil?
40
+ found_count = 'none'
41
+ found_string = nil
42
+ else
43
+ found_count = "#{found.length}:"
44
+ found_string = found.map {|job| strategy.pretty_print_job(job) }.join("\n")
45
+ end
46
+ [
47
+ "expected #{expected_count || 'any number of'} jobs matching #{expected.to_s},",
48
+ "found #{found_count}",
49
+ found_string,
50
+ ].compact.join(' ')
51
+ end
52
+
53
+
54
+ # Create a new enqueued expectation. Uses the given +expected+ Hash to determine
55
+ # if any jobs are enqueued that match the expected options.
56
+ #
57
+ # Each _key_ in +expected+ is a String or a Symbol that identifies an attribute
58
+ # of a job that the corresponding _value_ should be compared against. All attribute
59
+ # comparisons are performed using the triple equal (===) operator/method of
60
+ # the given _value_.
61
+ #
62
+ # +expected+ may additionally include a _count_ key of 'count' or :count that
63
+ # can be used to specify that a particular number of matching jobs are found.
64
+ #
65
+ # See BeanCounter::TestAssertions and/or BeanCounter::SpecMatchers for more information.
66
+ def initialize(expected)
67
+ @expected = expected
68
+ @expected_count = [expected.delete(:count), expected.delete('count')].compact.first
69
+ end
70
+
71
+
72
+ # Checks the beanstalkd pool for jobs matching the Hash of expected options
73
+ # provided at instantiation.
74
+ #
75
+ # If no _count_ option is provided, the expectation succeeds if any job is found
76
+ # that matches all of the expected options. If no jobs are found that match the
77
+ # expected options, the expecation fails.
78
+ #
79
+ # If a _count_ option is provided the expectation only succeeds if the triple equal
80
+ # (===) operator/method of the value of _count_ evaluates to true when given the
81
+ # total number of matching jobs. Otherwise the expecation fails. The use of ===
82
+ # allows for more advanced comparisons using Procs, Ranges, Regexps, etc.
83
+ #
84
+ # See Strategy#job_matches? and/or the #job_matches? method of the strategy
85
+ # in use for more detailed information on how it is determined whether or not
86
+ # a job matches the options expected.
87
+ #
88
+ # See also BeanCounter::TestAssertions and/or BeanCounter::SpecMatchers for additional
89
+ # information.
90
+ def matches?(given = nil)
91
+ if given.kind_of?(Proc)
92
+ return proc_matcher(given)
93
+ else
94
+ return collection_matcher(strategy.jobs)
95
+ end
96
+ end
97
+
98
+
99
+ # Builds the failure message used in the event of a negative expectation
100
+ # failure
101
+ def negative_failure_message
102
+ return '' if found.nil? || found == []
103
+
104
+ found_count = found.length
105
+ found_string = found.map {|job| strategy.pretty_print_job(job) }.join("\n")
106
+ if expected_count?
107
+ job_count = expected_count
108
+ job_word = expected_count == 1 ? 'job' : 'jobs'
109
+ else
110
+ job_count = 'any'
111
+ job_word = 'jobs'
112
+ end
113
+ return [
114
+ "did not expect #{job_count} #{job_word} matching #{expected.to_s},",
115
+ "found #{found_count}:",
116
+ found_string,
117
+ ].join(' ')
118
+ end
119
+
120
+
121
+ # Monitors the beanstalkd pool for new jobs enqueued during the provided
122
+ # block than passes any collected jobs to the collection matcher to determine
123
+ # if any jobs were enqueued that match the expected options provided at
124
+ # instantiation
125
+ def proc_matcher(block)
126
+ new_jobs = strategy.collect_new_jobs(&block)
127
+ collection_matcher(new_jobs)
128
+ end
129
+
130
+ end
@@ -0,0 +1,3 @@
1
+ require 'bean_counter/test_assertions'
2
+
3
+ MiniTest::Unit::TestCase.send(:include, BeanCounter::TestAssertions)
@@ -0,0 +1,5 @@
1
+ require 'bean_counter/spec_matchers'
2
+
3
+ if defined?(RSpec)
4
+ RSpec.configuration.include(BeanCounter::SpecMatchers)
5
+ end
@@ -0,0 +1,25 @@
1
+ module BeanCounter::SpecMatchers
2
+
3
+ # Creates a new BeanCounter::EnqueuedExpectation with +expected+ stored for
4
+ # later use when matching. Most of the time the value provided for +expected+
5
+ # will be ignored, the only exception is when +expected+ is given a block.
6
+ # When a block is provided for +expected+, only jobs enqueued during the
7
+ # execution of the block will be considered when matching.
8
+ #
9
+ # See BeanCounter::EnqueuedExpectation for additional information and usage
10
+ # patterns.
11
+ def have_enqueued(expected)
12
+ BeanCounter::EnqueuedExpectation.new(expected)
13
+ end
14
+
15
+ # Creates a new BeanCounter::TubeExpectation with +expected+ stored for
16
+ # later use when matching. However, +expected+ is never used when matching.
17
+ # Instead, all tubes are matched against until a match is found.
18
+ #
19
+ # See BeanCounter::TubeExpectation for additional information and usage
20
+ # patterns.
21
+ def have_tube(expected)
22
+ BeanCounter::TubeExpectation.new(expected)
23
+ end
24
+
25
+ end
@@ -0,0 +1,150 @@
1
+ require 'stalk_climber'
2
+
3
+ class BeanCounter::Strategy::StalkClimberStrategy < BeanCounter::Strategy
4
+
5
+ extend Forwardable
6
+
7
+ # Index of what method should be called to retrieve each stat
8
+ STATS_METHOD_NAMES = begin
9
+ attrs = (
10
+ BeanCounter::Strategy::MATCHABLE_JOB_ATTRIBUTES +
11
+ BeanCounter::Strategy::MATCHABLE_TUBE_ATTRIBUTES
12
+ ).map!(&:to_sym).uniq.sort
13
+ method_names = attrs.map {|method| method.to_s.gsub(/-/, '_').to_sym }
14
+ attr_methods = Hash[attrs.zip(method_names)]
15
+ attr_methods[:pause] = :pause_time
16
+ attr_methods
17
+ end
18
+
19
+ # Default tube used by StalkClimber when probing the beanstalkd pool
20
+ TEST_TUBE = 'bean_counter_stalk_climber_test'
21
+
22
+ # The tube that will be used by StalkClimber when probing the beanstalkd pool.
23
+ # Uses TEST_TUBE if no value provided.
24
+ attr_writer :test_tube
25
+
26
+ def_delegators :climber, :jobs, :tubes
27
+
28
+
29
+ # :call-seq:
30
+ # collect_new_jobs { block } => Array[StalkClimber::Job]
31
+ #
32
+ # Collects all jobs enqueued during the execution of the provided +block+.
33
+ # Returns an Array of StalkClimber::Job.
34
+ #
35
+ # Fulfills Strategy#collect_new_jobs contract. See Strategy#collect_new_jobs
36
+ # for more information.
37
+ def collect_new_jobs
38
+ raise ArgumentError, 'Block required' unless block_given?
39
+
40
+ min_ids = climber.max_job_ids
41
+ yield
42
+ max_ids = climber.max_job_ids
43
+ new_jobs = []
44
+ min_ids.each do |connection, min_id|
45
+ testable_ids = (min_id..max_ids[connection]).to_a
46
+ new_jobs.concat(connection.fetch_jobs(testable_ids).compact)
47
+ end
48
+ return new_jobs
49
+ end
50
+
51
+
52
+ # :call-seq:
53
+ # delete_job(job) => Boolean
54
+ #
55
+ # Attempts to delete the given StalkClimber::Job +job+. Returns true if
56
+ # deletion succeeds or if +job+ does not exist. Returns false if +job+ could
57
+ # not be deleted (typically due to it being reserved by another connection).
58
+ #
59
+ # Fulfills Strategy#delete_job contract. See Strategy#delete_job for more
60
+ # information.
61
+ def delete_job(job)
62
+ job.delete
63
+ return true
64
+ rescue Beaneater::NotFoundError
65
+ return job.exists? ? false : true
66
+ end
67
+
68
+
69
+ # :call-seq:
70
+ # job_matches?(job, options => {Symbol,String => Numeric,Proc,Range,Regexp,String}) => Boolean
71
+ #
72
+ # Returns a boolean indicating whether or not the provided StalkClimber::Job
73
+ # +job+ matches the given Hash of +options.
74
+ #
75
+ # Fulfills Strategy#job_matches? contract. See Strategy#job_matches? for more
76
+ # information.
77
+ def job_matches?(job, opts = {})
78
+ return matcher(MATCHABLE_JOB_ATTRIBUTES, job, opts)
79
+ end
80
+
81
+
82
+ # :call-seq:
83
+ # pretty_print_job(job) => String
84
+ #
85
+ # Returns a String representation of the StalkClimber::Job +job+ in a pretty,
86
+ # human readable format.
87
+ #
88
+ # Fulfills Strategy#pretty_print_job contract. See Strategy#pretty_print_job
89
+ # for more information.
90
+ def pretty_print_job(job)
91
+ return job.to_h.to_s
92
+ end
93
+
94
+
95
+ # :call-seq:
96
+ # pretty_print_tube(tube) => String
97
+ #
98
+ # Returns a String representation of +tube+ in a pretty, human readable format.
99
+ #
100
+ # Fulfills Strategy#pretty_print_tube contract. See Strategy#pretty_print_tube
101
+ # for more information.
102
+ def pretty_print_tube(tube)
103
+ return tube.to_h.to_s
104
+ end
105
+
106
+
107
+ # :call-seq:
108
+ # tube_matches?(tube, options => {Symbol,String => Numeric,Proc,Range,Regexp,String}) => Boolean
109
+ #
110
+ # Returns a boolean indicating whether or not the provided StalkClimber +tube+
111
+ # matches the given Hash of +options.
112
+ #
113
+ # Fulfills Strategy#tube_matches? contract. See Strategy#tube_matches? for
114
+ # more information.
115
+ def tube_matches?(tube, opts = {})
116
+ return matcher(MATCHABLE_TUBE_ATTRIBUTES, tube, opts)
117
+ end
118
+
119
+ private
120
+
121
+ # StalkClimber instance used to climb/crawl beanstalkd pool
122
+ def climber
123
+ return @climber ||= StalkClimber::Climber.new(BeanCounter.beanstalkd_url, test_tube)
124
+ end
125
+
126
+
127
+ # Given the set of valid attributes, +valid_attributes+, determines if every
128
+ # _value_ of +opts+ evaluates to true when compared to the attribute of
129
+ # +matchable+ identified by the corresponding +opts+ _key_.
130
+ def matcher(valid_attributes, matchable, opts = {})
131
+ # Refresh state/stats before checking match
132
+ return false unless matchable.exists?
133
+ return (opts.keys & valid_attributes).all? do |key|
134
+ opts[key] === matchable.send(stats_method_name(key))
135
+ end
136
+ end
137
+
138
+
139
+ # Simplify lookup of what method to call to retrieve requested stat
140
+ def stats_method_name(stats_attr)
141
+ return STATS_METHOD_NAMES[stats_attr.to_sym]
142
+ end
143
+
144
+
145
+ # Accessor for test_tube that defaults to TEST_TUBE
146
+ def test_tube
147
+ return @test_tube ||= TEST_TUBE
148
+ end
149
+
150
+ end
@@ -0,0 +1,250 @@
1
+ class BeanCounter::Strategy
2
+
3
+ # Available job attributes. These attributes can be used by strategies
4
+ # to validate what attributes are used for matching jobs.
5
+ MATCHABLE_JOB_ATTRIBUTES = begin
6
+ attrs = [
7
+ :age, :body, :buries, :connection, :delay, :id, :kicks, :pri, :releases,
8
+ :reserves, :state, :'time-left', :timeouts, :ttr, :tube,
9
+ ]
10
+ attrs.concat(attrs.map(&:to_s))
11
+ end
12
+
13
+ # Available tube attributes. These attributes can be used by strategies
14
+ # to validate what attributes are used for matching tubes.
15
+ MATCHABLE_TUBE_ATTRIBUTES = begin
16
+ attrs = [
17
+ :'cmd-delete', :'cmd-pause-tube', :'current-jobs-buried',
18
+ :'current-jobs-delayed', :'current-jobs-ready', :'current-jobs-reserved',
19
+ :'current-jobs-urgent', :'current-using', :'current-waiting',
20
+ :'current-watching', :name, :pause, :'pause-time-left', :'total-jobs',
21
+ ]
22
+ attrs.concat(attrs.map(&:to_s))
23
+ end
24
+
25
+ @@strategies = {}
26
+
27
+
28
+ # Maintain an index of classes known to subclass Strategy.
29
+ def self.inherited(subclass)
30
+ identifier = subclass.name || subclass.to_s[8, subclass.to_s.length - 9]
31
+ @@strategies[identifier.to_sym] = subclass
32
+ end
33
+
34
+
35
+ # :call-seq:
36
+ # known_strategy?(strategy_identifier) => Boolean
37
+ #
38
+ # Determines if the provided +strategy_identifer+ corresponds to a known
39
+ # subclass of strategy. The provided +strategy_identifer+ can be a class
40
+ # or any object that responds to :to_sym. Classes are compared directly.
41
+ # For non-class objects that respond to :to_sym, the symbolized form
42
+ # of +strategy_identifer+ is used as a key to attempt to retrieve a strategy
43
+ # from the strategies Hash.
44
+ #
45
+ # Returns true if +strategy_identifier+ isa known strategy or maps to a known
46
+ # strategy. Otherwise, false is returned.
47
+ #
48
+ # BeanCounter::Strategy.known_strategy?(Object)
49
+ # #=> false
50
+ #
51
+ # BeanCounter::Strategy.known_strategy?(BeanCounter::Strategy)
52
+ # #=> true
53
+ def self.known_strategy?(strategy_identifier)
54
+ return true if strategy_identifier.is_a?(Class) &&
55
+ strategy_identifier <= BeanCounter::Strategy
56
+ return true if strategy_identifier.respond_to?(:to_sym) &&
57
+ strategies.key?(strategy_identifier.to_sym)
58
+ return false
59
+ end
60
+
61
+
62
+ # :call-seq:
63
+ # materialize_strategy(strategy_identifier) => subclass of Strategy
64
+ #
65
+ # Materialize the provided +strategy_identifier+ into a subclass of Strategy.
66
+ # If +strategy_identifer+ is already a subclass of Strategy,
67
+ # +strategy_identifier+ is returned. Otherwise, +strategy_identifer+ is
68
+ # converted into a Symbol and is used as a key to retrieve a strategy from
69
+ # the known subclasses of Strategy. If +strategy_identifier does not map to
70
+ # a known subclass of Strategy, an ArgumentError is raised.
71
+ #
72
+ # BeanCounter::Strategy.materialize_strategy(:'BeanCounter::Strategy::StalkClimberStrategy')
73
+ # #=> BeanCounter::Strategy::StalkClimberStrategy
74
+ def self.materialize_strategy(strategy_identifier)
75
+ unless BeanCounter::Strategy.known_strategy?(strategy_identifier)
76
+ raise(
77
+ ArgumentError,
78
+ "Could not find #{strategy_identifier} among known strategies: #{strategies.keys.to_s}"
79
+ )
80
+ end
81
+ return strategy_identifier.is_a?(Class) ? strategy_identifier : strategies[strategy_identifier.to_sym]
82
+ end
83
+
84
+
85
+ # :call-seq:
86
+ # strategies() => Hash
87
+ #
88
+ # Returns a list of known classes that inherit from BeanCounter::Strategy.
89
+ # Typically this list represents the strategies available for interacting
90
+ # with beanstalkd.
91
+ def self.strategies
92
+ return @@strategies.dup
93
+ end
94
+
95
+
96
+ # :call-seq:
97
+ # collect_new_jobs { block } => Array[Strategy Job]
98
+ #
99
+ # Provide a means of collecting jobs enqueued during the execution of the
100
+ # provided +block+. Returns an Array of Jobs as implemented by the Strategy.
101
+ #
102
+ # Used internally to reduce the set of jobs that must be examined to evaluate
103
+ # the truth of an assertion to only those enqueued during the evaluation of
104
+ # the given +block+.
105
+ #
106
+ # new_jobs = strategy.collect_new_jobs do
107
+ # ...
108
+ # end
109
+ # #=> [job_enqueued_during_block, job_enqueued_during_block]
110
+ def collect_new_jobs
111
+ raise NotImplementedError
112
+ end
113
+
114
+
115
+ # :call-seq:
116
+ # delete_job(job) => Boolean
117
+ #
118
+ # Provide a means for deleting a job specific to the job interface used by
119
+ # the strategy. Should return true if the job was deleted successfully or
120
+ # no longer exists and false if the job could not be deleted.
121
+ #
122
+ # Used internally to delete a job, allowing the beanstalkd pool to be reset.
123
+ #
124
+ # strategy.delete_job(job)
125
+ # #=> true
126
+ def delete_job
127
+ raise NotImplementedError
128
+ end
129
+
130
+
131
+ # :call-seq:
132
+ # job_matches?(job, options => {Symbol,String => Numeric,Proc,Range,Regexp,String}) => Boolean
133
+ #
134
+ # Returns a boolean indicating whether or not the provided +job+ matches the
135
+ # given Hash of +options. Each _key_ in +options+ is a String or a Symbol that
136
+ # identifies an attribute of +job+ that the corresponding _value_ should be
137
+ # compared against. True is returned if every _value_ in +options+ evaluates to
138
+ # true when compared to the attribute of +job+ identified by the corresponding
139
+ # _key_. False is returned if any of the comparisons evaluates to false.
140
+ #
141
+ # If no options are given, returns true for any job that exists at the time of
142
+ # evaluation.
143
+ #
144
+ # Each attribute comparison is performed using the triple equal (===)
145
+ # operator/method of _value_ with the attribute of +job+ identified by _key_
146
+ # passed into the method. Use of === allows for more complex comparisons
147
+ # using Procs, Ranges, Regexps, etc.
148
+ #
149
+ # Consult MATCHABLE_JOB_ATTRIBUTES for a list of which attributes of +job+
150
+ # can be matched against.
151
+ #
152
+ # Used internally to evaluate if a job matches an assertion.
153
+ #
154
+ # strategy.job_matches?(reserved_job, :state => 'reserved')
155
+ # #=> true
156
+ #
157
+ # strategy.job_matches(small_job, :body => lambda {|body| body.length > 50 })
158
+ # #=> false
159
+ #
160
+ # strategy.job_matches(unreliable_job, :buries => 6..100)
161
+ # #=> true
162
+ def job_matches?
163
+ raise NotImplementedError
164
+ end
165
+
166
+
167
+ # :call-seq:
168
+ # jobs() => Enumerator
169
+ #
170
+ # Returns an Enumerator providing a means to enumerate all jobs in the beanstalkd
171
+ # pool.
172
+ #
173
+ # Used internally to enumerate all jobs to find jobs matching an assertion.
174
+ def jobs
175
+ raise NotImplementedError
176
+ end
177
+
178
+
179
+ # :call-seq:
180
+ # pretty_print_job(job) => String
181
+ #
182
+ # Returns a String representation of +job+ in a pretty, human readable
183
+ # format.
184
+ #
185
+ # Used internally to print a job when an assertion fails.
186
+ def pretty_print_job
187
+ raise NotImplementedError
188
+ end
189
+
190
+
191
+ # :call-seq:
192
+ # pretty_print_tube(tube) => String
193
+ #
194
+ # Returns a String representation of the tube in a pretty, human readable
195
+ # format. Used internally to print a tube when an assertion fails.
196
+ #
197
+ # Used internally to print a tube when an assertion fails.
198
+ def pretty_print_tube
199
+ raise NotImplementedError
200
+ end
201
+
202
+
203
+ # :call-seq:
204
+ # tube_matches?(tube, options => {Symbol,String => Numeric,Proc,Range,Regexp,String}) => Boolean
205
+ #
206
+ # Returns a boolean indicating whether or not the provided +tube+ matches the
207
+ # given Hash of +options. Each _key_ in +options+ is a String or a Symbol that
208
+ # identifies an attribute of +tube+ that the corresponding _value_ should be
209
+ # compared against. True is returned if every _value_ in +options+ evaluates to
210
+ # true when compared to the attribute of +tube+ identified by the corresponding
211
+ # _key_. False is returned if any of the comparisons evaluates to false.
212
+ #
213
+ # If no options are given, returns true for any tube that exists at the time of
214
+ # evaluation.
215
+ #
216
+ # Each attribute comparison is performed using the triple equal (===)
217
+ # operator/method of _value_ with the attribute of +job+ identified by _key_
218
+ # passed into the method. Use of === allows for more complex comparisons using
219
+ # Procs, Ranges, Regexps, etc.
220
+ #
221
+ # Consult MATCHABLE_TUBE_ATTRIBUTES for a list of which attributes of +tube+
222
+ # can be matched against.
223
+ #
224
+ # Used internally to evaluate if a tube matches an assertion.
225
+ #
226
+ # strategy.tube_matches?(paused_tube, :state => 'paused')
227
+ # #=> true
228
+ #
229
+ # strategy.tube_matches(test_tube, :name => /test/)
230
+ # #=> true
231
+ #
232
+ # strategy.tube_matches(backed_up_tube, 'current-jobs-ready' => 50..100)
233
+ # #=> true
234
+ def tube_matches?
235
+ raise NotImplementedError
236
+ end
237
+
238
+
239
+ # :call-seq:
240
+ # tubes() => Enumerator
241
+ #
242
+ # Returns an Enumerator providing a means to enumerate all tubes in the beanstalkd
243
+ # pool.
244
+ #
245
+ # Used internally to enumerate all tubes to find tubes matching an assertion.
246
+ def tubes
247
+ raise NotImplementedError
248
+ end
249
+
250
+ end