schedule_job 1.0.0 → 1.0.5
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 +1 -4
- data/Gemfile.lock +1 -1
- data/README.md +76 -2
- data/bin/schedule +2 -2
- data/lib/{schedule → schedule_job}/cli.rb +22 -13
- data/lib/{schedule → schedule_job}/cron.citrus +0 -0
- data/lib/{schedule → schedule_job}/cron.rb +22 -26
- data/lib/{schedule → schedule_job}/cron_parser.rb +2 -15
- data/lib/schedule_job/version.rb +3 -0
- data/lib/schedule_job.rb +2 -6
- data/schedule_job.gemspec +4 -2
- metadata +7 -8
- data/Rakefile +0 -8
- data/lib/schedule/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: 887f7a67ad740ea939e3c585534e820ad03d85695d07a74b26390c4300a8cb04
|
4
|
+
data.tar.gz: d61192e8ac1ba8b74f62de780b4b000d4b235aeb13f202d24e374f381f7c65ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86af048f9a4e1c2e50f9c7a63ffbe483fd5c8ffbda9ec521b5c7d2c39a8a6228367e239f0ab347d3c681a2fbbf03918691e3cbf95d67cbf5c256b8439e2dbfe3
|
7
|
+
data.tar.gz: 7866e34e5591ed82159cc81a268166562f07e50033998cee9ff0000baeafd92772df00a7ed3953a6e50f8d627f64fb636898bd432fe460f7099a958f7c078ae5
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,89 @@
|
|
1
|
-
#
|
1
|
+
# ScheduleJob
|
2
2
|
|
3
3
|
schedule is a frontend around crontab to add/remove cron jobs from user cron tables.
|
4
4
|
|
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:
|
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
|
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
|
+
~ ❯
|
85
|
+
```
|
86
|
+
|
13
87
|
## License
|
14
88
|
|
15
89
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/bin/schedule
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
require "optparse"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
module Schedule
|
3
|
+
module ScheduleJob
|
6
4
|
class Cli
|
7
5
|
def self.run(argv = ARGV)
|
8
6
|
cli = Cli.new
|
@@ -32,20 +30,28 @@ module Schedule
|
|
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 Schedule
|
|
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 Schedule
|
|
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
|
File without changes
|
@@ -8,7 +8,7 @@ require "stringio"
|
|
8
8
|
|
9
9
|
require_relative "./cron_parser"
|
10
10
|
|
11
|
-
module
|
11
|
+
module ScheduleJob
|
12
12
|
module Cron
|
13
13
|
|
14
14
|
class EnvironmentVar
|
@@ -50,12 +50,6 @@ module Schedule
|
|
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 Schedule
|
|
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
|
@@ -108,9 +94,9 @@ module Schedule
|
|
108
94
|
|
109
95
|
def install_cron_job(job)
|
110
96
|
job_spec = job.specification
|
111
|
-
# puts "Installing new cron job: #{job_spec}"
|
112
97
|
|
113
98
|
new_crontab = [read_crontab(@user).strip, job_spec.strip].reject(&:empty?).join("\n")
|
99
|
+
new_crontab << "\n" # add a trailing newline
|
114
100
|
write_crontab(new_crontab)
|
115
101
|
end
|
116
102
|
|
@@ -135,21 +121,12 @@ module Schedule
|
|
135
121
|
end
|
136
122
|
|
137
123
|
def write_crontab(new_crontab, user = @user)
|
124
|
+
# overwrite crontab interactively, per https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job
|
138
125
|
command = ["crontab"]
|
139
126
|
command << "-u #{user}" if user
|
140
127
|
command << "-"
|
141
128
|
command = command.join(" ")
|
142
129
|
|
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
130
|
stdout, stderr, exit_status = Open3.capture3(command, stdin_data: new_crontab)
|
154
131
|
crontab_output = stdout
|
155
132
|
error_output = stderr
|
@@ -196,6 +173,25 @@ module Schedule
|
|
196
173
|
self.new(schedule_spec, command)
|
197
174
|
end
|
198
175
|
|
176
|
+
# duration is one of: reboot, year, month, week, day, hour
|
177
|
+
def self.every_simple_duration(duration, command)
|
178
|
+
schedule_spec = case duration
|
179
|
+
when "reboot"
|
180
|
+
"@reboot"
|
181
|
+
when "year"
|
182
|
+
"@yearly"
|
183
|
+
when "month"
|
184
|
+
"@monthly"
|
185
|
+
when "week"
|
186
|
+
"@weekly"
|
187
|
+
when "day"
|
188
|
+
"@daily"
|
189
|
+
when "hour"
|
190
|
+
"@hourly"
|
191
|
+
end
|
192
|
+
self.new(schedule_spec, command)
|
193
|
+
end
|
194
|
+
|
199
195
|
attr_reader :schedule_spec
|
200
196
|
attr_reader :line_number
|
201
197
|
|
@@ -15,13 +15,9 @@ module Citrus
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
Citrus.require("
|
18
|
+
Citrus.require("schedule_job/cron")
|
19
19
|
|
20
|
-
|
21
|
-
# require "treetop"
|
22
|
-
# require "schedule/cron.treetop"
|
23
|
-
|
24
|
-
module Schedule
|
20
|
+
module ScheduleJob
|
25
21
|
module Cron
|
26
22
|
Grammar = ScheduleCronParser
|
27
23
|
|
@@ -34,7 +30,6 @@ module Schedule
|
|
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 Schedule
|
|
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 Schedule
|
|
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.rb
CHANGED
data/schedule_job.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require_relative "lib/schedule_job/version"
|
2
|
+
|
1
3
|
Gem::Specification.new do |spec|
|
2
4
|
spec.name = "schedule_job"
|
3
|
-
spec.version =
|
5
|
+
spec.version = ScheduleJob::VERSION
|
4
6
|
spec.authors = ["David Ellis"]
|
5
7
|
spec.email = ["david@conquerthelawn.com"]
|
6
8
|
|
@@ -8,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
8
10
|
spec.description = "job scheduler"
|
9
11
|
spec.homepage = "https://github.com/davidkellis/scheduler"
|
10
12
|
spec.license = "MIT"
|
11
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
12
14
|
|
13
15
|
spec.files = Dir["**/**"].
|
14
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.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Ellis
|
@@ -64,14 +64,13 @@ files:
|
|
64
64
|
- Gemfile.lock
|
65
65
|
- LICENSE.txt
|
66
66
|
- README.md
|
67
|
-
- Rakefile
|
68
67
|
- bin/schedule
|
69
|
-
- lib/schedule/cli.rb
|
70
|
-
- lib/schedule/cron.citrus
|
71
|
-
- lib/schedule/cron.rb
|
72
|
-
- lib/schedule/cron.treetop
|
73
|
-
- lib/schedule/cron_parser.rb
|
74
68
|
- lib/schedule_job.rb
|
69
|
+
- lib/schedule_job/cli.rb
|
70
|
+
- lib/schedule_job/cron.citrus
|
71
|
+
- lib/schedule_job/cron.rb
|
72
|
+
- lib/schedule_job/cron_parser.rb
|
73
|
+
- lib/schedule_job/version.rb
|
75
74
|
- schedule_job.gemspec
|
76
75
|
homepage: https://github.com/davidkellis/scheduler
|
77
76
|
licenses:
|
@@ -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
|
- - ">="
|
data/Rakefile
DELETED
data/lib/schedule/cron.treetop
DELETED
@@ -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
|