shashi 0.1.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.
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