cue 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.
- checksums.yaml +7 -0
- data/LICENSE.md +21 -0
- data/README.md +1 -0
- data/bin/cue +16 -0
- data/bin/cue-add +4 -0
- data/bin/cue-clear +4 -0
- data/bin/cue-delete +4 -0
- data/bin/cue-list +4 -0
- data/bin/cue-show +4 -0
- data/bin/cue-toggle +4 -0
- data/lib/colorfool.rb +25 -0
- data/lib/cue.rb +2 -0
- data/lib/cue/command/add.rb +27 -0
- data/lib/cue/command/base.rb +98 -0
- data/lib/cue/command/clear.rb +11 -0
- data/lib/cue/command/delete.rb +21 -0
- data/lib/cue/command/list.rb +12 -0
- data/lib/cue/command/show.rb +21 -0
- data/lib/cue/command/toggle.rb +23 -0
- data/lib/cue/command/utils/editor.rb +40 -0
- data/lib/cue/group.rb +17 -0
- data/lib/cue/indicator.rb +39 -0
- data/lib/cue/item.rb +79 -0
- data/lib/cue/store/file.rb +129 -0
- data/lib/cue/store/memory.rb +38 -0
- data/lib/cue/store/redis.rb +110 -0
- data/lib/cue/version.rb +3 -0
- metadata +104 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: c3e67b30c304c9b38c0b750b943c045b8f5ccd20
|
|
4
|
+
data.tar.gz: 1f4757388541654942e0adee30d1aadc051f5bc4
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0c64eede657d74523a8390aced2eefc1f0a7ede4f02e55c3268c34f7decedcb105b4fde9d069d4f7f8c6533e9cbf64dd7a0778e1d8e79784477b3f2c81946b7c
|
|
7
|
+
data.tar.gz: 2922380a75b9823bec5a02ab0bc730c00f1b672c6937531d02f5b5deff50121f07edf5c70a36d591c87cbaa9a418dfc47962ff5d18d74a6b1f5bd4f181e4fc59
|
data/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) arcsum42@gmail.com
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# cue
|
data/bin/cue
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
args = ARGV.dup
|
|
4
|
+
subcommand = args.first
|
|
5
|
+
|
|
6
|
+
if subcommand.nil?
|
|
7
|
+
system('cue-list')
|
|
8
|
+
elsif subcommand == 'rm'
|
|
9
|
+
args.shift
|
|
10
|
+
system('cue-delete', *args)
|
|
11
|
+
elsif ['add', 'clear', 'delete', 'list', 'show', 'toggle'].include?(subcommand)
|
|
12
|
+
args.shift
|
|
13
|
+
system("cue-#{subcommand}", *args)
|
|
14
|
+
else
|
|
15
|
+
abort "cue: #{subcommand} is not a cue command."
|
|
16
|
+
end
|
data/bin/cue-add
ADDED
data/bin/cue-clear
ADDED
data/bin/cue-delete
ADDED
data/bin/cue-list
ADDED
data/bin/cue-show
ADDED
data/bin/cue-toggle
ADDED
data/lib/colorfool.rb
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module ColorFool
|
|
2
|
+
COLORS = %i(green red)
|
|
3
|
+
|
|
4
|
+
CODES = {
|
|
5
|
+
black: 30,
|
|
6
|
+
red: 31,
|
|
7
|
+
green: 32,
|
|
8
|
+
yellow: 33,
|
|
9
|
+
blue: 34,
|
|
10
|
+
magenta: 35,
|
|
11
|
+
cyan: 36,
|
|
12
|
+
white: 37
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def code(color)
|
|
16
|
+
CODES[color]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def colorize(color, &block)
|
|
20
|
+
code = code(color)
|
|
21
|
+
content = block.call.to_s
|
|
22
|
+
|
|
23
|
+
"\e[#{code}m#{content}\e[0m"
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/cue.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'cue/command/base'
|
|
2
|
+
require 'cue/command/utils/editor'
|
|
3
|
+
|
|
4
|
+
module Cue
|
|
5
|
+
module Command
|
|
6
|
+
class Add < Base
|
|
7
|
+
def initialize(args)
|
|
8
|
+
super(args)
|
|
9
|
+
|
|
10
|
+
if @args.size == 1
|
|
11
|
+
@content = @args.first
|
|
12
|
+
else
|
|
13
|
+
@content = Utils::Editor.new.read
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def execute
|
|
18
|
+
item = Cue::Item.new(@content)
|
|
19
|
+
item.save(options.store)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def nargs
|
|
23
|
+
(0..1)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'cue/store/redis'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
|
|
6
|
+
module Cue
|
|
7
|
+
module Command
|
|
8
|
+
class Base
|
|
9
|
+
attr_reader :options
|
|
10
|
+
|
|
11
|
+
def initialize(args)
|
|
12
|
+
@options = OpenStruct.new.tap do |opts|
|
|
13
|
+
opts.store = Cue::Store::Redis.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@args = parser.parse(args)
|
|
17
|
+
configure_store
|
|
18
|
+
check_num_arguments
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def find_key(key_prefix)
|
|
22
|
+
keys = options.store.keys
|
|
23
|
+
item_ids = keys.select { |id| id.start_with?(key_prefix) }
|
|
24
|
+
|
|
25
|
+
if item_ids.size > 1
|
|
26
|
+
parser.abort "#{key_prefix} is too ambiguous."
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
item_id = item_ids.first
|
|
30
|
+
|
|
31
|
+
parser.abort("Couldn't find item #{key_prefix}.") unless item_id
|
|
32
|
+
item_id
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def find_item(key_prefix)
|
|
36
|
+
options.store.read(find_key(key_prefix))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def nargs
|
|
40
|
+
0
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def parser
|
|
44
|
+
@parser ||= OptionParser.new do |opts|
|
|
45
|
+
opts.banner = "Usage: #{File.basename($0)} [options]"
|
|
46
|
+
|
|
47
|
+
opts.on('-s', '--store [STORE]', 'Specify the store adapter') do |store|
|
|
48
|
+
begin
|
|
49
|
+
require "cue/store/#{store}"
|
|
50
|
+
klass = store.split('_').map(&:capitalize).join
|
|
51
|
+
options.store = Cue.const_get("Store::#{klass}").new
|
|
52
|
+
rescue LoadError
|
|
53
|
+
opts.abort "Couldn't find the store adapter \"#{store}\"."
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def check_num_arguments
|
|
62
|
+
case nargs
|
|
63
|
+
when Range
|
|
64
|
+
parser.abort('Invalid number of arguments.') unless nargs.cover?(@args.size)
|
|
65
|
+
else
|
|
66
|
+
parser.abort('Invalid number of arguments.') if @args.size != nargs
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def config_path
|
|
71
|
+
File.join(ENV['HOME'], '.cue', 'config.json')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def configure_redis
|
|
75
|
+
get_config(:redis) do |config|
|
|
76
|
+
Cue::Store::Redis.configure do |rconfig|
|
|
77
|
+
opts = config.select { |k,_| [:host, :port, :password].include?(k) }
|
|
78
|
+
rconfig.redis = Redis.new(opts)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def configure_store
|
|
84
|
+
case options.store
|
|
85
|
+
when Cue::Store::Redis
|
|
86
|
+
configure_redis
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def get_config(key=nil, &block)
|
|
91
|
+
return unless File.exists?(config_path)
|
|
92
|
+
|
|
93
|
+
json = JSON.parse(File.read(config_path), symbolize_names: true)
|
|
94
|
+
key.nil? ? yield(json) : yield(json[key])
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'cue/command/base'
|
|
2
|
+
|
|
3
|
+
module Cue
|
|
4
|
+
module Command
|
|
5
|
+
class Delete < Base
|
|
6
|
+
def initialize(args)
|
|
7
|
+
super(args)
|
|
8
|
+
@sha = @args.first
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def execute
|
|
12
|
+
item_key = find_key(@sha)
|
|
13
|
+
options.store.delete(item_key)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def nargs
|
|
17
|
+
1
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'cue/command/base'
|
|
2
|
+
|
|
3
|
+
module Cue
|
|
4
|
+
module Command
|
|
5
|
+
class Show < Base
|
|
6
|
+
def initialize(args)
|
|
7
|
+
super(args)
|
|
8
|
+
@sha = @args.first
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def execute
|
|
12
|
+
item = find_item(@sha)
|
|
13
|
+
puts item
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def nargs
|
|
17
|
+
1
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'cue/command/base'
|
|
2
|
+
|
|
3
|
+
module Cue
|
|
4
|
+
module Command
|
|
5
|
+
class Toggle < Base
|
|
6
|
+
def initialize(args)
|
|
7
|
+
super(args)
|
|
8
|
+
@sha = @args.first
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def execute
|
|
12
|
+
find_item(@sha).tap do |item|
|
|
13
|
+
item.toggle!
|
|
14
|
+
item.save(options.store)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def nargs
|
|
19
|
+
1
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
|
|
3
|
+
module Cue
|
|
4
|
+
module Command
|
|
5
|
+
module Utils
|
|
6
|
+
class Editor
|
|
7
|
+
def basename
|
|
8
|
+
'cue'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def command
|
|
12
|
+
ENV['EDITOR'] || default_editor
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def read
|
|
16
|
+
Process.wait(spawn([command, path].join(' ')))
|
|
17
|
+
content = File.read(path)
|
|
18
|
+
|
|
19
|
+
File.delete(path)
|
|
20
|
+
|
|
21
|
+
content
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def dir
|
|
25
|
+
'/tmp'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def path
|
|
29
|
+
@path ||= File.expand_path(Dir::Tmpname::make_tmpname(basename, nil), dir)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def default_editor
|
|
35
|
+
'vi'
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/cue/group.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'colorfool'
|
|
2
|
+
|
|
3
|
+
module Cue
|
|
4
|
+
class Indicator
|
|
5
|
+
include ColorFool
|
|
6
|
+
|
|
7
|
+
attr_reader :state
|
|
8
|
+
|
|
9
|
+
def initialize(state)
|
|
10
|
+
@state = state
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def color
|
|
14
|
+
case state
|
|
15
|
+
when :complete
|
|
16
|
+
:green
|
|
17
|
+
when :incomplete
|
|
18
|
+
:red
|
|
19
|
+
else
|
|
20
|
+
:none
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def symbol
|
|
25
|
+
case state
|
|
26
|
+
when :complete
|
|
27
|
+
'✓'
|
|
28
|
+
when :incomplete
|
|
29
|
+
'✗'
|
|
30
|
+
else
|
|
31
|
+
'?'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_s
|
|
36
|
+
colorize(color) { symbol }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/cue/item.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require 'colorfool'
|
|
2
|
+
require 'cue/indicator'
|
|
3
|
+
require 'digest'
|
|
4
|
+
|
|
5
|
+
module Cue
|
|
6
|
+
class Item
|
|
7
|
+
include ColorFool
|
|
8
|
+
include Comparable
|
|
9
|
+
|
|
10
|
+
attr_accessor :content
|
|
11
|
+
attr_reader :created_at, :state
|
|
12
|
+
|
|
13
|
+
def initialize(content, attrs={})
|
|
14
|
+
self.content = content
|
|
15
|
+
|
|
16
|
+
attrs.each do |k, v|
|
|
17
|
+
setter = "#{k}="
|
|
18
|
+
if respond_to?(setter, true)
|
|
19
|
+
send(setter, v)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
self.state = self.state || :incomplete
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def <=>(other)
|
|
27
|
+
created_at <=> other.created_at
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ==(other)
|
|
31
|
+
content == other.content
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def complete!
|
|
35
|
+
self.state = :complete
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def complete?
|
|
39
|
+
self.state == :complete
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def hash
|
|
43
|
+
Digest::SHA1.hexdigest(content)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def in_store?(store)
|
|
47
|
+
!store.read(hash).nil?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def incomplete!
|
|
51
|
+
self.state = :incomplete
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def incomplete?
|
|
55
|
+
self.state == :incomplete
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def save(store)
|
|
59
|
+
self.created_at = Time.now unless in_store?(store)
|
|
60
|
+
store.write(hash, self)
|
|
61
|
+
true
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_s
|
|
65
|
+
i = Indicator.new(state)
|
|
66
|
+
h = colorize(:cyan) { hash[0..6] }
|
|
67
|
+
"#{h} #{i} #{content}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def toggle!
|
|
71
|
+
complete? ? incomplete! : complete!
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
attr_writer :created_at, :state
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require 'cue/item'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'zlib'
|
|
4
|
+
|
|
5
|
+
module Cue
|
|
6
|
+
module Store
|
|
7
|
+
class File
|
|
8
|
+
include Enumerable
|
|
9
|
+
|
|
10
|
+
def initialize(root_path=nil)
|
|
11
|
+
@root_path = root_path
|
|
12
|
+
FileUtils.mkdir_p(items_path)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def clear
|
|
16
|
+
keys.each { |key| delete(key) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def delete(key)
|
|
20
|
+
FileUtils.rm_r(item_path(key))
|
|
21
|
+
key_dir = dir_for(key)
|
|
22
|
+
FileUtils.rm_r(key_dir) if Dir[::File.join(key_dir, '*')].empty?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def each
|
|
26
|
+
items = keys.map(&method(:read)).sort
|
|
27
|
+
yield(items)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def keys
|
|
31
|
+
keys = []
|
|
32
|
+
|
|
33
|
+
Dir.glob(::File.join(items_path, '*')).each do |prefix_dir|
|
|
34
|
+
prefix = ::File.basename(prefix_dir)
|
|
35
|
+
Dir.glob(::File.join(prefix_dir, '*')).each do |suffix_file|
|
|
36
|
+
suffix = ::File.basename(suffix_file)
|
|
37
|
+
keys << (prefix + suffix)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
keys
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def read(key)
|
|
45
|
+
return nil unless ::File.exists?(item_path(key))
|
|
46
|
+
|
|
47
|
+
data = nil
|
|
48
|
+
file_for_reading(item_path(key)) do |file|
|
|
49
|
+
data = uncompress(file.read)
|
|
50
|
+
end
|
|
51
|
+
return data if data.nil?
|
|
52
|
+
|
|
53
|
+
deserialize(data)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def write(key, item)
|
|
57
|
+
FileUtils.mkdir_p(dir_for(key))
|
|
58
|
+
file_for_writing(item_path(key)) do |file|
|
|
59
|
+
data = compress(serialize(item))
|
|
60
|
+
file.write(data)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def root_path
|
|
67
|
+
@root_path ||= ::File.join(ENV['HOME'], '.cue')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def compress(data)
|
|
71
|
+
Zlib::Deflate.deflate(data)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def deserialize(data)
|
|
75
|
+
created_at, state, content = data.unpack('Z*Z*Z*')
|
|
76
|
+
Cue::Item.new(content, created_at: created_at, state: state.to_sym)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def dir_for(key)
|
|
80
|
+
::File.join(items_path, prefix(key))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def file_for_writing(path, &block)
|
|
84
|
+
::File.open(path, mode_for_writing) { |file| yield(file) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def file_for_reading(path, &block)
|
|
88
|
+
::File.open(path, mode_for_reading) { |file| yield(file) }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def item_path(key)
|
|
92
|
+
::File.join(dir_for(key), suffix(key))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def items_path
|
|
96
|
+
@items_path ||= ::File.join(root_path, 'items')
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def keys_path
|
|
100
|
+
@keys_path ||= ::File.join(root_path, 'keys')
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def mode_for_reading
|
|
104
|
+
::File::RDONLY
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def mode_for_writing
|
|
108
|
+
::File::CREAT | ::File::WRONLY | ::File::TRUNC
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def prefix(key)
|
|
112
|
+
key[0..1]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def serialize(item)
|
|
116
|
+
data = [item.created_at.to_i.to_s, item.state.to_s, item.content.to_s]
|
|
117
|
+
data.pack('Z*Z*Z*')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def suffix(key)
|
|
121
|
+
key[2...(key.size)]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def uncompress(data)
|
|
125
|
+
Zlib::Inflate.inflate(data)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Cue
|
|
2
|
+
module Store
|
|
3
|
+
class Memory
|
|
4
|
+
include Enumerable
|
|
5
|
+
|
|
6
|
+
def clear
|
|
7
|
+
@store = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def delete(key)
|
|
11
|
+
store.delete(key)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def each
|
|
15
|
+
items = keys.map(&method(:read)).sort
|
|
16
|
+
yield(items)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def keys
|
|
20
|
+
store.keys
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def read(key)
|
|
24
|
+
store[key]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def write(key, item)
|
|
28
|
+
store[key] = item.dup
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def store
|
|
34
|
+
@store ||= {}
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'cue/item'
|
|
2
|
+
require 'redis'
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
module Cue
|
|
6
|
+
module Store
|
|
7
|
+
class Redis
|
|
8
|
+
include Enumerable
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
attr_writer :namespace, :redis
|
|
12
|
+
|
|
13
|
+
def configure(&block)
|
|
14
|
+
self.tap { |klass| yield(klass) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def namespace
|
|
18
|
+
@namespace ||= 'cue'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def redis
|
|
22
|
+
@redis ||= ::Redis.new
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def clear
|
|
27
|
+
item_keys = redis.smembers(redis_key('keys'))
|
|
28
|
+
keys_key = redis_key('keys')
|
|
29
|
+
|
|
30
|
+
redis.del(item_keys, keys_key)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def delete(key)
|
|
34
|
+
item_key = item_key(key)
|
|
35
|
+
|
|
36
|
+
redis.del(item_key)
|
|
37
|
+
redis.srem(redis_key('keys'), item_key)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def each
|
|
41
|
+
items = keys.map(&method(:read)).sort
|
|
42
|
+
yield(items)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def keys
|
|
46
|
+
redis.smembers(redis_key('keys')).map do |redis_key|
|
|
47
|
+
redis_key.split(':').last
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def read(key)
|
|
52
|
+
item_hash = redis.hgetall(item_key(key))
|
|
53
|
+
return nil if item_hash.empty?
|
|
54
|
+
|
|
55
|
+
deserialize(item_hash)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def write(key, item)
|
|
59
|
+
add_key(key)
|
|
60
|
+
add_item(key, item)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def add_item(key, item)
|
|
66
|
+
redis.mapped_hmset(item_key(key), serialize(item))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def add_key(key)
|
|
70
|
+
redis.sadd(redis_key('keys'), item_key(key))
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def deserialize(item_hash)
|
|
74
|
+
content = item_hash['content']
|
|
75
|
+
created_at = Time.parse(item_hash['created_at']) if item_hash['created_at']
|
|
76
|
+
state = item_hash['state'].to_sym
|
|
77
|
+
|
|
78
|
+
Cue::Item.new(content, created_at: created_at, state: state)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def item_key(key)
|
|
82
|
+
redis_key('item', key)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def namespace
|
|
86
|
+
self.class.namespace
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def redis
|
|
90
|
+
self.class.redis
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def redis_key(*components)
|
|
94
|
+
key = *components
|
|
95
|
+
key.unshift(namespace)
|
|
96
|
+
|
|
97
|
+
key.join(':')
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def serialize(item)
|
|
101
|
+
{
|
|
102
|
+
'state' => item.state.to_s,
|
|
103
|
+
'content' => item.content
|
|
104
|
+
}.tap do |hash|
|
|
105
|
+
hash['created_at'] = item.created_at.to_s if item.created_at
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
data/lib/cue/version.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: cue
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- John Doe
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2013-08-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: redis
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ~>
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 3.0.4
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ~>
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 3.0.4
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '>='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '>='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
description: Cue is a simple command line tool for keeping track of stuff.
|
|
42
|
+
email: arcsum42@gmail.com
|
|
43
|
+
executables:
|
|
44
|
+
- cue
|
|
45
|
+
- cue-add
|
|
46
|
+
- cue-clear
|
|
47
|
+
- cue-delete
|
|
48
|
+
- cue-list
|
|
49
|
+
- cue-show
|
|
50
|
+
- cue-toggle
|
|
51
|
+
extensions: []
|
|
52
|
+
extra_rdoc_files: []
|
|
53
|
+
files:
|
|
54
|
+
- README.md
|
|
55
|
+
- LICENSE.md
|
|
56
|
+
- lib/colorfool.rb
|
|
57
|
+
- lib/cue/command/add.rb
|
|
58
|
+
- lib/cue/command/base.rb
|
|
59
|
+
- lib/cue/command/clear.rb
|
|
60
|
+
- lib/cue/command/delete.rb
|
|
61
|
+
- lib/cue/command/list.rb
|
|
62
|
+
- lib/cue/command/show.rb
|
|
63
|
+
- lib/cue/command/toggle.rb
|
|
64
|
+
- lib/cue/command/utils/editor.rb
|
|
65
|
+
- lib/cue/group.rb
|
|
66
|
+
- lib/cue/indicator.rb
|
|
67
|
+
- lib/cue/item.rb
|
|
68
|
+
- lib/cue/store/file.rb
|
|
69
|
+
- lib/cue/store/memory.rb
|
|
70
|
+
- lib/cue/store/redis.rb
|
|
71
|
+
- lib/cue/version.rb
|
|
72
|
+
- lib/cue.rb
|
|
73
|
+
- bin/cue
|
|
74
|
+
- bin/cue-add
|
|
75
|
+
- bin/cue-clear
|
|
76
|
+
- bin/cue-delete
|
|
77
|
+
- bin/cue-list
|
|
78
|
+
- bin/cue-show
|
|
79
|
+
- bin/cue-toggle
|
|
80
|
+
homepage: https://github.com/arcsum/cue
|
|
81
|
+
licenses:
|
|
82
|
+
- MIT
|
|
83
|
+
metadata: {}
|
|
84
|
+
post_install_message:
|
|
85
|
+
rdoc_options: []
|
|
86
|
+
require_paths:
|
|
87
|
+
- lib
|
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - '>='
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '0'
|
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - '>='
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
requirements: []
|
|
99
|
+
rubyforge_project:
|
|
100
|
+
rubygems_version: 2.0.0
|
|
101
|
+
signing_key:
|
|
102
|
+
specification_version: 4
|
|
103
|
+
summary: keep track of stuff
|
|
104
|
+
test_files: []
|