doing 2.1.10 → 2.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -152,17 +152,23 @@ module Doing
152
152
  ##
153
153
  ## @return [String] file path
154
154
  ##
155
- def choose_config
155
+ def choose_config(create: false)
156
156
  return @config_file if @force_answer
157
157
 
158
- if @additional_configs.count.positive?
158
+ if @additional_configs.count.positive? || create
159
159
  choices = [@config_file].concat(@additional_configs)
160
+ choices.push('Create a new .doingrc in the current directory') if create && !File.exist?('.doingrc')
160
161
  res = Doing::Prompt.choose_from(choices.uniq.sort.reverse,
161
162
  sorted: false,
162
163
  prompt: 'Local configs found, select which to update > ')
163
164
 
164
165
  raise UserCancelled, 'Cancelled' unless res
165
166
 
167
+ if res =~ /^Create a new/
168
+ res = File.expand_path('.doingrc')
169
+ FileUtils.touch(res)
170
+ end
171
+
166
172
  res.strip || @config_file
167
173
  else
168
174
  @config_file
@@ -249,7 +255,8 @@ module Doing
249
255
  # defaults.
250
256
  #
251
257
  def from(user_config)
252
- Util.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
258
+ # Util.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
259
+ Configuration[user_config].stringify_keys.deep_merge(DEFAULTS, { extend_existing_arrays: true, sort_merged_arrays: true })
253
260
  end
254
261
 
255
262
  ##
@@ -320,8 +327,8 @@ module Doing
320
327
 
321
328
  Hooks.trigger :post_config, self
322
329
 
323
- # config = local_config.deep_merge(config) unless @ignore_local
324
- config = Util.deep_merge_hashes(config, local_config) unless @ignore_local
330
+ config = local_config.deep_merge(config, { extend_existing_arrays: true, sort_merged_arrays: true }) unless @ignore_local
331
+ # config = Util.deep_merge_hashes(config, local_config) unless @ignore_local
325
332
 
326
333
  Hooks.trigger :post_local_config, self
327
334
 
@@ -397,7 +404,7 @@ module Doing
397
404
 
398
405
  begin
399
406
  additional_configs.each do |cfg|
400
- local_configs.deep_merge(Util.safe_load_file(cfg))
407
+ local_configs.deep_merge(Util.safe_load_file(cfg), { extend_existing_arrays: true, sort_merged_arrays: true })
401
408
  end
402
409
  rescue StandardError
403
410
  Doing.logger.error('Config:', 'Error reading local configuration(s)')
@@ -416,15 +423,18 @@ module Doing
416
423
  end
417
424
 
418
425
  begin
426
+
419
427
  user_config = Util.safe_load_file(config_file)
428
+ raise StandardError, 'Invalid config file format' unless user_config.is_a?(Hash)
429
+
420
430
  if user_config.key?('html_template')
421
431
  user_config['export_templates'] ||= {}
422
- user_config['export_templates'].deep_merge(user_config.delete('html_template'))
432
+ user_config['export_templates'].deep_merge(user_config.delete('html_template'), { extend_existing_arrays: true, sort_merged_arrays: true })
423
433
  end
424
434
 
425
435
  user_config['include_notes'] = user_config.delete(':include_notes') if user_config.key?(':include_notes')
426
436
 
427
- user_config.deep_merge(DEFAULTS)
437
+ user_config.deep_merge(DEFAULTS, { extend_existing_arrays: true, sort_merged_arrays: true })
428
438
  rescue StandardError => e
429
439
  Doing.logger.error('Config:', 'Error reading default configuration')
430
440
  Doing.logger.error('Error:', e.message)
data/lib/doing/hooks.rb CHANGED
@@ -6,11 +6,16 @@ module Doing
6
6
  DEFAULT_PRIORITY = 20
7
7
 
8
8
  @registry = {
9
- post_config: [],
10
- post_local_config: [],
11
- post_read: [],
12
- pre_write: [],
13
- post_write: []
9
+ post_config: [], # wwid
10
+ post_local_config: [], # wwid
11
+ post_read: [], # wwid
12
+ pre_entry_add: [], # wwid, new_entry
13
+ post_entry_added: [], # wwid, new_entry.dup
14
+ post_entry_updated: [], # wwid, entry
15
+ post_entry_removed: [], # wwid, entry.dup
16
+ pre_export: [], # wwid, format, entries
17
+ pre_write: [], # wwid, file
18
+ post_write: [] # wwid, file
14
19
  }
15
20
 
16
21
  # map of all hooks and their priorities
data/lib/doing/items.rb CHANGED
@@ -69,7 +69,7 @@ module Doing
69
69
  if section =~ /^all$/i
70
70
  dup
71
71
  else
72
- items = Items.new.concat(select { |item| item.section == section })
72
+ items = Items.new.concat(select { |item| !item.nil? && item.section == section })
73
73
  items.add_section(section, log: false)
74
74
  items
75
75
  end
@@ -84,6 +84,7 @@ module Doing
84
84
  deleted = delete(item)
85
85
  Doing.logger.count(:deleted)
86
86
  Doing.logger.info('Entry deleted:', deleted.title) if single
87
+ deleted
87
88
  end
88
89
 
89
90
  ##
@@ -111,6 +112,20 @@ module Doing
111
112
  end
112
113
  end
113
114
 
115
+ ##
116
+ ## Return Items containing items that don't exist in receiver
117
+ ##
118
+ ## @param items [Items] Receiver
119
+ ##
120
+ def diff(items)
121
+ diff = Items.new
122
+ each do |item|
123
+ res = items.select { |i| i.equal?(item) }
124
+ diff.push(item) unless res.count.positive?
125
+ end
126
+ diff
127
+ end
128
+
114
129
  # Output sections and items in Doing file format
115
130
  def to_s
116
131
  out = []
data/lib/doing/pager.rb CHANGED
@@ -64,22 +64,8 @@ module Doing
64
64
 
65
65
  private
66
66
 
67
- def command_exist?(command)
68
- exts = ENV.fetch("PATHEXT", "").split(::File::PATH_SEPARATOR)
69
- if Pathname.new(command).absolute?
70
- ::File.exist?(command) ||
71
- exts.any? { |ext| ::File.exist?("#{command}#{ext}")}
72
- else
73
- ENV.fetch("PATH", "").split(::File::PATH_SEPARATOR).any? do |dir|
74
- file = ::File.join(dir, command)
75
- ::File.exist?(file) ||
76
- exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
77
- end
78
- end
79
- end
80
-
81
67
  def git_pager
82
- command_exist?("git") ? `git config --get-all core.pager` : nil
68
+ TTY::Which.exist?('git') ? `#{TTY::Which.which('git')} config --get-all core.pager` : nil
83
69
  end
84
70
 
85
71
  def pagers
@@ -91,11 +77,7 @@ module Doing
91
77
  execs = commands.empty? ? pagers : commands
92
78
  execs
93
79
  .compact.map(&:strip).reject(&:empty?).uniq
94
- .find { |cmd| command_exist?(cmd.split.first) }
95
- end
96
-
97
- def exec_available?(*commands)
98
- !find_executable(*commands).nil?
80
+ .find { |cmd| TTY::Which.exist?(cmd.split.first) }
99
81
  end
100
82
 
101
83
  def which_pager
@@ -73,7 +73,12 @@ module Doing
73
73
  dups = filtered - new_items.count
74
74
  Doing.logger.info(%(Skipped #{dups} items with overlapping times)) if dups.positive?
75
75
 
76
+ new_items.map { |item| Hooks.trigger :pre_entry_add, self, item }
77
+
76
78
  wwid.content.concat(new_items)
79
+
80
+ new_items.map { |item| Hooks.trigger :post_entry_added, self, item.dup }
81
+
77
82
  Doing.logger.info(%(Imported #{new_items.count} items to #{section}))
78
83
  end
79
84
 
@@ -80,7 +80,9 @@ module Doing
80
80
 
81
81
  imported.each do |item|
82
82
  wwid.content.add_section(item.section) unless wwid.content.section?(item.section)
83
+ Hooks.trigger :pre_entry_add, self, item
83
84
  wwid.content.push(item)
85
+ Hooks.trigger :post_entry_added, self, item.dup
84
86
  end
85
87
 
86
88
  Doing.logger.info('Imported:', "#{imported.count} items")
@@ -77,7 +77,12 @@ module Doing
77
77
  dups = filtered - new_items.count
78
78
  Doing.logger.debug('Skipped:' , %(#{dups} items with overlapping times)) if dups.positive?
79
79
 
80
+ new_items.map { |item| Hooks.trigger :pre_entry_add, self, item }
81
+
80
82
  wwid.content.concat(new_items)
83
+
84
+ new_items.map { |item| Hooks.trigger :post_entry_added, self, item.dup }
85
+
81
86
  Doing.logger.info('Imported:', %(#{new_items.count} items to #{section}))
82
87
  end
83
88
 
@@ -37,6 +37,19 @@ module Doing
37
37
  end
38
38
  end
39
39
 
40
+ ##
41
+ ## Retrieve the most recent backup
42
+ ##
43
+ ## @param filename The filename
44
+ ## @return [String] filename
45
+ ##
46
+ def last_backup(filename = nil, count: 1)
47
+ filename ||= Doing.config.settings['doing_file']
48
+
49
+ backup = get_backups(filename).slice(count - 1)
50
+ backup.nil? ? nil : File.join(backup_dir, backup)
51
+ end
52
+
40
53
  ##
41
54
  ## Restore the most recent backup. If a filename is
42
55
  ## provided, only backups of that filename will be used.
@@ -48,15 +61,13 @@ module Doing
48
61
  Doing.logger.benchmark(:restore_backup, :start)
49
62
  filename ||= Doing.config.settings['doing_file']
50
63
 
51
- result = get_backups(filename).slice(count - 1)
52
- raise DoingRuntimeError, 'End of undo history' if result.nil?
53
-
54
- backup_file = File.join(backup_dir, result)
64
+ backup_file = last_backup(filename, count: count)
65
+ raise DoingRuntimeError, 'End of undo history' if backup_file.nil?
55
66
 
56
67
  save_undone(filename)
57
68
  FileUtils.mv(backup_file, filename)
58
69
  prune_backups_after(File.basename(backup_file))
59
- Doing.logger.warn('File update:', "restored from #{result}")
70
+ Doing.logger.warn('File update:', "restored from #{backup_file}")
60
71
  Doing.logger.benchmark(:restore_backup, :finish)
61
72
  end
62
73
 
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.10'
2
+ VERSION = '2.1.11'
3
3
  end