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
Use docile with root class declaration #98
Comments
Cool @adrianthedev! I appreciate your interest in Docile. Can you please say a bit more about what you are hoping to accomplish? Are you saying that there is a problem implementing the desired DSL with Docile today? |
Thanks for the quick answer. What I'm trying to achieve is to be able to evaluate everything inside the class as a block for docile. I'll try to create an example today. How I could use docile now: class PostResource < Avo::BaseResource
self.fields = -> do
field :id, as: :id
field :name, as: :text
tab do
field :name, as: :text
end
end
end
dsl = Docile.dsl_eval(Builder.new, &PostResource.fields) How I'd like to use it: class PostResource < Avo::BaseResource
field :id, as: :id
field :name, as: :text
tab do
field :name, as: :text
end
end
dsl = Docile.dsl_eval(SOMETHING_HERE_TO_PICK_UP_THE_FIELDS) |
Ok, I am looking at these two files to understand what exists today: |
What would happen if you tried to introduce the # File: lib/avo/base_resource.rb
# Class: Avo::BaseResource
class << self
def tab(&block)
# do other stuff...
Docile.dsl_eval(self, &block)
end
end |
Now, I'm not sure if you are intending to model in your data structure that the DSL methods (like If so, to make the DSL map to that data structure, you are probably going to have to make all of the class method DSL calls refer to some shared state such as a stack of contexts, if that makes sense? So perhaps, you might have something like: def tab(**args, &block)
# assume this starts as [], and we stack up contexts
dsl_context_stack.push args.merge(wrapper_type: tab)
# Run against the class itself, but EVERY class method will refer to context
Docile.dsl_eval(self, &block)
# now we pop from the stack
dsl_context_stack.pop
end
def dsl_context
dsl_context_stack.last || {}
end
def field(field_name, as:, **args, &block)
# merge from dsl_context as well as any args[:context]
merged_context = dsl_context.merge(args.fetch(:context, {}))
# Do normal stuff for fields, but also checking...
if context[:wrapper_type] == :tab
# ...
end
end |
This would seem to be achievable from where your code is today, perhaps without overwhelming changes? Please let me know if this is helpful, or if I have misunderstood the issues at hand? |
Again, thanks for looking into this. I appreciate it! The most contrived example of the API I'm looking for is this one: class UserResource < Avo::BaseResource
field :first_name
panel do
field :last_name
end
# One set of tabs together
tabs do
tab :Main do
field :email
field :email
tool UserTool
end
tab :Other do
tool MuserTool
end
end
# Panel in between the tabs
panel do
field :first_name
tool :last_name
end
# Another set of tabs together
tabs do
tab :Another_One do
field :email
field :email
tool UserTool
end
tab :Other_One do
tool MuserTool
end
end
end What's to note here is that the I was hoping I could get everything in between |
I think that's not possible (to take everything in between and just use it as a block) and I'm going a different route. I'll post my solution here when done. Thank you! |
I'm wondering, What if...
This might allow the easier creation of a nested multi-level DSL, because the top-level class methods would be delegated to an instance, which can then create new instances for each tab/panel block? Also, do you feel comfortable separating a Builder class from the final data structure that is built? This may make your code ultimately cleaner and easier to understand. Best of luck! Hope this helps |
Hey man, I returned to the task today and tried your suggestions above and they worked out amazing! It didn't really come out as above, but very close. I was able to re-use the I'll publish clean code soon but there's something very messy here (extremely messy). |
Hi. Thanks for all your work!
I am the maintainer of https://github.com/avo-hq/avo. Avo is an admin panel framework where you can build apps very fast! It achieves that through an extendable and flexible DSL.
This is just a sample. The result of this you can visit here.
I'd like to change the way we build the DSL. At the moment we use static methods to get the
field
s and build the final object.Now, we're introducing wrappers like
tab
orpanel
.I know that you usually have to give docile a block with the DSL, but is there a way to use docile and pick up the fields from the resource root class like above?
Thank you!
The text was updated successfully, but these errors were encountered: