rbnotes 0.4.7 → 0.4.12

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.
@@ -4,9 +4,12 @@ module Rbnotes::Commands
4
4
  # Imports a existing file which specified by the argument as a note.
5
5
  #
6
6
  # A timestamp is generated referring to the birthtime of the given
7
- # file. If birthtime is not available on the system, use mtime
7
+ # file. If birthtime is not available on the system, uses mtime
8
8
  # (modification time).
9
9
  #
10
+ # When the option, "-m" (or "--use-mtime") is specified, uses mtime
11
+ # instead of birthtime.
12
+ #
10
13
  # Occasionally, there is another note which has the same timestmap
11
14
  # in the repository. Then, tries to create a new timestamp with a
12
15
  # suffix. Unluckily, when such timestamp with a suffix already
@@ -25,11 +28,29 @@ module Rbnotes::Commands
25
28
  # execute([PATHNAME], Rbnotes::Conf or Hash) -> nil
26
29
 
27
30
  def execute(args, conf)
31
+ @opts = {}
32
+ while args.size > 0
33
+ arg = args.shift
34
+ case arg
35
+ when "-m", "--use-mtime"
36
+ @opts[:use_mtime] = true
37
+ else
38
+ args.unshift(arg)
39
+ break
40
+ end
41
+ end
42
+
28
43
  file = args.shift
29
44
  unless file.nil?
30
45
  st = File::Stat.new(file)
31
- btime = st.respond_to?(:birthtime) ? st.birthtime : st.mtime
32
- stamp = Textrepo::Timestamp.new(btime)
46
+ time = nil
47
+ if @opts[:use_mtime]
48
+ time = st.mtime
49
+ else
50
+ time = st.respond_to?(:birthtime) ? st.birthtime : st.mtime
51
+ end
52
+
53
+ stamp = Textrepo::Timestamp.new(time)
33
54
  puts "Import [%s] (timestamp [%s]) ..." % [file, stamp]
34
55
 
35
56
  repo = Textrepo.init(conf)
@@ -72,7 +93,7 @@ module Rbnotes::Commands
72
93
  puts "Cannot create a text into the repository with the" \
73
94
  " specified file [%s]." % file
74
95
  puts "For, the birthtime [%s] is identical to some notes" \
75
- " already exists in the reopsitory." % btime
96
+ " already exists in the reopsitory." % time
76
97
  puts "Change the birthtime of the target file, then retry."
77
98
  else
78
99
  puts "... Done."
@@ -86,7 +107,7 @@ module Rbnotes::Commands
86
107
  def help # :nodoc:
87
108
  puts <<HELP
88
109
  usage:
89
- #{Rbnotes::NAME} import FILE
110
+ #{Rbnotes::NAME} import [-m|--use-mtime] FILE
90
111
 
91
112
  Imports a existing file which specified by the argument as a note.
92
113
 
@@ -24,10 +24,12 @@ module Rbnotes::Commands
24
24
  #
25
25
  # A keyword must be one of them:
26
26
  #
27
- # - "today" (or "to")
28
- # - "yeasterday" (or "ye")
29
- # - "this_week" (or "tw")
30
- # - "last_week" (or "lw")
27
+ # - "today" (or "to")
28
+ # - "yeasterday" (or "ye")
29
+ # - "this_week" (or "tw")
30
+ # - "last_week" (or "lw")
31
+ # - "this_month" (or "tm")
32
+ # - "last_month" (or "lm")
31
33
  #
32
34
  # Here is several examples of timestamp patterns.
33
35
  #
@@ -51,18 +53,68 @@ module Rbnotes::Commands
51
53
  # execute(Array, Rbnotes::Conf or Hash) -> nil
52
54
 
53
55
  def execute(args, conf)
54
- patterns = Rbnotes.utils.expand_keyword_in_args(args)
56
+ @opts = {}
57
+ while args.size > 0
58
+ arg = args.shift
59
+ case arg
60
+ when "-w", "--week"
61
+ @opts[:enum_week] = true
62
+ when "-v", "--verbose"
63
+ @opts[:verbose] = true
64
+ else
65
+ args.unshift(arg)
66
+ break
67
+ end
68
+ end
69
+
70
+ patterns = nil
71
+ if @opts[:enum_week]
72
+ arg = args.shift || Textrepo::Timestamp.now[0, 8]
73
+ case arg.size
74
+ when "yyyymodd".size, "yyyymoddhhmiss".size, "yyyymoddhhmiss_sfx".size
75
+ stamp_str = "#{arg}000000"[0, 14]
76
+ timestamp = Textrepo::Timestamp.parse_s(stamp_str)
77
+ when "modd".size
78
+ this_year = Time.now.year.to_s
79
+ stamp_str = "#{this_year}#{arg}000000"
80
+ begin
81
+ timestamp = Textrepo::Timestamp.parse_s(stamp_str)
82
+ rescue Textrepo::InvalidTimestampStringError => _e
83
+ raise InvalidTimestampPatternAsDateError, arg
84
+ end
85
+ else
86
+ raise InvalidTimestampPatternAsDateError, args.unshift(arg)
87
+ end
88
+ patterns = Rbnotes.utils.timestamp_patterns_in_week(timestamp)
89
+ else
90
+ patterns = Rbnotes.utils.expand_keyword_in_args(args)
91
+ end
92
+
55
93
  @repo = Textrepo.init(conf)
56
- # newer stamp shoud be above
57
- Rbnotes.utils.find_notes(patterns, @repo).each { |timestamp|
58
- puts Rbnotes.utils.make_headline(timestamp, @repo.read(timestamp))
59
- }
94
+ notes = Rbnotes.utils.find_notes(patterns, @repo)
95
+ output = []
96
+ if @opts[:verbose]
97
+ collect_timestamps_by_date(notes).each { |date, timestamps|
98
+ output << "#{date} (#{timestamps.size})"
99
+ timestamps.each { |timestamp|
100
+ pad = " "
101
+ output << Rbnotes.utils.make_headline(timestamp,
102
+ @repo.read(timestamp), pad)
103
+ }
104
+ }
105
+ else
106
+ notes.each { |timestamp|
107
+ output << Rbnotes.utils.make_headline(timestamp,
108
+ @repo.read(timestamp))
109
+ }
110
+ end
111
+ puts output
60
112
  end
61
113
 
62
114
  def help # :nodoc:
63
115
  puts <<HELP
64
116
  usage:
65
- #{Rbnotes::NAME} list [STAMP_PATTERN|KEYWORD]
117
+ #{Rbnotes::NAME} list [-w|--week][STAMP_PATTERN|KEYWORD]
66
118
 
67
119
  Show a list of notes. When no arguments, make a list with all notes
68
120
  in the repository. When specified STAMP_PATTERN, only those match the
@@ -83,9 +135,40 @@ KEYWORD:
83
135
  - "yeasterday" (or "ye")
84
136
  - "this_week" (or "tw")
85
137
  - "last_week" (or "lw")
138
+ - "this_month" (or "tm")
139
+ - "last_month" (or "lm")
86
140
 
141
+ An option "--week" is also acceptable. It specifies to enumerate all
142
+ days of a week. Typically, the option is used with a STAMP_PATTERN
143
+ which specifies a date, such "20201117", then it enumerates all days
144
+ of the week which contains "17th November 2020".
145
+
146
+ A STAMP_PATTERN other than (a) and (b) causes an error if it was used
147
+ with "--week" option.
148
+
149
+ When no STAMP_PATTERN was specified with "--week" option, the output
150
+ would be as same as the KEYWORD, "this_week" was specified.
87
151
  HELP
88
152
  end
89
153
 
154
+ # :stopdoc:
155
+
156
+ private
157
+
158
+ def collect_timestamps_by_date(timestamps)
159
+ result = {}
160
+ timestamps.map { |ts|
161
+ [ts.strftime("%Y-%m-%d"), ts]
162
+ }.reduce(result) { |r, pair|
163
+ date, stamp = pair
164
+ r[date] ||= []
165
+ r[date] << stamp
166
+ r
167
+ }
168
+ result
169
+ end
170
+
171
+ # :startdoc:
172
+
90
173
  end
91
174
  end
@@ -20,8 +20,12 @@ module Rbnotes::Commands
20
20
 
21
21
  picker = conf[:picker]
22
22
  unless picker.nil?
23
+ picker_opts = conf[:picker_option]
24
+ cmds = [picker]
25
+ cmds.concat(picker_opts.split) unless picker_opts.nil?
26
+
23
27
  require 'open3'
24
- result = Open3.pipeline_rw(picker) { |stdin, stdout, _|
28
+ result = Open3.pipeline_rw(cmds) { |stdin, stdout, _|
25
29
  stdin.puts list
26
30
  stdin.close
27
31
  stdout.read
@@ -77,11 +77,15 @@ HELP
77
77
  def timestamp_size
78
78
  timestamp.to_s.size
79
79
  end
80
+
81
+ def line_number_digits_size
82
+ line_number.to_s.size
83
+ end
80
84
  }
81
85
 
82
86
  def print_search_result(entries)
83
87
  maxcol_stamp = entries.map(&:timestamp_size).max
84
- maxcol_num = entries.map(&:line_number).max
88
+ maxcol_num = entries.map(&:line_number_digits_size).max
85
89
 
86
90
  sort(entries).each { |e|
87
91
  stamp_display = "%- *s" % [maxcol_stamp, e.timestamp]
@@ -1,52 +1,97 @@
1
1
  module Rbnotes::Commands
2
2
 
3
3
  ##
4
- # Shows the content of the note specified by the argument. The
4
+ # Shows the content of the notes specified by arguments. Each
5
5
  # argument must be a string which can be converted into
6
6
  # Textrepo::Timestamp object.
7
7
  #
8
- # A string for Timestamp must be:
8
+ # A string for Textrepo::Timestamp must be:
9
9
  #
10
10
  # "20201106112600" : year, date, time and sec
11
11
  # "20201106112600_012" : with suffix
12
12
  #
13
- # If no argument is passed, reads the standard input for an argument.
13
+ # If no argument is passed, reads the standard input for arguments.
14
14
 
15
15
  class Show < Command
16
16
 
17
17
  def description # :nodoc:
18
- "Show the content of a note"
18
+ "Show the content of notes"
19
19
  end
20
20
 
21
21
  def execute(args, conf)
22
- stamp = Rbnotes.utils.read_timestamp(args)
23
-
22
+ stamps = Rbnotes.utils.read_multiple_timestamps(args)
24
23
  repo = Textrepo.init(conf)
25
- content = repo.read(stamp)
24
+
25
+ content = stamps.map { |stamp| [stamp, repo.read(stamp)] }.to_h
26
26
 
27
27
  pager = conf[:pager]
28
28
  unless pager.nil?
29
- require 'open3'
30
- Open3.pipeline_w(pager) { |stdin|
31
- stdin.puts content
32
- stdin.close
33
- }
29
+ puts_with_pager(pager, make_output(content))
34
30
  else
35
- puts content
31
+ puts make_output(content)
36
32
  end
37
33
  end
38
34
 
39
35
  def help # :nodoc:
40
36
  puts <<HELP
41
37
  usage:
42
- #{Rbnotes::NAME} show [TIMESTAMP]
38
+ #{Rbnotes::NAME} show [TIMESTAMP...]
43
39
 
44
- Show the content of given note. TIMESTAMP must be a fully qualified
40
+ Show the content of given notes. TIMESTAMP must be a fully qualified
45
41
  one, such "20201016165130" or "20201016165130_012" if it has a suffix.
46
42
 
47
43
  The command try to read its argument from the standard input when no
48
44
  argument was passed in the command line.
49
45
  HELP
50
46
  end
47
+
48
+ # :stopdoc:
49
+
50
+ private
51
+
52
+ def puts_with_pager(pager, output)
53
+ require "open3"
54
+ Open3.pipeline_w(pager) { |stdin|
55
+ stdin.puts output
56
+ stdin.close
57
+ }
58
+ end
59
+
60
+ require "io/console/size"
61
+
62
+ def make_output(content)
63
+ if content.size <= 1
64
+ return content.values[0]
65
+ end
66
+
67
+ _, column = IO.console_size
68
+ output = content.map { |timestamp, text|
69
+ ary = [make_heading(timestamp, [column, 72].min)]
70
+ ary.concat(text)
71
+ ary
72
+ }
73
+
74
+ output = insert_delimiter(output, "")
75
+ output.flatten
76
+ end
77
+
78
+ def make_heading(timestamp, column)
79
+ stamp_str = timestamp.to_s
80
+ length = column - (stamp_str.size + 2)
81
+ "#{stamp_str} #{Array.new(length, '-').join}"
82
+ end
83
+
84
+ def insert_delimiter(ary, delimiter = "")
85
+ result = []
86
+ ary.each { |e|
87
+ result << e
88
+ result << delimiter
89
+ }
90
+ result.delete_at(-1)
91
+ result
92
+ end
93
+
94
+ # :startdoc:
95
+
51
96
  end
52
97
  end
@@ -0,0 +1,55 @@
1
+ module Rbnotes::Commands
2
+ ##
3
+ # Shows statistics.
4
+
5
+ class Statistics < Command
6
+
7
+ def description # :nodoc:
8
+ "Show statistics values"
9
+ end
10
+
11
+ def execute(args, conf)
12
+ report = :total
13
+ while args.size > 0
14
+ arg = args.shift
15
+ case arg
16
+ when "-y", "--yearly"
17
+ report = :yearly
18
+ break
19
+ when "-m", "--monthly"
20
+ report = :monthly
21
+ break
22
+ else
23
+ args.unshift(arg)
24
+ raise ArgumentError, "invalid option or argument: %s" % args.join(" ")
25
+ end
26
+ end
27
+
28
+ stats = Rbnotes::Statistics.new(conf)
29
+ case report
30
+ when :yearly
31
+ stats.yearly_report
32
+ when :monthly
33
+ stats.monthly_report
34
+ else
35
+ stats.total_report
36
+ end
37
+ end
38
+
39
+ def help
40
+ puts <<HELP
41
+ usage:
42
+ #{Rbnotes::NAME} statistics ([-y|--yearly]|[-m|--monthly])
43
+
44
+ option:
45
+ -y, --yearly : print yearly report
46
+ -m, --monthly : print monthly report
47
+
48
+ Show statistics.
49
+
50
+ In the version #{Rbnotes::VERSION}, only number of notes is supported.
51
+ HELP
52
+ end
53
+
54
+ end
55
+ end
@@ -82,7 +82,7 @@ module Rbnotes::Commands
82
82
  def help # :nodoc:
83
83
  puts <<HELP
84
84
  usage:
85
- #{Rbnotes::NAME} update [TIMESTAMP]
85
+ #{Rbnotes::NAME} update [-k|--keep] [TIMESTAMP]
86
86
 
87
87
  Updates the content of the note associated with given timestamp.
88
88
 
@@ -31,17 +31,26 @@ module Rbnotes
31
31
 
32
32
  DIRNAME_COMMON_CONF = ".config"
33
33
 
34
- def initialize(conf_path = nil) # :nodoc:
35
- @conf_path = conf_path || File.join(base_path, FILENAME_CONF)
36
-
34
+ def initialize(path = nil) # :nodoc:
37
35
  @conf = {}
38
- if FileTest.exist?(@conf_path)
39
- yaml_str = File.open(@conf_path, "r") { |f| f.read }
40
- @conf = YAML.load(yaml_str)
36
+
37
+ unless path.nil?
38
+ abspath = File.expand_path(path)
39
+ raise NoConfFileError, path unless FileTest.exist?(abspath)
40
+ @conf[:path] = abspath
41
41
  else
42
- @conf.merge(DEFAULT_VALUES)
42
+ @conf[:path] = default_conf_path
43
43
  end
44
- self
44
+
45
+ values =
46
+ if FileTest.exist?(@conf[:path])
47
+ yaml_str = File.open(@conf[:path], "r") { |f| f.read }
48
+ YAML.load(yaml_str)
49
+ else
50
+ DEFAULT_VALUES
51
+ end
52
+ @conf.merge!(values)
53
+ @conf[:config_home] = config_home
45
54
  end
46
55
 
47
56
  def_delegators(:@conf,
@@ -89,7 +98,7 @@ module Rbnotes
89
98
  :test => "_test",
90
99
  }
91
100
 
92
- def base_path
101
+ def config_home
93
102
  path = nil
94
103
  xdg, user = ["XDG_CONFIG_HOME", "HOME"].map{|n| ENV[n]}
95
104
  if xdg
@@ -97,12 +106,17 @@ module Rbnotes
97
106
  else
98
107
  path = File.join(user, DIRNAME_COMMON_CONF, DIRNAME_RBNOTES)
99
108
  end
100
- return path
109
+ path
110
+ end
111
+
112
+ def default_conf_path
113
+ File.join(config_home, FILENAME_CONF)
101
114
  end
102
- end
103
115
 
104
116
  # :startdoc:
105
117
 
118
+ end
119
+
106
120
  class << self
107
121
  ##
108
122
  # Gets the instance of Rbnotes::Conf. An optional argument is to