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.
@@ -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
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group(:spec) do
4
+ gem 'rspec'
5
+ end
@@ -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
@@ -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?`
@@ -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
@@ -0,0 +1,11 @@
1
+ rule Proc.new { true } do
2
+ "Go swimming"
3
+ end
4
+
5
+ rule Proc.new { false } do
6
+ "Steal things from little kids"
7
+ end
8
+
9
+ rule -> (date) { date.tuesday? } do
10
+ "Read a book"
11
+ end
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: []