shashi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/shashi.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "shashi/version"
2
+ require "shashi/utils"
3
+ require "shashi/cli"
4
+ require "shashi/command"
5
+
6
+ module Shashi
7
+ end
data/lib/shashi/cli.rb ADDED
@@ -0,0 +1,121 @@
1
+ require "optparse"
2
+
3
+ module Shashi
4
+ module CLI
5
+
6
+ def self.perform(options:)
7
+ arguments = {
8
+ file: "./shashi__db.json",
9
+ path: [],
10
+ force: false,
11
+ echo: true,
12
+ deep: false,
13
+ index: nil,
14
+ count: 1,
15
+ }
16
+
17
+ opt_parser = OptionParser.new do |opts|
18
+ opts.banner = "Usage: shashi [options]"
19
+
20
+ opts.on("--setup", "Creates the storage file with an empty set.") do
21
+ arguments[:command] = :setup
22
+ end
23
+
24
+ opts.on("--file FILE", "Uses FILE as the desired file path for the storage. Defaults to `./shashi__db.json`.") do |file|
25
+ arguments[:file] = file
26
+ end
27
+
28
+ opts.on("--path PATH", "`PATH := List<KEY>[separator:.]`. Address the document's item by chaining a list of keys. For example: `key1.key2.key3`.") do |path|
29
+ arguments[:path] = path.split(".")
30
+ end
31
+
32
+ opts.on("--create-set NAME", "Creates an empty set. Asks for confirmation if the key NAME already exists.") do |name|
33
+ arguments[:command] = :create_set
34
+ arguments[:set_name] = name
35
+ end
36
+
37
+ opts.on("--set KEY:VALUE", "Sets the KEY to VALUE. Asks for confirmation if the key NAME already exists. If no VALUE is given, prompts for it.") do |pair|
38
+ arguments[:command] = :set_set
39
+ arguments[:key], arguments[:value] = pair.split(":")
40
+ end
41
+
42
+ opts.on("--show KEYS", "`KEYS := List<KEY>[separator:,]`. Shows the values associated with keys but not the content of sets/lists. For example: `name,e-mail`.") do |keys|
43
+ arguments[:command] = :show_keys
44
+ arguments[:keys] = keys.split(",")
45
+ end
46
+
47
+ opts.on("--delete KEY", "Deletes the item. Asks for confirmation if it's a non-empty set or list.") do |key|
48
+ arguments[:command] = :delete
49
+ arguments[:key] = key
50
+ end
51
+
52
+ opts.on("--create-list NAME", "Creates an empty list. Asks for confirmation if the key NAME already exists.") do |name|
53
+ arguments[:command] = :create_list
54
+ arguments[:list_name] = name
55
+ end
56
+
57
+ opts.on("--index INDEX", Integer, "`INDEX := (Integer >= 0)`. References the n-th element of a list. Defaults to the size of the list (ie: the last element).") do |index|
58
+ arguments[:index] = index
59
+ end
60
+
61
+ opts.on("--count COUNT", Integer, "`COUNT := (Integer > 0), defaults to 1`.") do |count|
62
+ arguments[:count] = count
63
+ end
64
+
65
+ opts.on("--list-push VALUES", "`VALUES := List<VALUE>[separator:,]`. Push VALUES into a list.") do |values|
66
+ arguments[:command] = :list_push
67
+ arguments[:values] = values.split(",")
68
+ end
69
+
70
+ opts.on("--list-show", "Shows `COUNT` elements of a list, starting from `INDEX`.") do
71
+ arguments[:command] = :list_show
72
+ end
73
+
74
+ opts.on("--list-delete", "Deletes `COUNT` elements from a list, starting from `INDEX`.") do
75
+ arguments[:command] = :list_delete
76
+ end
77
+
78
+ opts.on("--deep", "Shows the values associated with KEYS (recursively) even if they contain sets or lists.") do
79
+ arguments[:deep] = true
80
+ end
81
+
82
+ opts.on("--no-echo", "When prompted for a value, doesn't show it while typing.") do
83
+ arguments[:echo] = false
84
+ end
85
+
86
+ opts.on("--force", "Doesn't ask for confirmation.") do
87
+ arguments[:force] = true
88
+ end
89
+
90
+ opts.on("-h", "--help", "Prints this help") do
91
+ puts opts
92
+ exit
93
+ end
94
+ end
95
+
96
+ opt_parser.parse!(options)
97
+
98
+ if Utils.blank?(arguments[:command])
99
+ puts opt_parser
100
+ exit 1
101
+ end
102
+
103
+ if arguments[:index] && arguments[:index] < 0
104
+ puts "`INDEX` must be greater than or equal to 0."
105
+ puts opt_parser
106
+ exit 1
107
+ end
108
+
109
+ if arguments[:count] <= 0
110
+ puts "`COUNT` must be greater than 0."
111
+ puts opt_parser
112
+ exit 1
113
+ end
114
+
115
+ arguments[:file] = File.expand_path(arguments[:file])
116
+
117
+ Command.perform(arguments: arguments)
118
+ end
119
+
120
+ end
121
+ end
@@ -0,0 +1,83 @@
1
+ require_relative "command/setup"
2
+ require_relative "command/create_set"
3
+ require_relative "command/set_set"
4
+ require_relative "command/show_keys"
5
+ require_relative "command/set_delete"
6
+ require_relative "command/create_list"
7
+ require_relative "command/list_push"
8
+ require_relative "command/list_show"
9
+ require_relative "command/list_delete"
10
+
11
+ module Shashi
12
+ module Command
13
+
14
+ def self.perform(arguments:)
15
+ case arguments[:command]
16
+ when :setup
17
+ Setup.perform(file: arguments[:file])
18
+ when :create_set
19
+ CreateSet.perform(
20
+ file: arguments[:file],
21
+ path: arguments[:path],
22
+ set_name: arguments[:set_name],
23
+ force: arguments[:force]
24
+ )
25
+ when :set_set
26
+ SetSet.perform(
27
+ file: arguments[:file],
28
+ path: arguments[:path],
29
+ key: arguments[:key],
30
+ value: arguments[:value],
31
+ force: arguments[:force],
32
+ echo: arguments[:echo]
33
+ )
34
+ when :show_keys
35
+ ShowKeys.perform(
36
+ file: arguments[:file],
37
+ path: arguments[:path],
38
+ keys: arguments[:keys],
39
+ deep: arguments[:deep],
40
+ )
41
+ when :delete
42
+ SetDelete.perform(
43
+ file: arguments[:file],
44
+ path: arguments[:path],
45
+ key: arguments[:key],
46
+ force: arguments[:force],
47
+ )
48
+ when :create_list
49
+ CreateList.perform(
50
+ file: arguments[:file],
51
+ path: arguments[:path],
52
+ list_name: arguments[:list_name],
53
+ force: arguments[:force]
54
+ )
55
+ when :list_push
56
+ ListPush.perform(
57
+ file: arguments[:file],
58
+ path: arguments[:path],
59
+ values: arguments[:values],
60
+ index: arguments[:index]
61
+ )
62
+ when :list_show
63
+ ListShow.perform(
64
+ file: arguments[:file],
65
+ path: arguments[:path],
66
+ index: arguments[:index],
67
+ count: arguments[:count]
68
+ )
69
+ when :list_delete
70
+ ListDelete.perform(
71
+ file: arguments[:file],
72
+ path: arguments[:path],
73
+ index: arguments[:index],
74
+ count: arguments[:count]
75
+ )
76
+ else
77
+ puts "Command `#{arguments[:command]}` is not recognized."
78
+ exit 1
79
+ end
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,39 @@
1
+ module Shashi
2
+ module Command
3
+ module CreateList
4
+
5
+ def self.perform(file:, path:, list_name:, force:)
6
+ data = Utils::Database.read_database(file: file)
7
+ data_reference = Utils::Data.walk(data: data, path: path)
8
+ if data_reference.has_key?(list_name)
9
+ if force
10
+ update_data(file: file, data: data, data_reference: data_reference, list_name: list_name)
11
+ else
12
+ print "The key #{list_name} already exists at #{path.join(".")}, overwrite? [y/N] "
13
+ choice = gets
14
+ case choice.strip
15
+ when "y"
16
+ update_data(file: file, data: data, data_reference: data_reference, list_name: list_name)
17
+ when ""
18
+ # do nothing
19
+ when "N"
20
+ # do nothing
21
+ else
22
+ puts "Choice not understood, ignoring."
23
+ end
24
+ end
25
+ else
26
+ update_data(file: file, data: data, data_reference: data_reference, list_name: list_name)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def self.update_data(file:, data:, data_reference:, list_name:)
33
+ data_reference[list_name] = []
34
+ Utils::Database.write_database(file: file, data: data)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ module Shashi
2
+ module Command
3
+ module CreateSet
4
+
5
+ def self.perform(file:, path:, set_name:, force:)
6
+ data = Utils::Database.read_database(file: file)
7
+ data_reference = Utils::Data.walk(data: data, path: path)
8
+ if data_reference.has_key?(set_name)
9
+ if force
10
+ update_data(file: file, data: data, data_reference: data_reference, set_name: set_name)
11
+ else
12
+ print "The key #{set_name} already exists at #{path.join(".")}, overwrite? [y/N] "
13
+ choice = gets
14
+ case choice.strip
15
+ when "y"
16
+ update_data(file: file, data: data, data_reference: data_reference, set_name: set_name)
17
+ when ""
18
+ # do nothing
19
+ when "N"
20
+ # do nothing
21
+ else
22
+ puts "Choice not understood, ignoring."
23
+ end
24
+ end
25
+ else
26
+ update_data(file: file, data: data, data_reference: data_reference, set_name: set_name)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def self.update_data(file:, data:, data_reference:, set_name:)
33
+ data_reference[set_name] = {}
34
+ Utils::Database.write_database(file: file, data: data)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ module Shashi
2
+ module Command
3
+ module ListDelete
4
+
5
+ def self.perform(file:, path:, index: 0, count: 1)
6
+ data = Utils::Database.read_database(file: file)
7
+ data_reference = Utils::Data.walk(data: data, path: path)
8
+ if Utils::Data.is_list?(data_reference)
9
+ if index
10
+ if data_reference.count <= index
11
+ puts "The index `#{index}` is too high, the highest possible index for this list is currently `#{data_reference.count - 1}`."
12
+ exit 1
13
+ end
14
+ if data_reference.count < index + count
15
+ puts "Starting from index `#{index}` you can delete to a maximum of `#{data_reference.count - index}`."
16
+ exit 1
17
+ end
18
+ else
19
+ index = 0;
20
+ end
21
+ data_reference.reject!.with_index do |value, i|
22
+ i >= index && i < index + count
23
+ end
24
+ Utils::Database.write_database(file: file, data: data)
25
+ else
26
+ puts "Path `#{path.join(".")}` doesn't lead to a list."
27
+ exit 1
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ module Shashi
2
+ module Command
3
+ module ListPush
4
+
5
+ def self.perform(file:, path:, values: [], index: -1)
6
+ data = Utils::Database.read_database(file: file)
7
+ data_reference = Utils::Data.walk(data: data, path: path)
8
+ if Utils::Data.is_list?(data_reference)
9
+ if index
10
+ if data_reference.count <= index
11
+ puts "The index `#{index}` is too high, the highest possible index for this list is currently `#{data_reference.count - 1}`."
12
+ exit 1
13
+ end
14
+ else
15
+ index = -1;
16
+ end
17
+ data_reference.insert(index, *values)
18
+ Utils::Database.write_database(file: file, data: data)
19
+ else
20
+ puts "Path `#{path.join(".")}` doesn't lead to a list."
21
+ exit 1
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,45 @@
1
+ module Shashi
2
+ module Command
3
+ module ListShow
4
+
5
+ def self.perform(file:, path:, index: 0, count: 1)
6
+ data = Utils::Database.read_database(file: file)
7
+ data_reference = Utils::Data.walk(data: data, path: path)
8
+ if Utils::Data.is_list?(data_reference)
9
+ if index
10
+ if data_reference.count <= index
11
+ puts "The index `#{index}` is too high, the highest possible index for this list is currently `#{data_reference.count - 1}`."
12
+ exit 1
13
+ end
14
+ if data_reference.count < index + count
15
+ puts "Starting from index `#{index}` you can access to a maximum of `#{data_reference.count - index}`."
16
+ exit 1
17
+ end
18
+ else
19
+ index = 0;
20
+ end
21
+ range_string = if index == index + count - 1
22
+ index
23
+ else
24
+ "#{index}-#{index + count}"
25
+ end
26
+ puts "`#{path.join(".")}`[#{range_string}]:"
27
+ data_reference[index..(index + count - 1)].each do |item|
28
+ content = if Utils::Data.is_list?(item)
29
+ "#List#"
30
+ elsif Utils::Data.is_set?(item)
31
+ "#Set#"
32
+ else
33
+ item
34
+ end
35
+ puts "- #{content}"
36
+ end
37
+ else
38
+ puts "Path `#{path.join(".")}` doesn't lead to a list."
39
+ exit 1
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,57 @@
1
+ module Shashi
2
+ module Command
3
+ module SetDelete
4
+
5
+ def self.perform(file:, path:, key:, force:)
6
+ data = Utils::Database.read_database(file: file)
7
+ data_reference = Utils::Data.walk(data: data, path: path)
8
+ if data_reference.has_key?(key)
9
+ if force
10
+ update_data(file: file, data: data, data_reference: data_reference, key: key)
11
+ else
12
+ value = data_reference[key]
13
+ if Utils::Data.is_list?(value)
14
+ if confirms_deletion?(key: key, path: path, value_type: "#List#")
15
+ update_data(file: file, data: data, data_reference: data_reference, key: key)
16
+ end
17
+ elsif Utils::Data.is_set?(value)
18
+ if confirms_deletion?(key: key, path: path, value_type: "#Set#")
19
+ update_data(file: file, data: data, data_reference: data_reference, key: key)
20
+ end
21
+ else
22
+ update_data(file: file, data: data, data_reference: data_reference, key: key)
23
+ end
24
+ end
25
+ else
26
+ puts "There is no key `#{key}` at `#{path.join(".")}`"
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def self.confirms_deletion?(key:, path:, value_type:)
33
+ print "The key `#{key}` at `#{path.join(".")}` contains a `#{value_type}`, confirm deletion? [y/N] "
34
+ choice = gets.strip
35
+ case choice
36
+ when "y"
37
+ true
38
+ when ""
39
+ # do nothing
40
+ false
41
+ when "N"
42
+ # do nothing
43
+ false
44
+ else
45
+ puts "Choice not understood, ignoring."
46
+ false
47
+ end
48
+ end
49
+
50
+ def self.update_data(file:, data:, data_reference:, key:)
51
+ data_reference.delete(key)
52
+ Utils::Database.write_database(file: file, data: data)
53
+ end
54
+
55
+ end
56
+ end
57
+ end