From 8ca3331d87c44ee427e859092964db349d8be4a8 Mon Sep 17 00:00:00 2001 From: Amanda Date: Mon, 23 Apr 2018 19:37:28 -0500 Subject: [PATCH 1/4] Add completed elm file. --- elm-todo/Todo.elm | 46 ++++------------------------------------------ 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/elm-todo/Todo.elm b/elm-todo/Todo.elm index 3a07b24..24dfddc 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,8 +74,6 @@ to them. -} type Msg = UpdateNewEntryField String - | EditingEntry Int Bool - | UpdateEntry Int String | Add | Delete Int | DeleteAllCompleted @@ -102,30 +98,7 @@ 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 - updateEntry t = - if t.id == id then - { t | description = task } - else - t - in - { model | entries = List.map updateEntry model.entries } - - Check id isCompleted -> + Check id isCompleted -> let updateEntry t = if t.id == id then @@ -229,7 +202,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 +213,7 @@ viewEntry todo = ] [] , label - [ onDoubleClick (EditingEntry todo.id True) ] + [] [ text todo.description ] , button [ class "destroy" @@ -248,16 +221,6 @@ viewEntry todo = ] [] ] - , input - [ class "edit" - , value todo.description - , name "title" - , id ("todo-" ++ toString todo.id) - , onInput (UpdateEntry todo.id) - , onBlur (EditingEntry todo.id False) - , onEnter (EditingEntry todo.id False) - ] - [] ] @@ -313,8 +276,7 @@ viewControlsClear entriesCompleted = infoFooter : Html msg infoFooter = footer [ class "info" ] - [ p [] [ text "Double-click to edit a todo" ] - , p [] + [p [] [ text "Written by " , a [ href "https://github.com/evancz" ] [ text "Evan Czaplicki" ] ] From c31a3013aad20a090385a58d8ace735ffe7597f7 Mon Sep 17 00:00:00 2001 From: Amanda Date: Mon, 23 Apr 2018 19:58:20 -0500 Subject: [PATCH 2/4] Add completed ruby file. --- ruby-todo/lib/engine.rb | 5 ++-- ruby-todo/lib/messages.rb | 50 +++++++++++++++++++++++++++++++------ ruby-todo/lib/model.rb | 4 +-- ruby-todo/test/todo_test.rb | 2 +- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/ruby-todo/lib/engine.rb b/ruby-todo/lib/engine.rb index a257c20..a7b0ebc 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) + new_model = model messages.map do |msg| - msg.apply_to(model) - model + new_model = msg.apply_to(new_model) + new_model end end end diff --git a/ruby-todo/lib/messages.rb b/ruby-todo/lib/messages.rb index abe85de..95e7411 100644 --- a/ruby-todo/lib/messages.rb +++ b/ruby-todo/lib/messages.rb @@ -2,13 +2,17 @@ module Msg class Add def apply_to(model) + new_entries = model.entries.dup unless model.new_entry_field.blank? - model.entries << Entry.new( + new.entries << Entry.new( description: model.new_entry_field, id: model.next_id) end - model.next_id += 1 - model.new_entry_field = "" + Model.new( + entries: new_entries, + new_entry_field = "", + next_id: model.next_id + 1 + ) end end @@ -20,7 +24,11 @@ def initialize(str) attr_reader :str def apply_to(model) - model.new_entry_field = str + Model.new( + entries: model.entries, + new_entry_field: str, + next_id: model.next_id + ) end end @@ -32,11 +40,27 @@ def initialize(id, is_completed) attr_reader :id, :is_completed def apply_to(model) + new_entries = [] model.entries.each do |entry| if entry.id == id - entry.completed = is_completed + new_entries << Entry.new( + id: entry.id, + description: entry.description, + completed: is_completed + ) + else + new_entries << Entry.new( + id: entry_id, + description: entry_description, + completed: entry.completed + ) end end + Model.new( + entries: new_entries, + new_entry_field: model.new_entry_field, + next_id: model.next_id + ) end end @@ -48,13 +72,25 @@ def initialize(id) attr_reader :id def apply_to(model) - model.entries.reject! { |e| e.id == id } + new_entries = model.entries.dup + new_entries.reject! { |e| e.id == id } + Model.new( + entries: new_entries, + new_entry_field: model.new_entry_field, + next_id: model.next_id + ) end end class DeleteAllCompleted def apply_to(model) - model.entries.reject!(&:completed) + new_entries = model.entries.dup + new_entries.reject!(&:completed) + Model.new( + entries: new_entries, + 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..e64ca6a 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? && @@ -20,7 +20,7 @@ def initialize(id:, description:, completed: false) @description, @id, @completed = description, id, completed end - attr_accessor :description, :completed, :id + attr_reader :description, :completed, :id def ==(other) !other.nil? && diff --git a/ruby-todo/test/todo_test.rb b/ruby-todo/test/todo_test.rb index f7436c7..d3351dc 100644 --- a/ruby-todo/test/todo_test.rb +++ b/ruby-todo/test/todo_test.rb @@ -91,7 +91,7 @@ end it "supports time travel" do - skip "Mutable model does not support time travel" + # skip "Mutable model does not support time travel" actual_history = Engine.run_with_history(Model.new, [ Msg::UpdateNewEntryField.new("go forward in time"), From 66d12c59c39ea93924140c905b0170d4908f3395 Mon Sep 17 00:00:00 2001 From: Amanda Date: Mon, 23 Apr 2018 20:09:44 -0500 Subject: [PATCH 3/4] Add completed swift file. Sorry it took a billion years. --- swift-todo/Sources/Todo/Engine.swift | 5 ++-- swift-todo/Sources/Todo/Message.swift | 32 +++++++++++++++------- swift-todo/Sources/Todo/Model.swift | 4 +-- swift-todo/Tests/TodoTests/TodoTests.swift | 2 -- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/swift-todo/Sources/Todo/Engine.swift b/swift-todo/Sources/Todo/Engine.swift index e3b14a7..aebfc0c 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 new_model: Model = model return messages.map { message in - message.apply(to: model) - return model + newModel = message.apply(to: newModel) + return newModel } } } diff --git a/swift-todo/Sources/Todo/Message.swift b/swift-todo/Sources/Todo/Message.swift index 92dd868..e6a2e8b 100644 --- a/swift-todo/Sources/Todo/Message.swift +++ b/swift-todo/Sources/Todo/Message.swift @@ -14,30 +14,42 @@ enum Message { case delete(Int) case deleteAllCompleted - func apply(to model: Model) { + func apply(to model: Model) -> Model { + var newModel: Model = model switch(self) { case .add: - if !model.newEntryField.isBlank() { - model.entries.append(Entry(id: model.nextID, description: model.newEntryField)) + if !newModel.newEntryField.isBlank() { + newModel.entries.append(Entry(id: model.nextID, description: model.newEntryField)) } - model.nextID += 1 - model.newEntryField = "" + newModel.nextID += 1 + newModel.newEntryField = "" case .updateNewEntryField(let str): - model.newEntryField = str + newModel.newEntryField = str case .check(let id, let isCompleted): - for entry in model.entries { + var newEntries: [Entry] = [] + for entry in newModel.entries { if(entry.id == id) { - entry.completed = isCompleted + newEntries.append( + Entry( + id: entry.id, + description: entry.description, + completed: isCompleted + ) + ) + } else { + newEntries.append(entry) } } + newModel.entries = newEntries case .delete(let id): - model.entries.remove { $0.id == id } + newModel.entries.remove { $0.id == id } case .deleteAllCompleted: - model.entries.remove { $0.completed } + newModel.entries.remove { $0.completed } } + return newModel } } 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..7c7539b 100644 --- a/swift-todo/Tests/TodoTests/TodoTests.swift +++ b/swift-todo/Tests/TodoTests/TodoTests.swift @@ -77,7 +77,6 @@ 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 +144,5 @@ class TodoTests: XCTestCase { XCTAssertEqual(expected, actual, "History mismatch at step \(index)") } } -*/ } From 4107b76430d0f5a9657e3c348673016532009ce9 Mon Sep 17 00:00:00 2001 From: Amanda Date: Sun, 6 May 2018 17:21:24 -0500 Subject: [PATCH 4/4] finall submission of hw 3 --- elm-todo/Todo.elm | 30 ++++++++++--- ruby-todo/lib/messages.rb | 52 +++++----------------- ruby-todo/lib/model.rb | 2 +- ruby-todo/test/todo_test.rb | 14 +++--- swift-todo/Sources/Todo/Engine.swift | 5 +-- swift-todo/Sources/Todo/Message.swift | 43 ++++++++---------- swift-todo/Sources/Todo/Model.swift | 2 +- swift-todo/Tests/TodoTests/TodoTests.swift | 6 ++- 8 files changed, 70 insertions(+), 84 deletions(-) diff --git a/elm-todo/Todo.elm b/elm-todo/Todo.elm index 24dfddc..90da0ba 100755 --- a/elm-todo/Todo.elm +++ b/elm-todo/Todo.elm @@ -1,18 +1,14 @@ port module Todo exposing (..) {-| TodoMVC implemented in Elm, using plain HTML and CSS for rendering. - This application is broken up into three key parts: - 1. Model - a full definition of the application's state 2. Update - a way to step the application state forward 3. View - a way to visualize our application state with HTML - This clean division of concerns is a core part of Elm. You can read more about this in -} -import Dom import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) @@ -74,6 +70,7 @@ to them. -} type Msg = UpdateNewEntryField String + | UpdateEntry Int String | Add | Delete Int | DeleteAllCompleted @@ -98,7 +95,17 @@ update msg model = UpdateNewEntryField str -> { model | newEntryField = str } - Check id isCompleted -> + UpdateEntry id task -> + let + updateEntry t = + if t.id == id then + { t | description = task } + else + t + in + { model | entries = List.map updateEntry model.entries } + + Check id isCompleted -> let updateEntry t = if t.id == id then @@ -221,6 +228,15 @@ viewEntry todo = ] [] ] + , + input + [ class "edit" + , value todo.description + , name "title" + , id ("todo-" ++ toString todo.id) + , onInput (UpdateEntry todo.id) + ] + [] ] @@ -276,7 +292,7 @@ viewControlsClear entriesCompleted = infoFooter : Html msg infoFooter = footer [ class "info" ] - [p [] + [ p [] [ text "Written by " , a [ href "https://github.com/evancz" ] [ text "Evan Czaplicki" ] ] @@ -284,4 +300,4 @@ infoFooter = [ text "Part of " , a [ href "http://todomvc.com" ] [ text "TodoMVC" ] ] - ] + ] \ No newline at end of file diff --git a/ruby-todo/lib/messages.rb b/ruby-todo/lib/messages.rb index 95e7411..d76313a 100644 --- a/ruby-todo/lib/messages.rb +++ b/ruby-todo/lib/messages.rb @@ -4,15 +4,11 @@ class Add def apply_to(model) new_entries = model.entries.dup unless model.new_entry_field.blank? - new.entries << Entry.new( + new_entries << Entry.new( description: model.new_entry_field, id: model.next_id) end - Model.new( - entries: new_entries, - new_entry_field = "", - next_id: model.next_id + 1 - ) + Model.new(entries: new_entries, new_entry_field: "", next_id: model.next_id + 1) end end @@ -21,14 +17,10 @@ def initialize(str) @str = str end - attr_reader :str + attr_reader :str def apply_to(model) - Model.new( - entries: model.entries, - new_entry_field: str, - next_id: model.next_id - ) + Model.new(entries: model.entries, new_entry_field: str, next_id: model.next_id) end end @@ -37,30 +29,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) new_entries = [] model.entries.each do |entry| if entry.id == id - new_entries << Entry.new( - id: entry.id, - description: entry.description, - completed: is_completed - ) + new_entries << Entry.new(id: entry.id, description: entry.description, completed: is_completed) else - new_entries << Entry.new( - id: entry_id, - description: entry_description, - completed: entry.completed - ) + new_entries << Entry.new(id: entry.id, description: entry.description, completed: entry.completed) end end - Model.new( - entries: new_entries, - new_entry_field: model.new_entry_field, - next_id: model.next_id - ) + Model.new(entries: new_entries, new_entry_field: model.new_entry_field, next_id: model.next_id) end end @@ -69,16 +49,12 @@ def initialize(id) @id = id end - attr_reader :id + attr_reader :id def apply_to(model) new_entries = model.entries.dup new_entries.reject! { |e| e.id == id } - Model.new( - entries: new_entries, - new_entry_field: model.new_entry_field, - next_id: model.next_id - ) + Model.new(entries: new_entries, new_entry_field: model.new_entry_field, next_id: model.next_id) end end @@ -86,12 +62,8 @@ class DeleteAllCompleted def apply_to(model) new_entries = model.entries.dup new_entries.reject!(&:completed) - Model.new( - entries: new_entries, - new_entry_field: model.new_entry_field, - next_id: model.next_id - ) + Model.new(entries: new_entries, new_entry_field: model.new_entry_field, next_id: model.next_id) end end -end +end \ No newline at end of file diff --git a/ruby-todo/lib/model.rb b/ruby-todo/lib/model.rb index e64ca6a..81818b8 100644 --- a/ruby-todo/lib/model.rb +++ b/ruby-todo/lib/model.rb @@ -28,4 +28,4 @@ def ==(other) self.description == other.description && self.completed == other.completed end -end +end \ No newline at end of file diff --git a/ruby-todo/test/todo_test.rb b/ruby-todo/test/todo_test.rb index d3351dc..6ecd3a3 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: [ @@ -158,9 +158,11 @@ # but comparing one step at a time gives more readable error messages: assert_equal expected_history.size, actual_history.size + assert_equal expected_history, actual_history + expected_history.zip(actual_history).each.with_index do |(expected, actual), index| assert_equal expected, actual, "History mismatch at step #{index}" end end -end +end \ No newline at end of file diff --git a/swift-todo/Sources/Todo/Engine.swift b/swift-todo/Sources/Todo/Engine.swift index aebfc0c..c6f92b4 100644 --- a/swift-todo/Sources/Todo/Engine.swift +++ b/swift-todo/Sources/Todo/Engine.swift @@ -4,7 +4,6 @@ // // Created by Paul on 2018/4/4. // - import Foundation struct Engine { @@ -13,10 +12,10 @@ struct Engine { } static func runWithHistory(on model: Model, applying messages: [Message]) -> [Model] { - var new_model: Model = model + var newModel = model return messages.map { message in newModel = message.apply(to: newModel) return newModel } } -} +} \ No newline at end of file diff --git a/swift-todo/Sources/Todo/Message.swift b/swift-todo/Sources/Todo/Message.swift index e6a2e8b..9d6a632 100644 --- a/swift-todo/Sources/Todo/Message.swift +++ b/swift-todo/Sources/Todo/Message.swift @@ -4,7 +4,6 @@ // // Created by Paul on 2018/4/4. // - import Foundation enum Message { @@ -15,41 +14,37 @@ enum Message { case deleteAllCompleted func apply(to model: Model) -> Model { - var newModel: Model = model - switch(self) { + switch (self) { case .add: - if !newModel.newEntryField.isBlank() { - newModel.entries.append(Entry(id: model.nextID, description: model.newEntryField)) + var newEntries = model.entries + if !model.newEntryField.isBlank() { + newEntries.append(Entry(id: model.nextID, description: model.newEntryField)) } - newModel.nextID += 1 - newModel.newEntryField = "" + return Model(nextID: model.nextID + 1, entries: newEntries) case .updateNewEntryField(let str): - newModel.newEntryField = str + return Model(nextID: model.nextID, newEntryField: str, entries: model.entries) case .check(let id, let isCompleted): - var newEntries: [Entry] = [] - for entry in newModel.entries { - if(entry.id == id) { - newEntries.append( - Entry( - id: entry.id, - description: entry.description, - completed: isCompleted - ) - ) + var newEntries = [Entry]() + for entry in model.entries { + if entry.id == id { + newEntries.append(Entry(id: entry.id, description: entry.description, completed: isCompleted)) } else { - newEntries.append(entry) + newEntries.append(Entry(id: entry.id, description: entry.description, completed: entry.completed)) } } - newModel.entries = newEntries + return Model(nextID: model.nextID, newEntryField: model.newEntryField, entries: newEntries) case .delete(let id): - newModel.entries.remove { $0.id == id } + var newEntries = model.entries + newEntries.remove { $0.id == id } + return Model(nextID: model.nextID, newEntryField: model.newEntryField, entries: newEntries) case .deleteAllCompleted: - newModel.entries.remove { $0.completed } + var newEntries = model.entries + newEntries.remove { $0.completed } + return Model(nextID: model.nextID, newEntryField: model.newEntryField, entries: newEntries) } - return newModel } -} +} \ No newline at end of file diff --git a/swift-todo/Sources/Todo/Model.swift b/swift-todo/Sources/Todo/Model.swift index d50d863..39eec71 100644 --- a/swift-todo/Sources/Todo/Model.swift +++ b/swift-todo/Sources/Todo/Model.swift @@ -37,4 +37,4 @@ extension Entry: Equatable { && lhs.description == rhs.description && lhs.completed == rhs.completed } -} +} \ No newline at end of file diff --git a/swift-todo/Tests/TodoTests/TodoTests.swift b/swift-todo/Tests/TodoTests/TodoTests.swift index 7c7539b..94c6355 100644 --- a/swift-todo/Tests/TodoTests/TodoTests.swift +++ b/swift-todo/Tests/TodoTests/TodoTests.swift @@ -26,6 +26,9 @@ class TodoTests: XCTestCase { .updateNewEntryField("hop on one foot"), .add ]) + + print("test test test") + print(newModel) XCTAssertEqual(3, newModel.entries.count) let newEntry = newModel.entries.last! XCTAssertEqual(12, newEntry.id) @@ -144,5 +147,4 @@ class TodoTests: XCTestCase { XCTAssertEqual(expected, actual, "History mismatch at step \(index)") } } - -} +} \ No newline at end of file