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 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