cron_config_parser 0.1.1 → 0.1.2
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 +4 -4
- data/Gemfile.lock +14 -1
- data/README.md +12 -4
- data/cron_config_parser.gemspec +1 -0
- data/lib/cron_config_parser.rb +163 -22
- data/lib/cron_config_parser/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 895da1f251f953d6815a2bb37ade3974189abbef9e6215c80de705b7164e6874
|
4
|
+
data.tar.gz: 1d1bcd7003feaf1453b86d87d96ff89126c2214d8c2218cb492e383e3b87d5cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbd0de9b030fe9134482ea5edc26fe82a87204572bf6fcdd54d9071476c1b8ee1388512236ed20c8ab4372dddcfeedf0102865b90a7357c2d5346b31822e2726
|
7
|
+
data.tar.gz: 9fafca4d6b2d9d03f716adf58e729fff7113009f0d1fc7ddd302d9ee3ad5dd040ddaa667e53c544a894821c4c452c867f3340a22bf7d91476df650699ae2c09d
|
data/Gemfile.lock
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cron_config_parser (0.1.
|
4
|
+
cron_config_parser (0.1.2)
|
5
|
+
activesupport (~> 5.2)
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
8
9
|
specs:
|
10
|
+
activesupport (5.2.3)
|
11
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
+
i18n (>= 0.7, < 2)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
tzinfo (~> 1.1)
|
15
|
+
concurrent-ruby (1.1.5)
|
9
16
|
diff-lcs (1.3)
|
17
|
+
i18n (1.6.0)
|
18
|
+
concurrent-ruby (~> 1.0)
|
19
|
+
minitest (5.11.3)
|
10
20
|
rake (10.5.0)
|
11
21
|
rspec (3.8.0)
|
12
22
|
rspec-core (~> 3.8.0)
|
@@ -21,6 +31,9 @@ GEM
|
|
21
31
|
diff-lcs (>= 1.2.0, < 2.0)
|
22
32
|
rspec-support (~> 3.8.0)
|
23
33
|
rspec-support (3.8.0)
|
34
|
+
thread_safe (0.3.6)
|
35
|
+
tzinfo (1.2.5)
|
36
|
+
thread_safe (~> 0.1)
|
24
37
|
|
25
38
|
PLATFORMS
|
26
39
|
ruby
|
data/README.md
CHANGED
@@ -37,12 +37,20 @@ enable check configured properties.
|
|
37
37
|
``` ruby
|
38
38
|
# return false if configured nil or '*'
|
39
39
|
config = CronConfigParser::Parser.call('00 5 * * * Asia/Tokyo')
|
40
|
-
config.
|
40
|
+
config.minutes_configured?
|
41
41
|
=> true
|
42
|
-
config.
|
42
|
+
config.days_configured?
|
43
43
|
=> false
|
44
44
|
```
|
45
45
|
|
46
|
+
enable check next execute time.
|
47
|
+
|
48
|
+
``` ruby
|
49
|
+
config = CronConfigParser::Parser.call('00 5 * * * Asia/Tokyo')
|
50
|
+
config.next_execute_at
|
51
|
+
=> 2019-05-23 05:00:00 +0900
|
52
|
+
```
|
53
|
+
|
46
54
|
This gem check simple validation when CronConfigParser::CronConfig object initialize.
|
47
55
|
If the config is invalid, Config::SyntaxError or Config::RequiredError is raised.
|
48
56
|
|
@@ -68,7 +76,7 @@ CronConfigParser::Parser.call('00 5,a * * * Asia/Tokyo', validation: false)
|
|
68
76
|
|
69
77
|
## Contributing
|
70
78
|
|
71
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
79
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Madogiwa0124/cron_config_parser. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
72
80
|
|
73
81
|
## License
|
74
82
|
|
@@ -76,4 +84,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
76
84
|
|
77
85
|
## Code of Conduct
|
78
86
|
|
79
|
-
Everyone interacting in the CronConfigParser project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
87
|
+
Everyone interacting in the CronConfigParser project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Madogiwa0124/cron_config_parser/blob/master/CODE_OF_CONDUCT.md).
|
data/cron_config_parser.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
|
+
spec.add_dependency "activesupport", "~> 5.2"
|
25
26
|
spec.add_development_dependency "bundler", "~> 1.17"
|
26
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
data/lib/cron_config_parser.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require "cron_config_parser/version"
|
2
|
+
require 'active_support/all'
|
2
3
|
|
3
4
|
module CronConfigParser
|
4
|
-
class ConfigSyntaxError < StandardError; end
|
5
|
-
class ConfigRequiredError < StandardError; end
|
6
|
-
|
7
5
|
class Parser
|
8
6
|
def self.call(cron_config, validation: true)
|
9
7
|
new(cron_config, validation: validation).call
|
@@ -24,50 +22,193 @@ module CronConfigParser
|
|
24
22
|
class CronConfig
|
25
23
|
NOT_CONFIGURED_MARK = '*'.freeze
|
26
24
|
|
27
|
-
def initialize(cron_config, validation: true)
|
25
|
+
def initialize(cron_config, validator: CronConfigParser::Varidator, validation: true)
|
28
26
|
cron_config = cron_config.split(' ').map { |item| item.split(',') }
|
29
27
|
@minutes, @hours, @days, @months, @wdays, @timezone = cron_config
|
30
28
|
# timezone is not multiple values.
|
31
29
|
@timezone = @timezone.to_a.first
|
32
|
-
|
30
|
+
validator.call!(self) if validation
|
33
31
|
end
|
34
32
|
|
35
|
-
|
33
|
+
attr_accessor :minutes, :hours, :days, :months, :wdays, :timezone
|
34
|
+
|
35
|
+
def next_execute_at(basis_datetime: Time.current)
|
36
|
+
ExecuteAtCalculator.new(cron_config: self, basis_datetime: basis_datetime).call
|
37
|
+
end
|
36
38
|
|
37
|
-
#
|
39
|
+
# define properties configured check methods
|
38
40
|
[:minutes, :hours, :days, :months, :wdays, :timezone].each do |attr|
|
39
41
|
define_method("#{attr}_configured?") do
|
40
42
|
value = send(attr).class == Array ? send(attr)[0] : send(attr)
|
41
43
|
![NOT_CONFIGURED_MARK, nil].include?(value)
|
42
44
|
end
|
43
45
|
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Varidator
|
49
|
+
class ConfigSyntaxError < StandardError; end
|
50
|
+
class ConfigRequiredError < StandardError; end
|
51
|
+
|
52
|
+
def self.call!(cron_config)
|
53
|
+
new(cron_config).call!
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(cron_config)
|
57
|
+
@cron_config = cron_config
|
58
|
+
end
|
59
|
+
|
60
|
+
def call!
|
61
|
+
raise ConfigRequiredError unless configured_required_properties?
|
62
|
+
raise ConfigSyntaxError unless configured_valid_syntax_properties?
|
63
|
+
end
|
44
64
|
|
45
65
|
private
|
46
66
|
|
47
|
-
|
48
|
-
|
49
|
-
|
67
|
+
attr_reader :cron_config
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def configured_required_properties?
|
72
|
+
![cron_config.minutes,
|
73
|
+
cron_config.hours,
|
74
|
+
cron_config.days,
|
75
|
+
cron_config.months,
|
76
|
+
cron_config.wdays].flatten.include?(nil)
|
50
77
|
end
|
51
78
|
|
52
|
-
def
|
53
|
-
if
|
54
|
-
|
55
|
-
|
79
|
+
def configured_valid_syntax_properties?
|
80
|
+
return false if cron_config.minutes_configured? && !values_in_range?(:minutes) && !validate_format?(:minutes)
|
81
|
+
return false if cron_config.hours_configured? && !values_in_range?(:hours) && !validate_format?(:hours)
|
82
|
+
return false if cron_config.days_configured? && !values_in_range?(:days) && !validate_format?(:days)
|
83
|
+
return false if cron_config.wdays_configured? && !values_in_range?(:wdays) && !validate_format?(:wdays)
|
84
|
+
return false if cron_config.months_configured? && !values_in_range?(:months) && !validate_format?(:months)
|
85
|
+
true
|
56
86
|
end
|
57
87
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
88
|
+
def validate_format?(property_sym)
|
89
|
+
valid_count = cron_config.send(property_sym).count do |value|
|
90
|
+
value.match?(/(\d{1,2}|\*)(\/|-)\d{1,2}/) || value.match?(/\d{1,2}/)
|
91
|
+
end
|
92
|
+
cron_config.send(property_sym).count == valid_count
|
63
93
|
end
|
64
94
|
|
65
|
-
def values_in_range?(
|
66
|
-
values
|
95
|
+
def values_in_range?(property_sym)
|
96
|
+
values = cron_config.send(property_sym)
|
97
|
+
hash = { minutes: 0..60, hours: 0..24, days: 1..31, months: 1..12, wdays: 0..6 }
|
98
|
+
values.count == values.count { |value| hash[property_sym].include?(to_i(value)) }
|
67
99
|
end
|
68
100
|
|
69
101
|
def to_i(string)
|
70
|
-
Integer(string) rescue
|
102
|
+
Integer(string) rescue string
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class ExecuteAtCalculator
|
107
|
+
WDAYS = %i[sunday monday tuesday wednesday thursday friday saturday].freeze
|
108
|
+
|
109
|
+
def initialize(cron_config:, basis_datetime:)
|
110
|
+
@cron_config = cron_config
|
111
|
+
@basis_datetime = basis_datetime
|
112
|
+
@execute_at = basis_datetime
|
113
|
+
prepare_cron_config
|
114
|
+
end
|
115
|
+
|
116
|
+
attr_accessor :cron_config, :basis_datetime, :execute_at
|
117
|
+
|
118
|
+
def call
|
119
|
+
next_minute
|
120
|
+
next_hour
|
121
|
+
next_day
|
122
|
+
next_wday
|
123
|
+
next_month
|
124
|
+
execute_at
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def prepare_cron_config
|
130
|
+
@cron_config.minutes = parse_config_property(:minutes)
|
131
|
+
@cron_config.hours = parse_config_property(:hours)
|
132
|
+
@cron_config.days = parse_config_property(:days)
|
133
|
+
@cron_config.months = parse_config_property(:months)
|
134
|
+
@cron_config.wdays = parse_config_property(:wdays)
|
135
|
+
end
|
136
|
+
|
137
|
+
def to_i(value)
|
138
|
+
Integer(value) rescue value
|
139
|
+
end
|
140
|
+
|
141
|
+
def parse_config_property(property_sym)
|
142
|
+
cron_config.send(property_sym).map do |property|
|
143
|
+
next to_i(property) unless property.match?(/\/|-/)
|
144
|
+
next parse_for_devided_config(property, property_sym) if property.include?('/')
|
145
|
+
next parse_for_range_config(property) if property.include?('-')
|
146
|
+
end.flatten.uniq.sort
|
147
|
+
end
|
148
|
+
|
149
|
+
def parse_for_devided_config(property, property_sym)
|
150
|
+
hash = { minutes: 0..60, hours: 0..24, days: 1..31, months: 1..12, wdays: 0..6 }
|
151
|
+
hash[property_sym].select { |val| (val % (property).split('/')[1].to_i) == 0 }
|
152
|
+
end
|
153
|
+
|
154
|
+
def parse_for_range_config(property)
|
155
|
+
range_start, range_end = property.split('-').map(&:to_i)
|
156
|
+
(range_start..range_end).to_a
|
157
|
+
end
|
158
|
+
|
159
|
+
def next_minute
|
160
|
+
return @execute_at = execute_at.since(1.minute) unless cron_config.minutes_configured?
|
161
|
+
next_minute = cron_config.minutes.select { |config_min| config_min > execute_at.min }.first
|
162
|
+
@execute_at = change_to_property_and_move_up(property: next_minute, property_sym: :minutes)
|
163
|
+
end
|
164
|
+
|
165
|
+
def next_hour
|
166
|
+
return unless cron_config.hours_configured?
|
167
|
+
next_hour = cron_config.hours.select { |config_hour| config_hour > execute_at.hour }.first
|
168
|
+
@execute_at = change_to_property_and_move_up(property: next_hour, property_sym: :hours)
|
169
|
+
# reset minute when execute in freture and not configured minute
|
170
|
+
@execute_at = @execute_at.change(min: 0) unless cron_config.minutes_configured?
|
171
|
+
end
|
172
|
+
|
173
|
+
def next_day
|
174
|
+
return unless cron_config.days_configured?
|
175
|
+
next_day = cron_config.days.select { |config_day| config_day > execute_at.day }.first
|
176
|
+
@execute_at = change_to_property_and_move_up(property: next_day, property_sym: :days)
|
177
|
+
# reset minute when execute in freture and not configured minute
|
178
|
+
@execute_at = @execute_at.change(min: 0) unless cron_config.minutes_configured?
|
179
|
+
end
|
180
|
+
|
181
|
+
def next_wday
|
182
|
+
return unless cron_config.wdays_configured?
|
183
|
+
next_wday = cron_config.wdays.select { |config_wday| config_wday > execute_at.wday }.first
|
184
|
+
next_wday_sym = next_wday ? WDAYS[next_wday] : WDAYS[cron_config.wdays.first]
|
185
|
+
@execute_at = execute_at.next_occurring(next_wday_sym)
|
186
|
+
# reset minute when execute in freture and not configured minute
|
187
|
+
@execute_at = @execute_at.change(min: 0) unless cron_config.minutes_configured?
|
188
|
+
end
|
189
|
+
|
190
|
+
def next_month
|
191
|
+
return unless cron_config.months_configured?
|
192
|
+
next_month = cron_config.months.select { |config_month| config_month > execute_at.month }.first
|
193
|
+
@execute_at = change_to_property_and_move_up(property: next_month, property_sym: :months)
|
194
|
+
# reset minute when execute in freture and not configured minute
|
195
|
+
@execute_at = @execute_at.change(min: 0) unless cron_config.minutes_configured?
|
196
|
+
end
|
197
|
+
|
198
|
+
def change_to_property_and_move_up(property:, property_sym:)
|
199
|
+
change_property = convert_hash(property_sym)[:change_property]
|
200
|
+
move_up_property = convert_hash(property_sym)[:move_up_property]
|
201
|
+
return execute_at.change(change_property => property) if property
|
202
|
+
execute_at.since(1.send(move_up_property)).change(
|
203
|
+
change_property => cron_config.send(property_sym).first
|
204
|
+
)
|
205
|
+
end
|
206
|
+
|
207
|
+
def convert_hash(property_sym)
|
208
|
+
{ minutes: { change_property: :min, move_up_property: :hour },
|
209
|
+
hours: { change_property: :hour, move_up_property: :day },
|
210
|
+
days: { change_property: :day, move_up_property: :month },
|
211
|
+
months: { change_property: :month, move_up_property: :year }, }[property_sym]
|
71
212
|
end
|
72
213
|
end
|
73
214
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cron_config_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Madogiwa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-21 00:00:00.000000000 Z
|
12
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: '5.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.2'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|