blackcal 0.1.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,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c49267c5358fa204f01ff7dca6d054f9725ae17bf3d20217bb8fcad773cca9c1
4
+ data.tar.gz: f52d729090a6c7c7274219c4461516eddcbdb7e50ada790922c886bf767a4209
5
+ SHA512:
6
+ metadata.gz: 3632b757a25e37ff7b90833ccde7d2fe0cce9195aa4382d027265a234e35db828e4af1cfadddc71508ea0a3567d7cad6f02ac9a4805e0016effd6e8569c3de4d
7
+ data.tar.gz: 775091c9427f3655f319063a6eac010fff45004362ee9577504222a88905ffe31201d7d5a67d73586afc3d88dad3615c7dc311a91b1d2c3d59f0911956758e57
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ inherit_from: .ruby-style-guide.yml
2
+ AllCops:
3
+ UseCache: true
4
+ CacheRootDirectory: tmp
5
+ Exclude:
6
+ - 'tmp/*.rb'
@@ -0,0 +1,270 @@
1
+ Rails:
2
+ Enabled: false
3
+ AllCops:
4
+ TargetRubyVersion: 2.3
5
+ Exclude:
6
+ - "vendor/**/*"
7
+ UseCache: true
8
+ Style/CollectionMethods:
9
+ Description: Preferred collection methods.
10
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#map-find-select-reduce-size
11
+ Enabled: true
12
+ PreferredMethods:
13
+ collect: map
14
+ collect!: map!
15
+ find: detect
16
+ find_all: select
17
+ reduce: inject
18
+ Style/RedundantFreeze:
19
+ Description: "Checks usages of Object#freeze on immutable objects."
20
+ Enabled: false
21
+ Layout/DotPosition:
22
+ Description: Checks the position of the dot in multi-line method calls.
23
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains
24
+ Enabled: true
25
+ EnforcedStyle: trailing
26
+ SupportedStyles:
27
+ - leading
28
+ - trailing
29
+ Naming/FileName:
30
+ Description: Use snake_case for source file names.
31
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#snake-case-files
32
+ Enabled: false
33
+ Exclude: []
34
+ Naming/MemoizedInstanceVariableName:
35
+ Description: Memoized method name should match memo instance variable name.
36
+ Enabled: false
37
+ Naming/UncommunicativeMethodParamName:
38
+ Description: >-
39
+ Checks for method parameter names that contain capital letters,
40
+ end in numbers, or do not meet a minimal length.
41
+ Enabled: false
42
+ Style/AsciiComments:
43
+ Description: This cop checks for non-ascii (non-English) characters in comments.
44
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals
45
+ AllowedChars:
46
+ - å
47
+ - ä
48
+ - ö
49
+ Enabled: true
50
+ Style/GuardClause:
51
+ Description: Check for conditionals that can be replaced with guard clauses
52
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals
53
+ Enabled: true
54
+ MinBodyLength: 3
55
+ Style/IfUnlessModifier:
56
+ Description: Favor modifier if/unless usage when you have a single-line body.
57
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier
58
+ Enabled: false
59
+ Style/OptionHash:
60
+ Description: Don't use option hashes when you can use keyword arguments.
61
+ Enabled: false
62
+ Style/PercentLiteralDelimiters:
63
+ Description: Use `%`-literal delimiters consistently
64
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-literal-braces
65
+ Enabled: false
66
+ PreferredDelimiters:
67
+ "%": "()"
68
+ "%i": "()"
69
+ "%q": "()"
70
+ "%Q": "()"
71
+ "%r": "{}"
72
+ "%s": "()"
73
+ "%w": "()"
74
+ "%W": "()"
75
+ "%x": "()"
76
+ Naming/PredicateName:
77
+ Description: Check the names of predicate methods.
78
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark
79
+ Enabled: true
80
+ NamePrefix:
81
+ - is_
82
+ - has_
83
+ - have_
84
+ NamePrefixBlacklist:
85
+ - is_
86
+ Exclude:
87
+ - spec/**/*
88
+ Style/RaiseArgs:
89
+ Description: Checks the arguments passed to raise/fail.
90
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#exception-class-messages
91
+ Enabled: false
92
+ EnforcedStyle: exploded
93
+ SupportedStyles:
94
+ - compact
95
+ - exploded
96
+ Style/SignalException:
97
+ Description: Checks for proper usage of fail and raise.
98
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#fail-method
99
+ Enabled: false
100
+ EnforcedStyle: semantic
101
+ SupportedStyles:
102
+ - only_raise
103
+ - only_fail
104
+ - semantic
105
+ Style/SingleLineBlockParams:
106
+ Description: Enforces the names of some block params.
107
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#reduce-blocks
108
+ Enabled: false
109
+ Methods:
110
+ - reduce:
111
+ - a
112
+ - e
113
+ - inject:
114
+ - a
115
+ - e
116
+ Style/TrivialAccessors:
117
+ Enabled: false
118
+ Style/SingleLineMethods:
119
+ Description: Avoid single-line methods.
120
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-single-line-methods
121
+ Enabled: false
122
+ AllowIfMethodIsEmpty: true
123
+ Style/StringLiterals:
124
+ Description: Checks if uses of quotes match the configured preference.
125
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-string-literals
126
+ Enabled: true
127
+ EnforcedStyle: single_quotes
128
+ SupportedStyles:
129
+ - single_quotes
130
+ - double_quotes
131
+ Style/MixinUsage:
132
+ Enabled: true
133
+ Exclude:
134
+ - exe/*
135
+ Style/StringLiteralsInInterpolation:
136
+ Description: Checks if uses of quotes inside expressions in interpolated strings
137
+ match the configured preference.
138
+ Enabled: true
139
+ EnforcedStyle: single_quotes
140
+ SupportedStyles:
141
+ - single_quotes
142
+ - double_quotes
143
+ Style/TrailingCommaInArrayLiteral:
144
+ Description: Checks for trailing comma in parameter lists and literals.
145
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas
146
+ Enabled: true
147
+ EnforcedStyleForMultiline: comma
148
+ Style/TrailingCommaInHashLiteral:
149
+ Description: Checks for trailing comma in parameter lists and literals.
150
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas
151
+ Enabled: true
152
+ EnforcedStyleForMultiline: comma
153
+ Metrics/AbcSize:
154
+ Description: A calculated magnitude based on number of assignments, branches, and
155
+ conditions.
156
+ Enabled: false
157
+ Max: 15
158
+ Metrics/ClassLength:
159
+ Description: Avoid classes longer than 100 lines of code.
160
+ Enabled: false
161
+ CountComments: false
162
+ Max: 100
163
+ Metrics/ModuleLength:
164
+ CountComments: false
165
+ Max: 100
166
+ Description: Avoid modules longer than 100 lines of code.
167
+ Enabled: false
168
+ Metrics/CyclomaticComplexity:
169
+ Description: A complexity metric that is strongly correlated to the number of test
170
+ cases needed to validate a method.
171
+ Enabled: false
172
+ Max: 6
173
+ Metrics/MethodLength:
174
+ Description: Avoid methods longer than 10 lines of code.
175
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#short-methods
176
+ Enabled: false
177
+ CountComments: false
178
+ Max: 10
179
+ Metrics/ParameterLists:
180
+ Description: Avoid parameter lists longer than three or four parameters.
181
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#too-many-params
182
+ Enabled: false
183
+ Max: 5
184
+ CountKeywordArgs: true
185
+ Metrics/PerceivedComplexity:
186
+ Description: A complexity metric geared towards measuring complexity for a human
187
+ reader.
188
+ Enabled: false
189
+ Max: 7
190
+ Metrics/LineLength:
191
+ Description: Maximum line length
192
+ Enabled: true
193
+ Max: 95
194
+ Exclude:
195
+ - Gemfile
196
+ - blackcal.gemspec
197
+ - spec/**/*
198
+ Metrics/BlockLength:
199
+ Enabled: true
200
+ Exclude:
201
+ - spec/**/*
202
+ Lint/AssignmentInCondition:
203
+ Description: Don't use assignment in conditions.
204
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition
205
+ Enabled: false
206
+ AllowSafeAssignment: true
207
+ Style/InlineComment:
208
+ Description: Avoid inline comments.
209
+ Enabled: false
210
+ Naming/AccessorMethodName:
211
+ Description: Check the naming of accessor methods for get_/set_.
212
+ Enabled: false
213
+ Style/Alias:
214
+ Description: Use alias_method instead of alias.
215
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#alias-method
216
+ Enabled: false
217
+ Style/Documentation:
218
+ Description: Document classes and non-namespace modules.
219
+ Enabled: false
220
+ Style/DoubleNegation:
221
+ Description: Checks for uses of double negation (!!).
222
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-bang-bang
223
+ Enabled: false
224
+ Style/EachWithObject:
225
+ Description: Prefer `each_with_object` over `inject` or `reduce`.
226
+ Enabled: false
227
+ Style/EmptyLiteral:
228
+ Description: Prefer literals to Array.new/Hash.new/String.new.
229
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#literal-array-hash
230
+ Enabled: false
231
+ Style/ModuleFunction:
232
+ Description: Checks for usage of `extend self` in modules.
233
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#module-function
234
+ Enabled: false
235
+ Style/OneLineConditional:
236
+ Description: Favor the ternary operator(?:) over if/then/else/end constructs.
237
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#ternary-operator
238
+ Enabled: false
239
+ Style/PerlBackrefs:
240
+ Description: Avoid Perl-style regex back references.
241
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers
242
+ Enabled: false
243
+ Style/Send:
244
+ Description: Prefer `Object#__send__` or `Object#public_send` to `send`, as `send`
245
+ may overlap with existing methods.
246
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#prefer-public-send
247
+ Enabled: false
248
+ Style/SpecialGlobalVars:
249
+ Description: Avoid Perl-style global variables.
250
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms
251
+ Enabled: false
252
+ Style/VariableInterpolation:
253
+ Description: Don't interpolate global, instance and class variables directly in
254
+ strings.
255
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#curlies-interpolate
256
+ Enabled: false
257
+ Style/WhenThen:
258
+ Description: Use when x then ... for one-line cases.
259
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#one-line-cases
260
+ Enabled: false
261
+ Lint/EachWithObjectArgument:
262
+ Description: Check for immutable argument given to each_with_object.
263
+ Enabled: true
264
+ Lint/HandleExceptions:
265
+ Description: Don't suppress exception.
266
+ StyleGuide: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions
267
+ Enabled: false
268
+ Lint/LiteralInInterpolation:
269
+ Description: Checks for literals used in interpolation.
270
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ - 2.5.1
6
+ before_install: gem install bundler -v 1.16.2
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in blackcal.gemspec
8
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ blackcal (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ byebug (10.0.2)
10
+ diff-lcs (1.3)
11
+ rake (10.5.0)
12
+ rspec (3.8.0)
13
+ rspec-core (~> 3.8.0)
14
+ rspec-expectations (~> 3.8.0)
15
+ rspec-mocks (~> 3.8.0)
16
+ rspec-core (3.8.0)
17
+ rspec-support (~> 3.8.0)
18
+ rspec-expectations (3.8.1)
19
+ diff-lcs (>= 1.2.0, < 2.0)
20
+ rspec-support (~> 3.8.0)
21
+ rspec-mocks (3.8.0)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.8.0)
24
+ rspec-support (3.8.0)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ blackcal!
31
+ bundler (~> 1.16)
32
+ byebug
33
+ rake (~> 10.0)
34
+ rspec (~> 3.0)
35
+
36
+ BUNDLED WITH
37
+ 1.16.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Jacob Burenstam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Blackcal [![Build Status](https://travis-ci.com/buren/blackcal.svg?branch=master)](https://travis-ci.com/buren/blackcal)
2
+
3
+ Create blacklist rules for calendars with ease. Supports recurring rules for certain weekdays, date numbers, hour of day.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'blackcal'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install blackcal
20
+
21
+ ## Usage
22
+
23
+ Schedule Mondays and Tuesdays
24
+ ```ruby
25
+ schedule = Blackcal::Schedule.new(weekdays: [:monday, :tuesday])
26
+ schedule.cover?('2019-01-01 19:00')
27
+ # => false
28
+ schedule.cover?('2019-01-02 11:00')
29
+ # => true
30
+ ```
31
+
32
+ Schedule between 18pm and 7am every day
33
+ ```ruby
34
+ schedule = Blackcal::Schedule.new(start_hour: 18, finish_hour: 7)
35
+ schedule.cover?('2019-01-01 19:00')
36
+ # => false
37
+ schedule.cover?('2019-01-01 11:00')
38
+ # => true
39
+ ```
40
+
41
+ Schedule day 15 and 17 of month
42
+ ```ruby
43
+ schedule = Blackcal::Schedule.new(days: [15, 17])
44
+ schedule.cover?('2019-01-15 19:00')
45
+ # => false
46
+ schedule.cover?('2019-01-01 11:00')
47
+ # => true
48
+ ```
49
+
50
+ All options at once - schedule Tuesdays, day 15-25, between 18pm and 7am every day
51
+ ```ruby
52
+ schedule = Blackcal::Schedule.new(
53
+ weekdays: [:monday, :tuesday],
54
+ start_hour: 18, finish_hour: 7,
55
+ days: (15..25).to_a
56
+ )
57
+ schedule.cover?('2019-01-15 19:00')
58
+ # => false
59
+ schedule.cover?('2019-01-01 11:00')
60
+ # => true
61
+ ```
62
+
63
+ Define when the schedule is active
64
+ ```ruby
65
+ Blackcal::Schedule.new(start_time: '2018-01-01 11:00', finish_time: '2019-01-01 11:00')
66
+ ```
67
+
68
+ Matrix representation
69
+ ```ruby
70
+ schedule = Blackcal::Schedule.new(weekdays: :friday, start_hour: 10, finish_hour: 14)
71
+ schedule.to_matrix(start_date: '2018-09-14', finish_date: '2018-09-16')
72
+ # => [[true, ...], [true, ...]]
73
+ ```
74
+
75
+ ## Development
76
+
77
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
78
+
79
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
80
+
81
+ ## Contributing
82
+
83
+ Bug reports and pull requests are welcome on GitHub at https://github.com/buren/blackcal.
84
+
85
+ ## License
86
+
87
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'blackcal'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/blackcal.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'blackcal/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'blackcal'
9
+ spec.version = Blackcal::VERSION
10
+ spec.authors = ['Jacob Burenstam']
11
+ spec.email = ['burenstam@gmail.com']
12
+
13
+ spec.summary = 'Create blacklist rules for calendars with ease.'
14
+ spec.description = 'Create blacklist rules for calendars with ease. Supports recurring rules for certain weekdays, date numbers, hour of day.'
15
+ spec.homepage = 'https://github.com/buren/blackcal'
16
+ spec.license = 'MIT'
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = 'exe'
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ['lib']
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.16'
28
+ spec.add_development_dependency 'byebug'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.0'
31
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blackcal
4
+ # Number range
5
+ class DayRange
6
+ # @return [Array<Symbol>] numbers in range
7
+ attr_reader :numbers
8
+
9
+ # Initialize numbers range
10
+ # @param [Array<Integer>, Integer, nil] numbers
11
+ # @example
12
+ # NumberRange.new(1)
13
+ # @example
14
+ # NumberRange.new([1, 2])
15
+ def initialize(numbers)
16
+ @numbers = Array(numbers) if numbers
17
+ end
18
+
19
+ # Returns true if it covers timestamp
20
+ # @return [Boolean]
21
+ def cover?(timestamp)
22
+ return false if numbers.nil? || numbers.empty?
23
+
24
+ numbers.include?(timestamp.day)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ require 'blackcal/time_range'
6
+ require 'blackcal/time_of_day_range'
7
+ require 'blackcal/weekday_range'
8
+ require 'blackcal/day_range'
9
+ require 'blackcal/slot_matrix'
10
+
11
+ module Blackcal
12
+ # Represents a schedule
13
+ class Schedule
14
+ # Initialize rule
15
+ # @param start_time [Time, Date, String, nil]
16
+ # @param finish_time [Time, Date, String, nil]
17
+ # @param start_hour [Integer, nil]
18
+ # @param finish_hour [Integer, nil]
19
+ # @param weekdays [Array<String>, Array<Symbol>, String, Symbol, nil]
20
+ # @param days [Array<Integer>, Integer, nil]
21
+ def initialize(
22
+ start_time: nil,
23
+ finish_time: nil,
24
+ start_hour: nil,
25
+ finish_hour: nil,
26
+ weekdays: nil,
27
+ # weeks_of_month: nil, # TODO
28
+ days: nil
29
+ )
30
+ @rule_range = TimeRange.new(parse_time(start_time), parse_time(finish_time)) if start_time || finish_time # rubocop:disable Metrics/LineLength
31
+ @time_of_day = TimeOfDayRange.new(start_hour, finish_hour) if start_hour || finish_hour # rubocop:disable Metrics/LineLength
32
+ @weekdays = WeekdayRange.new(weekdays) if weekdays
33
+ @days = DayRange.new(days) if days
34
+ end
35
+
36
+ # Returns true if calendar is open for timestamp
37
+ # @param [Time] timestamp
38
+ # @return [Boolean]
39
+ def cover?(timestamp)
40
+ timestamp = parse_time(timestamp)
41
+ return true if @rule_range && !@rule_range.cover?(timestamp)
42
+
43
+ [@weekdays, @days, @time_of_day].each do |range|
44
+ return true if range && !range.cover?(timestamp)
45
+ end
46
+
47
+ false
48
+ end
49
+
50
+ # Returns schedule represented as a matrix
51
+ # @param start_date [Date]
52
+ # @param finish_date [Date]
53
+ # @return [Array<Array<Boolean>>]
54
+ def to_matrix(start_date:, finish_date:)
55
+ start_time = parse_time(start_date).to_time
56
+ finish_time = parse_time(finish_date).to_time
57
+ matrix = SlotMatrix.new(24)
58
+
59
+ # TODO: This is needlessly inefficient..
60
+ seconds = (start_time - finish_time).abs
61
+ hours = (seconds / (60 * 60)).to_i
62
+ hours.times { |hour| matrix << cover?(start_time + (hour * 60 * 60)) }
63
+
64
+ matrix.data
65
+ end
66
+
67
+ private
68
+
69
+ def parse_time(time)
70
+ return Time.parse(time) if time.is_a?(String)
71
+ time
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blackcal
4
+ class SlotMatrix
5
+ def initialize(slots)
6
+ @matrix = [[]]
7
+ @slots = slots
8
+ end
9
+
10
+ # @return [Array<Array<Object>>] data
11
+ def data
12
+ @matrix
13
+ end
14
+
15
+ # Add value
16
+ # @param [Object, nil] value
17
+ def <<(value)
18
+ array = @matrix[@matrix.length - 1] || []
19
+
20
+ # move to next slot when max slot length is reached
21
+ if array.length >= @slots
22
+ array = []
23
+ @matrix << array
24
+ end
25
+
26
+ array << value
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blackcal
4
+ # Time of day range
5
+ class TimeOfDayRange
6
+ # Initialize time of day range
7
+ def initialize(start, finish = nil)
8
+ @start = start || 0
9
+ @finish = finish || 0
10
+
11
+ @disallowed_hours = if @finish < @start
12
+ (@start..23).to_a + (0..@finish).to_a
13
+ else
14
+ (@start..@finish).to_a
15
+ end
16
+ end
17
+
18
+ # Returns true if it covers timestamp
19
+ # @return [Boolean]
20
+ def cover?(timestamp)
21
+ hour = timestamp.hour
22
+ # min = timestamp.min # TODO: Support minutes
23
+ @disallowed_hours.include?(hour)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blackcal
4
+ # Time range
5
+ class TimeRange
6
+ attr_reader :start, :finish
7
+
8
+ # Initialize time range
9
+ def initialize(start_time, finish_time = nil)
10
+ @start = start_time
11
+ @finish = finish_time
12
+ end
13
+
14
+ # Returns true if it covers timestamp
15
+ # @return [Boolean]
16
+ def cover?(timestamp)
17
+ return false if start.nil? && finish.nil?
18
+ return start < timestamp if finish.nil?
19
+ return finish > timestamp if start.nil?
20
+
21
+ return true if finish < timestamp
22
+ return true if start > timestamp
23
+
24
+ false
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blackcal
4
+ VERSION = '0.1.0'.freeze
5
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blackcal
4
+ # Weekday range
5
+ class WeekdayRange
6
+ WEEKDAY_MAP = {
7
+ sunday: 0,
8
+ monday: 1,
9
+ tuesday: 2,
10
+ wednesday: 3,
11
+ thursday: 4,
12
+ friday: 5,
13
+ saturday: 6,
14
+ }.freeze
15
+
16
+ # @return [Array<Symbol>] weekdays in range
17
+ attr_reader :weekdays
18
+
19
+ # Initialize weekday range
20
+ # @param [Array<String>, Array<Symbol>, String, Symbol, nil] weekdays
21
+ # @example
22
+ # WeekdayRange.new(:monday)
23
+ # @example
24
+ # WeekdayRange.new([:monday, :thursday])
25
+ def initialize(weekdays)
26
+ @weekdays = Array(weekdays).map(&:to_sym) if weekdays
27
+ end
28
+
29
+ # Returns true if it covers timestamp
30
+ # @return [Boolean]
31
+ def cover?(timestamp)
32
+ return false if @weekdays.nil? || @weekdays.empty?
33
+
34
+ weekdays.any? do |weekday|
35
+ WEEKDAY_MAP.fetch(weekday) == timestamp.wday
36
+ end
37
+ end
38
+ end
39
+ end
data/lib/blackcal.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'blackcal/version'
4
+ require 'blackcal/schedule'
5
+
6
+ # Main module
7
+ module Blackcal
8
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blackcal
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jacob Burenstam
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-09-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Create blacklist rules for calendars with ease. Supports recurring rules
70
+ for certain weekdays, date numbers, hour of day.
71
+ email:
72
+ - burenstam@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".rubocop.yml"
80
+ - ".ruby-style-guide.yml"
81
+ - ".travis.yml"
82
+ - Gemfile
83
+ - Gemfile.lock
84
+ - LICENSE.txt
85
+ - README.md
86
+ - Rakefile
87
+ - bin/console
88
+ - bin/setup
89
+ - blackcal.gemspec
90
+ - lib/blackcal.rb
91
+ - lib/blackcal/day_range.rb
92
+ - lib/blackcal/schedule.rb
93
+ - lib/blackcal/slot_matrix.rb
94
+ - lib/blackcal/time_of_day_range.rb
95
+ - lib/blackcal/time_range.rb
96
+ - lib/blackcal/version.rb
97
+ - lib/blackcal/weekday_range.rb
98
+ homepage: https://github.com/buren/blackcal
99
+ licenses:
100
+ - MIT
101
+ metadata: {}
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 2.7.6
119
+ signing_key:
120
+ specification_version: 4
121
+ summary: Create blacklist rules for calendars with ease.
122
+ test_files: []