list-tool 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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +8 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +1 -0
  9. data/bin/clt +12 -0
  10. data/lib/list_tool/app/commands/add_item_command.rb +39 -0
  11. data/lib/list_tool/app/commands/add_list_command.rb +30 -0
  12. data/lib/list_tool/app/commands/delete_item_command.rb +39 -0
  13. data/lib/list_tool/app/commands/delete_list_command.rb +32 -0
  14. data/lib/list_tool/app/commands/help_command.rb +24 -0
  15. data/lib/list_tool/app/commands/rename_list_command.rb +34 -0
  16. data/lib/list_tool/app/commands/replace_item_command.rb +34 -0
  17. data/lib/list_tool/app/commands/show_items_command.rb +35 -0
  18. data/lib/list_tool/app/commands/show_lists_command.rb +26 -0
  19. data/lib/list_tool/app/commands/unknown_command.rb +26 -0
  20. data/lib/list_tool/app/commands/use_command.rb +31 -0
  21. data/lib/list_tool/app/commands/version_command.rb +24 -0
  22. data/lib/list_tool/app/commands.rb +43 -0
  23. data/lib/list_tool/app/printer.rb +41 -0
  24. data/lib/list_tool/app/runner.rb +54 -0
  25. data/lib/list_tool/app/string.rb +9 -0
  26. data/lib/list_tool/app.rb +9 -0
  27. data/lib/list_tool/data.rb +75 -0
  28. data/lib/list_tool/file_manager.rb +27 -0
  29. data/lib/list_tool/item.rb +23 -0
  30. data/lib/list_tool/json_parser.rb +11 -0
  31. data/lib/list_tool/list.rb +88 -0
  32. data/lib/list_tool/lister.rb +81 -0
  33. data/lib/list_tool/version.rb +3 -0
  34. data/lib/list_tool.rb +19 -0
  35. data/list_tool.gemspec +31 -0
  36. data/spec/fixtures/data.json +18 -0
  37. data/spec/list_tool/app/commands/add_item_command_spec.rb +108 -0
  38. data/spec/list_tool/app/commands/add_list_command_spec.rb +74 -0
  39. data/spec/list_tool/app/commands/delete_item_command_spec.rb +116 -0
  40. data/spec/list_tool/app/commands/delete_list_command_spec.rb +89 -0
  41. data/spec/list_tool/app/commands/help_command_spec.rb +41 -0
  42. data/spec/list_tool/app/commands/rename_list_command_spec.rb +95 -0
  43. data/spec/list_tool/app/commands/replace_item_command_spec.rb +97 -0
  44. data/spec/list_tool/app/commands/show_items_command_spec.rb +111 -0
  45. data/spec/list_tool/app/commands/show_lists_command_spec.rb +48 -0
  46. data/spec/list_tool/app/commands/unknown_command_spec.rb +31 -0
  47. data/spec/list_tool/app/commands/use_command_spec.rb +79 -0
  48. data/spec/list_tool/app/commands/version_comand_spec.rb +41 -0
  49. data/spec/list_tool/app/commands_spec.rb +80 -0
  50. data/spec/list_tool/app/printer_spec.rb +54 -0
  51. data/spec/list_tool/app/runner_spec.rb +166 -0
  52. data/spec/list_tool/app/string_spec.rb +32 -0
  53. data/spec/list_tool/data_spec.rb +257 -0
  54. data/spec/list_tool/file_manager_spec.rb +84 -0
  55. data/spec/list_tool/item_spec.rb +42 -0
  56. data/spec/list_tool/json_parser_spec.rb +14 -0
  57. data/spec/list_tool/list_spec.rb +221 -0
  58. data/spec/list_tool/lister_spec.rb +186 -0
  59. data/spec/spec_helper.rb +18 -0
  60. data/spec/support/factory.rb +33 -0
  61. metadata +213 -0
@@ -0,0 +1,75 @@
1
+ module ListTool
2
+
3
+ class Data
4
+ include Enumerable
5
+
6
+ attr_reader :lists, :default_list
7
+
8
+ def initialize(hash = {})
9
+ raise ArgumentError, 'argument is not a hash' unless hash.respond_to?(:to_hash)
10
+
11
+ hash['lists'] ||= []
12
+ raise ArgumentError, 'incorrect data given' unless hash['lists'].respond_to?(:to_ary)
13
+
14
+ @lists = []
15
+ hash['lists'].each { |list_data| add_list(list_data) }
16
+
17
+ set_default_list(hash['default']) if hash['default']
18
+ end
19
+
20
+ def each
21
+ @lists.each { |list| yield(list) }
22
+ end
23
+
24
+ def add_list(data)
25
+ list = List.new(data)
26
+ @lists << list
27
+ list
28
+ end
29
+
30
+ def delete_list(index)
31
+ list = @lists.delete_at(index)
32
+ @default_list = nil if @default_list == list
33
+ list
34
+ end
35
+
36
+ def clear_list(index)
37
+ return nil if @lists[index] == nil
38
+ @lists[index].clear!
39
+ end
40
+
41
+ def rename_list(index, name)
42
+ return nil if @lists[index] == nil
43
+ @lists[index].rename(name)
44
+ end
45
+
46
+ def set_default_list(index)
47
+ raise ArgumentError, 'argument is not an integer' unless index.respond_to?(:to_int)
48
+ return nil if @lists[index] == nil
49
+ @default_list = @lists[index]
50
+ end
51
+
52
+ def move_list(index, direction)
53
+ case direction
54
+ when :up
55
+ return unless (1...@lists.length).include?(index)
56
+ @lists[index], @lists[index-1] = @lists[index-1], @lists[index]
57
+ when :down
58
+ return unless (0...(@lists.length-1)).include?(index)
59
+ @lists[index], @lists[index+1] = @lists[index+1], @lists[index]
60
+ end
61
+ end
62
+
63
+ def to_json
64
+ json = "{"
65
+ json += "\"default\":#{@lists.index(@default_list)}," if @default_list
66
+ json += "\"lists\":["
67
+ @lists.each do |list|
68
+ json += list.to_json
69
+ json += ',' unless list == @lists.last
70
+ end
71
+ json += ']}'
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,27 @@
1
+ module ListTool
2
+
3
+ class FileManager
4
+
5
+ def self.load filename
6
+ File.read(filename)
7
+ rescue Errno::EACCES
8
+ raise FileAccessError, "can't read file '#{filename}': access denied"
9
+ rescue Errno::ENOENT
10
+ raise FileNotFoundError, "can't read file '#{filename}': file not found"
11
+ rescue
12
+ raise IOError, "can't read file '#{filename}': unknown error"
13
+ end
14
+
15
+ def self.save filename, data
16
+ File.open(filename, 'w') { |f| f << data.to_json }
17
+ rescue Errno::EACCES
18
+ raise FileAccessError, "can't open file '#{filename}': access denied"
19
+ rescue Errno::ENOENT
20
+ raise FileNotFoundError, "can't open file '#{filename}': file not found"
21
+ rescue
22
+ raise IOError, "can't open file '#{filename}': unknown error"
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,23 @@
1
+ module ListTool
2
+
3
+ class Item
4
+ attr_accessor :text
5
+
6
+ def initialize arg
7
+ if arg.is_a?(String)
8
+ @text = arg
9
+ elsif arg.is_a?(Hash)
10
+ raise(ArgumentError, "item text not found in given hash") unless arg['text'].is_a?(String)
11
+ @text = arg["text"]
12
+ else
13
+ raise(ArgumentError, "argument expected to be Hash or String, #{arg.class} given")
14
+ end
15
+ end
16
+
17
+ def to_json
18
+ "{\"text\":\"#{@text}\"}"
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,11 @@
1
+ module ListTool
2
+
3
+ class JsonParser
4
+
5
+ def self.parse json
6
+ JSON.parse(json)
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,88 @@
1
+ module ListTool
2
+
3
+ class List
4
+ include Enumerable
5
+
6
+ attr_reader :name, :items
7
+
8
+ def initialize(arg=nil)
9
+ if arg.respond_to?(:to_str)
10
+ @name = arg
11
+ @items = []
12
+ elsif arg.is_a?(Hash)
13
+ prepare_data(arg)
14
+
15
+ @name = arg['name']
16
+
17
+ @items = []
18
+ arg['items'].each do |item|
19
+ add_item(item)
20
+ end
21
+ else
22
+ raise(ArgumentError, "argument expected to be Hash or String, #{arg.class} given")
23
+ end
24
+ end
25
+
26
+ def clear!
27
+ @items = []
28
+ end
29
+
30
+ def rename str
31
+ raise ArgumentError, 'string expected' unless str.is_a?(String)
32
+ old_name = @name
33
+ @name = str
34
+ old_name
35
+ end
36
+
37
+ def to_json
38
+ json = "{\"name\":\"#{@name}\",\"items\":["
39
+ @items.each do |item|
40
+ json += item.to_json
41
+ json += ',' unless item == @items.last
42
+ end
43
+ json += ']}'
44
+ end
45
+
46
+ def each
47
+ @items.each { |item| yield(item) }
48
+ end
49
+
50
+ def add_item text
51
+ @items << Item.new(text)
52
+ end
53
+
54
+ def delete_item num
55
+ @items.delete_at(num)
56
+ end
57
+
58
+ def change_item index, new_text
59
+ raise ArgumentError, 'index is not an integer' unless index.respond_to?(:to_int)
60
+ raise ArgumentError, 'new text is not a string' unless new_text.respond_to?(:to_str)
61
+ return nil if @items[index].nil?
62
+ @items[index].text = new_text
63
+ end
64
+
65
+ def move_item num, direction
66
+ case direction
67
+ when :up
68
+ return unless (1...@items.length).include?(num)
69
+ @items[num], @items[num-1] = @items[num-1], @items[num]
70
+ when :down
71
+ return unless (0...(@items.length-1)).include?(num)
72
+ @items[num], @items[num+1] = @items[num+1], @items[num]
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def prepare_data data
79
+ data['items'] ||= []
80
+ data['name'] ||= 'Anonimous list'
81
+
82
+ data['name'].respond_to?(:to_str) || raise(ArgumentError, 'name is not a string')
83
+ data['items'].is_a?(Array) || raise(ArgumentError, '"items" is not an array')
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,81 @@
1
+ module ListTool
2
+ class Lister
3
+
4
+ def initialize
5
+ @data = Data.new
6
+ end
7
+
8
+ def inspect
9
+ "#<#{self.class}:0x#{self.__id__.to_s(16)}>"
10
+ end
11
+
12
+ def self.from_hash(hash)
13
+ lister = Lister.new
14
+ lister.instance_variable_set(:@data, Data.new(hash))
15
+ lister
16
+ end
17
+
18
+ def self.from_json(json)
19
+ data = JsonParser.parse(json)
20
+ from_hash(data)
21
+ end
22
+
23
+ def load(filename)
24
+ json = FileManager.load(filename)
25
+ @data = Data.new( JsonParser.parse(json) )
26
+ self
27
+ end
28
+
29
+ def save(filename)
30
+ FileManager.save(filename, @data)
31
+ end
32
+
33
+ def lists
34
+ out = {}
35
+ @data.each do |list|
36
+ out[list.name] = list.items.count
37
+ end
38
+ out
39
+ end
40
+
41
+ def list(index=nil)
42
+ list = if index
43
+ return nil if @data.lists[index].nil?
44
+ @data.lists[index]
45
+ else
46
+ raise NoDefaultListError, "default list not set" if @data.default_list.nil?
47
+ @data.default_list
48
+ end
49
+
50
+ out = {name: list.name, items: []}
51
+ list.items.each do |item|
52
+ out[:items] << item.text
53
+ end
54
+ out
55
+ end
56
+
57
+ def method_missing(name, *args, &block)
58
+ if name =~ /_list$/
59
+ object = @data
60
+ elsif name =~ /_item$/
61
+ object = if args[-1].is_a?(Hash) && args[-1].has_key?(:list)
62
+ return nil if @data.lists[ args[-1][:list] ].nil?
63
+ index = args.pop()[:list]
64
+ @data.lists[index]
65
+ else
66
+ raise NoDefaultListError, "default list not set" if @data.default_list.nil?
67
+ @data.default_list
68
+ end
69
+ else
70
+ super
71
+ end
72
+
73
+ result = object.send(name, *args, &block)
74
+ return nil if result.nil?
75
+ self
76
+ rescue NoMethodError => e
77
+ raise NoMethodError, "undefined method '#{name.to_s}' for #{self.inspect}"
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,3 @@
1
+ module ListTool
2
+ VERSION = "1.0.0"
3
+ end
data/lib/list_tool.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'json'
2
+
3
+ require_relative "./list_tool/version"
4
+ require_relative "./list_tool/lister"
5
+ require_relative "./list_tool/item"
6
+ require_relative "./list_tool/list"
7
+ require_relative "./list_tool/data"
8
+ require_relative "./list_tool/json_parser"
9
+ require_relative "./list_tool/file_manager"
10
+ require_relative "./list_tool/app.rb"
11
+
12
+ module ListTool
13
+ class FileAccessError < StandardError; end
14
+ class FileNotFoundError < StandardError; end
15
+ class NoDefaultListError < StandardError; end
16
+ class ListNotFoundError < StandardError; end;
17
+ class ItemNotFoundError < StandardError; end;
18
+ class UnknownCommandError < StandardError; end;
19
+ end
data/list_tool.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'list_tool/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "list-tool"
8
+ spec.version = ListTool::VERSION
9
+ spec.date = '2014-06-08'
10
+ spec.authors = ["Dmitrii Krasnov"]
11
+ spec.email = ["vizvamitra@gmail.com"]
12
+ spec.summary = "list-tool-#{ListTool::VERSION}"
13
+ spec.description = "A tool to manage lists of strings (like todos) in your app or terminal"
14
+ spec.homepage = "http://github.com/vizvamitra/list-tool"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.required_ruby_version = '>= 1.9.3'
23
+
24
+ # spec.add_runtime_dependency "json", '~> 1.8'
25
+ spec.add_development_dependency "bundler", "~> 1.5"
26
+ spec.add_development_dependency "rake", "~> 10.3"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "guard", "~> 2.6"
29
+ spec.add_development_dependency "guard-rspec", "~> 4.2"
30
+ spec.add_development_dependency "rb-readline", "~> 0.5"
31
+ end
@@ -0,0 +1,18 @@
1
+ { "default":0,
2
+ "lists":[
3
+ {
4
+ "name":"Todolist",
5
+ "items":[
6
+ {
7
+ "text": "item1"
8
+ },
9
+ {
10
+ "text": "item2"
11
+ }
12
+ ]
13
+ },
14
+ {
15
+ "name":"Wishlist",
16
+ "items":[]
17
+ }
18
+ ]}
@@ -0,0 +1,108 @@
1
+ require_relative '../../../spec_helper.rb'
2
+
3
+ describe ListTool::App::AddItemCommand do
4
+ subject { ListTool::App::AddItemCommand }
5
+
6
+ describe '.match?' do
7
+ it 'returns true if "a" or "add-item" given' do
8
+ expect( subject.match? "a" ).to be_truthy
9
+ expect( subject.match? "add-item" ).to be_truthy
10
+ end
11
+
12
+ it 'returns false otherwise' do
13
+ expect( subject.match? "some-arg" ).to be_falsey
14
+ end
15
+ end
16
+
17
+
18
+ describe '.parse' do
19
+
20
+ it 'shifts 2 args from ARGV' do
21
+ argv = ['text', '1']
22
+ expect( argv ).to receive(:shift).with(2).and_return(['text', '1'])
23
+ subject.parse argv
24
+ end
25
+
26
+ context 'success' do
27
+
28
+ context 'when list number not given' do
29
+ it 'returns {text: "item text"}' do
30
+ argv = ['item_text']
31
+ expect( subject.parse argv ).to eq( {text: 'item_text'} )
32
+ end
33
+ end
34
+
35
+ context 'when list number given' do
36
+ it 'returns {text: "item text", list: list_num}' do
37
+ argv = ['item_text', "2"]
38
+ expect( subject.parse argv ).to eq( {text: 'item_text', list: 1} )
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ context 'failure' do
45
+
46
+ context 'when item text not given' do
47
+ it 'raises ArgumentError' do
48
+ expect{ subject.parse([]) }.to raise_error( ArgumentError )
49
+ end
50
+ end
51
+
52
+ context 'when list number is not an integer' do
53
+ it 'raises ArgumentError' do
54
+ expect{ subject.parse(['text', 'not_an_int']) }.to raise_error( ArgumentError )
55
+ end
56
+ end
57
+
58
+ context 'when list number is less than 1' do
59
+ it 'raises ArgumentError' do
60
+ expect{ subject.parse(['text', '0']) }.to raise_error( ArgumentError )
61
+ end
62
+ end
63
+
64
+ context 'when not an array given' do
65
+ it 'raises ArgumentError' do
66
+ expect{ subject.parse "not_an_array" }.to raise_error( ArgumentError )
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+
73
+
74
+ describe '.execute' do
75
+ let (:lister) { ListTool::Lister.new }
76
+
77
+ context 'success' do
78
+ it 'calls lister.add_item with given options' do
79
+ expect(lister).to receive(:add_item).with('item text').and_return("not_nil")
80
+ subject.execute({text: 'item text'}, lister)
81
+ end
82
+ end
83
+
84
+ context 'failure' do
85
+
86
+ context 'when list not found' do
87
+ it 'raises ListNotFoundError' do
88
+ expect{ subject.execute({text: 'item text', list: 2}, lister) }.to raise_error(ListTool::ListNotFoundError )
89
+ end
90
+ end
91
+
92
+ context 'when list not specified and no default list set' do
93
+ it 'raises NoDefaultListError' do
94
+ expect{ subject.execute({text: 'item text'}, lister) }.to raise_error(ListTool::NoDefaultListError )
95
+ end
96
+ end
97
+
98
+ end
99
+ end
100
+
101
+
102
+ describe '.help' do
103
+ it 'returns help message' do
104
+ expect( subject.help ).to be_a String
105
+ end
106
+ end
107
+
108
+ end
@@ -0,0 +1,74 @@
1
+ require_relative '../../../spec_helper.rb'
2
+
3
+ describe ListTool::App::AddListCommand do
4
+ subject { ListTool::App::AddListCommand }
5
+
6
+ describe '.match?' do
7
+ it 'returns true if "al" or "add-list" given' do
8
+ expect( subject.match? "al" ).to be_truthy
9
+ expect( subject.match? "add-list" ).to be_truthy
10
+ end
11
+
12
+ it 'returns false otherwise' do
13
+ expect( subject.match? "some-arg" ).to be_falsey
14
+ end
15
+ end
16
+
17
+
18
+ describe '.parse' do
19
+ it 'shifts 1 arg from ARGV' do
20
+ argv = ['name']
21
+ expect( argv ).to receive(:shift).with(no_args).and_return('name')
22
+ subject.parse argv
23
+ end
24
+
25
+ context 'success' do
26
+ it 'returns {name: "name"}' do
27
+ expect( subject.parse(['name']) ).to eq( {name: 'name'} )
28
+ end
29
+ end
30
+
31
+ context 'failure' do
32
+
33
+ context 'when new name not given' do
34
+ it 'raises ArgumentError' do
35
+ expect{ subject.parse[] }.to raise_error(ArgumentError)
36
+ end
37
+ end
38
+
39
+ context 'when first arg is not a string' do
40
+ it 'raises ArgumentError' do
41
+ expect{ subject.parse([1]) }.to raise_error(ArgumentError)
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+
50
+ describe '.execute' do
51
+ let (:lister) { double('lister') }
52
+
53
+ context 'success' do
54
+ it 'calls lister.add_list with given name' do
55
+ expect(lister).to receive(:add_list).with('list name').and_return("not_nil")
56
+ subject.execute({name: 'list name'}, lister)
57
+ end
58
+ end
59
+
60
+ context 'list creation failed' do
61
+ it 'raises RuntimeError' do
62
+ allow(lister).to receive(:add_list).and_return(nil)
63
+ expect{ subject.execute({name: 'some name'}, lister) }.to raise_error(RuntimeError)
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+ describe '.help' do
70
+ it 'returns help message' do
71
+ expect( subject.help ).to be_a String
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,116 @@
1
+ require_relative '../../../spec_helper.rb'
2
+
3
+ describe ListTool::App::DeleteItemCommand do
4
+ subject { ListTool::App::DeleteItemCommand }
5
+
6
+ describe '.match?' do
7
+ it 'returns true if "d" or "del-item" given' do
8
+ expect( subject.match? "d" ).to be_truthy
9
+ expect( subject.match? "del-item" ).to be_truthy
10
+ end
11
+
12
+ it 'returns false otherwise' do
13
+ expect( subject.match? "some-arg" ).to be_falsey
14
+ end
15
+ end
16
+
17
+
18
+ describe '.parse' do
19
+
20
+ it 'shifts 2 args from ARGV' do
21
+ argv = ['2', '1']
22
+ expect( argv ).to receive(:shift).with(2).and_return(['2', '1'])
23
+ subject.parse argv
24
+ end
25
+
26
+ context 'success' do
27
+
28
+ context 'when list number not given' do
29
+ it 'returns {item: item_num}' do
30
+ argv = ["2"]
31
+ expect( subject.parse argv ).to eq( {item: 1} )
32
+ end
33
+ end
34
+
35
+ context 'when list number given' do
36
+ it 'returns {text: "item text", list: list_num}' do
37
+ argv = ["2", "1"]
38
+ expect( subject.parse argv ).to eq( {item: 1, list: 0} )
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ context 'failure' do
45
+
46
+ context 'when item number not given' do
47
+ it 'raises ArgumentError' do
48
+ expect{ subject.parse([]) }.to raise_error( ArgumentError )
49
+ end
50
+ end
51
+
52
+ context 'when list number is not an integer' do
53
+ it 'raises ArgumentError' do
54
+ expect{ subject.parse(['2', 'not_an_int']) }.to raise_error( ArgumentError )
55
+ end
56
+ end
57
+
58
+ context 'when list number is less than 1' do
59
+ it 'raises ArgumentError' do
60
+ expect{ subject.parse(['2', '0']) }.to raise_error( ArgumentError )
61
+ end
62
+ end
63
+
64
+ context 'when not an array given' do
65
+ it 'raises ArgumentError' do
66
+ expect{ subject.parse "not_an_array" }.to raise_error( ArgumentError )
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+
73
+
74
+ describe '.execute' do
75
+ let(:lister) { ListTool::Lister.new }
76
+
77
+ context 'success' do
78
+ context 'when list number is given' do
79
+ it 'calls lister.delete_item with item_num, {list: list_num}' do
80
+ expect(lister).to receive(:delete_item).with(2, {list: 2}).and_return("not_nill")
81
+ subject.execute({item: 2, list: 2}, lister)
82
+ end
83
+ end
84
+
85
+ context 'when list number is not given' do
86
+ it 'calls lister.delete_item with no args' do
87
+ expect(lister).to receive(:delete_item).with(2).and_return("not_nill")
88
+ subject.execute({item: 2}, lister)
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'failure' do
94
+ context 'when list not found' do
95
+ it 'raises ListNotFoundError' do
96
+ expect{ subject.execute({item: 2, list: 2}, lister) }.to raise_error(ListTool::ListNotFoundError )
97
+ end
98
+ end
99
+
100
+ context 'when list not specified and no default list set' do
101
+ it 'raises NoDefaultListError' do
102
+ expect{ subject.execute({item: 2}, lister) }.to raise_error(ListTool::NoDefaultListError )
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+
109
+
110
+ describe '.help' do
111
+ it 'returns help message' do
112
+ expect( subject.help ).to be_a String
113
+ end
114
+ end
115
+
116
+ end