todo-fede 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 58ded6bb5a70de8630f77cfa4e978fbdc2439de65024019dfc6f7a6de82c6744
4
+ data.tar.gz: cdf5570db57cea5f4adde6ba8496c0d4cbb69016e1381c7030caf0738d8c514e
5
+ SHA512:
6
+ metadata.gz: 3bb3dd42868f82c75beb57206adfb5eadd1849b07f2eb99c97d555e20c3c6ed4b43889a523300ed8ccad347185ef31f3dba7be1a19cf2c7a579a96ed8f0b25dd
7
+ data.tar.gz: ce42f10559aa1f28e41cef9a7d00e4190ca9aca8469be37481ede30e242dc8353c600e545bd6a30046d1a78706e9a054e36019fdcf5099806711b31ae89959cc
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ Dir['./lib/**/*.rb'].each { |f| require(f) }
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ require 'irb'
10
+ IRB.start(__FILE__)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ Dir['./lib/**/*.rb'].each { |f| require(f) }
5
+
6
+ TodoList.load
7
+ Main.start(ARGV)
8
+ TodoList.dump
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Error to be raised when there is no registry of a todo with certain ID.
4
+ class TodoNotFoundError < StandardError
5
+ def message
6
+ 'Sorry, there is no Todo item with such ID'
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This module provides helper methods to display
4
+ # informative messages to the user
5
+ module MainHelper
6
+ def display_description_needed_message
7
+ puts 'You must provide a description for the task'
8
+ end
9
+
10
+ def display_something_went_wrong_message(msg)
11
+ puts "Sorry, something went wrong: #{msg}"
12
+ end
13
+
14
+ def display_created_task_message(idx)
15
+ puts "Created task #{idx}"
16
+ end
17
+
18
+ def confirm_deletion_message(idx, todo)
19
+ "Permanently delete task #{idx + 1} #{todo.description}? (yes/no)"
20
+ end
21
+
22
+ def print_successfull_deletion_message
23
+ puts 'To-Do successfully deleted'
24
+ end
25
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This module provides helper methods to display the
4
+ # information of the TodoList instance to the user.
5
+ module TodoHelper
6
+ def display_all_todos(undone:, done:)
7
+ if undone.any? || done.any?
8
+ _display_todos(undone)
9
+ _display_done_todos(done)
10
+ _display_todos_count_message(undone)
11
+ else
12
+ _display_no_matches
13
+ end
14
+ end
15
+
16
+ def display_undone_todos(todos_list)
17
+ if todos_list.any?
18
+ _display_todos(todos_list)
19
+ _display_todos_count_message(todos_list)
20
+ else
21
+ _display_no_matches
22
+ end
23
+ end
24
+
25
+ def _display_done_todos(todos_list)
26
+ todos_list.each do |todo|
27
+ puts "* ~~#{todo.description}~~"
28
+ end
29
+ end
30
+
31
+ def _display_todos(todos_list)
32
+ puts 'ID Description'
33
+ puts '-- -----------'
34
+ todos_list.each_with_index do |todo, idx|
35
+ puts "#{_two_characters_format(idx + 1)} #{todo.description}"
36
+ end
37
+ end
38
+
39
+ def _display_todos_count_message(todos_list)
40
+ todos_count = todos_list.length
41
+ if todos_count > 1
42
+ puts "\n#{todos_count} tasks."
43
+ else
44
+ puts "\n#{todos_count} task."
45
+ end
46
+ end
47
+
48
+ def _two_characters_format(number)
49
+ return number.to_s if number > 9
50
+
51
+ "#{number} "
52
+ end
53
+
54
+ def _display_no_matches
55
+ puts 'No matches'
56
+ end
57
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'helpers/todo_helper'
5
+ require_relative 'helpers/main_helper'
6
+
7
+ # It's responsible for the application initialization and
8
+ # for the client communication interface.
9
+ class Main < Thor
10
+ include TodoHelper
11
+ include MainHelper
12
+
13
+ desc 'add TASK DESCRIPTION', 'Add tasks to a todo list'
14
+ def add(*description)
15
+ return unless validate_description_presence(description)
16
+
17
+ todo_idx = with_rescue do
18
+ todos_controller.add(description: description.join(' '))
19
+ end
20
+ display_created_task_message(todo_idx)
21
+ end
22
+
23
+ desc 'done IDX', 'Mark the todo with the provided <<IDX>> as done'
24
+ def done(idx)
25
+ with_rescue do
26
+ todos_controller.done(idx.to_i - 1)
27
+ end
28
+ end
29
+
30
+ desc 'delete IDX', 'Delete the task with the given IDX'
31
+ def delete(idx)
32
+ with_rescue do
33
+ index = idx.to_i - 1
34
+ todo = todos_controller.find(index)
35
+ if require_deletion_confirmation(index, todo)
36
+ todos_controller.delete(index)
37
+ print_successfull_deletion_message
38
+ end
39
+ end
40
+ end
41
+
42
+ desc 'list', 'Display a list of the tasks'
43
+ option :all
44
+ def list
45
+ todos = with_rescue do
46
+ todos_controller.list
47
+ end
48
+
49
+ if options['all']
50
+ display_all_todos(undone: todos[:undone_items], done: todos[:done_items])
51
+ else
52
+ display_undone_todos(todos[:undone_items])
53
+ end
54
+ end
55
+
56
+ class << self
57
+ def exit_on_failure?
58
+ true
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def validate_description_presence(description)
65
+ return true if description.count.positive?
66
+
67
+ display_description_needed_message
68
+ false
69
+ end
70
+
71
+ def todos_controller
72
+ TodosController.new
73
+ end
74
+
75
+ def require_deletion_confirmation(idx, todo)
76
+ confirm = nil
77
+ until %w[y n].include?(confirm)
78
+ confirm = ask(confirm_deletion_message(idx, todo))
79
+ end
80
+
81
+ confirm == 'y'
82
+ end
83
+
84
+ def with_rescue
85
+ yield
86
+ rescue TodoNotFoundError => e
87
+ puts e.message.to_s
88
+ rescue StandardError => e
89
+ display_something_went_wrong_message(e.message)
90
+ end
91
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Mixin module, adds the ability to persist a Singleton class in a
4
+ # local file and also de ability to load the Singleton class from that file.
5
+ # In order to work properply the class that include this modules must also
6
+ # include the ruby module Singleton
7
+ module SingletonStorer
8
+ # This module allows to embed class methods as part of the mixin.
9
+ module ClassMethods
10
+ def dump
11
+ instance._dump
12
+ end
13
+
14
+ def load
15
+ instance._load
16
+ end
17
+ end
18
+
19
+ def self.included(base)
20
+ base.extend(ClassMethods)
21
+ end
22
+
23
+ def _load
24
+ return unless File.exist?(persistence_file_name)
25
+
26
+ attributes = Marshal.load(File.read(persistence_file_name))
27
+ attributes.each do |attr, value|
28
+ instance_variable_set("@#{attr}".to_sym, value)
29
+ end
30
+ end
31
+
32
+ def _dump
33
+ File.write(persistence_file_name, Marshal.dump(attrs_to_hash))
34
+ end
35
+
36
+ def persistence_file_name
37
+ "#{self.class.name.downcase}.mp"
38
+ end
39
+
40
+ def attrs_to_hash
41
+ attrs = {}
42
+ self.class::PERSISTED_ATTRIBUTES.each do |attr|
43
+ attrs[attr] = send(attr)
44
+ end
45
+
46
+ attrs
47
+ end
48
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Representation of the main entity of the program, a to do item.
4
+ class Todo
5
+ attr_accessor(:description)
6
+
7
+ def initialize(description:)
8
+ @description = description
9
+ end
10
+
11
+ def update(**attrs)
12
+ attrs.each do |attr, value|
13
+ instance_variable_set("@#{attr}".to_sym, value)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require 'singleton_storer'
5
+
6
+ # Singleton class resposible for managing the CRUD operations related
7
+ # to a Todo instance.
8
+ class TodoList
9
+ PERSISTED_ATTRIBUTES = %i[undone_todos done_todos].freeze
10
+
11
+ include Singleton
12
+ include SingletonStorer
13
+
14
+ def initialize
15
+ set_defaults
16
+ end
17
+
18
+ def add(todo)
19
+ @undone_todos << todo
20
+ end
21
+
22
+ def move_to_done(idx)
23
+ raise TodoNotFoundError unless in_range?(idx)
24
+
25
+ @done_todos << remove_from_undone(idx)
26
+ end
27
+
28
+ def done
29
+ @done_todos
30
+ end
31
+
32
+ def undone
33
+ @undone_todos
34
+ end
35
+
36
+ def undone_count
37
+ @undone_todos.length
38
+ end
39
+
40
+ def find(idx)
41
+ raise TodoNotFoundError unless in_range?(idx)
42
+
43
+ @undone_todos[idx]
44
+ end
45
+
46
+ def delete(idx)
47
+ remove_from_undone idx
48
+ end
49
+
50
+ private
51
+
52
+ attr_accessor(*PERSISTED_ATTRIBUTES)
53
+
54
+ def set_defaults
55
+ @undone_todos = []
56
+ @done_todos = []
57
+ end
58
+
59
+ def remove_from_undone(idx)
60
+ raise TodoNotFoundError unless in_range?(idx)
61
+
62
+ @undone_todos.delete_at(idx)
63
+ end
64
+
65
+ def in_range?(idx)
66
+ (0..(@undone_todos.length - 1)).include?(idx)
67
+ end
68
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Plays the role of intermediary between the Main class and the Todo class
4
+ class TodosController
5
+ def add(description:)
6
+ todo = Todo.new(description: description)
7
+ todo_list.add(todo)
8
+ todo_list.undone_count
9
+ end
10
+
11
+ def list
12
+ {
13
+ done_items: todo_list.done,
14
+ undone_items: todo_list.undone
15
+ }
16
+ end
17
+
18
+ def done(idx)
19
+ todo_list.move_to_done(idx)
20
+ end
21
+
22
+ def delete(idx)
23
+ todo_list.delete(idx)
24
+ end
25
+
26
+ def find(idx)
27
+ todo_list.find(idx)
28
+ end
29
+
30
+ private
31
+
32
+ def todo_list
33
+ TodoList.instance
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Version
4
+ VERSION = '1.0.0'
5
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: todo-fede
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Federico Moya
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-02-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubocop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.79'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.79'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '12.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '12.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: thor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.0.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.0.1
83
+ description:
84
+ email:
85
+ - federicomoyamartin@gmail.com
86
+ executables:
87
+ - console
88
+ - setup
89
+ - todo
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - bin/console
94
+ - bin/setup
95
+ - bin/todo
96
+ - lib/errors/todo_not_found_error.rb
97
+ - lib/helpers/main_helper.rb
98
+ - lib/helpers/todo_helper.rb
99
+ - lib/main.rb
100
+ - lib/singleton_storer.rb
101
+ - lib/todo.rb
102
+ - lib/todo_list.rb
103
+ - lib/todos_controller.rb
104
+ - lib/version.rb
105
+ homepage:
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 2.7.0
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 3.1.2
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Cool todo app
128
+ test_files: []