Решение на Седма задача от Димитър Узунов

Обратно към всички решения

Към профила на Димитър Узунов

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 27 успешни тест(а)
  • 4 неуспешни тест(а)

Код

module LazyMode
extend self
DATE_PARSER = /(\d{4})-(\d\d)-(\d\d)( \+(\d+)([mwd]))?/
def create_file(file_name)
File.new(file_name).instance_eval &Proc.new
end
end
class LazyMode::Note
attr_reader :header, :tags, :file_name
attr_accessor :date
def initialize(header, tags, file_name, file)
@header = header
@tags = tags
@file_name = file_name
@file = file
@body = ''
@status = :topostpone
end
def body(content = nil)
content ? @body = content : @body
end
def status(type = nil)
type ? @status = type : @status
end
def scheduled_on_date?(date)
@dates.take_while { |current_date| current_date <= date }.last == date
end
private
def scheduled(date_string)
date = LazyMode::Date.new(date_string)
date_parts = LazyMode::DATE_PARSER.match date_string
count = date_parts[5].to_i
type = date_parts[6]
@dates = LazyMode::DateEnumerator.new(date, count, type)
end
def note(header, *tags)
new_note = LazyMode::Note.new(header, tags, @file_name, @file)
new_note.instance_eval &Proc.new
@file.notes << new_note
@file
end
end
class LazyMode::File
attr_reader :name, :notes
def initialize(name, notes = [])
@name = name
@notes = notes
end
def daily_agenda(date)
notes = @notes.select { |note| note.scheduled_on_date?(date) }
notes = notes.each { |note| note.date = date }
LazyMode::File.new("#{@name}-#{date.to_s}", notes)
end
def weekly_agenda(date)
agenda = LazyMode::File.new("#{@name}-#{date.to_s}-weekly")
dates = LazyMode::DateEnumerator.new(date, 1, 'd')
dates.take(7).each { |date| agenda.notes.concat(daily_agenda(date).notes) }
agenda
end
def where(tag: nil, text: //, status: nil)
notes = @notes.dup
notes = filter_notes_by_tag(notes, tag) if tag
notes = filter_notes_by_status(notes, status) if status
notes = filter_notes_by_text(notes, text)
LazyMode::File.new("#{@name}-where", notes)
end
private
def note(header, *tags)
new_note = LazyMode::Note.new(header, tags, @name, self)
new_note.instance_eval &Proc.new
@notes << new_note
self
end
def filter_notes_by_tag(notes, tag)
notes.select { |note| note.tags.include? tag }
end
def filter_notes_by_status(notes, status)
notes.select { |note| note.status == status }
end
def filter_notes_by_text(notes, text)
notes.select { |note| text.match note.header or text.match note.body }
end
end
class LazyMode::Date
include Comparable
attr_reader :year, :month, :day
def initialize(date_string)
date_parts = LazyMode::DATE_PARSER.match date_string
@year = date_parts[1].to_i
@month = date_parts[2].to_i
@day = date_parts[3].to_i
@date_string = date_string
end
def self.construct(year, month, day)
year = year.to_s.rjust(4, '0')
month = month.to_s.rjust(2, '0')
day = day.to_s.rjust(2, '0')
new("#{year}-#{month}-#{day}")
end
def to_s
@date_string
end
def <=>(other)
if @year == other.year
compare_months(other)
else
@year <=> other.year
end
end
private
def compare_months(other)
@month == other.month ? @day <=> other.day : @month <=> other.month
end
end
class LazyMode::DateEnumerator < Enumerator
def initialize(date, count, type)
@date = date
@count = count
@type = type
end
def each
case @type
when 'm' then each_months &Proc.new
when 'w' then each_weeks &Proc.new
when 'd' then each_days &Proc.new
else yield @date
end
end
private
def add_months_to_date(count, date)
year = date.year + ((date.month - 1) + count) / 12
month = ((date.month - 1) + count) % 12 + 1
LazyMode::Date.construct(year, month, date.day)
end
def add_days_to_date(count, date)
date = add_months_to_date(((date.day - 1) + count) / 30, date)
day = ((date.day - 1) + count) % 30 + 1
LazyMode::Date.construct(date.year, date.month, day)
end
def each_months
current_date = @date
loop do
yield current_date
current_date = add_months_to_date(@count, current_date)
end
end
def each_weeks
days_in_weeks = @count * 7
current_date = @date
loop do
yield current_date
current_date = add_days_to_date(days_in_weeks, current_date)
end
end
def each_days
current_date = @date
loop do
yield current_date
current_date = add_days_to_date(@count, current_date)
end
end
end

Лог от изпълнението

..............F....FF........F.

Failures:

  1) LazyMode#daily_agenda returns note scheduled with weekly repeater
     Failure/Error: scheduled '2012-12-5 +1w'
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:118:in `initialize'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:39:in `new'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:39:in `scheduled'
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:166:in `block (5 levels) in <top (required)>'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:92:in `instance_eval'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:92:in `note'
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:165:in `block (4 levels) in <top (required)>'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:7:in `instance_eval'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:7:in `create_file'
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:164:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) LazyMode#weekly_agenda returns multiple notes with different dates when scheduled with daily repeater
     Failure/Error: expect(agenda.notes.map(&:date).map(&:day)).to match_array([11, 12])
       expected collection contained:  [11, 12]
       actual collection contained:    [12, 12]
       the missing elements were:      [11]
       the extra elements were:        [12]
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:280:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) LazyMode#weekly_agenda returns note scheduled with weekly repeater
     Failure/Error: scheduled '2012-12-5 +1w'
     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:118:in `initialize'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:39:in `new'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:39:in `scheduled'
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:286:in `block (5 levels) in <top (required)>'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:92:in `instance_eval'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:92:in `note'
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:285:in `block (4 levels) in <top (required)>'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:7:in `instance_eval'
     # /tmp/d20160107-5693-1jb1xm6/solution.rb:7:in `create_file'
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:284:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) LazyMode.create_file can assign name to files
     Failure/Error: expect(file.name).to eq('important_notes_and_todos')
     NoMethodError:
       undefined method `name' for nil:NilClass
     # /tmp/d20160107-5693-1jb1xm6/spec.rb:460:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.02208 seconds
31 examples, 4 failures

Failed examples:

rspec /tmp/d20160107-5693-1jb1xm6/spec.rb:163 # LazyMode#daily_agenda returns note scheduled with weekly repeater
rspec /tmp/d20160107-5693-1jb1xm6/spec.rb:259 # LazyMode#weekly_agenda returns multiple notes with different dates when scheduled with daily repeater
rspec /tmp/d20160107-5693-1jb1xm6/spec.rb:283 # LazyMode#weekly_agenda returns note scheduled with weekly repeater
rspec /tmp/d20160107-5693-1jb1xm6/spec.rb:456 # LazyMode.create_file can assign name to files

История (1 версия и 0 коментара)

Димитър обнови решението на 20.12.2015 22:48 (преди около 9 години)

+module LazyMode
+ extend self
+
+ DATE_PARSER = /(\d{4})-(\d\d)-(\d\d)( \+(\d+)([mwd]))?/
+
+ def create_file(file_name)
+ File.new(file_name).instance_eval &Proc.new
+ end
+end
+
+class LazyMode::Note
+ attr_reader :header, :tags, :file_name
+ attr_accessor :date
+
+ def initialize(header, tags, file_name, file)
+ @header = header
+ @tags = tags
+ @file_name = file_name
+ @file = file
+ @body = ''
+ @status = :topostpone
+ end
+
+ def body(content = nil)
+ content ? @body = content : @body
+ end
+
+ def status(type = nil)
+ type ? @status = type : @status
+ end
+
+ def scheduled_on_date?(date)
+ @dates.take_while { |current_date| current_date <= date }.last == date
+ end
+
+ private
+
+ def scheduled(date_string)
+ date = LazyMode::Date.new(date_string)
+ date_parts = LazyMode::DATE_PARSER.match date_string
+ count = date_parts[5].to_i
+ type = date_parts[6]
+ @dates = LazyMode::DateEnumerator.new(date, count, type)
+ end
+
+ def note(header, *tags)
+ new_note = LazyMode::Note.new(header, tags, @file_name, @file)
+ new_note.instance_eval &Proc.new
+ @file.notes << new_note
+
+ @file
+ end
+end
+
+class LazyMode::File
+ attr_reader :name, :notes
+
+ def initialize(name, notes = [])
+ @name = name
+ @notes = notes
+ end
+
+ def daily_agenda(date)
+ notes = @notes.select { |note| note.scheduled_on_date?(date) }
+ notes = notes.each { |note| note.date = date }
+
+ LazyMode::File.new("#{@name}-#{date.to_s}", notes)
+ end
+
+ def weekly_agenda(date)
+ agenda = LazyMode::File.new("#{@name}-#{date.to_s}-weekly")
+
+ dates = LazyMode::DateEnumerator.new(date, 1, 'd')
+ dates.take(7).each { |date| agenda.notes.concat(daily_agenda(date).notes) }
+
+ agenda
+ end
+
+ def where(tag: nil, text: //, status: nil)
+ notes = @notes.dup
+ notes = filter_notes_by_tag(notes, tag) if tag
+ notes = filter_notes_by_status(notes, status) if status
+ notes = filter_notes_by_text(notes, text)
+
+ LazyMode::File.new("#{@name}-where", notes)
+ end
+
+ private
+
+ def note(header, *tags)
+ new_note = LazyMode::Note.new(header, tags, @name, self)
+ new_note.instance_eval &Proc.new
+ @notes << new_note
+
+ self
+ end
+
+ def filter_notes_by_tag(notes, tag)
+ notes.select { |note| note.tags.include? tag }
+ end
+
+ def filter_notes_by_status(notes, status)
+ notes.select { |note| note.status == status }
+ end
+
+ def filter_notes_by_text(notes, text)
+ notes.select { |note| text.match note.header or text.match note.body }
+ end
+end
+
+class LazyMode::Date
+ include Comparable
+
+ attr_reader :year, :month, :day
+
+ def initialize(date_string)
+ date_parts = LazyMode::DATE_PARSER.match date_string
+ @year = date_parts[1].to_i
+ @month = date_parts[2].to_i
+ @day = date_parts[3].to_i
+ @date_string = date_string
+ end
+
+ def self.construct(year, month, day)
+ year = year.to_s.rjust(4, '0')
+ month = month.to_s.rjust(2, '0')
+ day = day.to_s.rjust(2, '0')
+
+ new("#{year}-#{month}-#{day}")
+ end
+
+ def to_s
+ @date_string
+ end
+
+ def <=>(other)
+ if @year == other.year
+ compare_months(other)
+ else
+ @year <=> other.year
+ end
+ end
+
+ private
+
+ def compare_months(other)
+ @month == other.month ? @day <=> other.day : @month <=> other.month
+ end
+end
+
+class LazyMode::DateEnumerator < Enumerator
+ def initialize(date, count, type)
+ @date = date
+ @count = count
+ @type = type
+ end
+
+ def each
+ case @type
+ when 'm' then each_months &Proc.new
+ when 'w' then each_weeks &Proc.new
+ when 'd' then each_days &Proc.new
+ else yield @date
+ end
+ end
+
+ private
+
+ def add_months_to_date(count, date)
+ year = date.year + ((date.month - 1) + count) / 12
+ month = ((date.month - 1) + count) % 12 + 1
+
+ LazyMode::Date.construct(year, month, date.day)
+ end
+
+ def add_days_to_date(count, date)
+ date = add_months_to_date(((date.day - 1) + count) / 30, date)
+ day = ((date.day - 1) + count) % 30 + 1
+
+ LazyMode::Date.construct(date.year, date.month, day)
+ end
+
+ def each_months
+ current_date = @date
+ loop do
+ yield current_date
+ current_date = add_months_to_date(@count, current_date)
+ end
+ end
+
+ def each_weeks
+ days_in_weeks = @count * 7
+ current_date = @date
+ loop do
+ yield current_date
+ current_date = add_days_to_date(days_in_weeks, current_date)
+ end
+ end
+
+ def each_days
+ current_date = @date
+ loop do
+ yield current_date
+ current_date = add_days_to_date(@count, current_date)
+ end
+ end
+end