rbnotes 0.3.0 → 0.4.3
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/CHANGELOG.md +27 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -4
- data/README.md +55 -4
- data/conf/config.yml +7 -0
- data/conf/config_deve.yml +7 -0
- data/conf/config_test.yml +5 -0
- data/exe/rbnotes +39 -4
- data/lib/rbnotes.rb +2 -0
- data/lib/rbnotes/commands.rb +176 -36
- data/lib/rbnotes/commands/add.rb +92 -9
- data/lib/rbnotes/commands/delete.rb +24 -12
- data/lib/rbnotes/commands/export.rb +58 -0
- data/lib/rbnotes/commands/help.rb +98 -0
- data/lib/rbnotes/commands/import.rb +39 -2
- data/lib/rbnotes/commands/list.rb +30 -3
- data/lib/rbnotes/commands/search.rb +67 -0
- data/lib/rbnotes/commands/show.rb +33 -2
- data/lib/rbnotes/commands/update.rb +57 -18
- data/lib/rbnotes/error.rb +0 -11
- data/lib/rbnotes/utils.rb +6 -6
- data/lib/rbnotes/version.rb +2 -2
- data/rbnotes.gemspec +1 -1
- metadata +10 -4
data/lib/rbnotes/commands/add.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
1
|
module Rbnotes::Commands
|
2
|
+
|
2
3
|
##
|
3
|
-
# Adds a new note to the repository.
|
4
|
-
# at the execution time, then it is attached to the
|
5
|
-
# timestamp has already existed in the repository, the
|
6
|
-
# fails.
|
4
|
+
# Adds a new note to the repository. If no options, a new timestamp
|
5
|
+
# is generated at the execution time, then it is attached to the
|
6
|
+
# note. If the timestamp has already existed in the repository, the
|
7
|
+
# command fails.
|
8
|
+
#
|
9
|
+
# Accepts an option with `-t STAMP_PATTERN` (or `--timestamp`), a
|
10
|
+
# timestamp is generated according to `STAMP_PATTERN`.
|
11
|
+
#
|
12
|
+
# STAMP_PATTERN could be one of followings:
|
13
|
+
#
|
14
|
+
# "20201104172230_078" : full qualified timestamp string
|
15
|
+
# "20201104172230" : full qualified timestamp string (no suffix)
|
16
|
+
# "202011041722" : year, date and time (omit second part)
|
17
|
+
# "11041722" : date and time (omit year and second part)
|
7
18
|
#
|
8
19
|
# This command starts the external editor program to prepare text to
|
9
20
|
# store. The editor program will be searched in the following order:
|
@@ -14,23 +25,48 @@ module Rbnotes::Commands
|
|
14
25
|
# 4. "vi"
|
15
26
|
#
|
16
27
|
# If none of the above editor is available, the command fails.
|
17
|
-
|
28
|
+
|
18
29
|
class Add < Command
|
19
30
|
include ::Rbnotes::Utils
|
20
31
|
|
32
|
+
def description # :nodoc:
|
33
|
+
"Add a new note"
|
34
|
+
end
|
35
|
+
|
21
36
|
def execute(args, conf)
|
22
|
-
|
37
|
+
@opts = {}
|
38
|
+
while args.size > 0
|
39
|
+
arg = args.shift
|
40
|
+
case arg
|
41
|
+
when "-t", "--timestamp"
|
42
|
+
stamp_str = args.shift
|
43
|
+
raise ArgumentError, "missing timestamp: %s" % args.unshift(arg) if stamp_str.nil?
|
44
|
+
stamp_str = complement_timestamp_pattern(stamp_str)
|
45
|
+
@opts[:timestamp] = Textrepo::Timestamp.parse_s(stamp_str)
|
46
|
+
else
|
47
|
+
args.unshift(arg)
|
48
|
+
break
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
stamp = @opts[:timestamp] || Textrepo::Timestamp.new(Time.now)
|
23
53
|
|
24
54
|
candidates = [conf[:editor], ENV["EDITOR"], "nano", "vi"].compact
|
25
55
|
editor = find_program(candidates)
|
26
56
|
raise Rbnotes::NoEditorError, candidates if editor.nil?
|
27
57
|
|
28
|
-
tmpfile = run_with_tmpfile(editor,
|
58
|
+
tmpfile = run_with_tmpfile(editor, stamp.to_s)
|
59
|
+
|
60
|
+
unless FileTest.exist?(tmpfile)
|
61
|
+
puts "Cancel adding, since nothing to store"
|
62
|
+
return
|
63
|
+
end
|
64
|
+
|
29
65
|
text = File.readlines(tmpfile)
|
30
66
|
|
31
67
|
repo = Textrepo.init(conf)
|
32
68
|
begin
|
33
|
-
repo.create(
|
69
|
+
repo.create(stamp, text)
|
34
70
|
rescue Textrepo::DuplicateTimestampError => e
|
35
71
|
puts e.message
|
36
72
|
puts "Just wait a second, then retry."
|
@@ -39,11 +75,58 @@ module Rbnotes::Commands
|
|
39
75
|
rescue StandardError => e
|
40
76
|
puts e.message
|
41
77
|
else
|
42
|
-
puts "Add a note [%s]" %
|
78
|
+
puts "Add a note [%s]" % stamp.to_s
|
43
79
|
ensure
|
44
80
|
# Don't forget to remove the temporary file.
|
45
81
|
File.delete(tmpfile)
|
46
82
|
end
|
47
83
|
end
|
84
|
+
|
85
|
+
def help # :nodoc:
|
86
|
+
puts <<HELP
|
87
|
+
usage:
|
88
|
+
#{Rbnotes::NAME} add [(-t|--timestamp) STAMP_PATTERN]
|
89
|
+
|
90
|
+
Add a new note to the repository. If no options, a new timestamp is
|
91
|
+
generated at the execution time, then it is attached to the note.
|
92
|
+
|
93
|
+
Accept an option with `-t STAMP_PATTERN` (or `--timestamp`), a
|
94
|
+
timestamp is generated according to `STAMP_PATTERN`.
|
95
|
+
|
96
|
+
STAMP_PATTERN could be one of followings:
|
97
|
+
|
98
|
+
"20201104172230_078" : full qualified timestamp string
|
99
|
+
"20201104172230" : full qualified timestamp string (no suffix)
|
100
|
+
"202011041722" : year, date and time (omit second part)
|
101
|
+
"11041722" : date and time (omit year and second part)
|
102
|
+
|
103
|
+
This command starts the external editor program to prepare text to
|
104
|
+
store. The editor program will be searched in the following order:
|
105
|
+
|
106
|
+
1. configuration setting of ":editor"
|
107
|
+
2. ENV["EDITOR"]
|
108
|
+
3. "nano"
|
109
|
+
4. "vi"
|
110
|
+
|
111
|
+
If none of the above editor is available, the execution fails.
|
112
|
+
HELP
|
113
|
+
end
|
114
|
+
|
115
|
+
# :stopdoc:
|
116
|
+
private
|
117
|
+
def complement_timestamp_pattern(pattern)
|
118
|
+
stamp_str = nil
|
119
|
+
case pattern.to_s.size
|
120
|
+
when "yyyymoddhhmiss_lll".size, "yyyymoddhhmiss".size
|
121
|
+
stamp_str = pattern.dup
|
122
|
+
when "yyyymoddhhmi".size # omit sec part
|
123
|
+
stamp_str = "#{pattern}00"
|
124
|
+
when "moddhhmi".size # omit year and sec part
|
125
|
+
stamp_str = "#{Time.now.year}#{pattern}00"
|
126
|
+
else
|
127
|
+
raise Textrepo::InvalidTimestampStringError, pattern
|
128
|
+
end
|
129
|
+
stamp_str
|
130
|
+
end
|
48
131
|
end
|
49
132
|
end
|
@@ -1,18 +1,17 @@
|
|
1
|
-
|
1
|
+
module Rbnotes::Commands
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# It does nothing when the specified note does not exist except to
|
10
|
-
# print error message.
|
3
|
+
# Deletes a given note in the repository. The timestamp string must
|
4
|
+
# be a fully qualified one, like "20201016165130". If no argument
|
5
|
+
# was passed, it would try to read from the standard input.
|
6
|
+
#
|
7
|
+
# It does nothing to change the repository when the specified note
|
8
|
+
# does not exist.
|
11
9
|
|
12
|
-
|
10
|
+
class Delete < Command
|
11
|
+
def description # :nodoc:
|
12
|
+
"Delete a note"
|
13
|
+
end
|
13
14
|
|
14
|
-
module Rbnotes
|
15
|
-
class Commands::Delete < Commands::Command
|
16
15
|
def execute(args, conf)
|
17
16
|
stamp = Rbnotes::Utils.read_timestamp(args)
|
18
17
|
|
@@ -27,5 +26,18 @@ module Rbnotes
|
|
27
26
|
puts "Delete [%s]" % stamp.to_s
|
28
27
|
end
|
29
28
|
end
|
29
|
+
|
30
|
+
def help # :nodoc:
|
31
|
+
puts <<HELP
|
32
|
+
usage:
|
33
|
+
#{Rbnotes::NAME} delete [TIMESTAMP]
|
34
|
+
|
35
|
+
Delete a given note. TIMESTAMP must be a fully qualified one, such
|
36
|
+
"20201016165130" or "20201016165130_012" if it has a suffix.
|
37
|
+
|
38
|
+
Delete reads its argument from the standard input when no argument was
|
39
|
+
passed in the command line.
|
40
|
+
HELP
|
41
|
+
end
|
30
42
|
end
|
31
43
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Rbnotes::Commands
|
4
|
+
|
5
|
+
##
|
6
|
+
# Writes out a given note into a specified file. The file will be
|
7
|
+
# created in the current working directory unless an absolute path
|
8
|
+
# is specified as a filename.
|
9
|
+
#
|
10
|
+
# When no argument was passed, would try to read a timestamp string
|
11
|
+
# from the standard input.
|
12
|
+
|
13
|
+
class Export < Command
|
14
|
+
|
15
|
+
def description # :nodoc:
|
16
|
+
"Write out a note into a file"
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# :call-seq:
|
21
|
+
# execute([a String as timestring], Rbnotes::Conf or Hash) -> nil
|
22
|
+
|
23
|
+
def execute(args, conf)
|
24
|
+
stamp = Rbnotes::Utils.read_timestamp(args)
|
25
|
+
|
26
|
+
repo = Textrepo.init(conf)
|
27
|
+
begin
|
28
|
+
content = repo.read(stamp)
|
29
|
+
rescue Textrepo::MissingTimestampError => _
|
30
|
+
raise MissingTimestampError, stamp
|
31
|
+
end
|
32
|
+
|
33
|
+
pathname = Pathname.new(args.shift || "#{stamp}.md")
|
34
|
+
pathname.parent.mkpath
|
35
|
+
pathname.open("w"){ |f| f.puts content }
|
36
|
+
puts "Export a note [%s] into a file [%s]" % [stamp, pathname]
|
37
|
+
end
|
38
|
+
|
39
|
+
def help # :nodoc:
|
40
|
+
puts <<HELP
|
41
|
+
usage:
|
42
|
+
#{Rbnotes::NAME} export [TIMESTAMP [FILENAME]]
|
43
|
+
|
44
|
+
Write out a given note into a specified file. TIMESTAMP must be a
|
45
|
+
fully qualified one, such "20201108141600", or "20201108141600_012" if
|
46
|
+
it has a suffix. FILENAME is optional. When it omitted, the filename
|
47
|
+
would be a timestamp string with ".md" as its extension, such
|
48
|
+
"20201108141600.md"
|
49
|
+
|
50
|
+
The file will be created into the current working directory unless an
|
51
|
+
absolute path is specified as FILENAME.
|
52
|
+
|
53
|
+
When no argument was passed, it would try to read a timestamp string
|
54
|
+
from the standard input. Then, FILENAME would be regarded as omitted.
|
55
|
+
HELP
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Rbnotes::Commands
|
2
|
+
|
3
|
+
##
|
4
|
+
# Shows help message for the command which specifies with the
|
5
|
+
# argument.
|
6
|
+
|
7
|
+
class Help < Command
|
8
|
+
|
9
|
+
def description # :nodoc:
|
10
|
+
"Provide help on each command"
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# :call-seq:
|
15
|
+
# execute(["add"], Rbnotes::Conf or Hash) -> nil
|
16
|
+
# execute(["delete"], Rbnotes::Conf or Hash) -> nil
|
17
|
+
|
18
|
+
def execute(args, conf)
|
19
|
+
cmd_name = args.shift
|
20
|
+
case cmd_name
|
21
|
+
when nil
|
22
|
+
self.help
|
23
|
+
when "commands"
|
24
|
+
print_commands
|
25
|
+
else
|
26
|
+
Commands.load(cmd_name).help
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def help # :nodoc:
|
31
|
+
puts <<HELP
|
32
|
+
#{Rbnotes::NAME.capitalize} is a simple tool to write a note into a single repository.
|
33
|
+
|
34
|
+
When creates a new note, a timestamp is attached to the note. #{Rbnotes::NAME.capitalize}
|
35
|
+
manages notes with those timestamps, such update, delete, ...etc.
|
36
|
+
|
37
|
+
Timestamp is a series of digits which represents year, date, and time.
|
38
|
+
It looks like "20201106121100", means "2020-11-06 12:11:00". It is
|
39
|
+
generated in the local time.
|
40
|
+
|
41
|
+
usage:
|
42
|
+
#{Rbnotes::NAME} [option] [command] [args]
|
43
|
+
|
44
|
+
option:
|
45
|
+
-c, --conf [CONF_FILE] : specifiy the configuration file
|
46
|
+
-v, --version : print version
|
47
|
+
-h, --help : show this message
|
48
|
+
|
49
|
+
CONF_FILE must be written in YAML. To know about details of the
|
50
|
+
configuration file, see README.md or Wiki page.
|
51
|
+
|
52
|
+
Further help:
|
53
|
+
#{Rbnotes::NAME} help commands
|
54
|
+
#{Rbnotes::NAME} help COMMAND
|
55
|
+
#{Rbnotes::NAME} usage
|
56
|
+
|
57
|
+
Further information:
|
58
|
+
https://github.com/mnbi/rbnotes/wiki
|
59
|
+
HELP
|
60
|
+
end
|
61
|
+
|
62
|
+
# :stopdoc:
|
63
|
+
private
|
64
|
+
|
65
|
+
def print_commands
|
66
|
+
Dir.glob("*.rb", :base => __dir__) { |rb|
|
67
|
+
next if rb == "help.rb"
|
68
|
+
require_relative rb
|
69
|
+
}
|
70
|
+
commands = Commands.constants.difference([:Builtins, :Command])
|
71
|
+
builtins = Commands::Builtins.constants
|
72
|
+
|
73
|
+
puts "#{Rbnotes::NAME.capitalize} Commands:"
|
74
|
+
print_commands_desc(commands.sort)
|
75
|
+
puts
|
76
|
+
puts "for development purpose"
|
77
|
+
print_builtins_desc(builtins.sort)
|
78
|
+
end
|
79
|
+
|
80
|
+
def print_commands_desc(commands)
|
81
|
+
print_desc(Commands, commands)
|
82
|
+
end
|
83
|
+
|
84
|
+
def print_builtins_desc(builtins)
|
85
|
+
print_desc(Commands::Builtins, builtins)
|
86
|
+
end
|
87
|
+
|
88
|
+
def print_desc(mod, commands)
|
89
|
+
commands.map { |cmd|
|
90
|
+
name = "#{cmd.to_s.downcase} "[0, 8]
|
91
|
+
desc = mod.const_get(cmd, false).new.description
|
92
|
+
puts " #{name} #{desc}"
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
# :startdoc:
|
97
|
+
end
|
98
|
+
end
|
@@ -1,5 +1,29 @@
|
|
1
|
-
module Rbnotes
|
2
|
-
|
1
|
+
module Rbnotes::Commands
|
2
|
+
|
3
|
+
##
|
4
|
+
# Imports a existing file which specified by the argument as a note.
|
5
|
+
#
|
6
|
+
# A timestamp is generated referring to the birthtime of the given
|
7
|
+
# file. If birthtime is not available on the system, use mtime
|
8
|
+
# (modification time).
|
9
|
+
#
|
10
|
+
# Occasionally, there is another note which has the same timestmap
|
11
|
+
# in the repository. Then, tries to create a new timestamp with a
|
12
|
+
# suffix. Unluckily, when such timestamp with a suffix already
|
13
|
+
# exists, tries to create a new one with increasing suffix. Suffix
|
14
|
+
# will be "001", "002", ..., or "999". In worst case, all suffix
|
15
|
+
# might have been already used. Then, abandons to import.
|
16
|
+
|
17
|
+
class Import < Command
|
18
|
+
|
19
|
+
def description # :nodoc:
|
20
|
+
"Import a file as a note"
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# :call-seq:
|
25
|
+
# execute([PATHNAME], Rbnotes::Conf or Hash) -> nil
|
26
|
+
|
3
27
|
def execute(args, conf)
|
4
28
|
file = args.shift
|
5
29
|
unless file.nil?
|
@@ -58,5 +82,18 @@ module Rbnotes
|
|
58
82
|
super
|
59
83
|
end
|
60
84
|
end
|
85
|
+
|
86
|
+
def help # :nodoc:
|
87
|
+
puts <<HELP
|
88
|
+
usage:
|
89
|
+
#{Rbnotes::NAME} import FILE
|
90
|
+
|
91
|
+
Imports a existing file which specified by the argument as a note.
|
92
|
+
|
93
|
+
A timestamp is generated referring to the birthtime of the given file.
|
94
|
+
If birthtime is not available on the system, use mtime (modification
|
95
|
+
time).
|
96
|
+
HELP
|
97
|
+
end
|
61
98
|
end
|
62
99
|
end
|
@@ -1,15 +1,20 @@
|
|
1
1
|
require "unicode/display_width"
|
2
2
|
require "io/console/size"
|
3
3
|
|
4
|
-
module Rbnotes
|
4
|
+
module Rbnotes::Commands
|
5
|
+
|
5
6
|
##
|
6
7
|
# Defines `list` command for `rbnotes`. See the document of execute
|
7
8
|
# method to know about the behavior of this command.
|
8
9
|
|
9
|
-
class
|
10
|
+
class List < Command
|
11
|
+
|
12
|
+
def description # :nodoc:
|
13
|
+
"List notes"
|
14
|
+
end
|
10
15
|
|
11
16
|
##
|
12
|
-
# Shows
|
17
|
+
# Shows a list of notes in the repository. The only argument is
|
13
18
|
# optional. If it passed, it must be an timestamp pattern. A
|
14
19
|
# timestamp is an instance of Textrepo::Timestamp class. A
|
15
20
|
# timestamp pattern is a string which would match several
|
@@ -24,6 +29,9 @@ module Rbnotes
|
|
24
29
|
# "20201027": specifies year and date
|
25
30
|
# - all Timestamps those have the same year and date would match
|
26
31
|
#
|
32
|
+
# "202011": specifies year and month
|
33
|
+
# - all Timestamps those have the same year and month would match
|
34
|
+
#
|
27
35
|
# "2020": specifies year only
|
28
36
|
# - all Timestamps those have the same year would match
|
29
37
|
#
|
@@ -45,6 +53,25 @@ module Rbnotes
|
|
45
53
|
}
|
46
54
|
end
|
47
55
|
|
56
|
+
def help # :nodoc:
|
57
|
+
puts <<HELP
|
58
|
+
usage:
|
59
|
+
#{Rbnotes::NAME} list [STAMP_PATTERN]
|
60
|
+
|
61
|
+
Show a list of notes. When no arguments, make a list with all notes
|
62
|
+
in the repository. When specified STAMP_PATTERN, only those match the
|
63
|
+
pattern are listed.
|
64
|
+
|
65
|
+
STAMP_PATTERN must be:
|
66
|
+
|
67
|
+
(a) full qualified timestamp (with suffix): "20201030160200"
|
68
|
+
(b) year and date part: "20201030"
|
69
|
+
(c) year and month part: "202010"
|
70
|
+
(d) year part only: "2020"
|
71
|
+
(e) date part only: "1030"
|
72
|
+
HELP
|
73
|
+
end
|
74
|
+
|
48
75
|
# :stopdoc:
|
49
76
|
|
50
77
|
private
|