cronex 0.2.0

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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YzZlZDk0MGYzNDdhZDY2MGVkZGUwMDI3NDhiZjYxNDRhMjhkMjQ0ZA==
5
+ data.tar.gz: !binary |-
6
+ YzU5N2E3ZDI5NGQzMGY4NmMyN2Q1OTIwYTQwMWExZjc2YjUyOWE3YQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MDhhMzZjMTczNDhkMjYwZjNiYmZlNDMxYTE1YThkZGYzNmNmYTA2MGQwYzQ4
10
+ YTY2NWRiMTk0NjYzNmQ5MzBhYTVhZTZlZDkxM2Y3MzQ3MjBkNmQxZTYwY2Yx
11
+ ZDk3NTEzNzgxMjUxZDdmOWRkMjVmYWE3NzM0OGYzOTgzMTQwYjQ=
12
+ data.tar.gz: !binary |-
13
+ MjZlNTcwYWJmM2Y0OGI1MzE1NjdiMDQzMzk5NjYxNmFiYzY1YTgxYTk1ZDAw
14
+ YjdhNDQ0Njc2ODE0NjE4ZmY1OTJhYTgyYWVhYjcyN2JlZjViYTE5ZmY5YWVi
15
+ OGRlYjJkOWEwNTFlZTU5ZDNmNGNlZTZkMzkyOWE3MDkzYzU2YzY=
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.log
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .rvmrc
7
+ .yardoc
8
+ Gemfile.lock
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ temp
19
+ tmp
20
+ vendor
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,47 @@
1
+ Encoding:
2
+ Enabled: false
3
+
4
+ AmbiguousOperator:
5
+ Enabled: false
6
+
7
+ CaseIndentation:
8
+ Enabled: false
9
+
10
+ CyclomaticComplexity:
11
+ Enabled: false
12
+ Max: 10
13
+
14
+ PerceivedComplexity:
15
+ Enabled: false
16
+ Max: 10
17
+
18
+ Documentation:
19
+ Enabled: false
20
+
21
+ EmptyLinesAroundBody:
22
+ Enabled: false
23
+
24
+ ClassLength:
25
+ Enabled: false
26
+
27
+ LineLength:
28
+ Enabled: true
29
+ Max: 160
30
+
31
+ MethodLength:
32
+ Enabled: false
33
+
34
+ ModuleFunction:
35
+ Enabled: false
36
+
37
+ NestedTernaryOperator:
38
+ Enabled: false
39
+
40
+ RaiseArgs:
41
+ Enabled: false
42
+
43
+ RescueModifier:
44
+ Enabled: false
45
+
46
+ UnusedMethodArgument:
47
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ ### [0.2.0] - 2015-10-25
2
+ - Initial public version
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2015, Opower
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ #Cronex
2
+
3
+ A Ruby library that converts cron expressions into human readable strings.
4
+ Translated to Ruby from [cron-expression-descriptor](https://github.com/bradyholt/cron-expression-descriptor) (C#) via
5
+ [cron-parser](https://github.com/RedHogs/cron-parser) (Java).
6
+
7
+ Original Author & Credit: Brady Holt (http://www.geekytidbits.com).
8
+
9
+ ## Features
10
+
11
+ * Supports all cron expression special characters including: `*` `/` `,` `-` `?` `L` `W` `#`
12
+ * Supports 5, 6 (w/ seconds or year), or 7 (w/ seconds and year) part cron expressions
13
+ * Provides casing options (sentence, title, lower)
14
+ * Support for non-standard non-zero-based week day numbers
15
+ * Supports printing to locale specific human readable format
16
+
17
+ For a quick intro to cron see Quartz [Cron Tutorial](http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger).
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ gem 'cronex'
24
+
25
+ And then execute:
26
+
27
+ $ bundle install
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install cronex
32
+
33
+ ## Usage
34
+
35
+ #### Zero based day of week
36
+
37
+ Cronex::ExpressionDescriptor.new('*/5 15 * * 1-5').description
38
+ => Every 5 minutes, at 3:00 PM, Monday through Friday
39
+
40
+ Cronex::ExpressionDescriptor.new('0 0/30 8-9 5,20 * ?').description
41
+ => Every 30 minutes, between 8:00 AM and 9:59 AM, on day 5 and 20 of the month
42
+
43
+ #### Non-zero based day of week
44
+
45
+ Cronex::ExpressionDescriptor.new('*/5 15 * * 1-5', zero_based_dow: false).description
46
+ => Every 5 minutes, at 3:00 PM, Sunday through Thursday
47
+
48
+ See spec tests for more examples.
49
+
50
+ ### Contributing
51
+
52
+ 1. Fork it
53
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
54
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
55
+ 4. Push to the branch (`git push origin my-new-feature`)
56
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.pattern = 'spec/*_spec.rb'
6
+ end
7
+
8
+ task :default => :spec
data/cronex.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/cronex/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'cronex'
6
+ spec.version = Cronex::VERSION
7
+ spec.summary = 'Ruby library that converts cron expressions into human readable strings'
8
+ spec.description = spec.summary
9
+ spec.homepage = 'https://github.com/alpinweis/cronex'
10
+
11
+ spec.authors = ['Adrian Kazaku']
12
+ spec.email = ['alpinweis@gmail.com']
13
+
14
+ spec.required_ruby_version = '>= 1.9.3'
15
+
16
+ spec.license = 'Apache 2'
17
+
18
+ spec.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
19
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'pry', '~> 0.10'
24
+ spec.add_development_dependency 'rake', '~> 10.1'
25
+ spec.add_development_dependency 'rspec', '~> 3.1'
26
+ end
data/lib/cronex.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'date'
2
+ require 'time'
3
+ require 'yaml'
4
+ require_relative 'cronex/version'
5
+ require_relative 'cronex/errors'
6
+ require_relative 'cronex/resource'
7
+ require_relative 'cronex/utils'
8
+ require_relative 'cronex/parser'
9
+ require_relative 'cronex/exp_descriptor'
10
+ require_relative 'cronex/description'
@@ -0,0 +1,8 @@
1
+ require_relative 'description/base'
2
+ require_relative 'description/seconds'
3
+ require_relative 'description/minutes'
4
+ require_relative 'description/hours'
5
+ require_relative 'description/day_of_week'
6
+ require_relative 'description/day_of_month'
7
+ require_relative 'description/month'
8
+ require_relative 'description/year'
@@ -0,0 +1,59 @@
1
+ module Cronex
2
+ class Description
3
+
4
+ attr_accessor :resources, :options
5
+
6
+ def initialize(resources, options = {})
7
+ @resources = resources
8
+ @options = options || {}
9
+ end
10
+
11
+ def special_chars
12
+ ['/', '-', ',']
13
+ end
14
+
15
+ def segment_description(expression, all_description)
16
+ if expression.empty? || expression == '0'
17
+ desc = ''
18
+ elsif expression == '*'
19
+ desc = all_description
20
+ elsif !Cronex::Utils.include_any?(expression, special_chars)
21
+ desc = format(description_format(expression), single_item_description(expression))
22
+ elsif expression.include?('/')
23
+ segments = expression.split('/')
24
+ desc = format(interval_description_format(segments[1]), single_item_description(segments[1]))
25
+ # interval contains 'between' piece (e.g. 2-59/3)
26
+ if segments[0].include?('-')
27
+ between_segment_of_interval = segments[0]
28
+ between_segments = between_segment_of_interval.split('-')
29
+ desc += ', ' + format(
30
+ between_description_format(between_segment_of_interval),
31
+ single_item_description(between_segments[0]),
32
+ single_item_description(between_segments[1]).gsub(':00', ':59'))
33
+ elsif !Cronex::Utils.include_any?(segments[0], special_chars + ['*'])
34
+ desc += ', ' + format(starting_description_format(segments[0]), single_item_description(segments[0]))
35
+ end
36
+ elsif expression.include?('-')
37
+ segments = expression.split('-')
38
+ desc = format(
39
+ between_description_format(expression),
40
+ single_item_description(segments[0]),
41
+ single_item_description(segments[1]).gsub(':00', ':59'))
42
+ elsif expression.include?(',')
43
+ segments = expression.split(',')
44
+ segments = segments.map { |s| single_item_description(s) }
45
+ desc_content = segments[0...-1].join(', ') + ' ' + resources.get('and') + ' ' + segments.last
46
+ desc = format(description_format(expression), desc_content)
47
+ end
48
+
49
+ desc
50
+ end
51
+
52
+ def plural(expression, singular, plural)
53
+ number = Cronex::Utils.number?(expression)
54
+ return plural if number && number > 1
55
+ return plural if expression.include?(',')
56
+ singular
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ module Cronex
2
+ class DayOfMonthDescription < Description
3
+ def single_item_description(expression)
4
+ expression
5
+ end
6
+
7
+ def interval_description_format(expression)
8
+ ', ' + resources.get('every_x') + ' ' + plural(expression, resources.get('day'), resources.get('days'))
9
+ end
10
+
11
+ def between_description_format(expression)
12
+ ', ' + resources.get('between_days_of_the_month')
13
+ end
14
+
15
+ def description_format(expression)
16
+ ', ' + resources.get('on_day_of_the_month')
17
+ end
18
+
19
+ def starting_description_format(expression)
20
+ resources.get('starting') + ' ' + resources.get('on_day_of_the_month')
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,52 @@
1
+ module Cronex
2
+ class DayOfWeekDescription < Description
3
+ def single_item_description(expression)
4
+ exp = expression
5
+ if expression.include?('#')
6
+ exp = expression.partition('#').first
7
+ elsif expression.include?('L')
8
+ exp = exp.gsub('L', '')
9
+ end
10
+
11
+ if Cronex::Utils.number?(exp)
12
+ dow_num = Integer(exp)
13
+ zero_based_dow = options[:zero_based_dow]
14
+ invalid_dow = !zero_based_dow && dow_num <= 1
15
+ if invalid_dow || (zero_based_dow && dow_num == 0)
16
+ return Cronex::Utils.day_of_week_name(0) # or 7 as in java DateTime().withDayOfWeek(7) for Sunday
17
+ elsif !zero_based_dow
18
+ dow_num -= 1
19
+ end
20
+ return Cronex::Utils.day_of_week_name(dow_num)
21
+ else
22
+ return Date.parse(exp.capitalize).strftime('%A')
23
+ end
24
+ end
25
+
26
+ def interval_description_format(expression)
27
+ format(', ' + resources.get('interval_description_format'), expression)
28
+ end
29
+
30
+ def between_description_format(expression)
31
+ ', ' + resources.get('between_weekday_description_format')
32
+ end
33
+
34
+ def description_format(expression)
35
+ if expression.include?('#')
36
+ dow_num = expression.split('#').last
37
+ days = Hash[%w(1 2 3 4 5).zip(%w(first second third forth fifth))]
38
+ dow_desc = days[dow_num]
39
+ dow_desc = dow_desc ? resources.get(dow_desc) : ''
40
+ ', ' + resources.get('on_the_day_of_the_month').gsub(/{{.*}}/, dow_desc)
41
+ elsif expression.include?('L')
42
+ ', ' + resources.get('on_the_last_of_the_month')
43
+ else
44
+ ', ' + resources.get('only_on')
45
+ end
46
+ end
47
+
48
+ def starting_description_format(expression)
49
+ resources.get('starting') + ' ' + resources.get('on_x')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,23 @@
1
+ module Cronex
2
+ class HoursDescription < Description
3
+ def single_item_description(expression)
4
+ Cronex::Utils.format_time(expression, '0')
5
+ end
6
+
7
+ def interval_description_format(expression)
8
+ format(resources.get('every_x') + ' ' + plural(expression, resources.get('hour'), resources.get('hours')), expression)
9
+ end
10
+
11
+ def between_description_format(expression)
12
+ resources.get('between_x_and_y')
13
+ end
14
+
15
+ def description_format(expression)
16
+ resources.get('at_x')
17
+ end
18
+
19
+ def starting_description_format(expression)
20
+ resources.get('starting') + ' ' + description_format(expression)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module Cronex
2
+ class MinutesDescription < Description
3
+ def single_item_description(expression)
4
+ Cronex::Utils.format_minutes(expression)
5
+ end
6
+
7
+ def interval_description_format(expression)
8
+ format(resources.get('every_x') + ' ' + min_plural(expression), expression)
9
+ end
10
+
11
+ def between_description_format(expression)
12
+ resources.get('minutes_through_past_the_hour')
13
+ end
14
+
15
+ def description_format(expression)
16
+ expression == '0' ? '' : [resources.get('at_x'), min_plural(expression), resources.get('past_the_hour')].join(' ')
17
+ end
18
+
19
+ def starting_description_format(expression)
20
+ resources.get('starting') + ' ' + description_format(expression)
21
+ end
22
+
23
+ def min_plural(expression)
24
+ plural(expression, resources.get('minute'), resources.get('minutes'))
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Cronex
2
+ class MonthDescription < Description
3
+ def single_item_description(expression)
4
+ DateTime.new(Time.now.year, Integer(expression), 1).strftime('%B')
5
+ end
6
+
7
+ def interval_description_format(expression)
8
+ format(', ' + resources.get('every_x') + ' ' + plural(expression, resources.get('month'), resources.get('months')), expression)
9
+ end
10
+
11
+ def between_description_format(expression)
12
+ ', ' + resources.get('between_description_format')
13
+ end
14
+
15
+ def description_format(expression)
16
+ ', ' + resources.get('only_in')
17
+ end
18
+
19
+ def starting_description_format(expression)
20
+ resources.get('starting') + ' ' + resources.get('in_x')
21
+ end
22
+ end
23
+ end