Skip to content

Commit

Permalink
Pretty print JSON output
Browse files Browse the repository at this point in the history
- IMPROVED: Better formatting for JSON output
- NEW: --no-menu option for select command to use --query as a filter and act on matching entries without displaying menu
  • Loading branch information
ttscoff committed Oct 14, 2021
1 parent 0d31c05 commit 9c77c30
Show file tree
Hide file tree
Showing 12 changed files with 250 additions and 92 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### 1.0.89

- Pretty print JSON output
- --no-menu option for select command to use --query as a filter and act on matching entries without displaying menu

### 1.0.88

- Add --before and --after time search to yesterday command
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
doing (1.0.87)
doing (1.0.88)
chronic (~> 0.10, >= 0.10.2)
deep_merge (~> 1.2, >= 1.2.1)
gli (~> 2.19, >= 2.19.2)
Expand Down
9 changes: 7 additions & 2 deletions bin/doing
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,13 @@ command :select do |c|
c.arg_name 'SECTION'
c.flag %i[m move]

c.desc 'Initial search query for filtering'
c.desc 'Initial search query for filtering. Matching is fuzzy. For exact matching, start query with a single quote, e.g. `--query "\'search"'
c.arg_name 'QUERY'
c.flag %i[q query]

c.desc 'Use --no-menu to skip the interactive menu. Use with --query to filter items and act on results automatically. Test with `--output doing` to preview matches.'
c.switch %i[menu], negatable: true, default_value: true

c.desc 'Cancel selected items (add @done without timestamp)'
c.switch %i[c cancel], negatable: false, default_value: false

Expand All @@ -311,7 +314,7 @@ command :select do |c|
c.desc 'Add flag to selected item(s)'
c.switch %i[flag], negatable: false, default_value: false

c.desc 'Perform action without confirmation'
c.desc 'Perform action without confirmation.'
c.switch %i[force], negatable: false, default_value: false

c.desc 'Save selected entries to file using --output format'
Expand All @@ -323,6 +326,8 @@ command :select do |c|
c.flag %i[o output], must_match: /^(?:doing|taskpaper|html|csv|json|template|timeline)$/i

c.action do |_global_options, options, args|
exit_now! "--no-menu requires --query" if !options[:menu] && !options[:query]

wwid.interactive(options)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/doing/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Doing
VERSION = '1.0.88'
VERSION = '1.0.89'
end
13 changes: 10 additions & 3 deletions lib/doing/wwid.rb
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ def interactive(opt = {})
' | ',
item['title']
]
if opt[:section] =~ /^all/i
if section =~ /^all/i
out.concat([
' (',
item['section'],
Expand All @@ -834,7 +834,14 @@ def interactive(opt = {})
'--bind ctrl-a:select-all',
%(-q "#{opt[:query]}")
]
if !opt[:menu]
exit_now! "Can't skip menu when no query is provided" unless opt[:query]

fzf_args.concat([%(--filter="#{opt[:query]}"), '--no-sort'])
end

res = `echo #{Shellwords.escape(options.join("\n"))}|#{fzf} #{fzf_args.join(' ')}`
`echo '#{Shellwords.escape(options.join("\n"))}|#{fzf} #{fzf_args.join(' ')}' >> test.txt`
selected = []
res.split(/\n/).each do |item|
idx = item.match(/^(\d+)\)/)[1].to_i
Expand Down Expand Up @@ -1856,11 +1863,11 @@ def list_section(opt = {})
end
end
if opt[:output] == 'json'
out = {
puts JSON.pretty_generate({
'section' => section,
'items' => items_out,
'timers' => tag_times(format: 'json', sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order])
}.to_json
})
elsif opt[:output] == 'timeline'
template = <<~EOTEMPLATE
<!doctype html>
Expand Down
2 changes: 2 additions & 0 deletions test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/Users/ttscoff/Desktop/Code/doing/lib/doing/../helpers/fuzzyfilefinder
/Users/ttscoff/Desktop/Code/doing/lib/doing/../helpers/fuzzyfilefinder
64 changes: 64 additions & 0 deletions test/doing_day_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
require 'fileutils'
require 'tempfile'
require 'time'
require 'yaml'

require 'doing-helpers'
require 'test_helper'

# Tests for entry modifying commands
class DoingDayTest < Test::Unit::TestCase
include DoingHelpers
ENTRY_REGEX = /^\d{4}-\d\d-\d\d \d\d:\d\d \|/.freeze

def setup
@tmpdirs = []
@result = ''
@basedir = mktmpdir
@wwid_file = File.join(@basedir, 'wwid.md')
@config_file = File.join(File.dirname(__FILE__), 'test.doingrc')
end

def teardown
FileUtils.rm_rf(@tmpdirs)
end

def test_today_command
subject = 'Test new entry @tag1'
doing('done', subject)
subject2 = 'Test new entry 2 @tag2'
doing('now', subject2)
assert_count_entries(2, doing('today'), 'There should be 2 entries shown by `doing today`')
end

def test_yesterday_command
doing('done', 'Adding an entry finished yesterday', '--took', '30m', '--back', 'yesterday 3pm')
assert_count_entries(1, doing('yesterday'), 'There should be 1 entry shown by `doing yesterday`')
end

def test_on_command
# 1:42pm: Did a thing @done(2021-07-05 13:42)
doing('now', 'Test new entry @tag1')
doing('now', 'Test new entry 2 @tag2')
result = doing('--stdout', 'on', 'today')
assert_count_entries(2, result, 'There should be 2 entries')
end

private

def assert_count_entries(count, shown, message = 'Should be X entries shown')
assert_equal(count, shown.uncolor.strip.scan(ENTRY_REGEX).count, message)
end

def mktmpdir
tmpdir = Dir.mktmpdir
@tmpdirs.push(tmpdir)

tmpdir
end

def doing(*args)
doing_with_env({}, '--config_file', @config_file, '--doing_file', @wwid_file, *args)
end
end

57 changes: 57 additions & 0 deletions test/doing_last_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require 'fileutils'
require 'tempfile'
require 'time'
require 'yaml'

require 'doing-helpers'
require 'test_helper'

# Tests for entry modifying commands
class DoingLastTest < Test::Unit::TestCase
include DoingHelpers

def setup
@tmpdirs = []
@result = ''
@basedir = mktmpdir
@wwid_file = File.join(@basedir, 'wwid.md')
@config_file = File.join(File.dirname(__FILE__), 'test.doingrc')
@import_file = File.join(File.dirname(__FILE__), 'All Activities 2.json')
end

def teardown
FileUtils.rm_rf(@tmpdirs)
end

def test_last_command
subject = 'Test new entry @tag1'
doing('import', @import_file)
doing('now', subject)
assert_match(/#{subject}\s*$/, doing('last'), 'last entry should be entry just added')
end

def test_last_search_and_tag
unique_keyword = 'jumping jesus'
unique_tag = 'balloonpants'
doing('now', "Test new entry @#{unique_tag} sad monkey")
doing('now', "Test new entry @tag2 #{unique_keyword}")
doing('now', 'Test new entry @tag3 burly man')

assert_match(/#{unique_keyword}/, doing('last', '--search', unique_keyword), 'returned entry should contain unique keyword')
assert_match(/@#{unique_tag}/, doing('last', '--tag', unique_tag), 'returned entry should contain unique tag')
end

private

def mktmpdir
tmpdir = Dir.mktmpdir
@tmpdirs.push(tmpdir)

tmpdir
end

def doing(*args)
doing_with_env({}, '--config_file', @config_file, '--doing_file', @wwid_file, *args)
end
end

91 changes: 13 additions & 78 deletions test/doing_output_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,90 +10,23 @@
class DoingOutputTest < Test::Unit::TestCase
include DoingHelpers
ENTRY_REGEX = /^\d{4}-\d\d-\d\d \d\d:\d\d \|/.freeze
ENTRY_TS_REGEX = /\s*(?<ts>[^|]+) \s*\|/.freeze
ENTRY_DONE_REGEX = /@done\((?<ts>.*?)\)/.freeze

def setup
@tmpdirs = []
@result = ''
@basedir = mktmpdir
@wwid_file = File.join(@basedir, 'wwid.md')
@config_file = File.join(File.dirname(__FILE__), 'test.doingrc')
@import_file = File.join(File.dirname(__FILE__), 'All Activities 2.json')
@config = YAML.load(IO.read(@config_file))
end

def teardown
FileUtils.rm_rf(@tmpdirs)
end

def test_last_command
subject = 'Test new entry @tag1'
doing('now', subject)
assert_match(/#{subject}\s*$/, doing('last'), 'last entry should be entry just added')
end

def test_last_search_and_tag
unique_keyword = 'jumping jesus'
unique_tag = 'balloonpants'
doing('now', "Test new entry @#{unique_tag} sad monkey")
doing('now', "Test new entry @tag2 #{unique_keyword}")
doing('now', 'Test new entry @tag3 burly man')

assert_match(/#{unique_keyword}/, doing('last', '--search', unique_keyword), 'returned entry should contain unique keyword')
assert_match(/@#{unique_tag}/, doing('last', '--tag', unique_tag), 'returned entry should contain unique tag')
end

def test_view_command
subject = 'Test new entry @tag1'
doing('done', subject)
subject2 = 'Test new entry 2 @tag2'
doing('done', subject2)
assert_count_entries(2, doing('view', 'done'), 'There should be 2 entries shown by `view done`')
end

def test_show_command
subject = 'Test new entry @tag1'
doing('now', subject)
subject2 = 'Test new entry 2 @tag2'
doing('now', subject2)
result = doing('show').uncolor.strip
assert_count_entries(2, result, 'There should be 2 entries shown by `doing show`')
assert_match(/#{subject}\s*$/, result, 'doing show results should include test entry')
result = doing('show', '@tag1').uncolor.strip
assert_count_entries(1, result, 'There should be 1 entries shown by `doing show @tag1`')
assert_match(/#{subject}\s*$/, result, 'doing show @tag1 results should include test entry')
end

def test_show_command_tag_boolean
subject = 'Test new entry @tag1'
doing('now', subject)
subject2 = 'Test new entry 2 @tag2'
doing('now', subject2)
subject3 = 'Test new entry 3 @tag1 @tag2 @tag3'
doing('now', subject3)

result = doing('show', '--tag', 'tag1,tag2', '--bool', 'and').uncolor.strip
assert_count_entries(1, result, 'There should be 1 entry shown with both @tag1 and @tag2')
assert_match(/#{subject3}\s*$/, result, 'doing show results should include entry with both @tag1 and @tag2')

result = doing('show', '--tag', 'tag1,tag2', '--bool', 'or').uncolor.strip
assert_count_entries(3, result, 'There should be 3 entries shown with either @tag1 or @tag2')
result = doing('show', '--tag', 'tag2', '--bool', 'not').uncolor.strip
assert_count_entries(1, result, 'There should be 1 entry shown without @tag2')
assert_match(/#{subject}\s*$/, result, 'doing show results should include entry without @tag2')
end

def test_today_command
subject = 'Test new entry @tag1'
doing('done', subject)
subject2 = 'Test new entry 2 @tag2'
doing('now', subject2)
assert_count_entries(2, doing('today'), 'There should be 2 entries shown by `doing today`')
end

def test_yesterday_command
doing('done', 'Adding an entry finished yesterday', '--took', '30m', '--back', 'yesterday 3pm')
assert_count_entries(1, doing('yesterday'), 'There should be 1 entry shown by `doing yesterday`')
end

def test_sections_command
result = doing('sections').uncolor.strip
assert_match(/^#{@config['current_section']}$/, result, "#{@config['current_section']} should be the only section shown")
Expand All @@ -109,14 +42,6 @@ def test_recent_command
assert_equal(matches.count, 2, 'There should be 2 entries shown by `doing recent`')
end

def test_on_command
# 1:42pm: Did a thing @done(2021-07-05 13:42)
doing('now', 'Test new entry @tag1')
doing('now', 'Test new entry 2 @tag2')
result = doing('--stdout', 'on', 'today')
assert_count_entries(2, result, 'There should be 2 entries')
end

def test_template_command
result = doing('template', 'haml')
assert_match(/^!!!\s*\n%html/, result, 'Output should be a HAML template')
Expand All @@ -126,6 +51,16 @@ def test_template_command

private

def assert_matches(matches, shown)
matches.each do |regexp, msg, opt_refute|
if opt_refute
assert_no_match(regexp, shown, msg)
else
assert_match(regexp, shown, msg)
end
end
end

def assert_count_entries(count, shown, message = 'Should be X entries shown')
assert_equal(count, shown.uncolor.strip.scan(ENTRY_REGEX).count, message)
end
Expand Down
Loading

0 comments on commit 9c77c30

Please sign in to comment.