-
-
Notifications
You must be signed in to change notification settings - Fork 7
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
Newlines revamp (reading and writing) #7
base: main
Are you sure you want to change the base?
Conversation
It was only required for the MemoryFileSystem, not the real FileSystem, so writing an array would concatenate all the lines together without any spaces or newlines.
4ae201d
to
2710d51
Compare
Specifically, we don't want to *join* the lines, but rather append to each line. This lets us avoid having to manually add a newline to the end, and handle them all at once. Also, we chomp every line on read (and before write) so we don't duplicate any newlines
This is so when they're read out, they do not contain line breaks at the end of each line's string. Later on, when this content is passed to write, it is joined with , which will add newlines
This separates the concerns, so the adapters only write **String**s, they don't do any joining or coercion.
f3bd6fc
to
6a5f92d
Compare
Rebased for a cleaner commit history and rewrote the text in the PR too |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cllns Good work. 👍 Could you please let me know what do you think about my feedback? Thanks :)
lib/dry/files.rb
Outdated
def write(path, *content) | ||
adapter.write(path, *content) | ||
def write(path, lines) | ||
joined_lines = Array(lines).flatten.map { |line| line.chomp.concat(newline) }.join |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cllns Isn't this creating too many intermediate arrays? Can we use destructive counterparts (e.g. #map!
instead of #map
?
lib/dry/files.rb
Outdated
adapter.write(path, *content) | ||
def write(path, lines) | ||
joined_lines = Array(lines).flatten.map { |line| line.chomp.concat(newline) }.join | ||
joined_lines = "" if joined_lines == "\n" # Leave it empty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cllns Can we extract ""
as EMPTY_STRING.dup
?
Also, why "\n"
is hardcoded, given we have @newline
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched to \n
to newline
but I don't understand EMPTY_STRING.dup
.
I can extract an EMPTY_STRING = ""
in this file if you want (though I think ""
signifies an empty string well enough). I know what .dup
does, but I don't understand why it would be helpful here. Can you explain?
lib/dry/files/file_system.rb
Outdated
# | ||
# @since 0.1.0 | ||
# @api private | ||
def write(path, *content) | ||
def write(path, content) | ||
raise CanOnlyWriteStringError unless content.is_a?(String) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cllns Given this is an adapter (private API), we control the arguments, this exception seems to be a redundant internal assertion. Is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha. Was being defensive but you're right, it's not worth a custom Error
@@ -11,6 +10,12 @@ | |||
FileUtils.remove_entry_secure(root) | |||
end | |||
|
|||
describe "$INPUT_RECORD_SEPARATOR" do | |||
it "is not nil" do | |||
expect($INPUT_RECORD_SEPARATOR).not_to be_nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect($INPUT_RECORD_SEPARATOR).not_to be_nil | |
expected = if windows? | |
"\r\n" | |
else | |
"\n" | |
end | |
expect($INPUT_RECORD_SEPARATOR).to eq(expected) |
Then we can try to run CI on windows as well, if GHA allows that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on my research "$INPUT_RECORD_SEPARATOR does not give us \r\n on Windows" (from above). I don't have a Windows computer to confirm this but that is what I found.
Besides, we don't need to test Ruby. This is a regression test to ensure we don't remove require "english"
from this library (which is what this PR sought to fix in the first place). We don't care about the value, just that it's non-nil. And Windows CI sounds like something we should avoid if we can :)
@jodosha Comments addressed |
147b933
to
f0f4cff
Compare
794a552
to
d873b27
Compare
@cllns Could you please rebase with main? Thanks. :) |
$INPUT_RECORD_SEPARATOR
is only defined afterrequire "english"
(meaning it's an alias of$/
that's readable in english). We were only requiring it, outside of specs, in the memory adapter. Meaning, anyone using the realFileSystem
(not the memory adapter), would not get multi-line files outputted. Instead, the lines were joined together without any separating character.Additionally, when you're in a shell (depending on your shell settings), you can see the file also doesn't have a trailing newline.
$ cat hello_world.txt => helloworld%
This PR fixes all that :) I integrated @radar's work from #4 and extended it to the file system. This PR does fix the extra newlines issue that @solnic had with the generators. spec/unit/hanami/cli/commands/monolith/generate/slice_spec.rb
This does make the library less powerful because now it always adds a trailing newline. I think this is desirable, but it could make for unexpected file changes. For example, adding a line in the middle of a file will also add a newline to the end of the file. I think this is OK but we could handle those cases more elegantly, just don't think it's worth the increased complexity.
(It also changes the internal API, with an error, if you try to
write
anything but a string. This enforces a separation of concerns, where adapters now don't have to worry about joining or newline characters. They just write strings, already joined as desired from theDry::Files#write
implementation)One thing to note is that using
$INPUT_RECORD_SEPARATOR
does not give us\r\n
on Windows, if that's the intention. Instead of using a global variable, I think I'd prefer to have aDry::Files::NEWLINE = "\n"
constant. It'd be nice to get rid of them entirely. (We could also had a check for windows and define it as\r\n
in that case).