coding_challenge 0.1.0 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +84 -71
- data/coding_challenge.gemspec +1 -1
- data/gif1.gif +0 -0
- data/gif2.gif +0 -0
- data/lib/coding_challenge/commands/start.rb +33 -28
- data/lib/coding_challenge/commands/util/Inventory.rb +57 -54
- data/lib/coding_challenge/commands/util/file_read_error.rb +7 -0
- data/lib/coding_challenge/commands/util/invalid_option_error.rb +7 -0
- data/lib/coding_challenge/commands/util/invalid_product_type_error.rb +7 -0
- data/lib/coding_challenge/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfa7e08afbb3d98f9be768a7b97f9ec2c3d39ae40d5d4a1db52e4c8f2da4b87b
|
4
|
+
data.tar.gz: d85e74ec08bb62fb508dc06f760acb8f6a562399b797cbb19239d374dbe9a9c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce40b7010eaadf8b84842db73b690938f311627498bbedd01df1d8e09382aa1377e54ed0a8307f232ed7725277ba6201c40f5a7e5f8073f050cc1d77e9d9a975
|
7
|
+
data.tar.gz: fb13542e35ab806616132e23a8f2166d10d95d55b24cd46f62242e6e2182f63ad226e8bb1d76930c72955da03b872c36d759efcab914dd56f0ca500b442a58d6
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
# CodingChallenge
|
2
2
|
|
3
|
-
Had fun with this.
|
3
|
+
Had fun with this. I published it as gem here: https://rubygems.org/gems/coding_challenge.
|
4
|
+
|
5
|
+
## Quickstart
|
6
|
+
|
7
|
+
`gem install coding_challenge` then
|
8
|
+
`coding_challenge start`
|
9
|
+
|
10
|
+
## Screenshots
|
11
|
+
|
12
|
+
1. using CLI menu to input arguements
|
13
|
+

|
14
|
+
2. inputting arguments directly from commandline
|
15
|
+

|
4
16
|
|
5
17
|
## Installation
|
6
18
|
|
@@ -10,7 +22,7 @@ Clone repo. Then in project directory `bundle install`.
|
|
10
22
|
|
11
23
|
2. via rubygems
|
12
24
|
|
13
|
-
|
25
|
+
`gem install coding_challenge`
|
14
26
|
|
15
27
|
## Usage
|
16
28
|
|
@@ -20,91 +32,96 @@ To run with a cool CLI UI at the start, either do:
|
|
20
32
|
- (IF INSTALLED AS GEM) from CLI do: `coding_challenge start [product type] [options]`
|
21
33
|
|
22
34
|
To run without a cool CLI UI at the start but have it appear after, either do:
|
23
|
-
|
24
|
-
|
35
|
+
|
36
|
+
- (IF CLONED) Go to project directory and: `./exe/coding_challenge start [product type] [options] --skip_intro_animation=true`
|
37
|
+
- (IF INSTALLED AS GEM) from CLI do: `coding_challenge start [product type] [options] --skip_intro_animation=true`
|
25
38
|
|
26
39
|
## Testing
|
27
40
|
|
28
41
|
Clone and go to project directory and do `rspec spec`
|
29
42
|
|
30
|
-
## Code
|
31
|
-
|
32
|
-
I use an object to group together the query args and results like so
|
33
|
-
|
34
|
-
```
|
35
|
-
class Query
|
36
|
-
attr_reader :product_type, :options, :results
|
37
|
-
attr_writer :performed_at, :results
|
38
|
-
|
39
|
-
def initialize(query_args)
|
40
|
-
@product_type = query_args[0]
|
41
|
-
@options = query_args.slice(1, query_args.length)
|
42
|
-
@performed_at = nil
|
43
|
-
@results = nil
|
44
|
-
end
|
43
|
+
## Code Explanation
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
results_str += " Product Type Arg: #{@product_type}\n"
|
49
|
-
results_str += " Options Args: #{@options.join(', ')}\n"
|
50
|
-
results_str += " Results:\n"
|
51
|
-
results_str += " #{@results.join("\n ")}"
|
45
|
+
Since the product list is represented as an array, there is NO
|
46
|
+
way to solve this problem in O(1) time.
|
52
47
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
48
|
+
At the very least, any solution is going to require 1 full iteration through the product list.
|
49
|
+
What we can do, is create a hash based schema that will group all of the product types, option types,
|
50
|
+
and option values as keys in a logical hierachy so that afterwards, detecting the prescence of data can be done
|
51
|
+
simply by attempting to access it from the hash as a key O(1) time.
|
57
52
|
|
58
|
-
|
53
|
+
I tried to do this compactly/elegantly by creating the following method and having it execute
|
54
|
+
immediately after reading the products list:
|
59
55
|
|
60
56
|
```
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
search_start = query.options.length
|
69
|
-
option_types = product['options'].keys
|
70
|
-
|
71
|
-
(search_start..option_types.length - 1).each do |i|
|
72
|
-
option_type = option_types[i]
|
73
|
-
option_value = product['options'][option_type]
|
74
|
-
|
75
|
-
if remaining_props_seen[option_type].nil?
|
76
|
-
remaining_props_seen[option_type] = {}
|
77
|
-
remaining_props_seen[option_type][option_value] = true
|
78
|
-
remaining_props.push("#{option_type.capitalize}: #{option_value}")
|
79
|
-
elsif !remaining_props_seen[option_type][option_value]
|
80
|
-
remaining_props_seen[option_type][option_value] = true
|
81
|
-
remaining_props[i - search_start] += ", #{option_value}"
|
82
|
-
end
|
57
|
+
def index_product_schema(products_list)
|
58
|
+
products_schema = {}
|
59
|
+
products_list.each do |p|
|
60
|
+
if !products_schema.key?(p['product_type'])
|
61
|
+
products_schema[p['product_type']] = p['options'].transform_values { |o| Hash[o, true] }
|
62
|
+
else
|
63
|
+
products_schema[p['product_type']].merge!(p['options']) { |_, o, n| o.merge(Hash[n, true]) }
|
83
64
|
end
|
84
65
|
end
|
66
|
+
products_schema
|
67
|
+
end
|
85
68
|
```
|
86
69
|
|
87
|
-
|
70
|
+
The above operation going to require one loop through the product list and then for each item,
|
71
|
+
a nested loop that runs for the number of option types that exist for that item.
|
88
72
|
|
89
|
-
|
90
|
-
This method invokes some private methods I created for handling the cases but the logic is captured here:
|
73
|
+
The generated products schema would look like this:
|
91
74
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
load_from_file_path(source_uri)
|
96
|
-
elsif source_type == 'URL'
|
97
|
-
load_from_file_url(source_uri)
|
98
|
-
end
|
75
|
+
`{"tshirt"=>{"gender"=>{"male"=>true, "female"=>true}, "color"=>{"red"=>true, "green"=>true, "navy"=>true, "white"=>true, "black"=>true}, "size"=>{"small"=>true, "medium"=>true, "large"=>true, "extra-large"=>true, "2x-large"=>true}}, "mug"=>{"type"=>{"coffee-mug"=>true, "travel-mug"=>true}}, "sticker"=>{"size"=>{"x-small"=>true, "small"=>true, "medium"=>true, "large"=>true, "x-large"=>true}, "style"=>{"matte"=>true, "glossy"=>true}}}`
|
76
|
+
|
77
|
+
Run Time ~> sum of O(num_option_types<sub>i</sub>) where i goes from 1 to the length of the products_list array
|
99
78
|
|
100
|
-
|
101
|
-
|
102
|
-
|
79
|
+
Next, the following method below will execute using the product_schema produced by `index_product_schema`.
|
80
|
+
|
81
|
+
You can see that validating the precesence of/accessing the options schema for a particular
|
82
|
+
product type is done in O(1) in the first line.
|
83
|
+
|
84
|
+
In an option schema for a given product type, the keys are option types and the values are hashes that contain keys
|
85
|
+
every possible option value for a given option type.
|
86
|
+
ex for sticker:
|
87
|
+
|
88
|
+
`{"size"=>{"x-small"=>true, "small"=>true, "medium"=>true, "large"=>true, "x-large"=>true}, "style"=>{"matte"=>true, "glossy"=>true}}`
|
89
|
+
We can now iterate through all of the option types/option values pairs using an index value (arg_position) to keep
|
90
|
+
track of our position in the hash.
|
91
|
+
|
92
|
+
Validating an options argument against possible option values is done using the index to match up
|
93
|
+
the CLI argument at the position of the index to the current option types/option values pair. We do this in O(1)
|
94
|
+
time by seeing if the argument exists as a key in the option values pair.
|
95
|
+
|
96
|
+
The current option values hash is transformed into a friendly string by joining the keys
|
97
|
+
together with commas.
|
98
|
+
|
99
|
+
The main loop will execute for the number of option types for a given product type regardless of the
|
100
|
+
size of the cli arguments input, which is a respective constant for each product type, so it is there for O(1).
|
101
|
+
|
102
|
+
```
|
103
|
+
def handle_query(query)
|
104
|
+
product_options_schema = @products_schema[query.product_type.downcase]
|
105
|
+
is_invalid_product_type = product_options_schema.nil?
|
106
|
+
raise InvalidProductTypeError, query.product_type if is_invalid_product_type
|
107
|
+
|
108
|
+
results = []
|
109
|
+
product_options_schema.each_with_index do |(option_type, option_values_map), arg_position|
|
110
|
+
option_argument = query.options[arg_position]
|
111
|
+
is_argument_provided = !option_argument.nil?
|
112
|
+
|
113
|
+
if is_argument_provided
|
114
|
+
is_invalid_argument = !option_values_map.key?(option_argument)
|
115
|
+
raise InvalidOptionError.new(query.product_type, option_type, option_argument) if is_invalid_argument
|
116
|
+
else
|
117
|
+
possible_option_values = option_values_map.keys
|
118
|
+
results << "#{option_type.capitalize}: #{possible_option_values.join(', ')}"
|
119
|
+
end
|
103
120
|
end
|
104
121
|
|
105
|
-
|
122
|
+
query.results = results
|
123
|
+
query
|
106
124
|
end
|
107
|
-
|
108
125
|
```
|
109
126
|
|
110
127
|
## Contributing
|
@@ -118,7 +135,3 @@ Everyone interacting in the CodingChallenge project's codebases, issue trackers,
|
|
118
135
|
## Copyright
|
119
136
|
|
120
137
|
Copyright (c) 2020 Jorge Navarro. See [MIT License](LICENSE.txt) for further details.
|
121
|
-
|
122
|
-
```
|
123
|
-
|
124
|
-
```
|
data/coding_challenge.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = 'A hiring coding challenge.'
|
13
13
|
spec.description = 'A Ruby CLI app made for hiring coding challenge.'
|
14
14
|
spec.homepage = 'https://github.com/Jnavarr56/REDACTED-3-coding-challenge'
|
15
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
|
16
16
|
|
17
17
|
# blank for now
|
18
18
|
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
data/gif1.gif
ADDED
Binary file
|
data/gif2.gif
ADDED
Binary file
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../command'
|
4
|
-
require_relative './util/
|
5
|
-
require_relative './util/
|
4
|
+
require_relative './util/inventory'
|
5
|
+
require_relative './util/query'
|
6
6
|
require_relative './util/animation'
|
7
|
+
require_relative './util/invalid_product_type_error'
|
8
|
+
require_relative './util/invalid_option_error'
|
9
|
+
require_relative './util/file_read_error'
|
7
10
|
|
8
11
|
require 'tty-spinner'
|
9
12
|
require 'colorize'
|
@@ -35,16 +38,20 @@ module CodingChallenge
|
|
35
38
|
loading_animation('Calculating results...', 2)
|
36
39
|
|
37
40
|
new_inventory = Inventory.new
|
38
|
-
new_inventory.load_products_list_from_default
|
39
|
-
@inventory = new_inventory
|
40
41
|
|
41
|
-
|
42
|
-
|
42
|
+
begin
|
43
|
+
new_inventory.load_products_list_from_default
|
44
|
+
@inventory = new_inventory
|
45
|
+
new_query = Query.new(cli_args)
|
46
|
+
query_with_results = @inventory.handle_query(new_query)
|
43
47
|
|
44
|
-
|
45
|
-
|
48
|
+
puts 'Results:'.colorize(:yellow)
|
49
|
+
puts query_with_results.results
|
46
50
|
|
47
|
-
|
51
|
+
@queries.push(query_with_results.formatted_results)
|
52
|
+
rescue StandardError => e
|
53
|
+
puts "#{e.class.name}: #{e.message}".colorize(:red)
|
54
|
+
end
|
48
55
|
end
|
49
56
|
|
50
57
|
exited = false
|
@@ -124,14 +131,11 @@ module CodingChallenge
|
|
124
131
|
loading_animation('Checking file readability...', 2)
|
125
132
|
begin
|
126
133
|
new_inventory.load_products_list_from_source('FILE PATH', new_filepath)
|
127
|
-
|
128
|
-
raise StandardError if new_inventory.products_list.nil?
|
129
|
-
|
130
134
|
@inventory = new_inventory
|
131
135
|
prompt.say("\nFile loaded successfully!")
|
132
136
|
done = true
|
133
|
-
rescue StandardError
|
134
|
-
|
137
|
+
rescue StandardError => e
|
138
|
+
puts "#{e.class.name}: #{e.message}".colorize(:red)
|
135
139
|
end
|
136
140
|
end
|
137
141
|
end
|
@@ -146,15 +150,14 @@ module CodingChallenge
|
|
146
150
|
spinner.auto_spin
|
147
151
|
begin
|
148
152
|
new_inventory.load_products_list_from_source('URL', new_file_url)
|
149
|
-
raise StandardError if new_inventory.products_list.nil?
|
150
|
-
|
151
153
|
@inventory = new_inventory
|
152
154
|
prompt.say("\nFile fetched successfully!")
|
153
155
|
done = true
|
154
|
-
|
155
|
-
|
156
|
+
spinner.stop
|
157
|
+
rescue StandardError => e
|
158
|
+
spinner.stop
|
159
|
+
puts "#{e.class.name}: #{e.message}".colorize(:red)
|
156
160
|
end
|
157
|
-
spinner.stop
|
158
161
|
end
|
159
162
|
|
160
163
|
end
|
@@ -163,12 +166,10 @@ module CodingChallenge
|
|
163
166
|
spinner.auto_spin
|
164
167
|
begin
|
165
168
|
new_inventory.load_products_list_from_default
|
166
|
-
raise StandardError if new_inventory.products_list.nil?
|
167
|
-
|
168
169
|
@inventory = new_inventory
|
169
170
|
prompt.say("\nDefault file fetched successfully!")
|
170
|
-
rescue StandardError
|
171
|
-
|
171
|
+
rescue StandardError => e
|
172
|
+
puts "#{e.class.name}: #{e.message}".colorize(:red)
|
172
173
|
end
|
173
174
|
spinner.stop
|
174
175
|
end
|
@@ -202,11 +203,15 @@ module CodingChallenge
|
|
202
203
|
puts ''
|
203
204
|
|
204
205
|
new_query = Query.new(args)
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
206
|
+
|
207
|
+
begin
|
208
|
+
query_with_results = @inventory.handle_query(new_query)
|
209
|
+
puts 'Results:'.colorize(:yellow)
|
210
|
+
puts query_with_results.results
|
211
|
+
@queries.push(query_with_results.formatted_results)
|
212
|
+
rescue StandardError => e
|
213
|
+
puts "#{e.class.name}: #{e.message}".colorize(:red)
|
214
|
+
end
|
210
215
|
|
211
216
|
0
|
212
217
|
end
|
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative './invalid_product_type_error'
|
4
|
+
require_relative './invalid_option_error'
|
5
|
+
require_relative './file_read_error'
|
6
|
+
|
3
7
|
require 'net/http'
|
4
8
|
require 'json'
|
5
9
|
require 'date'
|
@@ -11,87 +15,86 @@ class Inventory
|
|
11
15
|
@source_type = nil
|
12
16
|
@source_uri = nil
|
13
17
|
@products_list = nil
|
18
|
+
@products_schema = nil
|
14
19
|
end
|
15
20
|
|
16
21
|
def handle_query(query)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
remaining_props_seen[option_type][option_value] = true
|
33
|
-
remaining_props.push("#{option_type.capitalize}: #{option_value}")
|
34
|
-
elsif !remaining_props_seen[option_type][option_value]
|
35
|
-
remaining_props_seen[option_type][option_value] = true
|
36
|
-
remaining_props[i - search_start] += ", #{option_value}"
|
37
|
-
end
|
22
|
+
product_options_schema = @products_schema[query.product_type.downcase]
|
23
|
+
is_invalid_product_type = product_options_schema.nil?
|
24
|
+
raise InvalidProductTypeError, query.product_type if is_invalid_product_type
|
25
|
+
|
26
|
+
results = []
|
27
|
+
product_options_schema.each_with_index do |(option_type, option_values_map), arg_position|
|
28
|
+
option_argument = query.options[arg_position]
|
29
|
+
is_argument_provided = !option_argument.nil?
|
30
|
+
|
31
|
+
if is_argument_provided
|
32
|
+
is_invalid_argument = !option_values_map.key?(option_argument)
|
33
|
+
raise InvalidOptionError.new(query.product_type, option_type, option_argument) if is_invalid_argument
|
34
|
+
else
|
35
|
+
possible_option_values = option_values_map.keys
|
36
|
+
results << "#{option_type.capitalize}: #{possible_option_values.join(', ')}"
|
38
37
|
end
|
39
38
|
end
|
40
39
|
|
41
|
-
query.
|
42
|
-
query.results = remaining_props
|
43
|
-
|
40
|
+
query.results = results
|
44
41
|
query
|
45
42
|
end
|
46
43
|
|
47
44
|
def load_products_list_from_source(source_type, source_uri)
|
48
|
-
|
49
|
-
load_from_file_path(source_uri)
|
50
|
-
|
51
|
-
|
45
|
+
begin
|
46
|
+
products_list = load_from_file_path(source_uri) if source_type == 'FILE PATH'
|
47
|
+
products_list = load_from_file_url(source_uri) if source_type == 'URL'
|
48
|
+
raise StandardError if products_list.nil?
|
49
|
+
rescue StandardError
|
50
|
+
raise FileReadError, source_uri
|
52
51
|
end
|
52
|
+
set_as_data_source(source_type, source_uri, products_list)
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
def load_products_list_from_default
|
56
|
+
begin
|
57
|
+
products_list = load_from_file_url(@@DEFAULT_PRODUCTS_LIST_URL)
|
58
|
+
raise StandardError if products_list.nil?
|
59
|
+
rescue StandardError
|
60
|
+
raise FileReadError, source_uri
|
57
61
|
end
|
58
|
-
|
59
|
-
@products_list
|
62
|
+
set_as_data_source('DEFAULT', @@DEFAULT_PRODUCTS_LIST_URL, products_list)
|
60
63
|
end
|
61
64
|
|
62
|
-
|
63
|
-
load_from_file_url(@@DEFAULT_PRODUCTS_LIST_URL)
|
65
|
+
private
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
67
|
+
def index_product_schema(products_list)
|
68
|
+
products_schema = {}
|
69
|
+
products_list.each do |p|
|
70
|
+
if !products_schema.key?(p['product_type'])
|
71
|
+
products_schema[p['product_type']] = p['options'].transform_values { |o| Hash[o, true] }
|
72
|
+
else
|
73
|
+
products_schema[p['product_type']].merge!(p['options']) { |_, o, n| o.merge(Hash[n, true]) }
|
74
|
+
end
|
68
75
|
end
|
69
|
-
|
70
|
-
@products_list
|
76
|
+
products_schema
|
71
77
|
end
|
72
78
|
|
73
|
-
|
79
|
+
def set_as_data_source(source_type, source_uri, products_list)
|
80
|
+
@products_list = products_list
|
81
|
+
@products_schema = index_product_schema(products_list)
|
82
|
+
@source_type = source_type
|
83
|
+
@source_uri = source_uri
|
84
|
+
end
|
74
85
|
|
75
86
|
def load_from_file_path(file_path)
|
76
87
|
products_list_file = File.open(file_path)
|
77
88
|
products_list_file_content = products_list_file.read
|
78
89
|
products_list_hash = JSON.parse(products_list_file_content)
|
79
|
-
|
80
|
-
@products_list = products_list_hash
|
81
|
-
rescue StandardError
|
82
|
-
@products_list = nil
|
90
|
+
products_list_hash
|
83
91
|
end
|
84
92
|
|
85
93
|
def load_from_file_url(url)
|
86
94
|
request_uri = URI(url)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
@products_list = products_list_hash
|
93
|
-
rescue StandardError
|
94
|
-
@products_list = nil
|
95
|
-
end
|
95
|
+
request_response = Net::HTTP.get_response(request_uri)
|
96
|
+
request_response_content = request_response.body
|
97
|
+
products_list_hash = JSON.parse(request_response_content)
|
98
|
+
products_list_hash
|
96
99
|
end
|
97
100
|
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class InvalidOptionError < StandardError
|
4
|
+
def initialize(product_type, option_type, option_argument)
|
5
|
+
super("Product of type #{product_type.upcase} and #{option_type.upcase} option type of value #{option_argument.upcase} not in catalog!")
|
6
|
+
end
|
7
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coding_challenge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jorge Navarro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -127,6 +127,8 @@ files:
|
|
127
127
|
- bin/setup
|
128
128
|
- coding_challenge.gemspec
|
129
129
|
- exe/coding_challenge
|
130
|
+
- gif1.gif
|
131
|
+
- gif2.gif
|
130
132
|
- lib/coding_challenge.rb
|
131
133
|
- lib/coding_challenge/cli.rb
|
132
134
|
- lib/coding_challenge/command.rb
|
@@ -135,6 +137,9 @@ files:
|
|
135
137
|
- lib/coding_challenge/commands/util/Inventory.rb
|
136
138
|
- lib/coding_challenge/commands/util/Query.rb
|
137
139
|
- lib/coding_challenge/commands/util/animation.rb
|
140
|
+
- lib/coding_challenge/commands/util/file_read_error.rb
|
141
|
+
- lib/coding_challenge/commands/util/invalid_option_error.rb
|
142
|
+
- lib/coding_challenge/commands/util/invalid_product_type_error.rb
|
138
143
|
- lib/coding_challenge/templates/.gitkeep
|
139
144
|
- lib/coding_challenge/templates/start/.gitkeep
|
140
145
|
- lib/coding_challenge/version.rb
|
@@ -153,7 +158,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
153
158
|
requirements:
|
154
159
|
- - ">="
|
155
160
|
- !ruby/object:Gem::Version
|
156
|
-
version: 2.
|
161
|
+
version: 2.6.0
|
157
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
163
|
requirements:
|
159
164
|
- - ">="
|