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

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

Към профила на Георги Карапетров

Резултати

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

Код

module LazyMode
def self.create_file(file_name, &block)
file = File.new(file_name)
file.instance_eval(&block)
file
end
class Date
include Comparable
attr_reader :year, :month, :day
DATE_FORMAT = "%04d-%02d-%02d"
PERIODS_HASH = {"d" => 1, "w" => 7, "m" => 30}
def initialize(date_string)
trimmed_string = extract_repeater(date_string).first
@repeater = extract_repeater(date_string).last
date_array = trimmed_string.split("-")
@year = date_array.first.to_i
@month = date_array[1].to_i
@day = date_array.last.to_i
end
def advance(days)
day = (@day + days) % 30
month = day < @day ? (@month + 1) % 12 : @month
year = month < @month ? (@year + 1) : @year
date_string = DATE_FORMAT % [year, month, day]
Date.new(date_string)
end
def advance!(days)
@day = (@day + days) % 30
@month = day < @day ? (@month + 1) % 12 : @month
@year = month < @month ? (@year + 1) : @year
end
def week_later
advance(7)
end
def to_s
date_string = DATE_FORMAT % [@year, @month, @day]
date_string
end
def <=>(other)
year_comparison = @year <=> other.year
return year_comparison unless year_comparison == 0
month_comparison = @month <=> other.month
return month_comparison unless month_comparison == 0
return @day <=> other.day
end
def apply_repeater!
return self unless @repeater
repeat_period = @repeater[-1]
quantifier = @repeater.sub("+", "").sub(repeat_period, "").to_i
step_forward = PERIODS_HASH[repeat_period] * quantifier
@repeater = nil
advance!(step_forward)
end
private
def extract_repeater(date_string)
/(\+\d+(d|w|y))/.match date_string
repeater = $1
trimmed_string = date_string.dup
trimmed_string.sub!(repeater, "") if repeater
[trimmed_string, repeater]
end
end #of class
class NoteParent
attr_accessor :file_name
attr_reader :notes
def initialize(name)
@file_name = name
@notes = []
end
def note(header, *tags, &block)
note = Note.new(header, tags)
note.file_name = file_name
note.instance_eval(&block)
@notes.push(note)
end
end #of class
class Note < NoteParent
attr_reader :header, :tags
def initialize(header, *tags)
super("")
@header = header
@tags = tags.flatten
@status = :topostpone
@body = ""
end
def status(*args)
return @status if args.count == 0
note_status = args.first
@status = note_status
end
def body(*args)
return @body if args.count == 0
note_body = args.first
@body = note_body
end
def scheduled(date_string)
note_scheduled = Date.new(date_string)
@date = note_scheduled
end
end #of class
class File < NoteParent
def initialize(name)
super
end
def daily_agenda(date)
notes = all_notes
notes_for_date = notes.select { |note| note.date == date }
repeated = notes.each { |note| note.date.apply_repeater!}
repeated.select! { |note| note.date == date }
Agenda.new(notes_for_date | repeated)
end
def weekly_agenda(date)
week_notes = all_notes.select { |note| within_a_week?(note, date) }
Agenda.new(week_notes)
end
private
def all_notes
all_notes_array = @notes.map { |note| [note] + all_notes_for_note(note) }
all_notes_array.flatten!
all_notes_array.each { |note| conform_to_date(note) }
all_notes_array
end
def all_notes_for_note(parent_note)
return [] if parent_note == nil
parent_note.notes.each { |note| [note] + all_notes_for_note(note) }
end
def within_a_week?(note, starting_date)
date = note.date.dup
within = date >= starting_date and date <= starting_date.week_later
date.apply_repeater!
within_repeat = date >= starting_date and date <= starting_date.week_later
within or within_repeat
end
def conform_to_date(note)
note.instance_eval do
def date
@date
end
end
end
end #of class
class Agenda
attr_reader :notes
def initialize(notes = [])
@notes = notes
end
def where(tag: nil, text: nil, status: nil)
notes_by_tag = by_tag(tag)
notes_by_text = by_text(text)
notes_by_status = by_status(status)
filtered_notes = notes_by_tag & notes_by_text & notes_by_status
Agenda.new(filtered_notes)
end
def by_tag(tag)
return @notes if tag == nil
@notes.select { |note| note.tags.include? tag }
end
def by_text(text)
return @notes if text == nil
@notes.select { |note| text.match "#{note.header}\n#{note.body}" }
end
def by_status(status)
return @notes if status == nil
@notes.select { |note| note.status == status }
end
end #of class
end #of module

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

...............F..FFFFFF.....F.

Failures:

  1) LazyMode#daily_agenda returns note scheduled with monthly repeater
     Failure/Error: expect(agenda.notes.size).to eq(1)
       
       expected: 1
            got: 0
       
       (compared using ==)
     # /tmp/d20160107-5693-1k12amt/spec.rb:198: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(agenda.notes.size).to eq(1)
       
       expected: 1
            got: 2
       
       (compared using ==)
     # /tmp/d20160107-5693-1k12amt/spec.rb:249: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(note.header).to eq('simple note')
       
       expected: "simple note"
            got: "simple note 2"
       
       (compared using ==)
     # /tmp/d20160107-5693-1k12amt/spec.rb:273:in `block (4 levels) in <top (required)>'
     # /tmp/d20160107-5693-1k12amt/spec.rb:272:in `each'
     # /tmp/d20160107-5693-1k12amt/spec.rb:272: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(first_note.date.day).to eq(12)
       
       expected: 12
            got: 5
       
       (compared using ==)
     # /tmp/d20160107-5693-1k12amt/spec.rb:303: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(agenda.notes.size).to eq(1)
       
       expected: 1
            got: 0
       
       (compared using ==)
     # /tmp/d20160107-5693-1k12amt/spec.rb:327: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#weekly_agenda does not return note whose start date is in the future
     Failure/Error: expect(agenda.notes.size).to eq(0)
       
       expected: 0
            got: 1
       
       (compared using ==)
     # /tmp/d20160107-5693-1k12amt/spec.rb:345: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#weekly_agenda returns nested notes
     Failure/Error: expect(agenda.notes.size).to eq(1)
       
       expected: 1
            got: 0
       
       (compared using ==)
     # /tmp/d20160107-5693-1k12amt/spec.rb:361: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.create_file can assign name to files
     Failure/Error: expect(file.name).to eq('important_notes_and_todos')
     NoMethodError:
       undefined method `name' for #<LazyMode::File:0x007efcc54d64a8>
     # /tmp/d20160107-5693-1k12amt/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.02204 seconds
31 examples, 8 failures

Failed examples:

rspec /tmp/d20160107-5693-1k12amt/spec.rb:186 # LazyMode#daily_agenda returns note scheduled with monthly repeater
rspec /tmp/d20160107-5693-1k12amt/spec.rb:237 # LazyMode#weekly_agenda returns note scheduled without repeater
rspec /tmp/d20160107-5693-1k12amt/spec.rb:259 # LazyMode#weekly_agenda returns multiple notes with different dates when scheduled with daily repeater
rspec /tmp/d20160107-5693-1k12amt/spec.rb:283 # LazyMode#weekly_agenda returns note scheduled with weekly repeater
rspec /tmp/d20160107-5693-1k12amt/spec.rb:315 # LazyMode#weekly_agenda returns note scheduled with monthly repeater
rspec /tmp/d20160107-5693-1k12amt/spec.rb:337 # LazyMode#weekly_agenda does not return note whose start date is in the future
rspec /tmp/d20160107-5693-1k12amt/spec.rb:348 # LazyMode#weekly_agenda returns nested notes
rspec /tmp/d20160107-5693-1k12amt/spec.rb:456 # LazyMode.create_file can assign name to files

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

Георги обнови решението на 21.12.2015 04:09 (преди около 9 години)

+module LazyMode
+
+ def self.create_file(file_name, &block)
+ file = File.new(file_name)
+ file.instance_eval(&block)
+ file
+ end
+
+ class Date
+ include Comparable
+ attr_reader :year, :month, :day
+ DATE_FORMAT = "%04d-%02d-%02d"
+ PERIODS_HASH = {"d" => 1, "w" => 7, "m" => 30}
+ def initialize(date_string)
+ trimmed_string = extract_repeater(date_string).first
+ @repeater = extract_repeater(date_string).last
+
+ date_array = trimmed_string.split("-")
+ @year = date_array.first.to_i
+ @month = date_array[1].to_i
+ @day = date_array.last.to_i
+ end
+
+ def advance(days)
+ day = (@day + days) % 30
+ month = day < @day ? (@month + 1) % 12 : @month
+ year = month < @month ? (@year + 1) : @year
+
+ date_string = DATE_FORMAT % [year, month, day]
+ Date.new(date_string)
+ end
+
+ def advance!(days)
+ @day = (@day + days) % 30
+ @month = day < @day ? (@month + 1) % 12 : @month
+ @year = month < @month ? (@year + 1) : @year
+ end
+
+ def week_later
+ advance(7)
+ end
+
+ def to_s
+ date_string = DATE_FORMAT % [@year, @month, @day]
+ date_string
+ end
+
+ def <=>(other)
+ year_comparison = @year <=> other.year
+ return year_comparison unless year_comparison == 0
+ month_comparison = @month <=> other.month
+ return month_comparison unless month_comparison == 0
+ return @day <=> other.day
+ end
+
+ def apply_repeater!
+ return self unless @repeater
+ repeat_period = @repeater[-1]
+ quantifier = @repeater.sub("+", "").sub(repeat_period, "").to_i
+ step_forward = PERIODS_HASH[repeat_period] * quantifier
+ @repeater = nil
+ advance!(step_forward)
+ end
+
+ private
+ def extract_repeater(date_string)
+ /(\+\d+(d|w|y))/.match date_string
+ repeater = $1
+ trimmed_string = date_string.dup
+ trimmed_string.sub!(repeater, "") if repeater
+ [trimmed_string, repeater]
+ end
+ end #of class
+
+ class NoteParent
+ attr_accessor :file_name
+ attr_reader :notes
+
+ def initialize(name)
+ @file_name = name
+ @notes = []
+ end
+
+ def note(header, *tags, &block)
+ note = Note.new(header, tags)
+ note.file_name = file_name
+ note.instance_eval(&block)
+ @notes.push(note)
+ end
+
+ end #of class
+
+ class Note < NoteParent
+ attr_reader :header, :tags
+
+ def initialize(header, *tags)
+ super("")
+ @header = header
+ @tags = tags.flatten
+ @status = :topostpone
+ @body = ""
+ end
+
+ def status(*args)
+ return @status if args.count == 0
+ note_status = args.first
+ @status = note_status
+ end
+
+ def body(*args)
+ return @body if args.count == 0
+ note_body = args.first
+ @body = note_body
+ end
+
+ def scheduled(date_string)
+ note_scheduled = Date.new(date_string)
+ @date = note_scheduled
+ end
+
+ end #of class
+
+ class File < NoteParent
+ def initialize(name)
+ super
+ end
+
+ def daily_agenda(date)
+ notes = all_notes
+ notes_for_date = notes.select { |note| note.date == date }
+ repeated = notes.each { |note| note.date.apply_repeater!}
+ repeated.select! { |note| note.date == date }
+ Agenda.new(notes_for_date | repeated)
+ end
+
+ def weekly_agenda(date)
+ week_notes = all_notes.select { |note| within_a_week?(note, date) }
+ Agenda.new(week_notes)
+ end
+
+ private
+ def all_notes
+ all_notes_array = @notes.map { |note| [note] + all_notes_for_note(note) }
+ all_notes_array.flatten!
+ all_notes_array.each { |note| conform_to_date(note) }
+ all_notes_array
+ end
+
+ def all_notes_for_note(parent_note)
+ return [] if parent_note == nil
+ parent_note.notes.each { |note| [note] + all_notes_for_note(note) }
+ end
+
+ def within_a_week?(note, starting_date)
+ date = note.date.dup
+ within = date >= starting_date and date <= starting_date.week_later
+ date.apply_repeater!
+ within_repeat = date >= starting_date and date <= starting_date.week_later
+
+ within or within_repeat
+
+ end
+
+ def conform_to_date(note)
+ note.instance_eval do
+ def date
+ @date
+ end
+ end
+ end
+
+ end #of class
+
+ class Agenda
+ attr_reader :notes
+
+ def initialize(notes = [])
+ @notes = notes
+ end
+
+ def where(tag: nil, text: nil, status: nil)
+
+ notes_by_tag = by_tag(tag)
+ notes_by_text = by_text(text)
+ notes_by_status = by_status(status)
+
+ filtered_notes = notes_by_tag & notes_by_text & notes_by_status
+
+ Agenda.new(filtered_notes)
+ end
+
+ def by_tag(tag)
+ return @notes if tag == nil
+ @notes.select { |note| note.tags.include? tag }
+ end
+
+ def by_text(text)
+ return @notes if text == nil
+ @notes.select { |note| text.match "#{note.header}\n#{note.body}" }
+ end
+
+ def by_status(status)
+ return @notes if status == nil
+ @notes.select { |note| note.status == status }
+ end
+
+ end #of class
+end #of module