From e1f638ec31cb971e4790fbcce3e341b9dddfa5ff Mon Sep 17 00:00:00 2001 From: milobeyene Date: Wed, 11 Apr 2018 13:55:38 -0500 Subject: [PATCH 1/4] Removed Elm feature, moving on to Part 1: Ruby --- elm-todo/Todo.elm | 44 +++----------------------------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/elm-todo/Todo.elm b/elm-todo/Todo.elm index 3a07b24..3c8ae87 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,29 +98,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 - 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 = @@ -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 3d48a691598e9acecfce363264729bb9fde3b6e5 Mon Sep 17 00:00:00 2001 From: milobeyene Date: Tue, 17 Apr 2018 16:08:00 -0500 Subject: [PATCH 2/4] Done with Part 1: Next up is Swift --- ruby-todo/Gemfile.lock | 1 + ruby-todo/lib/engine.rb | 3 +-- ruby-todo/lib/messages.rb | 26 +++++++++++++++++--------- ruby-todo/lib/model.rb | 4 ++-- ruby-todo/test/todo_test.rb | 2 +- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/ruby-todo/Gemfile.lock b/ruby-todo/Gemfile.lock index 8b2b027..15835e1 100644 --- a/ruby-todo/Gemfile.lock +++ b/ruby-todo/Gemfile.lock @@ -14,6 +14,7 @@ GEM PLATFORMS ruby + x64-mingw32 DEPENDENCIES minitest diff --git a/ruby-todo/lib/engine.rb b/ruby-todo/lib/engine.rb index a257c20..41926b3 100644 --- a/ruby-todo/lib/engine.rb +++ b/ruby-todo/lib/engine.rb @@ -5,8 +5,7 @@ def self.run(*args) def self.run_with_history(model, messages) messages.map do |msg| - msg.apply_to(model) - model + model = msg.apply_to(model) end end end diff --git a/ruby-todo/lib/messages.rb b/ruby-todo/lib/messages.rb index abe85de..009347e 100644 --- a/ruby-todo/lib/messages.rb +++ b/ruby-todo/lib/messages.rb @@ -2,13 +2,13 @@ module Msg class Add def apply_to(model) + new_mod_entries = model.entries.dup unless model.new_entry_field.blank? - model.entries << Entry.new( + new_mod_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_mod_entries, new_entry_field: "", next_id: model.next_id + 1) end end @@ -20,7 +20,7 @@ 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 @@ -30,14 +30,20 @@ def initialize(id, is_completed) end attr_reader :id, :is_completed - + def apply_to(model) + new_mod_entries = [] model.entries.each do |entry| if entry.id == id - entry.completed = is_completed + new_mod_entries << Entry.new(description: entry.description, + id: entry.id, + completed: is_completed) + else + new_mod_entries << entry end end - end + Model.new(entries: new_mod_entries, new_entry_field: model.new_entry_field, next_id: model.next_id) + end end class Delete @@ -48,13 +54,15 @@ def initialize(id) attr_reader :id def apply_to(model) - model.entries.reject! { |e| e.id == id } + new_mod_entries = model.entries.reject { |e| e.id == id } + Model.new(entries: new_mod_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_mod_entries = model.entries.reject(&:completed) + Model.new(entries: new_mod_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..a5441ba 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" + actual_history = Engine.run_with_history(Model.new, [ Msg::UpdateNewEntryField.new("go forward in time"), From 159cd2b29a8167bd3fd5529e20842af0fdce0c61 Mon Sep 17 00:00:00 2001 From: Milo Beyene Date: Tue, 17 Apr 2018 17:45:47 -0500 Subject: [PATCH 3/4] In the middle of Swift stuff.. --- ruby-todo/.DS_Store | Bin 0 -> 6148 bytes swift-todo/Sources/Todo/Engine.swift | 5 +++-- swift-todo/Sources/Todo/Message.swift | 29 ++++++++++++++------------ swift-todo/Sources/Todo/Model.swift | 4 ++-- 4 files changed, 21 insertions(+), 17 deletions(-) create mode 100644 ruby-todo/.DS_Store diff --git a/ruby-todo/.DS_Store b/ruby-todo/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..877637e47ca9a072aa6be9a50884ece0a1ae1237 GIT binary patch literal 6148 zcmeHK&2G~`5S~o}aRi7QDz(SGAoUQTL@g~+Rmn<=P;ZDJIMAxK8$+$S-YRy8XbAF! zhoEoJN8t&05FVg>`$Lo;b43Vdq}gwF_M5f*t?l&^k?0Ql9ik=?d2o%D2AUGnN2@^p0lMPlXuKkHrpr{ni*FqWkk~dW`$jFOxXS+wJe7Qmx&&TlX3bukpY;>Yb@k zFAwrz)(r-4O)u_8p^INBl}zIxd>u!l`W_k0_UI)AbdE(RT>|k1oY^I)Q4VfK`GS}~7I^5gu>!0BD^R9@ z`%roJ$_6>d3a|qIwF3J4AmJK)hlNG+=|E$S0Kgj3#t`eDMqMKv`VI?=7=Z~}3bdud z9WjJ0M_xLf@363F%SpJyhj3RG?t~)D)iJ*`bP~QrZdn0VU|xZ$?KbuP|LphY|M?>B zu>!2XKc#@E?f3S(xFxr@F5R5oYbE>yu1)g_i_;PWW-A6)Z^dhHW5`P#0DXsrMPy+7 OBVc6Uh86gu3j74Mzm4kv literal 0 HcmV?d00001 diff --git a/swift-todo/Sources/Todo/Engine.swift b/swift-todo/Sources/Todo/Engine.swift index e3b14a7..c717840 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 newModel = 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..986a81b 100644 --- a/swift-todo/Sources/Todo/Message.swift +++ b/swift-todo/Sources/Todo/Message.swift @@ -15,29 +15,32 @@ enum Message { case deleteAllCompleted func apply(to model: Model) { + var newModel = model switch(self) { case .add: - if !model.newEntryField.isBlank() { - model.entries.append(Entry(id: model.nextID, description: model.newEntryField)) - } - model.nextID += 1 - model.newEntryField = "" + //if !model.newEntryField.isBlank() { + // model.entries.append(Entry(id: model.nextID, description: model.newEntryField)) + //} + //model.nextID += 1 + //model.newEntryField = "" case .updateNewEntryField(let str): - model.newEntryField = str + //model.newEntryField = str case .check(let id, let isCompleted): - for entry in model.entries { - if(entry.id == id) { - entry.completed = isCompleted - } - } + //for entry in model.entries { + // if(entry.id == id) { + // entry.completed = isCompleted + // } + //} case .delete(let id): - model.entries.remove { $0.id == id } + //model.entries.remove { $0.id == id } case .deleteAllCompleted: - model.entries.remove { $0.completed } + //model.entries.remove { $0.completed } } + newModel = Model.init() + 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 From 55bb71f639921651dbd966fc7a7750abce63c125 Mon Sep 17 00:00:00 2001 From: Milo Beyene Date: Wed, 18 Apr 2018 12:40:30 -0500 Subject: [PATCH 4/4] Swift time travel passes --- swift-todo/Sources/Todo/Message.swift | 34 ++++++++++++---------- swift-todo/Tests/TodoTests/TodoTests.swift | 4 +-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/swift-todo/Sources/Todo/Message.swift b/swift-todo/Sources/Todo/Message.swift index 986a81b..fca87f3 100644 --- a/swift-todo/Sources/Todo/Message.swift +++ b/swift-todo/Sources/Todo/Message.swift @@ -14,33 +14,35 @@ enum Message { case delete(Int) case deleteAllCompleted - func apply(to model: Model) { + func apply(to model: Model) -> Model { var newModel = model switch(self) { case .add: - //if !model.newEntryField.isBlank() { - // model.entries.append(Entry(id: model.nextID, description: model.newEntryField)) - //} - //model.nextID += 1 - //model.newEntryField = "" + if !newModel.newEntryField.isBlank() { + newModel.entries.append(Entry(id: newModel.nextID, description: newModel.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 { - // if(entry.id == id) { - // entry.completed = isCompleted - // } - //} - + newModel.entries = [] + for entry in model.entries { + var e = entry + if(e.id == id) { + e.completed = isCompleted + } + newModel.entries.append(e) + } + 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 } } - newModel = Model.init() return newModel } } 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)") } } -*/ + }