### Interactive Console Source: https://github.com/rossta/montrose/blob/main/README.md Start an interactive Ruby console session for experimenting with the gem. ```bash bin/console ``` -------------------------------- ### Install Montrose Gem Source: https://github.com/rossta/montrose/blob/main/README.md Add the gem to your Gemfile and install it via bundle or directly. ```ruby gem "montrose" ``` ```bash $ bundle ``` ```bash $ gem install montrose ``` -------------------------------- ### Global Configuration Source: https://context7.com/rossta/montrose/llms.txt Set global defaults for recurrence options and ActiveSupport week start settings. ```ruby # Set default start time Montrose::Options.default_starts = -> { Time.current.beginning_of_day } # Set default end time Montrose::Options.default_until = -> { 1.year.from_now } # Set default frequency Montrose::Options.default_every = :day # Now recurrences use defaults Montrose.r.take(3) # Uses default frequency :day # Configure ActiveSupport beginning of week Date.beginning_of_week = :sunday # or :monday # In Rails config # config/application.rb config.beginning_of_week = :monday ``` -------------------------------- ### Define Monthly Recurrences Source: https://context7.com/rossta/montrose/llms.txt Examples of configuring monthly schedules using specific days, weekdays, or dates. ```ruby # Specific day of month Montrose.monthly(mday: 15, total: 3).map { |t| t.day } # => [15, 15, 15] # Multiple days of month including negative (from end) Montrose.monthly(mday: [1, -1], total: 4).map { |t| "#{t.month}/#{t.day}" } # => ["1/1", "1/31", "2/1", "2/29"] # Nth weekday of month (1st Friday) Montrose.monthly(day: { friday: [1] }, total: 3) .map { |t| t.strftime("%Y-%m-%d") } # => ["2024-01-05", "2024-02-02", "2024-03-01"] # First and last Sunday of month Montrose.monthly(day: { sunday: [1, -1] }, total: 4) .map { |t| t.strftime("%b %d") } # => ["Jan 07", "Jan 28", "Feb 04", "Feb 25"] # Friday the 13th Montrose.monthly(on: { friday: 13 }, total: 3) .map { |t| t.strftime("%Y-%m-%d") } # => ["2024-09-13", "2024-12-13", "2025-06-13"] ``` -------------------------------- ### Update Installed Gems Source: https://github.com/rossta/montrose/blob/main/README.md Update all installed gems for the gemfiles in the project using the provided script. ```bash bin/update ``` -------------------------------- ### Common Recurrence Usage Patterns Source: https://github.com/rossta/montrose/blob/main/README.md Examples of various recurrence configurations including daily, weekly, monthly, and yearly schedules with specific constraints. ```ruby require "montrose" # a new recurrence Montrose.r Montrose.recurrence Montrose::Recurrence.new # daily for 10 occurrences Montrose.daily(total: 10) # daily until December 23, 2015 starts = Date.new(2015, 1, 1) ends = Date.new(2015, 12, 23) Montrose.daily(starts: starts, until: ends) # every other day forever Montrose.daily(interval: 2) # every 10 days 5 occurrences Montrose.every(10.days, total: 5) # everyday in January for 3 years starts = Time.current.beginning_of_year ends = Time.current.end_of_year + 2.years Montrose.daily(month: :january, between: starts...ends) # weekly for 10 occurrences Montrose.weekly(total: 10) # weekly until December 23, 2015 ends_on = Date.new(2015, 12, 23) starts_on = ends_on - 15.weeks Montrose.every(:week, until: ends_on, starts: starts_on) # every other week forever Montrose.every(2.weeks) # weekly on Tuesday and Thursday for five weeks # from September 1, 2015 until October 5, 2015 Montrose.weekly(on: [:tuesday, :thursday], between: Date.new(2015, 9, 1)..Date.new(2015, 10, 5)) # every other week on Monday, Wednesday and Friday until December 23 2015, # but starting on Tuesday, September 1, 2015 Montrose.every(2.weeks, on: [:monday, :wednesday, :friday], starts: Date.new(2015, 9, 1)) # every other week on Tuesday and Thursday, for 8 occurrences Montrose.weekly(on: [:tuesday, :thursday], total: 8, interval: 2) # monthly on the first Friday for ten occurrences Montrose.monthly(day: { friday: [1] }, total: 10) # monthly on the first Friday until December 23, 2015 Montrose.every(:month, day: { friday: [1] }, until: Date.new(2016, 12, 23)) # every other month on the first and last Sunday of the month for 10 occurrences Montrose.every(:month, day: { sunday: [1, -1] }, interval: 2, total: 10) # monthly on the second-to-last Monday of the month for 6 months Montrose.every(:month, day: { monday: [-2] }, total: 6) # monthly on the third-to-the-last day of the month, forever Montrose.every(:month, mday: [-3]) # monthly on the 2nd and 15th of the month for 10 occurrences Montrose.every(:month, mday: [2, 15], total: 10) # monthly on the first and last day of the month for 10 occurrences Montrose.monthly(mday: [1, -1], total: 10) # every 18 months on the 10th thru 15th of the month for 10 occurrences Montrose.every(18.months, total: 10, mday: 10..15) # every Tuesday, every other month Montrose.every(2.months, on: :tuesday) # yearly in June and July for 10 occurrences Montrose.yearly(month: [:june, :july], total: 10) # every other year on January, February, and March for 10 occurrences Montrose.every(2.years, month: [:january, :february, :march], total: 10) # every third year on the 1st, 100th and 200th day for 10 occurrences Montrose.yearly(yday: [1, 100, 200], total: 10) # every 20th Monday of the year, forever Montrose.yearly(day: { monday: [20] }) # Monday of week number 20 forever Montrose.yearly(week: [20], on: :monday) # every Thursday in March, forever Montrose.monthly(month: :march, on: :thursday, at: "12 pm") # every Thursday, but only during June, July, and August, forever" do Montrose.monthly(month: 6..8, on: :thursday) # every Friday 13th, forever Montrose.monthly(on: { friday: 13 }) # first Saturday that follows the first Sunday of the month, forever Montrose.monthly(on: { saturday: 7..13 }) # every four years, the first Tuesday after a Monday in November, forever (U.S. Presidential Election day) Montrose.every(4.years, month: :november, on: { tuesday: 2..8 }) # every 3 hours from 9:00 AM to 5:00 PM on a specific day date = Date.new(2016, 9, 1) Montrose.hourly(between: date..(date+1), hour: 9..17, interval: 3) # every hour and a half for four occurrences Montrose.every(90.minutes, total: 4) # every 20 minutes from 9:00 AM to 4:40 PM every day Montrose.every(20.minutes, hour: 9..16) ``` -------------------------------- ### Apply Date Range Constraints Source: https://context7.com/rossta/montrose/llms.txt Use 'between', 'covering', 'starting', and 'ending' to bound recurrences to specific date ranges. ```ruby # Between date range (sets starts and until) start_date = Date.new(2024, 1, 1) end_date = Date.new(2024, 1, 31) Montrose.weekly(on: :monday, between: start_date..end_date) .map { |t| t.strftime("%Y-%m-%d") } # => ["2024-01-01", "2024-01-08", "2024-01-15", "2024-01-22", "2024-01-29"] # Covering (masking) - only emit events within range Montrose.weekly .starting(Date.new(2023, 12, 1)) .covering(Date.new(2024, 1, 10)..Date.new(2024, 1, 20)) .take(5) .map { |t| t.strftime("%Y-%m-%d") } # => ["2024-01-12", "2024-01-19"] # only events in covering range # Explicit start and end Montrose.daily .starting(Date.new(2024, 1, 15)) .ending(Date.new(2024, 1, 20)) .to_a .map { |t| t.day } # => [15, 16, 17, 18, 19, 20] # Everyday in January for 3 years starts = Time.current.beginning_of_year ends = Time.current.end_of_year + 2.years Montrose.daily(month: :january, between: starts...ends).count # => 93 # 31 days * 3 years ``` -------------------------------- ### Define daily recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Create daily recurrences with options for specific start times, intervals, or total counts. ```ruby Montrose.daily Montrose.every(:day) Montrose.r(every: :day) ``` ```ruby Montrose.every(9.days) Montrose.r(every: 9.days) Montrose.r(every: :day, interval: 9) ``` ```ruby Montrose.daily(at: "9:00 AM") Montrose.every(:day, at: "9:00 AM") Montrose.r(every: :day, at: "9:00 AM") ``` ```ruby Montrose.daily(total: 7) Montrose.every(:day, total: 7) Montrose.r(every: :day, total: 7) ``` -------------------------------- ### Run All Tests Source: https://github.com/rossta/montrose/blob/main/README.md Execute all tests across all gemfiles for the current Ruby version using the provided script. ```bash bin/spec ``` -------------------------------- ### Create Recurrences with Frequency Methods Source: https://context7.com/rossta/montrose/llms.txt Use convenience methods like minutely, hourly, daily, weekly, monthly, and yearly to define common recurrence patterns. ```ruby require "montrose" # Minutely recurrence every 15 minutes for 4 occurrences minutely = Montrose.minutely(interval: 15, total: 4) minutely.to_a # => [2024-01-15 10:00:00 -0500, 2024-01-15 10:15:00 -0500, # 2024-01-15 10:30:00 -0500, 2024-01-15 10:45:00 -0500] # Hourly recurrence with specific start time hourly = Montrose.hourly(starts: Time.parse("2024-01-15 09:00"), total: 3) hourly.to_a # => [2024-01-15 09:00:00, 2024-01-10:00:00, 2024-01-15 11:00:00] # Daily recurrence at specific time daily = Montrose.daily(at: "9:00 AM", total: 5) daily.take(3) # => [2024-01-15 09:00:00, 2024-01-16 09:00:00, 2024-01-17 09:00:00] # Weekly recurrence on specific days weekly = Montrose.weekly(on: [:monday, :wednesday, :friday], total: 6) weekly.map(&:strftime).take(6) # => ["Mon", "Wed", "Fri", "Mon", "Wed", "Fri"] # Monthly recurrence on specific day of month monthly = Montrose.monthly(mday: [1, 15], total: 4) monthly.map { |t| t.strftime("%b %d") } # => ["Jan 01", "Jan 15", "Feb 01", "Feb 15"] # Yearly recurrence in specific months yearly = Montrose.yearly(month: [:june, :december], total: 4) yearly.map { |t| t.strftime("%Y-%m") } # => ["2024-06", "2024-12", "2025-06", "2025-12"] ``` -------------------------------- ### Configure ActiveSupport settings Source: https://github.com/rossta/montrose/blob/main/README.md Adjust global date settings that affect how Montrose calculates weekly recurrences. ```ruby Date.beginning_of_the_week = :sunday # OR Date.beginning_of_the_week = :monday ``` ```ruby config.beginning_of_week = :sunday # OR config.beginning_of_week = :monday ``` -------------------------------- ### Define Generic Frequencies with every Source: https://context7.com/rossta/montrose/llms.txt The every method supports arbitrary frequencies and ActiveSupport duration objects for flexible scheduling. ```ruby # Every 2 days Montrose.every(:day, interval: 2, total: 3).to_a # => [2024-01-15, 2024-01-17, 2024-01-19] # Using ActiveSupport duration Montrose.every(2.weeks, total: 3).to_a # => [2024-01-15, 2024-01-29, 2024-02-12] # Every 90 minutes for 4 occurrences Montrose.every(90.minutes, total: 4).to_a # => [2024-01-15 10:00:00, 2024-01-15 11:30:00, # 2024-01-15 13:00:00, 2024-01-15 14:30:00] # Every 10 days with custom start Montrose.every(10.days, starts: Date.new(2024, 1, 1), total: 3).to_a # => [2024-01-01, 2024-01-11, 2024-01-21] # Every 4 years on specific month and day (US Presidential Election) Montrose.every(4.years, month: :november, on: { tuesday: 2..8 }, total: 3) .map { |t| t.strftime("%Y-%m-%d") } # => ["2024-11-05", "2028-11-07", "2032-11-02"] ``` -------------------------------- ### Apply Time-of-Day Constraints Source: https://context7.com/rossta/montrose/llms.txt Use 'at' for specific times and 'during' for time ranges to constrain events within a day. ```ruby # At specific time Montrose.daily(at: "9:00 AM", total: 3) .map { |t| t.strftime("%H:%M") } # => ["09:00", "09:00", "09:00"] # Multiple times per day Montrose.daily(at: ["9:00 AM", "5:00 PM"], total: 4) .map { |t| t.strftime("%H:%M") } # => ["09:00", "17:00", "09:00", "17:00"] # During time range (9am to 5pm) Montrose.every(20.minutes).during("9am-5pm").take(5) .map { |t| t.strftime("%H:%M") } # => ["09:00", "09:20", "09:40", "10:00", "10:20"] # Multiple time ranges Montrose.every(30.minutes).during("9am-12pm", "1pm-5pm").take(8) .map { |t| t.strftime("%H:%M") } # => ["09:00", "09:30", "10:00", "10:30", "11:00", "11:30", "13:00", "13:30"] # Using time range objects time = Time.current Montrose.every(20.minutes) .during(time.change(hour: 9)..time.change(hour: 17)) .take(3) # Using hour, min, sec tuples Montrose.every(20.minutes).during([9, 0, 0], [17, 0, 0]).take(3) ``` -------------------------------- ### Apply Day and Date Constraints Source: https://context7.com/rossta/montrose/llms.txt Use methods like on, day_of_week, day_of_month, and day_of_year to filter recurrence occurrences. ```ruby # Specific weekdays Montrose.daily.on(:saturday).total(3).map(&:wday) # => [6, 6, 6] # Saturday # Multiple weekdays Montrose.daily.day_of_week(:monday, :wednesday, :friday).total(6) .map { |t| t.strftime("%a") } ``` -------------------------------- ### Chain recurrence methods Source: https://github.com/rossta/montrose/blob/main/README.md Combine multiple configuration methods to refine recurrence rules. ```ruby Montrose.weekly.starting(3.weeks.from_now).on(:friday) Montrose.every(:day).at("4:05pm") Montrose.yearly.between(Time.current..10.years.from_now) ``` -------------------------------- ### Enumerating Recurrences Source: https://context7.com/rossta/montrose/llms.txt Demonstrates basic event enumeration and lazy evaluation for infinite recurrence patterns. ```ruby # Get events enumerator r = Montrose.daily r.events # => # r.events.take(5) # => [time1, time2, time3, time4, time5] # Lazy enumeration for infinite recurrences (required!) Montrose.daily .lazy .select { |t| t.day > 25 } .take(3) .to_a # => [Jan 26, Jan 27, Jan 28] # Complex lazy pipeline Montrose.hourly .events .lazy .select { |time| time.hour.between?(9, 17) } .take(8) .map { |t| t.strftime("%H:%M") } .to_a # => ["09:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00"] ``` -------------------------------- ### Apply Month and Week Constraints Source: https://context7.com/rossta/montrose/llms.txt Filter recurrences by specific months or weeks of the year. ```ruby # Specific months Montrose.daily(month: [:january, :july], total: 5) .map { |t| t.strftime("%b %d") } # => ["Jan 15", "Jan 16", "Jan 17", "Jan 18", "Jan 19"] # Month range Montrose.monthly(month: 6..8, on: :thursday, total: 6) .map { |t| t.strftime("%b %d") } # => ["Jun 06", "Jun 13", "Jul 04", "Jul 11", "Aug 01", "Aug 08"] # Week of year Montrose.yearly(week: [1, 26, 52], on: :monday, total: 3) .map { |t| t.strftime("%Y week %W") } # => ["2024 week 01", "2024 week 26", "2024 week 52"] # 20th Monday of year Montrose.yearly(day: { monday: [20] }, total: 3) .map { |t| t.strftime("%Y-%m-%d") } # => ["2024-05-13", "2025-05-19", "2026-05-18"] ``` -------------------------------- ### ActiveRecord Serialization Source: https://context7.com/rossta/montrose/llms.txt Integrate Montrose schedules into ActiveRecord models using the serialize method. ```ruby class CalendarEntry < ApplicationRecord serialize :schedule, Montrose::Schedule end entry = CalendarEntry.new entry.schedule = Montrose::Schedule.build do |s| s << Montrose.daily(at: "9am") s << Montrose.weekly(on: :friday, at: "4pm") end entry.save! ``` -------------------------------- ### Define weekly recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Create weekly recurrences with specific days of the week and optional time settings. ```ruby Montrose.weekly Montrose.every(:week) Montrose.r(every: :week) ``` ```ruby Montrose.every(:week, on: :monday) Montrose.every(:week, on: [:monday, :wednesday, :friday]) Montrose.every(2.weeks, on: :friday) Montrose.every(:week, on: :friday, at: "3:41 PM") Montrose.weekly(on: :thursday) ``` -------------------------------- ### Parsing iCal RRULE Source: https://context7.com/rossta/montrose/llms.txt Interoperate with calendar systems by parsing iCal RRULE strings. ```ruby # Parse iCal RRULE ical = <<~ICAL DTSTART;TZID=America/New_York:20240115T090000 RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10 ICAL recurrence = Montrose::Recurrence.from_ical(ical) recurrence.take(3).map { |t| t.strftime("%a %Y-%m-%d") } # => ["Mon 2024-01-15", "Wed 2024-01-17", "Fri 2024-01-19"] # Complex iCal rule ical = "RRULE:FREQ=MONTHLY;BYDAY=1FR;COUNT=6" Montrose::Recurrence.from_ical(ical).take(3) # => First Friday of each month for 6 occurrences # iCal with UNTIL ical = "DTSTART:20240101T100000\nRRULE:FREQ=DAILY;UNTIL=20240110T100000" Montrose::Recurrence.from_ical(ical).count # => 10 # iCal with exclusions ical = <<~ICAL DTSTART:20240101 RRULE:FREQ=DAILY;COUNT=10 EXDATE:20240105 ICAL Montrose::Recurrence.from_ical(ical).map(&:day) # => [1, 2, 3, 4, 6, 7, 8, 9, 10, 11] # 5 excluded ``` -------------------------------- ### Checking Event Inclusion Source: https://context7.com/rossta/montrose/llms.txt Use include? to verify if a specific timestamp falls within a recurrence pattern or range. ```ruby # Check if date is in recurrence recurrence = Montrose.weekly(on: :friday) recurrence.include?(Date.new(2024, 1, 19)) # => true (Friday) recurrence.include?(Date.new(2024, 1, 20)) # => false (Saturday) # Check with time precision recurrence = Montrose.daily(at: "9:00 AM") recurrence.include?(Time.parse("2024-01-15 09:00:00")) # => true recurrence.include?(Time.parse("2024-01-15 10:00:00")) # => false # Check finite recurrence r = Montrose.daily(starts: "2024-01-01", until: "2024-01-31") r.include?(Date.new(2024, 1, 15)) # => true r.include?(Date.new(2024, 2, 15)) # => false (outside range) # Finite vs infinite r = Montrose.daily(total: 10) r.finite? # => true r.infinite? # => false r = Montrose.daily r.finite? # => false r.infinite? # => true ``` -------------------------------- ### Define monthly recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Create monthly recurrences based on specific days of the month or specific weekdays. ```ruby Montrose.monthly(mday: 1) # first of the month Montrose.every(:month, mday: 1) Montrose.r(every: :month, mday: 1) ``` ```ruby Montrose.monthly(mday: [2, 15]) # 2nd and 15th of the month Montrose.monthly(mday: -3) # third-to-last day of the month Montrose.monthly(mday: 10..15) # 10th through the 15th day of the month ``` ```ruby Montrose.monthly(day: :friday, interval: 2) # every Friday every other month Montrose.every(:month, day: :friday, interval: 2) Montrose.r(every: :month, day: :friday, interval: 2) ``` ```ruby Montrose.monthly(day: { friday: [1] }) # 1st Friday of the month Montrose.monthly(day: { sunday: [1, -1] }) # first and last Sunday of the month ``` ```ruby Montrose.monthly(mday: 7..13, day: :saturday) # first Saturday that follow the first Sunday of the month ``` -------------------------------- ### Handle Infinite Recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Be cautious with infinite sequences when using Enumerable methods. ```ruby # Every day starting now r = Montrose.daily # this expression will never complete, Ctrl-c! r.map(&:to_date) ``` -------------------------------- ### Define minutely recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Create recurrences that repeat every minute or at specific intervals. ```ruby Montrose.minutely Montrose.r(every: :minute) ``` ```ruby Montrose.every(10.minutes) Montrose.r(every: 10.minutes) Montrose.r(every: :minute, interval: 10) # every 10 minutes ``` ```ruby Montrose.minutely(until: "9:00 PM") Montrose.r(every: :minute, until: "9:00 PM") ``` -------------------------------- ### Serializing Recurrences Source: https://context7.com/rossta/montrose/llms.txt Convert recurrence rules to and from Hash, JSON, and YAML for persistence. ```ruby # To hash recurrence = Montrose.every(:week, on: :monday, at: "9:00 AM") recurrence.to_hash # => {:every=>:week, :on=>:monday, :at=>[[9, 0, 0]]} # From hash opts = { every: :day, interval: 2, total: 5 } Montrose::Recurrence.new(opts).take(3) # => [day1, day3, day5] # To JSON recurrence = Montrose.daily(at: "10:00 AM", total: 5) json = recurrence.to_json # => '{"every":"day","at":[[10,0,0]],"total":5}' # From JSON Montrose::Recurrence.from_json(json).take(2) # => [time1, time2] # To YAML yaml = recurrence.to_yaml # => "---\nevery: day\nat:\n- - 10\n - 0\n - 0\ntotal: 5\n" # From YAML Montrose::Recurrence.from_yaml(yaml).take(2) # => [time1, time2] # Schedule serialization schedule = Montrose::Schedule.build do |s| s << { every: :day } s << { every: :week, on: :friday } end schedule.to_json # => '[{"every":"day"},{"every":"week","day":[5]}]' ``` -------------------------------- ### Define Recurrence with Hash Syntax Source: https://github.com/rossta/montrose/blob/main/README.md Use the hash-based syntax for defining recurrence rules. ```ruby Montrose.r(every: :week, on: :monday, at: "10:30 am") => # ``` -------------------------------- ### Define time-of-day ranges Source: https://github.com/rossta/montrose/blob/main/README.md Specify time-of-day constraints for a recurrence using strings, Ruby time ranges, or hour/minute/second tuples. ```ruby r = Montrose.every(20.minutes) r.during("9am-4:40pm") # as semantic time-of-day range OR r.during(time.change(hour: 9)..time.change(hour: 4: min: 40)) # as ruby time range OR r.during([9, 0, 0], [16, 40, 0]) # as hour, min, sec tuple pairs for start, end ``` ```ruby Montrose.every(20.minutes).during("9am-12pm", "1pm-5pm") ``` -------------------------------- ### Recurrence Dump and Load Source: https://context7.com/rossta/montrose/llms.txt Convert recurrence objects to and from JSON strings for storage or transmission. ```ruby json = Montrose::Recurrence.dump(recurrence) # => JSON string recurrence = Montrose::Recurrence.load(json) # => Recurrence object ``` -------------------------------- ### Fix Lint Errors Source: https://github.com/rossta/montrose/blob/main/README.md Automatically fix linting errors in the project using the StandardRB tool. ```bash bin/standardrb --fix ``` -------------------------------- ### Define yearly recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Create yearly recurrences with specific months, days, or day-of-year offsets. ```ruby Montrose.yearly Montrose.every(:year) Montrose.r(every: :year) ``` ```ruby Montrose.yearly(month: [:june, :july]) # yearly in June and July Montrose.yearly(month: 6..8, day: :thursday) # yearly in June, July, August on Thursday Montrose.yearly(yday: [1, 100]) # yearly on the 1st and 100th day of year ``` ```ruby Montrose.yearly(on: { january: 31 }) Montrose.r(every: :year, on: { 10 => 31 }, interval: 3) ``` -------------------------------- ### Handling Missing Frequency Errors Source: https://github.com/rossta/montrose/blob/main/README.md A frequency must be specified for a recurrence to be valid; otherwise, a ConfigurationError is raised. ```ruby r = Montrose.at("12pm") => # r.each Montrose::ConfigurationError: Please specify the :every option ``` -------------------------------- ### Serialize Montrose::Schedule with ActiveRecord Source: https://github.com/rossta/montrose/blob/main/README.md Use the `serialize` method in your ActiveRecord model to store `Montrose::Schedule` objects in a single database column. Ensure the `Montrose::Schedule` class is available. ```ruby class RecurringEvent < ApplicationRecord serialize :recurrence, Montrose::Schedule end ``` -------------------------------- ### Enumerate Events Source: https://context7.com/rossta/montrose/llms.txt Recurrences support standard Ruby Enumerable methods. ```ruby # Basic enumeration recurrence = Montrose.daily(total: 5) recurrence.each { |time| puts time } # Take specific number Montrose.hourly.take(3) # => [time1, time2, time3] # Map over events Montrose.weekly(on: :friday, total: 4).map(&:to_date) ``` -------------------------------- ### Generate Event Timestamps Source: https://github.com/rossta/montrose/blob/main/README.md Use the #events method to return an Enumerator for generating timestamps. ```ruby r = Montrose.hourly => # r.events => # r.events.take(10) => [2016-02-03 18:26:08 -0500, 2016-02-03 19:26:08 -0500, 2016-02-03 20:26:08 -0500, 2016-02-03 21:26:08 -0500, 2016-02-03 22:26:08 -0500, 2016-02-03 23:26:08 -0500, 2016-02-04 00:26:08 -0500, 2016-02-04 01:26:08 -0500, 2016-02-04 02:26:08 -0500, 2016-02-04 03:26:08 -0500] ``` -------------------------------- ### Enumerate and merge events Source: https://github.com/rossta/montrose/blob/main/README.md Iterate over generated events or merge additional rules into an existing recurrence. ```ruby r = Montrose.every(:month, mday: 31, until: "January 1, 2017") r.each { |time| puts time.to_s } r.take(10).to_a ``` ```ruby r.merge(starts: "2017-01-01").each { |time| puts time.to_s } ``` ```ruby r.events # => # r.events.take(10).each { |date| puts date.to_s } r.events.lazy.select { |time| time > 1.month.from_now }.take(3).each { |date| puts date.to_s } ``` -------------------------------- ### Combine multiple recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Use Montrose::Schedule to aggregate multiple recurrence rules into a single stream of events. ```ruby recurrence_1 = Montrose.monthly(day: { friday: [1] }) recurrence_2 = Montrose.weekly(on: :tuesday) schedule = Montrose::Schedule.build do |s| s << recurrence_1 s << recurrence_2 end # add after building s << Montrose.yearly ``` ```ruby schedule = Montrose::Schedule.build do |s| s << { day: { friday: [1] } } s << { on: :tuesday } end ``` ```ruby schedule.events # => # schedule.each do |event| puts event end ``` -------------------------------- ### Compose Recurrences via Method Chaining Source: https://context7.com/rossta/montrose/llms.txt Chain methods to build complex, immutable recurrence objects or merge multiple rules together. ```ruby # Build recurrence through chaining recurrence = Montrose.weekly .on(:monday) .at("10:30 am") .starting(Date.new(2024, 1, 1)) .ending(Date.new(2024, 3, 31)) recurrence.take(5).map { |t| t.strftime("%Y-%m-%d %H:%M") } # => ["2024-01-01 10:30", "2024-01-08 10:30", "2024-01-15 10:30", # "2024-01-22 10:30", "2024-01-29 10:30"] # Chain with specific days and time Montrose.every(:week) .on([:tuesday, :thursday]) .at("12:00 pm") .total(4) .to_a # => [Tue 12:00, Thu 12:00, Tue 12:00, Thu 12:00] # Merge multiple recurrences r1 = Montrose.every(:week) r2 = Montrose.on([:tuesday, :thursday]) r3 = Montrose.at("12 pm") combined = r1.merge(r2).merge(r3).total(4) combined.to_a # => [Tue 12:00, Thu 12:00, Tue 12:00, Thu 12:00] # Using hash syntax Montrose.r(every: :week, on: :monday, at: "10:30 am", total: 3).to_a # => [Mon 10:30, Mon 10:30, Mon 10:30] ``` -------------------------------- ### Serialize Recurrence to Hash Source: https://github.com/rossta/montrose/blob/main/README.md Convert a recurrence object to a hash and back to maintain state or configuration. ```ruby opts = Montrose::Recurrence.new(every: 10.minutes).to_h => {:every=>:minute, :interval=>10} Montrose::Recurrence.new(opts).take(3) => [2016-02-03 19:06:07 -0500, 2016-02-03 19:16:07 -0500, 2016-02-03 19:26:07 -0500] ``` -------------------------------- ### Create Recurrence Objects Source: https://github.com/rossta/montrose/blob/main/README.md Define recurring events using method chaining. ```ruby # Every Monday at 10:30am Montrose.weekly.on(:monday).at("10:30 am") => # ``` -------------------------------- ### Serialize Montrose::Recurrence with ActiveRecord Source: https://github.com/rossta/montrose/blob/main/README.md Use the `serialize` method in your ActiveRecord model to store `Montrose::Recurrence` objects in a single database column. Ensure the `Montrose::Recurrence` class is available. ```ruby class RecurringEvent < ApplicationRecord serialize :recurrence, Montrose::Recurrence end ``` -------------------------------- ### Define Yearly Recurrences Source: https://context7.com/rossta/montrose/llms.txt Configuring yearly schedules based on specific days of the year. ```ruby # Day of year Montrose.yearly(yday: [1, 100, 200], total: 3) .map { |t| t.strftime("%Y day %j") } # => ["2024 day 001", "2024 day 100", "2024 day 200"] ``` -------------------------------- ### Combining Multiple Recurrences with Schedule Source: https://context7.com/rossta/montrose/llms.txt Montrose::Schedule allows merging multiple recurrence rules into a single enumerable stream. ```ruby # Build schedule with block schedule = Montrose::Schedule.build do |s| s << Montrose.monthly(day: { friday: [1] }) # 1st Friday s << Montrose.weekly(on: :tuesday) # Every Tuesday end schedule.take(10).map { |t| t.strftime("%a %b %d") } # => Merged stream of both recurrences in chronological order # Add recurrences after building schedule = Montrose::Schedule.new schedule << { every: :day, at: "9am" } schedule << { every: :week, on: :friday, at: "5pm" } schedule.add(Montrose.yearly(month: :december, mday: 25)) # Enumerate schedule events schedule.events.take(5).each { |event| puts event } # Schedule is enumerable schedule.each do |event| puts event break if event > 1.month.from_now end # Check inclusion across all rules schedule.include?(Time.parse("2024-01-19 09:00")) # true if any rule matches ``` -------------------------------- ### Integrating with Rails ActiveRecord Source: https://context7.com/rossta/montrose/llms.txt Use Montrose::Recurrence as a serializer for ActiveRecord model attributes. ```ruby # Model with serialized recurrence class Event < ApplicationRecord serialize :recurrence, Montrose::Recurrence end # Create and save event = Event.new(name: "Weekly Standup") event.recurrence = Montrose.weekly(on: :monday, at: "9:00 AM") event.save! # Retrieve and enumerate event = Event.find(1) event.recurrence.take(5).each do |time| puts "Meeting at #{time}" end ``` -------------------------------- ### Exclude Specific Dates Source: https://context7.com/rossta/montrose/llms.txt Use 'except' to skip specific dates or arrays of dates from the recurrence. ```ruby # Exclude specific date Montrose.daily(total: 5) .except(Date.new(2024, 1, 17)) .starting(Date.new(2024, 1, 15)) .map { |t| t.day } # => [15, 16, 18, 19, 20] # 17 is skipped # Exclude multiple dates holidays = [Date.new(2024, 1, 1), Date.new(2024, 1, 15)] Montrose.daily(starts: Date.new(2024, 1, 1), total: 5) .except(holidays) .map { |t| t.day } # => [2, 3, 4, 5, 6] # Jan 1 and 15 excluded # Exclude with array syntax Montrose.daily .except("2024-01-20", "2024-01-21") .starting("2024-01-18") .take(5) .map { |t| t.day } # => [18, 19, 22, 23, 24] ``` -------------------------------- ### Enumerate Recurrence Dates Source: https://github.com/rossta/montrose/blob/main/README.md Recurrence objects are enumerable and can be mapped to dates. ```ruby # Every month starting a year from now on Friday the 13th for 5 occurrences r = Montrose.monthly.starting(1.year.from_now).on(friday: 13).repeat(5) r.map(&:to_date) => [Fri, 13 Oct 2017, Fri, 13 Apr 2018, Fri, 13 Jul 2018, Fri, 13 Sep 2019, Fri, 13 Dec 2019] ``` -------------------------------- ### Compose and Merge Recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Recurrence objects are immutable; chaining or merging returns a new object. ```ruby # Example 1 - building recurrence in succession r1 = Montrose.every(:week) r2 = r1.on([:tuesday, :thursday]) r3 = r2.at("12 pm") r4 = r3.total(4) # Example 2 - merging distinct recurrences r1 = Montrose.every(:week) r2 = Montrose.on([:tuesday, :thursday]) r3 = Montrose.at("12 pm") r4 = r1.merge(r2).merge(r3).total(4) ``` -------------------------------- ### Lazy Enumeration of Recurrences Source: https://github.com/rossta/montrose/blob/main/README.md Use the lazy enumerator to efficiently process large or infinite recurrence sequences. ```ruby r.lazy.map(&:to_date).select { |d| d.mday > 25 }.take(5).to_a ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.