Class: StoreHours::StoreHours
- Inherits:
-
Object
- Object
- StoreHours::StoreHours
- Defined in:
- lib/store_hours.rb
Overview
A very simple parser to parse text like
Mon-Fri: 9AM-5PM
Sat: 10AM-7PM
Sun: closed
and build an internal data structure to enable possible formatting and queries.
This class is designed to use when (1) you like to use a single text field in database to store open hours, and (2) you would like to be able to check whether the store opens for a certain time, or to make sure inputs are valid, or to display the hours in a format different from user input (for example, take plain text from users, but to format the input in html to display).
Here is an example about how to use this class in rails. Suppose you have a model called “Store” with a text filed named normal_business_hours, you can add this validation method:
validate :normal_business_hours_must_be_in_valid_format
def normal_business_hours_must_be_in_valid_format
hours_parser = ::StoreHours::StoreHours.new
#check whether input is valid?
success, = hours_parser.from_text(self.normal_business_hours)
if !success
#input is not valid
errors.add(:normal_business_hours, )
end
end
Please refer to text_input_parser.rb and tree_transformer.rb to get some idea of what kinds of inputs are valid.
Instance Method Summary collapse
-
#from_text(text) ⇒ Boolean, String
Try to parse the input text.
-
#initialize ⇒ StoreHours
constructor
A new instance of StoreHours.
- #is_open?(t) ⇒ Boolean
-
#to_text ⇒ Object
This is the method you can use to display store hours.
Constructor Details
#initialize ⇒ StoreHours
Returns a new instance of StoreHours.
43 44 45 |
# File 'lib/store_hours.rb', line 43 def initialize @hours = [] end |
Instance Method Details
#from_text(text) ⇒ Boolean, String
Try to parse the input text. the return value will be [false, “error message”]
This method will build the internal data structure for valid text argument.
Please don’t ignore the return value from this method as it is the only way to know whether input is valid.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/store_hours.rb', line 57 def from_text(text) text = '' if text == nil result = true = '' begin # parse the text into an intermediary tree # this call may raise Parslet::ParseFailed exception tree = TextInputParser.new.parse(text.strip.downcase) # convert the tree into internal data structure # please refer to tree_transformer.rb for the details of this structure # this call may raise StoreHours::SemanticError exception @hours = TreeTransformer.new.apply(tree) result = true rescue Parslet::ParseFailed => e puts e.cause.ascii_tree puts e.cause. puts text[0..e.cause.source.chars_left] result = false = "syntax error: input is not in correct format" rescue ::StoreHours::SemanticError => e puts e. result = false = e. end return [result, ] end |
#is_open?(t) ⇒ Boolean
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/store_hours.rb', line 117 def is_open?(t) @hours.each do |days_table| # days_table in the format of range(wday..wday) => [range(minutes..minutes),...] # only one key in the hash table days = days_table.keys.first if days.include?(t.wday == 0 ? 7 : t.wday) days_table[days].each do |min_range| minutes = t.hour * 60 + t.min if min_range.include?(minutes) return true end end end end return false end |
#to_text ⇒ Object
This is the method you can use to display store hours.
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 |
# File 'lib/store_hours.rb', line 91 def to_text text = '' @hours.each do |days_table| days = days_table.keys.first #days is the day range, for example, (1..5) if block_given? text += yield NUM_TO_WEEKDAY[days.first], NUM_TO_WEEKDAY[days.last], days_table[days] else text += NUM_TO_WEEKDAY[days.first].to_s text += "-" + NUM_TO_WEEKDAY[days.last].to_s if days.first != days.last text += ": " days_table[days].each_with_index do |minutes, index| text += ', ' if index > 0 if minutes.first == -1 #closed days text += "closed" elsif text += ::StoreHours::from_minutes_to_time_str(minutes.first) + " - " + ::StoreHours::from_minutes_to_time_str(minutes.last) end end text += "\n" end end text.strip end |