shoulda-whenever 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: b556da7fd43cfccee5935c3c6a63eb2fd51ec05b
4
+ data.tar.gz: e57ef2772b14aa2ea0b04ea4ad1ae5c34ef48d5e
5
+ SHA512:
6
+ metadata.gz: fed62e52acf39bd842e32adcf34192b7a431edd89bdf938dd3b0f24617eb7e77c48f87f12f075a883d5b866728a895a17a1aa27526b40262f20dbf23ac65e9af
7
+ data.tar.gz: 8a59abf46d0c53c03c24609c1fca40458a9ee444d9b9f69c4ded72cccff07e7153713c8e36b58f7e55472e2c22f104da1be2192c9895435f78be30deba286301
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ bin/
2
+ vendor/
3
+ .bundle
4
+ .rspec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rspec", "~> 3.3.0"
4
+ gem "whenever", "~> 0.9.4"
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ chronic (0.10.2)
5
+ diff-lcs (1.2.5)
6
+ rspec (3.3.0)
7
+ rspec-core (~> 3.3.0)
8
+ rspec-expectations (~> 3.3.0)
9
+ rspec-mocks (~> 3.3.0)
10
+ rspec-core (3.3.2)
11
+ rspec-support (~> 3.3.0)
12
+ rspec-expectations (3.3.1)
13
+ diff-lcs (>= 1.2.0, < 2.0)
14
+ rspec-support (~> 3.3.0)
15
+ rspec-mocks (3.3.2)
16
+ diff-lcs (>= 1.2.0, < 2.0)
17
+ rspec-support (~> 3.3.0)
18
+ rspec-support (3.3.0)
19
+ whenever (0.9.4)
20
+ chronic (>= 0.6.3)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ rspec (~> 3.3.0)
27
+ whenever (~> 0.9.4)
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # shoulda-whenever
2
+
3
+ This gem was born out of a desire to test the schedule for tasks being scheduled with Whenever. Not to test if Whenever can generate the proper CRON schedule, but to test whether I can generate the proper `config/schedule.rb`. It turns out I can't sometimes.
4
+
5
+ ## How to use this Gem
6
+
7
+ Add this to you gemfile:
8
+
9
+ ```ruby
10
+ gem "shoulda-whenever", "~> 0.0.1", "https://github.com/MGerrior/shoulda-whenever.git"
11
+ ```
12
+
13
+ Create a new schedule to be tested at `config/schedule.rb` (or anywhere really, but for the sake of the README, that's where it is):
14
+
15
+ ```ruby
16
+ every :friday, at: "12:00 PM" do
17
+ runner "Notifier.send_team_lunch_email"
18
+ end
19
+ ```
20
+
21
+ Create a new test file for testing your schedule, perhaps something like `spec/schedule_spec.rb`:
22
+
23
+ ```ruby
24
+ describe "Schedule" do
25
+ include Shoulda::Whenever
26
+
27
+ let(:whenever) { Whenever::JobList.new(file: File.join(Rails.root, "config", "schedule.rb").to_s) }
28
+
29
+ it "sends out the team lunch reminder email every friday at noon" do
30
+ expect(whenever).to schedule("Notifier.send_team_lunch_email").every(:friday).at("12:00 PM")
31
+ end
32
+ end
33
+ ```
@@ -0,0 +1,149 @@
1
+ module Shoulda
2
+ module Whenever
3
+ def schedule(task)
4
+ ScheduleMatcher.new(task)
5
+ end
6
+
7
+ alias_method :schedule_rake, :schedule
8
+ alias_method :schedule_runner, :schedule
9
+ alias_method :schedule_command, :schedule
10
+
11
+ class ScheduleMatcher
12
+ attr_reader :duration, :time, :task, :roles
13
+
14
+ def initialize(task)
15
+ @task = task
16
+ @duration = nil
17
+ @time = nil
18
+ @roles = nil
19
+ end
20
+
21
+ def matches?(subject)
22
+ jobs = subject.instance_variable_get("@jobs")
23
+
24
+ jobs = filter_jobs_by_duration(jobs)
25
+ jobs = filter_jobs_by_time(jobs)
26
+ jobs = filter_jobs_by_roles(jobs)
27
+ jobs = filter_jobs_by_task(jobs)
28
+
29
+ jobs.any?
30
+ end
31
+
32
+ def filter_jobs_by_duration(jobs)
33
+ if duration.nil?
34
+ jobs.values.flatten
35
+ else
36
+ duration_to_fetch = if duration.is_a?(String) || duration.is_a?(Symbol)
37
+ duration
38
+ else
39
+ duration.to_i
40
+ end
41
+
42
+ jobs.fetch(duration_to_fetch) { [] }
43
+ end
44
+ end
45
+
46
+ def filter_jobs_by_time(jobs)
47
+ return jobs if time.nil?
48
+
49
+ jobs.select { |job| job.at == time }
50
+ end
51
+
52
+ def filter_jobs_by_roles(jobs)
53
+ return jobs if roles.nil? || roles.empty?
54
+
55
+ jobs.select { |job| job.roles == roles }
56
+ end
57
+
58
+ def filter_jobs_by_task(jobs)
59
+ jobs.select do |job|
60
+ job.instance_variable_get("@options")[:task] == task
61
+ end
62
+ end
63
+
64
+ def every(duration)
65
+ @duration = duration
66
+
67
+ self
68
+ end
69
+
70
+ def at(time)
71
+ @time = time
72
+
73
+ self
74
+ end
75
+
76
+ def with_roles(roles)
77
+ @roles = Array(roles)
78
+
79
+ self
80
+ end
81
+ alias_method :with_role, :with_roles
82
+
83
+ def description
84
+ [
85
+ base_description,
86
+ duration_description,
87
+ time_description,
88
+ roles_description
89
+ ].compact.join(' ')
90
+ end
91
+
92
+ def failure_message
93
+ [
94
+ base_failure_message,
95
+ duration_description,
96
+ time_description,
97
+ roles_description
98
+ ].compact.join(' ')
99
+ end
100
+
101
+ def failure_message_when_negated
102
+ [
103
+ base_failure_message_when_negated,
104
+ duration_description,
105
+ time_description,
106
+ roles_description
107
+ ].compact.join(' ')
108
+ end
109
+
110
+ private
111
+
112
+ def base_description
113
+ "schedule \"#{ task }\""
114
+ end
115
+
116
+ def duration_description
117
+ unless duration.nil?
118
+ if duration.is_a?(String) || duration.is_a?(Symbol)
119
+ "every \"#{ duration }\""
120
+ else
121
+ "every #{ duration.to_i } seconds"
122
+ end
123
+ end
124
+ end
125
+
126
+ def time_description
127
+ unless time.nil?
128
+ "at \"#{ time }\""
129
+ end
130
+ end
131
+
132
+ def roles_description
133
+ unless roles.nil? || roles.empty?
134
+ role_names = roles.map { |role| "\"#{ role }\"" }.join(", ")
135
+
136
+ "with #{ role_names } role(s)"
137
+ end
138
+ end
139
+
140
+ def base_failure_message
141
+ "expected to schedule \"#{ task }\""
142
+ end
143
+
144
+ def base_failure_message_when_negated
145
+ "expected not to schedule \"#{ task }\""
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,5 @@
1
+ module Shoulda
2
+ module Whenever
3
+ VERSION = "0.0.1".freeze
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require "shoulda/whenever/schedule_matcher"
2
+
3
+ module Shoulda
4
+ module Whenever
5
+ end
6
+ end
data/lib/shoulda.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "shoulda/whenever"
2
+
3
+ module Shoulda
4
+ end
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), "lib")
2
+ require 'shoulda/whenever/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "shoulda-whenever"
6
+ s.version = Shoulda::Whenever::VERSION.dup
7
+ s.authors = ["Matthew Gerrior"]
8
+ s.date = Time.now.strftime("%Y-%m-%d")
9
+ s.email = "gerrior.matthew@gmail.com"
10
+ s.homepage = "http://rubygems.org/gems/shoulda-whenever"
11
+ s.summary = "Shoulda style matchers for whenever gem"
12
+ s.license = "MIT"
13
+ s.description = "This gem is designed to make it easier to test that the schedule you built with the 'whenever' gem is accurate."
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.require_paths = ["lib"]
18
+
19
+ s.required_ruby_version = '>= 1.9.3'
20
+
21
+ s.add_development_dependency "rspec", "~> 3.3.0"
22
+ s.add_development_dependency "whenever", "~> 0.9.4"
23
+ end
@@ -0,0 +1,228 @@
1
+ require "spec_helper"
2
+ require "whenever"
3
+ require "shoulda/whenever/schedule_matcher"
4
+ require "rspec/matchers/fail_matchers"
5
+
6
+ describe Shoulda::Whenever::ScheduleMatcher do
7
+ include Shoulda::Whenever
8
+ include RSpec::Matchers::FailMatchers
9
+
10
+ let(:whenever) { Whenever::JobList.new(string: schedule_string) }
11
+
12
+ describe "#description" do
13
+ context "basic schedule check" do
14
+ it "includes the task being scheduled" do
15
+ expect(described_class.new("rake:every:10:minutes").description).to eq("schedule \"rake:every:10:minutes\"")
16
+ end
17
+ end
18
+
19
+ context "with a duration" do
20
+ it "includes the duration at which the task is being scheduled" do
21
+ expect(
22
+ described_class.new("rake:every:10:minutes")
23
+ .every(Whenever::NumericSeconds.seconds(10, "minutes"))
24
+ .description
25
+ ).to eq("schedule \"rake:every:10:minutes\" every 600 seconds")
26
+ end
27
+ end
28
+
29
+ context "with a time to run" do
30
+ it "includes the time at which the task is scheduled to run" do
31
+ expect(
32
+ described_class.new("rake:every:10:minutes")
33
+ .at("12:00 PM")
34
+ .description
35
+ ).to eq("schedule \"rake:every:10:minutes\" at \"12:00 PM\"")
36
+ end
37
+ end
38
+
39
+ context "with a cron schedule" do
40
+ it "includes the schedule" do
41
+ expect(
42
+ described_class.new("rake:every:1:day:at:noon")
43
+ .every("0 0 27-31 * *")
44
+ .description
45
+ ).to eq("schedule \"rake:every:1:day:at:noon\" every \"0 0 27-31 * *\"")
46
+ end
47
+ end
48
+
49
+ context "with a symbol schedule" do
50
+ it "includes the schedule" do
51
+ expect(
52
+ described_class.new("rake:every:1:day:at:noon")
53
+ .every(:friday)
54
+ .description
55
+ ).to eq("schedule \"rake:every:1:day:at:noon\" every \"friday\"")
56
+ end
57
+ end
58
+
59
+ context "with a role" do
60
+ it "includes the role" do
61
+ expect(
62
+ described_class.new("rake:every:day").with_role(:app).description
63
+ ).to eq("schedule \"rake:every:day\" with \"app\" role(s)")
64
+ end
65
+ end
66
+
67
+ context "with multiple roles" do
68
+ it "includes the roles" do
69
+ expect(
70
+ described_class.new("rake:every:day").with_roles([:app, :database, :redis]).description
71
+ ).to eq("schedule \"rake:every:day\" with \"app\", \"database\", \"redis\" role(s)")
72
+ end
73
+ end
74
+ end
75
+
76
+ context "a task that is not scheduled" do
77
+ let(:schedule_string) { "" }
78
+
79
+ it "passes" do
80
+ expect(whenever).not_to schedule("MyTask.run")
81
+ end
82
+
83
+ it "fails" do
84
+ expect {
85
+ expect(whenever).to schedule("MyTask.run")
86
+ }.to fail_with("expected to schedule \"MyTask.run\"")
87
+ end
88
+ end
89
+
90
+ context "a task that is scheduled" do
91
+ let(:schedule_string) do
92
+ <<-SCHEDULE
93
+ every 3.hours do
94
+ rake "rake:every:3:hours"
95
+ end
96
+ SCHEDULE
97
+ end
98
+
99
+ it "passes" do
100
+ expect(whenever).to schedule("rake:every:3:hours")
101
+ end
102
+
103
+ it "fails" do
104
+ expect {
105
+ expect(whenever).not_to schedule("rake:every:3:hours")
106
+ }.to fail_with("expected not to schedule \"rake:every:3:hours\"")
107
+ end
108
+ end
109
+
110
+ context "a task that is scheduled after a certain duration" do
111
+ let(:schedule_string) do
112
+ <<-SCHEDULE
113
+ every 3.hours do
114
+ rake "rake:every:3:hours"
115
+ end
116
+ SCHEDULE
117
+ end
118
+
119
+ it "passes" do
120
+ expect(whenever).to schedule("rake:every:3:hours").every(Whenever::NumericSeconds.seconds(3, "hours"))
121
+ end
122
+ it "fails" do
123
+ expect {
124
+ expect(whenever).not_to schedule("rake:every:3:hours").every(Whenever::NumericSeconds.seconds(3, "hours"))
125
+ }.to fail_with("expected not to schedule \"rake:every:3:hours\" every 10800 seconds")
126
+ end
127
+ end
128
+
129
+ context "a task that is scheduled to run at a certain time" do
130
+ let(:schedule_string) do
131
+ <<-SCHEDULE
132
+ every 1.day, at: "12:00 PM" do
133
+ rake "rake:every:day:at:noon"
134
+ end
135
+ SCHEDULE
136
+ end
137
+
138
+ it "passes" do
139
+ expect(whenever).to schedule("rake:every:day:at:noon").every(Whenever::NumericSeconds.seconds(1, "day")).at("12:00 PM")
140
+ end
141
+
142
+ it "fails" do
143
+ expect {
144
+ expect(whenever).not_to schedule("rake:every:day:at:noon").every(Whenever::NumericSeconds.seconds(1, "day")).at("12:00 PM")
145
+ }.to fail_with("expected not to schedule \"rake:every:day:at:noon\" every 86400 seconds at \"12:00 PM\"")
146
+ end
147
+ end
148
+
149
+ context "a task that is scheduled for a certain day" do
150
+ let(:schedule_string) do
151
+ <<-SCHEDULE
152
+ every :friday do
153
+ rake "rake:every:friday"
154
+ end
155
+ SCHEDULE
156
+ end
157
+
158
+ it "passes" do
159
+ expect(whenever).to schedule("rake:every:friday").every(:friday)
160
+ end
161
+
162
+ it "fails" do
163
+ expect {
164
+ expect(whenever).not_to schedule("rake:every:friday").every(:friday)
165
+ }.to fail_with("expected not to schedule \"rake:every:friday\" every \"friday\"")
166
+ end
167
+ end
168
+
169
+ context "a task that is scheduled with cron syntax" do
170
+ let(:schedule_string) do
171
+ <<-SCHEDULE
172
+ every '0 0 27-31 * *' do
173
+ rake "rake:end:of:month"
174
+ end
175
+ SCHEDULE
176
+ end
177
+
178
+ it "passes" do
179
+ expect(whenever).to schedule("rake:end:of:month").every("0 0 27-31 * *")
180
+ end
181
+
182
+ it "fails" do
183
+ expect {
184
+ expect(whenever).not_to schedule("rake:end:of:month").every("0 0 27-31 * *")
185
+ }.to fail_with("expected not to schedule \"rake:end:of:month\" every \"0 0 27-31 * *\"")
186
+ end
187
+ end
188
+
189
+ context "a task that is scheduled for a certain role" do
190
+ let(:schedule_string) do
191
+ <<-SCHEDULE
192
+ every 10.minutes, roles: [:app] do
193
+ rake "rake:every:10:minutes"
194
+ end
195
+ SCHEDULE
196
+ end
197
+
198
+ it "passes" do
199
+ expect(whenever).to schedule("rake:every:10:minutes").with_role(:app)
200
+ end
201
+
202
+ it "fails" do
203
+ expect {
204
+ expect(whenever).not_to schedule("rake:every:10:minutes").with_role(:app)
205
+ }.to fail_with("expected not to schedule \"rake:every:10:minutes\" with \"app\" role(s)")
206
+ end
207
+ end
208
+
209
+ context "a task that is scheduled for multiple roles" do
210
+ let(:schedule_string) do
211
+ <<-SCHEDULE
212
+ every 10.minutes, roles: [:app, :database] do
213
+ rake "rake:every:10:minutes"
214
+ end
215
+ SCHEDULE
216
+ end
217
+
218
+ it "passes" do
219
+ expect(whenever).to schedule("rake:every:10:minutes").with_roles([:app, :database])
220
+ end
221
+
222
+ it "fails" do
223
+ expect {
224
+ expect(whenever).not_to schedule("rake:every:10:minutes").with_roles([:app, :database])
225
+ }.to fail_with("expected not to schedule \"rake:every:10:minutes\" with \"app\", \"database\" role(s)")
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,78 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, make a
10
+ # separate helper file that requires this one and then use it only in the specs
11
+ # that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+ RSpec.configure do |config|
18
+ # The settings below are suggested to provide a good initial experience
19
+ # with RSpec, but feel free to customize to your heart's content.
20
+ =begin
21
+ # These two settings work together to allow you to limit a spec run
22
+ # to individual examples or groups you care about by tagging them with
23
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
24
+ # get run.
25
+ config.filter_run :focus
26
+ config.run_all_when_everything_filtered = true
27
+
28
+ # Many RSpec users commonly either run the entire suite or an individual
29
+ # file, and it's useful to allow more verbose output when running an
30
+ # individual spec file.
31
+ if config.files_to_run.one?
32
+ # Use the documentation formatter for detailed output,
33
+ # unless a formatter has already been configured
34
+ # (e.g. via a command-line flag).
35
+ config.default_formatter = 'doc'
36
+ end
37
+
38
+ # Print the 10 slowest examples and example groups at the
39
+ # end of the spec run, to help surface which specs are running
40
+ # particularly slow.
41
+ config.profile_examples = 10
42
+
43
+ # Run specs in random order to surface order dependencies. If you find an
44
+ # order dependency and want to debug it, you can fix the order by providing
45
+ # the seed, which is printed after each run.
46
+ # --seed 1234
47
+ config.order = :random
48
+
49
+ # Seed global randomization in this process using the `--seed` CLI option.
50
+ # Setting this allows you to use `--seed` to deterministically reproduce
51
+ # test failures related to randomization by passing the same `--seed` value
52
+ # as the one that triggered the failure.
53
+ Kernel.srand config.seed
54
+
55
+ # rspec-expectations config goes here. You can use an alternate
56
+ # assertion/expectation library such as wrong or the stdlib/minitest
57
+ # assertions if you prefer.
58
+ config.expect_with :rspec do |expectations|
59
+ # Enable only the newer, non-monkey-patching expect syntax.
60
+ # For more details, see:
61
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
62
+ expectations.syntax = :expect
63
+ end
64
+
65
+ # rspec-mocks config goes here. You can use an alternate test double
66
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
67
+ config.mock_with :rspec do |mocks|
68
+ # Enable only the newer, non-monkey-patching expect syntax.
69
+ # For more details, see:
70
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
71
+ mocks.syntax = :expect
72
+
73
+ # Prevents you from mocking or stubbing a method that does not exist on
74
+ # a real object. This is generally recommended.
75
+ mocks.verify_partial_doubles = true
76
+ end
77
+ =end
78
+ end
@@ -0,0 +1,3 @@
1
+ every 3.hours do
2
+ rake "run:every:3:hours"
3
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shoulda-whenever
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Gerrior
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 3.3.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: whenever
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.4
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.4
41
+ description: This gem is designed to make it easier to test that the schedule you
42
+ built with the 'whenever' gem is accurate.
43
+ email: gerrior.matthew@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - Gemfile.lock
51
+ - README.md
52
+ - lib/shoulda.rb
53
+ - lib/shoulda/whenever.rb
54
+ - lib/shoulda/whenever/schedule_matcher.rb
55
+ - lib/shoulda/whenever/version.rb
56
+ - shoulda-whenever.gemspec
57
+ - spec/shoulda/whenever/schedule_matcher_spec.rb
58
+ - spec/spec_helper.rb
59
+ - spec/support/schedule.rb
60
+ homepage: http://rubygems.org/gems/shoulda-whenever
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.9.3
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.4.5
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Shoulda style matchers for whenever gem
84
+ test_files:
85
+ - spec/shoulda/whenever/schedule_matcher_spec.rb
86
+ - spec/spec_helper.rb
87
+ - spec/support/schedule.rb
88
+ has_rdoc: