diff --git a/elm-todo/Todo.elm b/elm-todo/Todo.elm index 3a07b24..dbe01a4 100755 --- a/elm-todo/Todo.elm +++ b/elm-todo/Todo.elm @@ -45,7 +45,6 @@ type alias Model = type alias Entry = { description : String , completed : Bool - , editing : Bool , id : Int } @@ -62,7 +61,6 @@ newEntry : String -> Int -> Entry newEntry desc id = { description = desc , completed = False - , editing = False , id = id } @@ -76,7 +74,6 @@ to them. -} type Msg = UpdateNewEntryField String - | EditingEntry Int Bool | UpdateEntry Int String | Add | Delete Int @@ -102,18 +99,6 @@ update msg model = UpdateNewEntryField str -> { model | newEntryField = str } - EditingEntry id isEditing -> - let - updateEntry t = - if t.id == id then - { t | editing = isEditing } - else - t - - focus = - Dom.focus ("todo-" ++ toString id) - in - { model | entries = List.map updateEntry model.entries } UpdateEntry id task -> let @@ -229,7 +214,7 @@ viewKeyedEntry todo = viewEntry : Entry -> Html Msg viewEntry todo = li - [ classList [ ( "completed", todo.completed ), ( "editing", todo.editing ) ] ] + [ classList [ ( "completed", todo.completed ) ] ] [ div [ class "view" ] [ input @@ -240,7 +225,7 @@ viewEntry todo = ] [] , label - [ onDoubleClick (EditingEntry todo.id True) ] + [] [ text todo.description ] , button [ class "destroy" @@ -254,8 +239,6 @@ viewEntry todo = , name "title" , id ("todo-" ++ toString todo.id) , onInput (UpdateEntry todo.id) - , onBlur (EditingEntry todo.id False) - , onEnter (EditingEntry todo.id False) ] [] ] diff --git a/ruby-todo/lib/engine.rb b/ruby-todo/lib/engine.rb index a257c20..500747c 100644 --- a/ruby-todo/lib/engine.rb +++ b/ruby-todo/lib/engine.rb @@ -4,9 +4,10 @@ def self.run(*args) end def self.run_with_history(model, messages) + model0 = model messages.map do |msg| - msg.apply_to(model) - model + model0 = msg.apply_to(model0) + model0 end end end diff --git a/ruby-todo/lib/messages.rb b/ruby-todo/lib/messages.rb index abe85de..3cb28ef 100644 --- a/ruby-todo/lib/messages.rb +++ b/ruby-todo/lib/messages.rb @@ -1,14 +1,13 @@ module Msg - class Add def apply_to(model) - unless model.new_entry_field.blank? - model.entries << Entry.new( + model0 = model.dup # Steven Roach told me about .dup + unless model0.new_entry_field.blank? + model0.entries << Entry.new( description: model.new_entry_field, id: model.next_id) end - model.next_id += 1 - model.new_entry_field = "" + Model.new(next_id: model.next_id + 1, entries: model0.entries, new_entry_field: "") end end @@ -17,10 +16,10 @@ def initialize(str) @str = str end - attr_reader :str + attr_reader :str def apply_to(model) - model.new_entry_field = str + Model.new(next_id: model.next_id, entries: model.entries, new_entry_field: str) end end @@ -29,14 +28,18 @@ def initialize(id, is_completed) @id, @is_completed = id, is_completed end - attr_reader :id, :is_completed + attr_reader :id, :is_completed def apply_to(model) + entries0 = [] model.entries.each do |entry| if entry.id == id - entry.completed = is_completed + entries0 << Entry.new(id: entry.id, description: entry.description, completed: is_completed) + else + entries0 << entry.dup end end + Model.new(entries: entries0, new_entry_field: model.new_entry_field, next_id: model.next_id) end end @@ -45,16 +48,20 @@ def initialize(id) @id = id end - attr_reader :id + attr_reader :id def apply_to(model) - model.entries.reject! { |e| e.id == id } + entries1 = model.entries.dup + entries1.reject! { |e| e.id == id } + Model.new(entries: entries1, new_entry_field: model.new_entry_field, next_id: model.next_id) end end class DeleteAllCompleted def apply_to(model) - model.entries.reject!(&:completed) + entries2 = model.entries.dup + entries2.reject!(&:completed) + Model.new(entries: entries2, new_entry_field: model.new_entry_field, next_id: model.next_id) end end diff --git a/ruby-todo/lib/model.rb b/ruby-todo/lib/model.rb index 75a6085..bdfccc1 100644 --- a/ruby-todo/lib/model.rb +++ b/ruby-todo/lib/model.rb @@ -5,7 +5,7 @@ def initialize(entries: [], new_entry_field: "", next_id: nil) (entries.lazy.map(&:id).max || -1) + 1 end - attr_accessor :entries, :new_entry_field, :next_id + attr_reader :entries, :new_entry_field, :next_id def ==(other) !other.nil? && diff --git a/ruby-todo/test/todo_test.rb b/ruby-todo/test/todo_test.rb index f7436c7..471fc7e 100644 --- a/ruby-todo/test/todo_test.rb +++ b/ruby-todo/test/todo_test.rb @@ -121,7 +121,7 @@ Entry.new(id: 0, description: "go forward in time", completed: false) ]), Model.new(next_id: 3, new_entry_field: "", entries: [ - Entry.new(id: 0, description: "go forward in time", completed: false), + Entry.new(id: 0, description: "go forward in time", completed: false), Entry.new(id: 2, description: "delete this item", completed: false) ]), Model.new(next_id: 3, new_entry_field: "", entries: [ @@ -134,19 +134,19 @@ Entry.new(id: 0, description: "go forward in time", completed: false) ]), Model.new(next_id: 4, new_entry_field: "", entries: [ - Entry.new(id: 0, description: "go forward in time", completed: false), + Entry.new(id: 0, description: "go forward in time", completed: false), Entry.new(id: 3, description: "go backward in time", completed: false) ]), Model.new(next_id: 4, new_entry_field: "", entries: [ - Entry.new(id: 0, description: "go forward in time", completed: true), + Entry.new(id: 0, description: "go forward in time", completed: true), Entry.new(id: 3, description: "go backward in time", completed: false) ]), Model.new(next_id: 4, new_entry_field: "", entries: [ - Entry.new(id: 0, description: "go forward in time", completed: true), + Entry.new(id: 0, description: "go forward in time", completed: true), Entry.new(id: 3, description: "go backward in time", completed: true) ]), Model.new(next_id: 4, new_entry_field: "", entries: [ - Entry.new(id: 0, description: "go forward in time", completed: true), + Entry.new(id: 0, description: "go forward in time", completed: true), Entry.new(id: 3, description: "go backward in time", completed: false) ]), Model.new(next_id: 4, new_entry_field: "", entries: [ diff --git a/swift-todo/Sources/Todo/Engine.swift b/swift-todo/Sources/Todo/Engine.swift index e3b14a7..8608c5f 100644 --- a/swift-todo/Sources/Todo/Engine.swift +++ b/swift-todo/Sources/Todo/Engine.swift @@ -13,9 +13,10 @@ struct Engine { } static func runWithHistory(on model: Model, applying messages: [Message]) -> [Model] { + var model1 = model return messages.map { message in - message.apply(to: model) - return model + model1 = message.apply(to: model1) + return model1 } } } diff --git a/swift-todo/Sources/Todo/Message.swift b/swift-todo/Sources/Todo/Message.swift index 92dd868..a07d061 100644 --- a/swift-todo/Sources/Todo/Message.swift +++ b/swift-todo/Sources/Todo/Message.swift @@ -14,30 +14,35 @@ enum Message { case delete(Int) case deleteAllCompleted - func apply(to model: Model) { + func apply(to model: Model) -> Model { + var model1 = model switch(self) { case .add: - if !model.newEntryField.isBlank() { - model.entries.append(Entry(id: model.nextID, description: model.newEntryField)) + if !model1.newEntryField.isBlank() { + model1.entries.append(Entry(id: model.nextID, description: model.newEntryField)) } - model.nextID += 1 - model.newEntryField = "" + return Model(nextID: model.nextID + 1, entries: model1.entries) case .updateNewEntryField(let str): - model.newEntryField = str + model1.newEntryField = str + return model1 case .check(let id, let isCompleted): - for entry in model.entries { - if(entry.id == id) { - entry.completed = isCompleted + for i in 0..<(model1.entries.count){ + if model1.entries[i].id == id{ + let entry0 = Entry(id: model1.entries[i].id, description: model1.entries[i].description, completed: isCompleted) + model1.entries[i] = entry0 } } + return model1 case .delete(let id): - model.entries.remove { $0.id == id } + model1.entries.remove { $0.id == id } + return model1 case .deleteAllCompleted: - model.entries.remove { $0.completed } + model1.entries.remove { $0.completed } + return model1 } } } diff --git a/swift-todo/Sources/Todo/Model.swift b/swift-todo/Sources/Todo/Model.swift index 1cca801..d50d863 100644 --- a/swift-todo/Sources/Todo/Model.swift +++ b/swift-todo/Sources/Todo/Model.swift @@ -1,4 +1,4 @@ -class Model { +struct Model { var entries: [Entry] var newEntryField: String var nextID: Int @@ -11,7 +11,7 @@ class Model { } } -class Entry { +struct Entry { var id: Int var description: String var completed: Bool diff --git a/swift-todo/Tests/TodoTests/TodoTests.swift b/swift-todo/Tests/TodoTests/TodoTests.swift index 9220517..7346f27 100644 --- a/swift-todo/Tests/TodoTests/TodoTests.swift +++ b/swift-todo/Tests/TodoTests/TodoTests.swift @@ -77,7 +77,7 @@ class TodoTests: XCTestCase { XCTAssertEqual([11], newModel.entries.map { $0.id }) } -/* + func testTimeTravel() { let actualHistory = Engine.runWithHistory(on: Model(), applying: [ .updateNewEntryField("go forward in time"), @@ -145,6 +145,6 @@ class TodoTests: XCTestCase { XCTAssertEqual(expected, actual, "History mismatch at step \(index)") } } -*/ + }