schedule_job 1.0.1 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -4
- data/Gemfile.lock +1 -1
- data/README.md +71 -1
- data/lib/schedule_job/cli.rb +21 -12
- data/lib/schedule_job/cron.rb +58 -42
- data/lib/schedule_job/cron_parser.rb +0 -13
- data/lib/schedule_job/version.rb +1 -1
- data/schedule_job.gemspec +1 -1
- metadata +2 -3
- data/lib/schedule_job/cron.treetop +0 -167
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a0f470384777a45f805dc1ff41c9f6386db8378c509eec95b647a577f43e06e
|
4
|
+
data.tar.gz: 9fa202bc1743951f7a2e350c379a1d0d79e0a5f2926fad5aa3c9393be042287d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddd20ca47d699cf56bd6e653a84065fe45c10133fd716af28fc092e2550deffe9a5465041e21ee287a3f4e9bfb34a9cdb14dd642ee5db1b3a807b6430fd9da28
|
7
|
+
data.tar.gz: 2e268c4aaa999e4c75df56aa0d4396a0269d9064cc9c46498598c0a5a0086ac1fe7e809cf243b8ddb2df98020b13fde6f6d40fd076e43ad440dc518918dadf81
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -5,13 +5,83 @@ schedule is a frontend around crontab to add/remove cron jobs from user cron tab
|
|
5
5
|
## Installation
|
6
6
|
|
7
7
|
```
|
8
|
-
gem install schedule_job
|
8
|
+
~ ❯ gem install schedule_job
|
9
|
+
Fetching schedule_job-1.0.1.gem
|
10
|
+
Successfully installed schedule_job-1.0.1
|
11
|
+
Parsing documentation for schedule_job-1.0.1
|
12
|
+
Installing ri documentation for schedule_job-1.0.1
|
13
|
+
Done installing documentation for schedule_job after 0 seconds
|
9
14
|
```
|
10
15
|
|
11
16
|
## Usage
|
12
17
|
|
18
|
+
Example usage:
|
13
19
|
```
|
20
|
+
~ ❯ schedule --help
|
21
|
+
Usage: schedule [options] command
|
22
|
+
-d, --dryrun Report what would happen but do not install the scheduled job.
|
23
|
+
-l, --list List installed cron jobs.
|
24
|
+
-r, --rm JOB_ID Remove the specified job id as indicated by --list
|
25
|
+
-u, --user USER User that the crontab belongs to.
|
26
|
+
-e, --every DURATION Run command every DURATION units of time (valid suffixes are m, h, d, M). DURATION may also be one of the special keywords: reboot, year, month, week, day, hour
|
27
|
+
For example:
|
28
|
+
--every 10m # every 10 minutes
|
29
|
+
--every 5h # every 5 hours
|
30
|
+
--every 2d # every 2 days
|
31
|
+
--every 3M # every 3 months
|
14
32
|
|
33
|
+
Special durations:
|
34
|
+
--every reboot # after every reboot
|
35
|
+
--every year # every year
|
36
|
+
--every month # every month
|
37
|
+
--every week # every week
|
38
|
+
--every day # every day
|
39
|
+
--every hour # every hour
|
40
|
+
|
41
|
+
-c, --cron CRON Run command on the given cron schedule.
|
42
|
+
For example:
|
43
|
+
--cron "*/5 15 * * 1-5" # Every 5 minutes, at 3:00 PM, Monday through Friday
|
44
|
+
--cron "0 0/30 8-9 5,20 * ?" # Every 30 minutes, between 8:00 AM and 9:59 AM, on day 5 and 20 of the month
|
45
|
+
|
46
|
+
~ ❯ schedule -l
|
47
|
+
~ ❯ schedule -d -e 10m backup.sh
|
48
|
+
Scheduling: backup.sh Every 10 minutes
|
49
|
+
Next three runs:
|
50
|
+
1. 2021-11-01 21:50:00 -0500
|
51
|
+
2. 2021-11-01 22:00:00 -0500
|
52
|
+
3. 2021-11-01 22:10:00 -0500
|
53
|
+
~ ❯ schedule -l
|
54
|
+
Jobs
|
55
|
+
1. backup.sh Every 10 minutes
|
56
|
+
~ ❯ crontab -l
|
57
|
+
*/10 * * * * backup.sh
|
58
|
+
~ ❯ schedule -e 3M quarterly_backup.sh
|
59
|
+
Scheduling: quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
|
60
|
+
Next three runs:
|
61
|
+
1. 2022-01-01 21:50:00 -0600
|
62
|
+
2. 2022-04-01 21:50:00 -0500
|
63
|
+
3. 2022-07-01 21:50:00 -0500
|
64
|
+
~ ❯ schedule -l
|
65
|
+
Jobs
|
66
|
+
1. backup.sh Every 10 minutes
|
67
|
+
2. quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
|
68
|
+
~ ❯ crontab -l
|
69
|
+
*/10 * * * * backup.sh
|
70
|
+
50 21 1 */3 * quarterly_backup.sh
|
71
|
+
~ ❯ schedule --dryrun --rm 1
|
72
|
+
Would remove: backup.sh Every 10 minutes
|
73
|
+
~ ❯ schedule --dryrun --rm 2
|
74
|
+
Would remove: quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
|
75
|
+
~ ❯ schedule --rm 1
|
76
|
+
Removing: backup.sh Every 10 minutes
|
77
|
+
~ ❯ schedule -l
|
78
|
+
Jobs
|
79
|
+
1. quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
|
80
|
+
~ ❯ schedule --rm 1
|
81
|
+
Removing: quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
|
82
|
+
~ ❯ schedule -l
|
83
|
+
~ ❯ crontab -l
|
84
|
+
~ ❯
|
15
85
|
```
|
16
86
|
|
17
87
|
## License
|
data/lib/schedule_job/cli.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
require "optparse"
|
2
2
|
|
3
|
-
# schedule --every 10m "my_command --foo --bar"
|
4
|
-
|
5
3
|
module ScheduleJob
|
6
4
|
class Cli
|
7
5
|
def self.run(argv = ARGV)
|
@@ -32,20 +30,28 @@ module ScheduleJob
|
|
32
30
|
options[:crontab_user] = user
|
33
31
|
end
|
34
32
|
|
35
|
-
opts.on("-e", "--every DURATION", "Run command every DURATION units of time.
|
33
|
+
opts.on("-e", "--every DURATION", "Run command every DURATION units of time (valid suffixes are m, h, d, M). DURATION may also be one of the special keywords: reboot, year, month, week, day, hour
|
36
34
|
For example:
|
37
|
-
--every 10m #
|
38
|
-
--every 5h #
|
39
|
-
--every 2d #
|
40
|
-
--every 3M #
|
35
|
+
--every 10m # every 10 minutes
|
36
|
+
--every 5h # every 5 hours
|
37
|
+
--every 2d # every 2 days
|
38
|
+
--every 3M # every 3 months
|
39
|
+
|
40
|
+
Special durations:
|
41
|
+
--every reboot # after every reboot
|
42
|
+
--every year # every year
|
43
|
+
--every month # every month
|
44
|
+
--every week # every week
|
45
|
+
--every day # every day
|
46
|
+
--every hour # every hour
|
41
47
|
") do |every|
|
42
48
|
options[:every] = every
|
43
49
|
end
|
44
50
|
|
45
51
|
opts.on("-c", "--cron CRON", "Run command on the given cron schedule.
|
46
52
|
For example:
|
47
|
-
--cron \"*/5 15 * * 1-5\" #
|
48
|
-
--cron \"0 0/30 8-9 5,20 * ?\" #
|
53
|
+
--cron \"*/5 15 * * 1-5\" # Every 5 minutes, at 3:00 PM, Monday through Friday
|
54
|
+
--cron \"0 0/30 8-9 5,20 * ?\" # Every 30 minutes, between 8:00 AM and 9:59 AM, on day 5 and 20 of the month
|
49
55
|
") do |cron_schedule|
|
50
56
|
options[:cron] = cron_schedule
|
51
57
|
end
|
@@ -63,6 +69,8 @@ module ScheduleJob
|
|
63
69
|
remove_job(args)
|
64
70
|
when args[:cron] || args[:every] # write jobs
|
65
71
|
install_job(args)
|
72
|
+
else
|
73
|
+
puts "No parameters specified. Please specify one of: --every, --cron, --list, or --rm"
|
66
74
|
end
|
67
75
|
end
|
68
76
|
|
@@ -90,13 +98,14 @@ module ScheduleJob
|
|
90
98
|
Cron::Job.new(cron_schedule, command)
|
91
99
|
when args[:every]
|
92
100
|
duration = args[:every]
|
93
|
-
match = duration.match(/(\d+)(m|h|d|M)/)
|
94
|
-
if match
|
101
|
+
if match = duration.match(/(\d+)(m|h|d|M)/)
|
95
102
|
qty = match[1].to_i
|
96
103
|
unit_of_time = match[2].to_s
|
97
104
|
Cron::Job.every(qty, unit_of_time, command)
|
105
|
+
elsif duration.match(/reboot|year|month|week|day|hour/)
|
106
|
+
Cron::Job.every_simple_duration(duration, command)
|
98
107
|
else
|
99
|
-
puts "'#{duration}' is an invalid duration. The duration must be specified as
|
108
|
+
puts "'#{duration}' is an invalid duration. The duration must be specified as either (1) integer followed immediately by m (minutes), h (hours), d (days), M (months) (e.g. 10m) or (2) reboot, year, month, week, day, hour"
|
100
109
|
exit(1)
|
101
110
|
end
|
102
111
|
end
|
data/lib/schedule_job/cron.rb
CHANGED
@@ -50,12 +50,6 @@ module ScheduleJob
|
|
50
50
|
|
51
51
|
raise("Unable to read crontab: #{error_output}") if !exit_status.success? && !no_crontab
|
52
52
|
|
53
|
-
# puts "read_crontab()"
|
54
|
-
# puts "stdout:"
|
55
|
-
# puts stdout
|
56
|
-
# puts "stderr:"
|
57
|
-
# puts stderr
|
58
|
-
|
59
53
|
crontab_output
|
60
54
|
end
|
61
55
|
|
@@ -63,16 +57,8 @@ module ScheduleJob
|
|
63
57
|
def parse_crontab(user_crontab)
|
64
58
|
parser = TableParser.new(user_crontab)
|
65
59
|
|
66
|
-
# user_crontab.each_line do |line|
|
67
|
-
# puts line
|
68
|
-
# puts "valid? #{LineParser.valid?(line)}"
|
69
|
-
# puts LineParser.parse(line)
|
70
|
-
# end
|
71
|
-
|
72
60
|
return [], [] unless parser.valid?
|
73
61
|
|
74
|
-
# puts "valid!"
|
75
|
-
|
76
62
|
environment_vars = parser.environment_vars&.map do |env_directive|
|
77
63
|
name = env_directive[:var].to_s
|
78
64
|
expr = env_directive[:expr].to_s
|
@@ -96,21 +82,25 @@ module ScheduleJob
|
|
96
82
|
puts "Scheduling: #{job.to_s}"
|
97
83
|
install_cron_job(job)
|
98
84
|
end
|
99
|
-
|
100
|
-
cron_parser = CronParser.new(job.schedule_spec)
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
85
|
+
|
86
|
+
cron_parser = CronParser.new(job.schedule_spec) rescue nil
|
87
|
+
if cron_parser
|
88
|
+
puts "Next three runs:"
|
89
|
+
first_run_time = cron_parser.next(Time.now)
|
90
|
+
second_run_time = cron_parser.next(first_run_time)
|
91
|
+
third_run_time = cron_parser.next(second_run_time)
|
92
|
+
|
93
|
+
puts "1. #{first_run_time}"
|
94
|
+
puts "2. #{second_run_time}"
|
95
|
+
puts "3. #{third_run_time}"
|
96
|
+
end
|
107
97
|
end
|
108
98
|
|
109
99
|
def install_cron_job(job)
|
110
100
|
job_spec = job.specification
|
111
|
-
# puts "Installing new cron job: #{job_spec}"
|
112
101
|
|
113
102
|
new_crontab = [read_crontab(@user).strip, job_spec.strip].reject(&:empty?).join("\n")
|
103
|
+
new_crontab << "\n" # add a trailing newline
|
114
104
|
write_crontab(new_crontab)
|
115
105
|
end
|
116
106
|
|
@@ -135,21 +125,12 @@ module ScheduleJob
|
|
135
125
|
end
|
136
126
|
|
137
127
|
def write_crontab(new_crontab, user = @user)
|
128
|
+
# overwrite crontab interactively, per https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job
|
138
129
|
command = ["crontab"]
|
139
130
|
command << "-u #{user}" if user
|
140
131
|
command << "-"
|
141
132
|
command = command.join(" ")
|
142
133
|
|
143
|
-
# command = "(crontab -l ; echo \"#{job_spec}\") | crontab -" # add new job to bottom of crontab, per https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job
|
144
|
-
# puts "writing new crontab:"
|
145
|
-
# puts new_crontab
|
146
|
-
# puts "*" * 80
|
147
|
-
|
148
|
-
# puts "write_crontab:"
|
149
|
-
# puts "command: #{command}"
|
150
|
-
# puts "new crontab:"
|
151
|
-
# puts new_crontab
|
152
|
-
|
153
134
|
stdout, stderr, exit_status = Open3.capture3(command, stdin_data: new_crontab)
|
154
135
|
crontab_output = stdout
|
155
136
|
error_output = stderr
|
@@ -184,14 +165,33 @@ module ScheduleJob
|
|
184
165
|
hour = next_moment.hour
|
185
166
|
day = next_moment.day
|
186
167
|
schedule_spec = case duration_unit_of_time
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
168
|
+
when "m"
|
169
|
+
"*/#{duration_quantity} * * * *"
|
170
|
+
when "h"
|
171
|
+
"#{minute} */#{duration_quantity} * * *"
|
172
|
+
when "d"
|
173
|
+
"#{minute} #{hour} */#{duration_quantity} * *"
|
174
|
+
when "M"
|
175
|
+
"#{minute} #{hour} #{day} */#{duration_quantity} *"
|
176
|
+
end
|
177
|
+
self.new(schedule_spec, command)
|
178
|
+
end
|
179
|
+
|
180
|
+
# duration is one of: reboot, year, month, week, day, hour
|
181
|
+
def self.every_simple_duration(duration, command)
|
182
|
+
schedule_spec = case duration
|
183
|
+
when "reboot"
|
184
|
+
"@reboot"
|
185
|
+
when "year"
|
186
|
+
"@yearly"
|
187
|
+
when "month"
|
188
|
+
"@monthly"
|
189
|
+
when "week"
|
190
|
+
"@weekly"
|
191
|
+
when "day"
|
192
|
+
"@daily"
|
193
|
+
when "hour"
|
194
|
+
"@hourly"
|
195
195
|
end
|
196
196
|
self.new(schedule_spec, command)
|
197
197
|
end
|
@@ -222,7 +222,23 @@ module ScheduleJob
|
|
222
222
|
end
|
223
223
|
|
224
224
|
def to_s
|
225
|
-
schedule =
|
225
|
+
schedule = case @schedule_spec
|
226
|
+
when "@reboot"
|
227
|
+
"at every reboot"
|
228
|
+
when "@yearly", "@annually"
|
229
|
+
"every year"
|
230
|
+
when "@monthly"
|
231
|
+
"every month"
|
232
|
+
when "@weekly"
|
233
|
+
"every week"
|
234
|
+
when "@daily"
|
235
|
+
"every day"
|
236
|
+
when "@hourly"
|
237
|
+
"every hour"
|
238
|
+
else
|
239
|
+
Cronex::ExpressionDescriptor.new(@schedule_spec).description
|
240
|
+
end
|
241
|
+
|
226
242
|
# str = "#{@command} #{schedule} (line #{@line_number}, pos #{@pos_offset})"
|
227
243
|
str = "#{@command} #{schedule}"
|
228
244
|
end
|
@@ -17,10 +17,6 @@ end
|
|
17
17
|
|
18
18
|
Citrus.require("schedule_job/cron")
|
19
19
|
|
20
|
-
# require "polyglot"
|
21
|
-
# require "treetop"
|
22
|
-
# require "schedule_job/cron.treetop"
|
23
|
-
|
24
20
|
module ScheduleJob
|
25
21
|
module Cron
|
26
22
|
Grammar = ScheduleCronParser
|
@@ -34,7 +30,6 @@ module ScheduleJob
|
|
34
30
|
|
35
31
|
def self.parse(user_crontab_string)
|
36
32
|
Grammar.parse(user_crontab_string, root: :user_crontab)
|
37
|
-
# ::CrontabParser.new.parse(user_crontab_string, root: :user_crontab)
|
38
33
|
end
|
39
34
|
|
40
35
|
def initialize(user_crontab_string)
|
@@ -55,17 +50,10 @@ module ScheduleJob
|
|
55
50
|
|
56
51
|
def environment_vars
|
57
52
|
@user_crontab&.capture(:environment)&.captures(:directive)
|
58
|
-
# puts @user_crontab.methods.sort.inspect
|
59
|
-
# puts @user_crontab.inspect
|
60
|
-
# puts "*" * 80
|
61
|
-
# puts @user_crontab.environment_spec.inspect
|
62
|
-
# exit()
|
63
|
-
# @user_crontab&.environment&.directive
|
64
53
|
end
|
65
54
|
|
66
55
|
def job_specs
|
67
56
|
@user_crontab&.capture(:jobspecs)&.captures(:jobspec)
|
68
|
-
# @user_crontab&.jobspecs&.jobspec
|
69
57
|
end
|
70
58
|
end
|
71
59
|
|
@@ -78,7 +66,6 @@ module ScheduleJob
|
|
78
66
|
|
79
67
|
def self.parse(cron_line)
|
80
68
|
Grammar.parse(cron_line, root: :jobspec, consume: false)
|
81
|
-
# ::CrontabParser.new.parse(cron_line, root: :jobspec, consume_all_input: false)
|
82
69
|
end
|
83
70
|
end
|
84
71
|
end
|
data/lib/schedule_job/version.rb
CHANGED
data/schedule_job.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.description = "job scheduler"
|
11
11
|
spec.homepage = "https://github.com/davidkellis/scheduler"
|
12
12
|
spec.license = "MIT"
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
14
14
|
|
15
15
|
spec.files = Dir["**/**"].
|
16
16
|
grep_v(/.gem$/).
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schedule_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Ellis
|
@@ -69,7 +69,6 @@ files:
|
|
69
69
|
- lib/schedule_job/cli.rb
|
70
70
|
- lib/schedule_job/cron.citrus
|
71
71
|
- lib/schedule_job/cron.rb
|
72
|
-
- lib/schedule_job/cron.treetop
|
73
72
|
- lib/schedule_job/cron_parser.rb
|
74
73
|
- lib/schedule_job/version.rb
|
75
74
|
- schedule_job.gemspec
|
@@ -85,7 +84,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
84
|
requirements:
|
86
85
|
- - ">="
|
87
86
|
- !ruby/object:Gem::Version
|
88
|
-
version: 2.
|
87
|
+
version: 2.5.0
|
89
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
89
|
requirements:
|
91
90
|
- - ">="
|
@@ -1,167 +0,0 @@
|
|
1
|
-
grammar Crontab
|
2
|
-
rule user_crontab
|
3
|
-
sep?
|
4
|
-
environment_spec:(environment sep)?
|
5
|
-
jobspecs?
|
6
|
-
sep?
|
7
|
-
end
|
8
|
-
|
9
|
-
rule environment
|
10
|
-
head:directive tail:(sep directive)*
|
11
|
-
end
|
12
|
-
|
13
|
-
rule directive
|
14
|
-
var space "=" space expr
|
15
|
-
end
|
16
|
-
|
17
|
-
rule var
|
18
|
-
alpha alphanumeric?
|
19
|
-
end
|
20
|
-
|
21
|
-
rule expr
|
22
|
-
command
|
23
|
-
end
|
24
|
-
|
25
|
-
rule jobspecs
|
26
|
-
head:jobspec tail:(sep jobspec)*
|
27
|
-
end
|
28
|
-
|
29
|
-
rule jobspec
|
30
|
-
schedule_spec space command ws*
|
31
|
-
end
|
32
|
-
|
33
|
-
rule schedule_spec
|
34
|
-
standard / special
|
35
|
-
end
|
36
|
-
|
37
|
-
rule standard
|
38
|
-
minute space hour space dayofmonth space month space dayofweek
|
39
|
-
end
|
40
|
-
|
41
|
-
rule special
|
42
|
-
"@" ("yearly" / "annually" / "monthly" / "weekly" / "daily" / "hourly" / "reboot")
|
43
|
-
end
|
44
|
-
|
45
|
-
rule minute
|
46
|
-
step
|
47
|
-
end
|
48
|
-
|
49
|
-
rule hour
|
50
|
-
step
|
51
|
-
end
|
52
|
-
|
53
|
-
rule dayofmonthtypes
|
54
|
-
step
|
55
|
-
end
|
56
|
-
|
57
|
-
rule monthtypes
|
58
|
-
step / altmonths
|
59
|
-
end
|
60
|
-
|
61
|
-
rule dayofweektypes
|
62
|
-
step / altdays
|
63
|
-
end
|
64
|
-
|
65
|
-
rule dayofmonth
|
66
|
-
dayofmonthtypes ("," dayofmonthtypes)*
|
67
|
-
end
|
68
|
-
|
69
|
-
rule month
|
70
|
-
monthtypes ("," monthtypes)*
|
71
|
-
end
|
72
|
-
|
73
|
-
rule dayofweek
|
74
|
-
dayofweektypes ("," dayofweektypes)*
|
75
|
-
end
|
76
|
-
|
77
|
-
rule command
|
78
|
-
quoted_string
|
79
|
-
/ (!("\n" / comment) .)+
|
80
|
-
end
|
81
|
-
|
82
|
-
rule step
|
83
|
-
common ("/" int)?
|
84
|
-
end
|
85
|
-
|
86
|
-
rule common
|
87
|
-
range / int / any
|
88
|
-
end
|
89
|
-
|
90
|
-
rule range
|
91
|
-
int "-" int
|
92
|
-
end
|
93
|
-
|
94
|
-
rule altdays
|
95
|
-
days ("," days)*
|
96
|
-
end
|
97
|
-
|
98
|
-
rule altmonths
|
99
|
-
months ("," months)*
|
100
|
-
end
|
101
|
-
|
102
|
-
rule days
|
103
|
-
"MON" / "TUE" / "WED" / "THU" / "FRI" / "SAT" / "SUN"
|
104
|
-
end
|
105
|
-
|
106
|
-
rule months
|
107
|
-
"JAN" / "FEB" / "MAR" / "APR" / "MAY" / "JUN" / "JUL" / "AUG" / "SEP" / "OCT" / "NOV" / "DEC"
|
108
|
-
end
|
109
|
-
|
110
|
-
rule any
|
111
|
-
"*"
|
112
|
-
end
|
113
|
-
|
114
|
-
rule int
|
115
|
-
[0-9]+
|
116
|
-
end
|
117
|
-
|
118
|
-
rule alpha
|
119
|
-
[a-zA-Z]+
|
120
|
-
end
|
121
|
-
|
122
|
-
rule alphanumeric
|
123
|
-
[a-zA-Z0-9]+
|
124
|
-
end
|
125
|
-
|
126
|
-
rule sep
|
127
|
-
(ws* nl)+
|
128
|
-
end
|
129
|
-
|
130
|
-
rule ws
|
131
|
-
space / comment
|
132
|
-
end
|
133
|
-
|
134
|
-
rule space
|
135
|
-
[ \t]+
|
136
|
-
end
|
137
|
-
|
138
|
-
rule nl
|
139
|
-
[\n]+
|
140
|
-
end
|
141
|
-
|
142
|
-
rule comment
|
143
|
-
"#" (!"\n" .)*
|
144
|
-
end
|
145
|
-
|
146
|
-
rule quoted_string
|
147
|
-
"\"" ( (!("\"" / "\\") .) / escape)* "\""
|
148
|
-
/ "'" ( (!("'" / "\\") .) / escape)* "'"
|
149
|
-
end
|
150
|
-
|
151
|
-
rule escape
|
152
|
-
"\\" escape_sequence
|
153
|
-
end
|
154
|
-
|
155
|
-
rule escape_sequence
|
156
|
-
"'"
|
157
|
-
/ "\""
|
158
|
-
/ "\\"
|
159
|
-
/ "b"
|
160
|
-
/ "f"
|
161
|
-
/ "n"
|
162
|
-
/ "r"
|
163
|
-
/ "t"
|
164
|
-
/ "v"
|
165
|
-
end
|
166
|
-
|
167
|
-
end
|