rbnotes 0.3.0 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 906c366a81295b7d9a1c2e86ad2bd6f1d35f410ac7360f1e2067c0a0f8e4f48b
4
- data.tar.gz: d2af84cbd9ddbb60fe6f21ddffb9c072ebe0b767e8c8ab6ae4cac0c1bca30acd
3
+ metadata.gz: f48ac5666d917964e9c103c11be86b12736b81ced6e072be4707e1e943b6ff76
4
+ data.tar.gz: d29b9b68d6ebfcfdc7289962405a0390daed2705cd80b3beb50e036d2f8d9e85
5
5
  SHA512:
6
- metadata.gz: 5fa3929995ebda0b4970c18516dadc37b5ddeb99d2a33c39ce90ac9f8bb90556c7a406b995b3373e4bc559c56b57750f0a0796f53b3d25624d1a891d2da456d1
7
- data.tar.gz: 99c4dd49875b4cf1f262cbd845bbccb6482449f0a1573ed188b50cd6814c1220cc7cea1032cc2b6bbaaeb2e05c4f21f8a241e8931ff8d44128e72f8457c1b113
6
+ metadata.gz: f5be0687fc189a5dad6178104a05af0f64e35fc44dd1a73bf677a232038b81b4f88e5562ca9f9e8f098152136c005ebdc334158d34652c0fe7a2bea8e13c4056
7
+ data.tar.gz: a1e5d671d93ff9efdbe33e7c6751984f851c39756304df7c874fe82df558b18b7f4f716d82253e99b2d8e21cc1d795d6b81c0f1ba665f8f3e99e38c30e4d19d8
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
  ## [Unreleased]
8
8
  Nothing to record here.
9
9
 
10
+ ## [0.4.3] - 2020-11-08
11
+ ### Added
12
+ - Add a new command `export` to write out a note into a file (#51)
13
+ - Add individual help for each command. (#42)
14
+
15
+ ### Fixed
16
+ - Fix `add` fails without modification (#48)
17
+
18
+ ## [0.4.2] - 2020-11-05
19
+ ### Added
20
+ - Add a feature to keep the timestamp in `update` command. (#44)
21
+
22
+ ### Fixed
23
+ - Fix issue #45: hanging up of `add` command.
24
+
25
+ ## [0.4.1] - 2020-11-04
26
+ ### Added
27
+ - Add a feature to accept a timestamp in `add` command. (#34)
28
+
29
+ ## [0.4.0] - 2020-11-03
30
+ ### Added
31
+ - Add a new command `search` to perform full text search. (#33)
32
+
33
+ ## [0.3.1] - 2020-10-30
34
+ ### Added
35
+ - Add feature to specify configuration file in the command line. (#21)
36
+
10
37
  ## [0.3.0] - 2020-10-29
11
38
  ### Added
12
39
  - Add feature to read argument from the standard input. (#27)
data/Gemfile CHANGED
@@ -6,4 +6,4 @@ gemspec
6
6
  gem "rake", "~> 13.0"
7
7
  gem "minitest", "~> 5.0"
8
8
 
9
- gem 'textrepo', "~> 0.4"
9
+ gem 'textrepo', "~> 0.5.4"
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbnotes (0.3.0)
5
- textrepo (~> 0.4)
4
+ rbnotes (0.4.3)
5
+ textrepo (~> 0.5.4)
6
6
  unicode-display_width (~> 1.7)
7
7
 
8
8
  GEM
@@ -10,7 +10,7 @@ GEM
10
10
  specs:
11
11
  minitest (5.14.2)
12
12
  rake (13.0.1)
13
- textrepo (0.4.4)
13
+ textrepo (0.5.4)
14
14
  unicode-display_width (1.7.0)
15
15
 
16
16
  PLATFORMS
@@ -20,7 +20,7 @@ DEPENDENCIES
20
20
  minitest (~> 5.0)
21
21
  rake (~> 13.0)
22
22
  rbnotes!
23
- textrepo (~> 0.4)
23
+ textrepo (~> 0.5.4)
24
24
 
25
25
  BUNDLED WITH
26
26
  2.1.4
data/README.md CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  Rbnotes is a simple utility to write a note in the single repository.
6
6
 
7
+ This document provides the basic information to use rbnotes.
8
+ You may find more useful information in [Wiki pages](https://github.com/mnbi/rbnotes/wiki).
9
+
7
10
  ## Installation
8
11
 
9
12
  Add this line to your application's Gemfile:
@@ -28,12 +31,19 @@ General syntax is:
28
31
  rbnotes [global_opts] [command] [command_opts] [args]
29
32
  ```
30
33
 
34
+ ### Global options
35
+
36
+ - "-c CONF_FILE", "--conf"
37
+ - specifies a configuration file
38
+
31
39
  ### Commands
32
40
 
33
41
  - import
34
42
  - imports existing files
35
43
  - list
36
44
  - lists notes in the repository with their timestamps and subject
45
+ - search
46
+ - search a word (or words) in the repository
37
47
  - show
38
48
  - shows the content of a note
39
49
  - add
@@ -57,6 +67,8 @@ Searches the configuration file in the following order:
57
67
 
58
68
  None of them is found, then the default configuration is used.
59
69
 
70
+ The global option "-c CONF_FILE" will override the location.
71
+
60
72
  #### Content
61
73
 
62
74
  The format of the configuration file must be written in YAML.
@@ -75,14 +87,16 @@ A real example:
75
87
 
76
88
  ``` yaml
77
89
  ---
78
- :run_mode: :development
90
+ :run_mode: :production
79
91
  :repository_type: :file_system
80
92
  :repository_name: "notes"
81
93
  :repository_base: "~"
82
- :pager: "bat"
94
+ :pager: "bat -l md"
83
95
  :editor: "/usr/local/bin/emacsclient"
84
96
  ```
85
97
 
98
+ The content is identical to `conf/config.yml`.
99
+
86
100
  #### Variables
87
101
 
88
102
  ##### :run-mode (mandatory)
@@ -124,13 +138,50 @@ the `:repository_name` value. It would be:
124
138
 
125
139
  > :repository_base/:repository_name
126
140
 
127
- The value must be an absolute path. The short-hand notation of the
128
- home directory ("~") is usable.
141
+ The value is recommended to be an absolute path in the production
142
+ time, since relative path will be expanded with the current working
143
+ directory. However, in the development and testing time, the relative
144
+ path may be useful. See `conf/config_deve.yml` or
145
+ `conf/config_test.yml`.
146
+
147
+ The short-hand notation of the home directory ("~") is usable.
129
148
 
130
149
  ##### Miscellaneous variables (optional)
131
150
 
132
151
  - :pager : specify a pager program
133
152
  - :editor : specify a editor program
153
+ - :searcher: specify a program to perform search
154
+ - :searcher_options: specify options to pass to the searcher program
155
+
156
+ Be careful to set `:searcher` and `:searcher_options`. The searcher
157
+ program must be expected to behave equivalent to `grep` with `-inRE`.
158
+ At least, its output must be the same format and it must runs
159
+ recursively to a directory.
160
+
161
+ If your favorite searcher is one of the followings, see the default
162
+ options which `textrepo` sets for those searchers. In most cases, you
163
+ don't have to set `:searcher_options` for them.
164
+
165
+ | searcher | default options in `textrepo` |
166
+ |:---------|:---------------------------------------------------|
167
+ | `grep` | `["-i", "-n", "-R", "-E"]` |
168
+ | `egrep` | `["-i", "-n", "-R"]` |
169
+ | `ggrep` | `["-i", "-n", "-R", "-E"]` |
170
+ | `gegrep` | `["-i", "-n", "-R"]` |
171
+ | `rg` | `["-S", "-n", "--no-heading", "--color", "never"]` |
172
+
173
+ Those searcher names are used in macOS (with Homebrew). Any other OS
174
+ might use different names.
175
+
176
+ - `grep` and `egrep` -> BSD grep (macOS default)
177
+ - `ggrep` and `gegrep` -> GNU grep
178
+ - `rg` -> ripgrep
179
+
180
+ If the name is different, `:searcher_options` should be set with the
181
+ same value. For example, if you system use the name `gnugrep` as GNU
182
+ grep, and you want to use it as the searcher (that is, set `gnugrep`
183
+ to `:searcher`), you should set `:searcher_options` value with `["-i",
184
+ "-n", "-R", "-E"]`.
134
185
 
135
186
  ##### Default values for mandatory variables
136
187
 
@@ -0,0 +1,7 @@
1
+ ---
2
+ :run_mode: :production
3
+ :repository_type: :file_system
4
+ :repository_name: "notes"
5
+ :repository_base: "~"
6
+ :pager: "bat -l md"
7
+ :editor: "/usr/local/bin/emacsclient"
@@ -0,0 +1,7 @@
1
+ ---
2
+ :run_mode: :development
3
+ :repository_type: :file_system
4
+ :repository_name: "notes"
5
+ :repository_base: "tmp"
6
+ :pager: "bat -l md"
7
+ :editor: "/usr/local/bin/emacsclient"
@@ -0,0 +1,5 @@
1
+ ---
2
+ :run_mode: :test
3
+ :repository_type: :file_system
4
+ :repository_name: "notes"
5
+ :repository_base: "test/sandbox"
@@ -4,20 +4,55 @@ require "rbnotes"
4
4
 
5
5
  include Rbnotes
6
6
 
7
- DEBUG = true
8
-
9
7
  class App
8
+ def initialize
9
+ @gopts = {}
10
+ end
11
+
12
+ def options
13
+ @gopts
14
+ end
15
+
16
+ def parse_global_options(args)
17
+ while args.size > 0
18
+ arg = args.shift
19
+ case arg
20
+ when "-c", "--conf"
21
+ file = args.shift
22
+ raise ArgumentError, args.unshift(arg) if file.nil?
23
+ file = File.expand_path(file)
24
+ raise ArgumentError, "no such file: %s" % file unless FileTest.exist?(file)
25
+ @gopts[:conf_file] = file
26
+ when "-v", "--version"
27
+ args.clear
28
+ args.unshift("version")
29
+ break
30
+ when "-h", "--help"
31
+ args.clear
32
+ args.unshift("help")
33
+ break
34
+ else
35
+ args.unshift(arg)
36
+ break
37
+ end
38
+ end
39
+ end
40
+
10
41
  def run(args)
11
42
  cmd = args.shift
12
- Commands.load(cmd).execute(args, Rbnotes.conf)
43
+ Commands.load(cmd).execute(args, Rbnotes.conf(@gopts[:conf_file]))
13
44
  end
14
45
  end
15
46
 
16
47
  app = App.new
17
48
  begin
49
+ app.parse_global_options(ARGV)
18
50
  app.run(ARGV)
19
51
  rescue MissingArgumentError, MissingTimestampError,
20
- InvalidTimestampStringError, NoEditorError, ProgramAbortError => e
52
+ NoEditorError, ProgramAbortError,
53
+ Textrepo::InvalidTimestampStringError,
54
+ ArgumentError,
55
+ Errno::EACCES => e
21
56
  puts e.message
22
57
  exit 1
23
58
  end
@@ -1,6 +1,8 @@
1
1
  require "textrepo"
2
2
 
3
3
  module Rbnotes
4
+ NAME = File.basename($PROGRAM_NAME) # :nodoc:
5
+
4
6
  require_relative "rbnotes/version"
5
7
  require_relative "rbnotes/error"
6
8
  require_relative "rbnotes/conf"
@@ -1,20 +1,40 @@
1
1
  module Rbnotes
2
+
2
3
  ##
3
4
  # This module defines all command classes of rbnotes. Each command
4
5
  # class must be derived from Rbnotes::Commands::Command class.
6
+
5
7
  module Commands
8
+
6
9
  ##
7
10
  # The base class for a command class.
11
+
8
12
  class Command
13
+
14
+ ##
15
+ # Short description of each command.
16
+
17
+ def description; nil; end
18
+
9
19
  ##
10
20
  # :call-seq:
11
- # Array, Hash -> nil
21
+ # execute(Array, Hash) -> nil
22
+ #
12
23
  # - Array: arguments for each command
13
24
  # - Hash : rbnotes configuration
14
- #
25
+
15
26
  def execute(args, conf)
16
- Builtins::DEFAULT_CMD.new.execute(args, conf)
27
+ Builtins.default_cmd.new.execute(args, conf)
28
+ end
29
+
30
+ ##
31
+ # Shows the help message for the command.
32
+ #
33
+
34
+ def help
35
+ Builtins::Usage.new.execute(nil, nil)
17
36
  end
37
+
18
38
  end
19
39
 
20
40
  # :stopdoc:
@@ -25,38 +45,73 @@ module Rbnotes
25
45
  # - stamp: converts given TIME_STR into a timestamp.
26
46
  # - time: converts given STAMP into a time string.
27
47
  module Builtins
28
- class Help < Command
48
+ class Usage < Command
49
+
50
+ def description
51
+ "Print usage"
52
+ end
53
+
29
54
  def execute(_, _)
30
55
  puts <<USAGE
31
- usage: rbnotes [command] [args]
32
-
33
- command:
34
- add : create a new note
35
- update STAMP : edit the note with external editor
36
- import FILE : import a FILE into the repository
37
- list NUM : list NUM notes
38
- show STAMP : show the note specified with STAMP
39
- delete STAMP : delete the note specified with STAMP
40
-
41
- conf : print the current configuraitons
42
- repo : print the repository path
43
- stamp TIME_STR : convert TIME_STR into a timestamp
44
- time STAMP : convert STAMP into a time string
45
- version : print version
46
- help : show help
56
+ Syntax:
57
+ #{Rbnotes::NAME} [-c| --conf CONF_FILE] [command] [args]
58
+
59
+ Example usage:
60
+ #{Rbnotes::NAME} add [-t STAMP_PATTERN]
61
+ #{Rbnotes::NAME} delete [TIMESTAMP]
62
+ #{Rbnotes::NAME} export [TIMESTAMP [FILENAME]]
63
+ #{Rbnotes::NAME} import FILE
64
+ #{Rbnotes::NAME} list [STAMP_PATTERN]
65
+ #{Rbnotes::NAME} search PATTERN [STAMP_PATTERN]
66
+ #{Rbnotes::NAME} show [TIMESTAMP]
67
+ #{Rbnotes::NAME} update [TIMESTAMP]
68
+
69
+ Further help for each command:
70
+ #{Rbnotes::NAME} help commands
71
+ #{Rbnotes::NAME} help [COMMAND]
72
+
73
+ Further information:
74
+ https://github.com/mnbi/rbnotes/wiki
75
+
47
76
  USAGE
48
77
  end
78
+
79
+ def help
80
+ puts <<HELP_USAGE
81
+ usage:
82
+ #{Rbnotes::NAME} usage
83
+
84
+ Print a short example of usage.
85
+ HELP_USAGE
86
+ end
49
87
  end
50
88
 
51
89
  class Version < Command
90
+ def description
91
+ "Print version"
92
+ end
93
+
52
94
  def execute(_, _)
53
- rbnotes_version = "rbnotes #{Rbnotes::VERSION} (#{Rbnotes::RELEASE})"
95
+ rbnotes_version = "#{Rbnotes::NAME} #{Rbnotes::VERSION} (#{Rbnotes::RELEASE})"
54
96
  textrepo_version = "textrepo #{Textrepo::VERSION}"
55
97
  puts "#{rbnotes_version} [#{textrepo_version}]"
56
98
  end
99
+
100
+ def help
101
+ puts <<VERSION
102
+ usage:
103
+ #{Rbnotes::NAME} version
104
+
105
+ Print version of #{Rbnotes::NAME} and release date.
106
+ VERSION
107
+ end
57
108
  end
58
109
 
59
110
  class Repo < Command
111
+ def description
112
+ "Print repository path"
113
+ end
114
+
60
115
  def execute(_, conf)
61
116
  name = conf[:repository_name]
62
117
  base = conf[:repository_base]
@@ -64,24 +119,54 @@ USAGE
64
119
 
65
120
  puts case type
66
121
  when :file_system
67
- "#{base}/#{name}"
122
+ File.expand_path(name, base)
68
123
  else
69
- "#{base}/#{name}"
124
+ File.join(base, name)
70
125
  end
71
126
  end
127
+
128
+ def help
129
+ puts <<REPO
130
+ usage:
131
+ #{Rbnotes::NAME} repo
132
+
133
+ Print the path of the repository. The type of the path entity depends
134
+ on what type is specified to the repository type in the configuration.
135
+ When ":file_system" is set to "repository_type", the path is a
136
+ directory which contains all note files. The structure of the
137
+ directory depends on the implementation of `textrepo`.
138
+ REPO
139
+ end
72
140
  end
73
141
 
74
142
  class Conf < Command
143
+ def description
144
+ "Print the current configuration"
145
+ end
146
+
75
147
  def execute(_, conf)
76
148
  conf.keys.sort.each { |k|
77
149
  puts "#{k}=#{conf[k]}"
78
150
  }
79
151
  end
152
+
153
+ def help
154
+ puts <<CONF
155
+ usage:
156
+ #{Rbnotes::NAME} conf
157
+
158
+ Print the current configuration values.
159
+ CONF
160
+ end
80
161
  end
81
162
 
82
163
  require "time"
83
164
 
84
165
  class Stamp < Command
166
+ def description
167
+ "Convert a time string into a timestamp string"
168
+ end
169
+
85
170
  def execute(args, _)
86
171
  time_str = args.shift
87
172
  unless time_str.nil?
@@ -91,9 +176,30 @@ USAGE
91
176
  super
92
177
  end
93
178
  end
179
+
180
+ def help
181
+ puts <<STAMP
182
+ usage:
183
+ #{Rbnotes::NAME} stamp
184
+
185
+ Convert a given time string into a timestamp string. The timestamp
186
+ string could be used as an argument of some rbnotes commands, such
187
+ "show". Here is short example of conversion:
188
+
189
+ "2020-11-06 16:51:15" -> "20201106165115"
190
+ "2020-11-06" -> "20201106000000"
191
+ "20201106" -> "20201106000000"
192
+ "2020-11-06 16" -> "20201106160000"
193
+ "2020-11-06 16:51" -> "20201106165100"
194
+ STAMP
195
+ end
94
196
  end
95
197
 
96
198
  class Time < Command
199
+ def description
200
+ "Convert a timestamp into a time string"
201
+ end
202
+
97
203
  def execute(args, _)
98
204
  stamp = args.shift
99
205
  unless stamp.nil?
@@ -103,39 +209,73 @@ USAGE
103
209
  super
104
210
  end
105
211
  end
212
+
213
+ def help
214
+ puts <<TIME
215
+ usage:
216
+ #{Rbnotes::NAME} time
217
+
218
+ Convert a given timestamp string into a time string. Here is short
219
+ example of conversion:
220
+
221
+ "20201106165115" -> "2020-11-06 16:51:15 +0900"
222
+ "202011061651" -> "2020-11-06 16:51:00 +0900"
223
+ "2020110616" -> "2020-11-06 16:00:00 +0900"
224
+ "20201106" -> "2020-11-06 00:00:00 +0900"
225
+ TIME
226
+ end
106
227
  end
107
228
 
108
- DEFAULT_CMD = Help
109
- end
229
+ class << self
230
+ def default_cmd_name
231
+ "usage"
232
+ end
233
+
234
+ def default_cmd
235
+ Usage
236
+ end
110
237
 
111
- DEFAULT_CMD_NAME = "help"
238
+ def command(name)
239
+ begin
240
+ const_defined?(name, false) ? const_get(name, false) : nil
241
+ rescue NameError => _
242
+ nil
243
+ end
244
+ end
245
+ end
246
+ end
112
247
 
113
248
  # :startdoc:
114
249
 
115
250
  class << self
251
+
116
252
  ##
117
253
  # Loads a class to perfom the command, then returns an instance
118
254
  # of the class.
119
255
  #
120
256
  # :call-seq:
121
- # "import" -> an object of Rbnotes::Commnads::Import
122
- # "list" -> an object of Rbnotes::Commands::List
123
- # "show" -> an object of Rbnotes::Commands::Show
124
- #
257
+ # load("add") -> Rbnotes::Commands::Add
258
+ # load("delete") -> Rbnotes::Commands::Delete
259
+ # load("export") -> Rbnotes::Commands::Export
260
+ # load("help") -> Rbnotes::Commands::Help
261
+ # load("import") -> Rbnotes::Commnads::Import
262
+ # load("list") -> Rbnotes::Commands::List
263
+ # load("search") -> Rbnotes::Commands::Search
264
+ # load("show") -> Rbnotes::Commands::Show
265
+ # load("update") -> Rbnotes::Commands::Update
266
+
125
267
  def load(cmd_name)
126
- cmd_name ||= DEFAULT_CMD_NAME
268
+ cmd_name ||= Builtins.default_cmd_name
127
269
  klass_name = cmd_name.capitalize
128
270
 
129
- klass = nil
130
- if Builtins.const_defined?(klass_name, false)
131
- klass = Builtins::const_get(klass_name, false)
132
- else
271
+ klass = Builtins.command(klass_name)
272
+ if klass.nil?
133
273
  begin
134
274
  require_relative "commands/#{cmd_name}"
135
275
  klass = const_get(klass_name, false)
136
276
  rescue LoadError => _
137
277
  STDERR.puts "unknown command: #{cmd_name}"
138
- klass = Builtins::DEFAULT_CMD
278
+ klass = Builtins.default_cmd
139
279
  end
140
280
  end
141
281
  klass.new