Решение на Седма задача от Станимир Богданов

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

Към профила на Станимир Богданов

Резултати

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

Код

module LazyMode
class Date
attr_reader :year, :month, :day, :date_string
def initialize(date_string)
@date_string = date_string
@year, @month, @day = date_string.split('-').map(&:to_i)
end
alias_method :to_s, :date_string
def add_day
@day += 1
if @day > 30
@day = 1
add_month
end
construct_new
end
def add_month
@month += 1
if @month > 12
@month = 1
@year += 1
end
construct_new
end
def add_week
7.times { add_day }
construct_new
end
private
def construct_new
Date.new("#{@year.to_s.rjust(4, '0')}-#{@month.to_s.rjust(2, '0')}-"\
"#{@day.to_s.rjust(2, '0')}")
end
end
class NoteBuilder
def initialize(header, tags, file_name, &block)
@header = header
@tags = tags
@file_name = file_name
@sub_notes = []
instance_eval(&block)
end
def status(value)
@status = value
end
def body(value)
@body = value
end
def scheduled(date)
@scheduled, @repeat = date.split
end
def note(header, *tags, &block)
note = Note.new(header, tags, @file_name, &block)
@sub_notes << note
note
end
def build
set_defaults
self
end
private
def set_defaults
@status ||= :topostpone
@body ||= ''
end
end
class Repeater
def initialize(start_date, period, frequency)
@date = Date.new(start_date)
@method_name = ('add_' + period).to_sym
@frequency = frequency
end
def repeats_before(date)
while @date.to_s <= date.to_s
yield @date
increment_date
end
end
private
def increment_date
@frequency.to_i.times { @date = @date.public_send(@method_name) }
end
end
class Note
attr_reader :header, :body, :status, :tags, :file_name, :sub_notes
def initialize(header, tags, file_name, &block)
note_builder = NoteBuilder.new(header, tags, file_name, &block).build
note_builder.instance_variables.each do |instance_variable|
value = note_builder.instance_variable_get(instance_variable)
instance_variable_set(instance_variable, value)
end
end
def repeats(date)
number, repeater, scale = @repeat.chars.drop(1)
case repeater
when 'd' then scale = 'day'
when 'w' then scale = 'week'
when 'm' then scale = 'month'
end
Repeater.new(@scheduled, scale, number).enum_for(:repeats_before, date)
end
def scheduled?(date)
@repeat ? scheduled_repeat?(date) : (date.to_s == @scheduled)
end
private
def scheduled_repeat?(date)
repeats(date).any? { |repeat| repeat.to_s == date.to_s }
end
end
class Agenda
attr_accessor :notes
def where(**kwargs)
copy = clone
notes = filter_by_tag(copy.notes, kwargs[:tag])
notes = filter_by_text(notes, kwargs[:text])
notes = filter_by_status(notes, kwargs[:status])
copy.notes = notes
copy
end
def filter_by_tag(notes, tag)
return notes unless tag
notes.select { |note| note.tags.include?(tag) }
end
def filter_by_text(notes, text)
return notes unless text
notes.select { |note| note.header =~ text }
end
def filter_by_status(notes, status)
return notes unless status
notes.select { |note| note.status == status }
end
private
def get_all_notes(list_of_notes)
notes = []
queue = list_of_notes.clone
until queue.empty?
notes << queue.first
add_sub_notes(queue, queue.shift)
end
notes
end
def add_sub_notes(queue, note)
note.sub_notes.each do |sub_note|
queue << sub_note
end
end
def add_if_scheduled_for_day(note, day)
if note.scheduled?(day)
@notes << build_agenda_item(note, day)
end
end
def build_agenda_item(note, date)
item = note.clone
item.define_singleton_method(:date) do
date
end
item
end
end
class DailyAgenda < Agenda
def initialize(date, notes)
@notes = []
@date = date
get_all_notes(notes).each do |note|
add_if_scheduled_for_day(note, date)
end
end
def where
end
end
class WeeklyAgenda < Agenda
def initialize(date, notes)
@notes = []
@week = get_week(date)
@date = date
get_all_notes(notes).each do |note|
add_if_scheduled_for_week(note)
end
end
def add_if_scheduled_for_week(note)
@week.each do |day|
add_if_scheduled_for_day(note, day)
end
end
private
def get_week(date)
7.times.each_with_object([]) do |_, week|
week << date
date = date.add_day
end
end
end
class File
attr_reader :name, :notes
def initialize(file_name)
@name = file_name
@notes = []
end
def note(header, *tags, &block)
note = Note.new(header, tags, @name, &block)
@notes << note
note
end
def daily_agenda(date)
DailyAgenda.new(date, @notes)
end
def weekly_agenda(date)
WeeklyAgenda.new(date, @notes)
end
end
def self.create_file(file_name, &block)
file = File.new(file_name)
file.instance_eval(&block)
file
end
end

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

..............F...FFFF..FFFFF..

Failures:

  1) LazyMode#daily_agenda returns note scheduled with weekly repeater
     Failure/Error: expect(agenda.notes.size).to eq(1)
       
       expected: 1
            got: 0
       
       (compared using ==)
     # /tmp/d20160107-5693-1at6wv2/spec.rb:175: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 note scheduled without repeater
     Failure/Error: expect(note.date.day).to eq(12)
       
       expected: 12
            got: 13
       
       (compared using ==)
     # /tmp/d20160107-5693-1at6wv2/spec.rb:256: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 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, 13]
       the missing elements were:      [11]
       the extra elements were:        [13]
     # /tmp/d20160107-5693-1at6wv2/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)>'

  4) LazyMode#weekly_agenda returns note scheduled with weekly repeater
     Failure/Error: expect(agenda.notes.size).to eq(2)
       
       expected: 2
            got: 1
       
       (compared using ==)
     # /tmp/d20160107-5693-1at6wv2/spec.rb:295: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)>'

  5) LazyMode#weekly_agenda returns note scheduled with monthly repeater
     Failure/Error: expect(note.date.day).to eq(12)
       
       expected: 12
            got: 13
       
       (compared using ==)
     # /tmp/d20160107-5693-1at6wv2/spec.rb:334: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)>'

  6) LazyMode#where filters by tag
     Failure/Error: notes = @agenda.where(tag: :important).notes
     ArgumentError:
       wrong number of arguments (1 for 0)
     # /tmp/d20160107-5693-1at6wv2/solution.rb:206:in `where'
     # /tmp/d20160107-5693-1at6wv2/spec.rb:391: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)>'

  7) LazyMode#where filters by body text
     Failure/Error: notes = @agenda.where(text: /Very/).notes
     ArgumentError:
       wrong number of arguments (1 for 0)
     # /tmp/d20160107-5693-1at6wv2/solution.rb:206:in `where'
     # /tmp/d20160107-5693-1at6wv2/spec.rb:409: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)>'

  8) LazyMode#where filters by header text
     Failure/Error: notes = @agenda.where(text: /not important/).notes
     ArgumentError:
       wrong number of arguments (1 for 0)
     # /tmp/d20160107-5693-1at6wv2/solution.rb:206:in `where'
     # /tmp/d20160107-5693-1at6wv2/spec.rb:421: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)>'

  9) LazyMode#where filters by status
     Failure/Error: notes = @agenda.where(status: :postponed).notes
     ArgumentError:
       wrong number of arguments (1 for 0)
     # /tmp/d20160107-5693-1at6wv2/solution.rb:206:in `where'
     # /tmp/d20160107-5693-1at6wv2/spec.rb:433: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)>'

  10) LazyMode#where filters by multiple filters
     Failure/Error: notes = @agenda.where(text: /important/, status: :postponed).notes
     ArgumentError:
       wrong number of arguments (1 for 0)
     # /tmp/d20160107-5693-1at6wv2/solution.rb:206:in `where'
     # /tmp/d20160107-5693-1at6wv2/spec.rb:444: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.02026 seconds
31 examples, 10 failures

Failed examples:

rspec /tmp/d20160107-5693-1at6wv2/spec.rb:163 # LazyMode#daily_agenda returns note scheduled with weekly repeater
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:237 # LazyMode#weekly_agenda returns note scheduled without repeater
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:259 # LazyMode#weekly_agenda returns multiple notes with different dates when scheduled with daily repeater
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:283 # LazyMode#weekly_agenda returns note scheduled with weekly repeater
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:315 # LazyMode#weekly_agenda returns note scheduled with monthly repeater
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:390 # LazyMode#where filters by tag
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:408 # LazyMode#where filters by body text
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:420 # LazyMode#where filters by header text
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:432 # LazyMode#where filters by status
rspec /tmp/d20160107-5693-1at6wv2/spec.rb:443 # LazyMode#where filters by multiple filters

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

Станимир обнови решението на 18.12.2015 23:18 (преди над 8 години)

+module LazyMode
+ class Date
+ attr_reader :year, :month, :day, :date_string
+
+ def initialize(date_string)
+ @date_string = date_string
+ @year, @month, @day = date_string.split('-').map(&:to_i)
+ end
+
+ alias_method :to_s, :date_string
+
+ def add_day
+ @day += 1
+
+ if @day > 30
+ @day = 1
+ add_month
+ end
+
+ construct_new
+ end
+
+ def add_month
+ @month += 1
+
+ if @month > 12
+ @month = 1
+ @year += 1
+ end
+
+ construct_new
+ end
+
+ def add_week
+ 7.times { add_day }
+ construct_new
+ end
+
+ private
+ def construct_new
+ Date.new("#{@year.to_s.rjust(4, '0')}-#{@month.to_s.rjust(2, '0')}-"\
+ "#{@day.to_s.rjust(2, '0')}")
+ end
+ end
+
+ class NoteBuilder
+ def initialize(header, tags, file_name, &block)
+ @header = header
+ @tags = tags
+ @file_name = file_name
+ @sub_notes = []
+ instance_eval(&block)
+ end
+
+ def status(value)
+ @status = value
+ end
+
+ def body(value)
+ @body = value
+ end
+
+ def scheduled(date)
+ @scheduled, @repeat = date.split
+ end
+
+ def note(header, *tags, &block)
+ note = Note.new(header, tags, @file_name, &block)
+ @sub_notes << note
+ note
+ end
+
+ def build
+ set_defaults
+ self
+ end
+
+ private
+ def set_defaults
+ @status ||= :topostpone
+ @body ||= ''
+ end
+ end
+
+ class Repeater
+ def initialize(start_date, period, frequency)
+ @date = Date.new(start_date)
+ @method_name = ('add_' + period).to_sym
+ @frequency = frequency
+ end
+
+ def repeats_before(date)
+ while @date.to_s <= date.to_s
+ yield @date
+ increment_date
+ end
+ end
+
+ private
+ def increment_date
+ @frequency.to_i.times { @date = @date.public_send(@method_name) }
+ end
+ end
+
+ class Note
+ attr_reader :header, :body, :status, :tags, :file_name, :sub_notes
+
+ def initialize(header, tags, file_name, &block)
+ note_builder = NoteBuilder.new(header, tags, file_name, &block).build
+
+ note_builder.instance_variables.each do |instance_variable|
+ value = note_builder.instance_variable_get(instance_variable)
+ instance_variable_set(instance_variable, value)
+ end
+ end
+
+ def repeats(date)
+ number, repeater, scale = @repeat.chars.drop(1)
+ case repeater
+ when 'd' then scale = 'day'
+ when 'w' then scale = 'week'
+ when 'm' then scale = 'month'
+ end
+ Repeater.new(@scheduled, scale, number).enum_for(:repeats_before, date)
+ end
+
+ def scheduled?(date)
+ @repeat ? scheduled_repeat?(date) : (date.to_s == @scheduled)
+ end
+
+ private
+ def scheduled_repeat?(date)
+ repeats(date).any? { |repeat| repeat.to_s == date.to_s }
+ end
+ end
+
+ class Agenda
+ attr_accessor :notes
+
+ def where(**kwargs)
+ copy = clone
+ notes = filter_by_tag(copy.notes, kwargs[:tag])
+ notes = filter_by_text(notes, kwargs[:text])
+ notes = filter_by_status(notes, kwargs[:status])
+ copy.notes = notes
+ copy
+ end
+
+ def filter_by_tag(notes, tag)
+ return notes unless tag
+ notes.select { |note| note.tags.include?(tag) }
+ end
+
+ def filter_by_text(notes, text)
+ return notes unless text
+ notes.select { |note| note.header =~ text }
+ end
+
+ def filter_by_status(notes, status)
+ return notes unless status
+ notes.select { |note| note.status == status }
+ end
+
+ private
+ def get_all_notes(list_of_notes)
+ notes = []
+ queue = list_of_notes.clone
+ until queue.empty?
+ notes << queue.first
+ add_sub_notes(queue, queue.shift)
+ end
+ notes
+ end
+
+ def add_sub_notes(queue, note)
+ note.sub_notes.each do |sub_note|
+ queue << sub_note
+ end
+ end
+
+ def add_if_scheduled_for_day(note, day)
+ if note.scheduled?(day)
+ @notes << build_agenda_item(note, day)
+ end
+ end
+
+ def build_agenda_item(note, date)
+ item = note.clone
+ item.define_singleton_method(:date) do
+ date
+ end
+ item
+ end
+ end
+
+ class DailyAgenda < Agenda
+ def initialize(date, notes)
+ @notes = []
+ @date = date
+
+ get_all_notes(notes).each do |note|
+ add_if_scheduled_for_day(note, date)
+ end
+ end
+
+ def where
+ end
+ end
+
+ class WeeklyAgenda < Agenda
+ def initialize(date, notes)
+ @notes = []
+ @week = get_week(date)
+ @date = date
+
+ get_all_notes(notes).each do |note|
+ add_if_scheduled_for_week(note)
+ end
+ end
+
+ def add_if_scheduled_for_week(note)
+ @week.each do |day|
+ add_if_scheduled_for_day(note, day)
+ end
+ end
+
+ private
+ def get_week(date)
+ 7.times.each_with_object([]) do |_, week|
+ week << date
+ date = date.add_day
+ end
+ end
+ end
+
+ class File
+ attr_reader :name, :notes
+
+ def initialize(file_name)
+ @name = file_name
+ @notes = []
+ end
+
+ def note(header, *tags, &block)
+ note = Note.new(header, tags, @name, &block)
+ @notes << note
+ note
+ end
+
+ def daily_agenda(date)
+ DailyAgenda.new(date, @notes)
+ end
+
+ def weekly_agenda(date)
+ WeeklyAgenda.new(date, @notes)
+ end
+ end
+
+ def self.create_file(file_name, &block)
+ file = File.new(file_name)
+ file.instance_eval(&block)
+ file
+ end
+end