schedule-dsl 0.0.1
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 +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +26 -0
- data/README.md +68 -0
- data/lib/schedule.rb +98 -0
- data/schedule-dsl.gemspec +11 -0
- data/spec/data/basic.rb +11 -0
- data/spec/data/empty.rb +0 -0
- data/spec/data/standard.rb +9 -0
- data/spec/schedule_spec.rb +63 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7b47e80c9c20de3922c89fec31755c1306f5d5b008f760eea5b67e3637d7e978
|
4
|
+
data.tar.gz: 802e2a55333f9a058951d6e15e679eeeb7092286525698a2fcff66efebf52780
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: adbc130c9ec66a7f5aa213a9f36e70f23a74f1e21681b3b91066fb9ae0e33fb6d48e7ee0582606c64886ce8d9ff0d6de3852f3ea5372a6538424b62f7d191163
|
7
|
+
data.tar.gz: 8f6b8a1f188bce244fb536aae111163614d02ebe3d277b814eb5af6fe9adb5b9882e38ebcb3b9087db9a18eb78ff639de1f6fd751456f53a9b32fd3694f47ebc
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.4.4)
|
5
|
+
rspec (3.10.0)
|
6
|
+
rspec-core (~> 3.10.0)
|
7
|
+
rspec-expectations (~> 3.10.0)
|
8
|
+
rspec-mocks (~> 3.10.0)
|
9
|
+
rspec-core (3.10.0)
|
10
|
+
rspec-support (~> 3.10.0)
|
11
|
+
rspec-expectations (3.10.0)
|
12
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
13
|
+
rspec-support (~> 3.10.0)
|
14
|
+
rspec-mocks (3.10.0)
|
15
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
16
|
+
rspec-support (~> 3.10.0)
|
17
|
+
rspec-support (3.10.0)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
rspec
|
24
|
+
|
25
|
+
BUNDLED WITH
|
26
|
+
2.1.4
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# About
|
2
|
+
|
3
|
+
_Provides a DSL for defining your schedule rules and getting results for given date._
|
4
|
+
|
5
|
+
# Examples
|
6
|
+
|
7
|
+
## Collect returned values
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# Your definition file.
|
11
|
+
|
12
|
+
rule Proc.new { true } do
|
13
|
+
"Go swimming"
|
14
|
+
end
|
15
|
+
|
16
|
+
rule Proc.new { false } do
|
17
|
+
"Steal things from little kids"
|
18
|
+
end
|
19
|
+
|
20
|
+
rule -> (date) { date.tuesday? } do
|
21
|
+
"Read a book"
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# Your script.
|
27
|
+
|
28
|
+
require 'schedule'
|
29
|
+
|
30
|
+
table = Schedule.load(definition_file_path)
|
31
|
+
table.filter(Date.today).evaluate
|
32
|
+
# => ["Go swimming", "Read a book"]
|
33
|
+
```
|
34
|
+
|
35
|
+
## Use a collector object
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# Your definition file.
|
39
|
+
|
40
|
+
rule -> (date) { date.tuesday? } do |time_frames|
|
41
|
+
time_frames[:morning] << "Go swimming"
|
42
|
+
end
|
43
|
+
|
44
|
+
rule -> (date) { date.weekday? } do |time_frames|
|
45
|
+
time_frames[:evening] << "Read a book"
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# Your script.
|
51
|
+
|
52
|
+
require 'schedule'
|
53
|
+
|
54
|
+
table = Schedule.load(definition_file_path)
|
55
|
+
time_frames = {morning: Array.new}
|
56
|
+
table.filter(Date.today).evaluate(time_frames) # Ignore the result.
|
57
|
+
time_frames # => {morning: "Go swimming"}
|
58
|
+
```
|
59
|
+
|
60
|
+
# API
|
61
|
+
|
62
|
+
## Custom `Date` extensions
|
63
|
+
|
64
|
+
Date passed as an argument to the condition is extended with `Schedule::DateExts`.
|
65
|
+
|
66
|
+
- `Date#weekend?`
|
67
|
+
- `Date#weekday?`
|
68
|
+
- `Date#last_day_of_a_month?`
|
data/lib/schedule.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Schedule
|
5
|
+
# Load schedule from definition file.
|
6
|
+
def self.load(path)
|
7
|
+
context = DSL.new
|
8
|
+
context.instance_eval(File.read(path), path)
|
9
|
+
context.rules
|
10
|
+
end
|
11
|
+
|
12
|
+
class RuleList
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
attr_reader :rules
|
16
|
+
def initialize
|
17
|
+
@rules = Array.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def_delegators :rules, :length, :first, :empty?, :<<
|
21
|
+
|
22
|
+
def filter(date)
|
23
|
+
FilteredRuleList.new(
|
24
|
+
date.extend(DateExts),
|
25
|
+
self.rules.select { |rule| rule.condition.call(date) })
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class FilteredRuleList
|
30
|
+
extend Forwardable
|
31
|
+
|
32
|
+
attr_reader :date, :rules
|
33
|
+
def initialize(date, rules)
|
34
|
+
@date, @rules = date, rules
|
35
|
+
end
|
36
|
+
|
37
|
+
def_delegators :rules, :length, :first, :empty?, :<<
|
38
|
+
|
39
|
+
# This method can be used in one of two ways:
|
40
|
+
#
|
41
|
+
# Either directly collect the results or pass a collection object,
|
42
|
+
# fill it in and then use that object directly rather than using
|
43
|
+
# the output of this method.
|
44
|
+
#
|
45
|
+
# # Collecting the results directly
|
46
|
+
#
|
47
|
+
# rule -> (date) { date.tuesday? } do
|
48
|
+
# "Go swimming"
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# list.evaluate # => ["Go swimming"]
|
52
|
+
#
|
53
|
+
# # Using a collection object
|
54
|
+
#
|
55
|
+
# rule -> (date) { date.tuesday? } do |time_frames|
|
56
|
+
# time_frames[:morning] << "Go swimming"
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# time_frames = {morning: Array.new}
|
60
|
+
# list.evaluate(time_frames) # Ignore the result.
|
61
|
+
# time_frames # => {morning: "Go swimming"}
|
62
|
+
def evaluate(*args)
|
63
|
+
self.rules.map { |rule| rule.block.call(*args) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Rule
|
68
|
+
attr_reader :condition, :block
|
69
|
+
def initialize(condition, &block)
|
70
|
+
@condition, @block = condition, block
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class DSL
|
75
|
+
attr_reader :rules
|
76
|
+
def initialize
|
77
|
+
@rules = RuleList.new
|
78
|
+
end
|
79
|
+
|
80
|
+
def rule(condition, &block)
|
81
|
+
self.rules << Rule.new(condition, &block)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module DateExts
|
86
|
+
def weekend?
|
87
|
+
self.saturday? || self.sunday?
|
88
|
+
end
|
89
|
+
|
90
|
+
def weekday?
|
91
|
+
!self.weekend?
|
92
|
+
end
|
93
|
+
|
94
|
+
def last_day_of_a_month?
|
95
|
+
self == Date.new(self.year, self.month, -1)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = 'schedule-dsl'
|
3
|
+
spec.version = '0.0.1'
|
4
|
+
spec.license = 'MIT' # Just so gem build would shut up. Use it however you like.
|
5
|
+
|
6
|
+
spec.summary = "Provides a DSL for defining your schedule rules and getting results for given date."
|
7
|
+
spec.author = "Jakub Šťastný"
|
8
|
+
spec.homepage = 'https://github.com/jakub-stastny/schedule-dsl'
|
9
|
+
|
10
|
+
spec.files = Dir["{lib,spec}/**/*.rb"] + ['Gemfile', 'Gemfile.lock', 'README.md', 'schedule-dsl.gemspec']
|
11
|
+
end
|
data/spec/data/basic.rb
ADDED
data/spec/data/empty.rb
ADDED
File without changes
|
@@ -0,0 +1,9 @@
|
|
1
|
+
rule -> (date) { date.tuesday? } do |time_frames|
|
2
|
+
time_frames[:morning] << "Go swimming"
|
3
|
+
end
|
4
|
+
|
5
|
+
# Date#weekday? is one of the custom date extensions
|
6
|
+
# defined in Schedule::DateExts.
|
7
|
+
rule -> (date) { date.weekday? } do |time_frames|
|
8
|
+
time_frames[:evening] << "Read a book"
|
9
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'schedule'
|
2
|
+
|
3
|
+
describe Schedule do
|
4
|
+
describe '.load(path)' do
|
5
|
+
it "loads an empty file and returns an empty definition table" do
|
6
|
+
expect(described_class.load('spec/data/empty.rb')).to be_empty
|
7
|
+
end
|
8
|
+
|
9
|
+
it "loads definitions from a file and returns the definition table" do
|
10
|
+
expect(described_class.load('spec/data/basic.rb')).not_to be_empty
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:date) do
|
15
|
+
Date.new(2020, 12, 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
context "basic rule list" do
|
19
|
+
let(:table) do
|
20
|
+
described_class.load('spec/data/basic.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#filter' do
|
24
|
+
it "returns a filtered list of rules which evaluated true for given date" do
|
25
|
+
expect(table.filter(date).length).to eql(2)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#evaluate' do
|
30
|
+
subject { table.filter(date) }
|
31
|
+
|
32
|
+
it "returns a list of outputs that were evaluated from each rule's block" do
|
33
|
+
expect(subject.evaluate).to eql(["Go swimming", "Read a book"])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "standard rule list" do
|
39
|
+
let(:time_frames) {{
|
40
|
+
morning: Array.new,
|
41
|
+
evening: Array.new
|
42
|
+
}}
|
43
|
+
|
44
|
+
let(:table) do
|
45
|
+
described_class.load('spec/data/standard.rb')
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#filter' do
|
49
|
+
it "returns a filtered list of rules which evaluated true for given date" do
|
50
|
+
expect(table.filter(date).length).to eql(2)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#evaluate' do
|
55
|
+
subject { table.filter(date) }
|
56
|
+
|
57
|
+
it "returns a list of outputs that were evaluated from each rule's block" do
|
58
|
+
subject.evaluate(time_frames)
|
59
|
+
expect(time_frames).to eql(morning: ["Go swimming"], evening: ["Read a book"])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: schedule-dsl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jakub Šťastný
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-12-03 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- Gemfile
|
20
|
+
- Gemfile.lock
|
21
|
+
- README.md
|
22
|
+
- lib/schedule.rb
|
23
|
+
- schedule-dsl.gemspec
|
24
|
+
- spec/data/basic.rb
|
25
|
+
- spec/data/empty.rb
|
26
|
+
- spec/data/standard.rb
|
27
|
+
- spec/schedule_spec.rb
|
28
|
+
homepage: https://github.com/jakub-stastny/schedule-dsl
|
29
|
+
licenses:
|
30
|
+
- MIT
|
31
|
+
metadata: {}
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubygems_version: 3.1.4
|
48
|
+
signing_key:
|
49
|
+
specification_version: 4
|
50
|
+
summary: Provides a DSL for defining your schedule rules and getting results for given
|
51
|
+
date.
|
52
|
+
test_files: []
|