sesame-cli 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/Gemfile +4 -1
- data/Gemfile.lock +16 -0
- data/README.md +36 -22
- data/Rakefile +14 -16
- data/VERSION +1 -1
- data/bin/sesame +12 -10
- data/lib/sesame/cave.rb +101 -61
- data/lib/sesame/dict.rb +7 -5
- data/lib/sesame/fail.rb +2 -0
- data/lib/sesame/jinn.rb +134 -84
- data/lib/sesame/lang/en.yml +2 -0
- data/lib/sesame.rb +2 -0
- data/sesame-cli.gemspec +12 -6
- data/spec/cave_spec.rb +188 -0
- data/spec/dict_spec.rb +13 -0
- data/spec/jinn_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -4
- metadata +22 -5
- data/sesame.gemspec +0 -99
data/lib/sesame/jinn.rb
CHANGED
@@ -1,27 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'highline/import'
|
2
4
|
require 'i18n'
|
3
5
|
require 'clipboard'
|
4
6
|
|
5
7
|
module Sesame
|
8
|
+
# The Jinn class is wholly responsible for interacting with the terminal.
|
6
9
|
class Jinn
|
10
|
+
# Pass in parsed command-line options as a Slop instance.
|
7
11
|
def initialize(opts)
|
12
|
+
I18n.load_path = Dir[File.join(File.dirname(__FILE__), 'lang', '*yml')]
|
8
13
|
@opts = opts
|
14
|
+
_config
|
9
15
|
_parse
|
10
16
|
_welcome
|
11
17
|
@sesame = Cave.new(@opts[:path])
|
12
|
-
I18n.load_path = Dir[File.join(File.dirname(__FILE__), 'lang', '*yml')]
|
13
18
|
rescue Fail => e
|
14
19
|
_error(e.message)
|
15
20
|
end
|
16
21
|
|
22
|
+
# Process the users request, possibly starting an interactive session.
|
17
23
|
def process!
|
18
|
-
|
24
|
+
return if @sesame.nil?
|
25
|
+
@was_locked = false
|
26
|
+
raise Fail, 'Cannot lock and expunge simultaneously' if @opts.lock? && @opts.expunge?
|
19
27
|
if @sesame.exists?
|
20
|
-
|
28
|
+
raise Fail, 'Please remove the cave before attempting to reconstruct' if @opts.reconstruct?
|
29
|
+
raise Fail, 'Cannot expunge lock; it doesn\'t exist' if @opts.expunge? && !@sesame.locked?
|
30
|
+
raise Fail, 'Please specify a command (or use interactive mode)' if !@opts.interactive? && @opts[:command].nil? && !@opts.lock? && !@opts.expunge?
|
31
|
+
if @sesame.locked? && @opts.expunge?
|
32
|
+
@sesame.forget
|
33
|
+
_warn('Lock expunged')
|
34
|
+
end
|
21
35
|
if @sesame.locked?
|
22
36
|
_unlock
|
23
|
-
@
|
24
|
-
was_locked = true
|
37
|
+
@was_locked = true
|
25
38
|
else
|
26
39
|
_open
|
27
40
|
end
|
@@ -30,7 +43,7 @@ module Sesame
|
|
30
43
|
_new
|
31
44
|
end
|
32
45
|
_process(@opts[:command])
|
33
|
-
if @opts
|
46
|
+
if @opts.interactive?
|
34
47
|
loop do
|
35
48
|
say("\n")
|
36
49
|
break if _prompt
|
@@ -38,32 +51,62 @@ module Sesame
|
|
38
51
|
if @opts.expunge?
|
39
52
|
@sesame.close
|
40
53
|
else
|
41
|
-
_lock
|
54
|
+
_lock
|
42
55
|
end
|
43
|
-
elsif was_locked
|
44
|
-
_lock(true)
|
45
|
-
else
|
56
|
+
elsif @opts.expunge? || (!@was_locked && !@opts.lock?)
|
46
57
|
@sesame.close
|
58
|
+
else
|
59
|
+
_lock
|
47
60
|
end
|
48
61
|
rescue Fail => e
|
49
62
|
_error(e.message)
|
63
|
+
rescue SystemExit, Interrupt
|
64
|
+
_error('Stopped by user')
|
50
65
|
end
|
51
66
|
|
52
67
|
protected
|
53
68
|
|
54
69
|
def _welcome
|
55
70
|
return if @opts[:quiet]
|
56
|
-
say(HighLine.color(<<~
|
71
|
+
say(HighLine.color(<<~WELCOME, :bold, :yellow))
|
57
72
|
╔═════════════════════════════════════╗
|
58
73
|
║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━┓ ┏┓ ┏┓ ┏━━━┓ ║
|
59
74
|
║ ┗━╋━┓ ┣━━┫ ┗━╋━┓ ┏┻━┻┓ ┃┗┳┛┃ ┣━━┫ ║
|
60
75
|
║ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗ ┛ ┗ ┛ ┗━━━┛ ║
|
61
76
|
╚═════════════════════════════════════╝
|
62
|
-
|
77
|
+
WELCOME
|
78
|
+
end
|
79
|
+
|
80
|
+
def _load_config(base = '.', name = '.sesamerc')
|
81
|
+
path = File.join(base, name)
|
82
|
+
if File.exist?(path)
|
83
|
+
JSON.parse(File.read(path), symbolize_names: true)
|
84
|
+
elsif name == '.sesamerc'
|
85
|
+
_load_config(base, 'sesame.cfg')
|
86
|
+
elsif base == '.'
|
87
|
+
_load_config(Dir.home)
|
88
|
+
else
|
89
|
+
{}
|
90
|
+
end
|
91
|
+
rescue JSON::ParserError
|
92
|
+
raise Fail, "#{path} is not valid JSON"
|
93
|
+
end
|
94
|
+
|
95
|
+
def _config
|
96
|
+
config = _load_config
|
97
|
+
_set_opt(:echo, config[:echo]) unless @opts.echo?
|
98
|
+
_set_opt(:interactive, config[:interactive]) unless @opts.interactive?
|
99
|
+
_set_opt(:quiet, config[:quiet]) unless @opts.quiet?
|
100
|
+
config[:path] ||= ENV.fetch('SESAME_PATH', '.')
|
101
|
+
_set_opt(:path, config[:path]) if @opts[:path].nil?
|
102
|
+
_set_opt(:path, File.expand_path(@opts[:path]))
|
63
103
|
end
|
64
104
|
|
65
105
|
def _parse
|
66
|
-
|
106
|
+
unless Dir.exist?(@opts[:path])
|
107
|
+
_error("No such directory: #{@opts[:path]}")
|
108
|
+
exit 2
|
109
|
+
end
|
67
110
|
_set_command('list') if @opts.list?
|
68
111
|
_set_command('add') if @opts.add?
|
69
112
|
_set_command('get') if @opts.get?
|
@@ -71,32 +114,11 @@ module Sesame
|
|
71
114
|
_set_command('delete') if @opts.delete?
|
72
115
|
end
|
73
116
|
|
74
|
-
def _set_path
|
75
|
-
# set @opts[:path] if nil from .sesamerc and then $SESAME_PATH and then current dir
|
76
|
-
if @opts[:path].nil?
|
77
|
-
@opts[:path] = _load_config || ENV.fetch('SESAME_PATH', '.')
|
78
|
-
end
|
79
|
-
@opts[:path] = File.expand_path(@opts[:path])
|
80
|
-
unless Dir.exist?(@opts[:path])
|
81
|
-
say("No such directory: #{@opts[:path]}")
|
82
|
-
exit 2
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def _load_config(base=".")
|
87
|
-
path = File.join(base, '.sesamerc')
|
88
|
-
if File.exist?(path)
|
89
|
-
File.read(path)
|
90
|
-
elsif base == '.'
|
91
|
-
_load_config(Dir.home)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
117
|
def _set_command(name)
|
96
118
|
if @opts[:command].nil?
|
97
|
-
|
119
|
+
_set_opt(:command, name)
|
98
120
|
else
|
99
|
-
|
121
|
+
_error("Cannot #{name} and #{@opts[:command]}")
|
100
122
|
exit 2
|
101
123
|
end
|
102
124
|
end
|
@@ -115,104 +137,115 @@ module Sesame
|
|
115
137
|
when :delete
|
116
138
|
_delete
|
117
139
|
else
|
118
|
-
_error
|
140
|
+
_error('Command not recognised')
|
119
141
|
end
|
120
142
|
end
|
121
143
|
|
122
144
|
def _prompt
|
123
145
|
done = false
|
124
|
-
_info(
|
146
|
+
_info('prompt')
|
125
147
|
choose do |menu|
|
126
148
|
menu.prompt = "\n> "
|
127
149
|
menu.shell = true
|
128
|
-
menu.choice(:list,
|
150
|
+
menu.choice(:list, 'Display all of the services and users in your Sesame store.') do |_, args|
|
129
151
|
_set_opts(args)
|
130
152
|
_list
|
131
153
|
end
|
132
|
-
menu.choice(:add,
|
154
|
+
menu.choice(:add, 'Add a new service and user to your Sesame store.') do |_, args|
|
133
155
|
_set_opts(args)
|
134
156
|
_add
|
135
157
|
end
|
136
|
-
menu.choice(:get,
|
158
|
+
menu.choice(:get, 'Retrieve the pass phrase for a service and user.') do |_, args|
|
137
159
|
_set_opts(args)
|
138
160
|
_get
|
139
161
|
end
|
140
|
-
menu.choice(:next,
|
162
|
+
menu.choice(:next, 'Generate a new passphrase for a service and user.') do |_, args|
|
141
163
|
_set_opts(args)
|
142
164
|
_next
|
143
165
|
end
|
144
|
-
menu.choice(:delete,
|
166
|
+
menu.choice(:delete, 'Remove a service and user from the Sesame store.') do |_, args|
|
145
167
|
_set_opts(args)
|
146
168
|
_delete
|
147
169
|
end
|
148
|
-
menu.choice(:exit,
|
170
|
+
menu.choice(:exit, 'Close Sesame.') do
|
149
171
|
done = true
|
150
172
|
end
|
151
173
|
end
|
174
|
+
_clear_opts
|
152
175
|
done
|
153
176
|
rescue Fail => e
|
154
177
|
_error(e.message)
|
155
178
|
end
|
156
179
|
|
157
|
-
def _error(details=
|
180
|
+
def _error(details = 'An error occurred')
|
158
181
|
message =
|
159
182
|
if @opts[:quiet]
|
160
|
-
_trans(
|
183
|
+
_trans('error', details: details)
|
161
184
|
else
|
162
|
-
_trans(
|
185
|
+
_trans('jinn.error', details: details)
|
163
186
|
end
|
164
187
|
say(HighLine.color(message, :bold, :red))
|
165
188
|
end
|
166
189
|
|
190
|
+
def _warn(details)
|
191
|
+
message =
|
192
|
+
if @opts[:quiet]
|
193
|
+
_trans('warn', details: details)
|
194
|
+
else
|
195
|
+
_trans('jinn.warn', details: details)
|
196
|
+
end
|
197
|
+
say(HighLine.color(message, :bold, :yellow))
|
198
|
+
end
|
199
|
+
|
167
200
|
def _new
|
168
201
|
words = nil
|
169
202
|
if @opts.reconstruct?
|
170
|
-
_info(
|
171
|
-
words = ask(
|
203
|
+
_info('reconstruct')
|
204
|
+
words = ask('🔑 ') { |q| q.echo = '*' }
|
172
205
|
end
|
173
206
|
phrase = @sesame.create!(words)
|
174
207
|
if words.nil?
|
175
|
-
_info(
|
208
|
+
_info('new')
|
176
209
|
_show(phrase)
|
177
210
|
else
|
178
|
-
_info(
|
211
|
+
_info('reconstructed')
|
179
212
|
end
|
180
213
|
end
|
181
214
|
|
182
215
|
def _open
|
183
|
-
_info(
|
184
|
-
words = ask(
|
216
|
+
_info('open')
|
217
|
+
words = ask('🔑 ') { |q| q.echo = '*' }
|
185
218
|
@sesame.open(words)
|
186
|
-
_info(
|
219
|
+
_info('path', path: @sesame.path)
|
187
220
|
end
|
188
221
|
|
189
222
|
def _unlock
|
190
|
-
_info(
|
191
|
-
key = ask(
|
223
|
+
_info('unlock')
|
224
|
+
key = ask('🔑 ') { |q| q.echo = '*' }
|
192
225
|
@sesame.unlock(key)
|
193
|
-
_info(
|
226
|
+
_info('path', path: @sesame.path)
|
194
227
|
end
|
195
228
|
|
196
229
|
def _forget
|
197
|
-
_info(
|
230
|
+
_info('forgot')
|
198
231
|
@sesame.forget
|
199
232
|
end
|
200
233
|
|
201
234
|
def _list
|
202
|
-
_info(
|
203
|
-
if @opts[:service].nil? || @opts[:service].length
|
235
|
+
_info('list')
|
236
|
+
if @opts[:service].nil? || @opts[:service].length.zero?
|
204
237
|
@sesame.index.each do |service, users|
|
205
238
|
next if service == 'sesame'
|
206
239
|
if users.count > 1
|
207
240
|
say("#{service} (#{users.count})")
|
208
241
|
else
|
209
|
-
say(service)
|
242
|
+
say("#{service} (#{users.first.first})")
|
210
243
|
end
|
211
244
|
end
|
212
245
|
else
|
213
246
|
users = @sesame.index[@opts[:service]]
|
214
|
-
raise Fail,
|
215
|
-
users.each do |user,
|
247
|
+
raise Fail, 'No such service found, you must be thinking of some other cave' if users.nil? || @opts[:service] == 'sesame'
|
248
|
+
users.sort.each do |user, _|
|
216
249
|
say(user)
|
217
250
|
end
|
218
251
|
end
|
@@ -220,53 +253,55 @@ module Sesame
|
|
220
253
|
|
221
254
|
def _get
|
222
255
|
phrase = @sesame.get(*_question, @opts[:offset])
|
223
|
-
_info(
|
256
|
+
_info('get', @sesame.item)
|
224
257
|
_show(phrase)
|
225
258
|
end
|
226
259
|
|
227
260
|
def _add
|
228
261
|
phrase = @sesame.insert(*_question(true), @opts[:offset])
|
229
|
-
_info(
|
262
|
+
_info('add', @sesame.item)
|
230
263
|
_show(phrase)
|
231
264
|
end
|
232
265
|
|
233
266
|
def _next
|
234
267
|
phrase = @sesame.update(*_question, @opts[:offset])
|
235
268
|
if phrase.nil?
|
236
|
-
_info(
|
269
|
+
_info('next_key')
|
270
|
+
@was_locked = false
|
271
|
+
_set_opt(:lock, true)
|
237
272
|
else
|
238
|
-
_info(
|
273
|
+
_info('next', @sesame.item)
|
239
274
|
_show(phrase)
|
240
275
|
end
|
241
276
|
end
|
242
277
|
|
243
278
|
def _delete
|
244
279
|
phrase = @sesame.delete(*_question)
|
245
|
-
_info(
|
280
|
+
_info('delete')
|
246
281
|
_show(phrase)
|
247
282
|
end
|
248
283
|
|
249
|
-
def _lock
|
284
|
+
def _lock
|
250
285
|
key = @sesame.lock
|
251
|
-
return if
|
252
|
-
_info(
|
286
|
+
return if @was_locked
|
287
|
+
_info('lock')
|
253
288
|
_show(key)
|
254
289
|
end
|
255
290
|
|
256
|
-
def _info(message, args={})
|
291
|
+
def _info(message, args = {})
|
257
292
|
message =
|
258
293
|
if @opts[:quiet]
|
259
294
|
_trans(message, args)
|
260
295
|
else
|
261
296
|
_trans("jinn.#{message}", args)
|
262
297
|
end
|
263
|
-
return if message.nil? || message.length
|
298
|
+
return if message.nil? || message.length.zero?
|
264
299
|
say(HighLine.color(message, :bold, :green))
|
265
300
|
end
|
266
301
|
|
267
302
|
def _trans(message, args)
|
268
303
|
retval = I18n.t(message, args)
|
269
|
-
if retval
|
304
|
+
if retval.match?(/^translation missing/)
|
270
305
|
retval =
|
271
306
|
if @opts[:echo]
|
272
307
|
I18n.t("#{message}_echo", args)
|
@@ -285,22 +320,37 @@ module Sesame
|
|
285
320
|
end
|
286
321
|
end
|
287
322
|
|
323
|
+
def _set_opt(name, val)
|
324
|
+
return unless val
|
325
|
+
@opts.option(name).ensure_call(val)
|
326
|
+
end
|
327
|
+
|
288
328
|
def _set_opts(args)
|
289
|
-
args = args.split(
|
290
|
-
return if args.count
|
291
|
-
|
292
|
-
|
329
|
+
args = args.split(' ').map(&:strip).map(&:downcase)
|
330
|
+
return if args.count.zero?
|
331
|
+
_set_opt(:service, args.first) if args.count < 3
|
332
|
+
_set_opt(:user, args.last) if args.count == 2
|
333
|
+
end
|
334
|
+
|
335
|
+
def _clear_opt(name)
|
336
|
+
@opts.option(name).reset
|
337
|
+
end
|
338
|
+
|
339
|
+
def _clear_opts
|
340
|
+
_clear_opt(:service)
|
341
|
+
_clear_opt(:user)
|
293
342
|
end
|
294
343
|
|
295
|
-
def _question(user_required=false)
|
296
|
-
service
|
344
|
+
def _question(user_required = false)
|
345
|
+
service = @opts[:service]
|
346
|
+
user = @opts[:user]
|
297
347
|
if service.nil?
|
298
|
-
_info(
|
299
|
-
service = ask(
|
348
|
+
_info('service')
|
349
|
+
service = ask('🏷 ')
|
300
350
|
end
|
301
351
|
if user.nil? && (user_required || !@sesame.unique?(service))
|
302
|
-
_info(
|
303
|
-
user = ask(
|
352
|
+
_info('user')
|
353
|
+
user = ask('👤 ')
|
304
354
|
end
|
305
355
|
[service.downcase, user.nil? ? nil : user.downcase]
|
306
356
|
end
|
data/lib/sesame/lang/en.yml
CHANGED
@@ -23,6 +23,7 @@ en:
|
|
23
23
|
lock_clip: 'Store locked. Unlock code copied to clipboard.'
|
24
24
|
service: 'Enter service name:'
|
25
25
|
user: 'Enter user name:'
|
26
|
+
warning: 'Warning: %{details}.'
|
26
27
|
jinn:
|
27
28
|
error: '🧞 - "A thousand apologies! %{details}."'
|
28
29
|
open: '🧞 - "Open sesame! Please incant the magic words..."'
|
@@ -48,3 +49,4 @@ en:
|
|
48
49
|
lock_clip: '🧞 - "I have secured your treasure. The key is in your clipboard."'
|
49
50
|
service: '🧞 - "What be the name of the service?"'
|
50
51
|
user: '🧞 - "And what be the name of the user?"'
|
52
|
+
warn: '🧞 - "Caution, master! %{details}."'
|
data/lib/sesame.rb
CHANGED
data/sesame-cli.gemspec
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: sesame-cli 0.
|
5
|
+
# stub: sesame-cli 0.2.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "sesame-cli".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.2.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Jason Hutchens".freeze, "Jack Casey".freeze]
|
14
|
-
s.date = "2018-04-
|
15
|
-
s.description = "Sesame is a simple password manager for the command-line
|
14
|
+
s.date = "2018-04-24"
|
15
|
+
s.description = "\u{1F9DE} - \"Sesame is a simple password manager for the command-line!\"".freeze
|
16
16
|
s.email = "jasonhutchens@gmail.com".freeze
|
17
17
|
s.executables = ["sesame".freeze]
|
18
18
|
s.extra_rdoc_files = [
|
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
]
|
21
21
|
s.files = [
|
22
22
|
".document",
|
23
|
+
".rubocop.yml",
|
23
24
|
"Gemfile",
|
24
25
|
"Gemfile.lock",
|
25
26
|
"README.md",
|
@@ -34,14 +35,16 @@ Gem::Specification.new do |s|
|
|
34
35
|
"lib/sesame/jinn.rb",
|
35
36
|
"lib/sesame/lang/en.yml",
|
36
37
|
"sesame-cli.gemspec",
|
37
|
-
"
|
38
|
+
"spec/cave_spec.rb",
|
39
|
+
"spec/dict_spec.rb",
|
40
|
+
"spec/jinn_spec.rb",
|
38
41
|
"spec/spec_helper.rb"
|
39
42
|
]
|
40
43
|
s.homepage = "http://github.com/kranzky/sesame-cli".freeze
|
41
44
|
s.licenses = ["UNLICENSE".freeze]
|
42
45
|
s.required_ruby_version = Gem::Requirement.new("~> 2.1".freeze)
|
43
46
|
s.rubygems_version = "2.7.3".freeze
|
44
|
-
s.summary = "Sesame is a simple password manager for the command-line
|
47
|
+
s.summary = "\u{1F9DE} - \"Sesame is a simple password manager for the command-line!\"".freeze
|
45
48
|
|
46
49
|
if s.respond_to? :specification_version then
|
47
50
|
s.specification_version = 4
|
@@ -60,6 +63,7 @@ Gem::Specification.new do |s|
|
|
60
63
|
s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
|
61
64
|
s.add_development_dependency(%q<rdoc>.freeze, ["~> 6.0"])
|
62
65
|
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.7"])
|
66
|
+
s.add_development_dependency(%q<rubocop>.freeze, ["~> 0.55"])
|
63
67
|
s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.15"])
|
64
68
|
s.add_development_dependency(%q<yard>.freeze, ["~> 0.9"])
|
65
69
|
else
|
@@ -76,6 +80,7 @@ Gem::Specification.new do |s|
|
|
76
80
|
s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
|
77
81
|
s.add_dependency(%q<rdoc>.freeze, ["~> 6.0"])
|
78
82
|
s.add_dependency(%q<rspec>.freeze, ["~> 3.7"])
|
83
|
+
s.add_dependency(%q<rubocop>.freeze, ["~> 0.55"])
|
79
84
|
s.add_dependency(%q<simplecov>.freeze, ["~> 0.15"])
|
80
85
|
s.add_dependency(%q<yard>.freeze, ["~> 0.9"])
|
81
86
|
end
|
@@ -93,6 +98,7 @@ Gem::Specification.new do |s|
|
|
93
98
|
s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.9"])
|
94
99
|
s.add_dependency(%q<rdoc>.freeze, ["~> 6.0"])
|
95
100
|
s.add_dependency(%q<rspec>.freeze, ["~> 3.7"])
|
101
|
+
s.add_dependency(%q<rubocop>.freeze, ["~> 0.55"])
|
96
102
|
s.add_dependency(%q<simplecov>.freeze, ["~> 0.15"])
|
97
103
|
s.add_dependency(%q<yard>.freeze, ["~> 0.9"])
|
98
104
|
end
|
data/spec/cave_spec.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
4
|
+
|
5
|
+
describe Sesame::Cave do
|
6
|
+
let(:cave) { Sesame::Cave.new(Dir.tmpdir, 20) }
|
7
|
+
|
8
|
+
after do
|
9
|
+
cave.close if cave.open?
|
10
|
+
cave.forget if cave.locked?
|
11
|
+
File.delete(cave.path) if cave.exists?
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#path' do
|
15
|
+
it 'returns the location of the sesame cave' do
|
16
|
+
expect(cave.path).to eq(File.join(Dir.tmpdir, 'sesame.cave'))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#item' do
|
21
|
+
before do
|
22
|
+
phrase = cave.create!
|
23
|
+
cave.insert('foo', 'bar')
|
24
|
+
cave.close
|
25
|
+
cave.open(phrase)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns nothing by default' do
|
29
|
+
expect(cave.item).to be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'after #get' do
|
33
|
+
before do
|
34
|
+
cave.get('foo')
|
35
|
+
end
|
36
|
+
it 'returns the item' do
|
37
|
+
expect(cave.item[:user]).to eq('bar')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'after #insert' do
|
42
|
+
before do
|
43
|
+
cave.insert('xxx', 'yyy')
|
44
|
+
end
|
45
|
+
it 'returns the item' do
|
46
|
+
expect(cave.item[:user]).to eq('yyy')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'after #update' do
|
51
|
+
before do
|
52
|
+
cave.update('foo')
|
53
|
+
end
|
54
|
+
it 'returns the item' do
|
55
|
+
expect(cave.item[:user]).to eq('bar')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'after #delete' do
|
60
|
+
before do
|
61
|
+
cave.delete('foo')
|
62
|
+
end
|
63
|
+
it 'returns the item' do
|
64
|
+
expect(cave.item[:user]).to eq('bar')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'after #lock' do
|
69
|
+
before do
|
70
|
+
cave.insert('xxx', 'yyy')
|
71
|
+
cave.lock
|
72
|
+
end
|
73
|
+
it 'is cleared' do
|
74
|
+
expect(cave.item).to be_nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#exists?' do
|
80
|
+
context 'by default' do
|
81
|
+
it 'returns false' do
|
82
|
+
expect(cave.exists?).to be false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'after #create! and #close' do
|
87
|
+
before do
|
88
|
+
cave.create!
|
89
|
+
cave.close
|
90
|
+
end
|
91
|
+
it 'returns true' do
|
92
|
+
expect(cave.exists?).to be true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#locked?' do
|
98
|
+
context 'by default' do
|
99
|
+
it 'returns false' do
|
100
|
+
expect(cave.locked?).to be false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'after #create! and #close' do
|
105
|
+
before do
|
106
|
+
cave.create!
|
107
|
+
cave.close
|
108
|
+
end
|
109
|
+
it 'returns false' do
|
110
|
+
expect(cave.locked?).to be false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'after #create! and #lock' do
|
115
|
+
before do
|
116
|
+
cave.create!
|
117
|
+
cave.lock
|
118
|
+
end
|
119
|
+
it 'returns true' do
|
120
|
+
expect(cave.locked?).to be true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'after #create! and #lock and #forget' do
|
125
|
+
before do
|
126
|
+
cave.create!
|
127
|
+
cave.lock
|
128
|
+
cave.forget
|
129
|
+
end
|
130
|
+
it 'returns false' do
|
131
|
+
expect(cave.locked?).to be false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'after #create! and #lock and #unlock' do
|
136
|
+
before do
|
137
|
+
cave.create!
|
138
|
+
code = cave.lock
|
139
|
+
cave.unlock(code)
|
140
|
+
end
|
141
|
+
it 'returns false' do
|
142
|
+
expect(cave.locked?).to be false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '#open?' do
|
148
|
+
end
|
149
|
+
|
150
|
+
describe '#dirty?' do
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#create!' do
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#open' do
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#close' do
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#lock' do
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#unlock' do
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#forget' do
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#index' do
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#unique?' do
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '#get' do
|
178
|
+
end
|
179
|
+
|
180
|
+
describe '#insert' do
|
181
|
+
end
|
182
|
+
|
183
|
+
describe '#update' do
|
184
|
+
end
|
185
|
+
|
186
|
+
describe '#delete' do
|
187
|
+
end
|
188
|
+
end
|