chrono 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a6bc0e19633446a8b89579f6cbd93c75bfde77d
4
+ data.tar.gz: e4b5d84609564d00fc9f7a052a36a9911780c494
5
+ SHA512:
6
+ metadata.gz: c942eeb72f2817153a52a33b25d4a4eee2e51bf6d94f937366bfa319f0075f23b9787c2a6a1f74a9e128a7f2b71b9fc22b2a4fe70a840e01234645cfe5634706
7
+ data.tar.gz: af90e4f872ad91502de4e0aea4c62702437d720b22afd4350e2088dd5da36923f543f028db948e636659c3fafd8da96e33c5f2f2adb80343338845cb257fd140
data/.gitignore ADDED
@@ -0,0 +1,22 @@
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
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in chrono.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Ryo Nakamura
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,33 @@
1
+ # Chrono
2
+ Provides a chain of logics about chronology.
3
+
4
+ ## Chrono::Iterator
5
+ Parse cron syntax and determine next scheduled run.
6
+
7
+ ```ruby
8
+ require "chrono"
9
+
10
+ iterator = Chrono::Iterator.new("30 * * * *")
11
+ iterator.next #=> 2000-01-01 00:30:00
12
+ iterator.next #=> 2000-01-02 00:30:00
13
+ iterator.next #=> 2000-01-03 00:30:00
14
+ ```
15
+
16
+ The following syntax is supported.
17
+ See [examples](https://github.com/r7kamura/chrono/blob/master/spec/chrono/iterator_spec.rb)
18
+ for more details.
19
+
20
+ * (*) Asterisk
21
+ * (,) Comma
22
+ * (-) Hyphen
23
+ * (/) Slash
24
+
25
+ ```
26
+ * * * * *
27
+ T T T T T
28
+ | | | | `- wday --- 0 .. 6
29
+ | | | `--- month -- 1 .. 12
30
+ | | `----- day ---- 1 .. 31
31
+ | `------- hour --- 0 .. 23
32
+ `--------- minute - 0 .. 59
33
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/chrono.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "chrono/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "chrono"
7
+ spec.version = Chrono::VERSION
8
+ spec.authors = ["Ryo Nakamura"]
9
+ spec.email = ["r7kamura@gmail.com"]
10
+ spec.summary = "Provides a chain of logics about chronology."
11
+ spec.homepage = "https://github.com/r7kamura/chrono"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_dependency "activesupport"
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency "rspec", "2.14.1"
23
+ end
data/lib/chrono.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "chrono/fields/base"
2
+ require "chrono/fields/day"
3
+ require "chrono/fields/hour"
4
+ require "chrono/fields/minute"
5
+ require "chrono/fields/month"
6
+ require "chrono/fields/wday"
7
+ require "chrono/iterator"
8
+ require "chrono/next_time"
9
+ require "chrono/schedule"
10
+ require "chrono/version"
@@ -0,0 +1,69 @@
1
+ module Chrono
2
+ module Fields
3
+ class Base
4
+ attr_reader :source
5
+
6
+ def initialize(source)
7
+ @source = source
8
+ end
9
+
10
+ def to_a
11
+ if has_multiple_elements?
12
+ fields.map(&:to_a).flatten.uniq.sort
13
+ else
14
+ lower.step(upper, step).to_a.sort
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def range
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def interpolated
25
+ source.gsub("*", "#{range.first}-#{range.last}")
26
+ end
27
+
28
+ def lower
29
+ @lower ||= match_data[1].to_i
30
+ end
31
+
32
+ def upper
33
+ if match_data[2]
34
+ match_data[2].to_i
35
+ else
36
+ lower
37
+ end
38
+ end
39
+
40
+ def step
41
+ if match_data[3]
42
+ match_data[3].to_i
43
+ else
44
+ 1
45
+ end
46
+ end
47
+
48
+ def pattern
49
+ %r<\A(\d+)(?:-(\d+))?(?:/(\d+))?\z>
50
+ end
51
+
52
+ def match_data
53
+ @match_data ||= interpolated.match(pattern)
54
+ end
55
+
56
+ def elements
57
+ @elements ||= source.split(",")
58
+ end
59
+
60
+ def has_multiple_elements?
61
+ elements.size >= 2
62
+ end
63
+
64
+ def fields
65
+ elements.map {|element| self.class.new(element) }
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,11 @@
1
+ module Chrono
2
+ module Fields
3
+ class Day < Base
4
+ private
5
+
6
+ def range
7
+ 1..31
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Chrono
2
+ module Fields
3
+ class Hour < Base
4
+ private
5
+
6
+ def range
7
+ 0..23
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Chrono
2
+ module Fields
3
+ class Minute < Base
4
+ private
5
+
6
+ def range
7
+ 0..59
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Chrono
2
+ module Fields
3
+ class Month < Base
4
+ private
5
+
6
+ def range
7
+ 1..12
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Chrono
2
+ module Fields
3
+ class Wday < Base
4
+ private
5
+
6
+ def range
7
+ 0..6
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Chrono
2
+ class Iterator
3
+ attr_accessor :now
4
+
5
+ attr_reader :source
6
+
7
+ def initialize(source, options = {})
8
+ @source = source
9
+ @now = options[:now] || Time.now
10
+ end
11
+
12
+ def next
13
+ self.now = NextTime.new(now: now, source: source).to_time
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,89 @@
1
+ require "active_support/core_ext/date"
2
+ require "active_support/core_ext/time"
3
+ require "active_support/core_ext/numeric/time"
4
+
5
+ module Chrono
6
+ class NextTime
7
+ attr_reader :now, :source
8
+
9
+ attr_writer :time
10
+
11
+ def initialize(options)
12
+ @now = options[:now]
13
+ @source = options[:source]
14
+ end
15
+
16
+ def to_time
17
+ loop do
18
+ case
19
+ when !scheduled_in_this_month?
20
+ carry_month
21
+ when !scheduled_in_this_day?
22
+ carry_day
23
+ when !scheduled_in_this_wday?
24
+ carry_day
25
+ when !scheduled_in_this_hour?
26
+ carry_hour
27
+ when !scheduled_in_this_minute?
28
+ carry_minute
29
+ else
30
+ break time
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def time
38
+ @time ||= now + 1.minute
39
+ end
40
+
41
+ def fields
42
+ @fields ||= source.split(" ")
43
+ end
44
+
45
+ def schedule
46
+ @schedule ||= Schedule.new(source)
47
+ end
48
+
49
+ def scheduled_in_this_month?
50
+ schedule.months.include?(time.month)
51
+ end
52
+
53
+ def scheduled_in_this_day?
54
+ schedule.days.include?(time.day)
55
+ end
56
+
57
+ def scheduled_in_this_wday?
58
+ schedule.wdays.include?(time.wday)
59
+ end
60
+
61
+ def scheduled_in_this_hour?
62
+ schedule.hours.include?(time.hour)
63
+ end
64
+
65
+ def scheduled_in_this_minute?
66
+ schedule.minutes.include?(time.min)
67
+ end
68
+
69
+ def carry_month
70
+ self.time = time.next_month.at_beginning_of_month
71
+ end
72
+
73
+ def carry_day
74
+ self.time = time.tomorrow.at_beginning_of_day
75
+ end
76
+
77
+ def carry_wday
78
+ self.time = time.next_week.at_beginning_of_week
79
+ end
80
+
81
+ def carry_hour
82
+ self.time = (time + 1.hour).at_beginning_of_hour
83
+ end
84
+
85
+ def carry_minute
86
+ self.time = (time + 1.minute).at_beginning_of_minute
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,35 @@
1
+ module Chrono
2
+ class Schedule
3
+ attr_reader :source
4
+
5
+ def initialize(source)
6
+ @source = source
7
+ end
8
+
9
+ def minutes
10
+ Fields::Minute.new(fields[0]).to_a
11
+ end
12
+
13
+ def hours
14
+ Fields::Hour.new(fields[1]).to_a
15
+ end
16
+
17
+ def days
18
+ Fields::Day.new(fields[2]).to_a
19
+ end
20
+
21
+ def months
22
+ Fields::Month.new(fields[3]).to_a
23
+ end
24
+
25
+ def wdays
26
+ Fields::Wday.new(fields[4]).to_a
27
+ end
28
+
29
+ private
30
+
31
+ def fields
32
+ @fields ||= source.split(" ")
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module Chrono
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe Chrono::Iterator do
4
+ describe "#next" do
5
+ [
6
+ "2000-01-01 00:00:00", "2000-01-01 00:01:00", "* * * * *",
7
+ "2000-01-01 00:59:00", "2000-01-01 01:00:00", "* * * * *",
8
+ "2000-01-01 23:59:00", "2000-01-02 00:00:00", "* * * * *",
9
+ "2000-01-31 23:59:00", "2000-02-01 00:00:00", "* * * * *",
10
+ "2000-12-31 23:59:00", "2001-01-01 00:00:00", "* * * * *",
11
+ "2000-01-01 00:00:00", "2000-01-01 00:15:00", "*/15 * * * *",
12
+ "2000-01-01 00:01:00", "2000-01-01 00:15:00", "*/15 * * * *",
13
+ "2000-01-01 00:00:00", "2000-01-01 00:31:00", "*/31 * * * *",
14
+ "2000-01-01 00:31:00", "2000-01-01 01:00:00", "*/31 * * * *",
15
+ "2000-01-01 00:15:00", "2000-01-01 00:25:00", "*/15,25 * * * *",
16
+ "2000-01-01 00:15:00", "2000-01-01 00:25:00", "25,*/15 * * * *",
17
+ "2000-01-01 00:00:00", "2000-01-01 03:30:00", "30 3,6,9 * * *",
18
+ "2000-01-01 00:00:00", "2000-01-04 00:00:00", "* * * * 2,3",
19
+ "2000-01-04 00:00:00", "2000-01-04 00:01:00", "* * * * 2,3",
20
+ "2000-01-01 00:01:00", "2000-01-01 00:04:00", "1-20/3 * * * *",
21
+ "2000-01-01 00:20:00", "2000-01-01 01:01:00", "1-20/3 * * * *",
22
+ ].each_slice(3) do |from, to, source|
23
+ it "ticks #{from} to #{to} by #{source}" do
24
+ now = Time.parse(from)
25
+ described_class.new(source, now: now).next.should == Time.parse(to)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
+ require "chrono"
3
+
4
+ RSpec.configure do |config|
5
+ config.treat_symbols_as_metadata_keys_with_true_values = true
6
+ config.run_all_when_everything_filtered = true
7
+ config.filter_run :focus
8
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chrono
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryo Nakamura
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-18 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: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.14.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.14.1
69
+ description:
70
+ email:
71
+ - r7kamura@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - chrono.gemspec
82
+ - lib/chrono.rb
83
+ - lib/chrono/fields/base.rb
84
+ - lib/chrono/fields/day.rb
85
+ - lib/chrono/fields/hour.rb
86
+ - lib/chrono/fields/minute.rb
87
+ - lib/chrono/fields/month.rb
88
+ - lib/chrono/fields/wday.rb
89
+ - lib/chrono/iterator.rb
90
+ - lib/chrono/next_time.rb
91
+ - lib/chrono/schedule.rb
92
+ - lib/chrono/version.rb
93
+ - spec/chrono/iterator_spec.rb
94
+ - spec/spec_helper.rb
95
+ homepage: https://github.com/r7kamura/chrono
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.2.2
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Provides a chain of logics about chronology.
119
+ test_files:
120
+ - spec/chrono/iterator_spec.rb
121
+ - spec/spec_helper.rb