Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add output formatters #48

Merged
merged 7 commits into from Jan 18, 2022
Merged

Add output formatters #48

merged 7 commits into from Jan 18, 2022

Conversation

nirvdrum
Copy link
Contributor

@nirvdrum nirvdrum commented Jan 4, 2022

The primary goal of this PR is to output Seafoam's results in a machine readable format for automation use cases, while not compromising the ease-of-use afforded by the current plain text output. In order to achieve that, I'm proposing a new formatting system with plain-text and JSON formatters to start. It may very well be the case that we never need another format, but if we do, it should slot in easily enough.

Copy link

@tomstuart tomstuart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know anything about Seafoam, really, but I like the way this works so far. A few (optional) questions inline.


if first == '--json'
formatter_module = Seafoam::Formatters::Json
args.drop(1)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t understand why this line is here. Is it left behind from an earlier attempt to strip the '--json'?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can revisit all of this. But, the context is that Seafoam doesn't use OptionParser to parse its arguments. I did it this way just to get the flag without impacting the rest of the argument processing. I think longer term, adopting OptionParser or maybe even something like Thor would be better.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But args.drop(1) doesn’t do anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I see. Sorry for missing that. The next line reassigns the values and that's all that's needed. It looks like this is just leftover garbage from when I was going back and forth between options. I'll clean that up.

file, *rest = parse_name(name)
raise ArgumentError, 'info only works with a file' unless rest == [nil, nil, nil]

raise ArgumentError, 'info does not take arguments' unless args.empty?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don’t we want to raise this error any more?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really recall. I think I changed it because the command processor never passes arguments down. But, I'll switch it back and potentially revisit when reworking argument processing.

Comment on lines 5 to 55
module Formatter
def format
raise NotImplementedError
end
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this module exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's my attempt at documenting an interface for what a formatter is. I find seeing a NotImplementedError more useful than NoMethodError. But, if it's too "out there", I can drop it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s not particularly “out there” but it’s also not doing anything for us yet. No big deal, either seems fine to me. (I know that some people feel more strongly about reserving NotImplementedError for specifically “when a feature is not implemented on the current platform” rather than missing methods in general, but I’m pretty sure MRI doesn’t care.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I've never seen that distinction before. It's probably selection bias, but I've mostly seen it to mean "yes, this method does exist but you're either calling it on the wrong object or it's not implemented for this object" to avoid any confusion around NoMethodError not referring a typo.

I'll circle back to this afterwards. For now, I'm finding it helpful to distinguish between commands that haven't been updated for the formatter system at all and those that have, but haven't been fully implemented yet.

Copy link
Contributor Author

@nirvdrum nirvdrum Jan 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed its usage in 831f13d. I'll have to consider usages of NotImplementedError in the future. Thanks for alerting me to that.

parser = BGV::BGVParser.new(file)
major, minor = parser.read_file_header(version_check: false)
@out.puts "BGV #{major}.#{minor}"
formatter = formatter_module::InfoFormatter.new(major, minor)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this design — I think it makes sense to pick a formatter namespace and then resolve the relevant constants within it. It’s a little unconventional (vs sending messages to an object) but it’s low-ceremony and it interacts nicely with autoloading.

module Seafoam
# Formatters are the mechanism by which `seafoam` command output is presented to the user.
module Formatters
autoload :Base, 'seafoam/formatters/base'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is always needed isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not needed for --help or --version, but those are limited cases. I can unconditionally require if you'd prefer.

@chrisseaton
Copy link
Contributor

Idea looks good. Just needs the comments going through.

@nirvdrum nirvdrum force-pushed the json-output branch 4 times, most recently from 831f13d to 66b6f8b Compare January 7, 2022 20:11
@nirvdrum nirvdrum marked this pull request as ready for review January 7, 2022 20:16
README.md Show resolved Hide resolved
@nirvdrum nirvdrum merged commit 6d41e6b into master Jan 18, 2022
@nirvdrum nirvdrum deleted the json-output branch January 18, 2022 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants