-
-
Notifications
You must be signed in to change notification settings - Fork 28
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 dry-operation generators #171
Conversation
By adding new templates for un-nested operations
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.
This is looking great, thanks for putting it together, @cllns!
Biggest piece of feedback from me is that I want us to allow users to generate operations into any place in their apps or slices.
In this way generate operation
is just a more specialised version of the generate component
command we've recently added.
Have left some inline comments explaining more of my thinking here.
Would you be up for making that adjustment? Thank you! ❤️
raise MissingSliceError.new(slice) unless fs.directory?(slice_directory) | ||
|
||
if context.namespaces.any? | ||
fs.mkdir(directory = fs.join(slice_directory, "operations", context.namespaces)) |
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 don't think we should hardcode "operations"
in the directory path here. Operations should be able to be created anywhere within an app or slice.
(This comment also applies to all the other places we've hard-coded "operations" within this PR)
All great feedback, I agree with all of it. Will work to implement it. Still unsure about the exact pattern we want but I can get us closer to allowing operations anywhere, even if we tweak the UX later |
Ok I implemented removing the "Operations" folder and namespace, so now it's completely generic. I also made it (in my latest commit) so that users must provide a namespace. I think this is fair, since Note that this is different from how component is currently generated, which lets people generate without the namespace. If we do this here, perhaps we should do it there too. I worry the error message I wrote is too verbose, WDYT? |
I see your point about guiding users away from creating operations in the top-level. What about issuing a warning instead of a hard-failure? So we'd still allow it to be created, but also give a hint to the user about possibly better approaches. And we could allow those warnings to be turned off with a --no-recommendations flag or something. My thinking here is that Hanami is not really providing hard-and-fast guidelines about user domain code at this point, so I think it's better to err on the side of flexibility. Plus, I think if I wanted a top-level operation, I'd be pretty annoyed if our CLI didn't let me generate one. If that all sounds like too much work, then I'm also fine with just allowing top-level operations without any kinds of warnings or errors or anything of the like. |
Ok, I got rid of the Error and now we have it as puts-ing a I added I started to add skip_recommendations as CLI arg but it's awkward and ends up touching a lot of stuff, so maybe we can wait until people complain to build that out? |
I just integrated dry-operation into my app and I had to add I was thinking we could just include it generally within the main App namespace by default, but the specs use inline syntax so that doesn't work due to nesting. Where should we |
Also, should we add ROM transaction support to the default Operation if hanami-db is loaded? Related to #180 I think it would be something like:
|
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.
Nearly there! Just a couple last thoughts. Thanks for bearing with me here, @cllns :)
else | ||
fs.mkdir(directory = fs.join(slice_directory)) | ||
fs.write(fs.join(directory, "#{context.name}.rb"), t("top_level_slice_operation.erb", context)) | ||
fs.recommend("Add a namespace to operation names, so they go into a folder within #{directory}/.") |
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.
What do you think about this for wording?
fs.recommend("Add a namespace to operation names, so they go into a folder within #{directory}/.") | |
fs.recommend(%(Generating a top-level operation. To generate into a directory, add a namespace: "my_namespace.#{context.name})) |
That first sentence is there to explain why we're offering the recommendation in the first place. The second sentence is there to give a bit more guidance as to what the "recommended" args might look like.
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.
Sweet, switched it to this. I added the indentation too so it's more noticeable.
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 Looks good! Let's add @since 2.2.0
instead of @since x.x.x
. After that's done, feel free to merge! Thank you!
I also added |
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.
Thanks again @cllns! This is looking good :)
I also added include Dry::Monads[:result] into the base app Action, so people can match on the result of operations in their actions with just Success(value) instead of needing to write Dry::Monads::Result::Success in every spot they use a dry-operation. What do we think about this?
Yep, I think this is great!
I left two tiny pieces of feedback about this via inline comment. Once those are done, let's merge this!
If we do this, I can also make a PR to hanami-rspec to add the require and config.include Dry::Monads[:result] in the rspec support file, so testing operations just works in the same way.
Yeah, that would be awesome!
@@ -5,5 +5,6 @@ require "hanami/action" | |||
|
|||
module <%= camelized_app_name %> | |||
class Action < Hanami::Action | |||
include Dry::Monads[:result] |
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.
include Dry::Monads[:result] | |
# Provide `Success` and `Failure` for pattern matching on operation results | |
include Dry::Monads[:result] |
I like that you've included this!
I suggest we include a little explainer to make it clear why this line is here.
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.
For consistency, can you please update the slice generator to include this in slice actions too?
The difference should be that the slice generator should check to see if dry-monads is bundled before it includes this line. If the user chooses to remove dry-operation from their Gemfile
, then dry-monads will disappear and the include
would then result in an error.
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 did this for the slice, but the slice actions inherit from app/action.rb so it doesn't do anything. I kept it in since I might be missing something, but I think we can remove it?
I also had to add a line to require dry/monads
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 Ah yeah, sorry, that's my mistake. With slice actions inheriting from an app action, we don't need to put anything additional into the slice actions.
Add dry-monads include for slice base action
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.
This is still looking great, thanks @cllns!
I just noted here that we indeed don't need to be touching slice actions — sorry for the runaround there.
Once that's sorted out again, this looks good to merge!
Addresses #166. This creates a base operation in the app, then one in each slice when they're generated. Also adds a
hanami generate operation
commandTwo issues that still need to be addressed:
Generating a top-level operation (i.e.I added different templates for top-level and nested operations to solve this. Open to other solutions, but this is simple.add_book
notadmin.books.add
) has empty lines around the class due to trying to add modules for namespaces that don't exist. The newlines from the ERB template are still there. A simple way to handle it would benested_app_operation.erb
andnested_slice_operation.erb
but maybe we can think of something better?I have anFixed this. This allowsxit
for doingadmin/books/add
because that should be the same asadmin.books.add
but it's rendering it asclass Admin::Books::Add
instead of nested modules. Feel free to remove it but I feel like we should support this syntax the same way as the period separated names.hanami generate operation admin/books/add
to work just likehanami generate admin.books.add
. This will match the folder structure. The only thing here is that now we should add the same functionality to all our generators, which I'm happy to do in a separate PR after this one.Also, @timriley do we still do
x.x.x
as the version number to be changed at release time?Happy to address any feedback, and also feel free to take this WIP and finish it as you wish @timriley, I don't want to hold you up.