Class: OnCalendar::Condition::Base
- Inherits:
-
Object
- Object
- OnCalendar::Condition::Base
- Defined in:
- lib/on_calendar/condition/base.rb
Instance Attribute Summary collapse
-
#base ⇒ Object
readonly
Returns the value of attribute base.
-
#step ⇒ Object
readonly
Returns the value of attribute step.
-
#wildcard ⇒ Object
readonly
Returns the value of attribute wildcard.
Class Method Summary collapse
-
.range_bounds ⇒ Object
Provide min / max of range for validation.
Instance Method Summary collapse
-
#distance_to_next(current, range_args: nil) ⇒ Object
Get next distance to valid base, if we rotate through range we get distance to min Note: We need to pass range_args becaue some subclasses need the context (ie: day_of_month).
-
#initialize(base: nil, step: nil, wildcard: false) ⇒ Base
constructor
A new instance of Base.
-
#match?(part) ⇒ Boolean
Match this condition - If wild card return true No step: - If within range true - Otherwise if base == argument With step: - Expand possible options to range.max does our argument match.
-
#range(clamp: nil) ⇒ Object
Some subclasses need more context for RANGE.
-
#valid?(value: nil) ⇒ Boolean
Validates whether value (if passed otherwise base) is acceptable Note: This is not context aware so you can pass it day 31 for a 30 day month and it will return true.
Constructor Details
#initialize(base: nil, step: nil, wildcard: false) ⇒ Base
Returns a new instance of Base.
8 9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/on_calendar/condition/base.rb', line 8 def initialize(base: nil, step: nil, wildcard: false) @base = base @step = step @wildcard = wildcard raise OnCalendar::Condition::Error, "Must supply base or wildcard=true" if base.nil? && !wildcard raise OnCalendar::Condition::Error, "Condition base value #{base} outside of allowed range #{range}" unless valid? raise OnCalendar::Condition::Error, "Condition step value #{step} must be > 0 and < than #{range.max}" if !step.nil? && (step == 0 || step > range.max) end |
Instance Attribute Details
#base ⇒ Object (readonly)
Returns the value of attribute base.
6 7 8 |
# File 'lib/on_calendar/condition/base.rb', line 6 def base @base end |
#step ⇒ Object (readonly)
Returns the value of attribute step.
6 7 8 |
# File 'lib/on_calendar/condition/base.rb', line 6 def step @step end |
#wildcard ⇒ Object (readonly)
Returns the value of attribute wildcard.
6 7 8 |
# File 'lib/on_calendar/condition/base.rb', line 6 def wildcard @wildcard end |
Class Method Details
.range_bounds ⇒ Object
Provide min / max of range for validation
27 28 29 |
# File 'lib/on_calendar/condition/base.rb', line 27 def self.range_bounds self.const_get(:RANGE).minmax end |
Instance Method Details
#distance_to_next(current, range_args: nil) ⇒ Object
Get next distance to valid base, if we rotate through range we get distance to min Note: We need to pass range_args becaue some subclasses need the context (ie: day_of_month)
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/on_calendar/condition/base.rb', line 71 def distance_to_next(current, range_args: nil) # If we have an invalid value no point continuing return nil unless valid?(value: current) # Wild card return +1 return 1 if wildcard # Build array to find needle_index arr = range(clamp: range_args).to_a needle_index = arr.index(current) return nil if needle_index.nil? # Default to increment value by 1 distance = 1 if step.nil? # If we are dealing with a range and the current and current+1 within range if base.is_a?(Range) if base.cover?(current) && base.cover?(arr.fetch(needle_index + 1, nil)) # Set +1 index target_index = needle_index + 1 else # Otherwise set the index of the minimum acceptable value target_index = arr.index(base.min) end else # Set index of base value target_index = arr.index(base) end # We have a step, we have to compare stepped array to get next distance otherwise min else # If base is range - we find the next value in base if base.is_a?(Range) stepped_arr = base.step(step).to_a next_value = stepped_arr.bsearch { |x| x > current } || base.min # Else we find next value in full RANGE else stepped_arr = (base..arr.max).step(step).to_a next_value = stepped_arr.bsearch { |x| x > current } || arr.min end target_index = arr.index(next_value) end # Lets work out distance between target_index and needle_index if !target_index.nil? && needle_index < target_index # If the needle is before target get how many steps we need to step distance = target_index - needle_index else # If is in front of us loop over until start of array # Note: This sounds counter intuitive - why not give the distance until the next value # However this forces us to re-evaluate all other date parts otherwise we might jump forward too far distance = arr.length - needle_index end distance end |
#match?(part) ⇒ Boolean
Match this condition
-
If wild card return true
No step:
- If within range true
- Otherwise if base == argument
With step:
- Expand possible options to range.max
does our argument match
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/on_calendar/condition/base.rb', line 39 def match?(part) return true if wildcard if step.nil? return base.cover?(part) if base.is_a?(Range) base == part else (base.is_a?(Range) ? base : (base..range.max)).step(step).to_a.include?(part) end end |
#range(clamp: nil) ⇒ Object
Some subclasses need more context for RANGE
22 23 24 |
# File 'lib/on_calendar/condition/base.rb', line 22 def range(clamp: nil) self.class::RANGE end |
#valid?(value: nil) ⇒ Boolean
Validates whether value (if passed otherwise base) is acceptable Note: This is not context aware so you can pass it day 31 for a 30 day month and it will return true
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/on_calendar/condition/base.rb', line 53 def valid?(value: nil) # Always yes for wildcard when value isn't supplied return true if wildcard && value.nil? value ||= base case value when Range # Check range is within RANGE return true if range.cover?(value) else # Check value is within RANGE return true if range.include?(value) end false end |